xref: /aosp_15_r20/external/libnl/lib/route/cls/u32.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) 2003-2013 Thomas Graf <[email protected]>
4*4dc78e53SAndroid Build Coastguard Worker  * Copyright (c) 2005-2006 Petr Gotthard <[email protected]>
5*4dc78e53SAndroid Build Coastguard Worker  * Copyright (c) 2005-2006 Siemens AG Oesterreich
6*4dc78e53SAndroid Build Coastguard Worker  */
7*4dc78e53SAndroid Build Coastguard Worker 
8*4dc78e53SAndroid Build Coastguard Worker /**
9*4dc78e53SAndroid Build Coastguard Worker  * @ingroup cls
10*4dc78e53SAndroid Build Coastguard Worker  * @defgroup cls_u32 Universal 32-bit Classifier
11*4dc78e53SAndroid Build Coastguard Worker  *
12*4dc78e53SAndroid Build Coastguard Worker  * @{
13*4dc78e53SAndroid Build Coastguard Worker  */
14*4dc78e53SAndroid Build Coastguard Worker 
15*4dc78e53SAndroid Build Coastguard Worker #include "nl-default.h"
16*4dc78e53SAndroid Build Coastguard Worker 
17*4dc78e53SAndroid Build Coastguard Worker #include <netlink/netlink.h>
18*4dc78e53SAndroid Build Coastguard Worker #include <netlink/attr.h>
19*4dc78e53SAndroid Build Coastguard Worker #include <netlink/utils.h>
20*4dc78e53SAndroid Build Coastguard Worker #include <netlink/route/classifier.h>
21*4dc78e53SAndroid Build Coastguard Worker #include <netlink/route/cls/u32.h>
22*4dc78e53SAndroid Build Coastguard Worker #include <netlink/route/action.h>
23*4dc78e53SAndroid Build Coastguard Worker 
24*4dc78e53SAndroid Build Coastguard Worker #include "tc-api.h"
25*4dc78e53SAndroid Build Coastguard Worker #include "nl-aux-route/nl-route.h"
26*4dc78e53SAndroid Build Coastguard Worker 
27*4dc78e53SAndroid Build Coastguard Worker /** @cond SKIP */
28*4dc78e53SAndroid Build Coastguard Worker struct rtnl_u32 {
29*4dc78e53SAndroid Build Coastguard Worker 	uint32_t cu_divisor;
30*4dc78e53SAndroid Build Coastguard Worker 	uint32_t cu_hash;
31*4dc78e53SAndroid Build Coastguard Worker 	uint32_t cu_classid;
32*4dc78e53SAndroid Build Coastguard Worker 	uint32_t cu_link;
33*4dc78e53SAndroid Build Coastguard Worker 	struct nl_data *cu_pcnt;
34*4dc78e53SAndroid Build Coastguard Worker 	struct nl_data *cu_selector;
35*4dc78e53SAndroid Build Coastguard Worker 	struct nl_data *cu_mark;
36*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_act *cu_act;
37*4dc78e53SAndroid Build Coastguard Worker 	struct nl_data *cu_police;
38*4dc78e53SAndroid Build Coastguard Worker 	char cu_indev[IFNAMSIZ];
39*4dc78e53SAndroid Build Coastguard Worker 	int cu_mask;
40*4dc78e53SAndroid Build Coastguard Worker };
41*4dc78e53SAndroid Build Coastguard Worker 
42*4dc78e53SAndroid Build Coastguard Worker #define U32_ATTR_DIVISOR      0x001
43*4dc78e53SAndroid Build Coastguard Worker #define U32_ATTR_HASH         0x002
44*4dc78e53SAndroid Build Coastguard Worker #define U32_ATTR_CLASSID      0x004
45*4dc78e53SAndroid Build Coastguard Worker #define U32_ATTR_LINK         0x008
46*4dc78e53SAndroid Build Coastguard Worker #define U32_ATTR_PCNT         0x010
47*4dc78e53SAndroid Build Coastguard Worker #define U32_ATTR_SELECTOR     0x020
48*4dc78e53SAndroid Build Coastguard Worker #define U32_ATTR_ACTION       0x040
49*4dc78e53SAndroid Build Coastguard Worker #define U32_ATTR_POLICE       0x080
50*4dc78e53SAndroid Build Coastguard Worker #define U32_ATTR_INDEV        0x100
51*4dc78e53SAndroid Build Coastguard Worker #define U32_ATTR_MARK	      0x200
52*4dc78e53SAndroid Build Coastguard Worker /** @endcond */
53*4dc78e53SAndroid Build Coastguard Worker 
u32_selector(struct rtnl_u32 * u)54*4dc78e53SAndroid Build Coastguard Worker static inline struct tc_u32_sel *u32_selector(struct rtnl_u32 *u)
55*4dc78e53SAndroid Build Coastguard Worker {
56*4dc78e53SAndroid Build Coastguard Worker 	return (struct tc_u32_sel *) u->cu_selector->d_data;
57*4dc78e53SAndroid Build Coastguard Worker }
58*4dc78e53SAndroid Build Coastguard Worker 
u32_selector_alloc(struct rtnl_u32 * u)59*4dc78e53SAndroid Build Coastguard Worker static inline struct tc_u32_sel *u32_selector_alloc(struct rtnl_u32 *u)
60*4dc78e53SAndroid Build Coastguard Worker {
61*4dc78e53SAndroid Build Coastguard Worker 	if (!u->cu_selector)
62*4dc78e53SAndroid Build Coastguard Worker 		u->cu_selector = nl_data_alloc(NULL, sizeof(struct tc_u32_sel));
63*4dc78e53SAndroid Build Coastguard Worker 
64*4dc78e53SAndroid Build Coastguard Worker 	return u32_selector(u);
65*4dc78e53SAndroid Build Coastguard Worker }
66*4dc78e53SAndroid Build Coastguard Worker 
u32_mark_alloc(struct rtnl_u32 * u)67*4dc78e53SAndroid Build Coastguard Worker static inline struct tc_u32_mark *u32_mark_alloc(struct rtnl_u32 *u)
68*4dc78e53SAndroid Build Coastguard Worker {
69*4dc78e53SAndroid Build Coastguard Worker 	if (!u->cu_mark)
70*4dc78e53SAndroid Build Coastguard Worker 		u->cu_mark = nl_data_alloc(NULL, sizeof(struct tc_u32_mark));
71*4dc78e53SAndroid Build Coastguard Worker 
72*4dc78e53SAndroid Build Coastguard Worker 	return (struct tc_u32_mark *) u->cu_mark->d_data;
73*4dc78e53SAndroid Build Coastguard Worker }
74*4dc78e53SAndroid Build Coastguard Worker 
75*4dc78e53SAndroid Build Coastguard Worker static struct nla_policy u32_policy[TCA_U32_MAX+1] = {
76*4dc78e53SAndroid Build Coastguard Worker 	[TCA_U32_DIVISOR]	= { .type = NLA_U32 },
77*4dc78e53SAndroid Build Coastguard Worker 	[TCA_U32_HASH]		= { .type = NLA_U32 },
78*4dc78e53SAndroid Build Coastguard Worker 	[TCA_U32_CLASSID]	= { .type = NLA_U32 },
79*4dc78e53SAndroid Build Coastguard Worker 	[TCA_U32_LINK]		= { .type = NLA_U32 },
80*4dc78e53SAndroid Build Coastguard Worker 	[TCA_U32_INDEV]		= { .type = NLA_STRING,
81*4dc78e53SAndroid Build Coastguard Worker 				    .maxlen = IFNAMSIZ },
82*4dc78e53SAndroid Build Coastguard Worker 	[TCA_U32_SEL]		= { .minlen = sizeof(struct tc_u32_sel) },
83*4dc78e53SAndroid Build Coastguard Worker 	[TCA_U32_PCNT]		= { .minlen = sizeof(struct tc_u32_pcnt) },
84*4dc78e53SAndroid Build Coastguard Worker 	[TCA_U32_MARK]		= { .minlen = sizeof(struct tc_u32_mark) }
85*4dc78e53SAndroid Build Coastguard Worker };
86*4dc78e53SAndroid Build Coastguard Worker 
u32_msg_parser(struct rtnl_tc * tc,void * data)87*4dc78e53SAndroid Build Coastguard Worker static int u32_msg_parser(struct rtnl_tc *tc, void *data)
88*4dc78e53SAndroid Build Coastguard Worker {
89*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_u32 *u = data;
90*4dc78e53SAndroid Build Coastguard Worker 	struct nlattr *tb[TCA_U32_MAX + 1];
91*4dc78e53SAndroid Build Coastguard Worker 	int err;
92*4dc78e53SAndroid Build Coastguard Worker 
93*4dc78e53SAndroid Build Coastguard Worker 	err = tca_parse(tb, TCA_U32_MAX, tc, u32_policy);
94*4dc78e53SAndroid Build Coastguard Worker 	if (err < 0)
95*4dc78e53SAndroid Build Coastguard Worker 		return err;
96*4dc78e53SAndroid Build Coastguard Worker 
97*4dc78e53SAndroid Build Coastguard Worker 	if (tb[TCA_U32_DIVISOR]) {
98*4dc78e53SAndroid Build Coastguard Worker 		u->cu_divisor = nla_get_u32(tb[TCA_U32_DIVISOR]);
99*4dc78e53SAndroid Build Coastguard Worker 		u->cu_mask |= U32_ATTR_DIVISOR;
100*4dc78e53SAndroid Build Coastguard Worker 	}
101*4dc78e53SAndroid Build Coastguard Worker 
102*4dc78e53SAndroid Build Coastguard Worker 	if (tb[TCA_U32_SEL]) {
103*4dc78e53SAndroid Build Coastguard Worker 		u->cu_selector = nl_data_alloc_attr(tb[TCA_U32_SEL]);
104*4dc78e53SAndroid Build Coastguard Worker 		if (!u->cu_selector)
105*4dc78e53SAndroid Build Coastguard Worker 			goto errout_nomem;
106*4dc78e53SAndroid Build Coastguard Worker 		u->cu_mask |= U32_ATTR_SELECTOR;
107*4dc78e53SAndroid Build Coastguard Worker 	}
108*4dc78e53SAndroid Build Coastguard Worker 
109*4dc78e53SAndroid Build Coastguard Worker 	if (tb[TCA_U32_MARK]) {
110*4dc78e53SAndroid Build Coastguard Worker 		u->cu_mark = nl_data_alloc_attr(tb[TCA_U32_MARK]);
111*4dc78e53SAndroid Build Coastguard Worker 		if (!u->cu_mark)
112*4dc78e53SAndroid Build Coastguard Worker 			goto errout_nomem;
113*4dc78e53SAndroid Build Coastguard Worker 		u->cu_mask |= U32_ATTR_MARK;
114*4dc78e53SAndroid Build Coastguard Worker 	}
115*4dc78e53SAndroid Build Coastguard Worker 
116*4dc78e53SAndroid Build Coastguard Worker 	if (tb[TCA_U32_HASH]) {
117*4dc78e53SAndroid Build Coastguard Worker 		u->cu_hash = nla_get_u32(tb[TCA_U32_HASH]);
118*4dc78e53SAndroid Build Coastguard Worker 		u->cu_mask |= U32_ATTR_HASH;
119*4dc78e53SAndroid Build Coastguard Worker 	}
120*4dc78e53SAndroid Build Coastguard Worker 
121*4dc78e53SAndroid Build Coastguard Worker 	if (tb[TCA_U32_CLASSID]) {
122*4dc78e53SAndroid Build Coastguard Worker 		u->cu_classid = nla_get_u32(tb[TCA_U32_CLASSID]);
123*4dc78e53SAndroid Build Coastguard Worker 		u->cu_mask |= U32_ATTR_CLASSID;
124*4dc78e53SAndroid Build Coastguard Worker 	}
125*4dc78e53SAndroid Build Coastguard Worker 
126*4dc78e53SAndroid Build Coastguard Worker 	if (tb[TCA_U32_LINK]) {
127*4dc78e53SAndroid Build Coastguard Worker 		u->cu_link = nla_get_u32(tb[TCA_U32_LINK]);
128*4dc78e53SAndroid Build Coastguard Worker 		u->cu_mask |= U32_ATTR_LINK;
129*4dc78e53SAndroid Build Coastguard Worker 	}
130*4dc78e53SAndroid Build Coastguard Worker 
131*4dc78e53SAndroid Build Coastguard Worker 	if (tb[TCA_U32_ACT]) {
132*4dc78e53SAndroid Build Coastguard Worker 		u->cu_mask |= U32_ATTR_ACTION;
133*4dc78e53SAndroid Build Coastguard Worker 		err = rtnl_act_parse(&u->cu_act, tb[TCA_U32_ACT]);
134*4dc78e53SAndroid Build Coastguard Worker 		if (err < 0)
135*4dc78e53SAndroid Build Coastguard Worker 			return err;
136*4dc78e53SAndroid Build Coastguard Worker 	}
137*4dc78e53SAndroid Build Coastguard Worker 
138*4dc78e53SAndroid Build Coastguard Worker 	if (tb[TCA_U32_POLICE]) {
139*4dc78e53SAndroid Build Coastguard Worker 		u->cu_police = nl_data_alloc_attr(tb[TCA_U32_POLICE]);
140*4dc78e53SAndroid Build Coastguard Worker 		if (!u->cu_police)
141*4dc78e53SAndroid Build Coastguard Worker 			goto errout_nomem;
142*4dc78e53SAndroid Build Coastguard Worker 		u->cu_mask |= U32_ATTR_POLICE;
143*4dc78e53SAndroid Build Coastguard Worker 	}
144*4dc78e53SAndroid Build Coastguard Worker 
145*4dc78e53SAndroid Build Coastguard Worker 	if (tb[TCA_U32_PCNT]) {
146*4dc78e53SAndroid Build Coastguard Worker 		struct tc_u32_sel *sel;
147*4dc78e53SAndroid Build Coastguard Worker 		size_t pcnt_size;
148*4dc78e53SAndroid Build Coastguard Worker 
149*4dc78e53SAndroid Build Coastguard Worker 		if (!tb[TCA_U32_SEL]) {
150*4dc78e53SAndroid Build Coastguard Worker 			err = -NLE_MISSING_ATTR;
151*4dc78e53SAndroid Build Coastguard Worker 			goto errout;
152*4dc78e53SAndroid Build Coastguard Worker 		}
153*4dc78e53SAndroid Build Coastguard Worker 
154*4dc78e53SAndroid Build Coastguard Worker 		sel = u->cu_selector->d_data;
155*4dc78e53SAndroid Build Coastguard Worker 		pcnt_size = sizeof(struct tc_u32_pcnt) +
156*4dc78e53SAndroid Build Coastguard Worker 				(sel->nkeys * sizeof(uint64_t));
157*4dc78e53SAndroid Build Coastguard Worker 		if (_nla_len(tb[TCA_U32_PCNT]) < pcnt_size) {
158*4dc78e53SAndroid Build Coastguard Worker 			err = -NLE_INVAL;
159*4dc78e53SAndroid Build Coastguard Worker 			goto errout;
160*4dc78e53SAndroid Build Coastguard Worker 		}
161*4dc78e53SAndroid Build Coastguard Worker 
162*4dc78e53SAndroid Build Coastguard Worker 		u->cu_pcnt = nl_data_alloc_attr(tb[TCA_U32_PCNT]);
163*4dc78e53SAndroid Build Coastguard Worker 		if (!u->cu_pcnt)
164*4dc78e53SAndroid Build Coastguard Worker 			goto errout_nomem;
165*4dc78e53SAndroid Build Coastguard Worker 		u->cu_mask |= U32_ATTR_PCNT;
166*4dc78e53SAndroid Build Coastguard Worker 	}
167*4dc78e53SAndroid Build Coastguard Worker 
168*4dc78e53SAndroid Build Coastguard Worker 	if (tb[TCA_U32_INDEV]) {
169*4dc78e53SAndroid Build Coastguard Worker 		nla_strlcpy(u->cu_indev, tb[TCA_U32_INDEV], IFNAMSIZ);
170*4dc78e53SAndroid Build Coastguard Worker 		u->cu_mask |= U32_ATTR_INDEV;
171*4dc78e53SAndroid Build Coastguard Worker 	}
172*4dc78e53SAndroid Build Coastguard Worker 
173*4dc78e53SAndroid Build Coastguard Worker 	return 0;
174*4dc78e53SAndroid Build Coastguard Worker 
175*4dc78e53SAndroid Build Coastguard Worker errout_nomem:
176*4dc78e53SAndroid Build Coastguard Worker 	err = -NLE_NOMEM;
177*4dc78e53SAndroid Build Coastguard Worker errout:
178*4dc78e53SAndroid Build Coastguard Worker 	return err;
179*4dc78e53SAndroid Build Coastguard Worker }
180*4dc78e53SAndroid Build Coastguard Worker 
u32_free_data(struct rtnl_tc * tc,void * data)181*4dc78e53SAndroid Build Coastguard Worker static void u32_free_data(struct rtnl_tc *tc, void *data)
182*4dc78e53SAndroid Build Coastguard Worker {
183*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_u32 *u = data;
184*4dc78e53SAndroid Build Coastguard Worker 
185*4dc78e53SAndroid Build Coastguard Worker 	if (u->cu_act)
186*4dc78e53SAndroid Build Coastguard Worker 		rtnl_act_put_all(&u->cu_act);
187*4dc78e53SAndroid Build Coastguard Worker 	nl_data_free(u->cu_mark);
188*4dc78e53SAndroid Build Coastguard Worker 	nl_data_free(u->cu_selector);
189*4dc78e53SAndroid Build Coastguard Worker 	nl_data_free(u->cu_police);
190*4dc78e53SAndroid Build Coastguard Worker 	nl_data_free(u->cu_pcnt);
191*4dc78e53SAndroid Build Coastguard Worker }
192*4dc78e53SAndroid Build Coastguard Worker 
u32_clone(void * _dst,void * _src)193*4dc78e53SAndroid Build Coastguard Worker static int u32_clone(void *_dst, void *_src)
194*4dc78e53SAndroid Build Coastguard Worker {
195*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_u32 *dst = _dst, *src = _src;
196*4dc78e53SAndroid Build Coastguard Worker 	_nl_auto_nl_data struct nl_data *selector = NULL;
197*4dc78e53SAndroid Build Coastguard Worker 	_nl_auto_nl_data struct nl_data *mark = NULL;
198*4dc78e53SAndroid Build Coastguard Worker 	_nl_auto_nl_data struct nl_data *police = NULL;
199*4dc78e53SAndroid Build Coastguard Worker 	_nl_auto_nl_data struct nl_data *pcnt = NULL;
200*4dc78e53SAndroid Build Coastguard Worker 	_nl_auto_nl_data struct nl_data *opts = NULL;
201*4dc78e53SAndroid Build Coastguard Worker 	_nl_auto_nl_data struct nl_data *xstats = NULL;
202*4dc78e53SAndroid Build Coastguard Worker 	_nl_auto_nl_data struct nl_data *subdata = NULL;
203*4dc78e53SAndroid Build Coastguard Worker 	_nl_auto_rtnl_act struct rtnl_act *act = NULL;
204*4dc78e53SAndroid Build Coastguard Worker 
205*4dc78e53SAndroid Build Coastguard Worker 	dst->cu_pcnt = NULL;
206*4dc78e53SAndroid Build Coastguard Worker 	dst->cu_selector = NULL;
207*4dc78e53SAndroid Build Coastguard Worker 	dst->cu_mark = NULL;
208*4dc78e53SAndroid Build Coastguard Worker 	dst->cu_act = NULL;
209*4dc78e53SAndroid Build Coastguard Worker 	dst->cu_police = NULL;
210*4dc78e53SAndroid Build Coastguard Worker 
211*4dc78e53SAndroid Build Coastguard Worker 	if (src->cu_selector) {
212*4dc78e53SAndroid Build Coastguard Worker 		if (!(selector = nl_data_clone(src->cu_selector)))
213*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_NOMEM;
214*4dc78e53SAndroid Build Coastguard Worker 	}
215*4dc78e53SAndroid Build Coastguard Worker 
216*4dc78e53SAndroid Build Coastguard Worker 	if (src->cu_mark) {
217*4dc78e53SAndroid Build Coastguard Worker 		if (!(mark = nl_data_clone(src->cu_mark)))
218*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_NOMEM;
219*4dc78e53SAndroid Build Coastguard Worker 	}
220*4dc78e53SAndroid Build Coastguard Worker 
221*4dc78e53SAndroid Build Coastguard Worker 	if (src->cu_act) {
222*4dc78e53SAndroid Build Coastguard Worker 		if (!(act = rtnl_act_alloc()))
223*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_NOMEM;
224*4dc78e53SAndroid Build Coastguard Worker 
225*4dc78e53SAndroid Build Coastguard Worker 		if (src->cu_act->c_opts) {
226*4dc78e53SAndroid Build Coastguard Worker 			if (!(opts = nl_data_clone(src->cu_act->c_opts)))
227*4dc78e53SAndroid Build Coastguard Worker 				return -NLE_NOMEM;
228*4dc78e53SAndroid Build Coastguard Worker 		}
229*4dc78e53SAndroid Build Coastguard Worker 
230*4dc78e53SAndroid Build Coastguard Worker 		if (src->cu_act->c_xstats) {
231*4dc78e53SAndroid Build Coastguard Worker 			if (!(xstats = nl_data_clone(src->cu_act->c_xstats)))
232*4dc78e53SAndroid Build Coastguard Worker 				return -NLE_NOMEM;
233*4dc78e53SAndroid Build Coastguard Worker 		}
234*4dc78e53SAndroid Build Coastguard Worker 
235*4dc78e53SAndroid Build Coastguard Worker 		if (src->cu_act->c_subdata) {
236*4dc78e53SAndroid Build Coastguard Worker 			if (!(subdata = nl_data_clone(src->cu_act->c_subdata)))
237*4dc78e53SAndroid Build Coastguard Worker 				return -NLE_NOMEM;
238*4dc78e53SAndroid Build Coastguard Worker 		}
239*4dc78e53SAndroid Build Coastguard Worker 	}
240*4dc78e53SAndroid Build Coastguard Worker 
241*4dc78e53SAndroid Build Coastguard Worker 	if (src->cu_police) {
242*4dc78e53SAndroid Build Coastguard Worker 		if (!(police = nl_data_clone(src->cu_police)))
243*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_NOMEM;
244*4dc78e53SAndroid Build Coastguard Worker 	}
245*4dc78e53SAndroid Build Coastguard Worker 
246*4dc78e53SAndroid Build Coastguard Worker 	if (src->cu_pcnt) {
247*4dc78e53SAndroid Build Coastguard Worker 		if (!(pcnt = nl_data_clone(src->cu_pcnt)))
248*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_NOMEM;
249*4dc78e53SAndroid Build Coastguard Worker 	}
250*4dc78e53SAndroid Build Coastguard Worker 
251*4dc78e53SAndroid Build Coastguard Worker 	/* we've passed the critical point and its safe to proceed */
252*4dc78e53SAndroid Build Coastguard Worker 
253*4dc78e53SAndroid Build Coastguard Worker 	if (selector)
254*4dc78e53SAndroid Build Coastguard Worker 		dst->cu_selector = _nl_steal_pointer(&selector);
255*4dc78e53SAndroid Build Coastguard Worker 
256*4dc78e53SAndroid Build Coastguard Worker 	if (mark)
257*4dc78e53SAndroid Build Coastguard Worker 		dst->cu_mark = _nl_steal_pointer(&mark);
258*4dc78e53SAndroid Build Coastguard Worker 
259*4dc78e53SAndroid Build Coastguard Worker 	if (police)
260*4dc78e53SAndroid Build Coastguard Worker 		dst->cu_police = _nl_steal_pointer(&police);
261*4dc78e53SAndroid Build Coastguard Worker 
262*4dc78e53SAndroid Build Coastguard Worker 	if (pcnt)
263*4dc78e53SAndroid Build Coastguard Worker 		dst->cu_pcnt = _nl_steal_pointer(&pcnt);
264*4dc78e53SAndroid Build Coastguard Worker 
265*4dc78e53SAndroid Build Coastguard Worker 	if (act) {
266*4dc78e53SAndroid Build Coastguard Worker 		dst->cu_act = _nl_steal_pointer(&act);
267*4dc78e53SAndroid Build Coastguard Worker 
268*4dc78e53SAndroid Build Coastguard Worker 		/* action nl list next and prev pointers must be updated */
269*4dc78e53SAndroid Build Coastguard Worker 		nl_init_list_head(&dst->cu_act->ce_list);
270*4dc78e53SAndroid Build Coastguard Worker 
271*4dc78e53SAndroid Build Coastguard Worker 		if (opts)
272*4dc78e53SAndroid Build Coastguard Worker 			dst->cu_act->c_opts = _nl_steal_pointer(&opts);
273*4dc78e53SAndroid Build Coastguard Worker 
274*4dc78e53SAndroid Build Coastguard Worker 		if (xstats)
275*4dc78e53SAndroid Build Coastguard Worker 			dst->cu_act->c_xstats = _nl_steal_pointer(&xstats);
276*4dc78e53SAndroid Build Coastguard Worker 
277*4dc78e53SAndroid Build Coastguard Worker 		if (subdata)
278*4dc78e53SAndroid Build Coastguard Worker 			dst->cu_act->c_subdata = _nl_steal_pointer(&subdata);
279*4dc78e53SAndroid Build Coastguard Worker 
280*4dc78e53SAndroid Build Coastguard Worker 		if (dst->cu_act->c_link) {
281*4dc78e53SAndroid Build Coastguard Worker 			nl_object_get(OBJ_CAST(dst->cu_act->c_link));
282*4dc78e53SAndroid Build Coastguard Worker 		}
283*4dc78e53SAndroid Build Coastguard Worker 
284*4dc78e53SAndroid Build Coastguard Worker 		dst->cu_act->a_next = NULL;   /* Only clone first in chain */
285*4dc78e53SAndroid Build Coastguard Worker 	}
286*4dc78e53SAndroid Build Coastguard Worker 
287*4dc78e53SAndroid Build Coastguard Worker 	return 0;
288*4dc78e53SAndroid Build Coastguard Worker }
289*4dc78e53SAndroid Build Coastguard Worker 
u32_dump_line(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)290*4dc78e53SAndroid Build Coastguard Worker static void u32_dump_line(struct rtnl_tc *tc, void *data,
291*4dc78e53SAndroid Build Coastguard Worker 			  struct nl_dump_params *p)
292*4dc78e53SAndroid Build Coastguard Worker {
293*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_u32 *u = data;
294*4dc78e53SAndroid Build Coastguard Worker 	char buf[32];
295*4dc78e53SAndroid Build Coastguard Worker 
296*4dc78e53SAndroid Build Coastguard Worker 	if (!u)
297*4dc78e53SAndroid Build Coastguard Worker 		return;
298*4dc78e53SAndroid Build Coastguard Worker 
299*4dc78e53SAndroid Build Coastguard Worker 	if (u->cu_mask & U32_ATTR_DIVISOR)
300*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, " divisor %u", u->cu_divisor);
301*4dc78e53SAndroid Build Coastguard Worker 	else if (u->cu_mask & U32_ATTR_CLASSID)
302*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, " target %s",
303*4dc78e53SAndroid Build Coastguard Worker 			rtnl_tc_handle2str(u->cu_classid, buf, sizeof(buf)));
304*4dc78e53SAndroid Build Coastguard Worker }
305*4dc78e53SAndroid Build Coastguard Worker 
print_selector(struct nl_dump_params * p,struct tc_u32_sel * sel,struct rtnl_u32 * u)306*4dc78e53SAndroid Build Coastguard Worker static void print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel,
307*4dc78e53SAndroid Build Coastguard Worker 			   struct rtnl_u32 *u)
308*4dc78e53SAndroid Build Coastguard Worker {
309*4dc78e53SAndroid Build Coastguard Worker 	int i;
310*4dc78e53SAndroid Build Coastguard Worker 	struct tc_u32_key *key;
311*4dc78e53SAndroid Build Coastguard Worker 
312*4dc78e53SAndroid Build Coastguard Worker 	if (sel->hmask || sel->hoff) {
313*4dc78e53SAndroid Build Coastguard Worker 		/* I guess this will never be used since the kernel only
314*4dc78e53SAndroid Build Coastguard Worker 		 * exports the selector if no divisor is set but hash offset
315*4dc78e53SAndroid Build Coastguard Worker 		 * and hash mask make only sense in hash filters with divisor
316*4dc78e53SAndroid Build Coastguard Worker 		 * set */
317*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, " hash at %u & 0x%x", sel->hoff, sel->hmask);
318*4dc78e53SAndroid Build Coastguard Worker 	}
319*4dc78e53SAndroid Build Coastguard Worker 
320*4dc78e53SAndroid Build Coastguard Worker 	if (sel->flags & (TC_U32_OFFSET | TC_U32_VAROFFSET)) {
321*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, " offset at %u", sel->off);
322*4dc78e53SAndroid Build Coastguard Worker 
323*4dc78e53SAndroid Build Coastguard Worker 		if (sel->flags & TC_U32_VAROFFSET)
324*4dc78e53SAndroid Build Coastguard Worker 			nl_dump(p, " variable (at %u & 0x%x) >> %u",
325*4dc78e53SAndroid Build Coastguard Worker 				sel->offoff, ntohs(sel->offmask), sel->offshift);
326*4dc78e53SAndroid Build Coastguard Worker 	}
327*4dc78e53SAndroid Build Coastguard Worker 
328*4dc78e53SAndroid Build Coastguard Worker 	if (sel->flags) {
329*4dc78e53SAndroid Build Coastguard Worker 		int flags = sel->flags;
330*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, " <");
331*4dc78e53SAndroid Build Coastguard Worker 
332*4dc78e53SAndroid Build Coastguard Worker #define PRINT_FLAG(f) if (flags & TC_U32_##f) { \
333*4dc78e53SAndroid Build Coastguard Worker 	flags &= ~TC_U32_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
334*4dc78e53SAndroid Build Coastguard Worker 
335*4dc78e53SAndroid Build Coastguard Worker 		PRINT_FLAG(TERMINAL);
336*4dc78e53SAndroid Build Coastguard Worker 		PRINT_FLAG(OFFSET);
337*4dc78e53SAndroid Build Coastguard Worker 		PRINT_FLAG(VAROFFSET);
338*4dc78e53SAndroid Build Coastguard Worker 		PRINT_FLAG(EAT);
339*4dc78e53SAndroid Build Coastguard Worker #undef PRINT_FLAG
340*4dc78e53SAndroid Build Coastguard Worker 
341*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, ">");
342*4dc78e53SAndroid Build Coastguard Worker 	}
343*4dc78e53SAndroid Build Coastguard Worker 
344*4dc78e53SAndroid Build Coastguard Worker 
345*4dc78e53SAndroid Build Coastguard Worker 	for (i = 0; i < sel->nkeys; i++) {
346*4dc78e53SAndroid Build Coastguard Worker 		key = &sel->keys[i];
347*4dc78e53SAndroid Build Coastguard Worker 
348*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, "\n");
349*4dc78e53SAndroid Build Coastguard Worker 		nl_dump_line(p, "      match key at %s%u ",
350*4dc78e53SAndroid Build Coastguard Worker 			key->offmask ? "nexthdr+" : "", key->off);
351*4dc78e53SAndroid Build Coastguard Worker 
352*4dc78e53SAndroid Build Coastguard Worker 		if (key->offmask)
353*4dc78e53SAndroid Build Coastguard Worker 			nl_dump(p, "[0x%u] ", key->offmask);
354*4dc78e53SAndroid Build Coastguard Worker 
355*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, "& 0x%08x == 0x%08x", ntohl(key->mask), ntohl(key->val));
356*4dc78e53SAndroid Build Coastguard Worker 
357*4dc78e53SAndroid Build Coastguard Worker 		if (p->dp_type == NL_DUMP_STATS &&
358*4dc78e53SAndroid Build Coastguard Worker 		    (u->cu_mask & U32_ATTR_PCNT)) {
359*4dc78e53SAndroid Build Coastguard Worker 			struct tc_u32_pcnt *pcnt = u->cu_pcnt->d_data;
360*4dc78e53SAndroid Build Coastguard Worker 
361*4dc78e53SAndroid Build Coastguard Worker 			nl_dump(p, " successful %llu",
362*4dc78e53SAndroid Build Coastguard Worker 				(long long unsigned)pcnt->kcnts[i]);
363*4dc78e53SAndroid Build Coastguard Worker 		}
364*4dc78e53SAndroid Build Coastguard Worker 	}
365*4dc78e53SAndroid Build Coastguard Worker }
366*4dc78e53SAndroid Build Coastguard Worker 
u32_dump_details(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)367*4dc78e53SAndroid Build Coastguard Worker static void u32_dump_details(struct rtnl_tc *tc, void *data,
368*4dc78e53SAndroid Build Coastguard Worker 			     struct nl_dump_params *p)
369*4dc78e53SAndroid Build Coastguard Worker {
370*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_u32 *u = data;
371*4dc78e53SAndroid Build Coastguard Worker 	struct tc_u32_sel *s = NULL;
372*4dc78e53SAndroid Build Coastguard Worker 	struct tc_u32_mark *m;
373*4dc78e53SAndroid Build Coastguard Worker 
374*4dc78e53SAndroid Build Coastguard Worker 	if (!u)
375*4dc78e53SAndroid Build Coastguard Worker 		return;
376*4dc78e53SAndroid Build Coastguard Worker 
377*4dc78e53SAndroid Build Coastguard Worker 	if (!(u->cu_mask & U32_ATTR_SELECTOR)) {
378*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, "no-selector");
379*4dc78e53SAndroid Build Coastguard Worker 	} else {
380*4dc78e53SAndroid Build Coastguard Worker 		s = u->cu_selector->d_data;
381*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, "nkeys %u", s->nkeys);
382*4dc78e53SAndroid Build Coastguard Worker 	}
383*4dc78e53SAndroid Build Coastguard Worker 
384*4dc78e53SAndroid Build Coastguard Worker 	if (!(u->cu_mask & U32_ATTR_MARK)) {
385*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, " no-mark");
386*4dc78e53SAndroid Build Coastguard Worker 	} else {
387*4dc78e53SAndroid Build Coastguard Worker 		m = u->cu_mark->d_data;
388*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, " mark 0x%u 0x%u", m->val, m->mask);
389*4dc78e53SAndroid Build Coastguard Worker 	}
390*4dc78e53SAndroid Build Coastguard Worker 
391*4dc78e53SAndroid Build Coastguard Worker 	if (u->cu_mask & U32_ATTR_HASH)
392*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, " ht key 0x%x hash 0x%u",
393*4dc78e53SAndroid Build Coastguard Worker 			TC_U32_USERHTID(u->cu_hash), TC_U32_HASH(u->cu_hash));
394*4dc78e53SAndroid Build Coastguard Worker 
395*4dc78e53SAndroid Build Coastguard Worker 	if (u->cu_mask & U32_ATTR_LINK)
396*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, " link %u", u->cu_link);
397*4dc78e53SAndroid Build Coastguard Worker 
398*4dc78e53SAndroid Build Coastguard Worker 	if (u->cu_mask & U32_ATTR_INDEV)
399*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, " indev %s", u->cu_indev);
400*4dc78e53SAndroid Build Coastguard Worker 
401*4dc78e53SAndroid Build Coastguard Worker 	if (u->cu_mask & U32_ATTR_SELECTOR)
402*4dc78e53SAndroid Build Coastguard Worker 		print_selector(p, s, u);
403*4dc78e53SAndroid Build Coastguard Worker 
404*4dc78e53SAndroid Build Coastguard Worker 	nl_dump(p, "\n");
405*4dc78e53SAndroid Build Coastguard Worker }
406*4dc78e53SAndroid Build Coastguard Worker 
u32_dump_stats(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)407*4dc78e53SAndroid Build Coastguard Worker static void u32_dump_stats(struct rtnl_tc *tc, void *data,
408*4dc78e53SAndroid Build Coastguard Worker 			   struct nl_dump_params *p)
409*4dc78e53SAndroid Build Coastguard Worker {
410*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_u32 *u = data;
411*4dc78e53SAndroid Build Coastguard Worker 
412*4dc78e53SAndroid Build Coastguard Worker 	if (!u)
413*4dc78e53SAndroid Build Coastguard Worker 		return;
414*4dc78e53SAndroid Build Coastguard Worker 
415*4dc78e53SAndroid Build Coastguard Worker 	if (u->cu_mask & U32_ATTR_PCNT) {
416*4dc78e53SAndroid Build Coastguard Worker 		struct tc_u32_pcnt *pc = u->cu_pcnt->d_data;
417*4dc78e53SAndroid Build Coastguard Worker 
418*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, "\n");
419*4dc78e53SAndroid Build Coastguard Worker 		nl_dump_line(p, "    hit %8llu count %8llu\n",
420*4dc78e53SAndroid Build Coastguard Worker 			     (long long unsigned)pc->rhit,
421*4dc78e53SAndroid Build Coastguard Worker 			     (long long unsigned)pc->rcnt);
422*4dc78e53SAndroid Build Coastguard Worker 	}
423*4dc78e53SAndroid Build Coastguard Worker }
424*4dc78e53SAndroid Build Coastguard Worker 
u32_msg_fill(struct rtnl_tc * tc,void * data,struct nl_msg * msg)425*4dc78e53SAndroid Build Coastguard Worker static int u32_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
426*4dc78e53SAndroid Build Coastguard Worker {
427*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_u32 *u = data;
428*4dc78e53SAndroid Build Coastguard Worker 
429*4dc78e53SAndroid Build Coastguard Worker 	if (!u)
430*4dc78e53SAndroid Build Coastguard Worker 		return 0;
431*4dc78e53SAndroid Build Coastguard Worker 
432*4dc78e53SAndroid Build Coastguard Worker 	if (u->cu_mask & U32_ATTR_DIVISOR)
433*4dc78e53SAndroid Build Coastguard Worker 		NLA_PUT_U32(msg, TCA_U32_DIVISOR, u->cu_divisor);
434*4dc78e53SAndroid Build Coastguard Worker 
435*4dc78e53SAndroid Build Coastguard Worker 	if (u->cu_mask & U32_ATTR_HASH)
436*4dc78e53SAndroid Build Coastguard Worker 		NLA_PUT_U32(msg, TCA_U32_HASH, u->cu_hash);
437*4dc78e53SAndroid Build Coastguard Worker 
438*4dc78e53SAndroid Build Coastguard Worker 	if (u->cu_mask & U32_ATTR_CLASSID)
439*4dc78e53SAndroid Build Coastguard Worker 		NLA_PUT_U32(msg, TCA_U32_CLASSID, u->cu_classid);
440*4dc78e53SAndroid Build Coastguard Worker 
441*4dc78e53SAndroid Build Coastguard Worker 	if (u->cu_mask & U32_ATTR_LINK)
442*4dc78e53SAndroid Build Coastguard Worker 		NLA_PUT_U32(msg, TCA_U32_LINK, u->cu_link);
443*4dc78e53SAndroid Build Coastguard Worker 
444*4dc78e53SAndroid Build Coastguard Worker 	if (u->cu_mask & U32_ATTR_SELECTOR)
445*4dc78e53SAndroid Build Coastguard Worker 		NLA_PUT_DATA(msg, TCA_U32_SEL, u->cu_selector);
446*4dc78e53SAndroid Build Coastguard Worker 
447*4dc78e53SAndroid Build Coastguard Worker 	if (u->cu_mask & U32_ATTR_MARK)
448*4dc78e53SAndroid Build Coastguard Worker 		NLA_PUT_DATA(msg, TCA_U32_MARK, u->cu_mark);
449*4dc78e53SAndroid Build Coastguard Worker 
450*4dc78e53SAndroid Build Coastguard Worker 	if (u->cu_mask & U32_ATTR_ACTION) {
451*4dc78e53SAndroid Build Coastguard Worker 		int err;
452*4dc78e53SAndroid Build Coastguard Worker 
453*4dc78e53SAndroid Build Coastguard Worker 		err = rtnl_act_fill(msg, TCA_U32_ACT, u->cu_act);
454*4dc78e53SAndroid Build Coastguard Worker 		if (err < 0)
455*4dc78e53SAndroid Build Coastguard Worker 			return err;
456*4dc78e53SAndroid Build Coastguard Worker 	}
457*4dc78e53SAndroid Build Coastguard Worker 
458*4dc78e53SAndroid Build Coastguard Worker 	if (u->cu_mask & U32_ATTR_POLICE)
459*4dc78e53SAndroid Build Coastguard Worker 		NLA_PUT_DATA(msg, TCA_U32_POLICE, u->cu_police);
460*4dc78e53SAndroid Build Coastguard Worker 
461*4dc78e53SAndroid Build Coastguard Worker 	if (u->cu_mask & U32_ATTR_INDEV)
462*4dc78e53SAndroid Build Coastguard Worker 		NLA_PUT_STRING(msg, TCA_U32_INDEV, u->cu_indev);
463*4dc78e53SAndroid Build Coastguard Worker 
464*4dc78e53SAndroid Build Coastguard Worker 	return 0;
465*4dc78e53SAndroid Build Coastguard Worker 
466*4dc78e53SAndroid Build Coastguard Worker nla_put_failure:
467*4dc78e53SAndroid Build Coastguard Worker 	return -NLE_NOMEM;
468*4dc78e53SAndroid Build Coastguard Worker }
469*4dc78e53SAndroid Build Coastguard Worker 
470*4dc78e53SAndroid Build Coastguard Worker /**
471*4dc78e53SAndroid Build Coastguard Worker  * @name Attribute Modifications
472*4dc78e53SAndroid Build Coastguard Worker  * @{
473*4dc78e53SAndroid Build Coastguard Worker  */
474*4dc78e53SAndroid Build Coastguard Worker 
rtnl_u32_set_handle(struct rtnl_cls * cls,int htid,int hash,int nodeid)475*4dc78e53SAndroid Build Coastguard Worker void rtnl_u32_set_handle(struct rtnl_cls *cls, int htid, int hash,
476*4dc78e53SAndroid Build Coastguard Worker 			 int nodeid)
477*4dc78e53SAndroid Build Coastguard Worker {
478*4dc78e53SAndroid Build Coastguard Worker 	uint32_t handle = (htid << 20) | (hash << 12) | nodeid;
479*4dc78e53SAndroid Build Coastguard Worker 
480*4dc78e53SAndroid Build Coastguard Worker 	rtnl_tc_set_handle((struct rtnl_tc *) cls, handle );
481*4dc78e53SAndroid Build Coastguard Worker }
482*4dc78e53SAndroid Build Coastguard Worker 
rtnl_u32_set_classid(struct rtnl_cls * cls,uint32_t classid)483*4dc78e53SAndroid Build Coastguard Worker int rtnl_u32_set_classid(struct rtnl_cls *cls, uint32_t classid)
484*4dc78e53SAndroid Build Coastguard Worker {
485*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_u32 *u;
486*4dc78e53SAndroid Build Coastguard Worker 
487*4dc78e53SAndroid Build Coastguard Worker 	if (!(u = rtnl_tc_data(TC_CAST(cls))))
488*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
489*4dc78e53SAndroid Build Coastguard Worker 
490*4dc78e53SAndroid Build Coastguard Worker 	u->cu_classid = classid;
491*4dc78e53SAndroid Build Coastguard Worker 	u->cu_mask |= U32_ATTR_CLASSID;
492*4dc78e53SAndroid Build Coastguard Worker 
493*4dc78e53SAndroid Build Coastguard Worker 	return 0;
494*4dc78e53SAndroid Build Coastguard Worker }
495*4dc78e53SAndroid Build Coastguard Worker 
rtnl_u32_get_classid(struct rtnl_cls * cls,uint32_t * classid)496*4dc78e53SAndroid Build Coastguard Worker int rtnl_u32_get_classid(struct rtnl_cls *cls, uint32_t *classid)
497*4dc78e53SAndroid Build Coastguard Worker {
498*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_u32 *u;
499*4dc78e53SAndroid Build Coastguard Worker 
500*4dc78e53SAndroid Build Coastguard Worker 	if (!(u = rtnl_tc_data_peek(TC_CAST(cls))))
501*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_INVAL;
502*4dc78e53SAndroid Build Coastguard Worker 
503*4dc78e53SAndroid Build Coastguard Worker 	if (!(u->cu_mask & U32_ATTR_CLASSID))
504*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_INVAL;
505*4dc78e53SAndroid Build Coastguard Worker 
506*4dc78e53SAndroid Build Coastguard Worker 	*classid = u->cu_classid;
507*4dc78e53SAndroid Build Coastguard Worker 	return 0;
508*4dc78e53SAndroid Build Coastguard Worker }
509*4dc78e53SAndroid Build Coastguard Worker 
rtnl_u32_set_divisor(struct rtnl_cls * cls,uint32_t divisor)510*4dc78e53SAndroid Build Coastguard Worker int rtnl_u32_set_divisor(struct rtnl_cls *cls, uint32_t divisor)
511*4dc78e53SAndroid Build Coastguard Worker {
512*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_u32 *u;
513*4dc78e53SAndroid Build Coastguard Worker 
514*4dc78e53SAndroid Build Coastguard Worker 	if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
515*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
516*4dc78e53SAndroid Build Coastguard Worker 
517*4dc78e53SAndroid Build Coastguard Worker 	u->cu_divisor = divisor;
518*4dc78e53SAndroid Build Coastguard Worker 	u->cu_mask |= U32_ATTR_DIVISOR;
519*4dc78e53SAndroid Build Coastguard Worker 	return 0;
520*4dc78e53SAndroid Build Coastguard Worker }
521*4dc78e53SAndroid Build Coastguard Worker 
rtnl_u32_set_link(struct rtnl_cls * cls,uint32_t link)522*4dc78e53SAndroid Build Coastguard Worker int rtnl_u32_set_link(struct rtnl_cls *cls, uint32_t link)
523*4dc78e53SAndroid Build Coastguard Worker {
524*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_u32 *u;
525*4dc78e53SAndroid Build Coastguard Worker 
526*4dc78e53SAndroid Build Coastguard Worker 	if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
527*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
528*4dc78e53SAndroid Build Coastguard Worker 
529*4dc78e53SAndroid Build Coastguard Worker 	u->cu_link = link;
530*4dc78e53SAndroid Build Coastguard Worker 	u->cu_mask |= U32_ATTR_LINK;
531*4dc78e53SAndroid Build Coastguard Worker 	return 0;
532*4dc78e53SAndroid Build Coastguard Worker }
533*4dc78e53SAndroid Build Coastguard Worker 
rtnl_u32_set_hashtable(struct rtnl_cls * cls,uint32_t ht)534*4dc78e53SAndroid Build Coastguard Worker int rtnl_u32_set_hashtable(struct rtnl_cls *cls, uint32_t ht)
535*4dc78e53SAndroid Build Coastguard Worker {
536*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_u32 *u;
537*4dc78e53SAndroid Build Coastguard Worker 
538*4dc78e53SAndroid Build Coastguard Worker 	if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
539*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
540*4dc78e53SAndroid Build Coastguard Worker 
541*4dc78e53SAndroid Build Coastguard Worker 	u->cu_hash = ht;
542*4dc78e53SAndroid Build Coastguard Worker 	u->cu_mask |= U32_ATTR_HASH;
543*4dc78e53SAndroid Build Coastguard Worker 	return 0;
544*4dc78e53SAndroid Build Coastguard Worker }
545*4dc78e53SAndroid Build Coastguard Worker 
rtnl_u32_set_hashmask(struct rtnl_cls * cls,uint32_t hashmask,uint32_t offset)546*4dc78e53SAndroid Build Coastguard Worker int rtnl_u32_set_hashmask(struct rtnl_cls *cls, uint32_t hashmask, uint32_t offset)
547*4dc78e53SAndroid Build Coastguard Worker {
548*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_u32 *u;
549*4dc78e53SAndroid Build Coastguard Worker 	struct tc_u32_sel *sel;
550*4dc78e53SAndroid Build Coastguard Worker 
551*4dc78e53SAndroid Build Coastguard Worker 	hashmask = htonl(hashmask);
552*4dc78e53SAndroid Build Coastguard Worker 
553*4dc78e53SAndroid Build Coastguard Worker 	if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
554*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
555*4dc78e53SAndroid Build Coastguard Worker 
556*4dc78e53SAndroid Build Coastguard Worker 	sel = u32_selector_alloc(u);
557*4dc78e53SAndroid Build Coastguard Worker 	if (!sel)
558*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
559*4dc78e53SAndroid Build Coastguard Worker 
560*4dc78e53SAndroid Build Coastguard Worker 	sel->hmask = hashmask;
561*4dc78e53SAndroid Build Coastguard Worker 	sel->hoff = offset;
562*4dc78e53SAndroid Build Coastguard Worker 	return 0;
563*4dc78e53SAndroid Build Coastguard Worker }
564*4dc78e53SAndroid Build Coastguard Worker 
rtnl_u32_set_selector(struct rtnl_cls * cls,int offoff,uint32_t offmask,char offshift,uint16_t off,char flags)565*4dc78e53SAndroid Build Coastguard Worker int rtnl_u32_set_selector(struct rtnl_cls *cls, int offoff, uint32_t offmask, char offshift, uint16_t off, char flags)
566*4dc78e53SAndroid Build Coastguard Worker {
567*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_u32 *u;
568*4dc78e53SAndroid Build Coastguard Worker 	struct tc_u32_sel *sel;
569*4dc78e53SAndroid Build Coastguard Worker 
570*4dc78e53SAndroid Build Coastguard Worker 	offmask = ntohs(offmask);
571*4dc78e53SAndroid Build Coastguard Worker 
572*4dc78e53SAndroid Build Coastguard Worker 	if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
573*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
574*4dc78e53SAndroid Build Coastguard Worker 
575*4dc78e53SAndroid Build Coastguard Worker 	sel = u32_selector_alloc(u);
576*4dc78e53SAndroid Build Coastguard Worker 	if (!sel)
577*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
578*4dc78e53SAndroid Build Coastguard Worker 
579*4dc78e53SAndroid Build Coastguard Worker 	sel->offoff = offoff;
580*4dc78e53SAndroid Build Coastguard Worker 	sel->offmask = offmask;
581*4dc78e53SAndroid Build Coastguard Worker 	sel->offshift = offshift;
582*4dc78e53SAndroid Build Coastguard Worker 	sel->flags |= TC_U32_VAROFFSET;
583*4dc78e53SAndroid Build Coastguard Worker 	sel->off = off;
584*4dc78e53SAndroid Build Coastguard Worker 	sel->flags |= flags;
585*4dc78e53SAndroid Build Coastguard Worker 	return 0;
586*4dc78e53SAndroid Build Coastguard Worker }
587*4dc78e53SAndroid Build Coastguard Worker 
rtnl_u32_set_cls_terminal(struct rtnl_cls * cls)588*4dc78e53SAndroid Build Coastguard Worker int rtnl_u32_set_cls_terminal(struct rtnl_cls *cls)
589*4dc78e53SAndroid Build Coastguard Worker {
590*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_u32 *u;
591*4dc78e53SAndroid Build Coastguard Worker 	struct tc_u32_sel *sel;
592*4dc78e53SAndroid Build Coastguard Worker 
593*4dc78e53SAndroid Build Coastguard Worker 	if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
594*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
595*4dc78e53SAndroid Build Coastguard Worker 
596*4dc78e53SAndroid Build Coastguard Worker 	sel = u32_selector_alloc(u);
597*4dc78e53SAndroid Build Coastguard Worker 	if (!sel)
598*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
599*4dc78e53SAndroid Build Coastguard Worker 
600*4dc78e53SAndroid Build Coastguard Worker 	sel->flags |= TC_U32_TERMINAL;
601*4dc78e53SAndroid Build Coastguard Worker 	return 0;
602*4dc78e53SAndroid Build Coastguard Worker }
603*4dc78e53SAndroid Build Coastguard Worker 
rtnl_u32_add_action(struct rtnl_cls * cls,struct rtnl_act * act)604*4dc78e53SAndroid Build Coastguard Worker int rtnl_u32_add_action(struct rtnl_cls *cls, struct rtnl_act *act)
605*4dc78e53SAndroid Build Coastguard Worker {
606*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_u32 *u;
607*4dc78e53SAndroid Build Coastguard Worker 	int err;
608*4dc78e53SAndroid Build Coastguard Worker 
609*4dc78e53SAndroid Build Coastguard Worker 	if (!act)
610*4dc78e53SAndroid Build Coastguard Worker 		return 0;
611*4dc78e53SAndroid Build Coastguard Worker 
612*4dc78e53SAndroid Build Coastguard Worker 	if (!(u = rtnl_tc_data(TC_CAST(cls))))
613*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
614*4dc78e53SAndroid Build Coastguard Worker 
615*4dc78e53SAndroid Build Coastguard Worker 	if ((err = _rtnl_act_append_get(&u->cu_act, act)) < 0)
616*4dc78e53SAndroid Build Coastguard Worker 		return err;
617*4dc78e53SAndroid Build Coastguard Worker 
618*4dc78e53SAndroid Build Coastguard Worker 	u->cu_mask |= U32_ATTR_ACTION;
619*4dc78e53SAndroid Build Coastguard Worker 	return 0;
620*4dc78e53SAndroid Build Coastguard Worker }
621*4dc78e53SAndroid Build Coastguard Worker 
rtnl_u32_get_action(struct rtnl_cls * cls)622*4dc78e53SAndroid Build Coastguard Worker struct rtnl_act* rtnl_u32_get_action(struct rtnl_cls *cls)
623*4dc78e53SAndroid Build Coastguard Worker {
624*4dc78e53SAndroid Build Coastguard Worker     struct rtnl_u32 *u;
625*4dc78e53SAndroid Build Coastguard Worker 
626*4dc78e53SAndroid Build Coastguard Worker     if (!(u = rtnl_tc_data_peek(TC_CAST(cls))))
627*4dc78e53SAndroid Build Coastguard Worker         return NULL;
628*4dc78e53SAndroid Build Coastguard Worker 
629*4dc78e53SAndroid Build Coastguard Worker     if (!(u->cu_mask & U32_ATTR_ACTION))
630*4dc78e53SAndroid Build Coastguard Worker         return NULL;
631*4dc78e53SAndroid Build Coastguard Worker 
632*4dc78e53SAndroid Build Coastguard Worker     return u->cu_act;
633*4dc78e53SAndroid Build Coastguard Worker }
634*4dc78e53SAndroid Build Coastguard Worker 
rtnl_u32_del_action(struct rtnl_cls * cls,struct rtnl_act * act)635*4dc78e53SAndroid Build Coastguard Worker int rtnl_u32_del_action(struct rtnl_cls *cls, struct rtnl_act *act)
636*4dc78e53SAndroid Build Coastguard Worker {
637*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_u32 *u;
638*4dc78e53SAndroid Build Coastguard Worker 	int ret;
639*4dc78e53SAndroid Build Coastguard Worker 
640*4dc78e53SAndroid Build Coastguard Worker 	if (!act)
641*4dc78e53SAndroid Build Coastguard Worker 		return 0;
642*4dc78e53SAndroid Build Coastguard Worker 
643*4dc78e53SAndroid Build Coastguard Worker 	if (!(u = rtnl_tc_data(TC_CAST(cls))))
644*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
645*4dc78e53SAndroid Build Coastguard Worker 
646*4dc78e53SAndroid Build Coastguard Worker 	if (!(u->cu_mask & U32_ATTR_ACTION))
647*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_INVAL;
648*4dc78e53SAndroid Build Coastguard Worker 
649*4dc78e53SAndroid Build Coastguard Worker 	ret = rtnl_act_remove(&u->cu_act, act);
650*4dc78e53SAndroid Build Coastguard Worker 	if (ret)
651*4dc78e53SAndroid Build Coastguard Worker 		return ret;
652*4dc78e53SAndroid Build Coastguard Worker 
653*4dc78e53SAndroid Build Coastguard Worker 	if (!u->cu_act)
654*4dc78e53SAndroid Build Coastguard Worker 		u->cu_mask &= ~U32_ATTR_ACTION;
655*4dc78e53SAndroid Build Coastguard Worker 	rtnl_act_put(act);
656*4dc78e53SAndroid Build Coastguard Worker 	return 0;
657*4dc78e53SAndroid Build Coastguard Worker }
658*4dc78e53SAndroid Build Coastguard Worker /** @} */
659*4dc78e53SAndroid Build Coastguard Worker 
660*4dc78e53SAndroid Build Coastguard Worker /**
661*4dc78e53SAndroid Build Coastguard Worker  * @name Selector Modifications
662*4dc78e53SAndroid Build Coastguard Worker  * @{
663*4dc78e53SAndroid Build Coastguard Worker  */
664*4dc78e53SAndroid Build Coastguard Worker 
rtnl_u32_set_flags(struct rtnl_cls * cls,int flags)665*4dc78e53SAndroid Build Coastguard Worker int rtnl_u32_set_flags(struct rtnl_cls *cls, int flags)
666*4dc78e53SAndroid Build Coastguard Worker {
667*4dc78e53SAndroid Build Coastguard Worker 	struct tc_u32_sel *sel;
668*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_u32 *u;
669*4dc78e53SAndroid Build Coastguard Worker 
670*4dc78e53SAndroid Build Coastguard Worker 	if (!(u = rtnl_tc_data(TC_CAST(cls))))
671*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
672*4dc78e53SAndroid Build Coastguard Worker 
673*4dc78e53SAndroid Build Coastguard Worker 	sel = u32_selector_alloc(u);
674*4dc78e53SAndroid Build Coastguard Worker 	if (!sel)
675*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
676*4dc78e53SAndroid Build Coastguard Worker 
677*4dc78e53SAndroid Build Coastguard Worker 	sel->flags |= flags;
678*4dc78e53SAndroid Build Coastguard Worker 	u->cu_mask |= U32_ATTR_SELECTOR;
679*4dc78e53SAndroid Build Coastguard Worker 
680*4dc78e53SAndroid Build Coastguard Worker 	return 0;
681*4dc78e53SAndroid Build Coastguard Worker }
682*4dc78e53SAndroid Build Coastguard Worker 
683*4dc78e53SAndroid Build Coastguard Worker /**
684*4dc78e53SAndroid Build Coastguard Worker  * Append new 32-bit key to the selector
685*4dc78e53SAndroid Build Coastguard Worker  *
686*4dc78e53SAndroid Build Coastguard Worker  * @arg cls	classifier to be modifier
687*4dc78e53SAndroid Build Coastguard Worker  * @arg val	value to be matched (network byte-order)
688*4dc78e53SAndroid Build Coastguard Worker  * @arg mask	mask to be applied before matching (network byte-order)
689*4dc78e53SAndroid Build Coastguard Worker  * @arg off	offset, in bytes, to start matching
690*4dc78e53SAndroid Build Coastguard Worker  * @arg offmask	offset mask
691*4dc78e53SAndroid Build Coastguard Worker  *
692*4dc78e53SAndroid Build Coastguard Worker  * General selectors define the pattern, mask and offset the pattern will be
693*4dc78e53SAndroid Build Coastguard Worker  * matched to the packet contents. Using the general selectors you can match
694*4dc78e53SAndroid Build Coastguard Worker  * virtually any single bit in the IP (or upper layer) header.
695*4dc78e53SAndroid Build Coastguard Worker  *
696*4dc78e53SAndroid Build Coastguard Worker */
rtnl_u32_add_key(struct rtnl_cls * cls,uint32_t val,uint32_t mask,int off,int offmask)697*4dc78e53SAndroid Build Coastguard Worker int rtnl_u32_add_key(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
698*4dc78e53SAndroid Build Coastguard Worker 		     int off, int offmask)
699*4dc78e53SAndroid Build Coastguard Worker {
700*4dc78e53SAndroid Build Coastguard Worker 	struct tc_u32_sel *sel;
701*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_u32 *u;
702*4dc78e53SAndroid Build Coastguard Worker 	int err;
703*4dc78e53SAndroid Build Coastguard Worker 
704*4dc78e53SAndroid Build Coastguard Worker 	if (!(u = rtnl_tc_data(TC_CAST(cls))))
705*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
706*4dc78e53SAndroid Build Coastguard Worker 
707*4dc78e53SAndroid Build Coastguard Worker 	sel = u32_selector_alloc(u);
708*4dc78e53SAndroid Build Coastguard Worker 	if (!sel)
709*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
710*4dc78e53SAndroid Build Coastguard Worker 
711*4dc78e53SAndroid Build Coastguard Worker 	if (sel->nkeys == UCHAR_MAX)
712*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
713*4dc78e53SAndroid Build Coastguard Worker 
714*4dc78e53SAndroid Build Coastguard Worker 	err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key));
715*4dc78e53SAndroid Build Coastguard Worker 	if (err < 0)
716*4dc78e53SAndroid Build Coastguard Worker 		return err;
717*4dc78e53SAndroid Build Coastguard Worker 
718*4dc78e53SAndroid Build Coastguard Worker 	/* the selector might have been moved by realloc */
719*4dc78e53SAndroid Build Coastguard Worker 	sel = u32_selector(u);
720*4dc78e53SAndroid Build Coastguard Worker 
721*4dc78e53SAndroid Build Coastguard Worker 	sel->keys[sel->nkeys].mask = mask;
722*4dc78e53SAndroid Build Coastguard Worker 	sel->keys[sel->nkeys].val = val & mask;
723*4dc78e53SAndroid Build Coastguard Worker 	sel->keys[sel->nkeys].off = off;
724*4dc78e53SAndroid Build Coastguard Worker 	sel->keys[sel->nkeys].offmask = offmask;
725*4dc78e53SAndroid Build Coastguard Worker 	sel->nkeys++;
726*4dc78e53SAndroid Build Coastguard Worker 	u->cu_mask |= U32_ATTR_SELECTOR;
727*4dc78e53SAndroid Build Coastguard Worker 
728*4dc78e53SAndroid Build Coastguard Worker 	return 0;
729*4dc78e53SAndroid Build Coastguard Worker }
730*4dc78e53SAndroid Build Coastguard Worker 
rtnl_u32_add_mark(struct rtnl_cls * cls,uint32_t val,uint32_t mask)731*4dc78e53SAndroid Build Coastguard Worker int rtnl_u32_add_mark(struct rtnl_cls *cls, uint32_t val, uint32_t mask)
732*4dc78e53SAndroid Build Coastguard Worker {
733*4dc78e53SAndroid Build Coastguard Worker 	struct tc_u32_mark *mark;
734*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_u32 *u;
735*4dc78e53SAndroid Build Coastguard Worker 
736*4dc78e53SAndroid Build Coastguard Worker 	if (!(u = rtnl_tc_data(TC_CAST(cls))))
737*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
738*4dc78e53SAndroid Build Coastguard Worker 
739*4dc78e53SAndroid Build Coastguard Worker 	mark = u32_mark_alloc(u);
740*4dc78e53SAndroid Build Coastguard Worker 	if (!mark)
741*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
742*4dc78e53SAndroid Build Coastguard Worker 
743*4dc78e53SAndroid Build Coastguard Worker 	mark->mask = mask;
744*4dc78e53SAndroid Build Coastguard Worker 	mark->val = val;
745*4dc78e53SAndroid Build Coastguard Worker 
746*4dc78e53SAndroid Build Coastguard Worker 	u->cu_mask |= U32_ATTR_MARK;
747*4dc78e53SAndroid Build Coastguard Worker 
748*4dc78e53SAndroid Build Coastguard Worker 	return 0;
749*4dc78e53SAndroid Build Coastguard Worker }
750*4dc78e53SAndroid Build Coastguard Worker 
rtnl_u32_del_mark(struct rtnl_cls * cls)751*4dc78e53SAndroid Build Coastguard Worker int rtnl_u32_del_mark(struct rtnl_cls *cls)
752*4dc78e53SAndroid Build Coastguard Worker {
753*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_u32 *u;
754*4dc78e53SAndroid Build Coastguard Worker 
755*4dc78e53SAndroid Build Coastguard Worker 	if (!(u = rtnl_tc_data(TC_CAST(cls))))
756*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
757*4dc78e53SAndroid Build Coastguard Worker 
758*4dc78e53SAndroid Build Coastguard Worker 	if (!(u->cu_mask))
759*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_INVAL;
760*4dc78e53SAndroid Build Coastguard Worker 
761*4dc78e53SAndroid Build Coastguard Worker 	if (!(u->cu_mask & U32_ATTR_MARK))
762*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_INVAL;
763*4dc78e53SAndroid Build Coastguard Worker 
764*4dc78e53SAndroid Build Coastguard Worker 	nl_data_free(u->cu_mark);
765*4dc78e53SAndroid Build Coastguard Worker 	u->cu_mark = NULL;
766*4dc78e53SAndroid Build Coastguard Worker 	u->cu_mask &= ~U32_ATTR_MARK;
767*4dc78e53SAndroid Build Coastguard Worker 
768*4dc78e53SAndroid Build Coastguard Worker 	return 0;
769*4dc78e53SAndroid Build Coastguard Worker }
770*4dc78e53SAndroid Build Coastguard Worker 
771*4dc78e53SAndroid Build Coastguard Worker /**
772*4dc78e53SAndroid Build Coastguard Worker  * Get the 32-bit key from the selector
773*4dc78e53SAndroid Build Coastguard Worker  *
774*4dc78e53SAndroid Build Coastguard Worker  * @arg cls	classifier to be retrieve
775*4dc78e53SAndroid Build Coastguard Worker  * @arg index	the index of the array of keys, start with 0
776*4dc78e53SAndroid Build Coastguard Worker  * @arg val	pointer to store value after masked (network byte-order)
777*4dc78e53SAndroid Build Coastguard Worker  * @arg mask	pointer to store the mask (network byte-order)
778*4dc78e53SAndroid Build Coastguard Worker  * @arg off	pointer to store the offset
779*4dc78e53SAndroid Build Coastguard Worker  * @arg offmask	pointer to store offset mask
780*4dc78e53SAndroid Build Coastguard Worker  *
781*4dc78e53SAndroid Build Coastguard Worker */
rtnl_u32_get_key(struct rtnl_cls * cls,uint8_t index,uint32_t * val,uint32_t * mask,int * off,int * offmask)782*4dc78e53SAndroid Build Coastguard Worker int rtnl_u32_get_key(struct rtnl_cls *cls, uint8_t index,
783*4dc78e53SAndroid Build Coastguard Worker 		     uint32_t *val, uint32_t *mask, int *off, int *offmask)
784*4dc78e53SAndroid Build Coastguard Worker {
785*4dc78e53SAndroid Build Coastguard Worker 	struct tc_u32_sel *sel;
786*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_u32 *u;
787*4dc78e53SAndroid Build Coastguard Worker 
788*4dc78e53SAndroid Build Coastguard Worker 	if (!(u = rtnl_tc_data(TC_CAST(cls))))
789*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
790*4dc78e53SAndroid Build Coastguard Worker 
791*4dc78e53SAndroid Build Coastguard Worker 	if (!(u->cu_mask & U32_ATTR_SELECTOR))
792*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_INVAL;
793*4dc78e53SAndroid Build Coastguard Worker 
794*4dc78e53SAndroid Build Coastguard Worker 	sel = u32_selector(u);
795*4dc78e53SAndroid Build Coastguard Worker 	if (index >= sel->nkeys)
796*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_RANGE;
797*4dc78e53SAndroid Build Coastguard Worker 
798*4dc78e53SAndroid Build Coastguard Worker 	*mask = sel->keys[index].mask;
799*4dc78e53SAndroid Build Coastguard Worker 	*val = sel->keys[index].val;
800*4dc78e53SAndroid Build Coastguard Worker 	*off = sel->keys[index].off;
801*4dc78e53SAndroid Build Coastguard Worker 	*offmask = sel->keys[index].offmask;
802*4dc78e53SAndroid Build Coastguard Worker 	return 0;
803*4dc78e53SAndroid Build Coastguard Worker }
804*4dc78e53SAndroid Build Coastguard Worker 
805*4dc78e53SAndroid Build Coastguard Worker 
rtnl_u32_add_key_uint8(struct rtnl_cls * cls,uint8_t val,uint8_t mask,int off,int offmask)806*4dc78e53SAndroid Build Coastguard Worker int rtnl_u32_add_key_uint8(struct rtnl_cls *cls, uint8_t val, uint8_t mask,
807*4dc78e53SAndroid Build Coastguard Worker 			   int off, int offmask)
808*4dc78e53SAndroid Build Coastguard Worker {
809*4dc78e53SAndroid Build Coastguard Worker 	int shift = 24 - 8 * (off & 3);
810*4dc78e53SAndroid Build Coastguard Worker 
811*4dc78e53SAndroid Build Coastguard Worker 	return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
812*4dc78e53SAndroid Build Coastguard Worker 				htonl((uint32_t)mask << shift),
813*4dc78e53SAndroid Build Coastguard Worker 				off & ~3, offmask);
814*4dc78e53SAndroid Build Coastguard Worker }
815*4dc78e53SAndroid Build Coastguard Worker 
816*4dc78e53SAndroid Build Coastguard Worker /**
817*4dc78e53SAndroid Build Coastguard Worker  * Append new selector key to match a 16-bit number
818*4dc78e53SAndroid Build Coastguard Worker  *
819*4dc78e53SAndroid Build Coastguard Worker  * @arg cls	classifier to be modified
820*4dc78e53SAndroid Build Coastguard Worker  * @arg val	value to be matched (host byte-order)
821*4dc78e53SAndroid Build Coastguard Worker  * @arg mask	mask to be applied before matching (host byte-order)
822*4dc78e53SAndroid Build Coastguard Worker  * @arg off	offset, in bytes, to start matching
823*4dc78e53SAndroid Build Coastguard Worker  * @arg offmask	offset mask
824*4dc78e53SAndroid Build Coastguard Worker */
rtnl_u32_add_key_uint16(struct rtnl_cls * cls,uint16_t val,uint16_t mask,int off,int offmask)825*4dc78e53SAndroid Build Coastguard Worker int rtnl_u32_add_key_uint16(struct rtnl_cls *cls, uint16_t val, uint16_t mask,
826*4dc78e53SAndroid Build Coastguard Worker 			    int off, int offmask)
827*4dc78e53SAndroid Build Coastguard Worker {
828*4dc78e53SAndroid Build Coastguard Worker 	int shift = ((off & 3) == 0 ? 16 : 0);
829*4dc78e53SAndroid Build Coastguard Worker 	if (off % 2)
830*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_INVAL;
831*4dc78e53SAndroid Build Coastguard Worker 
832*4dc78e53SAndroid Build Coastguard Worker 	return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
833*4dc78e53SAndroid Build Coastguard Worker 				htonl((uint32_t)mask << shift),
834*4dc78e53SAndroid Build Coastguard Worker 				off & ~3, offmask);
835*4dc78e53SAndroid Build Coastguard Worker }
836*4dc78e53SAndroid Build Coastguard Worker 
837*4dc78e53SAndroid Build Coastguard Worker /**
838*4dc78e53SAndroid Build Coastguard Worker  * Append new selector key to match a 32-bit number
839*4dc78e53SAndroid Build Coastguard Worker  *
840*4dc78e53SAndroid Build Coastguard Worker  * @arg cls	classifier to be modified
841*4dc78e53SAndroid Build Coastguard Worker  * @arg val	value to be matched (host byte-order)
842*4dc78e53SAndroid Build Coastguard Worker  * @arg mask	mask to be applied before matching (host byte-order)
843*4dc78e53SAndroid Build Coastguard Worker  * @arg off	offset, in bytes, to start matching
844*4dc78e53SAndroid Build Coastguard Worker  * @arg offmask	offset mask
845*4dc78e53SAndroid Build Coastguard Worker */
rtnl_u32_add_key_uint32(struct rtnl_cls * cls,uint32_t val,uint32_t mask,int off,int offmask)846*4dc78e53SAndroid Build Coastguard Worker int rtnl_u32_add_key_uint32(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
847*4dc78e53SAndroid Build Coastguard Worker 			    int off, int offmask)
848*4dc78e53SAndroid Build Coastguard Worker {
849*4dc78e53SAndroid Build Coastguard Worker 	return rtnl_u32_add_key(cls, htonl(val), htonl(mask),
850*4dc78e53SAndroid Build Coastguard Worker 				off & ~3, offmask);
851*4dc78e53SAndroid Build Coastguard Worker }
852*4dc78e53SAndroid Build Coastguard Worker 
rtnl_u32_add_key_in_addr(struct rtnl_cls * cls,const struct in_addr * addr,uint8_t bitmask,int off,int offmask)853*4dc78e53SAndroid Build Coastguard Worker int rtnl_u32_add_key_in_addr(struct rtnl_cls *cls, const struct in_addr *addr,
854*4dc78e53SAndroid Build Coastguard Worker 			     uint8_t bitmask, int off, int offmask)
855*4dc78e53SAndroid Build Coastguard Worker {
856*4dc78e53SAndroid Build Coastguard Worker 	uint32_t mask = 0xFFFFFFFF << (32 - bitmask);
857*4dc78e53SAndroid Build Coastguard Worker 	return rtnl_u32_add_key(cls, addr->s_addr, htonl(mask), off, offmask);
858*4dc78e53SAndroid Build Coastguard Worker }
859*4dc78e53SAndroid Build Coastguard Worker 
rtnl_u32_add_key_in6_addr(struct rtnl_cls * cls,const struct in6_addr * addr,uint8_t bitmask,int off,int offmask)860*4dc78e53SAndroid Build Coastguard Worker int rtnl_u32_add_key_in6_addr(struct rtnl_cls *cls, const struct in6_addr *addr,
861*4dc78e53SAndroid Build Coastguard Worker 			      uint8_t bitmask, int off, int offmask)
862*4dc78e53SAndroid Build Coastguard Worker {
863*4dc78e53SAndroid Build Coastguard Worker 	int i, err;
864*4dc78e53SAndroid Build Coastguard Worker 
865*4dc78e53SAndroid Build Coastguard Worker 	for (i = 1; i <= 4; i++) {
866*4dc78e53SAndroid Build Coastguard Worker 		if (32 * i - bitmask <= 0) {
867*4dc78e53SAndroid Build Coastguard Worker 			if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
868*4dc78e53SAndroid Build Coastguard Worker 						0xFFFFFFFF, off+4*(i-1), offmask)) < 0)
869*4dc78e53SAndroid Build Coastguard Worker 				return err;
870*4dc78e53SAndroid Build Coastguard Worker 		}
871*4dc78e53SAndroid Build Coastguard Worker 		else if (32 * i - bitmask < 32) {
872*4dc78e53SAndroid Build Coastguard Worker 			uint32_t mask = 0xFFFFFFFF << (32 * i - bitmask);
873*4dc78e53SAndroid Build Coastguard Worker 			if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
874*4dc78e53SAndroid Build Coastguard Worker 						htonl(mask), off+4*(i-1), offmask)) < 0)
875*4dc78e53SAndroid Build Coastguard Worker 				return err;
876*4dc78e53SAndroid Build Coastguard Worker 		}
877*4dc78e53SAndroid Build Coastguard Worker 		/* otherwise, if (32*i - bitmask >= 32) no key is generated */
878*4dc78e53SAndroid Build Coastguard Worker 	}
879*4dc78e53SAndroid Build Coastguard Worker 
880*4dc78e53SAndroid Build Coastguard Worker 	return 0;
881*4dc78e53SAndroid Build Coastguard Worker }
882*4dc78e53SAndroid Build Coastguard Worker 
883*4dc78e53SAndroid Build Coastguard Worker /** @} */
884*4dc78e53SAndroid Build Coastguard Worker 
885*4dc78e53SAndroid Build Coastguard Worker static struct rtnl_tc_ops u32_ops = {
886*4dc78e53SAndroid Build Coastguard Worker 	.to_kind		= "u32",
887*4dc78e53SAndroid Build Coastguard Worker 	.to_type		= RTNL_TC_TYPE_CLS,
888*4dc78e53SAndroid Build Coastguard Worker 	.to_size		= sizeof(struct rtnl_u32),
889*4dc78e53SAndroid Build Coastguard Worker 	.to_msg_parser		= u32_msg_parser,
890*4dc78e53SAndroid Build Coastguard Worker 	.to_free_data		= u32_free_data,
891*4dc78e53SAndroid Build Coastguard Worker 	.to_clone		= u32_clone,
892*4dc78e53SAndroid Build Coastguard Worker 	.to_msg_fill		= u32_msg_fill,
893*4dc78e53SAndroid Build Coastguard Worker 	.to_dump = {
894*4dc78e53SAndroid Build Coastguard Worker 	    [NL_DUMP_LINE]	= u32_dump_line,
895*4dc78e53SAndroid Build Coastguard Worker 	    [NL_DUMP_DETAILS]	= u32_dump_details,
896*4dc78e53SAndroid Build Coastguard Worker 	    [NL_DUMP_STATS]	= u32_dump_stats,
897*4dc78e53SAndroid Build Coastguard Worker 	},
898*4dc78e53SAndroid Build Coastguard Worker };
899*4dc78e53SAndroid Build Coastguard Worker 
u32_init(void)900*4dc78e53SAndroid Build Coastguard Worker static void _nl_init u32_init(void)
901*4dc78e53SAndroid Build Coastguard Worker {
902*4dc78e53SAndroid Build Coastguard Worker 	rtnl_tc_register(&u32_ops);
903*4dc78e53SAndroid Build Coastguard Worker }
904*4dc78e53SAndroid Build Coastguard Worker 
u32_exit(void)905*4dc78e53SAndroid Build Coastguard Worker static void _nl_exit u32_exit(void)
906*4dc78e53SAndroid Build Coastguard Worker {
907*4dc78e53SAndroid Build Coastguard Worker 	rtnl_tc_unregister(&u32_ops);
908*4dc78e53SAndroid Build Coastguard Worker }
909*4dc78e53SAndroid Build Coastguard Worker 
910*4dc78e53SAndroid Build Coastguard Worker /** @} */
911