Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * net/sched/em_text.c  Textsearch ematch
0004  *
0005  * Authors: Thomas Graf <tgraf@suug.ch>
0006  */
0007 
0008 #include <linux/slab.h>
0009 #include <linux/module.h>
0010 #include <linux/types.h>
0011 #include <linux/kernel.h>
0012 #include <linux/string.h>
0013 #include <linux/skbuff.h>
0014 #include <linux/textsearch.h>
0015 #include <linux/tc_ematch/tc_em_text.h>
0016 #include <net/pkt_cls.h>
0017 
0018 struct text_match {
0019     u16         from_offset;
0020     u16         to_offset;
0021     u8          from_layer;
0022     u8          to_layer;
0023     struct ts_config    *config;
0024 };
0025 
0026 #define EM_TEXT_PRIV(m) ((struct text_match *) (m)->data)
0027 
0028 static int em_text_match(struct sk_buff *skb, struct tcf_ematch *m,
0029              struct tcf_pkt_info *info)
0030 {
0031     struct text_match *tm = EM_TEXT_PRIV(m);
0032     int from, to;
0033 
0034     from = tcf_get_base_ptr(skb, tm->from_layer) - skb->data;
0035     from += tm->from_offset;
0036 
0037     to = tcf_get_base_ptr(skb, tm->to_layer) - skb->data;
0038     to += tm->to_offset;
0039 
0040     return skb_find_text(skb, from, to, tm->config) != UINT_MAX;
0041 }
0042 
0043 static int em_text_change(struct net *net, void *data, int len,
0044               struct tcf_ematch *m)
0045 {
0046     struct text_match *tm;
0047     struct tcf_em_text *conf = data;
0048     struct ts_config *ts_conf;
0049     int flags = 0;
0050 
0051     if (len < sizeof(*conf) || len < (sizeof(*conf) + conf->pattern_len))
0052         return -EINVAL;
0053 
0054     if (conf->from_layer > conf->to_layer)
0055         return -EINVAL;
0056 
0057     if (conf->from_layer == conf->to_layer &&
0058         conf->from_offset > conf->to_offset)
0059         return -EINVAL;
0060 
0061 retry:
0062     ts_conf = textsearch_prepare(conf->algo, (u8 *) conf + sizeof(*conf),
0063                      conf->pattern_len, GFP_KERNEL, flags);
0064 
0065     if (flags & TS_AUTOLOAD)
0066         rtnl_lock();
0067 
0068     if (IS_ERR(ts_conf)) {
0069         if (PTR_ERR(ts_conf) == -ENOENT && !(flags & TS_AUTOLOAD)) {
0070             rtnl_unlock();
0071             flags |= TS_AUTOLOAD;
0072             goto retry;
0073         } else
0074             return PTR_ERR(ts_conf);
0075     } else if (flags & TS_AUTOLOAD) {
0076         textsearch_destroy(ts_conf);
0077         return -EAGAIN;
0078     }
0079 
0080     tm = kmalloc(sizeof(*tm), GFP_KERNEL);
0081     if (tm == NULL) {
0082         textsearch_destroy(ts_conf);
0083         return -ENOBUFS;
0084     }
0085 
0086     tm->from_offset = conf->from_offset;
0087     tm->to_offset   = conf->to_offset;
0088     tm->from_layer  = conf->from_layer;
0089     tm->to_layer    = conf->to_layer;
0090     tm->config      = ts_conf;
0091 
0092     m->datalen = sizeof(*tm);
0093     m->data = (unsigned long) tm;
0094 
0095     return 0;
0096 }
0097 
0098 static void em_text_destroy(struct tcf_ematch *m)
0099 {
0100     if (EM_TEXT_PRIV(m) && EM_TEXT_PRIV(m)->config)
0101         textsearch_destroy(EM_TEXT_PRIV(m)->config);
0102 }
0103 
0104 static int em_text_dump(struct sk_buff *skb, struct tcf_ematch *m)
0105 {
0106     struct text_match *tm = EM_TEXT_PRIV(m);
0107     struct tcf_em_text conf;
0108 
0109     strncpy(conf.algo, tm->config->ops->name, sizeof(conf.algo) - 1);
0110     conf.from_offset = tm->from_offset;
0111     conf.to_offset = tm->to_offset;
0112     conf.from_layer = tm->from_layer;
0113     conf.to_layer = tm->to_layer;
0114     conf.pattern_len = textsearch_get_pattern_len(tm->config);
0115     conf.pad = 0;
0116 
0117     if (nla_put_nohdr(skb, sizeof(conf), &conf) < 0)
0118         goto nla_put_failure;
0119     if (nla_append(skb, conf.pattern_len,
0120                textsearch_get_pattern(tm->config)) < 0)
0121         goto nla_put_failure;
0122     return 0;
0123 
0124 nla_put_failure:
0125     return -1;
0126 }
0127 
0128 static struct tcf_ematch_ops em_text_ops = {
0129     .kind     = TCF_EM_TEXT,
0130     .change   = em_text_change,
0131     .match    = em_text_match,
0132     .destroy  = em_text_destroy,
0133     .dump     = em_text_dump,
0134     .owner    = THIS_MODULE,
0135     .link     = LIST_HEAD_INIT(em_text_ops.link)
0136 };
0137 
0138 static int __init init_em_text(void)
0139 {
0140     return tcf_em_register(&em_text_ops);
0141 }
0142 
0143 static void __exit exit_em_text(void)
0144 {
0145     tcf_em_unregister(&em_text_ops);
0146 }
0147 
0148 MODULE_LICENSE("GPL");
0149 
0150 module_init(init_em_text);
0151 module_exit(exit_em_text);
0152 
0153 MODULE_ALIAS_TCF_EMATCH(TCF_EM_TEXT);