| Thomas Graf | d675c98 | 2005-06-23 21:00:58 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * net/sched/em_text.c	Textsearch ematch | 
|  | 3 | * | 
|  | 4 | *		This program is free software; you can redistribute it and/or | 
|  | 5 | *		modify it under the terms of the GNU General Public License | 
|  | 6 | *		as published by the Free Software Foundation; either version | 
|  | 7 | *		2 of the License, or (at your option) any later version. | 
|  | 8 | * | 
|  | 9 | * Authors:	Thomas Graf <tgraf@suug.ch> | 
|  | 10 | */ | 
|  | 11 |  | 
| Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 12 | #include <linux/slab.h> | 
| Thomas Graf | d675c98 | 2005-06-23 21:00:58 -0700 | [diff] [blame] | 13 | #include <linux/module.h> | 
|  | 14 | #include <linux/types.h> | 
|  | 15 | #include <linux/kernel.h> | 
| Thomas Graf | d675c98 | 2005-06-23 21:00:58 -0700 | [diff] [blame] | 16 | #include <linux/string.h> | 
|  | 17 | #include <linux/skbuff.h> | 
|  | 18 | #include <linux/textsearch.h> | 
|  | 19 | #include <linux/tc_ematch/tc_em_text.h> | 
|  | 20 | #include <net/pkt_cls.h> | 
|  | 21 |  | 
| Eric Dumazet | cc7ec45 | 2011-01-19 19:26:56 +0000 | [diff] [blame] | 22 | struct text_match { | 
| Thomas Graf | d675c98 | 2005-06-23 21:00:58 -0700 | [diff] [blame] | 23 | u16			from_offset; | 
|  | 24 | u16			to_offset; | 
|  | 25 | u8			from_layer; | 
|  | 26 | u8			to_layer; | 
|  | 27 | struct ts_config	*config; | 
|  | 28 | }; | 
|  | 29 |  | 
|  | 30 | #define EM_TEXT_PRIV(m) ((struct text_match *) (m)->data) | 
|  | 31 |  | 
|  | 32 | static int em_text_match(struct sk_buff *skb, struct tcf_ematch *m, | 
|  | 33 | struct tcf_pkt_info *info) | 
|  | 34 | { | 
|  | 35 | struct text_match *tm = EM_TEXT_PRIV(m); | 
|  | 36 | int from, to; | 
|  | 37 | struct ts_state state; | 
|  | 38 |  | 
|  | 39 | from = tcf_get_base_ptr(skb, tm->from_layer) - skb->data; | 
|  | 40 | from += tm->from_offset; | 
|  | 41 |  | 
|  | 42 | to = tcf_get_base_ptr(skb, tm->to_layer) - skb->data; | 
|  | 43 | to += tm->to_offset; | 
|  | 44 |  | 
|  | 45 | return skb_find_text(skb, from, to, tm->config, &state) != UINT_MAX; | 
|  | 46 | } | 
|  | 47 |  | 
|  | 48 | static int em_text_change(struct tcf_proto *tp, void *data, int len, | 
|  | 49 | struct tcf_ematch *m) | 
|  | 50 | { | 
|  | 51 | struct text_match *tm; | 
|  | 52 | struct tcf_em_text *conf = data; | 
|  | 53 | struct ts_config *ts_conf; | 
|  | 54 | int flags = 0; | 
|  | 55 |  | 
| Thomas Graf | d675c98 | 2005-06-23 21:00:58 -0700 | [diff] [blame] | 56 | if (len < sizeof(*conf) || len < (sizeof(*conf) + conf->pattern_len)) | 
|  | 57 | return -EINVAL; | 
|  | 58 |  | 
|  | 59 | if (conf->from_layer > conf->to_layer) | 
|  | 60 | return -EINVAL; | 
|  | 61 |  | 
|  | 62 | if (conf->from_layer == conf->to_layer && | 
|  | 63 | conf->from_offset > conf->to_offset) | 
|  | 64 | return -EINVAL; | 
|  | 65 |  | 
|  | 66 | retry: | 
|  | 67 | ts_conf = textsearch_prepare(conf->algo, (u8 *) conf + sizeof(*conf), | 
|  | 68 | conf->pattern_len, GFP_KERNEL, flags); | 
|  | 69 |  | 
|  | 70 | if (flags & TS_AUTOLOAD) | 
|  | 71 | rtnl_lock(); | 
|  | 72 |  | 
|  | 73 | if (IS_ERR(ts_conf)) { | 
|  | 74 | if (PTR_ERR(ts_conf) == -ENOENT && !(flags & TS_AUTOLOAD)) { | 
|  | 75 | rtnl_unlock(); | 
|  | 76 | flags |= TS_AUTOLOAD; | 
|  | 77 | goto retry; | 
|  | 78 | } else | 
|  | 79 | return PTR_ERR(ts_conf); | 
|  | 80 | } else if (flags & TS_AUTOLOAD) { | 
|  | 81 | textsearch_destroy(ts_conf); | 
|  | 82 | return -EAGAIN; | 
|  | 83 | } | 
|  | 84 |  | 
|  | 85 | tm = kmalloc(sizeof(*tm), GFP_KERNEL); | 
|  | 86 | if (tm == NULL) { | 
|  | 87 | textsearch_destroy(ts_conf); | 
|  | 88 | return -ENOBUFS; | 
|  | 89 | } | 
|  | 90 |  | 
|  | 91 | tm->from_offset = conf->from_offset; | 
|  | 92 | tm->to_offset   = conf->to_offset; | 
|  | 93 | tm->from_layer  = conf->from_layer; | 
|  | 94 | tm->to_layer    = conf->to_layer; | 
|  | 95 | tm->config      = ts_conf; | 
|  | 96 |  | 
|  | 97 | m->datalen = sizeof(*tm); | 
|  | 98 | m->data = (unsigned long) tm; | 
|  | 99 |  | 
|  | 100 | return 0; | 
|  | 101 | } | 
|  | 102 |  | 
|  | 103 | static void em_text_destroy(struct tcf_proto *tp, struct tcf_ematch *m) | 
|  | 104 | { | 
| Thomas Graf | 5ec1cea | 2010-10-31 09:37:38 -0700 | [diff] [blame] | 105 | if (EM_TEXT_PRIV(m) && EM_TEXT_PRIV(m)->config) | 
|  | 106 | textsearch_destroy(EM_TEXT_PRIV(m)->config); | 
| Thomas Graf | d675c98 | 2005-06-23 21:00:58 -0700 | [diff] [blame] | 107 | } | 
|  | 108 |  | 
|  | 109 | static int em_text_dump(struct sk_buff *skb, struct tcf_ematch *m) | 
|  | 110 | { | 
|  | 111 | struct text_match *tm = EM_TEXT_PRIV(m); | 
|  | 112 | struct tcf_em_text conf; | 
|  | 113 |  | 
|  | 114 | strncpy(conf.algo, tm->config->ops->name, sizeof(conf.algo) - 1); | 
|  | 115 | conf.from_offset = tm->from_offset; | 
|  | 116 | conf.to_offset = tm->to_offset; | 
|  | 117 | conf.from_layer = tm->from_layer; | 
|  | 118 | conf.to_layer = tm->to_layer; | 
|  | 119 | conf.pattern_len = textsearch_get_pattern_len(tm->config); | 
|  | 120 | conf.pad = 0; | 
|  | 121 |  | 
| Patrick McHardy | add93b6 | 2008-01-22 22:11:33 -0800 | [diff] [blame] | 122 | if (nla_put_nohdr(skb, sizeof(conf), &conf) < 0) | 
|  | 123 | goto nla_put_failure; | 
|  | 124 | if (nla_append(skb, conf.pattern_len, | 
|  | 125 | textsearch_get_pattern(tm->config)) < 0) | 
|  | 126 | goto nla_put_failure; | 
| Thomas Graf | d675c98 | 2005-06-23 21:00:58 -0700 | [diff] [blame] | 127 | return 0; | 
|  | 128 |  | 
| Patrick McHardy | add93b6 | 2008-01-22 22:11:33 -0800 | [diff] [blame] | 129 | nla_put_failure: | 
| Thomas Graf | d675c98 | 2005-06-23 21:00:58 -0700 | [diff] [blame] | 130 | return -1; | 
| YOSHIFUJI Hideaki | 10297b9 | 2007-02-09 23:25:16 +0900 | [diff] [blame] | 131 | } | 
| Thomas Graf | d675c98 | 2005-06-23 21:00:58 -0700 | [diff] [blame] | 132 |  | 
|  | 133 | static struct tcf_ematch_ops em_text_ops = { | 
|  | 134 | .kind	  = TCF_EM_TEXT, | 
|  | 135 | .change	  = em_text_change, | 
|  | 136 | .match	  = em_text_match, | 
|  | 137 | .destroy  = em_text_destroy, | 
|  | 138 | .dump	  = em_text_dump, | 
|  | 139 | .owner	  = THIS_MODULE, | 
|  | 140 | .link	  = LIST_HEAD_INIT(em_text_ops.link) | 
|  | 141 | }; | 
|  | 142 |  | 
|  | 143 | static int __init init_em_text(void) | 
|  | 144 | { | 
|  | 145 | return tcf_em_register(&em_text_ops); | 
|  | 146 | } | 
|  | 147 |  | 
| YOSHIFUJI Hideaki | 10297b9 | 2007-02-09 23:25:16 +0900 | [diff] [blame] | 148 | static void __exit exit_em_text(void) | 
| Thomas Graf | d675c98 | 2005-06-23 21:00:58 -0700 | [diff] [blame] | 149 | { | 
|  | 150 | tcf_em_unregister(&em_text_ops); | 
|  | 151 | } | 
|  | 152 |  | 
|  | 153 | MODULE_LICENSE("GPL"); | 
|  | 154 |  | 
|  | 155 | module_init(init_em_text); | 
|  | 156 | module_exit(exit_em_text); | 
| Patrick McHardy | db3d99c | 2007-07-11 19:46:26 -0700 | [diff] [blame] | 157 |  | 
|  | 158 | MODULE_ALIAS_TCF_EMATCH(TCF_EM_TEXT); |