xref: /aosp_15_r20/external/libnl/lib/route/cls/ematch.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
1*4dc78e53SAndroid Build Coastguard Worker /* SPDX-License-Identifier: LGPL-2.1-only */
2*4dc78e53SAndroid Build Coastguard Worker /*
3*4dc78e53SAndroid Build Coastguard Worker  * Copyright (c) 2008-2013 Thomas Graf <[email protected]>
4*4dc78e53SAndroid Build Coastguard Worker  */
5*4dc78e53SAndroid Build Coastguard Worker 
6*4dc78e53SAndroid Build Coastguard Worker /**
7*4dc78e53SAndroid Build Coastguard Worker  * @ingroup cls
8*4dc78e53SAndroid Build Coastguard Worker  * @defgroup ematch Extended Match
9*4dc78e53SAndroid Build Coastguard Worker  *
10*4dc78e53SAndroid Build Coastguard Worker  * @{
11*4dc78e53SAndroid Build Coastguard Worker  */
12*4dc78e53SAndroid Build Coastguard Worker 
13*4dc78e53SAndroid Build Coastguard Worker #include "nl-default.h"
14*4dc78e53SAndroid Build Coastguard Worker 
15*4dc78e53SAndroid Build Coastguard Worker #include <linux/tc_ematch/tc_em_cmp.h>
16*4dc78e53SAndroid Build Coastguard Worker 
17*4dc78e53SAndroid Build Coastguard Worker #include <netlink/netlink.h>
18*4dc78e53SAndroid Build Coastguard Worker #include <netlink/route/classifier.h>
19*4dc78e53SAndroid Build Coastguard Worker #include <netlink/route/cls/ematch.h>
20*4dc78e53SAndroid Build Coastguard Worker #include <netlink/route/cls/ematch/cmp.h>
21*4dc78e53SAndroid Build Coastguard Worker 
22*4dc78e53SAndroid Build Coastguard Worker #include "nl-route.h"
23*4dc78e53SAndroid Build Coastguard Worker #include "nl-aux-core/nl-core.h"
24*4dc78e53SAndroid Build Coastguard Worker 
25*4dc78e53SAndroid Build Coastguard Worker #include "ematch_syntax.h"
26*4dc78e53SAndroid Build Coastguard Worker #include "ematch_grammar.h"
27*4dc78e53SAndroid Build Coastguard Worker 
28*4dc78e53SAndroid Build Coastguard Worker /**
29*4dc78e53SAndroid Build Coastguard Worker  * @name Module API
30*4dc78e53SAndroid Build Coastguard Worker  * @{
31*4dc78e53SAndroid Build Coastguard Worker  */
32*4dc78e53SAndroid Build Coastguard Worker 
33*4dc78e53SAndroid Build Coastguard Worker static NL_LIST_HEAD(ematch_ops_list);
34*4dc78e53SAndroid Build Coastguard Worker 
35*4dc78e53SAndroid Build Coastguard Worker /**
36*4dc78e53SAndroid Build Coastguard Worker  * Register ematch module
37*4dc78e53SAndroid Build Coastguard Worker  * @arg ops		Module operations.
38*4dc78e53SAndroid Build Coastguard Worker  *
39*4dc78e53SAndroid Build Coastguard Worker  * This function must be called by each ematch module at initialization
40*4dc78e53SAndroid Build Coastguard Worker  * time. It registers the calling module as available module.
41*4dc78e53SAndroid Build Coastguard Worker  *
42*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success or a negative error code.
43*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_ematch_register(struct rtnl_ematch_ops * ops)44*4dc78e53SAndroid Build Coastguard Worker int rtnl_ematch_register(struct rtnl_ematch_ops *ops)
45*4dc78e53SAndroid Build Coastguard Worker {
46*4dc78e53SAndroid Build Coastguard Worker 	if (rtnl_ematch_lookup_ops(ops->eo_kind))
47*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_EXIST;
48*4dc78e53SAndroid Build Coastguard Worker 
49*4dc78e53SAndroid Build Coastguard Worker 	NL_DBG(1, "ematch module \"%s\" registered\n", ops->eo_name);
50*4dc78e53SAndroid Build Coastguard Worker 
51*4dc78e53SAndroid Build Coastguard Worker 	nl_list_add_tail(&ops->eo_list, &ematch_ops_list);
52*4dc78e53SAndroid Build Coastguard Worker 
53*4dc78e53SAndroid Build Coastguard Worker 	return 0;
54*4dc78e53SAndroid Build Coastguard Worker }
55*4dc78e53SAndroid Build Coastguard Worker 
56*4dc78e53SAndroid Build Coastguard Worker /**
57*4dc78e53SAndroid Build Coastguard Worker  * Lookup ematch module by identification number.
58*4dc78e53SAndroid Build Coastguard Worker  * @arg kind		Module kind.
59*4dc78e53SAndroid Build Coastguard Worker  *
60*4dc78e53SAndroid Build Coastguard Worker  * Searches the list of registered ematch modules for match and returns it.
61*4dc78e53SAndroid Build Coastguard Worker  *
62*4dc78e53SAndroid Build Coastguard Worker  * @return Module operations or NULL if not found.
63*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_ematch_lookup_ops(int kind)64*4dc78e53SAndroid Build Coastguard Worker struct rtnl_ematch_ops *rtnl_ematch_lookup_ops(int kind)
65*4dc78e53SAndroid Build Coastguard Worker {
66*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_ematch_ops *ops;
67*4dc78e53SAndroid Build Coastguard Worker 
68*4dc78e53SAndroid Build Coastguard Worker 	nl_list_for_each_entry(ops, &ematch_ops_list, eo_list)
69*4dc78e53SAndroid Build Coastguard Worker 		if (ops->eo_kind == kind)
70*4dc78e53SAndroid Build Coastguard Worker 			return ops;
71*4dc78e53SAndroid Build Coastguard Worker 
72*4dc78e53SAndroid Build Coastguard Worker 	return NULL;
73*4dc78e53SAndroid Build Coastguard Worker }
74*4dc78e53SAndroid Build Coastguard Worker 
75*4dc78e53SAndroid Build Coastguard Worker /**
76*4dc78e53SAndroid Build Coastguard Worker  * Lookup ematch module by name
77*4dc78e53SAndroid Build Coastguard Worker  * @arg name		Name of ematch module.
78*4dc78e53SAndroid Build Coastguard Worker  *
79*4dc78e53SAndroid Build Coastguard Worker  * Searches the list of registered ematch modules for a match and returns it.
80*4dc78e53SAndroid Build Coastguard Worker  *
81*4dc78e53SAndroid Build Coastguard Worker  * @return Module operations or NULL if not fuond.
82*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_ematch_lookup_ops_by_name(const char * name)83*4dc78e53SAndroid Build Coastguard Worker struct rtnl_ematch_ops *rtnl_ematch_lookup_ops_by_name(const char *name)
84*4dc78e53SAndroid Build Coastguard Worker {
85*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_ematch_ops *ops;
86*4dc78e53SAndroid Build Coastguard Worker 
87*4dc78e53SAndroid Build Coastguard Worker 	nl_list_for_each_entry(ops, &ematch_ops_list, eo_list)
88*4dc78e53SAndroid Build Coastguard Worker 		if (!strcasecmp(ops->eo_name, name))
89*4dc78e53SAndroid Build Coastguard Worker 			return ops;
90*4dc78e53SAndroid Build Coastguard Worker 
91*4dc78e53SAndroid Build Coastguard Worker 	return NULL;
92*4dc78e53SAndroid Build Coastguard Worker }
93*4dc78e53SAndroid Build Coastguard Worker 
94*4dc78e53SAndroid Build Coastguard Worker /** @} */
95*4dc78e53SAndroid Build Coastguard Worker 
96*4dc78e53SAndroid Build Coastguard Worker /**
97*4dc78e53SAndroid Build Coastguard Worker  * @name Match
98*4dc78e53SAndroid Build Coastguard Worker  */
99*4dc78e53SAndroid Build Coastguard Worker 
100*4dc78e53SAndroid Build Coastguard Worker /**
101*4dc78e53SAndroid Build Coastguard Worker  * Allocate ematch object.
102*4dc78e53SAndroid Build Coastguard Worker  *
103*4dc78e53SAndroid Build Coastguard Worker  * Allocates and initializes an ematch object.
104*4dc78e53SAndroid Build Coastguard Worker  *
105*4dc78e53SAndroid Build Coastguard Worker  * @return New ematch object or NULL.
106*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_ematch_alloc(void)107*4dc78e53SAndroid Build Coastguard Worker struct rtnl_ematch *rtnl_ematch_alloc(void)
108*4dc78e53SAndroid Build Coastguard Worker {
109*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_ematch *e;
110*4dc78e53SAndroid Build Coastguard Worker 
111*4dc78e53SAndroid Build Coastguard Worker 	if (!(e = calloc(1, sizeof(*e))))
112*4dc78e53SAndroid Build Coastguard Worker 		return NULL;
113*4dc78e53SAndroid Build Coastguard Worker 
114*4dc78e53SAndroid Build Coastguard Worker 	NL_DBG(2, "allocated ematch %p\n", e);
115*4dc78e53SAndroid Build Coastguard Worker 
116*4dc78e53SAndroid Build Coastguard Worker 	NL_INIT_LIST_HEAD(&e->e_list);
117*4dc78e53SAndroid Build Coastguard Worker 	NL_INIT_LIST_HEAD(&e->e_childs);
118*4dc78e53SAndroid Build Coastguard Worker 
119*4dc78e53SAndroid Build Coastguard Worker 	return e;
120*4dc78e53SAndroid Build Coastguard Worker }
121*4dc78e53SAndroid Build Coastguard Worker 
122*4dc78e53SAndroid Build Coastguard Worker /**
123*4dc78e53SAndroid Build Coastguard Worker  * Add ematch to the end of the parent's list of children.
124*4dc78e53SAndroid Build Coastguard Worker  * @arg parent		parent ematch object
125*4dc78e53SAndroid Build Coastguard Worker  * @arg child		ematch object to be added to parent
126*4dc78e53SAndroid Build Coastguard Worker  *
127*4dc78e53SAndroid Build Coastguard Worker  * The parent must be a container ematch.
128*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_ematch_add_child(struct rtnl_ematch * parent,struct rtnl_ematch * child)129*4dc78e53SAndroid Build Coastguard Worker int rtnl_ematch_add_child(struct rtnl_ematch *parent,
130*4dc78e53SAndroid Build Coastguard Worker 			   struct rtnl_ematch *child)
131*4dc78e53SAndroid Build Coastguard Worker {
132*4dc78e53SAndroid Build Coastguard Worker 	if (parent->e_kind != TCF_EM_CONTAINER)
133*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_OPNOTSUPP;
134*4dc78e53SAndroid Build Coastguard Worker 
135*4dc78e53SAndroid Build Coastguard Worker 	NL_DBG(2, "added ematch %p \"%s\" to container %p\n",
136*4dc78e53SAndroid Build Coastguard Worker 		  child, child->e_ops->eo_name, parent);
137*4dc78e53SAndroid Build Coastguard Worker 
138*4dc78e53SAndroid Build Coastguard Worker 	nl_list_add_tail(&child->e_list, &parent->e_childs);
139*4dc78e53SAndroid Build Coastguard Worker 
140*4dc78e53SAndroid Build Coastguard Worker 	return 0;
141*4dc78e53SAndroid Build Coastguard Worker }
142*4dc78e53SAndroid Build Coastguard Worker 
143*4dc78e53SAndroid Build Coastguard Worker /**
144*4dc78e53SAndroid Build Coastguard Worker  * Remove ematch from the list of ematches it is linked to.
145*4dc78e53SAndroid Build Coastguard Worker  * @arg ematch		ematch object
146*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_ematch_unlink(struct rtnl_ematch * ematch)147*4dc78e53SAndroid Build Coastguard Worker void rtnl_ematch_unlink(struct rtnl_ematch *ematch)
148*4dc78e53SAndroid Build Coastguard Worker {
149*4dc78e53SAndroid Build Coastguard Worker 	NL_DBG(2, "unlinked ematch %p from any lists\n", ematch);
150*4dc78e53SAndroid Build Coastguard Worker 
151*4dc78e53SAndroid Build Coastguard Worker 	if (!nl_list_empty(&ematch->e_childs))
152*4dc78e53SAndroid Build Coastguard Worker 		NL_DBG(1, "warning: ematch %p with childs was unlinked\n",
153*4dc78e53SAndroid Build Coastguard Worker 			  ematch);
154*4dc78e53SAndroid Build Coastguard Worker 
155*4dc78e53SAndroid Build Coastguard Worker 	nl_list_del(&ematch->e_list);
156*4dc78e53SAndroid Build Coastguard Worker 	nl_init_list_head(&ematch->e_list);
157*4dc78e53SAndroid Build Coastguard Worker }
158*4dc78e53SAndroid Build Coastguard Worker 
rtnl_ematch_free(struct rtnl_ematch * ematch)159*4dc78e53SAndroid Build Coastguard Worker void rtnl_ematch_free(struct rtnl_ematch *ematch)
160*4dc78e53SAndroid Build Coastguard Worker {
161*4dc78e53SAndroid Build Coastguard Worker 	NL_DBG(2, "freed ematch %p\n", ematch);
162*4dc78e53SAndroid Build Coastguard Worker 	rtnl_ematch_unlink(ematch);
163*4dc78e53SAndroid Build Coastguard Worker 	free(ematch->e_data);
164*4dc78e53SAndroid Build Coastguard Worker 	free(ematch);
165*4dc78e53SAndroid Build Coastguard Worker }
166*4dc78e53SAndroid Build Coastguard Worker 
rtnl_ematch_set_ops(struct rtnl_ematch * ematch,struct rtnl_ematch_ops * ops)167*4dc78e53SAndroid Build Coastguard Worker int rtnl_ematch_set_ops(struct rtnl_ematch *ematch, struct rtnl_ematch_ops *ops)
168*4dc78e53SAndroid Build Coastguard Worker {
169*4dc78e53SAndroid Build Coastguard Worker 	if (ematch->e_ops)
170*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_EXIST;
171*4dc78e53SAndroid Build Coastguard Worker 
172*4dc78e53SAndroid Build Coastguard Worker 	ematch->e_ops = ops;
173*4dc78e53SAndroid Build Coastguard Worker 	ematch->e_kind = ops->eo_kind;
174*4dc78e53SAndroid Build Coastguard Worker 
175*4dc78e53SAndroid Build Coastguard Worker 	if (ops->eo_datalen) {
176*4dc78e53SAndroid Build Coastguard Worker 		ematch->e_data = calloc(1, ops->eo_datalen);
177*4dc78e53SAndroid Build Coastguard Worker 		if (!ematch->e_data)
178*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_NOMEM;
179*4dc78e53SAndroid Build Coastguard Worker 
180*4dc78e53SAndroid Build Coastguard Worker 		ematch->e_datalen = ops->eo_datalen;
181*4dc78e53SAndroid Build Coastguard Worker 	}
182*4dc78e53SAndroid Build Coastguard Worker 
183*4dc78e53SAndroid Build Coastguard Worker 	return 0;
184*4dc78e53SAndroid Build Coastguard Worker }
185*4dc78e53SAndroid Build Coastguard Worker 
rtnl_ematch_set_kind(struct rtnl_ematch * ematch,uint16_t kind)186*4dc78e53SAndroid Build Coastguard Worker int rtnl_ematch_set_kind(struct rtnl_ematch *ematch, uint16_t kind)
187*4dc78e53SAndroid Build Coastguard Worker {
188*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_ematch_ops *ops;
189*4dc78e53SAndroid Build Coastguard Worker 
190*4dc78e53SAndroid Build Coastguard Worker 	if (ematch->e_kind)
191*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_EXIST;
192*4dc78e53SAndroid Build Coastguard Worker 
193*4dc78e53SAndroid Build Coastguard Worker 	ematch->e_kind = kind;
194*4dc78e53SAndroid Build Coastguard Worker 
195*4dc78e53SAndroid Build Coastguard Worker 	if ((ops = rtnl_ematch_lookup_ops(kind)))
196*4dc78e53SAndroid Build Coastguard Worker 		rtnl_ematch_set_ops(ematch, ops);
197*4dc78e53SAndroid Build Coastguard Worker 
198*4dc78e53SAndroid Build Coastguard Worker 	return 0;
199*4dc78e53SAndroid Build Coastguard Worker }
200*4dc78e53SAndroid Build Coastguard Worker 
rtnl_ematch_set_name(struct rtnl_ematch * ematch,const char * name)201*4dc78e53SAndroid Build Coastguard Worker int rtnl_ematch_set_name(struct rtnl_ematch *ematch, const char *name)
202*4dc78e53SAndroid Build Coastguard Worker {
203*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_ematch_ops *ops;
204*4dc78e53SAndroid Build Coastguard Worker 
205*4dc78e53SAndroid Build Coastguard Worker 	if (ematch->e_kind)
206*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_EXIST;
207*4dc78e53SAndroid Build Coastguard Worker 
208*4dc78e53SAndroid Build Coastguard Worker 	if (!(ops = rtnl_ematch_lookup_ops_by_name(name)))
209*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_OPNOTSUPP;
210*4dc78e53SAndroid Build Coastguard Worker 
211*4dc78e53SAndroid Build Coastguard Worker 	rtnl_ematch_set_ops(ematch, ops);
212*4dc78e53SAndroid Build Coastguard Worker 
213*4dc78e53SAndroid Build Coastguard Worker 	return 0;
214*4dc78e53SAndroid Build Coastguard Worker }
215*4dc78e53SAndroid Build Coastguard Worker 
rtnl_ematch_set_flags(struct rtnl_ematch * ematch,uint16_t flags)216*4dc78e53SAndroid Build Coastguard Worker void rtnl_ematch_set_flags(struct rtnl_ematch *ematch, uint16_t flags)
217*4dc78e53SAndroid Build Coastguard Worker {
218*4dc78e53SAndroid Build Coastguard Worker 	ematch->e_flags |= flags;
219*4dc78e53SAndroid Build Coastguard Worker }
220*4dc78e53SAndroid Build Coastguard Worker 
rtnl_ematch_unset_flags(struct rtnl_ematch * ematch,uint16_t flags)221*4dc78e53SAndroid Build Coastguard Worker void rtnl_ematch_unset_flags(struct rtnl_ematch *ematch, uint16_t flags)
222*4dc78e53SAndroid Build Coastguard Worker {
223*4dc78e53SAndroid Build Coastguard Worker 	ematch->e_flags &= ~flags;
224*4dc78e53SAndroid Build Coastguard Worker }
225*4dc78e53SAndroid Build Coastguard Worker 
rtnl_ematch_get_flags(struct rtnl_ematch * ematch)226*4dc78e53SAndroid Build Coastguard Worker uint16_t rtnl_ematch_get_flags(struct rtnl_ematch *ematch)
227*4dc78e53SAndroid Build Coastguard Worker {
228*4dc78e53SAndroid Build Coastguard Worker 	return ematch->e_flags;
229*4dc78e53SAndroid Build Coastguard Worker }
230*4dc78e53SAndroid Build Coastguard Worker 
rtnl_ematch_data(struct rtnl_ematch * ematch)231*4dc78e53SAndroid Build Coastguard Worker void *rtnl_ematch_data(struct rtnl_ematch *ematch)
232*4dc78e53SAndroid Build Coastguard Worker {
233*4dc78e53SAndroid Build Coastguard Worker 	return ematch->e_data;
234*4dc78e53SAndroid Build Coastguard Worker }
235*4dc78e53SAndroid Build Coastguard Worker 
236*4dc78e53SAndroid Build Coastguard Worker /** @} */
237*4dc78e53SAndroid Build Coastguard Worker 
238*4dc78e53SAndroid Build Coastguard Worker /**
239*4dc78e53SAndroid Build Coastguard Worker  * @name Tree
240*4dc78e53SAndroid Build Coastguard Worker  */
241*4dc78e53SAndroid Build Coastguard Worker 
242*4dc78e53SAndroid Build Coastguard Worker /**
243*4dc78e53SAndroid Build Coastguard Worker  * Allocate ematch tree object
244*4dc78e53SAndroid Build Coastguard Worker  * @arg progid		program id
245*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_ematch_tree_alloc(uint16_t progid)246*4dc78e53SAndroid Build Coastguard Worker struct rtnl_ematch_tree *rtnl_ematch_tree_alloc(uint16_t progid)
247*4dc78e53SAndroid Build Coastguard Worker {
248*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_ematch_tree *tree;
249*4dc78e53SAndroid Build Coastguard Worker 
250*4dc78e53SAndroid Build Coastguard Worker 	if (!(tree = calloc(1, sizeof(*tree))))
251*4dc78e53SAndroid Build Coastguard Worker 		return NULL;
252*4dc78e53SAndroid Build Coastguard Worker 
253*4dc78e53SAndroid Build Coastguard Worker 	NL_INIT_LIST_HEAD(&tree->et_list);
254*4dc78e53SAndroid Build Coastguard Worker 	tree->et_progid = progid;
255*4dc78e53SAndroid Build Coastguard Worker 
256*4dc78e53SAndroid Build Coastguard Worker 	NL_DBG(2, "allocated new ematch tree %p, progid=%u\n", tree, progid);
257*4dc78e53SAndroid Build Coastguard Worker 
258*4dc78e53SAndroid Build Coastguard Worker 	return tree;
259*4dc78e53SAndroid Build Coastguard Worker }
260*4dc78e53SAndroid Build Coastguard Worker 
free_ematch_list(struct nl_list_head * head)261*4dc78e53SAndroid Build Coastguard Worker static void free_ematch_list(struct nl_list_head *head)
262*4dc78e53SAndroid Build Coastguard Worker {
263*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_ematch *pos, *next;
264*4dc78e53SAndroid Build Coastguard Worker 
265*4dc78e53SAndroid Build Coastguard Worker 	nl_list_for_each_entry_safe(pos, next, head, e_list) {
266*4dc78e53SAndroid Build Coastguard Worker 		if (!nl_list_empty(&pos->e_childs))
267*4dc78e53SAndroid Build Coastguard Worker 			free_ematch_list(&pos->e_childs);
268*4dc78e53SAndroid Build Coastguard Worker 		rtnl_ematch_free(pos);
269*4dc78e53SAndroid Build Coastguard Worker 	}
270*4dc78e53SAndroid Build Coastguard Worker }
271*4dc78e53SAndroid Build Coastguard Worker 
272*4dc78e53SAndroid Build Coastguard Worker /**
273*4dc78e53SAndroid Build Coastguard Worker  * Free ematch tree object
274*4dc78e53SAndroid Build Coastguard Worker  * @arg tree		ematch tree object
275*4dc78e53SAndroid Build Coastguard Worker  *
276*4dc78e53SAndroid Build Coastguard Worker  * This function frees the ematch tree and all ematches attached to it.
277*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_ematch_tree_free(struct rtnl_ematch_tree * tree)278*4dc78e53SAndroid Build Coastguard Worker void rtnl_ematch_tree_free(struct rtnl_ematch_tree *tree)
279*4dc78e53SAndroid Build Coastguard Worker {
280*4dc78e53SAndroid Build Coastguard Worker 	if (!tree)
281*4dc78e53SAndroid Build Coastguard Worker 		return;
282*4dc78e53SAndroid Build Coastguard Worker 
283*4dc78e53SAndroid Build Coastguard Worker 	free_ematch_list(&tree->et_list);
284*4dc78e53SAndroid Build Coastguard Worker 
285*4dc78e53SAndroid Build Coastguard Worker 	NL_DBG(2, "Freed ematch tree %p\n", tree);
286*4dc78e53SAndroid Build Coastguard Worker 
287*4dc78e53SAndroid Build Coastguard Worker 	free(tree);
288*4dc78e53SAndroid Build Coastguard Worker }
289*4dc78e53SAndroid Build Coastguard Worker 
clone_ematch_list(struct nl_list_head * dst,struct nl_list_head * src)290*4dc78e53SAndroid Build Coastguard Worker static int clone_ematch_list(struct nl_list_head *dst, struct nl_list_head *src)
291*4dc78e53SAndroid Build Coastguard Worker {
292*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_ematch *new = NULL, *pos = NULL;
293*4dc78e53SAndroid Build Coastguard Worker 
294*4dc78e53SAndroid Build Coastguard Worker 	nl_list_for_each_entry(pos, src, e_list) {
295*4dc78e53SAndroid Build Coastguard Worker 		new = rtnl_ematch_alloc();
296*4dc78e53SAndroid Build Coastguard Worker 		if (!new)
297*4dc78e53SAndroid Build Coastguard Worker 			goto nomem;
298*4dc78e53SAndroid Build Coastguard Worker 
299*4dc78e53SAndroid Build Coastguard Worker 		new->e_id      = pos->e_id;
300*4dc78e53SAndroid Build Coastguard Worker 		new->e_kind    = pos->e_kind;
301*4dc78e53SAndroid Build Coastguard Worker 		new->e_flags   = pos->e_flags;
302*4dc78e53SAndroid Build Coastguard Worker 		new->e_index   = pos->e_index;
303*4dc78e53SAndroid Build Coastguard Worker 		new->e_datalen = pos->e_datalen;
304*4dc78e53SAndroid Build Coastguard Worker 
305*4dc78e53SAndroid Build Coastguard Worker 		if (pos->e_ops) {
306*4dc78e53SAndroid Build Coastguard Worker 			if (rtnl_ematch_set_ops(new, pos->e_ops))
307*4dc78e53SAndroid Build Coastguard Worker 				goto nomem;
308*4dc78e53SAndroid Build Coastguard Worker 		}
309*4dc78e53SAndroid Build Coastguard Worker 
310*4dc78e53SAndroid Build Coastguard Worker 		if (!nl_list_empty(&pos->e_childs)) {
311*4dc78e53SAndroid Build Coastguard Worker 			if (clone_ematch_list(&new->e_childs, &pos->e_childs) < 0)
312*4dc78e53SAndroid Build Coastguard Worker 				goto nomem;
313*4dc78e53SAndroid Build Coastguard Worker 		}
314*4dc78e53SAndroid Build Coastguard Worker 		nl_list_add_tail(&new->e_list, dst);
315*4dc78e53SAndroid Build Coastguard Worker 	}
316*4dc78e53SAndroid Build Coastguard Worker 
317*4dc78e53SAndroid Build Coastguard Worker 	return 0;
318*4dc78e53SAndroid Build Coastguard Worker 
319*4dc78e53SAndroid Build Coastguard Worker nomem:
320*4dc78e53SAndroid Build Coastguard Worker 	if (new)
321*4dc78e53SAndroid Build Coastguard Worker 		free(new);
322*4dc78e53SAndroid Build Coastguard Worker 	free_ematch_list(dst);
323*4dc78e53SAndroid Build Coastguard Worker 	return -NLE_NOMEM;
324*4dc78e53SAndroid Build Coastguard Worker }
325*4dc78e53SAndroid Build Coastguard Worker 
326*4dc78e53SAndroid Build Coastguard Worker /**
327*4dc78e53SAndroid Build Coastguard Worker  * Clone ematch tree object
328*4dc78e53SAndroid Build Coastguard Worker  * @arg src		ematch tree object
329*4dc78e53SAndroid Build Coastguard Worker  *
330*4dc78e53SAndroid Build Coastguard Worker  * This function clones the ematch tree and all ematches attached to it.
331*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_ematch_tree_clone(struct rtnl_ematch_tree * src)332*4dc78e53SAndroid Build Coastguard Worker struct rtnl_ematch_tree *rtnl_ematch_tree_clone(struct rtnl_ematch_tree *src)
333*4dc78e53SAndroid Build Coastguard Worker {
334*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_ematch_tree *dst = NULL;
335*4dc78e53SAndroid Build Coastguard Worker 
336*4dc78e53SAndroid Build Coastguard Worker 	if (!src)
337*4dc78e53SAndroid Build Coastguard Worker 		return NULL;
338*4dc78e53SAndroid Build Coastguard Worker 
339*4dc78e53SAndroid Build Coastguard Worker 	if (!(dst = rtnl_ematch_tree_alloc(src->et_progid)))
340*4dc78e53SAndroid Build Coastguard Worker 		return NULL;
341*4dc78e53SAndroid Build Coastguard Worker 
342*4dc78e53SAndroid Build Coastguard Worker 	clone_ematch_list(&dst->et_list, &src->et_list);
343*4dc78e53SAndroid Build Coastguard Worker 
344*4dc78e53SAndroid Build Coastguard Worker 	return dst;
345*4dc78e53SAndroid Build Coastguard Worker }
346*4dc78e53SAndroid Build Coastguard Worker 
347*4dc78e53SAndroid Build Coastguard Worker /**
348*4dc78e53SAndroid Build Coastguard Worker  * Add ematch object to the end of the ematch tree
349*4dc78e53SAndroid Build Coastguard Worker  * @arg tree		ematch tree object
350*4dc78e53SAndroid Build Coastguard Worker  * @arg ematch		ematch object to add
351*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_ematch_tree_add(struct rtnl_ematch_tree * tree,struct rtnl_ematch * ematch)352*4dc78e53SAndroid Build Coastguard Worker void rtnl_ematch_tree_add(struct rtnl_ematch_tree *tree,
353*4dc78e53SAndroid Build Coastguard Worker 			  struct rtnl_ematch *ematch)
354*4dc78e53SAndroid Build Coastguard Worker {
355*4dc78e53SAndroid Build Coastguard Worker 	nl_list_add_tail(&ematch->e_list, &tree->et_list);
356*4dc78e53SAndroid Build Coastguard Worker }
357*4dc78e53SAndroid Build Coastguard Worker 
container_ref(struct rtnl_ematch * ematch)358*4dc78e53SAndroid Build Coastguard Worker static inline uint32_t container_ref(struct rtnl_ematch *ematch)
359*4dc78e53SAndroid Build Coastguard Worker {
360*4dc78e53SAndroid Build Coastguard Worker 	return *((uint32_t *) rtnl_ematch_data(ematch));
361*4dc78e53SAndroid Build Coastguard Worker }
362*4dc78e53SAndroid Build Coastguard Worker 
link_tree(struct rtnl_ematch * index[],int nmatches,int pos,struct nl_list_head * root)363*4dc78e53SAndroid Build Coastguard Worker static int link_tree(struct rtnl_ematch *index[], int nmatches, int pos,
364*4dc78e53SAndroid Build Coastguard Worker 		     struct nl_list_head *root)
365*4dc78e53SAndroid Build Coastguard Worker {
366*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_ematch *ematch;
367*4dc78e53SAndroid Build Coastguard Worker 	int i;
368*4dc78e53SAndroid Build Coastguard Worker 
369*4dc78e53SAndroid Build Coastguard Worker 	for (i = pos; i < nmatches; i++) {
370*4dc78e53SAndroid Build Coastguard Worker 		ematch = index[i];
371*4dc78e53SAndroid Build Coastguard Worker 
372*4dc78e53SAndroid Build Coastguard Worker 		nl_list_add_tail(&ematch->e_list, root);
373*4dc78e53SAndroid Build Coastguard Worker 
374*4dc78e53SAndroid Build Coastguard Worker 		if (ematch->e_kind == TCF_EM_CONTAINER)
375*4dc78e53SAndroid Build Coastguard Worker 			link_tree(index, nmatches, container_ref(ematch),
376*4dc78e53SAndroid Build Coastguard Worker 				  &ematch->e_childs);
377*4dc78e53SAndroid Build Coastguard Worker 
378*4dc78e53SAndroid Build Coastguard Worker 		if (!(ematch->e_flags & TCF_EM_REL_MASK))
379*4dc78e53SAndroid Build Coastguard Worker 			return 0;
380*4dc78e53SAndroid Build Coastguard Worker 	}
381*4dc78e53SAndroid Build Coastguard Worker 
382*4dc78e53SAndroid Build Coastguard Worker 	/* Last entry in chain can't possibly have no relation */
383*4dc78e53SAndroid Build Coastguard Worker 	return -NLE_INVAL;
384*4dc78e53SAndroid Build Coastguard Worker }
385*4dc78e53SAndroid Build Coastguard Worker 
386*4dc78e53SAndroid Build Coastguard Worker static struct nla_policy tree_policy[TCA_EMATCH_TREE_MAX+1] = {
387*4dc78e53SAndroid Build Coastguard Worker 	[TCA_EMATCH_TREE_HDR]  = { .minlen=sizeof(struct tcf_ematch_tree_hdr) },
388*4dc78e53SAndroid Build Coastguard Worker 	[TCA_EMATCH_TREE_LIST] = { .type = NLA_NESTED },
389*4dc78e53SAndroid Build Coastguard Worker };
390*4dc78e53SAndroid Build Coastguard Worker 
391*4dc78e53SAndroid Build Coastguard Worker /**
392*4dc78e53SAndroid Build Coastguard Worker  * Parse ematch netlink attributes
393*4dc78e53SAndroid Build Coastguard Worker  *
394*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success or a negative error code.
395*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_ematch_parse_attr(struct nlattr * attr,struct rtnl_ematch_tree ** result)396*4dc78e53SAndroid Build Coastguard Worker int rtnl_ematch_parse_attr(struct nlattr *attr, struct rtnl_ematch_tree **result)
397*4dc78e53SAndroid Build Coastguard Worker {
398*4dc78e53SAndroid Build Coastguard Worker 	struct nlattr *a, *tb[TCA_EMATCH_TREE_MAX+1];
399*4dc78e53SAndroid Build Coastguard Worker 	struct tcf_ematch_tree_hdr *thdr;
400*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_ematch_tree *tree;
401*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_ematch **index;
402*4dc78e53SAndroid Build Coastguard Worker 	int nmatches = 0, err, remaining;
403*4dc78e53SAndroid Build Coastguard Worker 
404*4dc78e53SAndroid Build Coastguard Worker 	NL_DBG(2, "Parsing attribute %p as ematch tree\n", attr);
405*4dc78e53SAndroid Build Coastguard Worker 
406*4dc78e53SAndroid Build Coastguard Worker 	err = nla_parse_nested(tb, TCA_EMATCH_TREE_MAX, attr, tree_policy);
407*4dc78e53SAndroid Build Coastguard Worker 	if (err < 0)
408*4dc78e53SAndroid Build Coastguard Worker 		return err;
409*4dc78e53SAndroid Build Coastguard Worker 
410*4dc78e53SAndroid Build Coastguard Worker 	if (!tb[TCA_EMATCH_TREE_HDR])
411*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_MISSING_ATTR;
412*4dc78e53SAndroid Build Coastguard Worker 
413*4dc78e53SAndroid Build Coastguard Worker 	thdr = nla_data(tb[TCA_EMATCH_TREE_HDR]);
414*4dc78e53SAndroid Build Coastguard Worker 
415*4dc78e53SAndroid Build Coastguard Worker 	/* Ignore empty trees */
416*4dc78e53SAndroid Build Coastguard Worker 	if (thdr->nmatches == 0) {
417*4dc78e53SAndroid Build Coastguard Worker 		NL_DBG(2, "Ignoring empty ematch configuration\n");
418*4dc78e53SAndroid Build Coastguard Worker 		return 0;
419*4dc78e53SAndroid Build Coastguard Worker 	}
420*4dc78e53SAndroid Build Coastguard Worker 
421*4dc78e53SAndroid Build Coastguard Worker 	if (!tb[TCA_EMATCH_TREE_LIST])
422*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_MISSING_ATTR;
423*4dc78e53SAndroid Build Coastguard Worker 
424*4dc78e53SAndroid Build Coastguard Worker 	NL_DBG(2, "ematch tree found with nmatches=%u, progid=%u\n",
425*4dc78e53SAndroid Build Coastguard Worker 		  thdr->nmatches, thdr->progid);
426*4dc78e53SAndroid Build Coastguard Worker 
427*4dc78e53SAndroid Build Coastguard Worker 	/*
428*4dc78e53SAndroid Build Coastguard Worker 	 * Do some basic sanity checking since we will allocate
429*4dc78e53SAndroid Build Coastguard Worker 	 * index[thdr->nmatches]. Calculate how many ematch headers fit into
430*4dc78e53SAndroid Build Coastguard Worker 	 * the provided data and make sure nmatches does not exceed it.
431*4dc78e53SAndroid Build Coastguard Worker 	 */
432*4dc78e53SAndroid Build Coastguard Worker 	if (thdr->nmatches > (nla_len(tb[TCA_EMATCH_TREE_LIST]) /
433*4dc78e53SAndroid Build Coastguard Worker 			      nla_total_size(sizeof(struct tcf_ematch_hdr))))
434*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_INVAL;
435*4dc78e53SAndroid Build Coastguard Worker 
436*4dc78e53SAndroid Build Coastguard Worker 	if (!(index = calloc(thdr->nmatches, sizeof(struct rtnl_ematch *))))
437*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
438*4dc78e53SAndroid Build Coastguard Worker 
439*4dc78e53SAndroid Build Coastguard Worker 	if (!(tree = rtnl_ematch_tree_alloc(thdr->progid))) {
440*4dc78e53SAndroid Build Coastguard Worker 		err = -NLE_NOMEM;
441*4dc78e53SAndroid Build Coastguard Worker 		goto errout;
442*4dc78e53SAndroid Build Coastguard Worker 	}
443*4dc78e53SAndroid Build Coastguard Worker 
444*4dc78e53SAndroid Build Coastguard Worker 	nla_for_each_nested(a, tb[TCA_EMATCH_TREE_LIST], remaining) {
445*4dc78e53SAndroid Build Coastguard Worker 		struct rtnl_ematch_ops *ops;
446*4dc78e53SAndroid Build Coastguard Worker 		struct tcf_ematch_hdr *hdr;
447*4dc78e53SAndroid Build Coastguard Worker 		struct rtnl_ematch *ematch;
448*4dc78e53SAndroid Build Coastguard Worker 		void *data;
449*4dc78e53SAndroid Build Coastguard Worker 		size_t len;
450*4dc78e53SAndroid Build Coastguard Worker 
451*4dc78e53SAndroid Build Coastguard Worker 		NL_DBG(3, "parsing ematch attribute %d, len=%u\n",
452*4dc78e53SAndroid Build Coastguard Worker 			  nmatches+1, nla_len(a));
453*4dc78e53SAndroid Build Coastguard Worker 
454*4dc78e53SAndroid Build Coastguard Worker 		if (_nla_len(a) < sizeof(*hdr)) {
455*4dc78e53SAndroid Build Coastguard Worker 			err = -NLE_INVAL;
456*4dc78e53SAndroid Build Coastguard Worker 			goto errout;
457*4dc78e53SAndroid Build Coastguard Worker 		}
458*4dc78e53SAndroid Build Coastguard Worker 
459*4dc78e53SAndroid Build Coastguard Worker 		/* Quit as soon as we've parsed more matches than expected */
460*4dc78e53SAndroid Build Coastguard Worker 		if (nmatches >= thdr->nmatches) {
461*4dc78e53SAndroid Build Coastguard Worker 			err = -NLE_RANGE;
462*4dc78e53SAndroid Build Coastguard Worker 			goto errout;
463*4dc78e53SAndroid Build Coastguard Worker 		}
464*4dc78e53SAndroid Build Coastguard Worker 
465*4dc78e53SAndroid Build Coastguard Worker 		hdr = nla_data(a);
466*4dc78e53SAndroid Build Coastguard Worker 		data = (char *) nla_data(a) + NLA_ALIGN(sizeof(*hdr));
467*4dc78e53SAndroid Build Coastguard Worker 		len = nla_len(a) - NLA_ALIGN(sizeof(*hdr));
468*4dc78e53SAndroid Build Coastguard Worker 
469*4dc78e53SAndroid Build Coastguard Worker 		NL_DBG(3, "ematch attribute matchid=%u, kind=%u, flags=%u\n",
470*4dc78e53SAndroid Build Coastguard Worker 			  hdr->matchid, hdr->kind, hdr->flags);
471*4dc78e53SAndroid Build Coastguard Worker 
472*4dc78e53SAndroid Build Coastguard Worker 		/*
473*4dc78e53SAndroid Build Coastguard Worker 		 * Container matches contain a reference to another sequence
474*4dc78e53SAndroid Build Coastguard Worker 		 * of matches. Ensure that the reference is within boundries.
475*4dc78e53SAndroid Build Coastguard Worker 		 */
476*4dc78e53SAndroid Build Coastguard Worker 		if (hdr->kind == TCF_EM_CONTAINER &&
477*4dc78e53SAndroid Build Coastguard Worker 		    *((uint32_t *) data) >= thdr->nmatches) {
478*4dc78e53SAndroid Build Coastguard Worker 			err = -NLE_INVAL;
479*4dc78e53SAndroid Build Coastguard Worker 			goto errout;
480*4dc78e53SAndroid Build Coastguard Worker 		}
481*4dc78e53SAndroid Build Coastguard Worker 
482*4dc78e53SAndroid Build Coastguard Worker 		if (!(ematch = rtnl_ematch_alloc())) {
483*4dc78e53SAndroid Build Coastguard Worker 			err = -NLE_NOMEM;
484*4dc78e53SAndroid Build Coastguard Worker 			goto errout;
485*4dc78e53SAndroid Build Coastguard Worker 		}
486*4dc78e53SAndroid Build Coastguard Worker 
487*4dc78e53SAndroid Build Coastguard Worker 		ematch->e_id = hdr->matchid;
488*4dc78e53SAndroid Build Coastguard Worker 		ematch->e_kind = hdr->kind;
489*4dc78e53SAndroid Build Coastguard Worker 		ematch->e_flags = hdr->flags;
490*4dc78e53SAndroid Build Coastguard Worker 
491*4dc78e53SAndroid Build Coastguard Worker 		if ((ops = rtnl_ematch_lookup_ops(hdr->kind))) {
492*4dc78e53SAndroid Build Coastguard Worker 			if (ops->eo_minlen && len < ops->eo_minlen) {
493*4dc78e53SAndroid Build Coastguard Worker 				rtnl_ematch_free(ematch);
494*4dc78e53SAndroid Build Coastguard Worker 				err = -NLE_INVAL;
495*4dc78e53SAndroid Build Coastguard Worker 				goto errout;
496*4dc78e53SAndroid Build Coastguard Worker 			}
497*4dc78e53SAndroid Build Coastguard Worker 
498*4dc78e53SAndroid Build Coastguard Worker 			rtnl_ematch_set_ops(ematch, ops);
499*4dc78e53SAndroid Build Coastguard Worker 
500*4dc78e53SAndroid Build Coastguard Worker 			if (ops->eo_parse &&
501*4dc78e53SAndroid Build Coastguard Worker 			    (err = ops->eo_parse(ematch, data, len)) < 0) {
502*4dc78e53SAndroid Build Coastguard Worker 				rtnl_ematch_free(ematch);
503*4dc78e53SAndroid Build Coastguard Worker 				goto errout;
504*4dc78e53SAndroid Build Coastguard Worker 			}
505*4dc78e53SAndroid Build Coastguard Worker 		}
506*4dc78e53SAndroid Build Coastguard Worker 
507*4dc78e53SAndroid Build Coastguard Worker 		NL_DBG(3, "index[%d] = %p\n", nmatches, ematch);
508*4dc78e53SAndroid Build Coastguard Worker 		index[nmatches++] = ematch;
509*4dc78e53SAndroid Build Coastguard Worker 	}
510*4dc78e53SAndroid Build Coastguard Worker 
511*4dc78e53SAndroid Build Coastguard Worker 	if (nmatches != thdr->nmatches) {
512*4dc78e53SAndroid Build Coastguard Worker 		err = -NLE_INVAL;
513*4dc78e53SAndroid Build Coastguard Worker 		goto errout;
514*4dc78e53SAndroid Build Coastguard Worker 	}
515*4dc78e53SAndroid Build Coastguard Worker 
516*4dc78e53SAndroid Build Coastguard Worker 	err = link_tree(index, nmatches, 0, &tree->et_list);
517*4dc78e53SAndroid Build Coastguard Worker 	if (err < 0)
518*4dc78e53SAndroid Build Coastguard Worker 		goto errout;
519*4dc78e53SAndroid Build Coastguard Worker 
520*4dc78e53SAndroid Build Coastguard Worker 	free(index);
521*4dc78e53SAndroid Build Coastguard Worker 	*result = tree;
522*4dc78e53SAndroid Build Coastguard Worker 
523*4dc78e53SAndroid Build Coastguard Worker 	return 0;
524*4dc78e53SAndroid Build Coastguard Worker 
525*4dc78e53SAndroid Build Coastguard Worker errout:
526*4dc78e53SAndroid Build Coastguard Worker 	rtnl_ematch_tree_free(tree);
527*4dc78e53SAndroid Build Coastguard Worker 	free(index);
528*4dc78e53SAndroid Build Coastguard Worker 	return err;
529*4dc78e53SAndroid Build Coastguard Worker }
530*4dc78e53SAndroid Build Coastguard Worker 
dump_ematch_sequence(struct nl_list_head * head,struct nl_dump_params * p)531*4dc78e53SAndroid Build Coastguard Worker static void dump_ematch_sequence(struct nl_list_head *head,
532*4dc78e53SAndroid Build Coastguard Worker 				 struct nl_dump_params *p)
533*4dc78e53SAndroid Build Coastguard Worker {
534*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_ematch *match;
535*4dc78e53SAndroid Build Coastguard Worker 
536*4dc78e53SAndroid Build Coastguard Worker 	nl_list_for_each_entry(match, head, e_list) {
537*4dc78e53SAndroid Build Coastguard Worker 		if (match->e_flags & TCF_EM_INVERT)
538*4dc78e53SAndroid Build Coastguard Worker 			nl_dump(p, "!");
539*4dc78e53SAndroid Build Coastguard Worker 
540*4dc78e53SAndroid Build Coastguard Worker 		if (match->e_kind == TCF_EM_CONTAINER) {
541*4dc78e53SAndroid Build Coastguard Worker 			nl_dump(p, "(");
542*4dc78e53SAndroid Build Coastguard Worker 			dump_ematch_sequence(&match->e_childs, p);
543*4dc78e53SAndroid Build Coastguard Worker 			nl_dump(p, ")");
544*4dc78e53SAndroid Build Coastguard Worker 		} else if (!match->e_ops) {
545*4dc78e53SAndroid Build Coastguard Worker 			nl_dump(p, "[unknown ematch %d]", match->e_kind);
546*4dc78e53SAndroid Build Coastguard Worker 		} else {
547*4dc78e53SAndroid Build Coastguard Worker 			if (match->e_ops->eo_dump)
548*4dc78e53SAndroid Build Coastguard Worker 				match->e_ops->eo_dump(match, p);
549*4dc78e53SAndroid Build Coastguard Worker 			else
550*4dc78e53SAndroid Build Coastguard Worker 				nl_dump(p, "[data]");
551*4dc78e53SAndroid Build Coastguard Worker 		}
552*4dc78e53SAndroid Build Coastguard Worker 
553*4dc78e53SAndroid Build Coastguard Worker 		switch (match->e_flags & TCF_EM_REL_MASK) {
554*4dc78e53SAndroid Build Coastguard Worker 		case TCF_EM_REL_AND:
555*4dc78e53SAndroid Build Coastguard Worker 			nl_dump(p, " AND ");
556*4dc78e53SAndroid Build Coastguard Worker 			break;
557*4dc78e53SAndroid Build Coastguard Worker 		case TCF_EM_REL_OR:
558*4dc78e53SAndroid Build Coastguard Worker 			nl_dump(p, " OR ");
559*4dc78e53SAndroid Build Coastguard Worker 			break;
560*4dc78e53SAndroid Build Coastguard Worker 		default:
561*4dc78e53SAndroid Build Coastguard Worker 			/* end of first level ematch sequence */
562*4dc78e53SAndroid Build Coastguard Worker 			return;
563*4dc78e53SAndroid Build Coastguard Worker 		}
564*4dc78e53SAndroid Build Coastguard Worker 	}
565*4dc78e53SAndroid Build Coastguard Worker }
566*4dc78e53SAndroid Build Coastguard Worker 
rtnl_ematch_tree_dump(struct rtnl_ematch_tree * tree,struct nl_dump_params * p)567*4dc78e53SAndroid Build Coastguard Worker void rtnl_ematch_tree_dump(struct rtnl_ematch_tree *tree,
568*4dc78e53SAndroid Build Coastguard Worker 			   struct nl_dump_params *p)
569*4dc78e53SAndroid Build Coastguard Worker {
570*4dc78e53SAndroid Build Coastguard Worker 	if (!tree)
571*4dc78e53SAndroid Build Coastguard Worker 		BUG();
572*4dc78e53SAndroid Build Coastguard Worker 
573*4dc78e53SAndroid Build Coastguard Worker 	dump_ematch_sequence(&tree->et_list, p);
574*4dc78e53SAndroid Build Coastguard Worker 	nl_dump(p, "\n");
575*4dc78e53SAndroid Build Coastguard Worker }
576*4dc78e53SAndroid Build Coastguard Worker 
update_container_index(struct nl_list_head * list,int * index)577*4dc78e53SAndroid Build Coastguard Worker static int update_container_index(struct nl_list_head *list, int *index)
578*4dc78e53SAndroid Build Coastguard Worker {
579*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_ematch *e;
580*4dc78e53SAndroid Build Coastguard Worker 
581*4dc78e53SAndroid Build Coastguard Worker 	nl_list_for_each_entry(e, list, e_list)
582*4dc78e53SAndroid Build Coastguard Worker 		e->e_index = (*index)++;
583*4dc78e53SAndroid Build Coastguard Worker 
584*4dc78e53SAndroid Build Coastguard Worker 	nl_list_for_each_entry(e, list, e_list) {
585*4dc78e53SAndroid Build Coastguard Worker 		if (e->e_kind == TCF_EM_CONTAINER) {
586*4dc78e53SAndroid Build Coastguard Worker 			int err;
587*4dc78e53SAndroid Build Coastguard Worker 
588*4dc78e53SAndroid Build Coastguard Worker 			if (nl_list_empty(&e->e_childs))
589*4dc78e53SAndroid Build Coastguard Worker 				return -NLE_OBJ_NOTFOUND;
590*4dc78e53SAndroid Build Coastguard Worker 
591*4dc78e53SAndroid Build Coastguard Worker 			*((uint32_t *) e->e_data) = *index;
592*4dc78e53SAndroid Build Coastguard Worker 
593*4dc78e53SAndroid Build Coastguard Worker 			err = update_container_index(&e->e_childs, index);
594*4dc78e53SAndroid Build Coastguard Worker 			if (err < 0)
595*4dc78e53SAndroid Build Coastguard Worker 				return err;
596*4dc78e53SAndroid Build Coastguard Worker 		}
597*4dc78e53SAndroid Build Coastguard Worker 	}
598*4dc78e53SAndroid Build Coastguard Worker 
599*4dc78e53SAndroid Build Coastguard Worker 	return 0;
600*4dc78e53SAndroid Build Coastguard Worker }
601*4dc78e53SAndroid Build Coastguard Worker 
fill_ematch_sequence(struct nl_msg * msg,struct nl_list_head * list)602*4dc78e53SAndroid Build Coastguard Worker static int fill_ematch_sequence(struct nl_msg *msg, struct nl_list_head *list)
603*4dc78e53SAndroid Build Coastguard Worker {
604*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_ematch *e;
605*4dc78e53SAndroid Build Coastguard Worker 
606*4dc78e53SAndroid Build Coastguard Worker 	nl_list_for_each_entry(e, list, e_list) {
607*4dc78e53SAndroid Build Coastguard Worker 		struct tcf_ematch_hdr match = {
608*4dc78e53SAndroid Build Coastguard Worker 			.matchid = e->e_id,
609*4dc78e53SAndroid Build Coastguard Worker 			.kind = e->e_kind,
610*4dc78e53SAndroid Build Coastguard Worker 			.flags = e->e_flags,
611*4dc78e53SAndroid Build Coastguard Worker 		};
612*4dc78e53SAndroid Build Coastguard Worker 		struct nlattr *attr;
613*4dc78e53SAndroid Build Coastguard Worker 		int err = 0;
614*4dc78e53SAndroid Build Coastguard Worker 
615*4dc78e53SAndroid Build Coastguard Worker 		if (!(attr = nla_nest_start(msg, e->e_index + 1)))
616*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_NOMEM;
617*4dc78e53SAndroid Build Coastguard Worker 
618*4dc78e53SAndroid Build Coastguard Worker 		if (nlmsg_append(msg, &match, sizeof(match), 0) < 0)
619*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_NOMEM;
620*4dc78e53SAndroid Build Coastguard Worker 
621*4dc78e53SAndroid Build Coastguard Worker 		if (e->e_ops->eo_fill)
622*4dc78e53SAndroid Build Coastguard Worker 			err = e->e_ops->eo_fill(e, msg);
623*4dc78e53SAndroid Build Coastguard Worker 		else if (e->e_flags & TCF_EM_SIMPLE)
624*4dc78e53SAndroid Build Coastguard Worker 			err = nlmsg_append(msg, e->e_data, 4, 0);
625*4dc78e53SAndroid Build Coastguard Worker 		else if (e->e_datalen > 0)
626*4dc78e53SAndroid Build Coastguard Worker 			err = nlmsg_append(msg, e->e_data, e->e_datalen, 0);
627*4dc78e53SAndroid Build Coastguard Worker 
628*4dc78e53SAndroid Build Coastguard Worker 		NL_DBG(3, "msg %p: added ematch [%d] id=%d kind=%d flags=%d\n",
629*4dc78e53SAndroid Build Coastguard Worker 			  msg, e->e_index, match.matchid, match.kind, match.flags);
630*4dc78e53SAndroid Build Coastguard Worker 
631*4dc78e53SAndroid Build Coastguard Worker 		if (err < 0)
632*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_NOMEM;
633*4dc78e53SAndroid Build Coastguard Worker 
634*4dc78e53SAndroid Build Coastguard Worker 		nla_nest_end(msg, attr);
635*4dc78e53SAndroid Build Coastguard Worker 	}
636*4dc78e53SAndroid Build Coastguard Worker 
637*4dc78e53SAndroid Build Coastguard Worker 	nl_list_for_each_entry(e, list, e_list) {
638*4dc78e53SAndroid Build Coastguard Worker 		if (e->e_kind == TCF_EM_CONTAINER &&
639*4dc78e53SAndroid Build Coastguard Worker 		    fill_ematch_sequence(msg, &e->e_childs) < 0)
640*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_NOMEM;
641*4dc78e53SAndroid Build Coastguard Worker 	}
642*4dc78e53SAndroid Build Coastguard Worker 
643*4dc78e53SAndroid Build Coastguard Worker 	return 0;
644*4dc78e53SAndroid Build Coastguard Worker }
645*4dc78e53SAndroid Build Coastguard Worker 
rtnl_ematch_fill_attr(struct nl_msg * msg,int attrid,struct rtnl_ematch_tree * tree)646*4dc78e53SAndroid Build Coastguard Worker int rtnl_ematch_fill_attr(struct nl_msg *msg, int attrid,
647*4dc78e53SAndroid Build Coastguard Worker 			  struct rtnl_ematch_tree *tree)
648*4dc78e53SAndroid Build Coastguard Worker {
649*4dc78e53SAndroid Build Coastguard Worker 	struct tcf_ematch_tree_hdr thdr = {
650*4dc78e53SAndroid Build Coastguard Worker 		.progid = tree->et_progid,
651*4dc78e53SAndroid Build Coastguard Worker 	};
652*4dc78e53SAndroid Build Coastguard Worker 	struct nlattr *list, *topattr;
653*4dc78e53SAndroid Build Coastguard Worker 	int err, index = 0;
654*4dc78e53SAndroid Build Coastguard Worker 
655*4dc78e53SAndroid Build Coastguard Worker 	/* Assign index number to each ematch to allow for references
656*4dc78e53SAndroid Build Coastguard Worker 	 * to be made while constructing the sequence of matches. */
657*4dc78e53SAndroid Build Coastguard Worker 	err = update_container_index(&tree->et_list, &index);
658*4dc78e53SAndroid Build Coastguard Worker 	if (err < 0)
659*4dc78e53SAndroid Build Coastguard Worker 		return err;
660*4dc78e53SAndroid Build Coastguard Worker 
661*4dc78e53SAndroid Build Coastguard Worker 	if (!(topattr = nla_nest_start(msg, attrid)))
662*4dc78e53SAndroid Build Coastguard Worker 		goto nla_put_failure;
663*4dc78e53SAndroid Build Coastguard Worker 
664*4dc78e53SAndroid Build Coastguard Worker 	thdr.nmatches = index;
665*4dc78e53SAndroid Build Coastguard Worker 	NLA_PUT(msg, TCA_EMATCH_TREE_HDR, sizeof(thdr), &thdr);
666*4dc78e53SAndroid Build Coastguard Worker 
667*4dc78e53SAndroid Build Coastguard Worker 	if (!(list = nla_nest_start(msg, TCA_EMATCH_TREE_LIST)))
668*4dc78e53SAndroid Build Coastguard Worker 		goto nla_put_failure;
669*4dc78e53SAndroid Build Coastguard Worker 
670*4dc78e53SAndroid Build Coastguard Worker 	if (fill_ematch_sequence(msg, &tree->et_list) < 0)
671*4dc78e53SAndroid Build Coastguard Worker 		goto nla_put_failure;
672*4dc78e53SAndroid Build Coastguard Worker 
673*4dc78e53SAndroid Build Coastguard Worker 	nla_nest_end(msg, list);
674*4dc78e53SAndroid Build Coastguard Worker 
675*4dc78e53SAndroid Build Coastguard Worker 	nla_nest_end(msg, topattr);
676*4dc78e53SAndroid Build Coastguard Worker 
677*4dc78e53SAndroid Build Coastguard Worker 	return 0;
678*4dc78e53SAndroid Build Coastguard Worker 
679*4dc78e53SAndroid Build Coastguard Worker nla_put_failure:
680*4dc78e53SAndroid Build Coastguard Worker 	return -NLE_NOMEM;
681*4dc78e53SAndroid Build Coastguard Worker }
682*4dc78e53SAndroid Build Coastguard Worker 
683*4dc78e53SAndroid Build Coastguard Worker /** @} */
684*4dc78e53SAndroid Build Coastguard Worker 
685*4dc78e53SAndroid Build Coastguard Worker extern int ematch_parse(void *, char **, struct nl_list_head *);
686*4dc78e53SAndroid Build Coastguard Worker 
rtnl_ematch_parse_expr(const char * expr,char ** errp,struct rtnl_ematch_tree ** result)687*4dc78e53SAndroid Build Coastguard Worker int rtnl_ematch_parse_expr(const char *expr, char **errp,
688*4dc78e53SAndroid Build Coastguard Worker 			   struct rtnl_ematch_tree **result)
689*4dc78e53SAndroid Build Coastguard Worker {
690*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_ematch_tree *tree;
691*4dc78e53SAndroid Build Coastguard Worker 	YY_BUFFER_STATE buf = NULL;
692*4dc78e53SAndroid Build Coastguard Worker 	yyscan_t scanner = NULL;
693*4dc78e53SAndroid Build Coastguard Worker 	int err;
694*4dc78e53SAndroid Build Coastguard Worker 
695*4dc78e53SAndroid Build Coastguard Worker 	NL_DBG(2, "Parsing ematch expression \"%s\"\n", expr);
696*4dc78e53SAndroid Build Coastguard Worker 
697*4dc78e53SAndroid Build Coastguard Worker 	if (!(tree = rtnl_ematch_tree_alloc(RTNL_EMATCH_PROGID)))
698*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_FAILURE;
699*4dc78e53SAndroid Build Coastguard Worker 
700*4dc78e53SAndroid Build Coastguard Worker 	if (ematch_lex_init(&scanner) < 0) {
701*4dc78e53SAndroid Build Coastguard Worker 		err = -NLE_FAILURE;
702*4dc78e53SAndroid Build Coastguard Worker 		goto errout;
703*4dc78e53SAndroid Build Coastguard Worker 	}
704*4dc78e53SAndroid Build Coastguard Worker 
705*4dc78e53SAndroid Build Coastguard Worker 	buf = ematch__scan_string(expr, scanner);
706*4dc78e53SAndroid Build Coastguard Worker 
707*4dc78e53SAndroid Build Coastguard Worker 	if (ematch_parse(scanner, errp, &tree->et_list) != 0) {
708*4dc78e53SAndroid Build Coastguard Worker 		ematch__delete_buffer(buf, scanner);
709*4dc78e53SAndroid Build Coastguard Worker 		err = -NLE_PARSE_ERR;
710*4dc78e53SAndroid Build Coastguard Worker 		goto errout;
711*4dc78e53SAndroid Build Coastguard Worker 	}
712*4dc78e53SAndroid Build Coastguard Worker 
713*4dc78e53SAndroid Build Coastguard Worker 	ematch_lex_destroy(scanner);
714*4dc78e53SAndroid Build Coastguard Worker 	*result = tree;
715*4dc78e53SAndroid Build Coastguard Worker 
716*4dc78e53SAndroid Build Coastguard Worker 	return 0;
717*4dc78e53SAndroid Build Coastguard Worker 
718*4dc78e53SAndroid Build Coastguard Worker errout:
719*4dc78e53SAndroid Build Coastguard Worker 	if (scanner)
720*4dc78e53SAndroid Build Coastguard Worker 		ematch_lex_destroy(scanner);
721*4dc78e53SAndroid Build Coastguard Worker 
722*4dc78e53SAndroid Build Coastguard Worker 	rtnl_ematch_tree_free(tree);
723*4dc78e53SAndroid Build Coastguard Worker 
724*4dc78e53SAndroid Build Coastguard Worker 	return err;
725*4dc78e53SAndroid Build Coastguard Worker }
726*4dc78e53SAndroid Build Coastguard Worker 
727*4dc78e53SAndroid Build Coastguard Worker static const char *layer_txt[] = {
728*4dc78e53SAndroid Build Coastguard Worker 	[TCF_LAYER_LINK]	= "eth",
729*4dc78e53SAndroid Build Coastguard Worker 	[TCF_LAYER_NETWORK]	= "ip",
730*4dc78e53SAndroid Build Coastguard Worker 	[TCF_LAYER_TRANSPORT]	= "tcp",
731*4dc78e53SAndroid Build Coastguard Worker };
732*4dc78e53SAndroid Build Coastguard Worker 
rtnl_ematch_offset2txt(uint8_t layer,uint16_t offset,char * buf,size_t len)733*4dc78e53SAndroid Build Coastguard Worker char *rtnl_ematch_offset2txt(uint8_t layer, uint16_t offset, char *buf, size_t len)
734*4dc78e53SAndroid Build Coastguard Worker {
735*4dc78e53SAndroid Build Coastguard Worker 	snprintf(buf, len, "%s+%u",
736*4dc78e53SAndroid Build Coastguard Worker 		 (layer <= TCF_LAYER_MAX) ? layer_txt[layer] : "?",
737*4dc78e53SAndroid Build Coastguard Worker 		 offset);
738*4dc78e53SAndroid Build Coastguard Worker 
739*4dc78e53SAndroid Build Coastguard Worker 	return buf;
740*4dc78e53SAndroid Build Coastguard Worker }
741*4dc78e53SAndroid Build Coastguard Worker 
742*4dc78e53SAndroid Build Coastguard Worker static const char *operand_txt[] = {
743*4dc78e53SAndroid Build Coastguard Worker 	[TCF_EM_OPND_EQ] = "=",
744*4dc78e53SAndroid Build Coastguard Worker 	[TCF_EM_OPND_LT] = "<",
745*4dc78e53SAndroid Build Coastguard Worker 	[TCF_EM_OPND_GT] = ">",
746*4dc78e53SAndroid Build Coastguard Worker };
747*4dc78e53SAndroid Build Coastguard Worker 
rtnl_ematch_opnd2txt(uint8_t opnd,char * buf,size_t len)748*4dc78e53SAndroid Build Coastguard Worker char *rtnl_ematch_opnd2txt(uint8_t opnd, char *buf, size_t len)
749*4dc78e53SAndroid Build Coastguard Worker {
750*4dc78e53SAndroid Build Coastguard Worker 	snprintf(buf, len, "%s",
751*4dc78e53SAndroid Build Coastguard Worker 		opnd < ARRAY_SIZE(operand_txt) ? operand_txt[opnd] : "?");
752*4dc78e53SAndroid Build Coastguard Worker 
753*4dc78e53SAndroid Build Coastguard Worker 	return buf;
754*4dc78e53SAndroid Build Coastguard Worker }
755*4dc78e53SAndroid Build Coastguard Worker 
756*4dc78e53SAndroid Build Coastguard Worker /** @} */
757