xref: /aosp_15_r20/external/iproute2/tc/em_u32.c (revision de1e4e894b0c224df933550f0afdecc354b238c4)
1*de1e4e89SAndroid Build Coastguard Worker /*
2*de1e4e89SAndroid Build Coastguard Worker  * em_u32.c		U32 Ematch
3*de1e4e89SAndroid Build Coastguard Worker  *
4*de1e4e89SAndroid Build Coastguard Worker  *		This program is free software; you can distribute 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:	Thomas Graf <[email protected]>
10*de1e4e89SAndroid Build Coastguard Worker  */
11*de1e4e89SAndroid Build Coastguard Worker 
12*de1e4e89SAndroid Build Coastguard Worker #include <stdio.h>
13*de1e4e89SAndroid Build Coastguard Worker #include <stdlib.h>
14*de1e4e89SAndroid Build Coastguard Worker #include <unistd.h>
15*de1e4e89SAndroid Build Coastguard Worker #include <syslog.h>
16*de1e4e89SAndroid Build Coastguard Worker #include <fcntl.h>
17*de1e4e89SAndroid Build Coastguard Worker #include <sys/socket.h>
18*de1e4e89SAndroid Build Coastguard Worker #include <netinet/in.h>
19*de1e4e89SAndroid Build Coastguard Worker #include <arpa/inet.h>
20*de1e4e89SAndroid Build Coastguard Worker #include <string.h>
21*de1e4e89SAndroid Build Coastguard Worker #include <errno.h>
22*de1e4e89SAndroid Build Coastguard Worker 
23*de1e4e89SAndroid Build Coastguard Worker #include "m_ematch.h"
24*de1e4e89SAndroid Build Coastguard Worker 
25*de1e4e89SAndroid Build Coastguard Worker extern struct ematch_util u32_ematch_util;
26*de1e4e89SAndroid Build Coastguard Worker 
u32_print_usage(FILE * fd)27*de1e4e89SAndroid Build Coastguard Worker static void u32_print_usage(FILE *fd)
28*de1e4e89SAndroid Build Coastguard Worker {
29*de1e4e89SAndroid Build Coastguard Worker 	fprintf(fd,
30*de1e4e89SAndroid Build Coastguard Worker 	    "Usage: u32(ALIGN VALUE MASK at [ nexthdr+ ] OFFSET)\n" \
31*de1e4e89SAndroid Build Coastguard Worker 	    "where: ALIGN  := { u8 | u16 | u32 }\n" \
32*de1e4e89SAndroid Build Coastguard Worker 	    "\n" \
33*de1e4e89SAndroid Build Coastguard Worker 	    "Example: u32(u16 0x1122 0xffff at nexthdr+4)\n");
34*de1e4e89SAndroid Build Coastguard Worker }
35*de1e4e89SAndroid Build Coastguard Worker 
u32_parse_eopt(struct nlmsghdr * n,struct tcf_ematch_hdr * hdr,struct bstr * args)36*de1e4e89SAndroid Build Coastguard Worker static int u32_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr,
37*de1e4e89SAndroid Build Coastguard Worker 			  struct bstr *args)
38*de1e4e89SAndroid Build Coastguard Worker {
39*de1e4e89SAndroid Build Coastguard Worker 	struct bstr *a;
40*de1e4e89SAndroid Build Coastguard Worker 	int align, nh_len;
41*de1e4e89SAndroid Build Coastguard Worker 	unsigned long key, mask, offmask = 0, offset;
42*de1e4e89SAndroid Build Coastguard Worker 	struct tc_u32_key u_key = {};
43*de1e4e89SAndroid Build Coastguard Worker 
44*de1e4e89SAndroid Build Coastguard Worker #define PARSE_ERR(CARG, FMT, ARGS...) \
45*de1e4e89SAndroid Build Coastguard Worker 	em_parse_error(EINVAL, args, CARG, &u32_ematch_util, FMT, ##ARGS)
46*de1e4e89SAndroid Build Coastguard Worker 
47*de1e4e89SAndroid Build Coastguard Worker 	if (args == NULL)
48*de1e4e89SAndroid Build Coastguard Worker 		return PARSE_ERR(args, "u32: missing arguments");
49*de1e4e89SAndroid Build Coastguard Worker 
50*de1e4e89SAndroid Build Coastguard Worker 	if (!bstrcmp(args, "u8"))
51*de1e4e89SAndroid Build Coastguard Worker 		align = 1;
52*de1e4e89SAndroid Build Coastguard Worker 	else if (!bstrcmp(args, "u16"))
53*de1e4e89SAndroid Build Coastguard Worker 		align = 2;
54*de1e4e89SAndroid Build Coastguard Worker 	else if (!bstrcmp(args, "u32"))
55*de1e4e89SAndroid Build Coastguard Worker 		align = 4;
56*de1e4e89SAndroid Build Coastguard Worker 	else
57*de1e4e89SAndroid Build Coastguard Worker 		return PARSE_ERR(args, "u32: invalid alignment");
58*de1e4e89SAndroid Build Coastguard Worker 
59*de1e4e89SAndroid Build Coastguard Worker 	a = bstr_next(args);
60*de1e4e89SAndroid Build Coastguard Worker 	if (a == NULL)
61*de1e4e89SAndroid Build Coastguard Worker 		return PARSE_ERR(a, "u32: missing key");
62*de1e4e89SAndroid Build Coastguard Worker 
63*de1e4e89SAndroid Build Coastguard Worker 	key = bstrtoul(a);
64*de1e4e89SAndroid Build Coastguard Worker 	if (key == ULONG_MAX)
65*de1e4e89SAndroid Build Coastguard Worker 		return PARSE_ERR(a, "u32: invalid key, must be numeric");
66*de1e4e89SAndroid Build Coastguard Worker 
67*de1e4e89SAndroid Build Coastguard Worker 	a = bstr_next(a);
68*de1e4e89SAndroid Build Coastguard Worker 	if (a == NULL)
69*de1e4e89SAndroid Build Coastguard Worker 		return PARSE_ERR(a, "u32: missing mask");
70*de1e4e89SAndroid Build Coastguard Worker 
71*de1e4e89SAndroid Build Coastguard Worker 	mask = bstrtoul(a);
72*de1e4e89SAndroid Build Coastguard Worker 	if (mask == ULONG_MAX)
73*de1e4e89SAndroid Build Coastguard Worker 		return PARSE_ERR(a, "u32: invalid mask, must be numeric");
74*de1e4e89SAndroid Build Coastguard Worker 
75*de1e4e89SAndroid Build Coastguard Worker 	a = bstr_next(a);
76*de1e4e89SAndroid Build Coastguard Worker 	if (a == NULL || bstrcmp(a, "at") != 0)
77*de1e4e89SAndroid Build Coastguard Worker 		return PARSE_ERR(a, "u32: missing \"at\"");
78*de1e4e89SAndroid Build Coastguard Worker 
79*de1e4e89SAndroid Build Coastguard Worker 	a = bstr_next(a);
80*de1e4e89SAndroid Build Coastguard Worker 	if (a == NULL)
81*de1e4e89SAndroid Build Coastguard Worker 		return PARSE_ERR(a, "u32: missing offset");
82*de1e4e89SAndroid Build Coastguard Worker 
83*de1e4e89SAndroid Build Coastguard Worker 	nh_len = strlen("nexthdr+");
84*de1e4e89SAndroid Build Coastguard Worker 	if (a->len > nh_len && !memcmp(a->data, "nexthdr+", nh_len)) {
85*de1e4e89SAndroid Build Coastguard Worker 		char buf[a->len - nh_len + 1];
86*de1e4e89SAndroid Build Coastguard Worker 
87*de1e4e89SAndroid Build Coastguard Worker 		offmask = -1;
88*de1e4e89SAndroid Build Coastguard Worker 		memcpy(buf, a->data + nh_len, a->len - nh_len);
89*de1e4e89SAndroid Build Coastguard Worker 		offset = strtoul(buf, NULL, 0);
90*de1e4e89SAndroid Build Coastguard Worker 	} else if (!bstrcmp(a, "nexthdr+")) {
91*de1e4e89SAndroid Build Coastguard Worker 		a = bstr_next(a);
92*de1e4e89SAndroid Build Coastguard Worker 		if (a == NULL)
93*de1e4e89SAndroid Build Coastguard Worker 			return PARSE_ERR(a, "u32: missing offset");
94*de1e4e89SAndroid Build Coastguard Worker 		offset = bstrtoul(a);
95*de1e4e89SAndroid Build Coastguard Worker 	} else
96*de1e4e89SAndroid Build Coastguard Worker 		offset = bstrtoul(a);
97*de1e4e89SAndroid Build Coastguard Worker 
98*de1e4e89SAndroid Build Coastguard Worker 	if (offset == ULONG_MAX)
99*de1e4e89SAndroid Build Coastguard Worker 		return PARSE_ERR(a, "u32: invalid offset");
100*de1e4e89SAndroid Build Coastguard Worker 
101*de1e4e89SAndroid Build Coastguard Worker 	if (a->next)
102*de1e4e89SAndroid Build Coastguard Worker 		return PARSE_ERR(a->next, "u32: unexpected trailer");
103*de1e4e89SAndroid Build Coastguard Worker 
104*de1e4e89SAndroid Build Coastguard Worker 	switch (align) {
105*de1e4e89SAndroid Build Coastguard Worker 		case 1:
106*de1e4e89SAndroid Build Coastguard Worker 			if (key > 0xFF)
107*de1e4e89SAndroid Build Coastguard Worker 				return PARSE_ERR(a, "Illegal key (>0xFF)");
108*de1e4e89SAndroid Build Coastguard Worker 			if (mask > 0xFF)
109*de1e4e89SAndroid Build Coastguard Worker 				return PARSE_ERR(a, "Illegal mask (>0xFF)");
110*de1e4e89SAndroid Build Coastguard Worker 
111*de1e4e89SAndroid Build Coastguard Worker 			key <<= 24 - ((offset & 3) * 8);
112*de1e4e89SAndroid Build Coastguard Worker 			mask <<= 24 - ((offset & 3) * 8);
113*de1e4e89SAndroid Build Coastguard Worker 			offset &= ~3;
114*de1e4e89SAndroid Build Coastguard Worker 			break;
115*de1e4e89SAndroid Build Coastguard Worker 
116*de1e4e89SAndroid Build Coastguard Worker 		case 2:
117*de1e4e89SAndroid Build Coastguard Worker 			if (key > 0xFFFF)
118*de1e4e89SAndroid Build Coastguard Worker 				return PARSE_ERR(a, "Illegal key (>0xFFFF)");
119*de1e4e89SAndroid Build Coastguard Worker 			if (mask > 0xFFFF)
120*de1e4e89SAndroid Build Coastguard Worker 				return PARSE_ERR(a, "Illegal mask (>0xFFFF)");
121*de1e4e89SAndroid Build Coastguard Worker 
122*de1e4e89SAndroid Build Coastguard Worker 			if ((offset & 3) == 0) {
123*de1e4e89SAndroid Build Coastguard Worker 				key <<= 16;
124*de1e4e89SAndroid Build Coastguard Worker 				mask <<= 16;
125*de1e4e89SAndroid Build Coastguard Worker 			}
126*de1e4e89SAndroid Build Coastguard Worker 			offset &= ~3;
127*de1e4e89SAndroid Build Coastguard Worker 			break;
128*de1e4e89SAndroid Build Coastguard Worker 	}
129*de1e4e89SAndroid Build Coastguard Worker 
130*de1e4e89SAndroid Build Coastguard Worker 	key = htonl(key);
131*de1e4e89SAndroid Build Coastguard Worker 	mask = htonl(mask);
132*de1e4e89SAndroid Build Coastguard Worker 
133*de1e4e89SAndroid Build Coastguard Worker 	if (offset % 4)
134*de1e4e89SAndroid Build Coastguard Worker 		return PARSE_ERR(a, "u32: invalid offset alignment, " \
135*de1e4e89SAndroid Build Coastguard Worker 		    "must be aligned to 4.");
136*de1e4e89SAndroid Build Coastguard Worker 
137*de1e4e89SAndroid Build Coastguard Worker 	key &= mask;
138*de1e4e89SAndroid Build Coastguard Worker 
139*de1e4e89SAndroid Build Coastguard Worker 	u_key.mask = mask;
140*de1e4e89SAndroid Build Coastguard Worker 	u_key.val = key;
141*de1e4e89SAndroid Build Coastguard Worker 	u_key.off = offset;
142*de1e4e89SAndroid Build Coastguard Worker 	u_key.offmask = offmask;
143*de1e4e89SAndroid Build Coastguard Worker 
144*de1e4e89SAndroid Build Coastguard Worker 	addraw_l(n, MAX_MSG, hdr, sizeof(*hdr));
145*de1e4e89SAndroid Build Coastguard Worker 	addraw_l(n, MAX_MSG, &u_key, sizeof(u_key));
146*de1e4e89SAndroid Build Coastguard Worker 
147*de1e4e89SAndroid Build Coastguard Worker #undef PARSE_ERR
148*de1e4e89SAndroid Build Coastguard Worker 	return 0;
149*de1e4e89SAndroid Build Coastguard Worker }
150*de1e4e89SAndroid Build Coastguard Worker 
u32_print_eopt(FILE * fd,struct tcf_ematch_hdr * hdr,void * data,int data_len)151*de1e4e89SAndroid Build Coastguard Worker static int u32_print_eopt(FILE *fd, struct tcf_ematch_hdr *hdr, void *data,
152*de1e4e89SAndroid Build Coastguard Worker 			  int data_len)
153*de1e4e89SAndroid Build Coastguard Worker {
154*de1e4e89SAndroid Build Coastguard Worker 	struct tc_u32_key *u_key = data;
155*de1e4e89SAndroid Build Coastguard Worker 
156*de1e4e89SAndroid Build Coastguard Worker 	if (data_len < sizeof(*u_key)) {
157*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "U32 header size mismatch\n");
158*de1e4e89SAndroid Build Coastguard Worker 		return -1;
159*de1e4e89SAndroid Build Coastguard Worker 	}
160*de1e4e89SAndroid Build Coastguard Worker 
161*de1e4e89SAndroid Build Coastguard Worker 	fprintf(fd, "%08x/%08x at %s%d",
162*de1e4e89SAndroid Build Coastguard Worker 	    (unsigned int) ntohl(u_key->val),
163*de1e4e89SAndroid Build Coastguard Worker 	    (unsigned int) ntohl(u_key->mask),
164*de1e4e89SAndroid Build Coastguard Worker 	    u_key->offmask ? "nexthdr+" : "",
165*de1e4e89SAndroid Build Coastguard Worker 	    u_key->off);
166*de1e4e89SAndroid Build Coastguard Worker 
167*de1e4e89SAndroid Build Coastguard Worker 	return 0;
168*de1e4e89SAndroid Build Coastguard Worker }
169*de1e4e89SAndroid Build Coastguard Worker 
170*de1e4e89SAndroid Build Coastguard Worker struct ematch_util u32_ematch_util = {
171*de1e4e89SAndroid Build Coastguard Worker 	.kind = "u32",
172*de1e4e89SAndroid Build Coastguard Worker 	.kind_num = TCF_EM_U32,
173*de1e4e89SAndroid Build Coastguard Worker 	.parse_eopt = u32_parse_eopt,
174*de1e4e89SAndroid Build Coastguard Worker 	.print_eopt = u32_print_eopt,
175*de1e4e89SAndroid Build Coastguard Worker 	.print_usage = u32_print_usage
176*de1e4e89SAndroid Build Coastguard Worker };
177