xref: /aosp_15_r20/external/iproute2/tc/m_action.c (revision de1e4e894b0c224df933550f0afdecc354b238c4)
1*de1e4e89SAndroid Build Coastguard Worker /*
2*de1e4e89SAndroid Build Coastguard Worker  * m_action.c		Action Management
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  * - parse to be passed a filedescriptor for logging purposes
13*de1e4e89SAndroid Build Coastguard Worker  *
14*de1e4e89SAndroid Build Coastguard Worker */
15*de1e4e89SAndroid Build Coastguard Worker 
16*de1e4e89SAndroid Build Coastguard Worker #include <stdio.h>
17*de1e4e89SAndroid Build Coastguard Worker #include <stdlib.h>
18*de1e4e89SAndroid Build Coastguard Worker #include <unistd.h>
19*de1e4e89SAndroid Build Coastguard Worker #include <syslog.h>
20*de1e4e89SAndroid Build Coastguard Worker #include <fcntl.h>
21*de1e4e89SAndroid Build Coastguard Worker #include <sys/socket.h>
22*de1e4e89SAndroid Build Coastguard Worker #include <netinet/in.h>
23*de1e4e89SAndroid Build Coastguard Worker #include <arpa/inet.h>
24*de1e4e89SAndroid Build Coastguard Worker #include <string.h>
25*de1e4e89SAndroid Build Coastguard Worker #include <dlfcn.h>
26*de1e4e89SAndroid Build Coastguard Worker 
27*de1e4e89SAndroid Build Coastguard Worker #include "utils.h"
28*de1e4e89SAndroid Build Coastguard Worker #include "tc_common.h"
29*de1e4e89SAndroid Build Coastguard Worker #include "tc_util.h"
30*de1e4e89SAndroid Build Coastguard Worker 
31*de1e4e89SAndroid Build Coastguard Worker static struct action_util *action_list;
32*de1e4e89SAndroid Build Coastguard Worker 
33*de1e4e89SAndroid Build Coastguard Worker #ifdef CONFIG_GACT
34*de1e4e89SAndroid Build Coastguard Worker int gact_ld; /* f*ckin backward compatibility */
35*de1e4e89SAndroid Build Coastguard Worker #endif
36*de1e4e89SAndroid Build Coastguard Worker int tab_flush;
37*de1e4e89SAndroid Build Coastguard Worker 
act_usage(void)38*de1e4e89SAndroid Build Coastguard Worker static void act_usage(void)
39*de1e4e89SAndroid Build Coastguard Worker {
40*de1e4e89SAndroid Build Coastguard Worker 	/*XXX: In the near future add a action->print_help to improve
41*de1e4e89SAndroid Build Coastguard Worker 	 * usability
42*de1e4e89SAndroid Build Coastguard Worker 	 * This would mean new tc will not be backward compatible
43*de1e4e89SAndroid Build Coastguard Worker 	 * with any action .so from the old days. But if someone really
44*de1e4e89SAndroid Build Coastguard Worker 	 * does that, they would know how to fix this ..
45*de1e4e89SAndroid Build Coastguard Worker 	 *
46*de1e4e89SAndroid Build Coastguard Worker 	*/
47*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stderr, "usage: tc actions <ACTSPECOP>*\n");
48*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stderr,
49*de1e4e89SAndroid Build Coastguard Worker 		"Where: \tACTSPECOP := ACR | GD | FL\n"
50*de1e4e89SAndroid Build Coastguard Worker 			"\tACR := add | change | replace <ACTSPEC>*\n"
51*de1e4e89SAndroid Build Coastguard Worker 			"\tGD := get | delete | <ACTISPEC>*\n"
52*de1e4e89SAndroid Build Coastguard Worker 			"\tFL := ls | list | flush | <ACTNAMESPEC>\n"
53*de1e4e89SAndroid Build Coastguard Worker 			"\tACTNAMESPEC :=  action <ACTNAME>\n"
54*de1e4e89SAndroid Build Coastguard Worker 			"\tACTISPEC := <ACTNAMESPEC> <INDEXSPEC>\n"
55*de1e4e89SAndroid Build Coastguard Worker 			"\tACTSPEC := action <ACTDETAIL> [INDEXSPEC]\n"
56*de1e4e89SAndroid Build Coastguard Worker 			"\tINDEXSPEC := index <32 bit indexvalue>\n"
57*de1e4e89SAndroid Build Coastguard Worker 			"\tACTDETAIL := <ACTNAME> <ACTPARAMS>\n"
58*de1e4e89SAndroid Build Coastguard Worker 			"\t\tExample ACTNAME is gact, mirred, bpf, etc\n"
59*de1e4e89SAndroid Build Coastguard Worker 			"\t\tEach action has its own parameters (ACTPARAMS)\n"
60*de1e4e89SAndroid Build Coastguard Worker 			"\n");
61*de1e4e89SAndroid Build Coastguard Worker 
62*de1e4e89SAndroid Build Coastguard Worker 	exit(-1);
63*de1e4e89SAndroid Build Coastguard Worker }
64*de1e4e89SAndroid Build Coastguard Worker 
print_noaopt(struct action_util * au,FILE * f,struct rtattr * opt)65*de1e4e89SAndroid Build Coastguard Worker static int print_noaopt(struct action_util *au, FILE *f, struct rtattr *opt)
66*de1e4e89SAndroid Build Coastguard Worker {
67*de1e4e89SAndroid Build Coastguard Worker 	if (opt && RTA_PAYLOAD(opt))
68*de1e4e89SAndroid Build Coastguard Worker 		fprintf(f, "[Unknown action, optlen=%u] ",
69*de1e4e89SAndroid Build Coastguard Worker 			(unsigned int) RTA_PAYLOAD(opt));
70*de1e4e89SAndroid Build Coastguard Worker 	return 0;
71*de1e4e89SAndroid Build Coastguard Worker }
72*de1e4e89SAndroid Build Coastguard Worker 
parse_noaopt(struct action_util * au,int * argc_p,char *** argv_p,int code,struct nlmsghdr * n)73*de1e4e89SAndroid Build Coastguard Worker static int parse_noaopt(struct action_util *au, int *argc_p, char ***argv_p, int code, struct nlmsghdr *n)
74*de1e4e89SAndroid Build Coastguard Worker {
75*de1e4e89SAndroid Build Coastguard Worker 	int argc = *argc_p;
76*de1e4e89SAndroid Build Coastguard Worker 	char **argv = *argv_p;
77*de1e4e89SAndroid Build Coastguard Worker 
78*de1e4e89SAndroid Build Coastguard Worker 	if (argc) {
79*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "Unknown action \"%s\", hence option \"%s\" is unparsable\n", au->id, *argv);
80*de1e4e89SAndroid Build Coastguard Worker 	} else {
81*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "Unknown action \"%s\"\n", au->id);
82*de1e4e89SAndroid Build Coastguard Worker 	}
83*de1e4e89SAndroid Build Coastguard Worker 	return -1;
84*de1e4e89SAndroid Build Coastguard Worker }
85*de1e4e89SAndroid Build Coastguard Worker 
get_action_kind(char * str)86*de1e4e89SAndroid Build Coastguard Worker static struct action_util *get_action_kind(char *str)
87*de1e4e89SAndroid Build Coastguard Worker {
88*de1e4e89SAndroid Build Coastguard Worker 	static void *aBODY;
89*de1e4e89SAndroid Build Coastguard Worker 	void *dlh;
90*de1e4e89SAndroid Build Coastguard Worker 	char buf[256];
91*de1e4e89SAndroid Build Coastguard Worker 	struct action_util *a;
92*de1e4e89SAndroid Build Coastguard Worker #ifdef CONFIG_GACT
93*de1e4e89SAndroid Build Coastguard Worker 	int looked4gact = 0;
94*de1e4e89SAndroid Build Coastguard Worker restart_s:
95*de1e4e89SAndroid Build Coastguard Worker #endif
96*de1e4e89SAndroid Build Coastguard Worker 	for (a = action_list; a; a = a->next) {
97*de1e4e89SAndroid Build Coastguard Worker 		if (strcmp(a->id, str) == 0)
98*de1e4e89SAndroid Build Coastguard Worker 			return a;
99*de1e4e89SAndroid Build Coastguard Worker 	}
100*de1e4e89SAndroid Build Coastguard Worker 
101*de1e4e89SAndroid Build Coastguard Worker 	snprintf(buf, sizeof(buf), "%s/m_%s.so", get_tc_lib(), str);
102*de1e4e89SAndroid Build Coastguard Worker 	dlh = dlopen(buf, RTLD_LAZY | RTLD_GLOBAL);
103*de1e4e89SAndroid Build Coastguard Worker 	if (dlh == NULL) {
104*de1e4e89SAndroid Build Coastguard Worker 		dlh = aBODY;
105*de1e4e89SAndroid Build Coastguard Worker 		if (dlh == NULL) {
106*de1e4e89SAndroid Build Coastguard Worker 			dlh = aBODY = dlopen(NULL, RTLD_LAZY);
107*de1e4e89SAndroid Build Coastguard Worker 			if (dlh == NULL)
108*de1e4e89SAndroid Build Coastguard Worker 				goto noexist;
109*de1e4e89SAndroid Build Coastguard Worker 		}
110*de1e4e89SAndroid Build Coastguard Worker 	}
111*de1e4e89SAndroid Build Coastguard Worker 
112*de1e4e89SAndroid Build Coastguard Worker 	snprintf(buf, sizeof(buf), "%s_action_util", str);
113*de1e4e89SAndroid Build Coastguard Worker 	a = dlsym(dlh, buf);
114*de1e4e89SAndroid Build Coastguard Worker 	if (a == NULL)
115*de1e4e89SAndroid Build Coastguard Worker 		goto noexist;
116*de1e4e89SAndroid Build Coastguard Worker 
117*de1e4e89SAndroid Build Coastguard Worker reg:
118*de1e4e89SAndroid Build Coastguard Worker 	a->next = action_list;
119*de1e4e89SAndroid Build Coastguard Worker 	action_list = a;
120*de1e4e89SAndroid Build Coastguard Worker 	return a;
121*de1e4e89SAndroid Build Coastguard Worker 
122*de1e4e89SAndroid Build Coastguard Worker noexist:
123*de1e4e89SAndroid Build Coastguard Worker #ifdef CONFIG_GACT
124*de1e4e89SAndroid Build Coastguard Worker 	if (!looked4gact) {
125*de1e4e89SAndroid Build Coastguard Worker 		looked4gact = 1;
126*de1e4e89SAndroid Build Coastguard Worker 		strcpy(str, "gact");
127*de1e4e89SAndroid Build Coastguard Worker 		goto restart_s;
128*de1e4e89SAndroid Build Coastguard Worker 	}
129*de1e4e89SAndroid Build Coastguard Worker #endif
130*de1e4e89SAndroid Build Coastguard Worker 	a = calloc(1, sizeof(*a));
131*de1e4e89SAndroid Build Coastguard Worker 	if (a) {
132*de1e4e89SAndroid Build Coastguard Worker 		strncpy(a->id, "noact", 15);
133*de1e4e89SAndroid Build Coastguard Worker 		a->parse_aopt = parse_noaopt;
134*de1e4e89SAndroid Build Coastguard Worker 		a->print_aopt = print_noaopt;
135*de1e4e89SAndroid Build Coastguard Worker 		goto reg;
136*de1e4e89SAndroid Build Coastguard Worker 	}
137*de1e4e89SAndroid Build Coastguard Worker 	return a;
138*de1e4e89SAndroid Build Coastguard Worker }
139*de1e4e89SAndroid Build Coastguard Worker 
140*de1e4e89SAndroid Build Coastguard Worker static int
new_cmd(char ** argv)141*de1e4e89SAndroid Build Coastguard Worker new_cmd(char **argv)
142*de1e4e89SAndroid Build Coastguard Worker {
143*de1e4e89SAndroid Build Coastguard Worker 	if ((matches(*argv, "change") == 0) ||
144*de1e4e89SAndroid Build Coastguard Worker 		(matches(*argv, "replace") == 0) ||
145*de1e4e89SAndroid Build Coastguard Worker 		(matches(*argv, "delete") == 0) ||
146*de1e4e89SAndroid Build Coastguard Worker 		(matches(*argv, "get") == 0) ||
147*de1e4e89SAndroid Build Coastguard Worker 		(matches(*argv, "add") == 0))
148*de1e4e89SAndroid Build Coastguard Worker 			return 1;
149*de1e4e89SAndroid Build Coastguard Worker 
150*de1e4e89SAndroid Build Coastguard Worker 	return 0;
151*de1e4e89SAndroid Build Coastguard Worker 
152*de1e4e89SAndroid Build Coastguard Worker }
153*de1e4e89SAndroid Build Coastguard Worker 
parse_action(int * argc_p,char *** argv_p,int tca_id,struct nlmsghdr * n)154*de1e4e89SAndroid Build Coastguard Worker int parse_action(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n)
155*de1e4e89SAndroid Build Coastguard Worker {
156*de1e4e89SAndroid Build Coastguard Worker 	int argc = *argc_p;
157*de1e4e89SAndroid Build Coastguard Worker 	char **argv = *argv_p;
158*de1e4e89SAndroid Build Coastguard Worker 	struct rtattr *tail, *tail2;
159*de1e4e89SAndroid Build Coastguard Worker 	char k[16];
160*de1e4e89SAndroid Build Coastguard Worker 	int act_ck_len = 0;
161*de1e4e89SAndroid Build Coastguard Worker 	int ok = 0;
162*de1e4e89SAndroid Build Coastguard Worker 	int eap = 0; /* expect action parameters */
163*de1e4e89SAndroid Build Coastguard Worker 
164*de1e4e89SAndroid Build Coastguard Worker 	int ret = 0;
165*de1e4e89SAndroid Build Coastguard Worker 	int prio = 0;
166*de1e4e89SAndroid Build Coastguard Worker 	unsigned char act_ck[TC_COOKIE_MAX_SIZE];
167*de1e4e89SAndroid Build Coastguard Worker 
168*de1e4e89SAndroid Build Coastguard Worker 	if (argc <= 0)
169*de1e4e89SAndroid Build Coastguard Worker 		return -1;
170*de1e4e89SAndroid Build Coastguard Worker 
171*de1e4e89SAndroid Build Coastguard Worker 	tail = tail2 = NLMSG_TAIL(n);
172*de1e4e89SAndroid Build Coastguard Worker 
173*de1e4e89SAndroid Build Coastguard Worker 	addattr_l(n, MAX_MSG, tca_id, NULL, 0);
174*de1e4e89SAndroid Build Coastguard Worker 
175*de1e4e89SAndroid Build Coastguard Worker 	while (argc > 0) {
176*de1e4e89SAndroid Build Coastguard Worker 
177*de1e4e89SAndroid Build Coastguard Worker 		memset(k, 0, sizeof(k));
178*de1e4e89SAndroid Build Coastguard Worker 
179*de1e4e89SAndroid Build Coastguard Worker 		if (strcmp(*argv, "action") == 0) {
180*de1e4e89SAndroid Build Coastguard Worker 			argc--;
181*de1e4e89SAndroid Build Coastguard Worker 			argv++;
182*de1e4e89SAndroid Build Coastguard Worker 			eap = 1;
183*de1e4e89SAndroid Build Coastguard Worker #ifdef CONFIG_GACT
184*de1e4e89SAndroid Build Coastguard Worker 			if (!gact_ld) {
185*de1e4e89SAndroid Build Coastguard Worker 				get_action_kind("gact");
186*de1e4e89SAndroid Build Coastguard Worker 			}
187*de1e4e89SAndroid Build Coastguard Worker #endif
188*de1e4e89SAndroid Build Coastguard Worker 			continue;
189*de1e4e89SAndroid Build Coastguard Worker 		} else if (strcmp(*argv, "flowid") == 0) {
190*de1e4e89SAndroid Build Coastguard Worker 			break;
191*de1e4e89SAndroid Build Coastguard Worker 		} else if (strcmp(*argv, "classid") == 0) {
192*de1e4e89SAndroid Build Coastguard Worker 			break;
193*de1e4e89SAndroid Build Coastguard Worker 		} else if (strcmp(*argv, "help") == 0) {
194*de1e4e89SAndroid Build Coastguard Worker 			return -1;
195*de1e4e89SAndroid Build Coastguard Worker 		} else if (new_cmd(argv)) {
196*de1e4e89SAndroid Build Coastguard Worker 			goto done0;
197*de1e4e89SAndroid Build Coastguard Worker 		} else {
198*de1e4e89SAndroid Build Coastguard Worker 			struct action_util *a = NULL;
199*de1e4e89SAndroid Build Coastguard Worker 
200*de1e4e89SAndroid Build Coastguard Worker 			strncpy(k, *argv, sizeof(k) - 1);
201*de1e4e89SAndroid Build Coastguard Worker 			eap = 0;
202*de1e4e89SAndroid Build Coastguard Worker 			if (argc > 0) {
203*de1e4e89SAndroid Build Coastguard Worker 				a = get_action_kind(k);
204*de1e4e89SAndroid Build Coastguard Worker 			} else {
205*de1e4e89SAndroid Build Coastguard Worker done0:
206*de1e4e89SAndroid Build Coastguard Worker 				if (ok)
207*de1e4e89SAndroid Build Coastguard Worker 					break;
208*de1e4e89SAndroid Build Coastguard Worker 				else
209*de1e4e89SAndroid Build Coastguard Worker 					goto done;
210*de1e4e89SAndroid Build Coastguard Worker 			}
211*de1e4e89SAndroid Build Coastguard Worker 
212*de1e4e89SAndroid Build Coastguard Worker 			if (a == NULL) {
213*de1e4e89SAndroid Build Coastguard Worker 				goto bad_val;
214*de1e4e89SAndroid Build Coastguard Worker 			}
215*de1e4e89SAndroid Build Coastguard Worker 
216*de1e4e89SAndroid Build Coastguard Worker 			tail = NLMSG_TAIL(n);
217*de1e4e89SAndroid Build Coastguard Worker 			addattr_l(n, MAX_MSG, ++prio, NULL, 0);
218*de1e4e89SAndroid Build Coastguard Worker 			addattr_l(n, MAX_MSG, TCA_ACT_KIND, k, strlen(k) + 1);
219*de1e4e89SAndroid Build Coastguard Worker 
220*de1e4e89SAndroid Build Coastguard Worker 			ret = a->parse_aopt(a, &argc, &argv, TCA_ACT_OPTIONS,
221*de1e4e89SAndroid Build Coastguard Worker 					    n);
222*de1e4e89SAndroid Build Coastguard Worker 
223*de1e4e89SAndroid Build Coastguard Worker 			if (ret < 0) {
224*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "bad action parsing\n");
225*de1e4e89SAndroid Build Coastguard Worker 				goto bad_val;
226*de1e4e89SAndroid Build Coastguard Worker 			}
227*de1e4e89SAndroid Build Coastguard Worker 
228*de1e4e89SAndroid Build Coastguard Worker 			if (*argv && strcmp(*argv, "cookie") == 0) {
229*de1e4e89SAndroid Build Coastguard Worker 				size_t slen;
230*de1e4e89SAndroid Build Coastguard Worker 
231*de1e4e89SAndroid Build Coastguard Worker 				NEXT_ARG();
232*de1e4e89SAndroid Build Coastguard Worker 				slen = strlen(*argv);
233*de1e4e89SAndroid Build Coastguard Worker 				if (slen > TC_COOKIE_MAX_SIZE * 2) {
234*de1e4e89SAndroid Build Coastguard Worker 					char cookie_err_m[128];
235*de1e4e89SAndroid Build Coastguard Worker 
236*de1e4e89SAndroid Build Coastguard Worker 					snprintf(cookie_err_m, 128,
237*de1e4e89SAndroid Build Coastguard Worker 						 "%zd Max allowed size %d",
238*de1e4e89SAndroid Build Coastguard Worker 						 slen, TC_COOKIE_MAX_SIZE*2);
239*de1e4e89SAndroid Build Coastguard Worker 					invarg(cookie_err_m, *argv);
240*de1e4e89SAndroid Build Coastguard Worker 				}
241*de1e4e89SAndroid Build Coastguard Worker 
242*de1e4e89SAndroid Build Coastguard Worker 				if (hex2mem(*argv, act_ck, slen / 2) < 0)
243*de1e4e89SAndroid Build Coastguard Worker 					invarg("cookie must be a hex string\n",
244*de1e4e89SAndroid Build Coastguard Worker 					       *argv);
245*de1e4e89SAndroid Build Coastguard Worker 
246*de1e4e89SAndroid Build Coastguard Worker 				act_ck_len = slen / 2;
247*de1e4e89SAndroid Build Coastguard Worker 				argc--;
248*de1e4e89SAndroid Build Coastguard Worker 				argv++;
249*de1e4e89SAndroid Build Coastguard Worker 			}
250*de1e4e89SAndroid Build Coastguard Worker 
251*de1e4e89SAndroid Build Coastguard Worker 			if (act_ck_len)
252*de1e4e89SAndroid Build Coastguard Worker 				addattr_l(n, MAX_MSG, TCA_ACT_COOKIE,
253*de1e4e89SAndroid Build Coastguard Worker 					  &act_ck, act_ck_len);
254*de1e4e89SAndroid Build Coastguard Worker 
255*de1e4e89SAndroid Build Coastguard Worker 			tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
256*de1e4e89SAndroid Build Coastguard Worker 			ok++;
257*de1e4e89SAndroid Build Coastguard Worker 		}
258*de1e4e89SAndroid Build Coastguard Worker 	}
259*de1e4e89SAndroid Build Coastguard Worker 
260*de1e4e89SAndroid Build Coastguard Worker 	if (eap > 0) {
261*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "bad action empty %d\n", eap);
262*de1e4e89SAndroid Build Coastguard Worker 		goto bad_val;
263*de1e4e89SAndroid Build Coastguard Worker 	}
264*de1e4e89SAndroid Build Coastguard Worker 
265*de1e4e89SAndroid Build Coastguard Worker 	tail2->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail2;
266*de1e4e89SAndroid Build Coastguard Worker 
267*de1e4e89SAndroid Build Coastguard Worker done:
268*de1e4e89SAndroid Build Coastguard Worker 	*argc_p = argc;
269*de1e4e89SAndroid Build Coastguard Worker 	*argv_p = argv;
270*de1e4e89SAndroid Build Coastguard Worker 	return 0;
271*de1e4e89SAndroid Build Coastguard Worker bad_val:
272*de1e4e89SAndroid Build Coastguard Worker 	/* no need to undo things, returning from here should
273*de1e4e89SAndroid Build Coastguard Worker 	 * cause enough pain */
274*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stderr, "parse_action: bad value (%d:%s)!\n", argc, *argv);
275*de1e4e89SAndroid Build Coastguard Worker 	return -1;
276*de1e4e89SAndroid Build Coastguard Worker }
277*de1e4e89SAndroid Build Coastguard Worker 
tc_print_one_action(FILE * f,struct rtattr * arg)278*de1e4e89SAndroid Build Coastguard Worker static int tc_print_one_action(FILE *f, struct rtattr *arg)
279*de1e4e89SAndroid Build Coastguard Worker {
280*de1e4e89SAndroid Build Coastguard Worker 
281*de1e4e89SAndroid Build Coastguard Worker 	struct rtattr *tb[TCA_ACT_MAX + 1];
282*de1e4e89SAndroid Build Coastguard Worker 	int err = 0;
283*de1e4e89SAndroid Build Coastguard Worker 	struct action_util *a = NULL;
284*de1e4e89SAndroid Build Coastguard Worker 
285*de1e4e89SAndroid Build Coastguard Worker 	if (arg == NULL)
286*de1e4e89SAndroid Build Coastguard Worker 		return -1;
287*de1e4e89SAndroid Build Coastguard Worker 
288*de1e4e89SAndroid Build Coastguard Worker 	parse_rtattr_nested(tb, TCA_ACT_MAX, arg);
289*de1e4e89SAndroid Build Coastguard Worker 
290*de1e4e89SAndroid Build Coastguard Worker 	if (tb[TCA_ACT_KIND] == NULL) {
291*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "NULL Action!\n");
292*de1e4e89SAndroid Build Coastguard Worker 		return -1;
293*de1e4e89SAndroid Build Coastguard Worker 	}
294*de1e4e89SAndroid Build Coastguard Worker 
295*de1e4e89SAndroid Build Coastguard Worker 
296*de1e4e89SAndroid Build Coastguard Worker 	a = get_action_kind(RTA_DATA(tb[TCA_ACT_KIND]));
297*de1e4e89SAndroid Build Coastguard Worker 	if (a == NULL)
298*de1e4e89SAndroid Build Coastguard Worker 		return err;
299*de1e4e89SAndroid Build Coastguard Worker 
300*de1e4e89SAndroid Build Coastguard Worker 	err = a->print_aopt(a, f, tb[TCA_ACT_OPTIONS]);
301*de1e4e89SAndroid Build Coastguard Worker 
302*de1e4e89SAndroid Build Coastguard Worker 	if (err < 0)
303*de1e4e89SAndroid Build Coastguard Worker 		return err;
304*de1e4e89SAndroid Build Coastguard Worker 
305*de1e4e89SAndroid Build Coastguard Worker 	if (show_stats && tb[TCA_ACT_STATS]) {
306*de1e4e89SAndroid Build Coastguard Worker 
307*de1e4e89SAndroid Build Coastguard Worker 		fprintf(f, "\tAction statistics:\n");
308*de1e4e89SAndroid Build Coastguard Worker 		print_tcstats2_attr(f, tb[TCA_ACT_STATS], "\t", NULL);
309*de1e4e89SAndroid Build Coastguard Worker 		if (tb[TCA_ACT_COOKIE]) {
310*de1e4e89SAndroid Build Coastguard Worker 			int strsz = RTA_PAYLOAD(tb[TCA_ACT_COOKIE]);
311*de1e4e89SAndroid Build Coastguard Worker 			char b1[strsz * 2 + 1];
312*de1e4e89SAndroid Build Coastguard Worker 
313*de1e4e89SAndroid Build Coastguard Worker 			fprintf(f, "\n\tcookie len %d %s ", strsz,
314*de1e4e89SAndroid Build Coastguard Worker 				hexstring_n2a(RTA_DATA(tb[TCA_ACT_COOKIE]),
315*de1e4e89SAndroid Build Coastguard Worker 					      strsz, b1, sizeof(b1)));
316*de1e4e89SAndroid Build Coastguard Worker 		}
317*de1e4e89SAndroid Build Coastguard Worker 		fprintf(f, "\n");
318*de1e4e89SAndroid Build Coastguard Worker 	}
319*de1e4e89SAndroid Build Coastguard Worker 
320*de1e4e89SAndroid Build Coastguard Worker 	return 0;
321*de1e4e89SAndroid Build Coastguard Worker }
322*de1e4e89SAndroid Build Coastguard Worker 
323*de1e4e89SAndroid Build Coastguard Worker static int
tc_print_action_flush(FILE * f,const struct rtattr * arg)324*de1e4e89SAndroid Build Coastguard Worker tc_print_action_flush(FILE *f, const struct rtattr *arg)
325*de1e4e89SAndroid Build Coastguard Worker {
326*de1e4e89SAndroid Build Coastguard Worker 
327*de1e4e89SAndroid Build Coastguard Worker 	struct rtattr *tb[TCA_MAX + 1];
328*de1e4e89SAndroid Build Coastguard Worker 	int err = 0;
329*de1e4e89SAndroid Build Coastguard Worker 	struct action_util *a = NULL;
330*de1e4e89SAndroid Build Coastguard Worker 	__u32 *delete_count = 0;
331*de1e4e89SAndroid Build Coastguard Worker 
332*de1e4e89SAndroid Build Coastguard Worker 	parse_rtattr_nested(tb, TCA_MAX, arg);
333*de1e4e89SAndroid Build Coastguard Worker 
334*de1e4e89SAndroid Build Coastguard Worker 	if (tb[TCA_KIND] == NULL) {
335*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "NULL Action!\n");
336*de1e4e89SAndroid Build Coastguard Worker 		return -1;
337*de1e4e89SAndroid Build Coastguard Worker 	}
338*de1e4e89SAndroid Build Coastguard Worker 
339*de1e4e89SAndroid Build Coastguard Worker 	a = get_action_kind(RTA_DATA(tb[TCA_KIND]));
340*de1e4e89SAndroid Build Coastguard Worker 	if (a == NULL)
341*de1e4e89SAndroid Build Coastguard Worker 		return err;
342*de1e4e89SAndroid Build Coastguard Worker 
343*de1e4e89SAndroid Build Coastguard Worker 	delete_count = RTA_DATA(tb[TCA_FCNT]);
344*de1e4e89SAndroid Build Coastguard Worker 	fprintf(f, " %s (%d entries)\n", a->id, *delete_count);
345*de1e4e89SAndroid Build Coastguard Worker 	tab_flush = 0;
346*de1e4e89SAndroid Build Coastguard Worker 	return 0;
347*de1e4e89SAndroid Build Coastguard Worker }
348*de1e4e89SAndroid Build Coastguard Worker 
349*de1e4e89SAndroid Build Coastguard Worker int
tc_print_action(FILE * f,const struct rtattr * arg,unsigned short tot_acts)350*de1e4e89SAndroid Build Coastguard Worker tc_print_action(FILE *f, const struct rtattr *arg, unsigned short tot_acts)
351*de1e4e89SAndroid Build Coastguard Worker {
352*de1e4e89SAndroid Build Coastguard Worker 
353*de1e4e89SAndroid Build Coastguard Worker 	int i;
354*de1e4e89SAndroid Build Coastguard Worker 
355*de1e4e89SAndroid Build Coastguard Worker 	if (arg == NULL)
356*de1e4e89SAndroid Build Coastguard Worker 		return 0;
357*de1e4e89SAndroid Build Coastguard Worker 
358*de1e4e89SAndroid Build Coastguard Worker 	if (!tot_acts)
359*de1e4e89SAndroid Build Coastguard Worker 		tot_acts = TCA_ACT_MAX_PRIO;
360*de1e4e89SAndroid Build Coastguard Worker 
361*de1e4e89SAndroid Build Coastguard Worker 	struct rtattr *tb[tot_acts + 1];
362*de1e4e89SAndroid Build Coastguard Worker 
363*de1e4e89SAndroid Build Coastguard Worker 	parse_rtattr_nested(tb, tot_acts, arg);
364*de1e4e89SAndroid Build Coastguard Worker 
365*de1e4e89SAndroid Build Coastguard Worker 	if (tab_flush && NULL != tb[0]  && NULL == tb[1])
366*de1e4e89SAndroid Build Coastguard Worker 		return tc_print_action_flush(f, tb[0]);
367*de1e4e89SAndroid Build Coastguard Worker 
368*de1e4e89SAndroid Build Coastguard Worker 	for (i = 0; i < tot_acts; i++) {
369*de1e4e89SAndroid Build Coastguard Worker 		if (tb[i]) {
370*de1e4e89SAndroid Build Coastguard Worker 			fprintf(f, "\n\taction order %d: ", i);
371*de1e4e89SAndroid Build Coastguard Worker 			if (tc_print_one_action(f, tb[i]) < 0) {
372*de1e4e89SAndroid Build Coastguard Worker 				fprintf(f, "Error printing action\n");
373*de1e4e89SAndroid Build Coastguard Worker 			}
374*de1e4e89SAndroid Build Coastguard Worker 		}
375*de1e4e89SAndroid Build Coastguard Worker 
376*de1e4e89SAndroid Build Coastguard Worker 	}
377*de1e4e89SAndroid Build Coastguard Worker 
378*de1e4e89SAndroid Build Coastguard Worker 	return 0;
379*de1e4e89SAndroid Build Coastguard Worker }
380*de1e4e89SAndroid Build Coastguard Worker 
print_action(const struct sockaddr_nl * who,struct nlmsghdr * n,void * arg)381*de1e4e89SAndroid Build Coastguard Worker int print_action(const struct sockaddr_nl *who,
382*de1e4e89SAndroid Build Coastguard Worker 			   struct nlmsghdr *n,
383*de1e4e89SAndroid Build Coastguard Worker 			   void *arg)
384*de1e4e89SAndroid Build Coastguard Worker {
385*de1e4e89SAndroid Build Coastguard Worker 	FILE *fp = (FILE *)arg;
386*de1e4e89SAndroid Build Coastguard Worker 	struct tcamsg *t = NLMSG_DATA(n);
387*de1e4e89SAndroid Build Coastguard Worker 	int len = n->nlmsg_len;
388*de1e4e89SAndroid Build Coastguard Worker 	__u32 *tot_acts = NULL;
389*de1e4e89SAndroid Build Coastguard Worker 	struct rtattr *tb[TCA_ROOT_MAX+1];
390*de1e4e89SAndroid Build Coastguard Worker 
391*de1e4e89SAndroid Build Coastguard Worker 	len -= NLMSG_LENGTH(sizeof(*t));
392*de1e4e89SAndroid Build Coastguard Worker 
393*de1e4e89SAndroid Build Coastguard Worker 	if (len < 0) {
394*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "Wrong len %d\n", len);
395*de1e4e89SAndroid Build Coastguard Worker 		return -1;
396*de1e4e89SAndroid Build Coastguard Worker 	}
397*de1e4e89SAndroid Build Coastguard Worker 
398*de1e4e89SAndroid Build Coastguard Worker 	parse_rtattr(tb, TCA_ROOT_MAX, TA_RTA(t), len);
399*de1e4e89SAndroid Build Coastguard Worker 
400*de1e4e89SAndroid Build Coastguard Worker 	if (tb[TCA_ROOT_COUNT])
401*de1e4e89SAndroid Build Coastguard Worker 		tot_acts = RTA_DATA(tb[TCA_ROOT_COUNT]);
402*de1e4e89SAndroid Build Coastguard Worker 
403*de1e4e89SAndroid Build Coastguard Worker 	fprintf(fp, "total acts %d\n", tot_acts ? *tot_acts:0);
404*de1e4e89SAndroid Build Coastguard Worker 	if (tb[TCA_ACT_TAB] == NULL) {
405*de1e4e89SAndroid Build Coastguard Worker 		if (n->nlmsg_type != RTM_GETACTION)
406*de1e4e89SAndroid Build Coastguard Worker 			fprintf(stderr, "print_action: NULL kind\n");
407*de1e4e89SAndroid Build Coastguard Worker 		return -1;
408*de1e4e89SAndroid Build Coastguard Worker 	}
409*de1e4e89SAndroid Build Coastguard Worker 
410*de1e4e89SAndroid Build Coastguard Worker 	if (n->nlmsg_type == RTM_DELACTION) {
411*de1e4e89SAndroid Build Coastguard Worker 		if (n->nlmsg_flags & NLM_F_ROOT) {
412*de1e4e89SAndroid Build Coastguard Worker 			fprintf(fp, "Flushed table ");
413*de1e4e89SAndroid Build Coastguard Worker 			tab_flush = 1;
414*de1e4e89SAndroid Build Coastguard Worker 		} else {
415*de1e4e89SAndroid Build Coastguard Worker 			fprintf(fp, "Deleted action ");
416*de1e4e89SAndroid Build Coastguard Worker 		}
417*de1e4e89SAndroid Build Coastguard Worker 	}
418*de1e4e89SAndroid Build Coastguard Worker 
419*de1e4e89SAndroid Build Coastguard Worker 	if (n->nlmsg_type == RTM_NEWACTION) {
420*de1e4e89SAndroid Build Coastguard Worker 		if ((n->nlmsg_flags & NLM_F_CREATE) &&
421*de1e4e89SAndroid Build Coastguard Worker 		    !(n->nlmsg_flags & NLM_F_REPLACE)) {
422*de1e4e89SAndroid Build Coastguard Worker 			fprintf(fp, "Added action ");
423*de1e4e89SAndroid Build Coastguard Worker 		} else if (n->nlmsg_flags & NLM_F_REPLACE) {
424*de1e4e89SAndroid Build Coastguard Worker 			fprintf(fp, "Replaced action ");
425*de1e4e89SAndroid Build Coastguard Worker 		}
426*de1e4e89SAndroid Build Coastguard Worker 	}
427*de1e4e89SAndroid Build Coastguard Worker 
428*de1e4e89SAndroid Build Coastguard Worker 
429*de1e4e89SAndroid Build Coastguard Worker 	tc_print_action(fp, tb[TCA_ACT_TAB], tot_acts ? *tot_acts:0);
430*de1e4e89SAndroid Build Coastguard Worker 
431*de1e4e89SAndroid Build Coastguard Worker 	return 0;
432*de1e4e89SAndroid Build Coastguard Worker }
433*de1e4e89SAndroid Build Coastguard Worker 
tc_action_gd(int cmd,unsigned int flags,int * argc_p,char *** argv_p)434*de1e4e89SAndroid Build Coastguard Worker static int tc_action_gd(int cmd, unsigned int flags, int *argc_p, char ***argv_p)
435*de1e4e89SAndroid Build Coastguard Worker {
436*de1e4e89SAndroid Build Coastguard Worker 	char k[16];
437*de1e4e89SAndroid Build Coastguard Worker 	struct action_util *a = NULL;
438*de1e4e89SAndroid Build Coastguard Worker 	int argc = *argc_p;
439*de1e4e89SAndroid Build Coastguard Worker 	char **argv = *argv_p;
440*de1e4e89SAndroid Build Coastguard Worker 	int prio = 0;
441*de1e4e89SAndroid Build Coastguard Worker 	int ret = 0;
442*de1e4e89SAndroid Build Coastguard Worker 	__u32 i = 0;
443*de1e4e89SAndroid Build Coastguard Worker 	struct rtattr *tail;
444*de1e4e89SAndroid Build Coastguard Worker 	struct rtattr *tail2;
445*de1e4e89SAndroid Build Coastguard Worker 	struct nlmsghdr *ans = NULL;
446*de1e4e89SAndroid Build Coastguard Worker 
447*de1e4e89SAndroid Build Coastguard Worker 	struct {
448*de1e4e89SAndroid Build Coastguard Worker 		struct nlmsghdr         n;
449*de1e4e89SAndroid Build Coastguard Worker 		struct tcamsg           t;
450*de1e4e89SAndroid Build Coastguard Worker 		char                    buf[MAX_MSG];
451*de1e4e89SAndroid Build Coastguard Worker 	} req = {
452*de1e4e89SAndroid Build Coastguard Worker 		.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg)),
453*de1e4e89SAndroid Build Coastguard Worker 		.n.nlmsg_flags = NLM_F_REQUEST | flags,
454*de1e4e89SAndroid Build Coastguard Worker 		.n.nlmsg_type = cmd,
455*de1e4e89SAndroid Build Coastguard Worker 		.t.tca_family = AF_UNSPEC,
456*de1e4e89SAndroid Build Coastguard Worker 	};
457*de1e4e89SAndroid Build Coastguard Worker 
458*de1e4e89SAndroid Build Coastguard Worker 	argc -= 1;
459*de1e4e89SAndroid Build Coastguard Worker 	argv += 1;
460*de1e4e89SAndroid Build Coastguard Worker 
461*de1e4e89SAndroid Build Coastguard Worker 
462*de1e4e89SAndroid Build Coastguard Worker 	tail = NLMSG_TAIL(&req.n);
463*de1e4e89SAndroid Build Coastguard Worker 	addattr_l(&req.n, MAX_MSG, TCA_ACT_TAB, NULL, 0);
464*de1e4e89SAndroid Build Coastguard Worker 
465*de1e4e89SAndroid Build Coastguard Worker 	while (argc > 0) {
466*de1e4e89SAndroid Build Coastguard Worker 		if (strcmp(*argv, "action") == 0) {
467*de1e4e89SAndroid Build Coastguard Worker 			argc--;
468*de1e4e89SAndroid Build Coastguard Worker 			argv++;
469*de1e4e89SAndroid Build Coastguard Worker 			continue;
470*de1e4e89SAndroid Build Coastguard Worker 		} else if (strcmp(*argv, "help") == 0) {
471*de1e4e89SAndroid Build Coastguard Worker 			return -1;
472*de1e4e89SAndroid Build Coastguard Worker 		}
473*de1e4e89SAndroid Build Coastguard Worker 
474*de1e4e89SAndroid Build Coastguard Worker 		strncpy(k, *argv, sizeof(k) - 1);
475*de1e4e89SAndroid Build Coastguard Worker 		a = get_action_kind(k);
476*de1e4e89SAndroid Build Coastguard Worker 		if (a == NULL) {
477*de1e4e89SAndroid Build Coastguard Worker 			fprintf(stderr, "Error: non existent action: %s\n", k);
478*de1e4e89SAndroid Build Coastguard Worker 			ret = -1;
479*de1e4e89SAndroid Build Coastguard Worker 			goto bad_val;
480*de1e4e89SAndroid Build Coastguard Worker 		}
481*de1e4e89SAndroid Build Coastguard Worker 		if (strcmp(a->id, k) != 0) {
482*de1e4e89SAndroid Build Coastguard Worker 			fprintf(stderr, "Error: non existent action: %s\n", k);
483*de1e4e89SAndroid Build Coastguard Worker 			ret = -1;
484*de1e4e89SAndroid Build Coastguard Worker 			goto bad_val;
485*de1e4e89SAndroid Build Coastguard Worker 		}
486*de1e4e89SAndroid Build Coastguard Worker 
487*de1e4e89SAndroid Build Coastguard Worker 		argc -= 1;
488*de1e4e89SAndroid Build Coastguard Worker 		argv += 1;
489*de1e4e89SAndroid Build Coastguard Worker 		if (argc <= 0) {
490*de1e4e89SAndroid Build Coastguard Worker 			fprintf(stderr, "Error: no index specified action: %s\n", k);
491*de1e4e89SAndroid Build Coastguard Worker 			ret = -1;
492*de1e4e89SAndroid Build Coastguard Worker 			goto bad_val;
493*de1e4e89SAndroid Build Coastguard Worker 		}
494*de1e4e89SAndroid Build Coastguard Worker 
495*de1e4e89SAndroid Build Coastguard Worker 		if (matches(*argv, "index") == 0) {
496*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
497*de1e4e89SAndroid Build Coastguard Worker 			if (get_u32(&i, *argv, 10)) {
498*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "Illegal \"index\"\n");
499*de1e4e89SAndroid Build Coastguard Worker 				ret = -1;
500*de1e4e89SAndroid Build Coastguard Worker 				goto bad_val;
501*de1e4e89SAndroid Build Coastguard Worker 			}
502*de1e4e89SAndroid Build Coastguard Worker 			argc -= 1;
503*de1e4e89SAndroid Build Coastguard Worker 			argv += 1;
504*de1e4e89SAndroid Build Coastguard Worker 		} else {
505*de1e4e89SAndroid Build Coastguard Worker 			fprintf(stderr, "Error: no index specified action: %s\n", k);
506*de1e4e89SAndroid Build Coastguard Worker 			ret = -1;
507*de1e4e89SAndroid Build Coastguard Worker 			goto bad_val;
508*de1e4e89SAndroid Build Coastguard Worker 		}
509*de1e4e89SAndroid Build Coastguard Worker 
510*de1e4e89SAndroid Build Coastguard Worker 		tail2 = NLMSG_TAIL(&req.n);
511*de1e4e89SAndroid Build Coastguard Worker 		addattr_l(&req.n, MAX_MSG, ++prio, NULL, 0);
512*de1e4e89SAndroid Build Coastguard Worker 		addattr_l(&req.n, MAX_MSG, TCA_ACT_KIND, k, strlen(k) + 1);
513*de1e4e89SAndroid Build Coastguard Worker 		if (i > 0)
514*de1e4e89SAndroid Build Coastguard Worker 			addattr32(&req.n, MAX_MSG, TCA_ACT_INDEX, i);
515*de1e4e89SAndroid Build Coastguard Worker 		tail2->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail2;
516*de1e4e89SAndroid Build Coastguard Worker 
517*de1e4e89SAndroid Build Coastguard Worker 	}
518*de1e4e89SAndroid Build Coastguard Worker 
519*de1e4e89SAndroid Build Coastguard Worker 	tail->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail;
520*de1e4e89SAndroid Build Coastguard Worker 
521*de1e4e89SAndroid Build Coastguard Worker 	req.n.nlmsg_seq = rth.dump = ++rth.seq;
522*de1e4e89SAndroid Build Coastguard Worker 	if (cmd == RTM_GETACTION)
523*de1e4e89SAndroid Build Coastguard Worker 		ans = &req.n;
524*de1e4e89SAndroid Build Coastguard Worker 
525*de1e4e89SAndroid Build Coastguard Worker 	if (rtnl_talk(&rth, &req.n, ans, MAX_MSG) < 0) {
526*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "We have an error talking to the kernel\n");
527*de1e4e89SAndroid Build Coastguard Worker 		return 1;
528*de1e4e89SAndroid Build Coastguard Worker 	}
529*de1e4e89SAndroid Build Coastguard Worker 
530*de1e4e89SAndroid Build Coastguard Worker 	if (ans && print_action(NULL, &req.n, (void *)stdout) < 0) {
531*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "Dump terminated\n");
532*de1e4e89SAndroid Build Coastguard Worker 		return 1;
533*de1e4e89SAndroid Build Coastguard Worker 	}
534*de1e4e89SAndroid Build Coastguard Worker 
535*de1e4e89SAndroid Build Coastguard Worker 	*argc_p = argc;
536*de1e4e89SAndroid Build Coastguard Worker 	*argv_p = argv;
537*de1e4e89SAndroid Build Coastguard Worker bad_val:
538*de1e4e89SAndroid Build Coastguard Worker 	return ret;
539*de1e4e89SAndroid Build Coastguard Worker }
540*de1e4e89SAndroid Build Coastguard Worker 
tc_action_modify(int cmd,unsigned int flags,int * argc_p,char *** argv_p)541*de1e4e89SAndroid Build Coastguard Worker static int tc_action_modify(int cmd, unsigned int flags, int *argc_p, char ***argv_p)
542*de1e4e89SAndroid Build Coastguard Worker {
543*de1e4e89SAndroid Build Coastguard Worker 	int argc = *argc_p;
544*de1e4e89SAndroid Build Coastguard Worker 	char **argv = *argv_p;
545*de1e4e89SAndroid Build Coastguard Worker 	int ret = 0;
546*de1e4e89SAndroid Build Coastguard Worker 	struct {
547*de1e4e89SAndroid Build Coastguard Worker 		struct nlmsghdr         n;
548*de1e4e89SAndroid Build Coastguard Worker 		struct tcamsg           t;
549*de1e4e89SAndroid Build Coastguard Worker 		char                    buf[MAX_MSG];
550*de1e4e89SAndroid Build Coastguard Worker 	} req = {
551*de1e4e89SAndroid Build Coastguard Worker 		.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg)),
552*de1e4e89SAndroid Build Coastguard Worker 		.n.nlmsg_flags = NLM_F_REQUEST | flags,
553*de1e4e89SAndroid Build Coastguard Worker 		.n.nlmsg_type = cmd,
554*de1e4e89SAndroid Build Coastguard Worker 		.t.tca_family = AF_UNSPEC,
555*de1e4e89SAndroid Build Coastguard Worker 	};
556*de1e4e89SAndroid Build Coastguard Worker 	struct rtattr *tail = NLMSG_TAIL(&req.n);
557*de1e4e89SAndroid Build Coastguard Worker 
558*de1e4e89SAndroid Build Coastguard Worker 	argc -= 1;
559*de1e4e89SAndroid Build Coastguard Worker 	argv += 1;
560*de1e4e89SAndroid Build Coastguard Worker 	if (parse_action(&argc, &argv, TCA_ACT_TAB, &req.n)) {
561*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "Illegal \"action\"\n");
562*de1e4e89SAndroid Build Coastguard Worker 		return -1;
563*de1e4e89SAndroid Build Coastguard Worker 	}
564*de1e4e89SAndroid Build Coastguard Worker 	tail->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail;
565*de1e4e89SAndroid Build Coastguard Worker 
566*de1e4e89SAndroid Build Coastguard Worker 	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0) {
567*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "We have an error talking to the kernel\n");
568*de1e4e89SAndroid Build Coastguard Worker 		ret = -1;
569*de1e4e89SAndroid Build Coastguard Worker 	}
570*de1e4e89SAndroid Build Coastguard Worker 
571*de1e4e89SAndroid Build Coastguard Worker 	*argc_p = argc;
572*de1e4e89SAndroid Build Coastguard Worker 	*argv_p = argv;
573*de1e4e89SAndroid Build Coastguard Worker 
574*de1e4e89SAndroid Build Coastguard Worker 	return ret;
575*de1e4e89SAndroid Build Coastguard Worker }
576*de1e4e89SAndroid Build Coastguard Worker 
tc_act_list_or_flush(int * argc_p,char *** argv_p,int event)577*de1e4e89SAndroid Build Coastguard Worker static int tc_act_list_or_flush(int *argc_p, char ***argv_p, int event)
578*de1e4e89SAndroid Build Coastguard Worker {
579*de1e4e89SAndroid Build Coastguard Worker 	struct rtattr *tail, *tail2, *tail3, *tail4;
580*de1e4e89SAndroid Build Coastguard Worker 	int ret = 0, prio = 0, msg_size = 0;
581*de1e4e89SAndroid Build Coastguard Worker 	struct action_util *a = NULL;
582*de1e4e89SAndroid Build Coastguard Worker 	struct nla_bitfield32 flag_select = { 0 };
583*de1e4e89SAndroid Build Coastguard Worker 	char **argv = *argv_p;
584*de1e4e89SAndroid Build Coastguard Worker 	__u32 msec_since = 0;
585*de1e4e89SAndroid Build Coastguard Worker 	int argc = *argc_p;
586*de1e4e89SAndroid Build Coastguard Worker 	char k[16];
587*de1e4e89SAndroid Build Coastguard Worker 	struct {
588*de1e4e89SAndroid Build Coastguard Worker 		struct nlmsghdr         n;
589*de1e4e89SAndroid Build Coastguard Worker 		struct tcamsg           t;
590*de1e4e89SAndroid Build Coastguard Worker 		char                    buf[MAX_MSG];
591*de1e4e89SAndroid Build Coastguard Worker 	} req = {
592*de1e4e89SAndroid Build Coastguard Worker 		.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg)),
593*de1e4e89SAndroid Build Coastguard Worker 		.t.tca_family = AF_UNSPEC,
594*de1e4e89SAndroid Build Coastguard Worker 	};
595*de1e4e89SAndroid Build Coastguard Worker 
596*de1e4e89SAndroid Build Coastguard Worker 	tail = NLMSG_TAIL(&req.n);
597*de1e4e89SAndroid Build Coastguard Worker 	addattr_l(&req.n, MAX_MSG, TCA_ACT_TAB, NULL, 0);
598*de1e4e89SAndroid Build Coastguard Worker 	tail2 = NLMSG_TAIL(&req.n);
599*de1e4e89SAndroid Build Coastguard Worker 
600*de1e4e89SAndroid Build Coastguard Worker 	strncpy(k, *argv, sizeof(k) - 1);
601*de1e4e89SAndroid Build Coastguard Worker #ifdef CONFIG_GACT
602*de1e4e89SAndroid Build Coastguard Worker 	if (!gact_ld) {
603*de1e4e89SAndroid Build Coastguard Worker 		get_action_kind("gact");
604*de1e4e89SAndroid Build Coastguard Worker 	}
605*de1e4e89SAndroid Build Coastguard Worker #endif
606*de1e4e89SAndroid Build Coastguard Worker 	a = get_action_kind(k);
607*de1e4e89SAndroid Build Coastguard Worker 	if (a == NULL) {
608*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "bad action %s\n", k);
609*de1e4e89SAndroid Build Coastguard Worker 		goto bad_val;
610*de1e4e89SAndroid Build Coastguard Worker 	}
611*de1e4e89SAndroid Build Coastguard Worker 	if (strcmp(a->id, k) != 0) {
612*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "bad action %s\n", k);
613*de1e4e89SAndroid Build Coastguard Worker 		goto bad_val;
614*de1e4e89SAndroid Build Coastguard Worker 	}
615*de1e4e89SAndroid Build Coastguard Worker 	strncpy(k, *argv, sizeof(k) - 1);
616*de1e4e89SAndroid Build Coastguard Worker 
617*de1e4e89SAndroid Build Coastguard Worker 	argc -= 1;
618*de1e4e89SAndroid Build Coastguard Worker 	argv += 1;
619*de1e4e89SAndroid Build Coastguard Worker 
620*de1e4e89SAndroid Build Coastguard Worker 	if (argc && (strcmp(*argv, "since") == 0)) {
621*de1e4e89SAndroid Build Coastguard Worker 		NEXT_ARG();
622*de1e4e89SAndroid Build Coastguard Worker 		if (get_u32(&msec_since, *argv, 0))
623*de1e4e89SAndroid Build Coastguard Worker 			invarg("dump time \"since\" is invalid", *argv);
624*de1e4e89SAndroid Build Coastguard Worker 	}
625*de1e4e89SAndroid Build Coastguard Worker 
626*de1e4e89SAndroid Build Coastguard Worker 	addattr_l(&req.n, MAX_MSG, ++prio, NULL, 0);
627*de1e4e89SAndroid Build Coastguard Worker 	addattr_l(&req.n, MAX_MSG, TCA_ACT_KIND, k, strlen(k) + 1);
628*de1e4e89SAndroid Build Coastguard Worker 	tail2->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail2;
629*de1e4e89SAndroid Build Coastguard Worker 	tail->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail;
630*de1e4e89SAndroid Build Coastguard Worker 
631*de1e4e89SAndroid Build Coastguard Worker 	tail3 = NLMSG_TAIL(&req.n);
632*de1e4e89SAndroid Build Coastguard Worker 	flag_select.value |= TCA_FLAG_LARGE_DUMP_ON;
633*de1e4e89SAndroid Build Coastguard Worker 	flag_select.selector |= TCA_FLAG_LARGE_DUMP_ON;
634*de1e4e89SAndroid Build Coastguard Worker 	addattr_l(&req.n, MAX_MSG, TCA_ROOT_FLAGS, &flag_select,
635*de1e4e89SAndroid Build Coastguard Worker 		  sizeof(struct nla_bitfield32));
636*de1e4e89SAndroid Build Coastguard Worker 	tail3->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail3;
637*de1e4e89SAndroid Build Coastguard Worker 	if (msec_since) {
638*de1e4e89SAndroid Build Coastguard Worker 		tail4 = NLMSG_TAIL(&req.n);
639*de1e4e89SAndroid Build Coastguard Worker 		addattr32(&req.n, MAX_MSG, TCA_ROOT_TIME_DELTA, msec_since);
640*de1e4e89SAndroid Build Coastguard Worker 		tail4->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail4;
641*de1e4e89SAndroid Build Coastguard Worker 	}
642*de1e4e89SAndroid Build Coastguard Worker 	msg_size = NLMSG_ALIGN(req.n.nlmsg_len) - NLMSG_ALIGN(sizeof(struct nlmsghdr));
643*de1e4e89SAndroid Build Coastguard Worker 
644*de1e4e89SAndroid Build Coastguard Worker 	if (event == RTM_GETACTION) {
645*de1e4e89SAndroid Build Coastguard Worker 		if (rtnl_dump_request(&rth, event, (void *)&req.t, msg_size) < 0) {
646*de1e4e89SAndroid Build Coastguard Worker 			perror("Cannot send dump request");
647*de1e4e89SAndroid Build Coastguard Worker 			return 1;
648*de1e4e89SAndroid Build Coastguard Worker 		}
649*de1e4e89SAndroid Build Coastguard Worker 		ret = rtnl_dump_filter(&rth, print_action, stdout);
650*de1e4e89SAndroid Build Coastguard Worker 	}
651*de1e4e89SAndroid Build Coastguard Worker 
652*de1e4e89SAndroid Build Coastguard Worker 	if (event == RTM_DELACTION) {
653*de1e4e89SAndroid Build Coastguard Worker 		req.n.nlmsg_len = NLMSG_ALIGN(req.n.nlmsg_len);
654*de1e4e89SAndroid Build Coastguard Worker 		req.n.nlmsg_type = RTM_DELACTION;
655*de1e4e89SAndroid Build Coastguard Worker 		req.n.nlmsg_flags |= NLM_F_ROOT;
656*de1e4e89SAndroid Build Coastguard Worker 		req.n.nlmsg_flags |= NLM_F_REQUEST;
657*de1e4e89SAndroid Build Coastguard Worker 		if (rtnl_talk(&rth, &req.n, NULL, 0) < 0) {
658*de1e4e89SAndroid Build Coastguard Worker 			fprintf(stderr, "We have an error flushing\n");
659*de1e4e89SAndroid Build Coastguard Worker 			return 1;
660*de1e4e89SAndroid Build Coastguard Worker 		}
661*de1e4e89SAndroid Build Coastguard Worker 
662*de1e4e89SAndroid Build Coastguard Worker 	}
663*de1e4e89SAndroid Build Coastguard Worker 
664*de1e4e89SAndroid Build Coastguard Worker bad_val:
665*de1e4e89SAndroid Build Coastguard Worker 
666*de1e4e89SAndroid Build Coastguard Worker 	*argc_p = argc;
667*de1e4e89SAndroid Build Coastguard Worker 	*argv_p = argv;
668*de1e4e89SAndroid Build Coastguard Worker 	return ret;
669*de1e4e89SAndroid Build Coastguard Worker }
670*de1e4e89SAndroid Build Coastguard Worker 
do_action(int argc,char ** argv)671*de1e4e89SAndroid Build Coastguard Worker int do_action(int argc, char **argv)
672*de1e4e89SAndroid Build Coastguard Worker {
673*de1e4e89SAndroid Build Coastguard Worker 
674*de1e4e89SAndroid Build Coastguard Worker 	int ret = 0;
675*de1e4e89SAndroid Build Coastguard Worker 
676*de1e4e89SAndroid Build Coastguard Worker 	while (argc > 0) {
677*de1e4e89SAndroid Build Coastguard Worker 
678*de1e4e89SAndroid Build Coastguard Worker 		if (matches(*argv, "add") == 0) {
679*de1e4e89SAndroid Build Coastguard Worker 			ret =  tc_action_modify(RTM_NEWACTION, NLM_F_EXCL|NLM_F_CREATE, &argc, &argv);
680*de1e4e89SAndroid Build Coastguard Worker 		} else if (matches(*argv, "change") == 0 ||
681*de1e4e89SAndroid Build Coastguard Worker 			  matches(*argv, "replace") == 0) {
682*de1e4e89SAndroid Build Coastguard Worker 			ret = tc_action_modify(RTM_NEWACTION, NLM_F_CREATE|NLM_F_REPLACE, &argc, &argv);
683*de1e4e89SAndroid Build Coastguard Worker 		} else if (matches(*argv, "delete") == 0) {
684*de1e4e89SAndroid Build Coastguard Worker 			argc -= 1;
685*de1e4e89SAndroid Build Coastguard Worker 			argv += 1;
686*de1e4e89SAndroid Build Coastguard Worker 			ret = tc_action_gd(RTM_DELACTION, 0,  &argc, &argv);
687*de1e4e89SAndroid Build Coastguard Worker 		} else if (matches(*argv, "get") == 0) {
688*de1e4e89SAndroid Build Coastguard Worker 			argc -= 1;
689*de1e4e89SAndroid Build Coastguard Worker 			argv += 1;
690*de1e4e89SAndroid Build Coastguard Worker 			ret = tc_action_gd(RTM_GETACTION, 0,  &argc, &argv);
691*de1e4e89SAndroid Build Coastguard Worker 		} else if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
692*de1e4e89SAndroid Build Coastguard Worker 						|| matches(*argv, "lst") == 0) {
693*de1e4e89SAndroid Build Coastguard Worker 			if (argc <= 2) {
694*de1e4e89SAndroid Build Coastguard Worker 				act_usage();
695*de1e4e89SAndroid Build Coastguard Worker 				return -1;
696*de1e4e89SAndroid Build Coastguard Worker 			}
697*de1e4e89SAndroid Build Coastguard Worker 
698*de1e4e89SAndroid Build Coastguard Worker 			argc -= 2;
699*de1e4e89SAndroid Build Coastguard Worker 			argv += 2;
700*de1e4e89SAndroid Build Coastguard Worker 			return tc_act_list_or_flush(&argc, &argv,
701*de1e4e89SAndroid Build Coastguard Worker 						    RTM_GETACTION);
702*de1e4e89SAndroid Build Coastguard Worker 		} else if (matches(*argv, "flush") == 0) {
703*de1e4e89SAndroid Build Coastguard Worker 			if (argc <= 2) {
704*de1e4e89SAndroid Build Coastguard Worker 				act_usage();
705*de1e4e89SAndroid Build Coastguard Worker 				return -1;
706*de1e4e89SAndroid Build Coastguard Worker 			}
707*de1e4e89SAndroid Build Coastguard Worker 
708*de1e4e89SAndroid Build Coastguard Worker 			argc -= 2;
709*de1e4e89SAndroid Build Coastguard Worker 			argv += 2;
710*de1e4e89SAndroid Build Coastguard Worker 			return tc_act_list_or_flush(&argc, &argv,
711*de1e4e89SAndroid Build Coastguard Worker 						    RTM_DELACTION);
712*de1e4e89SAndroid Build Coastguard Worker 		} else if (matches(*argv, "help") == 0) {
713*de1e4e89SAndroid Build Coastguard Worker 			act_usage();
714*de1e4e89SAndroid Build Coastguard Worker 			return -1;
715*de1e4e89SAndroid Build Coastguard Worker 		} else {
716*de1e4e89SAndroid Build Coastguard Worker 			fprintf(stderr, "Command \"%s\" is unknown, try \"tc actions help\".\n", *argv);
717*de1e4e89SAndroid Build Coastguard Worker 			return -1;
718*de1e4e89SAndroid Build Coastguard Worker 		}
719*de1e4e89SAndroid Build Coastguard Worker 
720*de1e4e89SAndroid Build Coastguard Worker 		if (ret < 0)
721*de1e4e89SAndroid Build Coastguard Worker 			return -1;
722*de1e4e89SAndroid Build Coastguard Worker 	}
723*de1e4e89SAndroid Build Coastguard Worker 
724*de1e4e89SAndroid Build Coastguard Worker 	return 0;
725*de1e4e89SAndroid Build Coastguard Worker }
726