xref: /aosp_15_r20/external/iproute2/tc/f_u32.c (revision de1e4e894b0c224df933550f0afdecc354b238c4)
1*de1e4e89SAndroid Build Coastguard Worker /*
2*de1e4e89SAndroid Build Coastguard Worker  * q_u32.c		U32 filter.
3*de1e4e89SAndroid Build Coastguard Worker  *
4*de1e4e89SAndroid Build Coastguard Worker  *		This program is free software; you can u32istribute it and/or
5*de1e4e89SAndroid Build Coastguard Worker  *		modify it under the terms of the GNU General Public License
6*de1e4e89SAndroid Build Coastguard Worker  *		as published by the Free Software Foundation; either version
7*de1e4e89SAndroid Build Coastguard Worker  *		2 of the License, or (at your option) any later version.
8*de1e4e89SAndroid Build Coastguard Worker  *
9*de1e4e89SAndroid Build Coastguard Worker  * Authors:	Alexey Kuznetsov, <[email protected]>
10*de1e4e89SAndroid Build Coastguard Worker  *		Match mark added by Catalin(ux aka Dino) BOIE <catab at umbrella.ro> [5 nov 2004]
11*de1e4e89SAndroid Build Coastguard Worker  *
12*de1e4e89SAndroid Build Coastguard Worker  */
13*de1e4e89SAndroid Build Coastguard Worker 
14*de1e4e89SAndroid Build Coastguard Worker #include <stdio.h>
15*de1e4e89SAndroid Build Coastguard Worker #include <stdlib.h>
16*de1e4e89SAndroid Build Coastguard Worker #include <unistd.h>
17*de1e4e89SAndroid Build Coastguard Worker #include <syslog.h>
18*de1e4e89SAndroid Build Coastguard Worker #include <fcntl.h>
19*de1e4e89SAndroid Build Coastguard Worker #include <sys/socket.h>
20*de1e4e89SAndroid Build Coastguard Worker #include <netinet/in.h>
21*de1e4e89SAndroid Build Coastguard Worker #include <arpa/inet.h>
22*de1e4e89SAndroid Build Coastguard Worker #include <string.h>
23*de1e4e89SAndroid Build Coastguard Worker #include <linux/if.h>
24*de1e4e89SAndroid Build Coastguard Worker #include <linux/if_ether.h>
25*de1e4e89SAndroid Build Coastguard Worker 
26*de1e4e89SAndroid Build Coastguard Worker #include "utils.h"
27*de1e4e89SAndroid Build Coastguard Worker #include "tc_util.h"
28*de1e4e89SAndroid Build Coastguard Worker 
29*de1e4e89SAndroid Build Coastguard Worker extern int show_pretty;
30*de1e4e89SAndroid Build Coastguard Worker 
explain(void)31*de1e4e89SAndroid Build Coastguard Worker static void explain(void)
32*de1e4e89SAndroid Build Coastguard Worker {
33*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stderr,
34*de1e4e89SAndroid Build Coastguard Worker 		"Usage: ... u32 [ match SELECTOR ... ] [ link HTID ] [ classid CLASSID ]\n"
35*de1e4e89SAndroid Build Coastguard Worker 		"               [ action ACTION_SPEC ] [ offset OFFSET_SPEC ]\n"
36*de1e4e89SAndroid Build Coastguard Worker 		"               [ ht HTID ] [ hashkey HASHKEY_SPEC ]\n"
37*de1e4e89SAndroid Build Coastguard Worker 		"               [ sample SAMPLE ] [skip_hw | skip_sw]\n"
38*de1e4e89SAndroid Build Coastguard Worker 		"or         u32 divisor DIVISOR\n"
39*de1e4e89SAndroid Build Coastguard Worker 		"\n"
40*de1e4e89SAndroid Build Coastguard Worker 		"Where: SELECTOR := SAMPLE SAMPLE ...\n"
41*de1e4e89SAndroid Build Coastguard Worker 		"       SAMPLE := { ip | ip6 | udp | tcp | icmp | u{32|16|8} | mark }\n"
42*de1e4e89SAndroid Build Coastguard Worker 		"                 SAMPLE_ARGS [ divisor DIVISOR ]\n"
43*de1e4e89SAndroid Build Coastguard Worker 		"       FILTERID := X:Y:Z\n"
44*de1e4e89SAndroid Build Coastguard Worker 		"\nNOTE: CLASSID is parsed at hexadecimal input.\n");
45*de1e4e89SAndroid Build Coastguard Worker }
46*de1e4e89SAndroid Build Coastguard Worker 
get_u32_handle(__u32 * handle,const char * str)47*de1e4e89SAndroid Build Coastguard Worker static int get_u32_handle(__u32 *handle, const char *str)
48*de1e4e89SAndroid Build Coastguard Worker {
49*de1e4e89SAndroid Build Coastguard Worker 	__u32 htid = 0, hash = 0, nodeid = 0;
50*de1e4e89SAndroid Build Coastguard Worker 	char *tmp = strchr(str, ':');
51*de1e4e89SAndroid Build Coastguard Worker 
52*de1e4e89SAndroid Build Coastguard Worker 	if (tmp == NULL) {
53*de1e4e89SAndroid Build Coastguard Worker 		if (memcmp("0x", str, 2) == 0)
54*de1e4e89SAndroid Build Coastguard Worker 			return get_u32(handle, str, 16);
55*de1e4e89SAndroid Build Coastguard Worker 		return -1;
56*de1e4e89SAndroid Build Coastguard Worker 	}
57*de1e4e89SAndroid Build Coastguard Worker 	htid = strtoul(str, &tmp, 16);
58*de1e4e89SAndroid Build Coastguard Worker 	if (tmp == str && *str != ':' && *str != 0)
59*de1e4e89SAndroid Build Coastguard Worker 		return -1;
60*de1e4e89SAndroid Build Coastguard Worker 	if (htid >= 0x1000)
61*de1e4e89SAndroid Build Coastguard Worker 		return -1;
62*de1e4e89SAndroid Build Coastguard Worker 	if (*tmp) {
63*de1e4e89SAndroid Build Coastguard Worker 		str = tmp + 1;
64*de1e4e89SAndroid Build Coastguard Worker 		hash = strtoul(str, &tmp, 16);
65*de1e4e89SAndroid Build Coastguard Worker 		if (tmp == str && *str != ':' && *str != 0)
66*de1e4e89SAndroid Build Coastguard Worker 			return -1;
67*de1e4e89SAndroid Build Coastguard Worker 		if (hash >= 0x100)
68*de1e4e89SAndroid Build Coastguard Worker 			return -1;
69*de1e4e89SAndroid Build Coastguard Worker 		if (*tmp) {
70*de1e4e89SAndroid Build Coastguard Worker 			str = tmp + 1;
71*de1e4e89SAndroid Build Coastguard Worker 			nodeid = strtoul(str, &tmp, 16);
72*de1e4e89SAndroid Build Coastguard Worker 			if (tmp == str && *str != 0)
73*de1e4e89SAndroid Build Coastguard Worker 				return -1;
74*de1e4e89SAndroid Build Coastguard Worker 			if (nodeid >= 0x1000)
75*de1e4e89SAndroid Build Coastguard Worker 				return -1;
76*de1e4e89SAndroid Build Coastguard Worker 		}
77*de1e4e89SAndroid Build Coastguard Worker 	}
78*de1e4e89SAndroid Build Coastguard Worker 	*handle = (htid<<20)|(hash<<12)|nodeid;
79*de1e4e89SAndroid Build Coastguard Worker 	return 0;
80*de1e4e89SAndroid Build Coastguard Worker }
81*de1e4e89SAndroid Build Coastguard Worker 
sprint_u32_handle(__u32 handle,char * buf)82*de1e4e89SAndroid Build Coastguard Worker static char *sprint_u32_handle(__u32 handle, char *buf)
83*de1e4e89SAndroid Build Coastguard Worker {
84*de1e4e89SAndroid Build Coastguard Worker 	int bsize = SPRINT_BSIZE-1;
85*de1e4e89SAndroid Build Coastguard Worker 	__u32 htid = TC_U32_HTID(handle);
86*de1e4e89SAndroid Build Coastguard Worker 	__u32 hash = TC_U32_HASH(handle);
87*de1e4e89SAndroid Build Coastguard Worker 	__u32 nodeid = TC_U32_NODE(handle);
88*de1e4e89SAndroid Build Coastguard Worker 	char *b = buf;
89*de1e4e89SAndroid Build Coastguard Worker 
90*de1e4e89SAndroid Build Coastguard Worker 	if (handle == 0) {
91*de1e4e89SAndroid Build Coastguard Worker 		snprintf(b, bsize, "none");
92*de1e4e89SAndroid Build Coastguard Worker 		return b;
93*de1e4e89SAndroid Build Coastguard Worker 	}
94*de1e4e89SAndroid Build Coastguard Worker 	if (htid) {
95*de1e4e89SAndroid Build Coastguard Worker 		int l = snprintf(b, bsize, "%x:", htid>>20);
96*de1e4e89SAndroid Build Coastguard Worker 
97*de1e4e89SAndroid Build Coastguard Worker 		bsize -= l;
98*de1e4e89SAndroid Build Coastguard Worker 		b += l;
99*de1e4e89SAndroid Build Coastguard Worker 	}
100*de1e4e89SAndroid Build Coastguard Worker 	if (nodeid|hash) {
101*de1e4e89SAndroid Build Coastguard Worker 		if (hash) {
102*de1e4e89SAndroid Build Coastguard Worker 			int l = snprintf(b, bsize, "%x", hash);
103*de1e4e89SAndroid Build Coastguard Worker 
104*de1e4e89SAndroid Build Coastguard Worker 			bsize -= l;
105*de1e4e89SAndroid Build Coastguard Worker 			b += l;
106*de1e4e89SAndroid Build Coastguard Worker 		}
107*de1e4e89SAndroid Build Coastguard Worker 		if (nodeid) {
108*de1e4e89SAndroid Build Coastguard Worker 			int l = snprintf(b, bsize, ":%x", nodeid);
109*de1e4e89SAndroid Build Coastguard Worker 
110*de1e4e89SAndroid Build Coastguard Worker 			bsize -= l;
111*de1e4e89SAndroid Build Coastguard Worker 			b += l;
112*de1e4e89SAndroid Build Coastguard Worker 		}
113*de1e4e89SAndroid Build Coastguard Worker 	}
114*de1e4e89SAndroid Build Coastguard Worker 	if (show_raw)
115*de1e4e89SAndroid Build Coastguard Worker 		snprintf(b, bsize, "[%08x] ", handle);
116*de1e4e89SAndroid Build Coastguard Worker 	return buf;
117*de1e4e89SAndroid Build Coastguard Worker }
118*de1e4e89SAndroid Build Coastguard Worker 
pack_key(struct tc_u32_sel * sel,__u32 key,__u32 mask,int off,int offmask)119*de1e4e89SAndroid Build Coastguard Worker static int pack_key(struct tc_u32_sel *sel, __u32 key, __u32 mask,
120*de1e4e89SAndroid Build Coastguard Worker 		    int off, int offmask)
121*de1e4e89SAndroid Build Coastguard Worker {
122*de1e4e89SAndroid Build Coastguard Worker 	int i;
123*de1e4e89SAndroid Build Coastguard Worker 	int hwm = sel->nkeys;
124*de1e4e89SAndroid Build Coastguard Worker 
125*de1e4e89SAndroid Build Coastguard Worker 	key &= mask;
126*de1e4e89SAndroid Build Coastguard Worker 
127*de1e4e89SAndroid Build Coastguard Worker 	for (i = 0; i < hwm; i++) {
128*de1e4e89SAndroid Build Coastguard Worker 		if (sel->keys[i].off == off && sel->keys[i].offmask == offmask) {
129*de1e4e89SAndroid Build Coastguard Worker 			__u32 intersect = mask & sel->keys[i].mask;
130*de1e4e89SAndroid Build Coastguard Worker 
131*de1e4e89SAndroid Build Coastguard Worker 			if ((key ^ sel->keys[i].val) & intersect)
132*de1e4e89SAndroid Build Coastguard Worker 				return -1;
133*de1e4e89SAndroid Build Coastguard Worker 			sel->keys[i].val |= key;
134*de1e4e89SAndroid Build Coastguard Worker 			sel->keys[i].mask |= mask;
135*de1e4e89SAndroid Build Coastguard Worker 			return 0;
136*de1e4e89SAndroid Build Coastguard Worker 		}
137*de1e4e89SAndroid Build Coastguard Worker 	}
138*de1e4e89SAndroid Build Coastguard Worker 
139*de1e4e89SAndroid Build Coastguard Worker 	if (hwm >= 128)
140*de1e4e89SAndroid Build Coastguard Worker 		return -1;
141*de1e4e89SAndroid Build Coastguard Worker 	if (off % 4)
142*de1e4e89SAndroid Build Coastguard Worker 		return -1;
143*de1e4e89SAndroid Build Coastguard Worker 	sel->keys[hwm].val = key;
144*de1e4e89SAndroid Build Coastguard Worker 	sel->keys[hwm].mask = mask;
145*de1e4e89SAndroid Build Coastguard Worker 	sel->keys[hwm].off = off;
146*de1e4e89SAndroid Build Coastguard Worker 	sel->keys[hwm].offmask = offmask;
147*de1e4e89SAndroid Build Coastguard Worker 	sel->nkeys++;
148*de1e4e89SAndroid Build Coastguard Worker 	return 0;
149*de1e4e89SAndroid Build Coastguard Worker }
150*de1e4e89SAndroid Build Coastguard Worker 
pack_key32(struct tc_u32_sel * sel,__u32 key,__u32 mask,int off,int offmask)151*de1e4e89SAndroid Build Coastguard Worker static int pack_key32(struct tc_u32_sel *sel, __u32 key, __u32 mask,
152*de1e4e89SAndroid Build Coastguard Worker 		      int off, int offmask)
153*de1e4e89SAndroid Build Coastguard Worker {
154*de1e4e89SAndroid Build Coastguard Worker 	key = htonl(key);
155*de1e4e89SAndroid Build Coastguard Worker 	mask = htonl(mask);
156*de1e4e89SAndroid Build Coastguard Worker 	return pack_key(sel, key, mask, off, offmask);
157*de1e4e89SAndroid Build Coastguard Worker }
158*de1e4e89SAndroid Build Coastguard Worker 
pack_key16(struct tc_u32_sel * sel,__u32 key,__u32 mask,int off,int offmask)159*de1e4e89SAndroid Build Coastguard Worker static int pack_key16(struct tc_u32_sel *sel, __u32 key, __u32 mask,
160*de1e4e89SAndroid Build Coastguard Worker 		      int off, int offmask)
161*de1e4e89SAndroid Build Coastguard Worker {
162*de1e4e89SAndroid Build Coastguard Worker 	if (key > 0xFFFF || mask > 0xFFFF)
163*de1e4e89SAndroid Build Coastguard Worker 		return -1;
164*de1e4e89SAndroid Build Coastguard Worker 
165*de1e4e89SAndroid Build Coastguard Worker 	if ((off & 3) == 0) {
166*de1e4e89SAndroid Build Coastguard Worker 		key <<= 16;
167*de1e4e89SAndroid Build Coastguard Worker 		mask <<= 16;
168*de1e4e89SAndroid Build Coastguard Worker 	}
169*de1e4e89SAndroid Build Coastguard Worker 	off &= ~3;
170*de1e4e89SAndroid Build Coastguard Worker 	key = htonl(key);
171*de1e4e89SAndroid Build Coastguard Worker 	mask = htonl(mask);
172*de1e4e89SAndroid Build Coastguard Worker 
173*de1e4e89SAndroid Build Coastguard Worker 	return pack_key(sel, key, mask, off, offmask);
174*de1e4e89SAndroid Build Coastguard Worker }
175*de1e4e89SAndroid Build Coastguard Worker 
pack_key8(struct tc_u32_sel * sel,__u32 key,__u32 mask,int off,int offmask)176*de1e4e89SAndroid Build Coastguard Worker static int pack_key8(struct tc_u32_sel *sel, __u32 key, __u32 mask, int off,
177*de1e4e89SAndroid Build Coastguard Worker 		     int offmask)
178*de1e4e89SAndroid Build Coastguard Worker {
179*de1e4e89SAndroid Build Coastguard Worker 	if (key > 0xFF || mask > 0xFF)
180*de1e4e89SAndroid Build Coastguard Worker 		return -1;
181*de1e4e89SAndroid Build Coastguard Worker 
182*de1e4e89SAndroid Build Coastguard Worker 	if ((off & 3) == 0) {
183*de1e4e89SAndroid Build Coastguard Worker 		key <<= 24;
184*de1e4e89SAndroid Build Coastguard Worker 		mask <<= 24;
185*de1e4e89SAndroid Build Coastguard Worker 	} else if ((off & 3) == 1) {
186*de1e4e89SAndroid Build Coastguard Worker 		key <<= 16;
187*de1e4e89SAndroid Build Coastguard Worker 		mask <<= 16;
188*de1e4e89SAndroid Build Coastguard Worker 	} else if ((off & 3) == 2) {
189*de1e4e89SAndroid Build Coastguard Worker 		key <<= 8;
190*de1e4e89SAndroid Build Coastguard Worker 		mask <<= 8;
191*de1e4e89SAndroid Build Coastguard Worker 	}
192*de1e4e89SAndroid Build Coastguard Worker 	off &= ~3;
193*de1e4e89SAndroid Build Coastguard Worker 	key = htonl(key);
194*de1e4e89SAndroid Build Coastguard Worker 	mask = htonl(mask);
195*de1e4e89SAndroid Build Coastguard Worker 
196*de1e4e89SAndroid Build Coastguard Worker 	return pack_key(sel, key, mask, off, offmask);
197*de1e4e89SAndroid Build Coastguard Worker }
198*de1e4e89SAndroid Build Coastguard Worker 
199*de1e4e89SAndroid Build Coastguard Worker 
parse_at(int * argc_p,char *** argv_p,int * off,int * offmask)200*de1e4e89SAndroid Build Coastguard Worker static int parse_at(int *argc_p, char ***argv_p, int *off, int *offmask)
201*de1e4e89SAndroid Build Coastguard Worker {
202*de1e4e89SAndroid Build Coastguard Worker 	int argc = *argc_p;
203*de1e4e89SAndroid Build Coastguard Worker 	char **argv = *argv_p;
204*de1e4e89SAndroid Build Coastguard Worker 	char *p = *argv;
205*de1e4e89SAndroid Build Coastguard Worker 
206*de1e4e89SAndroid Build Coastguard Worker 	if (argc <= 0)
207*de1e4e89SAndroid Build Coastguard Worker 		return -1;
208*de1e4e89SAndroid Build Coastguard Worker 
209*de1e4e89SAndroid Build Coastguard Worker 	if (strlen(p) > strlen("nexthdr+") &&
210*de1e4e89SAndroid Build Coastguard Worker 	    memcmp(p, "nexthdr+", strlen("nexthdr+")) == 0) {
211*de1e4e89SAndroid Build Coastguard Worker 		*offmask = -1;
212*de1e4e89SAndroid Build Coastguard Worker 		p += strlen("nexthdr+");
213*de1e4e89SAndroid Build Coastguard Worker 	} else if (matches(*argv, "nexthdr+") == 0) {
214*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
215*de1e4e89SAndroid Build Coastguard Worker 		*offmask = -1;
216*de1e4e89SAndroid Build Coastguard Worker 		p = *argv;
217*de1e4e89SAndroid Build Coastguard Worker 	}
218*de1e4e89SAndroid Build Coastguard Worker 
219*de1e4e89SAndroid Build Coastguard Worker 	if (get_integer(off, p, 0))
220*de1e4e89SAndroid Build Coastguard Worker 		return -1;
221*de1e4e89SAndroid Build Coastguard Worker 	argc--; argv++;
222*de1e4e89SAndroid Build Coastguard Worker 
223*de1e4e89SAndroid Build Coastguard Worker 	*argc_p = argc;
224*de1e4e89SAndroid Build Coastguard Worker 	*argv_p = argv;
225*de1e4e89SAndroid Build Coastguard Worker 	return 0;
226*de1e4e89SAndroid Build Coastguard Worker }
227*de1e4e89SAndroid Build Coastguard Worker 
228*de1e4e89SAndroid Build Coastguard Worker 
parse_u32(int * argc_p,char *** argv_p,struct tc_u32_sel * sel,int off,int offmask)229*de1e4e89SAndroid Build Coastguard Worker static int parse_u32(int *argc_p, char ***argv_p, struct tc_u32_sel *sel,
230*de1e4e89SAndroid Build Coastguard Worker 		     int off, int offmask)
231*de1e4e89SAndroid Build Coastguard Worker {
232*de1e4e89SAndroid Build Coastguard Worker 	int res = -1;
233*de1e4e89SAndroid Build Coastguard Worker 	int argc = *argc_p;
234*de1e4e89SAndroid Build Coastguard Worker 	char **argv = *argv_p;
235*de1e4e89SAndroid Build Coastguard Worker 	__u32 key;
236*de1e4e89SAndroid Build Coastguard Worker 	__u32 mask;
237*de1e4e89SAndroid Build Coastguard Worker 
238*de1e4e89SAndroid Build Coastguard Worker 	if (argc < 2)
239*de1e4e89SAndroid Build Coastguard Worker 		return -1;
240*de1e4e89SAndroid Build Coastguard Worker 
241*de1e4e89SAndroid Build Coastguard Worker 	if (get_u32(&key, *argv, 0))
242*de1e4e89SAndroid Build Coastguard Worker 		return -1;
243*de1e4e89SAndroid Build Coastguard Worker 	argc--; argv++;
244*de1e4e89SAndroid Build Coastguard Worker 
245*de1e4e89SAndroid Build Coastguard Worker 	if (get_u32(&mask, *argv, 16))
246*de1e4e89SAndroid Build Coastguard Worker 		return -1;
247*de1e4e89SAndroid Build Coastguard Worker 	argc--; argv++;
248*de1e4e89SAndroid Build Coastguard Worker 
249*de1e4e89SAndroid Build Coastguard Worker 	if (argc > 0 && strcmp(argv[0], "at") == 0) {
250*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
251*de1e4e89SAndroid Build Coastguard Worker 		if (parse_at(&argc, &argv, &off, &offmask))
252*de1e4e89SAndroid Build Coastguard Worker 			return -1;
253*de1e4e89SAndroid Build Coastguard Worker 	}
254*de1e4e89SAndroid Build Coastguard Worker 
255*de1e4e89SAndroid Build Coastguard Worker 	res = pack_key32(sel, key, mask, off, offmask);
256*de1e4e89SAndroid Build Coastguard Worker 	*argc_p = argc;
257*de1e4e89SAndroid Build Coastguard Worker 	*argv_p = argv;
258*de1e4e89SAndroid Build Coastguard Worker 	return res;
259*de1e4e89SAndroid Build Coastguard Worker }
260*de1e4e89SAndroid Build Coastguard Worker 
parse_u16(int * argc_p,char *** argv_p,struct tc_u32_sel * sel,int off,int offmask)261*de1e4e89SAndroid Build Coastguard Worker static int parse_u16(int *argc_p, char ***argv_p, struct tc_u32_sel *sel,
262*de1e4e89SAndroid Build Coastguard Worker 		     int off, int offmask)
263*de1e4e89SAndroid Build Coastguard Worker {
264*de1e4e89SAndroid Build Coastguard Worker 	int res = -1;
265*de1e4e89SAndroid Build Coastguard Worker 	int argc = *argc_p;
266*de1e4e89SAndroid Build Coastguard Worker 	char **argv = *argv_p;
267*de1e4e89SAndroid Build Coastguard Worker 	__u32 key;
268*de1e4e89SAndroid Build Coastguard Worker 	__u32 mask;
269*de1e4e89SAndroid Build Coastguard Worker 
270*de1e4e89SAndroid Build Coastguard Worker 	if (argc < 2)
271*de1e4e89SAndroid Build Coastguard Worker 		return -1;
272*de1e4e89SAndroid Build Coastguard Worker 
273*de1e4e89SAndroid Build Coastguard Worker 	if (get_u32(&key, *argv, 0))
274*de1e4e89SAndroid Build Coastguard Worker 		return -1;
275*de1e4e89SAndroid Build Coastguard Worker 	argc--; argv++;
276*de1e4e89SAndroid Build Coastguard Worker 
277*de1e4e89SAndroid Build Coastguard Worker 	if (get_u32(&mask, *argv, 16))
278*de1e4e89SAndroid Build Coastguard Worker 		return -1;
279*de1e4e89SAndroid Build Coastguard Worker 	argc--; argv++;
280*de1e4e89SAndroid Build Coastguard Worker 
281*de1e4e89SAndroid Build Coastguard Worker 	if (argc > 0 && strcmp(argv[0], "at") == 0) {
282*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
283*de1e4e89SAndroid Build Coastguard Worker 		if (parse_at(&argc, &argv, &off, &offmask))
284*de1e4e89SAndroid Build Coastguard Worker 			return -1;
285*de1e4e89SAndroid Build Coastguard Worker 	}
286*de1e4e89SAndroid Build Coastguard Worker 	res = pack_key16(sel, key, mask, off, offmask);
287*de1e4e89SAndroid Build Coastguard Worker 	*argc_p = argc;
288*de1e4e89SAndroid Build Coastguard Worker 	*argv_p = argv;
289*de1e4e89SAndroid Build Coastguard Worker 	return res;
290*de1e4e89SAndroid Build Coastguard Worker }
291*de1e4e89SAndroid Build Coastguard Worker 
parse_u8(int * argc_p,char *** argv_p,struct tc_u32_sel * sel,int off,int offmask)292*de1e4e89SAndroid Build Coastguard Worker static int parse_u8(int *argc_p, char ***argv_p, struct tc_u32_sel *sel,
293*de1e4e89SAndroid Build Coastguard Worker 		    int off, int offmask)
294*de1e4e89SAndroid Build Coastguard Worker {
295*de1e4e89SAndroid Build Coastguard Worker 	int res = -1;
296*de1e4e89SAndroid Build Coastguard Worker 	int argc = *argc_p;
297*de1e4e89SAndroid Build Coastguard Worker 	char **argv = *argv_p;
298*de1e4e89SAndroid Build Coastguard Worker 	__u32 key;
299*de1e4e89SAndroid Build Coastguard Worker 	__u32 mask;
300*de1e4e89SAndroid Build Coastguard Worker 
301*de1e4e89SAndroid Build Coastguard Worker 	if (argc < 2)
302*de1e4e89SAndroid Build Coastguard Worker 		return -1;
303*de1e4e89SAndroid Build Coastguard Worker 
304*de1e4e89SAndroid Build Coastguard Worker 	if (get_u32(&key, *argv, 0))
305*de1e4e89SAndroid Build Coastguard Worker 		return -1;
306*de1e4e89SAndroid Build Coastguard Worker 	argc--; argv++;
307*de1e4e89SAndroid Build Coastguard Worker 
308*de1e4e89SAndroid Build Coastguard Worker 	if (get_u32(&mask, *argv, 16))
309*de1e4e89SAndroid Build Coastguard Worker 		return -1;
310*de1e4e89SAndroid Build Coastguard Worker 	argc--; argv++;
311*de1e4e89SAndroid Build Coastguard Worker 
312*de1e4e89SAndroid Build Coastguard Worker 	if (key > 0xFF || mask > 0xFF)
313*de1e4e89SAndroid Build Coastguard Worker 		return -1;
314*de1e4e89SAndroid Build Coastguard Worker 
315*de1e4e89SAndroid Build Coastguard Worker 	if (argc > 0 && strcmp(argv[0], "at") == 0) {
316*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
317*de1e4e89SAndroid Build Coastguard Worker 		if (parse_at(&argc, &argv, &off, &offmask))
318*de1e4e89SAndroid Build Coastguard Worker 			return -1;
319*de1e4e89SAndroid Build Coastguard Worker 	}
320*de1e4e89SAndroid Build Coastguard Worker 
321*de1e4e89SAndroid Build Coastguard Worker 	res = pack_key8(sel, key, mask, off, offmask);
322*de1e4e89SAndroid Build Coastguard Worker 	*argc_p = argc;
323*de1e4e89SAndroid Build Coastguard Worker 	*argv_p = argv;
324*de1e4e89SAndroid Build Coastguard Worker 	return res;
325*de1e4e89SAndroid Build Coastguard Worker }
326*de1e4e89SAndroid Build Coastguard Worker 
parse_ip_addr(int * argc_p,char *** argv_p,struct tc_u32_sel * sel,int off)327*de1e4e89SAndroid Build Coastguard Worker static int parse_ip_addr(int *argc_p, char ***argv_p, struct tc_u32_sel *sel,
328*de1e4e89SAndroid Build Coastguard Worker 			 int off)
329*de1e4e89SAndroid Build Coastguard Worker {
330*de1e4e89SAndroid Build Coastguard Worker 	int res = -1;
331*de1e4e89SAndroid Build Coastguard Worker 	int argc = *argc_p;
332*de1e4e89SAndroid Build Coastguard Worker 	char **argv = *argv_p;
333*de1e4e89SAndroid Build Coastguard Worker 	inet_prefix addr;
334*de1e4e89SAndroid Build Coastguard Worker 	__u32 mask;
335*de1e4e89SAndroid Build Coastguard Worker 	int offmask = 0;
336*de1e4e89SAndroid Build Coastguard Worker 
337*de1e4e89SAndroid Build Coastguard Worker 	if (argc < 1)
338*de1e4e89SAndroid Build Coastguard Worker 		return -1;
339*de1e4e89SAndroid Build Coastguard Worker 
340*de1e4e89SAndroid Build Coastguard Worker 	if (get_prefix_1(&addr, *argv, AF_INET))
341*de1e4e89SAndroid Build Coastguard Worker 		return -1;
342*de1e4e89SAndroid Build Coastguard Worker 	argc--; argv++;
343*de1e4e89SAndroid Build Coastguard Worker 
344*de1e4e89SAndroid Build Coastguard Worker 	if (argc > 0 && strcmp(argv[0], "at") == 0) {
345*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
346*de1e4e89SAndroid Build Coastguard Worker 		if (parse_at(&argc, &argv, &off, &offmask))
347*de1e4e89SAndroid Build Coastguard Worker 			return -1;
348*de1e4e89SAndroid Build Coastguard Worker 	}
349*de1e4e89SAndroid Build Coastguard Worker 
350*de1e4e89SAndroid Build Coastguard Worker 	mask = 0;
351*de1e4e89SAndroid Build Coastguard Worker 	if (addr.bitlen)
352*de1e4e89SAndroid Build Coastguard Worker 		mask = htonl(0xFFFFFFFF << (32 - addr.bitlen));
353*de1e4e89SAndroid Build Coastguard Worker 	if (pack_key(sel, addr.data[0], mask, off, offmask) < 0)
354*de1e4e89SAndroid Build Coastguard Worker 		return -1;
355*de1e4e89SAndroid Build Coastguard Worker 	res = 0;
356*de1e4e89SAndroid Build Coastguard Worker 
357*de1e4e89SAndroid Build Coastguard Worker 	*argc_p = argc;
358*de1e4e89SAndroid Build Coastguard Worker 	*argv_p = argv;
359*de1e4e89SAndroid Build Coastguard Worker 	return res;
360*de1e4e89SAndroid Build Coastguard Worker }
361*de1e4e89SAndroid Build Coastguard Worker 
parse_ip6_addr(int * argc_p,char *** argv_p,struct tc_u32_sel * sel,int off)362*de1e4e89SAndroid Build Coastguard Worker static int parse_ip6_addr(int *argc_p, char ***argv_p,
363*de1e4e89SAndroid Build Coastguard Worker 			  struct tc_u32_sel *sel, int off)
364*de1e4e89SAndroid Build Coastguard Worker {
365*de1e4e89SAndroid Build Coastguard Worker 	int res = -1;
366*de1e4e89SAndroid Build Coastguard Worker 	int argc = *argc_p;
367*de1e4e89SAndroid Build Coastguard Worker 	char **argv = *argv_p;
368*de1e4e89SAndroid Build Coastguard Worker 	int plen = 128;
369*de1e4e89SAndroid Build Coastguard Worker 	int i;
370*de1e4e89SAndroid Build Coastguard Worker 	inet_prefix addr;
371*de1e4e89SAndroid Build Coastguard Worker 	int offmask = 0;
372*de1e4e89SAndroid Build Coastguard Worker 
373*de1e4e89SAndroid Build Coastguard Worker 	if (argc < 1)
374*de1e4e89SAndroid Build Coastguard Worker 		return -1;
375*de1e4e89SAndroid Build Coastguard Worker 
376*de1e4e89SAndroid Build Coastguard Worker 	if (get_prefix_1(&addr, *argv, AF_INET6))
377*de1e4e89SAndroid Build Coastguard Worker 		return -1;
378*de1e4e89SAndroid Build Coastguard Worker 	argc--; argv++;
379*de1e4e89SAndroid Build Coastguard Worker 
380*de1e4e89SAndroid Build Coastguard Worker 	if (argc > 0 && strcmp(argv[0], "at") == 0) {
381*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
382*de1e4e89SAndroid Build Coastguard Worker 		if (parse_at(&argc, &argv, &off, &offmask))
383*de1e4e89SAndroid Build Coastguard Worker 			return -1;
384*de1e4e89SAndroid Build Coastguard Worker 	}
385*de1e4e89SAndroid Build Coastguard Worker 
386*de1e4e89SAndroid Build Coastguard Worker 	plen = addr.bitlen;
387*de1e4e89SAndroid Build Coastguard Worker 	for (i = 0; i < plen; i += 32) {
388*de1e4e89SAndroid Build Coastguard Worker 		if (i + 31 < plen) {
389*de1e4e89SAndroid Build Coastguard Worker 			res = pack_key(sel, addr.data[i / 32],
390*de1e4e89SAndroid Build Coastguard Worker 				       0xFFFFFFFF, off + 4 * (i / 32), offmask);
391*de1e4e89SAndroid Build Coastguard Worker 			if (res < 0)
392*de1e4e89SAndroid Build Coastguard Worker 				return -1;
393*de1e4e89SAndroid Build Coastguard Worker 		} else if (i < plen) {
394*de1e4e89SAndroid Build Coastguard Worker 			__u32 mask = htonl(0xFFFFFFFF << (32 - (plen - i)));
395*de1e4e89SAndroid Build Coastguard Worker 
396*de1e4e89SAndroid Build Coastguard Worker 			res = pack_key(sel, addr.data[i / 32],
397*de1e4e89SAndroid Build Coastguard Worker 				       mask, off + 4 * (i / 32), offmask);
398*de1e4e89SAndroid Build Coastguard Worker 			if (res < 0)
399*de1e4e89SAndroid Build Coastguard Worker 				return -1;
400*de1e4e89SAndroid Build Coastguard Worker 		}
401*de1e4e89SAndroid Build Coastguard Worker 	}
402*de1e4e89SAndroid Build Coastguard Worker 	res = 0;
403*de1e4e89SAndroid Build Coastguard Worker 
404*de1e4e89SAndroid Build Coastguard Worker 	*argc_p = argc;
405*de1e4e89SAndroid Build Coastguard Worker 	*argv_p = argv;
406*de1e4e89SAndroid Build Coastguard Worker 	return res;
407*de1e4e89SAndroid Build Coastguard Worker }
408*de1e4e89SAndroid Build Coastguard Worker 
parse_ip6_class(int * argc_p,char *** argv_p,struct tc_u32_sel * sel)409*de1e4e89SAndroid Build Coastguard Worker static int parse_ip6_class(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
410*de1e4e89SAndroid Build Coastguard Worker {
411*de1e4e89SAndroid Build Coastguard Worker 	int res = -1;
412*de1e4e89SAndroid Build Coastguard Worker 	int argc = *argc_p;
413*de1e4e89SAndroid Build Coastguard Worker 	char **argv = *argv_p;
414*de1e4e89SAndroid Build Coastguard Worker 	__u32 key;
415*de1e4e89SAndroid Build Coastguard Worker 	__u32 mask;
416*de1e4e89SAndroid Build Coastguard Worker 	int off = 0;
417*de1e4e89SAndroid Build Coastguard Worker 	int offmask = 0;
418*de1e4e89SAndroid Build Coastguard Worker 
419*de1e4e89SAndroid Build Coastguard Worker 	if (argc < 2)
420*de1e4e89SAndroid Build Coastguard Worker 		return -1;
421*de1e4e89SAndroid Build Coastguard Worker 
422*de1e4e89SAndroid Build Coastguard Worker 	if (get_u32(&key, *argv, 0))
423*de1e4e89SAndroid Build Coastguard Worker 		return -1;
424*de1e4e89SAndroid Build Coastguard Worker 	argc--; argv++;
425*de1e4e89SAndroid Build Coastguard Worker 
426*de1e4e89SAndroid Build Coastguard Worker 	if (get_u32(&mask, *argv, 16))
427*de1e4e89SAndroid Build Coastguard Worker 		return -1;
428*de1e4e89SAndroid Build Coastguard Worker 	argc--; argv++;
429*de1e4e89SAndroid Build Coastguard Worker 
430*de1e4e89SAndroid Build Coastguard Worker 	if (key > 0xFF || mask > 0xFF)
431*de1e4e89SAndroid Build Coastguard Worker 		return -1;
432*de1e4e89SAndroid Build Coastguard Worker 
433*de1e4e89SAndroid Build Coastguard Worker 	key <<= 20;
434*de1e4e89SAndroid Build Coastguard Worker 	mask <<= 20;
435*de1e4e89SAndroid Build Coastguard Worker 	key = htonl(key);
436*de1e4e89SAndroid Build Coastguard Worker 	mask = htonl(mask);
437*de1e4e89SAndroid Build Coastguard Worker 
438*de1e4e89SAndroid Build Coastguard Worker 	res = pack_key(sel, key, mask, off, offmask);
439*de1e4e89SAndroid Build Coastguard Worker 	if (res < 0)
440*de1e4e89SAndroid Build Coastguard Worker 		return -1;
441*de1e4e89SAndroid Build Coastguard Worker 
442*de1e4e89SAndroid Build Coastguard Worker 	*argc_p = argc;
443*de1e4e89SAndroid Build Coastguard Worker 	*argv_p = argv;
444*de1e4e89SAndroid Build Coastguard Worker 	return 0;
445*de1e4e89SAndroid Build Coastguard Worker }
446*de1e4e89SAndroid Build Coastguard Worker 
parse_ether_addr(int * argc_p,char *** argv_p,struct tc_u32_sel * sel,int off)447*de1e4e89SAndroid Build Coastguard Worker static int parse_ether_addr(int *argc_p, char ***argv_p,
448*de1e4e89SAndroid Build Coastguard Worker 			    struct tc_u32_sel *sel, int off)
449*de1e4e89SAndroid Build Coastguard Worker {
450*de1e4e89SAndroid Build Coastguard Worker 	int res = -1;
451*de1e4e89SAndroid Build Coastguard Worker 	int argc = *argc_p;
452*de1e4e89SAndroid Build Coastguard Worker 	char **argv = *argv_p;
453*de1e4e89SAndroid Build Coastguard Worker 	__u8 addr[6];
454*de1e4e89SAndroid Build Coastguard Worker 	int offmask = 0;
455*de1e4e89SAndroid Build Coastguard Worker 	int i;
456*de1e4e89SAndroid Build Coastguard Worker 
457*de1e4e89SAndroid Build Coastguard Worker 	if (argc < 1)
458*de1e4e89SAndroid Build Coastguard Worker 		return -1;
459*de1e4e89SAndroid Build Coastguard Worker 
460*de1e4e89SAndroid Build Coastguard Worker 	if (sscanf(*argv, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
461*de1e4e89SAndroid Build Coastguard Worker 		   addr + 0, addr + 1, addr + 2,
462*de1e4e89SAndroid Build Coastguard Worker 		   addr + 3, addr + 4, addr + 5) != 6) {
463*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "parse_ether_addr: improperly formed address '%s'\n",
464*de1e4e89SAndroid Build Coastguard Worker 			*argv);
465*de1e4e89SAndroid Build Coastguard Worker 		return -1;
466*de1e4e89SAndroid Build Coastguard Worker 	}
467*de1e4e89SAndroid Build Coastguard Worker 
468*de1e4e89SAndroid Build Coastguard Worker 	argc--; argv++;
469*de1e4e89SAndroid Build Coastguard Worker 	if (argc > 0 && strcmp(argv[0], "at") == 0) {
470*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
471*de1e4e89SAndroid Build Coastguard Worker 		if (parse_at(&argc, &argv, &off, &offmask))
472*de1e4e89SAndroid Build Coastguard Worker 			return -1;
473*de1e4e89SAndroid Build Coastguard Worker 	}
474*de1e4e89SAndroid Build Coastguard Worker 
475*de1e4e89SAndroid Build Coastguard Worker 	for (i = 0; i < 6; i++) {
476*de1e4e89SAndroid Build Coastguard Worker 		res = pack_key8(sel, addr[i], 0xFF, off + i, offmask);
477*de1e4e89SAndroid Build Coastguard Worker 		if (res < 0)
478*de1e4e89SAndroid Build Coastguard Worker 			return -1;
479*de1e4e89SAndroid Build Coastguard Worker 	}
480*de1e4e89SAndroid Build Coastguard Worker 
481*de1e4e89SAndroid Build Coastguard Worker 	*argc_p = argc;
482*de1e4e89SAndroid Build Coastguard Worker 	*argv_p = argv;
483*de1e4e89SAndroid Build Coastguard Worker 	return res;
484*de1e4e89SAndroid Build Coastguard Worker }
485*de1e4e89SAndroid Build Coastguard Worker 
parse_ip(int * argc_p,char *** argv_p,struct tc_u32_sel * sel)486*de1e4e89SAndroid Build Coastguard Worker static int parse_ip(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
487*de1e4e89SAndroid Build Coastguard Worker {
488*de1e4e89SAndroid Build Coastguard Worker 	int res = -1;
489*de1e4e89SAndroid Build Coastguard Worker 	int argc = *argc_p;
490*de1e4e89SAndroid Build Coastguard Worker 	char **argv = *argv_p;
491*de1e4e89SAndroid Build Coastguard Worker 
492*de1e4e89SAndroid Build Coastguard Worker 	if (argc < 2)
493*de1e4e89SAndroid Build Coastguard Worker 		return -1;
494*de1e4e89SAndroid Build Coastguard Worker 
495*de1e4e89SAndroid Build Coastguard Worker 	if (strcmp(*argv, "src") == 0) {
496*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
497*de1e4e89SAndroid Build Coastguard Worker 		res = parse_ip_addr(&argc, &argv, sel, 12);
498*de1e4e89SAndroid Build Coastguard Worker 	} else if (strcmp(*argv, "dst") == 0) {
499*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
500*de1e4e89SAndroid Build Coastguard Worker 		res = parse_ip_addr(&argc, &argv, sel, 16);
501*de1e4e89SAndroid Build Coastguard Worker 	} else if (strcmp(*argv, "tos") == 0 ||
502*de1e4e89SAndroid Build Coastguard Worker 	    matches(*argv, "dsfield") == 0 ||
503*de1e4e89SAndroid Build Coastguard Worker 	    matches(*argv, "precedence") == 0) {
504*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
505*de1e4e89SAndroid Build Coastguard Worker 		res = parse_u8(&argc, &argv, sel, 1, 0);
506*de1e4e89SAndroid Build Coastguard Worker 	} else if (strcmp(*argv, "ihl") == 0) {
507*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
508*de1e4e89SAndroid Build Coastguard Worker 		res = parse_u8(&argc, &argv, sel, 0, 0);
509*de1e4e89SAndroid Build Coastguard Worker 	} else if (strcmp(*argv, "protocol") == 0) {
510*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
511*de1e4e89SAndroid Build Coastguard Worker 		res = parse_u8(&argc, &argv, sel, 9, 0);
512*de1e4e89SAndroid Build Coastguard Worker 	} else if (strcmp(*argv, "nofrag") == 0) {
513*de1e4e89SAndroid Build Coastguard Worker 		argc--; argv++;
514*de1e4e89SAndroid Build Coastguard Worker 		res = pack_key16(sel, 0, 0x3FFF, 6, 0);
515*de1e4e89SAndroid Build Coastguard Worker 	} else if (strcmp(*argv, "firstfrag") == 0) {
516*de1e4e89SAndroid Build Coastguard Worker 		argc--; argv++;
517*de1e4e89SAndroid Build Coastguard Worker 		res = pack_key16(sel, 0x2000, 0x3FFF, 6, 0);
518*de1e4e89SAndroid Build Coastguard Worker 	} else if (strcmp(*argv, "df") == 0) {
519*de1e4e89SAndroid Build Coastguard Worker 		argc--; argv++;
520*de1e4e89SAndroid Build Coastguard Worker 		res = pack_key16(sel, 0x4000, 0x4000, 6, 0);
521*de1e4e89SAndroid Build Coastguard Worker 	} else if (strcmp(*argv, "mf") == 0) {
522*de1e4e89SAndroid Build Coastguard Worker 		argc--; argv++;
523*de1e4e89SAndroid Build Coastguard Worker 		res = pack_key16(sel, 0x2000, 0x2000, 6, 0);
524*de1e4e89SAndroid Build Coastguard Worker 	} else if (strcmp(*argv, "dport") == 0) {
525*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
526*de1e4e89SAndroid Build Coastguard Worker 		res = parse_u16(&argc, &argv, sel, 22, 0);
527*de1e4e89SAndroid Build Coastguard Worker 	} else if (strcmp(*argv, "sport") == 0) {
528*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
529*de1e4e89SAndroid Build Coastguard Worker 		res = parse_u16(&argc, &argv, sel, 20, 0);
530*de1e4e89SAndroid Build Coastguard Worker 	} else if (strcmp(*argv, "icmp_type") == 0) {
531*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
532*de1e4e89SAndroid Build Coastguard Worker 		res = parse_u8(&argc, &argv, sel, 20, 0);
533*de1e4e89SAndroid Build Coastguard Worker 	} else if (strcmp(*argv, "icmp_code") == 0) {
534*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
535*de1e4e89SAndroid Build Coastguard Worker 		res = parse_u8(&argc, &argv, sel, 21, 0);
536*de1e4e89SAndroid Build Coastguard Worker 	} else
537*de1e4e89SAndroid Build Coastguard Worker 		return -1;
538*de1e4e89SAndroid Build Coastguard Worker 
539*de1e4e89SAndroid Build Coastguard Worker 	*argc_p = argc;
540*de1e4e89SAndroid Build Coastguard Worker 	*argv_p = argv;
541*de1e4e89SAndroid Build Coastguard Worker 	return res;
542*de1e4e89SAndroid Build Coastguard Worker }
543*de1e4e89SAndroid Build Coastguard Worker 
parse_ip6(int * argc_p,char *** argv_p,struct tc_u32_sel * sel)544*de1e4e89SAndroid Build Coastguard Worker static int parse_ip6(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
545*de1e4e89SAndroid Build Coastguard Worker {
546*de1e4e89SAndroid Build Coastguard Worker 	int res = -1;
547*de1e4e89SAndroid Build Coastguard Worker 	int argc = *argc_p;
548*de1e4e89SAndroid Build Coastguard Worker 	char **argv = *argv_p;
549*de1e4e89SAndroid Build Coastguard Worker 
550*de1e4e89SAndroid Build Coastguard Worker 	if (argc < 2)
551*de1e4e89SAndroid Build Coastguard Worker 		return -1;
552*de1e4e89SAndroid Build Coastguard Worker 
553*de1e4e89SAndroid Build Coastguard Worker 	if (strcmp(*argv, "src") == 0) {
554*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
555*de1e4e89SAndroid Build Coastguard Worker 		res = parse_ip6_addr(&argc, &argv, sel, 8);
556*de1e4e89SAndroid Build Coastguard Worker 	} else if (strcmp(*argv, "dst") == 0) {
557*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
558*de1e4e89SAndroid Build Coastguard Worker 		res = parse_ip6_addr(&argc, &argv, sel, 24);
559*de1e4e89SAndroid Build Coastguard Worker 	} else if (strcmp(*argv, "priority") == 0) {
560*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
561*de1e4e89SAndroid Build Coastguard Worker 		res = parse_ip6_class(&argc, &argv, sel);
562*de1e4e89SAndroid Build Coastguard Worker 	} else if (strcmp(*argv, "protocol") == 0) {
563*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
564*de1e4e89SAndroid Build Coastguard Worker 		res = parse_u8(&argc, &argv, sel, 6, 0);
565*de1e4e89SAndroid Build Coastguard Worker 	} else if (strcmp(*argv, "flowlabel") == 0) {
566*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
567*de1e4e89SAndroid Build Coastguard Worker 		res = parse_u32(&argc, &argv, sel, 0, 0);
568*de1e4e89SAndroid Build Coastguard Worker 	} else if (strcmp(*argv, "dport") == 0) {
569*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
570*de1e4e89SAndroid Build Coastguard Worker 		res = parse_u16(&argc, &argv, sel, 42, 0);
571*de1e4e89SAndroid Build Coastguard Worker 	} else if (strcmp(*argv, "sport") == 0) {
572*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
573*de1e4e89SAndroid Build Coastguard Worker 		res = parse_u16(&argc, &argv, sel, 40, 0);
574*de1e4e89SAndroid Build Coastguard Worker 	} else if (strcmp(*argv, "icmp_type") == 0) {
575*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
576*de1e4e89SAndroid Build Coastguard Worker 		res = parse_u8(&argc, &argv, sel, 40, 0);
577*de1e4e89SAndroid Build Coastguard Worker 	} else if (strcmp(*argv, "icmp_code") == 0) {
578*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
579*de1e4e89SAndroid Build Coastguard Worker 		res = parse_u8(&argc, &argv, sel, 41, 1);
580*de1e4e89SAndroid Build Coastguard Worker 	} else
581*de1e4e89SAndroid Build Coastguard Worker 		return -1;
582*de1e4e89SAndroid Build Coastguard Worker 
583*de1e4e89SAndroid Build Coastguard Worker 	*argc_p = argc;
584*de1e4e89SAndroid Build Coastguard Worker 	*argv_p = argv;
585*de1e4e89SAndroid Build Coastguard Worker 	return res;
586*de1e4e89SAndroid Build Coastguard Worker }
587*de1e4e89SAndroid Build Coastguard Worker 
parse_ether(int * argc_p,char *** argv_p,struct tc_u32_sel * sel)588*de1e4e89SAndroid Build Coastguard Worker static int parse_ether(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
589*de1e4e89SAndroid Build Coastguard Worker {
590*de1e4e89SAndroid Build Coastguard Worker 	int res = -1;
591*de1e4e89SAndroid Build Coastguard Worker 	int argc = *argc_p;
592*de1e4e89SAndroid Build Coastguard Worker 	char **argv = *argv_p;
593*de1e4e89SAndroid Build Coastguard Worker 
594*de1e4e89SAndroid Build Coastguard Worker 	if (argc < 2)
595*de1e4e89SAndroid Build Coastguard Worker 		return -1;
596*de1e4e89SAndroid Build Coastguard Worker 
597*de1e4e89SAndroid Build Coastguard Worker 	if (strcmp(*argv, "src") == 0) {
598*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
599*de1e4e89SAndroid Build Coastguard Worker 		res = parse_ether_addr(&argc, &argv, sel, -8);
600*de1e4e89SAndroid Build Coastguard Worker 	} else if (strcmp(*argv, "dst") == 0) {
601*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
602*de1e4e89SAndroid Build Coastguard Worker 		res = parse_ether_addr(&argc, &argv, sel, -14);
603*de1e4e89SAndroid Build Coastguard Worker 	} else {
604*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "Unknown match: ether %s\n", *argv);
605*de1e4e89SAndroid Build Coastguard Worker 		return -1;
606*de1e4e89SAndroid Build Coastguard Worker 	}
607*de1e4e89SAndroid Build Coastguard Worker 
608*de1e4e89SAndroid Build Coastguard Worker 	*argc_p = argc;
609*de1e4e89SAndroid Build Coastguard Worker 	*argv_p = argv;
610*de1e4e89SAndroid Build Coastguard Worker 	return res;
611*de1e4e89SAndroid Build Coastguard Worker }
612*de1e4e89SAndroid Build Coastguard Worker 
613*de1e4e89SAndroid Build Coastguard Worker #define parse_tcp parse_udp
parse_udp(int * argc_p,char *** argv_p,struct tc_u32_sel * sel)614*de1e4e89SAndroid Build Coastguard Worker static int parse_udp(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
615*de1e4e89SAndroid Build Coastguard Worker {
616*de1e4e89SAndroid Build Coastguard Worker 	int res = -1;
617*de1e4e89SAndroid Build Coastguard Worker 	int argc = *argc_p;
618*de1e4e89SAndroid Build Coastguard Worker 	char **argv = *argv_p;
619*de1e4e89SAndroid Build Coastguard Worker 
620*de1e4e89SAndroid Build Coastguard Worker 	if (argc < 2)
621*de1e4e89SAndroid Build Coastguard Worker 		return -1;
622*de1e4e89SAndroid Build Coastguard Worker 
623*de1e4e89SAndroid Build Coastguard Worker 	if (strcmp(*argv, "src") == 0) {
624*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
625*de1e4e89SAndroid Build Coastguard Worker 		res = parse_u16(&argc, &argv, sel, 0, -1);
626*de1e4e89SAndroid Build Coastguard Worker 	} else if (strcmp(*argv, "dst") == 0) {
627*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
628*de1e4e89SAndroid Build Coastguard Worker 		res = parse_u16(&argc, &argv, sel, 2, -1);
629*de1e4e89SAndroid Build Coastguard Worker 	} else
630*de1e4e89SAndroid Build Coastguard Worker 		return -1;
631*de1e4e89SAndroid Build Coastguard Worker 
632*de1e4e89SAndroid Build Coastguard Worker 	*argc_p = argc;
633*de1e4e89SAndroid Build Coastguard Worker 	*argv_p = argv;
634*de1e4e89SAndroid Build Coastguard Worker 	return res;
635*de1e4e89SAndroid Build Coastguard Worker }
636*de1e4e89SAndroid Build Coastguard Worker 
637*de1e4e89SAndroid Build Coastguard Worker 
parse_icmp(int * argc_p,char *** argv_p,struct tc_u32_sel * sel)638*de1e4e89SAndroid Build Coastguard Worker static int parse_icmp(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
639*de1e4e89SAndroid Build Coastguard Worker {
640*de1e4e89SAndroid Build Coastguard Worker 	int res = -1;
641*de1e4e89SAndroid Build Coastguard Worker 	int argc = *argc_p;
642*de1e4e89SAndroid Build Coastguard Worker 	char **argv = *argv_p;
643*de1e4e89SAndroid Build Coastguard Worker 
644*de1e4e89SAndroid Build Coastguard Worker 	if (argc < 2)
645*de1e4e89SAndroid Build Coastguard Worker 		return -1;
646*de1e4e89SAndroid Build Coastguard Worker 
647*de1e4e89SAndroid Build Coastguard Worker 	if (strcmp(*argv, "type") == 0) {
648*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
649*de1e4e89SAndroid Build Coastguard Worker 		res = parse_u8(&argc, &argv, sel, 0, -1);
650*de1e4e89SAndroid Build Coastguard Worker 	} else if (strcmp(*argv, "code") == 0) {
651*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
652*de1e4e89SAndroid Build Coastguard Worker 		res = parse_u8(&argc, &argv, sel, 1, -1);
653*de1e4e89SAndroid Build Coastguard Worker 	} else
654*de1e4e89SAndroid Build Coastguard Worker 		return -1;
655*de1e4e89SAndroid Build Coastguard Worker 
656*de1e4e89SAndroid Build Coastguard Worker 	*argc_p = argc;
657*de1e4e89SAndroid Build Coastguard Worker 	*argv_p = argv;
658*de1e4e89SAndroid Build Coastguard Worker 	return res;
659*de1e4e89SAndroid Build Coastguard Worker }
660*de1e4e89SAndroid Build Coastguard Worker 
parse_mark(int * argc_p,char *** argv_p,struct nlmsghdr * n)661*de1e4e89SAndroid Build Coastguard Worker static int parse_mark(int *argc_p, char ***argv_p, struct nlmsghdr *n)
662*de1e4e89SAndroid Build Coastguard Worker {
663*de1e4e89SAndroid Build Coastguard Worker 	int res = -1;
664*de1e4e89SAndroid Build Coastguard Worker 	int argc = *argc_p;
665*de1e4e89SAndroid Build Coastguard Worker 	char **argv = *argv_p;
666*de1e4e89SAndroid Build Coastguard Worker 	struct tc_u32_mark mark;
667*de1e4e89SAndroid Build Coastguard Worker 
668*de1e4e89SAndroid Build Coastguard Worker 	if (argc <= 1)
669*de1e4e89SAndroid Build Coastguard Worker 		return -1;
670*de1e4e89SAndroid Build Coastguard Worker 
671*de1e4e89SAndroid Build Coastguard Worker 	if (get_u32(&mark.val, *argv, 0)) {
672*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "Illegal \"mark\" value\n");
673*de1e4e89SAndroid Build Coastguard Worker 		return -1;
674*de1e4e89SAndroid Build Coastguard Worker 	}
675*de1e4e89SAndroid Build Coastguard Worker 	NEXT_ARG();
676*de1e4e89SAndroid Build Coastguard Worker 
677*de1e4e89SAndroid Build Coastguard Worker 	if (get_u32(&mark.mask, *argv, 0)) {
678*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "Illegal \"mark\" mask\n");
679*de1e4e89SAndroid Build Coastguard Worker 		return -1;
680*de1e4e89SAndroid Build Coastguard Worker 	}
681*de1e4e89SAndroid Build Coastguard Worker 	NEXT_ARG();
682*de1e4e89SAndroid Build Coastguard Worker 
683*de1e4e89SAndroid Build Coastguard Worker 	if ((mark.val & mark.mask) != mark.val) {
684*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "Illegal \"mark\" (impossible combination)\n");
685*de1e4e89SAndroid Build Coastguard Worker 		return -1;
686*de1e4e89SAndroid Build Coastguard Worker 	}
687*de1e4e89SAndroid Build Coastguard Worker 
688*de1e4e89SAndroid Build Coastguard Worker 	addattr_l(n, MAX_MSG, TCA_U32_MARK, &mark, sizeof(mark));
689*de1e4e89SAndroid Build Coastguard Worker 	res = 0;
690*de1e4e89SAndroid Build Coastguard Worker 
691*de1e4e89SAndroid Build Coastguard Worker 	*argc_p = argc;
692*de1e4e89SAndroid Build Coastguard Worker 	*argv_p = argv;
693*de1e4e89SAndroid Build Coastguard Worker 	return res;
694*de1e4e89SAndroid Build Coastguard Worker }
695*de1e4e89SAndroid Build Coastguard Worker 
parse_selector(int * argc_p,char *** argv_p,struct tc_u32_sel * sel,struct nlmsghdr * n)696*de1e4e89SAndroid Build Coastguard Worker static int parse_selector(int *argc_p, char ***argv_p,
697*de1e4e89SAndroid Build Coastguard Worker 			  struct tc_u32_sel *sel, struct nlmsghdr *n)
698*de1e4e89SAndroid Build Coastguard Worker {
699*de1e4e89SAndroid Build Coastguard Worker 	int argc = *argc_p;
700*de1e4e89SAndroid Build Coastguard Worker 	char **argv = *argv_p;
701*de1e4e89SAndroid Build Coastguard Worker 	int res = -1;
702*de1e4e89SAndroid Build Coastguard Worker 
703*de1e4e89SAndroid Build Coastguard Worker 	if (argc <= 0)
704*de1e4e89SAndroid Build Coastguard Worker 		return -1;
705*de1e4e89SAndroid Build Coastguard Worker 
706*de1e4e89SAndroid Build Coastguard Worker 	if (matches(*argv, "u32") == 0) {
707*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
708*de1e4e89SAndroid Build Coastguard Worker 		res = parse_u32(&argc, &argv, sel, 0, 0);
709*de1e4e89SAndroid Build Coastguard Worker 	} else if (matches(*argv, "u16") == 0) {
710*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
711*de1e4e89SAndroid Build Coastguard Worker 		res = parse_u16(&argc, &argv, sel, 0, 0);
712*de1e4e89SAndroid Build Coastguard Worker 	} else if (matches(*argv, "u8") == 0) {
713*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
714*de1e4e89SAndroid Build Coastguard Worker 		res = parse_u8(&argc, &argv, sel, 0, 0);
715*de1e4e89SAndroid Build Coastguard Worker 	} else if (matches(*argv, "ip") == 0) {
716*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
717*de1e4e89SAndroid Build Coastguard Worker 		res = parse_ip(&argc, &argv, sel);
718*de1e4e89SAndroid Build Coastguard Worker 	} else	if (matches(*argv, "ip6") == 0) {
719*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
720*de1e4e89SAndroid Build Coastguard Worker 		res = parse_ip6(&argc, &argv, sel);
721*de1e4e89SAndroid Build Coastguard Worker 	} else if (matches(*argv, "udp") == 0) {
722*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
723*de1e4e89SAndroid Build Coastguard Worker 		res = parse_udp(&argc, &argv, sel);
724*de1e4e89SAndroid Build Coastguard Worker 	} else if (matches(*argv, "tcp") == 0) {
725*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
726*de1e4e89SAndroid Build Coastguard Worker 		res = parse_tcp(&argc, &argv, sel);
727*de1e4e89SAndroid Build Coastguard Worker 	} else if (matches(*argv, "icmp") == 0) {
728*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
729*de1e4e89SAndroid Build Coastguard Worker 		res = parse_icmp(&argc, &argv, sel);
730*de1e4e89SAndroid Build Coastguard Worker 	} else if (matches(*argv, "mark") == 0) {
731*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
732*de1e4e89SAndroid Build Coastguard Worker 		res = parse_mark(&argc, &argv, n);
733*de1e4e89SAndroid Build Coastguard Worker 	} else if (matches(*argv, "ether") == 0) {
734*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
735*de1e4e89SAndroid Build Coastguard Worker 		res = parse_ether(&argc, &argv, sel);
736*de1e4e89SAndroid Build Coastguard Worker 	} else
737*de1e4e89SAndroid Build Coastguard Worker 		return -1;
738*de1e4e89SAndroid Build Coastguard Worker 
739*de1e4e89SAndroid Build Coastguard Worker 	*argc_p = argc;
740*de1e4e89SAndroid Build Coastguard Worker 	*argv_p = argv;
741*de1e4e89SAndroid Build Coastguard Worker 	return res;
742*de1e4e89SAndroid Build Coastguard Worker }
743*de1e4e89SAndroid Build Coastguard Worker 
parse_offset(int * argc_p,char *** argv_p,struct tc_u32_sel * sel)744*de1e4e89SAndroid Build Coastguard Worker static int parse_offset(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
745*de1e4e89SAndroid Build Coastguard Worker {
746*de1e4e89SAndroid Build Coastguard Worker 	int argc = *argc_p;
747*de1e4e89SAndroid Build Coastguard Worker 	char **argv = *argv_p;
748*de1e4e89SAndroid Build Coastguard Worker 
749*de1e4e89SAndroid Build Coastguard Worker 	while (argc > 0) {
750*de1e4e89SAndroid Build Coastguard Worker 		if (matches(*argv, "plus") == 0) {
751*de1e4e89SAndroid Build Coastguard Worker 			int off;
752*de1e4e89SAndroid Build Coastguard Worker 
753*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
754*de1e4e89SAndroid Build Coastguard Worker 			if (get_integer(&off, *argv, 0))
755*de1e4e89SAndroid Build Coastguard Worker 				return -1;
756*de1e4e89SAndroid Build Coastguard Worker 			sel->off = off;
757*de1e4e89SAndroid Build Coastguard Worker 			sel->flags |= TC_U32_OFFSET;
758*de1e4e89SAndroid Build Coastguard Worker 		} else if (matches(*argv, "at") == 0) {
759*de1e4e89SAndroid Build Coastguard Worker 			int off;
760*de1e4e89SAndroid Build Coastguard Worker 
761*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
762*de1e4e89SAndroid Build Coastguard Worker 			if (get_integer(&off, *argv, 0))
763*de1e4e89SAndroid Build Coastguard Worker 				return -1;
764*de1e4e89SAndroid Build Coastguard Worker 			sel->offoff = off;
765*de1e4e89SAndroid Build Coastguard Worker 			if (off%2) {
766*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "offset \"at\" must be even\n");
767*de1e4e89SAndroid Build Coastguard Worker 				return -1;
768*de1e4e89SAndroid Build Coastguard Worker 			}
769*de1e4e89SAndroid Build Coastguard Worker 			sel->flags |= TC_U32_VAROFFSET;
770*de1e4e89SAndroid Build Coastguard Worker 		} else if (matches(*argv, "mask") == 0) {
771*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
772*de1e4e89SAndroid Build Coastguard Worker 			if (get_be16(&sel->offmask, *argv, 16))
773*de1e4e89SAndroid Build Coastguard Worker 				return -1;
774*de1e4e89SAndroid Build Coastguard Worker 			sel->flags |= TC_U32_VAROFFSET;
775*de1e4e89SAndroid Build Coastguard Worker 		} else if (matches(*argv, "shift") == 0) {
776*de1e4e89SAndroid Build Coastguard Worker 			int shift;
777*de1e4e89SAndroid Build Coastguard Worker 
778*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
779*de1e4e89SAndroid Build Coastguard Worker 			if (get_integer(&shift, *argv, 0))
780*de1e4e89SAndroid Build Coastguard Worker 				return -1;
781*de1e4e89SAndroid Build Coastguard Worker 			sel->offshift = shift;
782*de1e4e89SAndroid Build Coastguard Worker 			sel->flags |= TC_U32_VAROFFSET;
783*de1e4e89SAndroid Build Coastguard Worker 		} else if (matches(*argv, "eat") == 0) {
784*de1e4e89SAndroid Build Coastguard Worker 			sel->flags |= TC_U32_EAT;
785*de1e4e89SAndroid Build Coastguard Worker 		} else {
786*de1e4e89SAndroid Build Coastguard Worker 			break;
787*de1e4e89SAndroid Build Coastguard Worker 		}
788*de1e4e89SAndroid Build Coastguard Worker 		argc--; argv++;
789*de1e4e89SAndroid Build Coastguard Worker 	}
790*de1e4e89SAndroid Build Coastguard Worker 
791*de1e4e89SAndroid Build Coastguard Worker 	*argc_p = argc;
792*de1e4e89SAndroid Build Coastguard Worker 	*argv_p = argv;
793*de1e4e89SAndroid Build Coastguard Worker 	return 0;
794*de1e4e89SAndroid Build Coastguard Worker }
795*de1e4e89SAndroid Build Coastguard Worker 
parse_hashkey(int * argc_p,char *** argv_p,struct tc_u32_sel * sel)796*de1e4e89SAndroid Build Coastguard Worker static int parse_hashkey(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
797*de1e4e89SAndroid Build Coastguard Worker {
798*de1e4e89SAndroid Build Coastguard Worker 	int argc = *argc_p;
799*de1e4e89SAndroid Build Coastguard Worker 	char **argv = *argv_p;
800*de1e4e89SAndroid Build Coastguard Worker 
801*de1e4e89SAndroid Build Coastguard Worker 	while (argc > 0) {
802*de1e4e89SAndroid Build Coastguard Worker 		if (matches(*argv, "mask") == 0) {
803*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
804*de1e4e89SAndroid Build Coastguard Worker 			if (get_be32(&sel->hmask, *argv, 16))
805*de1e4e89SAndroid Build Coastguard Worker 				return -1;
806*de1e4e89SAndroid Build Coastguard Worker 		} else if (matches(*argv, "at") == 0) {
807*de1e4e89SAndroid Build Coastguard Worker 			int num;
808*de1e4e89SAndroid Build Coastguard Worker 
809*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
810*de1e4e89SAndroid Build Coastguard Worker 			if (get_integer(&num, *argv, 0))
811*de1e4e89SAndroid Build Coastguard Worker 				return -1;
812*de1e4e89SAndroid Build Coastguard Worker 			if (num%4)
813*de1e4e89SAndroid Build Coastguard Worker 				return -1;
814*de1e4e89SAndroid Build Coastguard Worker 			sel->hoff = num;
815*de1e4e89SAndroid Build Coastguard Worker 		} else {
816*de1e4e89SAndroid Build Coastguard Worker 			break;
817*de1e4e89SAndroid Build Coastguard Worker 		}
818*de1e4e89SAndroid Build Coastguard Worker 		argc--; argv++;
819*de1e4e89SAndroid Build Coastguard Worker 	}
820*de1e4e89SAndroid Build Coastguard Worker 
821*de1e4e89SAndroid Build Coastguard Worker 	*argc_p = argc;
822*de1e4e89SAndroid Build Coastguard Worker 	*argv_p = argv;
823*de1e4e89SAndroid Build Coastguard Worker 	return 0;
824*de1e4e89SAndroid Build Coastguard Worker }
825*de1e4e89SAndroid Build Coastguard Worker 
print_ipv4(FILE * f,const struct tc_u32_key * key)826*de1e4e89SAndroid Build Coastguard Worker static void print_ipv4(FILE *f, const struct tc_u32_key *key)
827*de1e4e89SAndroid Build Coastguard Worker {
828*de1e4e89SAndroid Build Coastguard Worker 	char abuf[256];
829*de1e4e89SAndroid Build Coastguard Worker 
830*de1e4e89SAndroid Build Coastguard Worker 	switch (key->off) {
831*de1e4e89SAndroid Build Coastguard Worker 	case 0:
832*de1e4e89SAndroid Build Coastguard Worker 		switch (ntohl(key->mask)) {
833*de1e4e89SAndroid Build Coastguard Worker 		case 0x0f000000:
834*de1e4e89SAndroid Build Coastguard Worker 			fprintf(f, "\n  match IP ihl %u",
835*de1e4e89SAndroid Build Coastguard Worker 				ntohl(key->val) >> 24);
836*de1e4e89SAndroid Build Coastguard Worker 			return;
837*de1e4e89SAndroid Build Coastguard Worker 		case 0x00ff0000:
838*de1e4e89SAndroid Build Coastguard Worker 			fprintf(f, "\n  match IP dsfield %#x",
839*de1e4e89SAndroid Build Coastguard Worker 				ntohl(key->val) >> 16);
840*de1e4e89SAndroid Build Coastguard Worker 			return;
841*de1e4e89SAndroid Build Coastguard Worker 		}
842*de1e4e89SAndroid Build Coastguard Worker 		break;
843*de1e4e89SAndroid Build Coastguard Worker 	case 8:
844*de1e4e89SAndroid Build Coastguard Worker 		if (ntohl(key->mask) == 0x00ff0000) {
845*de1e4e89SAndroid Build Coastguard Worker 			fprintf(f, "\n  match IP protocol %d",
846*de1e4e89SAndroid Build Coastguard Worker 				ntohl(key->val) >> 16);
847*de1e4e89SAndroid Build Coastguard Worker 			return;
848*de1e4e89SAndroid Build Coastguard Worker 		}
849*de1e4e89SAndroid Build Coastguard Worker 		break;
850*de1e4e89SAndroid Build Coastguard Worker 	case 12:
851*de1e4e89SAndroid Build Coastguard Worker 	case 16: {
852*de1e4e89SAndroid Build Coastguard Worker 			int bits = mask2bits(key->mask);
853*de1e4e89SAndroid Build Coastguard Worker 
854*de1e4e89SAndroid Build Coastguard Worker 			if (bits >= 0) {
855*de1e4e89SAndroid Build Coastguard Worker 				fprintf(f, "\n  %s %s/%d",
856*de1e4e89SAndroid Build Coastguard Worker 					key->off == 12 ? "match IP src" : "match IP dst",
857*de1e4e89SAndroid Build Coastguard Worker 					inet_ntop(AF_INET, &key->val,
858*de1e4e89SAndroid Build Coastguard Worker 						  abuf, sizeof(abuf)),
859*de1e4e89SAndroid Build Coastguard Worker 					bits);
860*de1e4e89SAndroid Build Coastguard Worker 				return;
861*de1e4e89SAndroid Build Coastguard Worker 			}
862*de1e4e89SAndroid Build Coastguard Worker 		}
863*de1e4e89SAndroid Build Coastguard Worker 		break;
864*de1e4e89SAndroid Build Coastguard Worker 
865*de1e4e89SAndroid Build Coastguard Worker 	case 20:
866*de1e4e89SAndroid Build Coastguard Worker 		switch (ntohl(key->mask)) {
867*de1e4e89SAndroid Build Coastguard Worker 		case 0x0000ffff:
868*de1e4e89SAndroid Build Coastguard Worker 			fprintf(f, "\n  match dport %u",
869*de1e4e89SAndroid Build Coastguard Worker 				ntohl(key->val) & 0xffff);
870*de1e4e89SAndroid Build Coastguard Worker 			return;
871*de1e4e89SAndroid Build Coastguard Worker 		case 0xffff0000:
872*de1e4e89SAndroid Build Coastguard Worker 			fprintf(f, "\n  match sport %u",
873*de1e4e89SAndroid Build Coastguard Worker 				ntohl(key->val) >> 16);
874*de1e4e89SAndroid Build Coastguard Worker 			return;
875*de1e4e89SAndroid Build Coastguard Worker 		case 0xffffffff:
876*de1e4e89SAndroid Build Coastguard Worker 			fprintf(f, "\n  match dport %u, match sport %u",
877*de1e4e89SAndroid Build Coastguard Worker 				ntohl(key->val) & 0xffff,
878*de1e4e89SAndroid Build Coastguard Worker 				ntohl(key->val) >> 16);
879*de1e4e89SAndroid Build Coastguard Worker 
880*de1e4e89SAndroid Build Coastguard Worker 			return;
881*de1e4e89SAndroid Build Coastguard Worker 		}
882*de1e4e89SAndroid Build Coastguard Worker 		/* XXX: Default print_raw */
883*de1e4e89SAndroid Build Coastguard Worker 	}
884*de1e4e89SAndroid Build Coastguard Worker }
885*de1e4e89SAndroid Build Coastguard Worker 
print_ipv6(FILE * f,const struct tc_u32_key * key)886*de1e4e89SAndroid Build Coastguard Worker static void print_ipv6(FILE *f, const struct tc_u32_key *key)
887*de1e4e89SAndroid Build Coastguard Worker {
888*de1e4e89SAndroid Build Coastguard Worker 	char abuf[256];
889*de1e4e89SAndroid Build Coastguard Worker 
890*de1e4e89SAndroid Build Coastguard Worker 	switch (key->off) {
891*de1e4e89SAndroid Build Coastguard Worker 	case 0:
892*de1e4e89SAndroid Build Coastguard Worker 		switch (ntohl(key->mask)) {
893*de1e4e89SAndroid Build Coastguard Worker 		case 0x0f000000:
894*de1e4e89SAndroid Build Coastguard Worker 			fprintf(f, "\n  match IP ihl %u",
895*de1e4e89SAndroid Build Coastguard Worker 				ntohl(key->val) >> 24);
896*de1e4e89SAndroid Build Coastguard Worker 			return;
897*de1e4e89SAndroid Build Coastguard Worker 		case 0x00ff0000:
898*de1e4e89SAndroid Build Coastguard Worker 			fprintf(f, "\n  match IP dsfield %#x",
899*de1e4e89SAndroid Build Coastguard Worker 				ntohl(key->val) >> 16);
900*de1e4e89SAndroid Build Coastguard Worker 			return;
901*de1e4e89SAndroid Build Coastguard Worker 		}
902*de1e4e89SAndroid Build Coastguard Worker 		break;
903*de1e4e89SAndroid Build Coastguard Worker 	case 8:
904*de1e4e89SAndroid Build Coastguard Worker 		if (ntohl(key->mask) == 0x00ff0000) {
905*de1e4e89SAndroid Build Coastguard Worker 			fprintf(f, "\n  match IP protocol %d",
906*de1e4e89SAndroid Build Coastguard Worker 				ntohl(key->val) >> 16);
907*de1e4e89SAndroid Build Coastguard Worker 			return;
908*de1e4e89SAndroid Build Coastguard Worker 		}
909*de1e4e89SAndroid Build Coastguard Worker 		break;
910*de1e4e89SAndroid Build Coastguard Worker 	case 12:
911*de1e4e89SAndroid Build Coastguard Worker 	case 16: {
912*de1e4e89SAndroid Build Coastguard Worker 			int bits = mask2bits(key->mask);
913*de1e4e89SAndroid Build Coastguard Worker 
914*de1e4e89SAndroid Build Coastguard Worker 			if (bits >= 0) {
915*de1e4e89SAndroid Build Coastguard Worker 				fprintf(f, "\n  %s %s/%d",
916*de1e4e89SAndroid Build Coastguard Worker 					key->off == 12 ? "match IP src" : "match IP dst",
917*de1e4e89SAndroid Build Coastguard Worker 					inet_ntop(AF_INET, &key->val,
918*de1e4e89SAndroid Build Coastguard Worker 						  abuf, sizeof(abuf)),
919*de1e4e89SAndroid Build Coastguard Worker 					bits);
920*de1e4e89SAndroid Build Coastguard Worker 				return;
921*de1e4e89SAndroid Build Coastguard Worker 			}
922*de1e4e89SAndroid Build Coastguard Worker 		}
923*de1e4e89SAndroid Build Coastguard Worker 		break;
924*de1e4e89SAndroid Build Coastguard Worker 
925*de1e4e89SAndroid Build Coastguard Worker 	case 20:
926*de1e4e89SAndroid Build Coastguard Worker 		switch (ntohl(key->mask)) {
927*de1e4e89SAndroid Build Coastguard Worker 		case 0x0000ffff:
928*de1e4e89SAndroid Build Coastguard Worker 			fprintf(f, "\n  match sport %u",
929*de1e4e89SAndroid Build Coastguard Worker 				ntohl(key->val) & 0xffff);
930*de1e4e89SAndroid Build Coastguard Worker 			return;
931*de1e4e89SAndroid Build Coastguard Worker 		case 0xffff0000:
932*de1e4e89SAndroid Build Coastguard Worker 			fprintf(f, "\n  match dport %u",
933*de1e4e89SAndroid Build Coastguard Worker 				ntohl(key->val) >> 16);
934*de1e4e89SAndroid Build Coastguard Worker 			return;
935*de1e4e89SAndroid Build Coastguard Worker 		case 0xffffffff:
936*de1e4e89SAndroid Build Coastguard Worker 			fprintf(f, "\n  match sport %u, match dport %u",
937*de1e4e89SAndroid Build Coastguard Worker 				ntohl(key->val) & 0xffff,
938*de1e4e89SAndroid Build Coastguard Worker 				ntohl(key->val) >> 16);
939*de1e4e89SAndroid Build Coastguard Worker 
940*de1e4e89SAndroid Build Coastguard Worker 			return;
941*de1e4e89SAndroid Build Coastguard Worker 		}
942*de1e4e89SAndroid Build Coastguard Worker 		/* XXX: Default print_raw */
943*de1e4e89SAndroid Build Coastguard Worker 	}
944*de1e4e89SAndroid Build Coastguard Worker }
945*de1e4e89SAndroid Build Coastguard Worker 
print_raw(FILE * f,const struct tc_u32_key * key)946*de1e4e89SAndroid Build Coastguard Worker static void print_raw(FILE *f, const struct tc_u32_key *key)
947*de1e4e89SAndroid Build Coastguard Worker {
948*de1e4e89SAndroid Build Coastguard Worker 	fprintf(f, "\n  match %08x/%08x at %s%d",
949*de1e4e89SAndroid Build Coastguard Worker 		(unsigned int)ntohl(key->val),
950*de1e4e89SAndroid Build Coastguard Worker 		(unsigned int)ntohl(key->mask),
951*de1e4e89SAndroid Build Coastguard Worker 		key->offmask ? "nexthdr+" : "",
952*de1e4e89SAndroid Build Coastguard Worker 		key->off);
953*de1e4e89SAndroid Build Coastguard Worker }
954*de1e4e89SAndroid Build Coastguard Worker 
955*de1e4e89SAndroid Build Coastguard Worker static const struct {
956*de1e4e89SAndroid Build Coastguard Worker 	__u16 proto;
957*de1e4e89SAndroid Build Coastguard Worker 	__u16 pad;
958*de1e4e89SAndroid Build Coastguard Worker 	void (*pprinter)(FILE *f, const struct tc_u32_key *key);
959*de1e4e89SAndroid Build Coastguard Worker } u32_pprinters[] = {
960*de1e4e89SAndroid Build Coastguard Worker 	{0,	   0, print_raw},
961*de1e4e89SAndroid Build Coastguard Worker 	{ETH_P_IP, 0, print_ipv4},
962*de1e4e89SAndroid Build Coastguard Worker 	{ETH_P_IPV6, 0, print_ipv6},
963*de1e4e89SAndroid Build Coastguard Worker };
964*de1e4e89SAndroid Build Coastguard Worker 
show_keys(FILE * f,const struct tc_u32_key * key)965*de1e4e89SAndroid Build Coastguard Worker static void show_keys(FILE *f, const struct tc_u32_key *key)
966*de1e4e89SAndroid Build Coastguard Worker {
967*de1e4e89SAndroid Build Coastguard Worker 	int i = 0;
968*de1e4e89SAndroid Build Coastguard Worker 
969*de1e4e89SAndroid Build Coastguard Worker 	if (!show_pretty)
970*de1e4e89SAndroid Build Coastguard Worker 		goto show_k;
971*de1e4e89SAndroid Build Coastguard Worker 
972*de1e4e89SAndroid Build Coastguard Worker 	for (i = 0; i < ARRAY_SIZE(u32_pprinters); i++) {
973*de1e4e89SAndroid Build Coastguard Worker 		if (u32_pprinters[i].proto == ntohs(f_proto)) {
974*de1e4e89SAndroid Build Coastguard Worker show_k:
975*de1e4e89SAndroid Build Coastguard Worker 			u32_pprinters[i].pprinter(f, key);
976*de1e4e89SAndroid Build Coastguard Worker 			return;
977*de1e4e89SAndroid Build Coastguard Worker 		}
978*de1e4e89SAndroid Build Coastguard Worker 	}
979*de1e4e89SAndroid Build Coastguard Worker 
980*de1e4e89SAndroid Build Coastguard Worker 	i = 0;
981*de1e4e89SAndroid Build Coastguard Worker 	goto show_k;
982*de1e4e89SAndroid Build Coastguard Worker }
983*de1e4e89SAndroid Build Coastguard Worker 
u32_parse_opt(struct filter_util * qu,char * handle,int argc,char ** argv,struct nlmsghdr * n)984*de1e4e89SAndroid Build Coastguard Worker static int u32_parse_opt(struct filter_util *qu, char *handle,
985*de1e4e89SAndroid Build Coastguard Worker 			 int argc, char **argv, struct nlmsghdr *n)
986*de1e4e89SAndroid Build Coastguard Worker {
987*de1e4e89SAndroid Build Coastguard Worker 	struct {
988*de1e4e89SAndroid Build Coastguard Worker 		struct tc_u32_sel sel;
989*de1e4e89SAndroid Build Coastguard Worker 		struct tc_u32_key keys[128];
990*de1e4e89SAndroid Build Coastguard Worker 	} sel = {};
991*de1e4e89SAndroid Build Coastguard Worker 	struct tcmsg *t = NLMSG_DATA(n);
992*de1e4e89SAndroid Build Coastguard Worker 	struct rtattr *tail;
993*de1e4e89SAndroid Build Coastguard Worker 	int sel_ok = 0, terminal_ok = 0;
994*de1e4e89SAndroid Build Coastguard Worker 	int sample_ok = 0;
995*de1e4e89SAndroid Build Coastguard Worker 	__u32 htid = 0;
996*de1e4e89SAndroid Build Coastguard Worker 	__u32 order = 0;
997*de1e4e89SAndroid Build Coastguard Worker 	__u32 flags = 0;
998*de1e4e89SAndroid Build Coastguard Worker 
999*de1e4e89SAndroid Build Coastguard Worker 	if (handle && get_u32_handle(&t->tcm_handle, handle)) {
1000*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "Illegal filter ID\n");
1001*de1e4e89SAndroid Build Coastguard Worker 		return -1;
1002*de1e4e89SAndroid Build Coastguard Worker 	}
1003*de1e4e89SAndroid Build Coastguard Worker 
1004*de1e4e89SAndroid Build Coastguard Worker 	if (argc == 0)
1005*de1e4e89SAndroid Build Coastguard Worker 		return 0;
1006*de1e4e89SAndroid Build Coastguard Worker 
1007*de1e4e89SAndroid Build Coastguard Worker 	tail = NLMSG_TAIL(n);
1008*de1e4e89SAndroid Build Coastguard Worker 	addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0);
1009*de1e4e89SAndroid Build Coastguard Worker 
1010*de1e4e89SAndroid Build Coastguard Worker 	while (argc > 0) {
1011*de1e4e89SAndroid Build Coastguard Worker 		if (matches(*argv, "match") == 0) {
1012*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
1013*de1e4e89SAndroid Build Coastguard Worker 			if (parse_selector(&argc, &argv, &sel.sel, n)) {
1014*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "Illegal \"match\"\n");
1015*de1e4e89SAndroid Build Coastguard Worker 				return -1;
1016*de1e4e89SAndroid Build Coastguard Worker 			}
1017*de1e4e89SAndroid Build Coastguard Worker 			sel_ok++;
1018*de1e4e89SAndroid Build Coastguard Worker 			continue;
1019*de1e4e89SAndroid Build Coastguard Worker 		} else if (matches(*argv, "offset") == 0) {
1020*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
1021*de1e4e89SAndroid Build Coastguard Worker 			if (parse_offset(&argc, &argv, &sel.sel)) {
1022*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "Illegal \"offset\"\n");
1023*de1e4e89SAndroid Build Coastguard Worker 				return -1;
1024*de1e4e89SAndroid Build Coastguard Worker 			}
1025*de1e4e89SAndroid Build Coastguard Worker 			continue;
1026*de1e4e89SAndroid Build Coastguard Worker 		} else if (matches(*argv, "hashkey") == 0) {
1027*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
1028*de1e4e89SAndroid Build Coastguard Worker 			if (parse_hashkey(&argc, &argv, &sel.sel)) {
1029*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "Illegal \"hashkey\"\n");
1030*de1e4e89SAndroid Build Coastguard Worker 				return -1;
1031*de1e4e89SAndroid Build Coastguard Worker 			}
1032*de1e4e89SAndroid Build Coastguard Worker 			continue;
1033*de1e4e89SAndroid Build Coastguard Worker 		} else if (matches(*argv, "classid") == 0 ||
1034*de1e4e89SAndroid Build Coastguard Worker 			   strcmp(*argv, "flowid") == 0) {
1035*de1e4e89SAndroid Build Coastguard Worker 			unsigned int flowid;
1036*de1e4e89SAndroid Build Coastguard Worker 
1037*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
1038*de1e4e89SAndroid Build Coastguard Worker 			if (get_tc_classid(&flowid, *argv)) {
1039*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "Illegal \"classid\"\n");
1040*de1e4e89SAndroid Build Coastguard Worker 				return -1;
1041*de1e4e89SAndroid Build Coastguard Worker 			}
1042*de1e4e89SAndroid Build Coastguard Worker 			addattr_l(n, MAX_MSG, TCA_U32_CLASSID, &flowid, 4);
1043*de1e4e89SAndroid Build Coastguard Worker 			sel.sel.flags |= TC_U32_TERMINAL;
1044*de1e4e89SAndroid Build Coastguard Worker 		} else if (matches(*argv, "divisor") == 0) {
1045*de1e4e89SAndroid Build Coastguard Worker 			unsigned int divisor;
1046*de1e4e89SAndroid Build Coastguard Worker 
1047*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
1048*de1e4e89SAndroid Build Coastguard Worker 			if (get_unsigned(&divisor, *argv, 0) ||
1049*de1e4e89SAndroid Build Coastguard Worker 			    divisor == 0 ||
1050*de1e4e89SAndroid Build Coastguard Worker 			    divisor > 0x100 || ((divisor - 1) & divisor)) {
1051*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "Illegal \"divisor\"\n");
1052*de1e4e89SAndroid Build Coastguard Worker 				return -1;
1053*de1e4e89SAndroid Build Coastguard Worker 			}
1054*de1e4e89SAndroid Build Coastguard Worker 			addattr_l(n, MAX_MSG, TCA_U32_DIVISOR, &divisor, 4);
1055*de1e4e89SAndroid Build Coastguard Worker 		} else if (matches(*argv, "order") == 0) {
1056*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
1057*de1e4e89SAndroid Build Coastguard Worker 			if (get_u32(&order, *argv, 0)) {
1058*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "Illegal \"order\"\n");
1059*de1e4e89SAndroid Build Coastguard Worker 				return -1;
1060*de1e4e89SAndroid Build Coastguard Worker 			}
1061*de1e4e89SAndroid Build Coastguard Worker 		} else if (strcmp(*argv, "link") == 0) {
1062*de1e4e89SAndroid Build Coastguard Worker 			unsigned int linkid;
1063*de1e4e89SAndroid Build Coastguard Worker 
1064*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
1065*de1e4e89SAndroid Build Coastguard Worker 			if (get_u32_handle(&linkid, *argv)) {
1066*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "Illegal \"link\"\n");
1067*de1e4e89SAndroid Build Coastguard Worker 				return -1;
1068*de1e4e89SAndroid Build Coastguard Worker 			}
1069*de1e4e89SAndroid Build Coastguard Worker 			if (linkid && TC_U32_NODE(linkid)) {
1070*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "\"link\" must be a hash table.\n");
1071*de1e4e89SAndroid Build Coastguard Worker 				return -1;
1072*de1e4e89SAndroid Build Coastguard Worker 			}
1073*de1e4e89SAndroid Build Coastguard Worker 			addattr_l(n, MAX_MSG, TCA_U32_LINK, &linkid, 4);
1074*de1e4e89SAndroid Build Coastguard Worker 		} else if (strcmp(*argv, "ht") == 0) {
1075*de1e4e89SAndroid Build Coastguard Worker 			unsigned int ht;
1076*de1e4e89SAndroid Build Coastguard Worker 
1077*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
1078*de1e4e89SAndroid Build Coastguard Worker 			if (get_u32_handle(&ht, *argv)) {
1079*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "Illegal \"ht\"\n");
1080*de1e4e89SAndroid Build Coastguard Worker 				return -1;
1081*de1e4e89SAndroid Build Coastguard Worker 			}
1082*de1e4e89SAndroid Build Coastguard Worker 			if (handle && TC_U32_NODE(ht)) {
1083*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "\"ht\" must be a hash table.\n");
1084*de1e4e89SAndroid Build Coastguard Worker 				return -1;
1085*de1e4e89SAndroid Build Coastguard Worker 			}
1086*de1e4e89SAndroid Build Coastguard Worker 			if (sample_ok)
1087*de1e4e89SAndroid Build Coastguard Worker 				htid = (htid & 0xFF000) | (ht & 0xFFF00000);
1088*de1e4e89SAndroid Build Coastguard Worker 			else
1089*de1e4e89SAndroid Build Coastguard Worker 				htid = (ht & 0xFFFFF000);
1090*de1e4e89SAndroid Build Coastguard Worker 		} else if (strcmp(*argv, "sample") == 0) {
1091*de1e4e89SAndroid Build Coastguard Worker 			__u32 hash;
1092*de1e4e89SAndroid Build Coastguard Worker 			unsigned int divisor = 0x100;
1093*de1e4e89SAndroid Build Coastguard Worker 			struct {
1094*de1e4e89SAndroid Build Coastguard Worker 				struct tc_u32_sel sel;
1095*de1e4e89SAndroid Build Coastguard Worker 				struct tc_u32_key keys[4];
1096*de1e4e89SAndroid Build Coastguard Worker 			} sel2 = {};
1097*de1e4e89SAndroid Build Coastguard Worker 
1098*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
1099*de1e4e89SAndroid Build Coastguard Worker 			if (parse_selector(&argc, &argv, &sel2.sel, n)) {
1100*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "Illegal \"sample\"\n");
1101*de1e4e89SAndroid Build Coastguard Worker 				return -1;
1102*de1e4e89SAndroid Build Coastguard Worker 			}
1103*de1e4e89SAndroid Build Coastguard Worker 			if (sel2.sel.nkeys != 1) {
1104*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "\"sample\" must contain exactly ONE key.\n");
1105*de1e4e89SAndroid Build Coastguard Worker 				return -1;
1106*de1e4e89SAndroid Build Coastguard Worker 			}
1107*de1e4e89SAndroid Build Coastguard Worker 			if (*argv != 0 && strcmp(*argv, "divisor") == 0) {
1108*de1e4e89SAndroid Build Coastguard Worker 				NEXT_ARG();
1109*de1e4e89SAndroid Build Coastguard Worker 				if (get_unsigned(&divisor, *argv, 0) ||
1110*de1e4e89SAndroid Build Coastguard Worker 				    divisor == 0 || divisor > 0x100 ||
1111*de1e4e89SAndroid Build Coastguard Worker 				    ((divisor - 1) & divisor)) {
1112*de1e4e89SAndroid Build Coastguard Worker 					fprintf(stderr, "Illegal sample \"divisor\"\n");
1113*de1e4e89SAndroid Build Coastguard Worker 					return -1;
1114*de1e4e89SAndroid Build Coastguard Worker 				}
1115*de1e4e89SAndroid Build Coastguard Worker 				NEXT_ARG();
1116*de1e4e89SAndroid Build Coastguard Worker 			}
1117*de1e4e89SAndroid Build Coastguard Worker 			hash = sel2.sel.keys[0].val & sel2.sel.keys[0].mask;
1118*de1e4e89SAndroid Build Coastguard Worker 			hash ^= hash >> 16;
1119*de1e4e89SAndroid Build Coastguard Worker 			hash ^= hash >> 8;
1120*de1e4e89SAndroid Build Coastguard Worker 			htid = ((hash % divisor) << 12) | (htid & 0xFFF00000);
1121*de1e4e89SAndroid Build Coastguard Worker 			sample_ok = 1;
1122*de1e4e89SAndroid Build Coastguard Worker 			continue;
1123*de1e4e89SAndroid Build Coastguard Worker 		} else if (strcmp(*argv, "indev") == 0) {
1124*de1e4e89SAndroid Build Coastguard Worker 			char ind[IFNAMSIZ + 1] = {};
1125*de1e4e89SAndroid Build Coastguard Worker 
1126*de1e4e89SAndroid Build Coastguard Worker 			argc--;
1127*de1e4e89SAndroid Build Coastguard Worker 			argv++;
1128*de1e4e89SAndroid Build Coastguard Worker 			if (argc < 1) {
1129*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "Illegal indev\n");
1130*de1e4e89SAndroid Build Coastguard Worker 				return -1;
1131*de1e4e89SAndroid Build Coastguard Worker 			}
1132*de1e4e89SAndroid Build Coastguard Worker 			strncpy(ind, *argv, sizeof(ind) - 1);
1133*de1e4e89SAndroid Build Coastguard Worker 			addattr_l(n, MAX_MSG, TCA_U32_INDEV, ind,
1134*de1e4e89SAndroid Build Coastguard Worker 				  strlen(ind) + 1);
1135*de1e4e89SAndroid Build Coastguard Worker 
1136*de1e4e89SAndroid Build Coastguard Worker 		} else if (matches(*argv, "action") == 0) {
1137*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
1138*de1e4e89SAndroid Build Coastguard Worker 			if (parse_action(&argc, &argv, TCA_U32_ACT, n)) {
1139*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "Illegal \"action\"\n");
1140*de1e4e89SAndroid Build Coastguard Worker 				return -1;
1141*de1e4e89SAndroid Build Coastguard Worker 			}
1142*de1e4e89SAndroid Build Coastguard Worker 			terminal_ok++;
1143*de1e4e89SAndroid Build Coastguard Worker 			continue;
1144*de1e4e89SAndroid Build Coastguard Worker 
1145*de1e4e89SAndroid Build Coastguard Worker 		} else if (matches(*argv, "police") == 0) {
1146*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
1147*de1e4e89SAndroid Build Coastguard Worker 			if (parse_police(&argc, &argv, TCA_U32_POLICE, n)) {
1148*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "Illegal \"police\"\n");
1149*de1e4e89SAndroid Build Coastguard Worker 				return -1;
1150*de1e4e89SAndroid Build Coastguard Worker 			}
1151*de1e4e89SAndroid Build Coastguard Worker 			terminal_ok++;
1152*de1e4e89SAndroid Build Coastguard Worker 			continue;
1153*de1e4e89SAndroid Build Coastguard Worker 		} else if (strcmp(*argv, "skip_hw") == 0) {
1154*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
1155*de1e4e89SAndroid Build Coastguard Worker 			flags |= TCA_CLS_FLAGS_SKIP_HW;
1156*de1e4e89SAndroid Build Coastguard Worker 			continue;
1157*de1e4e89SAndroid Build Coastguard Worker 		} else if (strcmp(*argv, "skip_sw") == 0) {
1158*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
1159*de1e4e89SAndroid Build Coastguard Worker 			flags |= TCA_CLS_FLAGS_SKIP_SW;
1160*de1e4e89SAndroid Build Coastguard Worker 			continue;
1161*de1e4e89SAndroid Build Coastguard Worker 		} else if (strcmp(*argv, "help") == 0) {
1162*de1e4e89SAndroid Build Coastguard Worker 			explain();
1163*de1e4e89SAndroid Build Coastguard Worker 			return -1;
1164*de1e4e89SAndroid Build Coastguard Worker 		} else {
1165*de1e4e89SAndroid Build Coastguard Worker 			fprintf(stderr, "What is \"%s\"?\n", *argv);
1166*de1e4e89SAndroid Build Coastguard Worker 			explain();
1167*de1e4e89SAndroid Build Coastguard Worker 			return -1;
1168*de1e4e89SAndroid Build Coastguard Worker 		}
1169*de1e4e89SAndroid Build Coastguard Worker 		argc--; argv++;
1170*de1e4e89SAndroid Build Coastguard Worker 	}
1171*de1e4e89SAndroid Build Coastguard Worker 
1172*de1e4e89SAndroid Build Coastguard Worker 	/* We dont necessarily need class/flowids */
1173*de1e4e89SAndroid Build Coastguard Worker 	if (terminal_ok)
1174*de1e4e89SAndroid Build Coastguard Worker 		sel.sel.flags |= TC_U32_TERMINAL;
1175*de1e4e89SAndroid Build Coastguard Worker 
1176*de1e4e89SAndroid Build Coastguard Worker 	if (order) {
1177*de1e4e89SAndroid Build Coastguard Worker 		if (TC_U32_NODE(t->tcm_handle) &&
1178*de1e4e89SAndroid Build Coastguard Worker 		    order != TC_U32_NODE(t->tcm_handle)) {
1179*de1e4e89SAndroid Build Coastguard Worker 			fprintf(stderr, "\"order\" contradicts \"handle\"\n");
1180*de1e4e89SAndroid Build Coastguard Worker 			return -1;
1181*de1e4e89SAndroid Build Coastguard Worker 		}
1182*de1e4e89SAndroid Build Coastguard Worker 		t->tcm_handle |= order;
1183*de1e4e89SAndroid Build Coastguard Worker 	}
1184*de1e4e89SAndroid Build Coastguard Worker 
1185*de1e4e89SAndroid Build Coastguard Worker 	if (htid)
1186*de1e4e89SAndroid Build Coastguard Worker 		addattr_l(n, MAX_MSG, TCA_U32_HASH, &htid, 4);
1187*de1e4e89SAndroid Build Coastguard Worker 	if (sel_ok)
1188*de1e4e89SAndroid Build Coastguard Worker 		addattr_l(n, MAX_MSG, TCA_U32_SEL, &sel,
1189*de1e4e89SAndroid Build Coastguard Worker 			  sizeof(sel.sel) +
1190*de1e4e89SAndroid Build Coastguard Worker 			  sel.sel.nkeys * sizeof(struct tc_u32_key));
1191*de1e4e89SAndroid Build Coastguard Worker 	if (flags) {
1192*de1e4e89SAndroid Build Coastguard Worker 		if (!(flags ^ (TCA_CLS_FLAGS_SKIP_HW |
1193*de1e4e89SAndroid Build Coastguard Worker 			       TCA_CLS_FLAGS_SKIP_SW))) {
1194*de1e4e89SAndroid Build Coastguard Worker 			fprintf(stderr,
1195*de1e4e89SAndroid Build Coastguard Worker 				"skip_hw and skip_sw are mutually exclusive\n");
1196*de1e4e89SAndroid Build Coastguard Worker 			return -1;
1197*de1e4e89SAndroid Build Coastguard Worker 		}
1198*de1e4e89SAndroid Build Coastguard Worker 		addattr_l(n, MAX_MSG, TCA_U32_FLAGS, &flags, 4);
1199*de1e4e89SAndroid Build Coastguard Worker 	}
1200*de1e4e89SAndroid Build Coastguard Worker 
1201*de1e4e89SAndroid Build Coastguard Worker 	tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
1202*de1e4e89SAndroid Build Coastguard Worker 	return 0;
1203*de1e4e89SAndroid Build Coastguard Worker }
1204*de1e4e89SAndroid Build Coastguard Worker 
u32_print_opt(struct filter_util * qu,FILE * f,struct rtattr * opt,__u32 handle)1205*de1e4e89SAndroid Build Coastguard Worker static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt,
1206*de1e4e89SAndroid Build Coastguard Worker 			 __u32 handle)
1207*de1e4e89SAndroid Build Coastguard Worker {
1208*de1e4e89SAndroid Build Coastguard Worker 	struct rtattr *tb[TCA_U32_MAX + 1];
1209*de1e4e89SAndroid Build Coastguard Worker 	struct tc_u32_sel *sel = NULL;
1210*de1e4e89SAndroid Build Coastguard Worker 	struct tc_u32_pcnt *pf = NULL;
1211*de1e4e89SAndroid Build Coastguard Worker 
1212*de1e4e89SAndroid Build Coastguard Worker 	if (opt == NULL)
1213*de1e4e89SAndroid Build Coastguard Worker 		return 0;
1214*de1e4e89SAndroid Build Coastguard Worker 
1215*de1e4e89SAndroid Build Coastguard Worker 	parse_rtattr_nested(tb, TCA_U32_MAX, opt);
1216*de1e4e89SAndroid Build Coastguard Worker 
1217*de1e4e89SAndroid Build Coastguard Worker 	if (handle) {
1218*de1e4e89SAndroid Build Coastguard Worker 		SPRINT_BUF(b1);
1219*de1e4e89SAndroid Build Coastguard Worker 		fprintf(f, "fh %s ", sprint_u32_handle(handle, b1));
1220*de1e4e89SAndroid Build Coastguard Worker 	}
1221*de1e4e89SAndroid Build Coastguard Worker 
1222*de1e4e89SAndroid Build Coastguard Worker 	if (TC_U32_NODE(handle))
1223*de1e4e89SAndroid Build Coastguard Worker 		fprintf(f, "order %d ", TC_U32_NODE(handle));
1224*de1e4e89SAndroid Build Coastguard Worker 
1225*de1e4e89SAndroid Build Coastguard Worker 	if (tb[TCA_U32_SEL]) {
1226*de1e4e89SAndroid Build Coastguard Worker 		if (RTA_PAYLOAD(tb[TCA_U32_SEL])  < sizeof(*sel))
1227*de1e4e89SAndroid Build Coastguard Worker 			return -1;
1228*de1e4e89SAndroid Build Coastguard Worker 
1229*de1e4e89SAndroid Build Coastguard Worker 		sel = RTA_DATA(tb[TCA_U32_SEL]);
1230*de1e4e89SAndroid Build Coastguard Worker 	}
1231*de1e4e89SAndroid Build Coastguard Worker 
1232*de1e4e89SAndroid Build Coastguard Worker 	if (tb[TCA_U32_DIVISOR]) {
1233*de1e4e89SAndroid Build Coastguard Worker 		fprintf(f, "ht divisor %d ",
1234*de1e4e89SAndroid Build Coastguard Worker 			rta_getattr_u32(tb[TCA_U32_DIVISOR]));
1235*de1e4e89SAndroid Build Coastguard Worker 	} else if (tb[TCA_U32_HASH]) {
1236*de1e4e89SAndroid Build Coastguard Worker 		__u32 htid = rta_getattr_u32(tb[TCA_U32_HASH]);
1237*de1e4e89SAndroid Build Coastguard Worker 
1238*de1e4e89SAndroid Build Coastguard Worker 		fprintf(f, "key ht %x bkt %x ", TC_U32_USERHTID(htid),
1239*de1e4e89SAndroid Build Coastguard Worker 			TC_U32_HASH(htid));
1240*de1e4e89SAndroid Build Coastguard Worker 	} else {
1241*de1e4e89SAndroid Build Coastguard Worker 		fprintf(f, "??? ");
1242*de1e4e89SAndroid Build Coastguard Worker 	}
1243*de1e4e89SAndroid Build Coastguard Worker 	if (tb[TCA_U32_CLASSID]) {
1244*de1e4e89SAndroid Build Coastguard Worker 		SPRINT_BUF(b1);
1245*de1e4e89SAndroid Build Coastguard Worker 		fprintf(f, "%sflowid %s ",
1246*de1e4e89SAndroid Build Coastguard Worker 			!sel || !(sel->flags & TC_U32_TERMINAL) ? "*" : "",
1247*de1e4e89SAndroid Build Coastguard Worker 			sprint_tc_classid(rta_getattr_u32(tb[TCA_U32_CLASSID]),
1248*de1e4e89SAndroid Build Coastguard Worker 					  b1));
1249*de1e4e89SAndroid Build Coastguard Worker 	} else if (sel && sel->flags & TC_U32_TERMINAL) {
1250*de1e4e89SAndroid Build Coastguard Worker 		fprintf(f, "terminal flowid ??? ");
1251*de1e4e89SAndroid Build Coastguard Worker 	}
1252*de1e4e89SAndroid Build Coastguard Worker 	if (tb[TCA_U32_LINK]) {
1253*de1e4e89SAndroid Build Coastguard Worker 		SPRINT_BUF(b1);
1254*de1e4e89SAndroid Build Coastguard Worker 		fprintf(f, "link %s ",
1255*de1e4e89SAndroid Build Coastguard Worker 			sprint_u32_handle(rta_getattr_u32(tb[TCA_U32_LINK]),
1256*de1e4e89SAndroid Build Coastguard Worker 					  b1));
1257*de1e4e89SAndroid Build Coastguard Worker 	}
1258*de1e4e89SAndroid Build Coastguard Worker 
1259*de1e4e89SAndroid Build Coastguard Worker 	if (tb[TCA_U32_FLAGS]) {
1260*de1e4e89SAndroid Build Coastguard Worker 		__u32 flags = rta_getattr_u32(tb[TCA_U32_FLAGS]);
1261*de1e4e89SAndroid Build Coastguard Worker 
1262*de1e4e89SAndroid Build Coastguard Worker 		if (flags & TCA_CLS_FLAGS_SKIP_HW)
1263*de1e4e89SAndroid Build Coastguard Worker 			fprintf(f, "skip_hw ");
1264*de1e4e89SAndroid Build Coastguard Worker 		if (flags & TCA_CLS_FLAGS_SKIP_SW)
1265*de1e4e89SAndroid Build Coastguard Worker 			fprintf(f, "skip_sw ");
1266*de1e4e89SAndroid Build Coastguard Worker 
1267*de1e4e89SAndroid Build Coastguard Worker 		if (flags & TCA_CLS_FLAGS_IN_HW)
1268*de1e4e89SAndroid Build Coastguard Worker 			fprintf(f, "in_hw ");
1269*de1e4e89SAndroid Build Coastguard Worker 		else if (flags & TCA_CLS_FLAGS_NOT_IN_HW)
1270*de1e4e89SAndroid Build Coastguard Worker 			fprintf(f, "not_in_hw ");
1271*de1e4e89SAndroid Build Coastguard Worker 	}
1272*de1e4e89SAndroid Build Coastguard Worker 
1273*de1e4e89SAndroid Build Coastguard Worker 	if (tb[TCA_U32_PCNT]) {
1274*de1e4e89SAndroid Build Coastguard Worker 		if (RTA_PAYLOAD(tb[TCA_U32_PCNT])  < sizeof(*pf)) {
1275*de1e4e89SAndroid Build Coastguard Worker 			fprintf(f, "Broken perf counters\n");
1276*de1e4e89SAndroid Build Coastguard Worker 			return -1;
1277*de1e4e89SAndroid Build Coastguard Worker 		}
1278*de1e4e89SAndroid Build Coastguard Worker 		pf = RTA_DATA(tb[TCA_U32_PCNT]);
1279*de1e4e89SAndroid Build Coastguard Worker 	}
1280*de1e4e89SAndroid Build Coastguard Worker 
1281*de1e4e89SAndroid Build Coastguard Worker 	if (sel && show_stats && NULL != pf)
1282*de1e4e89SAndroid Build Coastguard Worker 		fprintf(f, " (rule hit %llu success %llu)",
1283*de1e4e89SAndroid Build Coastguard Worker 			(unsigned long long) pf->rcnt,
1284*de1e4e89SAndroid Build Coastguard Worker 			(unsigned long long) pf->rhit);
1285*de1e4e89SAndroid Build Coastguard Worker 
1286*de1e4e89SAndroid Build Coastguard Worker 	if (tb[TCA_U32_MARK]) {
1287*de1e4e89SAndroid Build Coastguard Worker 		struct tc_u32_mark *mark = RTA_DATA(tb[TCA_U32_MARK]);
1288*de1e4e89SAndroid Build Coastguard Worker 
1289*de1e4e89SAndroid Build Coastguard Worker 		if (RTA_PAYLOAD(tb[TCA_U32_MARK]) < sizeof(*mark)) {
1290*de1e4e89SAndroid Build Coastguard Worker 			fprintf(f, "\n  Invalid mark (kernel&iproute2 mismatch)\n");
1291*de1e4e89SAndroid Build Coastguard Worker 		} else {
1292*de1e4e89SAndroid Build Coastguard Worker 			fprintf(f, "\n  mark 0x%04x 0x%04x (success %d)",
1293*de1e4e89SAndroid Build Coastguard Worker 				mark->val, mark->mask, mark->success);
1294*de1e4e89SAndroid Build Coastguard Worker 		}
1295*de1e4e89SAndroid Build Coastguard Worker 	}
1296*de1e4e89SAndroid Build Coastguard Worker 
1297*de1e4e89SAndroid Build Coastguard Worker 	if (sel) {
1298*de1e4e89SAndroid Build Coastguard Worker 		if (sel->nkeys) {
1299*de1e4e89SAndroid Build Coastguard Worker 			int i;
1300*de1e4e89SAndroid Build Coastguard Worker 
1301*de1e4e89SAndroid Build Coastguard Worker 			for (i = 0; i < sel->nkeys; i++) {
1302*de1e4e89SAndroid Build Coastguard Worker 				show_keys(f, sel->keys + i);
1303*de1e4e89SAndroid Build Coastguard Worker 				if (show_stats && NULL != pf)
1304*de1e4e89SAndroid Build Coastguard Worker 					fprintf(f, " (success %llu ) ",
1305*de1e4e89SAndroid Build Coastguard Worker 						(unsigned long long) pf->kcnts[i]);
1306*de1e4e89SAndroid Build Coastguard Worker 			}
1307*de1e4e89SAndroid Build Coastguard Worker 		}
1308*de1e4e89SAndroid Build Coastguard Worker 
1309*de1e4e89SAndroid Build Coastguard Worker 		if (sel->flags & (TC_U32_VAROFFSET | TC_U32_OFFSET)) {
1310*de1e4e89SAndroid Build Coastguard Worker 			fprintf(f, "\n    offset ");
1311*de1e4e89SAndroid Build Coastguard Worker 			if (sel->flags & TC_U32_VAROFFSET)
1312*de1e4e89SAndroid Build Coastguard Worker 				fprintf(f, "%04x>>%d at %d ",
1313*de1e4e89SAndroid Build Coastguard Worker 					ntohs(sel->offmask),
1314*de1e4e89SAndroid Build Coastguard Worker 					sel->offshift,  sel->offoff);
1315*de1e4e89SAndroid Build Coastguard Worker 			if (sel->off)
1316*de1e4e89SAndroid Build Coastguard Worker 				fprintf(f, "plus %d ", sel->off);
1317*de1e4e89SAndroid Build Coastguard Worker 		}
1318*de1e4e89SAndroid Build Coastguard Worker 		if (sel->flags & TC_U32_EAT)
1319*de1e4e89SAndroid Build Coastguard Worker 			fprintf(f, " eat ");
1320*de1e4e89SAndroid Build Coastguard Worker 
1321*de1e4e89SAndroid Build Coastguard Worker 		if (sel->hmask) {
1322*de1e4e89SAndroid Build Coastguard Worker 			fprintf(f, "\n    hash mask %08x at %d ",
1323*de1e4e89SAndroid Build Coastguard Worker 				(unsigned int)htonl(sel->hmask), sel->hoff);
1324*de1e4e89SAndroid Build Coastguard Worker 		}
1325*de1e4e89SAndroid Build Coastguard Worker 	}
1326*de1e4e89SAndroid Build Coastguard Worker 
1327*de1e4e89SAndroid Build Coastguard Worker 	if (tb[TCA_U32_POLICE]) {
1328*de1e4e89SAndroid Build Coastguard Worker 		fprintf(f, "\n");
1329*de1e4e89SAndroid Build Coastguard Worker 		tc_print_police(f, tb[TCA_U32_POLICE]);
1330*de1e4e89SAndroid Build Coastguard Worker 	}
1331*de1e4e89SAndroid Build Coastguard Worker 
1332*de1e4e89SAndroid Build Coastguard Worker 	if (tb[TCA_U32_INDEV]) {
1333*de1e4e89SAndroid Build Coastguard Worker 		struct rtattr *idev = tb[TCA_U32_INDEV];
1334*de1e4e89SAndroid Build Coastguard Worker 
1335*de1e4e89SAndroid Build Coastguard Worker 		fprintf(f, "\n  input dev %s\n", rta_getattr_str(idev));
1336*de1e4e89SAndroid Build Coastguard Worker 	}
1337*de1e4e89SAndroid Build Coastguard Worker 
1338*de1e4e89SAndroid Build Coastguard Worker 	if (tb[TCA_U32_ACT])
1339*de1e4e89SAndroid Build Coastguard Worker 		tc_print_action(f, tb[TCA_U32_ACT], 0);
1340*de1e4e89SAndroid Build Coastguard Worker 
1341*de1e4e89SAndroid Build Coastguard Worker 	return 0;
1342*de1e4e89SAndroid Build Coastguard Worker }
1343*de1e4e89SAndroid Build Coastguard Worker 
1344*de1e4e89SAndroid Build Coastguard Worker struct filter_util u32_filter_util = {
1345*de1e4e89SAndroid Build Coastguard Worker 	.id = "u32",
1346*de1e4e89SAndroid Build Coastguard Worker 	.parse_fopt = u32_parse_opt,
1347*de1e4e89SAndroid Build Coastguard Worker 	.print_fopt = u32_print_opt,
1348*de1e4e89SAndroid Build Coastguard Worker };
1349