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