xref: /aosp_15_r20/external/iproute2/tc/m_pedit.c (revision de1e4e894b0c224df933550f0afdecc354b238c4)
1*de1e4e89SAndroid Build Coastguard Worker /*
2*de1e4e89SAndroid Build Coastguard Worker  * m_pedit.c		generic packet editor actions module
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:  J Hadi Salim ([email protected])
10*de1e4e89SAndroid Build Coastguard Worker  *
11*de1e4e89SAndroid Build Coastguard Worker  * TODO:
12*de1e4e89SAndroid Build Coastguard Worker  *	1) Big endian broken in some spots
13*de1e4e89SAndroid Build Coastguard Worker  *	2) A lot of this stuff was added on the fly; get a big double-double
14*de1e4e89SAndroid Build Coastguard Worker  *	and clean it up at some point.
15*de1e4e89SAndroid Build Coastguard Worker  *
16*de1e4e89SAndroid Build Coastguard Worker  */
17*de1e4e89SAndroid Build Coastguard Worker 
18*de1e4e89SAndroid Build Coastguard Worker #include <stdio.h>
19*de1e4e89SAndroid Build Coastguard Worker #include <stdlib.h>
20*de1e4e89SAndroid Build Coastguard Worker #include <unistd.h>
21*de1e4e89SAndroid Build Coastguard Worker #include <syslog.h>
22*de1e4e89SAndroid Build Coastguard Worker #include <fcntl.h>
23*de1e4e89SAndroid Build Coastguard Worker #include <sys/socket.h>
24*de1e4e89SAndroid Build Coastguard Worker #include <netinet/in.h>
25*de1e4e89SAndroid Build Coastguard Worker #include <arpa/inet.h>
26*de1e4e89SAndroid Build Coastguard Worker #include <string.h>
27*de1e4e89SAndroid Build Coastguard Worker #include <dlfcn.h>
28*de1e4e89SAndroid Build Coastguard Worker #include "utils.h"
29*de1e4e89SAndroid Build Coastguard Worker #include "tc_util.h"
30*de1e4e89SAndroid Build Coastguard Worker #include "m_pedit.h"
31*de1e4e89SAndroid Build Coastguard Worker #include "rt_names.h"
32*de1e4e89SAndroid Build Coastguard Worker 
33*de1e4e89SAndroid Build Coastguard Worker static struct m_pedit_util *pedit_list;
34*de1e4e89SAndroid Build Coastguard Worker static int pedit_debug;
35*de1e4e89SAndroid Build Coastguard Worker 
explain(void)36*de1e4e89SAndroid Build Coastguard Worker static void explain(void)
37*de1e4e89SAndroid Build Coastguard Worker {
38*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stderr, "Usage: ... pedit munge [ex] <MUNGE> [CONTROL]\n");
39*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stderr,
40*de1e4e89SAndroid Build Coastguard Worker 		"Where: MUNGE := <RAW>|<LAYERED>\n"
41*de1e4e89SAndroid Build Coastguard Worker 		"\t<RAW>:= <OFFSETC>[ATC]<CMD>\n \t\tOFFSETC:= offset <offval> <u8|u16|u32>\n"
42*de1e4e89SAndroid Build Coastguard Worker 		"\t\tATC:= at <atval> offmask <maskval> shift <shiftval>\n"
43*de1e4e89SAndroid Build Coastguard Worker 		"\t\tNOTE: offval is byte offset, must be multiple of 4\n"
44*de1e4e89SAndroid Build Coastguard Worker 		"\t\tNOTE: maskval is a 32 bit hex number\n \t\tNOTE: shiftval is a shift value\n"
45*de1e4e89SAndroid Build Coastguard Worker 		"\t\tCMD:= clear | invert | set <setval>| add <addval> | retain\n"
46*de1e4e89SAndroid Build Coastguard Worker 		"\t<LAYERED>:= ip <ipdata> | ip6 <ip6data>\n"
47*de1e4e89SAndroid Build Coastguard Worker 		" \t\t| udp <udpdata> | tcp <tcpdata> | icmp <icmpdata>\n"
48*de1e4e89SAndroid Build Coastguard Worker 		"\tCONTROL:= reclassify | pipe | drop | continue | pass |\n"
49*de1e4e89SAndroid Build Coastguard Worker 		"\t          goto chain <CHAIN_INDEX>\n"
50*de1e4e89SAndroid Build Coastguard Worker 		"\tNOTE: if 'ex' is set, extended functionality will be supported (kernel >= 4.11)\n"
51*de1e4e89SAndroid Build Coastguard Worker 		"For Example usage look at the examples directory\n");
52*de1e4e89SAndroid Build Coastguard Worker 
53*de1e4e89SAndroid Build Coastguard Worker }
54*de1e4e89SAndroid Build Coastguard Worker 
usage(void)55*de1e4e89SAndroid Build Coastguard Worker static void usage(void)
56*de1e4e89SAndroid Build Coastguard Worker {
57*de1e4e89SAndroid Build Coastguard Worker 	explain();
58*de1e4e89SAndroid Build Coastguard Worker 	exit(-1);
59*de1e4e89SAndroid Build Coastguard Worker }
60*de1e4e89SAndroid Build Coastguard Worker 
pedit_parse_nopopt(int * argc_p,char *** argv_p,struct m_pedit_sel * sel,struct m_pedit_key * tkey)61*de1e4e89SAndroid Build Coastguard Worker static int pedit_parse_nopopt(int *argc_p, char ***argv_p,
62*de1e4e89SAndroid Build Coastguard Worker 			      struct m_pedit_sel *sel,
63*de1e4e89SAndroid Build Coastguard Worker 			      struct m_pedit_key *tkey)
64*de1e4e89SAndroid Build Coastguard Worker {
65*de1e4e89SAndroid Build Coastguard Worker 	int argc = *argc_p;
66*de1e4e89SAndroid Build Coastguard Worker 	char **argv = *argv_p;
67*de1e4e89SAndroid Build Coastguard Worker 
68*de1e4e89SAndroid Build Coastguard Worker 	if (argc) {
69*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr,
70*de1e4e89SAndroid Build Coastguard Worker 			"Unknown action  hence option \"%s\" is unparsable\n",
71*de1e4e89SAndroid Build Coastguard Worker 			*argv);
72*de1e4e89SAndroid Build Coastguard Worker 		return -1;
73*de1e4e89SAndroid Build Coastguard Worker 	}
74*de1e4e89SAndroid Build Coastguard Worker 
75*de1e4e89SAndroid Build Coastguard Worker 	return 0;
76*de1e4e89SAndroid Build Coastguard Worker 
77*de1e4e89SAndroid Build Coastguard Worker }
78*de1e4e89SAndroid Build Coastguard Worker 
get_pedit_kind(const char * str)79*de1e4e89SAndroid Build Coastguard Worker static struct m_pedit_util *get_pedit_kind(const char *str)
80*de1e4e89SAndroid Build Coastguard Worker {
81*de1e4e89SAndroid Build Coastguard Worker 	static void *pBODY;
82*de1e4e89SAndroid Build Coastguard Worker 	void *dlh;
83*de1e4e89SAndroid Build Coastguard Worker 	char buf[256];
84*de1e4e89SAndroid Build Coastguard Worker 	struct m_pedit_util *p;
85*de1e4e89SAndroid Build Coastguard Worker 
86*de1e4e89SAndroid Build Coastguard Worker 	for (p = pedit_list; p; p = p->next) {
87*de1e4e89SAndroid Build Coastguard Worker 		if (strcmp(p->id, str) == 0)
88*de1e4e89SAndroid Build Coastguard Worker 			return p;
89*de1e4e89SAndroid Build Coastguard Worker 	}
90*de1e4e89SAndroid Build Coastguard Worker 
91*de1e4e89SAndroid Build Coastguard Worker 	snprintf(buf, sizeof(buf), "p_%s.so", str);
92*de1e4e89SAndroid Build Coastguard Worker 	dlh = dlopen(buf, RTLD_LAZY);
93*de1e4e89SAndroid Build Coastguard Worker 	if (dlh == NULL) {
94*de1e4e89SAndroid Build Coastguard Worker 		dlh = pBODY;
95*de1e4e89SAndroid Build Coastguard Worker 		if (dlh == NULL) {
96*de1e4e89SAndroid Build Coastguard Worker 			dlh = pBODY = dlopen(NULL, RTLD_LAZY);
97*de1e4e89SAndroid Build Coastguard Worker 			if (dlh == NULL)
98*de1e4e89SAndroid Build Coastguard Worker 				goto noexist;
99*de1e4e89SAndroid Build Coastguard Worker 		}
100*de1e4e89SAndroid Build Coastguard Worker 	}
101*de1e4e89SAndroid Build Coastguard Worker 
102*de1e4e89SAndroid Build Coastguard Worker 	snprintf(buf, sizeof(buf), "p_pedit_%s", str);
103*de1e4e89SAndroid Build Coastguard Worker 	p = dlsym(dlh, buf);
104*de1e4e89SAndroid Build Coastguard Worker 	if (p == NULL)
105*de1e4e89SAndroid Build Coastguard Worker 		goto noexist;
106*de1e4e89SAndroid Build Coastguard Worker 
107*de1e4e89SAndroid Build Coastguard Worker reg:
108*de1e4e89SAndroid Build Coastguard Worker 	p->next = pedit_list;
109*de1e4e89SAndroid Build Coastguard Worker 	pedit_list = p;
110*de1e4e89SAndroid Build Coastguard Worker 	return p;
111*de1e4e89SAndroid Build Coastguard Worker 
112*de1e4e89SAndroid Build Coastguard Worker noexist:
113*de1e4e89SAndroid Build Coastguard Worker 	p = calloc(1, sizeof(*p));
114*de1e4e89SAndroid Build Coastguard Worker 	if (p) {
115*de1e4e89SAndroid Build Coastguard Worker 		strncpy(p->id, str, sizeof(p->id) - 1);
116*de1e4e89SAndroid Build Coastguard Worker 		p->parse_peopt = pedit_parse_nopopt;
117*de1e4e89SAndroid Build Coastguard Worker 		goto reg;
118*de1e4e89SAndroid Build Coastguard Worker 	}
119*de1e4e89SAndroid Build Coastguard Worker 	return p;
120*de1e4e89SAndroid Build Coastguard Worker }
121*de1e4e89SAndroid Build Coastguard Worker 
pack_key(struct m_pedit_sel * _sel,struct m_pedit_key * tkey)122*de1e4e89SAndroid Build Coastguard Worker int pack_key(struct m_pedit_sel *_sel, struct m_pedit_key *tkey)
123*de1e4e89SAndroid Build Coastguard Worker {
124*de1e4e89SAndroid Build Coastguard Worker 	struct tc_pedit_sel *sel = &_sel->sel;
125*de1e4e89SAndroid Build Coastguard Worker 	struct m_pedit_key_ex *keys_ex = _sel->keys_ex;
126*de1e4e89SAndroid Build Coastguard Worker 	int hwm = sel->nkeys;
127*de1e4e89SAndroid Build Coastguard Worker 
128*de1e4e89SAndroid Build Coastguard Worker 	if (hwm >= MAX_OFFS)
129*de1e4e89SAndroid Build Coastguard Worker 		return -1;
130*de1e4e89SAndroid Build Coastguard Worker 
131*de1e4e89SAndroid Build Coastguard Worker 	if (tkey->off % 4) {
132*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "offsets MUST be in 32 bit boundaries\n");
133*de1e4e89SAndroid Build Coastguard Worker 		return -1;
134*de1e4e89SAndroid Build Coastguard Worker 	}
135*de1e4e89SAndroid Build Coastguard Worker 
136*de1e4e89SAndroid Build Coastguard Worker 	sel->keys[hwm].val = tkey->val;
137*de1e4e89SAndroid Build Coastguard Worker 	sel->keys[hwm].mask = tkey->mask;
138*de1e4e89SAndroid Build Coastguard Worker 	sel->keys[hwm].off = tkey->off;
139*de1e4e89SAndroid Build Coastguard Worker 	sel->keys[hwm].at = tkey->at;
140*de1e4e89SAndroid Build Coastguard Worker 	sel->keys[hwm].offmask = tkey->offmask;
141*de1e4e89SAndroid Build Coastguard Worker 	sel->keys[hwm].shift = tkey->shift;
142*de1e4e89SAndroid Build Coastguard Worker 
143*de1e4e89SAndroid Build Coastguard Worker 	if (_sel->extended) {
144*de1e4e89SAndroid Build Coastguard Worker 		keys_ex[hwm].htype = tkey->htype;
145*de1e4e89SAndroid Build Coastguard Worker 		keys_ex[hwm].cmd = tkey->cmd;
146*de1e4e89SAndroid Build Coastguard Worker 	} else {
147*de1e4e89SAndroid Build Coastguard Worker 		if (tkey->htype != TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK ||
148*de1e4e89SAndroid Build Coastguard Worker 		    tkey->cmd != TCA_PEDIT_KEY_EX_CMD_SET) {
149*de1e4e89SAndroid Build Coastguard Worker 			fprintf(stderr,
150*de1e4e89SAndroid Build Coastguard Worker 				"Munge parameters not supported. Use 'pedit ex munge ...'.\n");
151*de1e4e89SAndroid Build Coastguard Worker 			return -1;
152*de1e4e89SAndroid Build Coastguard Worker 		}
153*de1e4e89SAndroid Build Coastguard Worker 	}
154*de1e4e89SAndroid Build Coastguard Worker 
155*de1e4e89SAndroid Build Coastguard Worker 	sel->nkeys++;
156*de1e4e89SAndroid Build Coastguard Worker 	return 0;
157*de1e4e89SAndroid Build Coastguard Worker }
158*de1e4e89SAndroid Build Coastguard Worker 
pack_key32(__u32 retain,struct m_pedit_sel * sel,struct m_pedit_key * tkey)159*de1e4e89SAndroid Build Coastguard Worker int pack_key32(__u32 retain, struct m_pedit_sel *sel,
160*de1e4e89SAndroid Build Coastguard Worker 	       struct m_pedit_key *tkey)
161*de1e4e89SAndroid Build Coastguard Worker {
162*de1e4e89SAndroid Build Coastguard Worker 	if (tkey->off > (tkey->off & ~3)) {
163*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr,
164*de1e4e89SAndroid Build Coastguard Worker 			"pack_key32: 32 bit offsets must begin in 32bit boundaries\n");
165*de1e4e89SAndroid Build Coastguard Worker 		return -1;
166*de1e4e89SAndroid Build Coastguard Worker 	}
167*de1e4e89SAndroid Build Coastguard Worker 
168*de1e4e89SAndroid Build Coastguard Worker 	tkey->val = htonl(tkey->val & retain);
169*de1e4e89SAndroid Build Coastguard Worker 	tkey->mask = htonl(tkey->mask | ~retain);
170*de1e4e89SAndroid Build Coastguard Worker 	return pack_key(sel, tkey);
171*de1e4e89SAndroid Build Coastguard Worker }
172*de1e4e89SAndroid Build Coastguard Worker 
pack_key16(__u32 retain,struct m_pedit_sel * sel,struct m_pedit_key * tkey)173*de1e4e89SAndroid Build Coastguard Worker int pack_key16(__u32 retain, struct m_pedit_sel *sel,
174*de1e4e89SAndroid Build Coastguard Worker 	       struct m_pedit_key *tkey)
175*de1e4e89SAndroid Build Coastguard Worker {
176*de1e4e89SAndroid Build Coastguard Worker 	int ind, stride;
177*de1e4e89SAndroid Build Coastguard Worker 	__u32 m[4] = { 0x0000FFFF, 0xFF0000FF, 0xFFFF0000 };
178*de1e4e89SAndroid Build Coastguard Worker 
179*de1e4e89SAndroid Build Coastguard Worker 	if (tkey->val > 0xFFFF || tkey->mask > 0xFFFF) {
180*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "pack_key16 bad value\n");
181*de1e4e89SAndroid Build Coastguard Worker 		return -1;
182*de1e4e89SAndroid Build Coastguard Worker 	}
183*de1e4e89SAndroid Build Coastguard Worker 
184*de1e4e89SAndroid Build Coastguard Worker 	ind = tkey->off & 3;
185*de1e4e89SAndroid Build Coastguard Worker 
186*de1e4e89SAndroid Build Coastguard Worker 	if (ind == 3) {
187*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "pack_key16 bad index value %d\n", ind);
188*de1e4e89SAndroid Build Coastguard Worker 		return -1;
189*de1e4e89SAndroid Build Coastguard Worker 	}
190*de1e4e89SAndroid Build Coastguard Worker 
191*de1e4e89SAndroid Build Coastguard Worker 	stride = 8 * (2 - ind);
192*de1e4e89SAndroid Build Coastguard Worker 	tkey->val = htonl((tkey->val & retain) << stride);
193*de1e4e89SAndroid Build Coastguard Worker 	tkey->mask = htonl(((tkey->mask | ~retain) << stride) | m[ind]);
194*de1e4e89SAndroid Build Coastguard Worker 
195*de1e4e89SAndroid Build Coastguard Worker 	tkey->off &= ~3;
196*de1e4e89SAndroid Build Coastguard Worker 
197*de1e4e89SAndroid Build Coastguard Worker 	if (pedit_debug)
198*de1e4e89SAndroid Build Coastguard Worker 		printf("pack_key16: Final val %08x mask %08x\n",
199*de1e4e89SAndroid Build Coastguard Worker 		       tkey->val, tkey->mask);
200*de1e4e89SAndroid Build Coastguard Worker 	return pack_key(sel, tkey);
201*de1e4e89SAndroid Build Coastguard Worker 
202*de1e4e89SAndroid Build Coastguard Worker }
203*de1e4e89SAndroid Build Coastguard Worker 
pack_key8(__u32 retain,struct m_pedit_sel * sel,struct m_pedit_key * tkey)204*de1e4e89SAndroid Build Coastguard Worker int pack_key8(__u32 retain, struct m_pedit_sel *sel, struct m_pedit_key *tkey)
205*de1e4e89SAndroid Build Coastguard Worker {
206*de1e4e89SAndroid Build Coastguard Worker 	int ind, stride;
207*de1e4e89SAndroid Build Coastguard Worker 	__u32 m[4] = { 0x00FFFFFF, 0xFF00FFFF, 0xFFFF00FF, 0xFFFFFF00 };
208*de1e4e89SAndroid Build Coastguard Worker 
209*de1e4e89SAndroid Build Coastguard Worker 	if (tkey->val > 0xFF || tkey->mask > 0xFF) {
210*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "pack_key8 bad value (val %x mask %x\n",
211*de1e4e89SAndroid Build Coastguard Worker 			tkey->val, tkey->mask);
212*de1e4e89SAndroid Build Coastguard Worker 		return -1;
213*de1e4e89SAndroid Build Coastguard Worker 	}
214*de1e4e89SAndroid Build Coastguard Worker 
215*de1e4e89SAndroid Build Coastguard Worker 	ind = tkey->off & 3;
216*de1e4e89SAndroid Build Coastguard Worker 
217*de1e4e89SAndroid Build Coastguard Worker 	stride = 8 * (3 - ind);
218*de1e4e89SAndroid Build Coastguard Worker 	tkey->val = htonl((tkey->val & retain) << stride);
219*de1e4e89SAndroid Build Coastguard Worker 	tkey->mask = htonl(((tkey->mask | ~retain) << stride) | m[ind]);
220*de1e4e89SAndroid Build Coastguard Worker 
221*de1e4e89SAndroid Build Coastguard Worker 	tkey->off &= ~3;
222*de1e4e89SAndroid Build Coastguard Worker 
223*de1e4e89SAndroid Build Coastguard Worker 	if (pedit_debug)
224*de1e4e89SAndroid Build Coastguard Worker 		printf("pack_key8: Final word off %d  val %08x mask %08x\n",
225*de1e4e89SAndroid Build Coastguard Worker 		       tkey->off, tkey->val, tkey->mask);
226*de1e4e89SAndroid Build Coastguard Worker 	return pack_key(sel, tkey);
227*de1e4e89SAndroid Build Coastguard Worker }
228*de1e4e89SAndroid Build Coastguard Worker 
pack_mac(struct m_pedit_sel * sel,struct m_pedit_key * tkey,__u8 * mac)229*de1e4e89SAndroid Build Coastguard Worker static int pack_mac(struct m_pedit_sel *sel, struct m_pedit_key *tkey,
230*de1e4e89SAndroid Build Coastguard Worker 		    __u8 *mac)
231*de1e4e89SAndroid Build Coastguard Worker {
232*de1e4e89SAndroid Build Coastguard Worker 	int ret = 0;
233*de1e4e89SAndroid Build Coastguard Worker 
234*de1e4e89SAndroid Build Coastguard Worker 	if (!(tkey->off & 0x3)) {
235*de1e4e89SAndroid Build Coastguard Worker 		tkey->mask = 0;
236*de1e4e89SAndroid Build Coastguard Worker 		tkey->val = ntohl(*((__u32 *)mac));
237*de1e4e89SAndroid Build Coastguard Worker 		ret |= pack_key32(~0, sel, tkey);
238*de1e4e89SAndroid Build Coastguard Worker 
239*de1e4e89SAndroid Build Coastguard Worker 		tkey->off += 4;
240*de1e4e89SAndroid Build Coastguard Worker 		tkey->mask = 0;
241*de1e4e89SAndroid Build Coastguard Worker 		tkey->val = ntohs(*((__u16 *)&mac[4]));
242*de1e4e89SAndroid Build Coastguard Worker 		ret |= pack_key16(~0, sel, tkey);
243*de1e4e89SAndroid Build Coastguard Worker 	} else if (!(tkey->off & 0x1)) {
244*de1e4e89SAndroid Build Coastguard Worker 		tkey->mask = 0;
245*de1e4e89SAndroid Build Coastguard Worker 		tkey->val = ntohs(*((__u16 *)mac));
246*de1e4e89SAndroid Build Coastguard Worker 		ret |= pack_key16(~0, sel, tkey);
247*de1e4e89SAndroid Build Coastguard Worker 
248*de1e4e89SAndroid Build Coastguard Worker 		tkey->off += 4;
249*de1e4e89SAndroid Build Coastguard Worker 		tkey->mask = 0;
250*de1e4e89SAndroid Build Coastguard Worker 		tkey->val = ntohl(*((__u32 *)(mac + 2)));
251*de1e4e89SAndroid Build Coastguard Worker 		ret |= pack_key32(~0, sel, tkey);
252*de1e4e89SAndroid Build Coastguard Worker 	} else {
253*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr,
254*de1e4e89SAndroid Build Coastguard Worker 			"pack_mac: mac offsets must begin in 32bit or 16bit boundaries\n");
255*de1e4e89SAndroid Build Coastguard Worker 		return -1;
256*de1e4e89SAndroid Build Coastguard Worker 	}
257*de1e4e89SAndroid Build Coastguard Worker 
258*de1e4e89SAndroid Build Coastguard Worker 	return ret;
259*de1e4e89SAndroid Build Coastguard Worker }
260*de1e4e89SAndroid Build Coastguard Worker 
pack_ipv6(struct m_pedit_sel * sel,struct m_pedit_key * tkey,__u32 * ipv6)261*de1e4e89SAndroid Build Coastguard Worker static int pack_ipv6(struct m_pedit_sel *sel, struct m_pedit_key *tkey,
262*de1e4e89SAndroid Build Coastguard Worker 		     __u32 *ipv6)
263*de1e4e89SAndroid Build Coastguard Worker {
264*de1e4e89SAndroid Build Coastguard Worker 	int ret = 0;
265*de1e4e89SAndroid Build Coastguard Worker 	int i;
266*de1e4e89SAndroid Build Coastguard Worker 
267*de1e4e89SAndroid Build Coastguard Worker 	if (tkey->off & 0x3) {
268*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr,
269*de1e4e89SAndroid Build Coastguard Worker 			"pack_ipv6: IPv6 offsets must begin in 32bit boundaries\n");
270*de1e4e89SAndroid Build Coastguard Worker 		return -1;
271*de1e4e89SAndroid Build Coastguard Worker 	}
272*de1e4e89SAndroid Build Coastguard Worker 
273*de1e4e89SAndroid Build Coastguard Worker 	for (i = 0; i < 4; i++) {
274*de1e4e89SAndroid Build Coastguard Worker 		tkey->mask = 0;
275*de1e4e89SAndroid Build Coastguard Worker 		tkey->val = ntohl(ipv6[i]);
276*de1e4e89SAndroid Build Coastguard Worker 
277*de1e4e89SAndroid Build Coastguard Worker 		ret = pack_key32(~0, sel, tkey);
278*de1e4e89SAndroid Build Coastguard Worker 		if (ret)
279*de1e4e89SAndroid Build Coastguard Worker 			return ret;
280*de1e4e89SAndroid Build Coastguard Worker 
281*de1e4e89SAndroid Build Coastguard Worker 		tkey->off += 4;
282*de1e4e89SAndroid Build Coastguard Worker 	}
283*de1e4e89SAndroid Build Coastguard Worker 
284*de1e4e89SAndroid Build Coastguard Worker 	return 0;
285*de1e4e89SAndroid Build Coastguard Worker }
286*de1e4e89SAndroid Build Coastguard Worker 
parse_val(int * argc_p,char *** argv_p,__u32 * val,int type)287*de1e4e89SAndroid Build Coastguard Worker int parse_val(int *argc_p, char ***argv_p, __u32 *val, int type)
288*de1e4e89SAndroid Build Coastguard Worker {
289*de1e4e89SAndroid Build Coastguard Worker 	int argc = *argc_p;
290*de1e4e89SAndroid Build Coastguard Worker 	char **argv = *argv_p;
291*de1e4e89SAndroid Build Coastguard Worker 
292*de1e4e89SAndroid Build Coastguard Worker 	if (argc <= 0)
293*de1e4e89SAndroid Build Coastguard Worker 		return -1;
294*de1e4e89SAndroid Build Coastguard Worker 
295*de1e4e89SAndroid Build Coastguard Worker 	if (type == TINT)
296*de1e4e89SAndroid Build Coastguard Worker 		return get_integer((int *)val, *argv, 0);
297*de1e4e89SAndroid Build Coastguard Worker 
298*de1e4e89SAndroid Build Coastguard Worker 	if (type == TU32)
299*de1e4e89SAndroid Build Coastguard Worker 		return get_u32(val, *argv, 0);
300*de1e4e89SAndroid Build Coastguard Worker 
301*de1e4e89SAndroid Build Coastguard Worker 	if (type == TIPV4) {
302*de1e4e89SAndroid Build Coastguard Worker 		inet_prefix addr;
303*de1e4e89SAndroid Build Coastguard Worker 
304*de1e4e89SAndroid Build Coastguard Worker 		if (get_prefix_1(&addr, *argv, AF_INET))
305*de1e4e89SAndroid Build Coastguard Worker 			return -1;
306*de1e4e89SAndroid Build Coastguard Worker 
307*de1e4e89SAndroid Build Coastguard Worker 		*val = addr.data[0];
308*de1e4e89SAndroid Build Coastguard Worker 		return 0;
309*de1e4e89SAndroid Build Coastguard Worker 	}
310*de1e4e89SAndroid Build Coastguard Worker 
311*de1e4e89SAndroid Build Coastguard Worker 	if (type == TIPV6) {
312*de1e4e89SAndroid Build Coastguard Worker 		inet_prefix addr;
313*de1e4e89SAndroid Build Coastguard Worker 
314*de1e4e89SAndroid Build Coastguard Worker 		if (get_prefix_1(&addr, *argv, AF_INET6))
315*de1e4e89SAndroid Build Coastguard Worker 			return -1;
316*de1e4e89SAndroid Build Coastguard Worker 
317*de1e4e89SAndroid Build Coastguard Worker 		memcpy(val, addr.data, addr.bytelen);
318*de1e4e89SAndroid Build Coastguard Worker 
319*de1e4e89SAndroid Build Coastguard Worker 		return 0;
320*de1e4e89SAndroid Build Coastguard Worker 	}
321*de1e4e89SAndroid Build Coastguard Worker 
322*de1e4e89SAndroid Build Coastguard Worker 	if (type == TMAC) {
323*de1e4e89SAndroid Build Coastguard Worker #define MAC_ALEN 6
324*de1e4e89SAndroid Build Coastguard Worker 		int ret = ll_addr_a2n((char *)val, MAC_ALEN, *argv);
325*de1e4e89SAndroid Build Coastguard Worker 
326*de1e4e89SAndroid Build Coastguard Worker 		if (ret == MAC_ALEN)
327*de1e4e89SAndroid Build Coastguard Worker 			return 0;
328*de1e4e89SAndroid Build Coastguard Worker 	}
329*de1e4e89SAndroid Build Coastguard Worker 
330*de1e4e89SAndroid Build Coastguard Worker 	return -1;
331*de1e4e89SAndroid Build Coastguard Worker }
332*de1e4e89SAndroid Build Coastguard Worker 
parse_cmd(int * argc_p,char *** argv_p,__u32 len,int type,__u32 retain,struct m_pedit_sel * sel,struct m_pedit_key * tkey)333*de1e4e89SAndroid Build Coastguard Worker int parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type, __u32 retain,
334*de1e4e89SAndroid Build Coastguard Worker 	      struct m_pedit_sel *sel, struct m_pedit_key *tkey)
335*de1e4e89SAndroid Build Coastguard Worker {
336*de1e4e89SAndroid Build Coastguard Worker 	__u32 mask[4] = { 0 };
337*de1e4e89SAndroid Build Coastguard Worker 	__u32 val[4] = { 0 };
338*de1e4e89SAndroid Build Coastguard Worker 	__u32 *m = &mask[0];
339*de1e4e89SAndroid Build Coastguard Worker 	__u32 *v = &val[0];
340*de1e4e89SAndroid Build Coastguard Worker 	__u32 o = 0xFF;
341*de1e4e89SAndroid Build Coastguard Worker 	int res = -1;
342*de1e4e89SAndroid Build Coastguard Worker 	int argc = *argc_p;
343*de1e4e89SAndroid Build Coastguard Worker 	char **argv = *argv_p;
344*de1e4e89SAndroid Build Coastguard Worker 
345*de1e4e89SAndroid Build Coastguard Worker 	if (argc <= 0)
346*de1e4e89SAndroid Build Coastguard Worker 		return -1;
347*de1e4e89SAndroid Build Coastguard Worker 
348*de1e4e89SAndroid Build Coastguard Worker 	if (pedit_debug)
349*de1e4e89SAndroid Build Coastguard Worker 		printf("parse_cmd argc %d %s offset %d length %d\n",
350*de1e4e89SAndroid Build Coastguard Worker 		       argc, *argv, tkey->off, len);
351*de1e4e89SAndroid Build Coastguard Worker 
352*de1e4e89SAndroid Build Coastguard Worker 	if (len == 2)
353*de1e4e89SAndroid Build Coastguard Worker 		o = 0xFFFF;
354*de1e4e89SAndroid Build Coastguard Worker 	if (len == 4)
355*de1e4e89SAndroid Build Coastguard Worker 		o = 0xFFFFFFFF;
356*de1e4e89SAndroid Build Coastguard Worker 
357*de1e4e89SAndroid Build Coastguard Worker 	if (matches(*argv, "invert") == 0) {
358*de1e4e89SAndroid Build Coastguard Worker 		*v = *m = o;
359*de1e4e89SAndroid Build Coastguard Worker 	} else if (matches(*argv, "set") == 0 ||
360*de1e4e89SAndroid Build Coastguard Worker 		   matches(*argv, "add") == 0) {
361*de1e4e89SAndroid Build Coastguard Worker 		if (matches(*argv, "add") == 0)
362*de1e4e89SAndroid Build Coastguard Worker 			tkey->cmd = TCA_PEDIT_KEY_EX_CMD_ADD;
363*de1e4e89SAndroid Build Coastguard Worker 
364*de1e4e89SAndroid Build Coastguard Worker 		if (!sel->extended && tkey->cmd) {
365*de1e4e89SAndroid Build Coastguard Worker 			fprintf(stderr,
366*de1e4e89SAndroid Build Coastguard Worker 				"Non extended mode. only 'set' command is supported\n");
367*de1e4e89SAndroid Build Coastguard Worker 			return -1;
368*de1e4e89SAndroid Build Coastguard Worker 		}
369*de1e4e89SAndroid Build Coastguard Worker 
370*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
371*de1e4e89SAndroid Build Coastguard Worker 		if (parse_val(&argc, &argv, val, type))
372*de1e4e89SAndroid Build Coastguard Worker 			return -1;
373*de1e4e89SAndroid Build Coastguard Worker 	} else if (matches(*argv, "preserve") == 0) {
374*de1e4e89SAndroid Build Coastguard Worker 		retain = 0;
375*de1e4e89SAndroid Build Coastguard Worker 	} else {
376*de1e4e89SAndroid Build Coastguard Worker 		if (matches(*argv, "clear") != 0)
377*de1e4e89SAndroid Build Coastguard Worker 			return -1;
378*de1e4e89SAndroid Build Coastguard Worker 	}
379*de1e4e89SAndroid Build Coastguard Worker 
380*de1e4e89SAndroid Build Coastguard Worker 	argc--;
381*de1e4e89SAndroid Build Coastguard Worker 	argv++;
382*de1e4e89SAndroid Build Coastguard Worker 
383*de1e4e89SAndroid Build Coastguard Worker 	if (argc && matches(*argv, "retain") == 0) {
384*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
385*de1e4e89SAndroid Build Coastguard Worker 		if (parse_val(&argc, &argv, &retain, TU32))
386*de1e4e89SAndroid Build Coastguard Worker 			return -1;
387*de1e4e89SAndroid Build Coastguard Worker 		argc--;
388*de1e4e89SAndroid Build Coastguard Worker 		argv++;
389*de1e4e89SAndroid Build Coastguard Worker 	}
390*de1e4e89SAndroid Build Coastguard Worker 
391*de1e4e89SAndroid Build Coastguard Worker 	if (len > 4 && retain != ~0) {
392*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr,
393*de1e4e89SAndroid Build Coastguard Worker 			"retain is not supported for fields longer the 32 bits\n");
394*de1e4e89SAndroid Build Coastguard Worker 		return -1;
395*de1e4e89SAndroid Build Coastguard Worker 	}
396*de1e4e89SAndroid Build Coastguard Worker 
397*de1e4e89SAndroid Build Coastguard Worker 	if (type == TMAC) {
398*de1e4e89SAndroid Build Coastguard Worker 		res = pack_mac(sel, tkey, (__u8 *)val);
399*de1e4e89SAndroid Build Coastguard Worker 		goto done;
400*de1e4e89SAndroid Build Coastguard Worker 	}
401*de1e4e89SAndroid Build Coastguard Worker 
402*de1e4e89SAndroid Build Coastguard Worker 	if (type == TIPV6) {
403*de1e4e89SAndroid Build Coastguard Worker 		res = pack_ipv6(sel, tkey, val);
404*de1e4e89SAndroid Build Coastguard Worker 		goto done;
405*de1e4e89SAndroid Build Coastguard Worker 	}
406*de1e4e89SAndroid Build Coastguard Worker 
407*de1e4e89SAndroid Build Coastguard Worker 	tkey->val = *v;
408*de1e4e89SAndroid Build Coastguard Worker 	tkey->mask = *m;
409*de1e4e89SAndroid Build Coastguard Worker 
410*de1e4e89SAndroid Build Coastguard Worker 	if (type == TIPV4)
411*de1e4e89SAndroid Build Coastguard Worker 		tkey->val = ntohl(tkey->val);
412*de1e4e89SAndroid Build Coastguard Worker 
413*de1e4e89SAndroid Build Coastguard Worker 	if (len == 1) {
414*de1e4e89SAndroid Build Coastguard Worker 		res = pack_key8(retain, sel, tkey);
415*de1e4e89SAndroid Build Coastguard Worker 		goto done;
416*de1e4e89SAndroid Build Coastguard Worker 	}
417*de1e4e89SAndroid Build Coastguard Worker 	if (len == 2) {
418*de1e4e89SAndroid Build Coastguard Worker 		res = pack_key16(retain, sel, tkey);
419*de1e4e89SAndroid Build Coastguard Worker 		goto done;
420*de1e4e89SAndroid Build Coastguard Worker 	}
421*de1e4e89SAndroid Build Coastguard Worker 	if (len == 4) {
422*de1e4e89SAndroid Build Coastguard Worker 		res = pack_key32(retain, sel, tkey);
423*de1e4e89SAndroid Build Coastguard Worker 		goto done;
424*de1e4e89SAndroid Build Coastguard Worker 	}
425*de1e4e89SAndroid Build Coastguard Worker 
426*de1e4e89SAndroid Build Coastguard Worker 	return -1;
427*de1e4e89SAndroid Build Coastguard Worker done:
428*de1e4e89SAndroid Build Coastguard Worker 	if (pedit_debug)
429*de1e4e89SAndroid Build Coastguard Worker 		printf("parse_cmd done argc %d %s offset %d length %d\n",
430*de1e4e89SAndroid Build Coastguard Worker 		       argc, *argv, tkey->off, len);
431*de1e4e89SAndroid Build Coastguard Worker 	*argc_p = argc;
432*de1e4e89SAndroid Build Coastguard Worker 	*argv_p = argv;
433*de1e4e89SAndroid Build Coastguard Worker 	return res;
434*de1e4e89SAndroid Build Coastguard Worker 
435*de1e4e89SAndroid Build Coastguard Worker }
436*de1e4e89SAndroid Build Coastguard Worker 
parse_offset(int * argc_p,char *** argv_p,struct m_pedit_sel * sel,struct m_pedit_key * tkey)437*de1e4e89SAndroid Build Coastguard Worker int parse_offset(int *argc_p, char ***argv_p, struct m_pedit_sel *sel,
438*de1e4e89SAndroid Build Coastguard Worker 		 struct m_pedit_key *tkey)
439*de1e4e89SAndroid Build Coastguard Worker {
440*de1e4e89SAndroid Build Coastguard Worker 	int off;
441*de1e4e89SAndroid Build Coastguard Worker 	__u32 len, retain;
442*de1e4e89SAndroid Build Coastguard Worker 	int argc = *argc_p;
443*de1e4e89SAndroid Build Coastguard Worker 	char **argv = *argv_p;
444*de1e4e89SAndroid Build Coastguard Worker 	int res = -1;
445*de1e4e89SAndroid Build Coastguard Worker 
446*de1e4e89SAndroid Build Coastguard Worker 	if (argc <= 0)
447*de1e4e89SAndroid Build Coastguard Worker 		return -1;
448*de1e4e89SAndroid Build Coastguard Worker 
449*de1e4e89SAndroid Build Coastguard Worker 	if (get_integer(&off, *argv, 0))
450*de1e4e89SAndroid Build Coastguard Worker 		return -1;
451*de1e4e89SAndroid Build Coastguard Worker 	tkey->off = off;
452*de1e4e89SAndroid Build Coastguard Worker 
453*de1e4e89SAndroid Build Coastguard Worker 	argc--;
454*de1e4e89SAndroid Build Coastguard Worker 	argv++;
455*de1e4e89SAndroid Build Coastguard Worker 
456*de1e4e89SAndroid Build Coastguard Worker 	if (argc <= 0)
457*de1e4e89SAndroid Build Coastguard Worker 		return -1;
458*de1e4e89SAndroid Build Coastguard Worker 
459*de1e4e89SAndroid Build Coastguard Worker 	if (matches(*argv, "u32") == 0) {
460*de1e4e89SAndroid Build Coastguard Worker 		len = 4;
461*de1e4e89SAndroid Build Coastguard Worker 		retain = 0xFFFFFFFF;
462*de1e4e89SAndroid Build Coastguard Worker 		goto done;
463*de1e4e89SAndroid Build Coastguard Worker 	}
464*de1e4e89SAndroid Build Coastguard Worker 	if (matches(*argv, "u16") == 0) {
465*de1e4e89SAndroid Build Coastguard Worker 		len = 2;
466*de1e4e89SAndroid Build Coastguard Worker 		retain = 0xffff;
467*de1e4e89SAndroid Build Coastguard Worker 		goto done;
468*de1e4e89SAndroid Build Coastguard Worker 	}
469*de1e4e89SAndroid Build Coastguard Worker 	if (matches(*argv, "u8") == 0) {
470*de1e4e89SAndroid Build Coastguard Worker 		len = 1;
471*de1e4e89SAndroid Build Coastguard Worker 		retain = 0xff;
472*de1e4e89SAndroid Build Coastguard Worker 		goto done;
473*de1e4e89SAndroid Build Coastguard Worker 	}
474*de1e4e89SAndroid Build Coastguard Worker 
475*de1e4e89SAndroid Build Coastguard Worker 	return -1;
476*de1e4e89SAndroid Build Coastguard Worker 
477*de1e4e89SAndroid Build Coastguard Worker done:
478*de1e4e89SAndroid Build Coastguard Worker 
479*de1e4e89SAndroid Build Coastguard Worker 	NEXT_ARG();
480*de1e4e89SAndroid Build Coastguard Worker 
481*de1e4e89SAndroid Build Coastguard Worker 	/* [at <someval> offmask <maskval> shift <shiftval>] */
482*de1e4e89SAndroid Build Coastguard Worker 	if (matches(*argv, "at") == 0) {
483*de1e4e89SAndroid Build Coastguard Worker 
484*de1e4e89SAndroid Build Coastguard Worker 		__u32 atv = 0, offmask = 0x0, shift = 0;
485*de1e4e89SAndroid Build Coastguard Worker 
486*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
487*de1e4e89SAndroid Build Coastguard Worker 		if (get_u32(&atv, *argv, 0))
488*de1e4e89SAndroid Build Coastguard Worker 			return -1;
489*de1e4e89SAndroid Build Coastguard Worker 		tkey->at = atv;
490*de1e4e89SAndroid Build Coastguard Worker 
491*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
492*de1e4e89SAndroid Build Coastguard Worker 
493*de1e4e89SAndroid Build Coastguard Worker 		if (get_u32(&offmask, *argv, 16))
494*de1e4e89SAndroid Build Coastguard Worker 			return -1;
495*de1e4e89SAndroid Build Coastguard Worker 		tkey->offmask = offmask;
496*de1e4e89SAndroid Build Coastguard Worker 
497*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
498*de1e4e89SAndroid Build Coastguard Worker 
499*de1e4e89SAndroid Build Coastguard Worker 		if (get_u32(&shift, *argv, 0))
500*de1e4e89SAndroid Build Coastguard Worker 			return -1;
501*de1e4e89SAndroid Build Coastguard Worker 		tkey->shift = shift;
502*de1e4e89SAndroid Build Coastguard Worker 
503*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
504*de1e4e89SAndroid Build Coastguard Worker 	}
505*de1e4e89SAndroid Build Coastguard Worker 
506*de1e4e89SAndroid Build Coastguard Worker 	res = parse_cmd(&argc, &argv, len, TU32, retain, sel, tkey);
507*de1e4e89SAndroid Build Coastguard Worker 
508*de1e4e89SAndroid Build Coastguard Worker 	*argc_p = argc;
509*de1e4e89SAndroid Build Coastguard Worker 	*argv_p = argv;
510*de1e4e89SAndroid Build Coastguard Worker 	return res;
511*de1e4e89SAndroid Build Coastguard Worker }
512*de1e4e89SAndroid Build Coastguard Worker 
parse_munge(int * argc_p,char *** argv_p,struct m_pedit_sel * sel)513*de1e4e89SAndroid Build Coastguard Worker static int parse_munge(int *argc_p, char ***argv_p, struct m_pedit_sel *sel)
514*de1e4e89SAndroid Build Coastguard Worker {
515*de1e4e89SAndroid Build Coastguard Worker 	struct m_pedit_key tkey = {};
516*de1e4e89SAndroid Build Coastguard Worker 	int argc = *argc_p;
517*de1e4e89SAndroid Build Coastguard Worker 	char **argv = *argv_p;
518*de1e4e89SAndroid Build Coastguard Worker 	int res = -1;
519*de1e4e89SAndroid Build Coastguard Worker 
520*de1e4e89SAndroid Build Coastguard Worker 	if (argc <= 0)
521*de1e4e89SAndroid Build Coastguard Worker 		return -1;
522*de1e4e89SAndroid Build Coastguard Worker 
523*de1e4e89SAndroid Build Coastguard Worker 	if (matches(*argv, "offset") == 0) {
524*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
525*de1e4e89SAndroid Build Coastguard Worker 		res = parse_offset(&argc, &argv, sel, &tkey);
526*de1e4e89SAndroid Build Coastguard Worker 		goto done;
527*de1e4e89SAndroid Build Coastguard Worker 	} else {
528*de1e4e89SAndroid Build Coastguard Worker 		char k[16];
529*de1e4e89SAndroid Build Coastguard Worker 		struct m_pedit_util *p = NULL;
530*de1e4e89SAndroid Build Coastguard Worker 
531*de1e4e89SAndroid Build Coastguard Worker 		strncpy(k, *argv, sizeof(k) - 1);
532*de1e4e89SAndroid Build Coastguard Worker 
533*de1e4e89SAndroid Build Coastguard Worker 		if (argc > 0) {
534*de1e4e89SAndroid Build Coastguard Worker 			p = get_pedit_kind(k);
535*de1e4e89SAndroid Build Coastguard Worker 			if (p == NULL)
536*de1e4e89SAndroid Build Coastguard Worker 				goto bad_val;
537*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
538*de1e4e89SAndroid Build Coastguard Worker 			res = p->parse_peopt(&argc, &argv, sel, &tkey);
539*de1e4e89SAndroid Build Coastguard Worker 			if (res < 0) {
540*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "bad pedit parsing\n");
541*de1e4e89SAndroid Build Coastguard Worker 				goto bad_val;
542*de1e4e89SAndroid Build Coastguard Worker 			}
543*de1e4e89SAndroid Build Coastguard Worker 			goto done;
544*de1e4e89SAndroid Build Coastguard Worker 		}
545*de1e4e89SAndroid Build Coastguard Worker 	}
546*de1e4e89SAndroid Build Coastguard Worker 
547*de1e4e89SAndroid Build Coastguard Worker bad_val:
548*de1e4e89SAndroid Build Coastguard Worker 	return -1;
549*de1e4e89SAndroid Build Coastguard Worker 
550*de1e4e89SAndroid Build Coastguard Worker done:
551*de1e4e89SAndroid Build Coastguard Worker 
552*de1e4e89SAndroid Build Coastguard Worker 	*argc_p = argc;
553*de1e4e89SAndroid Build Coastguard Worker 	*argv_p = argv;
554*de1e4e89SAndroid Build Coastguard Worker 	return res;
555*de1e4e89SAndroid Build Coastguard Worker }
556*de1e4e89SAndroid Build Coastguard Worker 
pedit_keys_ex_getattr(struct rtattr * attr,struct m_pedit_key_ex * keys_ex,int n)557*de1e4e89SAndroid Build Coastguard Worker static int pedit_keys_ex_getattr(struct rtattr *attr,
558*de1e4e89SAndroid Build Coastguard Worker 				 struct m_pedit_key_ex *keys_ex, int n)
559*de1e4e89SAndroid Build Coastguard Worker {
560*de1e4e89SAndroid Build Coastguard Worker 	struct rtattr *i;
561*de1e4e89SAndroid Build Coastguard Worker 	int rem = RTA_PAYLOAD(attr);
562*de1e4e89SAndroid Build Coastguard Worker 	struct rtattr *tb[TCA_PEDIT_KEY_EX_MAX + 1];
563*de1e4e89SAndroid Build Coastguard Worker 	struct m_pedit_key_ex *k = keys_ex;
564*de1e4e89SAndroid Build Coastguard Worker 
565*de1e4e89SAndroid Build Coastguard Worker 	for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
566*de1e4e89SAndroid Build Coastguard Worker 		if (!n)
567*de1e4e89SAndroid Build Coastguard Worker 			return -1;
568*de1e4e89SAndroid Build Coastguard Worker 
569*de1e4e89SAndroid Build Coastguard Worker 		if (i->rta_type != TCA_PEDIT_KEY_EX)
570*de1e4e89SAndroid Build Coastguard Worker 			return -1;
571*de1e4e89SAndroid Build Coastguard Worker 
572*de1e4e89SAndroid Build Coastguard Worker 		parse_rtattr_nested(tb, TCA_PEDIT_KEY_EX_MAX, i);
573*de1e4e89SAndroid Build Coastguard Worker 
574*de1e4e89SAndroid Build Coastguard Worker 		k->htype = rta_getattr_u16(tb[TCA_PEDIT_KEY_EX_HTYPE]);
575*de1e4e89SAndroid Build Coastguard Worker 		k->cmd = rta_getattr_u16(tb[TCA_PEDIT_KEY_EX_CMD]);
576*de1e4e89SAndroid Build Coastguard Worker 
577*de1e4e89SAndroid Build Coastguard Worker 		k++;
578*de1e4e89SAndroid Build Coastguard Worker 		n--;
579*de1e4e89SAndroid Build Coastguard Worker 	}
580*de1e4e89SAndroid Build Coastguard Worker 
581*de1e4e89SAndroid Build Coastguard Worker 	return !!n;
582*de1e4e89SAndroid Build Coastguard Worker }
583*de1e4e89SAndroid Build Coastguard Worker 
pedit_keys_ex_addattr(struct m_pedit_sel * sel,struct nlmsghdr * n)584*de1e4e89SAndroid Build Coastguard Worker static int pedit_keys_ex_addattr(struct m_pedit_sel *sel, struct nlmsghdr *n)
585*de1e4e89SAndroid Build Coastguard Worker {
586*de1e4e89SAndroid Build Coastguard Worker 	struct m_pedit_key_ex *k = sel->keys_ex;
587*de1e4e89SAndroid Build Coastguard Worker 	struct rtattr *keys_start;
588*de1e4e89SAndroid Build Coastguard Worker 	int i;
589*de1e4e89SAndroid Build Coastguard Worker 
590*de1e4e89SAndroid Build Coastguard Worker 	if (!sel->extended)
591*de1e4e89SAndroid Build Coastguard Worker 		return 0;
592*de1e4e89SAndroid Build Coastguard Worker 
593*de1e4e89SAndroid Build Coastguard Worker 	keys_start = addattr_nest(n, MAX_MSG, TCA_PEDIT_KEYS_EX | NLA_F_NESTED);
594*de1e4e89SAndroid Build Coastguard Worker 
595*de1e4e89SAndroid Build Coastguard Worker 	for (i = 0; i < sel->sel.nkeys; i++) {
596*de1e4e89SAndroid Build Coastguard Worker 		struct rtattr *key_start;
597*de1e4e89SAndroid Build Coastguard Worker 
598*de1e4e89SAndroid Build Coastguard Worker 		key_start = addattr_nest(n, MAX_MSG,
599*de1e4e89SAndroid Build Coastguard Worker 					 TCA_PEDIT_KEY_EX | NLA_F_NESTED);
600*de1e4e89SAndroid Build Coastguard Worker 
601*de1e4e89SAndroid Build Coastguard Worker 		if (addattr16(n, MAX_MSG, TCA_PEDIT_KEY_EX_HTYPE, k->htype) ||
602*de1e4e89SAndroid Build Coastguard Worker 		    addattr16(n, MAX_MSG, TCA_PEDIT_KEY_EX_CMD, k->cmd)) {
603*de1e4e89SAndroid Build Coastguard Worker 			return -1;
604*de1e4e89SAndroid Build Coastguard Worker 		}
605*de1e4e89SAndroid Build Coastguard Worker 
606*de1e4e89SAndroid Build Coastguard Worker 		addattr_nest_end(n, key_start);
607*de1e4e89SAndroid Build Coastguard Worker 
608*de1e4e89SAndroid Build Coastguard Worker 		k++;
609*de1e4e89SAndroid Build Coastguard Worker 	}
610*de1e4e89SAndroid Build Coastguard Worker 
611*de1e4e89SAndroid Build Coastguard Worker 	addattr_nest_end(n, keys_start);
612*de1e4e89SAndroid Build Coastguard Worker 
613*de1e4e89SAndroid Build Coastguard Worker 	return 0;
614*de1e4e89SAndroid Build Coastguard Worker }
615*de1e4e89SAndroid Build Coastguard Worker 
parse_pedit(struct action_util * a,int * argc_p,char *** argv_p,int tca_id,struct nlmsghdr * n)616*de1e4e89SAndroid Build Coastguard Worker int parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
617*de1e4e89SAndroid Build Coastguard Worker 		struct nlmsghdr *n)
618*de1e4e89SAndroid Build Coastguard Worker {
619*de1e4e89SAndroid Build Coastguard Worker 	struct m_pedit_sel sel = {};
620*de1e4e89SAndroid Build Coastguard Worker 
621*de1e4e89SAndroid Build Coastguard Worker 	int argc = *argc_p;
622*de1e4e89SAndroid Build Coastguard Worker 	char **argv = *argv_p;
623*de1e4e89SAndroid Build Coastguard Worker 	int ok = 0, iok = 0;
624*de1e4e89SAndroid Build Coastguard Worker 	struct rtattr *tail;
625*de1e4e89SAndroid Build Coastguard Worker 
626*de1e4e89SAndroid Build Coastguard Worker 	while (argc > 0) {
627*de1e4e89SAndroid Build Coastguard Worker 		if (pedit_debug > 1)
628*de1e4e89SAndroid Build Coastguard Worker 			fprintf(stderr, "while pedit (%d:%s)\n", argc, *argv);
629*de1e4e89SAndroid Build Coastguard Worker 		if (matches(*argv, "pedit") == 0) {
630*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
631*de1e4e89SAndroid Build Coastguard Worker 			ok++;
632*de1e4e89SAndroid Build Coastguard Worker 
633*de1e4e89SAndroid Build Coastguard Worker 			if (matches(*argv, "ex") == 0) {
634*de1e4e89SAndroid Build Coastguard Worker 				if (ok > 1) {
635*de1e4e89SAndroid Build Coastguard Worker 					fprintf(stderr,
636*de1e4e89SAndroid Build Coastguard Worker 						"'ex' must be before first 'munge'\n");
637*de1e4e89SAndroid Build Coastguard Worker 					explain();
638*de1e4e89SAndroid Build Coastguard Worker 					return -1;
639*de1e4e89SAndroid Build Coastguard Worker 				}
640*de1e4e89SAndroid Build Coastguard Worker 				sel.extended = true;
641*de1e4e89SAndroid Build Coastguard Worker 				NEXT_ARG();
642*de1e4e89SAndroid Build Coastguard Worker 			}
643*de1e4e89SAndroid Build Coastguard Worker 
644*de1e4e89SAndroid Build Coastguard Worker 			continue;
645*de1e4e89SAndroid Build Coastguard Worker 		} else if (matches(*argv, "help") == 0) {
646*de1e4e89SAndroid Build Coastguard Worker 			usage();
647*de1e4e89SAndroid Build Coastguard Worker 		} else if (matches(*argv, "munge") == 0) {
648*de1e4e89SAndroid Build Coastguard Worker 			if (!ok) {
649*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "Bad pedit construct (%s)\n",
650*de1e4e89SAndroid Build Coastguard Worker 					*argv);
651*de1e4e89SAndroid Build Coastguard Worker 				explain();
652*de1e4e89SAndroid Build Coastguard Worker 				return -1;
653*de1e4e89SAndroid Build Coastguard Worker 			}
654*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
655*de1e4e89SAndroid Build Coastguard Worker 
656*de1e4e89SAndroid Build Coastguard Worker 			if (parse_munge(&argc, &argv, &sel)) {
657*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "Bad pedit construct (%s)\n",
658*de1e4e89SAndroid Build Coastguard Worker 					*argv);
659*de1e4e89SAndroid Build Coastguard Worker 				explain();
660*de1e4e89SAndroid Build Coastguard Worker 				return -1;
661*de1e4e89SAndroid Build Coastguard Worker 			}
662*de1e4e89SAndroid Build Coastguard Worker 			ok++;
663*de1e4e89SAndroid Build Coastguard Worker 		} else {
664*de1e4e89SAndroid Build Coastguard Worker 			break;
665*de1e4e89SAndroid Build Coastguard Worker 		}
666*de1e4e89SAndroid Build Coastguard Worker 
667*de1e4e89SAndroid Build Coastguard Worker 	}
668*de1e4e89SAndroid Build Coastguard Worker 
669*de1e4e89SAndroid Build Coastguard Worker 	if (!ok) {
670*de1e4e89SAndroid Build Coastguard Worker 		explain();
671*de1e4e89SAndroid Build Coastguard Worker 		return -1;
672*de1e4e89SAndroid Build Coastguard Worker 	}
673*de1e4e89SAndroid Build Coastguard Worker 
674*de1e4e89SAndroid Build Coastguard Worker 	parse_action_control_dflt(&argc, &argv, &sel.sel.action, false, TC_ACT_OK);
675*de1e4e89SAndroid Build Coastguard Worker 
676*de1e4e89SAndroid Build Coastguard Worker 	if (argc) {
677*de1e4e89SAndroid Build Coastguard Worker 		if (matches(*argv, "index") == 0) {
678*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
679*de1e4e89SAndroid Build Coastguard Worker 			if (get_u32(&sel.sel.index, *argv, 10)) {
680*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "Pedit: Illegal \"index\"\n");
681*de1e4e89SAndroid Build Coastguard Worker 				return -1;
682*de1e4e89SAndroid Build Coastguard Worker 			}
683*de1e4e89SAndroid Build Coastguard Worker 			argc--;
684*de1e4e89SAndroid Build Coastguard Worker 			argv++;
685*de1e4e89SAndroid Build Coastguard Worker 			iok++;
686*de1e4e89SAndroid Build Coastguard Worker 		}
687*de1e4e89SAndroid Build Coastguard Worker 	}
688*de1e4e89SAndroid Build Coastguard Worker 
689*de1e4e89SAndroid Build Coastguard Worker 	tail = NLMSG_TAIL(n);
690*de1e4e89SAndroid Build Coastguard Worker 	addattr_l(n, MAX_MSG, tca_id, NULL, 0);
691*de1e4e89SAndroid Build Coastguard Worker 	if (!sel.extended) {
692*de1e4e89SAndroid Build Coastguard Worker 		addattr_l(n, MAX_MSG, TCA_PEDIT_PARMS, &sel,
693*de1e4e89SAndroid Build Coastguard Worker 			  sizeof(sel.sel) +
694*de1e4e89SAndroid Build Coastguard Worker 			  sel.sel.nkeys * sizeof(struct tc_pedit_key));
695*de1e4e89SAndroid Build Coastguard Worker 	} else {
696*de1e4e89SAndroid Build Coastguard Worker 		addattr_l(n, MAX_MSG, TCA_PEDIT_PARMS_EX, &sel,
697*de1e4e89SAndroid Build Coastguard Worker 			  sizeof(sel.sel) +
698*de1e4e89SAndroid Build Coastguard Worker 			  sel.sel.nkeys * sizeof(struct tc_pedit_key));
699*de1e4e89SAndroid Build Coastguard Worker 
700*de1e4e89SAndroid Build Coastguard Worker 		pedit_keys_ex_addattr(&sel, n);
701*de1e4e89SAndroid Build Coastguard Worker 	}
702*de1e4e89SAndroid Build Coastguard Worker 
703*de1e4e89SAndroid Build Coastguard Worker 	tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail;
704*de1e4e89SAndroid Build Coastguard Worker 
705*de1e4e89SAndroid Build Coastguard Worker 	*argc_p = argc;
706*de1e4e89SAndroid Build Coastguard Worker 	*argv_p = argv;
707*de1e4e89SAndroid Build Coastguard Worker 	return 0;
708*de1e4e89SAndroid Build Coastguard Worker }
709*de1e4e89SAndroid Build Coastguard Worker 
710*de1e4e89SAndroid Build Coastguard Worker const char *pedit_htype_str[] = {
711*de1e4e89SAndroid Build Coastguard Worker 	[TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK] = "",
712*de1e4e89SAndroid Build Coastguard Worker 	[TCA_PEDIT_KEY_EX_HDR_TYPE_ETH] = "eth",
713*de1e4e89SAndroid Build Coastguard Worker 	[TCA_PEDIT_KEY_EX_HDR_TYPE_IP4] = "ipv4",
714*de1e4e89SAndroid Build Coastguard Worker 	[TCA_PEDIT_KEY_EX_HDR_TYPE_IP6] = "ipv6",
715*de1e4e89SAndroid Build Coastguard Worker 	[TCA_PEDIT_KEY_EX_HDR_TYPE_TCP] = "tcp",
716*de1e4e89SAndroid Build Coastguard Worker 	[TCA_PEDIT_KEY_EX_HDR_TYPE_UDP] = "udp",
717*de1e4e89SAndroid Build Coastguard Worker };
718*de1e4e89SAndroid Build Coastguard Worker 
print_pedit_location(FILE * f,enum pedit_header_type htype,__u32 off)719*de1e4e89SAndroid Build Coastguard Worker static void print_pedit_location(FILE *f,
720*de1e4e89SAndroid Build Coastguard Worker 				 enum pedit_header_type htype, __u32 off)
721*de1e4e89SAndroid Build Coastguard Worker {
722*de1e4e89SAndroid Build Coastguard Worker 	if (htype == TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK) {
723*de1e4e89SAndroid Build Coastguard Worker 		fprintf(f, "%d", (unsigned int)off);
724*de1e4e89SAndroid Build Coastguard Worker 		return;
725*de1e4e89SAndroid Build Coastguard Worker 	}
726*de1e4e89SAndroid Build Coastguard Worker 
727*de1e4e89SAndroid Build Coastguard Worker 	if (htype < ARRAY_SIZE(pedit_htype_str))
728*de1e4e89SAndroid Build Coastguard Worker 		fprintf(f, "%s", pedit_htype_str[htype]);
729*de1e4e89SAndroid Build Coastguard Worker 	else
730*de1e4e89SAndroid Build Coastguard Worker 		fprintf(f, "unknown(%d)", htype);
731*de1e4e89SAndroid Build Coastguard Worker 
732*de1e4e89SAndroid Build Coastguard Worker 	fprintf(f, "%c%d", (int)off  >= 0 ? '+' : '-', abs((int)off));
733*de1e4e89SAndroid Build Coastguard Worker }
734*de1e4e89SAndroid Build Coastguard Worker 
print_pedit(struct action_util * au,FILE * f,struct rtattr * arg)735*de1e4e89SAndroid Build Coastguard Worker int print_pedit(struct action_util *au, FILE *f, struct rtattr *arg)
736*de1e4e89SAndroid Build Coastguard Worker {
737*de1e4e89SAndroid Build Coastguard Worker 	struct tc_pedit_sel *sel;
738*de1e4e89SAndroid Build Coastguard Worker 	struct rtattr *tb[TCA_PEDIT_MAX + 1];
739*de1e4e89SAndroid Build Coastguard Worker 	struct m_pedit_key_ex *keys_ex = NULL;
740*de1e4e89SAndroid Build Coastguard Worker 
741*de1e4e89SAndroid Build Coastguard Worker 	if (arg == NULL)
742*de1e4e89SAndroid Build Coastguard Worker 		return -1;
743*de1e4e89SAndroid Build Coastguard Worker 
744*de1e4e89SAndroid Build Coastguard Worker 	parse_rtattr_nested(tb, TCA_PEDIT_MAX, arg);
745*de1e4e89SAndroid Build Coastguard Worker 
746*de1e4e89SAndroid Build Coastguard Worker 	if (!tb[TCA_PEDIT_PARMS] && !tb[TCA_PEDIT_PARMS_EX]) {
747*de1e4e89SAndroid Build Coastguard Worker 		fprintf(f, "[NULL pedit parameters]");
748*de1e4e89SAndroid Build Coastguard Worker 		return -1;
749*de1e4e89SAndroid Build Coastguard Worker 	}
750*de1e4e89SAndroid Build Coastguard Worker 
751*de1e4e89SAndroid Build Coastguard Worker 	if (tb[TCA_PEDIT_PARMS]) {
752*de1e4e89SAndroid Build Coastguard Worker 		sel = RTA_DATA(tb[TCA_PEDIT_PARMS]);
753*de1e4e89SAndroid Build Coastguard Worker 	} else {
754*de1e4e89SAndroid Build Coastguard Worker 		int err;
755*de1e4e89SAndroid Build Coastguard Worker 
756*de1e4e89SAndroid Build Coastguard Worker 		sel = RTA_DATA(tb[TCA_PEDIT_PARMS_EX]);
757*de1e4e89SAndroid Build Coastguard Worker 
758*de1e4e89SAndroid Build Coastguard Worker 		if (!tb[TCA_PEDIT_KEYS_EX]) {
759*de1e4e89SAndroid Build Coastguard Worker 			fprintf(f, "Netlink error\n");
760*de1e4e89SAndroid Build Coastguard Worker 			return -1;
761*de1e4e89SAndroid Build Coastguard Worker 		}
762*de1e4e89SAndroid Build Coastguard Worker 
763*de1e4e89SAndroid Build Coastguard Worker 		keys_ex = calloc(sel->nkeys, sizeof(*keys_ex));
764*de1e4e89SAndroid Build Coastguard Worker 		if (!keys_ex) {
765*de1e4e89SAndroid Build Coastguard Worker 			fprintf(f, "Out of memory\n");
766*de1e4e89SAndroid Build Coastguard Worker 			return -1;
767*de1e4e89SAndroid Build Coastguard Worker 		}
768*de1e4e89SAndroid Build Coastguard Worker 
769*de1e4e89SAndroid Build Coastguard Worker 		err = pedit_keys_ex_getattr(tb[TCA_PEDIT_KEYS_EX], keys_ex,
770*de1e4e89SAndroid Build Coastguard Worker 					    sel->nkeys);
771*de1e4e89SAndroid Build Coastguard Worker 		if (err) {
772*de1e4e89SAndroid Build Coastguard Worker 			fprintf(f, "Netlink error\n");
773*de1e4e89SAndroid Build Coastguard Worker 
774*de1e4e89SAndroid Build Coastguard Worker 			free(keys_ex);
775*de1e4e89SAndroid Build Coastguard Worker 			return -1;
776*de1e4e89SAndroid Build Coastguard Worker 		}
777*de1e4e89SAndroid Build Coastguard Worker 	}
778*de1e4e89SAndroid Build Coastguard Worker 
779*de1e4e89SAndroid Build Coastguard Worker 	fprintf(f, " pedit ");
780*de1e4e89SAndroid Build Coastguard Worker 	print_action_control(f, "action ", sel->action, " ");
781*de1e4e89SAndroid Build Coastguard Worker 	fprintf(f,"keys %d\n ", sel->nkeys);
782*de1e4e89SAndroid Build Coastguard Worker 	fprintf(f, "\t index %u ref %d bind %d", sel->index, sel->refcnt,
783*de1e4e89SAndroid Build Coastguard Worker 		sel->bindcnt);
784*de1e4e89SAndroid Build Coastguard Worker 
785*de1e4e89SAndroid Build Coastguard Worker 	if (show_stats) {
786*de1e4e89SAndroid Build Coastguard Worker 		if (tb[TCA_PEDIT_TM]) {
787*de1e4e89SAndroid Build Coastguard Worker 			struct tcf_t *tm = RTA_DATA(tb[TCA_PEDIT_TM]);
788*de1e4e89SAndroid Build Coastguard Worker 
789*de1e4e89SAndroid Build Coastguard Worker 			print_tm(f, tm);
790*de1e4e89SAndroid Build Coastguard Worker 		}
791*de1e4e89SAndroid Build Coastguard Worker 	}
792*de1e4e89SAndroid Build Coastguard Worker 	if (sel->nkeys) {
793*de1e4e89SAndroid Build Coastguard Worker 		int i;
794*de1e4e89SAndroid Build Coastguard Worker 		struct tc_pedit_key *key = sel->keys;
795*de1e4e89SAndroid Build Coastguard Worker 		struct m_pedit_key_ex *key_ex = keys_ex;
796*de1e4e89SAndroid Build Coastguard Worker 
797*de1e4e89SAndroid Build Coastguard Worker 		for (i = 0; i < sel->nkeys; i++, key++) {
798*de1e4e89SAndroid Build Coastguard Worker 			enum pedit_header_type htype =
799*de1e4e89SAndroid Build Coastguard Worker 				TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK;
800*de1e4e89SAndroid Build Coastguard Worker 			enum pedit_cmd cmd = TCA_PEDIT_KEY_EX_CMD_SET;
801*de1e4e89SAndroid Build Coastguard Worker 
802*de1e4e89SAndroid Build Coastguard Worker 			if (keys_ex) {
803*de1e4e89SAndroid Build Coastguard Worker 				htype = key_ex->htype;
804*de1e4e89SAndroid Build Coastguard Worker 				cmd = key_ex->cmd;
805*de1e4e89SAndroid Build Coastguard Worker 
806*de1e4e89SAndroid Build Coastguard Worker 				key_ex++;
807*de1e4e89SAndroid Build Coastguard Worker 			}
808*de1e4e89SAndroid Build Coastguard Worker 
809*de1e4e89SAndroid Build Coastguard Worker 			fprintf(f, "\n\t key #%d", i);
810*de1e4e89SAndroid Build Coastguard Worker 
811*de1e4e89SAndroid Build Coastguard Worker 			fprintf(f, "  at ");
812*de1e4e89SAndroid Build Coastguard Worker 
813*de1e4e89SAndroid Build Coastguard Worker 			print_pedit_location(f, htype, key->off);
814*de1e4e89SAndroid Build Coastguard Worker 
815*de1e4e89SAndroid Build Coastguard Worker 			fprintf(f, ": %s %08x mask %08x",
816*de1e4e89SAndroid Build Coastguard Worker 				cmd ? "add" : "val",
817*de1e4e89SAndroid Build Coastguard Worker 				(unsigned int)ntohl(key->val),
818*de1e4e89SAndroid Build Coastguard Worker 				(unsigned int)ntohl(key->mask));
819*de1e4e89SAndroid Build Coastguard Worker 		}
820*de1e4e89SAndroid Build Coastguard Worker 	} else {
821*de1e4e89SAndroid Build Coastguard Worker 		fprintf(f, "\npedit %x keys %d is not LEGIT", sel->index,
822*de1e4e89SAndroid Build Coastguard Worker 			sel->nkeys);
823*de1e4e89SAndroid Build Coastguard Worker 	}
824*de1e4e89SAndroid Build Coastguard Worker 
825*de1e4e89SAndroid Build Coastguard Worker 	fprintf(f, "\n ");
826*de1e4e89SAndroid Build Coastguard Worker 
827*de1e4e89SAndroid Build Coastguard Worker 	free(keys_ex);
828*de1e4e89SAndroid Build Coastguard Worker 	return 0;
829*de1e4e89SAndroid Build Coastguard Worker }
830*de1e4e89SAndroid Build Coastguard Worker 
pedit_print_xstats(struct action_util * au,FILE * f,struct rtattr * xstats)831*de1e4e89SAndroid Build Coastguard Worker int pedit_print_xstats(struct action_util *au, FILE *f, struct rtattr *xstats)
832*de1e4e89SAndroid Build Coastguard Worker {
833*de1e4e89SAndroid Build Coastguard Worker 	return 0;
834*de1e4e89SAndroid Build Coastguard Worker }
835*de1e4e89SAndroid Build Coastguard Worker 
836*de1e4e89SAndroid Build Coastguard Worker struct action_util pedit_action_util = {
837*de1e4e89SAndroid Build Coastguard Worker 	.id = "pedit",
838*de1e4e89SAndroid Build Coastguard Worker 	.parse_aopt = parse_pedit,
839*de1e4e89SAndroid Build Coastguard Worker 	.print_aopt = print_pedit,
840*de1e4e89SAndroid Build Coastguard Worker };
841