1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * net/sched/em_text.c Textsearch ematch
5 * Authors: Thomas Graf <tgraf@suug.ch>
8 #include <linux/slab.h>
9 #include <linux/module.h>
10 #include <linux/types.h>
11 #include <linux/kernel.h>
12 #include <linux/string.h>
13 #include <linux/skbuff.h>
14 #include <linux/textsearch.h>
15 #include <linux/tc_ematch/tc_em_text.h>
16 #include <net/pkt_cls.h>
23 struct ts_config
*config
;
26 #define EM_TEXT_PRIV(m) ((struct text_match *) (m)->data)
28 static int em_text_match(struct sk_buff
*skb
, struct tcf_ematch
*m
,
29 struct tcf_pkt_info
*info
)
31 struct text_match
*tm
= EM_TEXT_PRIV(m
);
34 from
= tcf_get_base_ptr(skb
, tm
->from_layer
) - skb
->data
;
35 from
+= tm
->from_offset
;
37 to
= tcf_get_base_ptr(skb
, tm
->to_layer
) - skb
->data
;
40 return skb_find_text(skb
, from
, to
, tm
->config
) != UINT_MAX
;
43 static int em_text_change(struct net
*net
, void *data
, int len
,
46 struct text_match
*tm
;
47 struct tcf_em_text
*conf
= data
;
48 struct ts_config
*ts_conf
;
51 if (len
< sizeof(*conf
) || len
< (sizeof(*conf
) + conf
->pattern_len
))
54 if (conf
->from_layer
> conf
->to_layer
)
57 if (conf
->from_layer
== conf
->to_layer
&&
58 conf
->from_offset
> conf
->to_offset
)
62 ts_conf
= textsearch_prepare(conf
->algo
, (u8
*) conf
+ sizeof(*conf
),
63 conf
->pattern_len
, GFP_KERNEL
, flags
);
65 if (flags
& TS_AUTOLOAD
)
68 if (IS_ERR(ts_conf
)) {
69 if (PTR_ERR(ts_conf
) == -ENOENT
&& !(flags
& TS_AUTOLOAD
)) {
74 return PTR_ERR(ts_conf
);
75 } else if (flags
& TS_AUTOLOAD
) {
76 textsearch_destroy(ts_conf
);
80 tm
= kmalloc(sizeof(*tm
), GFP_KERNEL
);
82 textsearch_destroy(ts_conf
);
86 tm
->from_offset
= conf
->from_offset
;
87 tm
->to_offset
= conf
->to_offset
;
88 tm
->from_layer
= conf
->from_layer
;
89 tm
->to_layer
= conf
->to_layer
;
92 m
->datalen
= sizeof(*tm
);
93 m
->data
= (unsigned long) tm
;
98 static void em_text_destroy(struct tcf_ematch
*m
)
100 if (EM_TEXT_PRIV(m
) && EM_TEXT_PRIV(m
)->config
)
101 textsearch_destroy(EM_TEXT_PRIV(m
)->config
);
104 static int em_text_dump(struct sk_buff
*skb
, struct tcf_ematch
*m
)
106 struct text_match
*tm
= EM_TEXT_PRIV(m
);
107 struct tcf_em_text conf
;
109 strncpy(conf
.algo
, tm
->config
->ops
->name
, sizeof(conf
.algo
) - 1);
110 conf
.from_offset
= tm
->from_offset
;
111 conf
.to_offset
= tm
->to_offset
;
112 conf
.from_layer
= tm
->from_layer
;
113 conf
.to_layer
= tm
->to_layer
;
114 conf
.pattern_len
= textsearch_get_pattern_len(tm
->config
);
117 if (nla_put_nohdr(skb
, sizeof(conf
), &conf
) < 0)
118 goto nla_put_failure
;
119 if (nla_append(skb
, conf
.pattern_len
,
120 textsearch_get_pattern(tm
->config
)) < 0)
121 goto nla_put_failure
;
128 static struct tcf_ematch_ops em_text_ops
= {
130 .change
= em_text_change
,
131 .match
= em_text_match
,
132 .destroy
= em_text_destroy
,
133 .dump
= em_text_dump
,
134 .owner
= THIS_MODULE
,
135 .link
= LIST_HEAD_INIT(em_text_ops
.link
)
138 static int __init
init_em_text(void)
140 return tcf_em_register(&em_text_ops
);
143 static void __exit
exit_em_text(void)
145 tcf_em_unregister(&em_text_ops
);
148 MODULE_LICENSE("GPL");
150 module_init(init_em_text
);
151 module_exit(exit_em_text
);
153 MODULE_ALIAS_TCF_EMATCH(TCF_EM_TEXT
);