0001
0002
0003
0004
0005
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);