xref: /openwifi/user_space/sdrctl_src/sdrctl.c (revision 2ee67178825ee52f380c2f72b7135d15ddadca60)
1*2ee67178SXianjun Jiao /*
2*2ee67178SXianjun Jiao  * nl80211 userspace tool
3*2ee67178SXianjun Jiao  *
4*2ee67178SXianjun Jiao  * Copyright 2007, 2008	Johannes Berg <[email protected]>
5*2ee67178SXianjun Jiao  * Modified by Xianjun jiao. [email protected]; [email protected];
6*2ee67178SXianjun Jiao  */
7*2ee67178SXianjun Jiao 
8*2ee67178SXianjun Jiao #include <errno.h>
9*2ee67178SXianjun Jiao #include <stdio.h>
10*2ee67178SXianjun Jiao #include <string.h>
11*2ee67178SXianjun Jiao #include <net/if.h>
12*2ee67178SXianjun Jiao #include <sys/types.h>
13*2ee67178SXianjun Jiao #include <sys/stat.h>
14*2ee67178SXianjun Jiao #include <fcntl.h>
15*2ee67178SXianjun Jiao #include <unistd.h>
16*2ee67178SXianjun Jiao #include <stdbool.h>
17*2ee67178SXianjun Jiao 
18*2ee67178SXianjun Jiao #include <netlink/genl/genl.h>
19*2ee67178SXianjun Jiao #include <netlink/genl/family.h>
20*2ee67178SXianjun Jiao #include <netlink/genl/ctrl.h>
21*2ee67178SXianjun Jiao #include <netlink/msg.h>
22*2ee67178SXianjun Jiao #include <netlink/attr.h>
23*2ee67178SXianjun Jiao 
24*2ee67178SXianjun Jiao #include "nl80211.h"
25*2ee67178SXianjun Jiao #include "sdrctl.h"
26*2ee67178SXianjun Jiao 
27*2ee67178SXianjun Jiao /* libnl 1.x compatibility code */
28*2ee67178SXianjun Jiao #if !defined(CONFIG_LIBNL20) && !defined(CONFIG_LIBNL30)
29*2ee67178SXianjun Jiao static inline struct nl_handle *nl_socket_alloc(void)
30*2ee67178SXianjun Jiao {
31*2ee67178SXianjun Jiao 	return nl_handle_alloc();
32*2ee67178SXianjun Jiao }
33*2ee67178SXianjun Jiao 
34*2ee67178SXianjun Jiao static inline void nl_socket_free(struct nl_sock *h)
35*2ee67178SXianjun Jiao {
36*2ee67178SXianjun Jiao 	nl_handle_destroy(h);
37*2ee67178SXianjun Jiao }
38*2ee67178SXianjun Jiao 
39*2ee67178SXianjun Jiao static inline int nl_socket_set_buffer_size(struct nl_sock *sk,
40*2ee67178SXianjun Jiao 					    int rxbuf, int txbuf)
41*2ee67178SXianjun Jiao {
42*2ee67178SXianjun Jiao 	return nl_set_buffer_size(sk, rxbuf, txbuf);
43*2ee67178SXianjun Jiao }
44*2ee67178SXianjun Jiao #endif /* CONFIG_LIBNL20 && CONFIG_LIBNL30 */
45*2ee67178SXianjun Jiao 
46*2ee67178SXianjun Jiao int iw_debug = 0;
47*2ee67178SXianjun Jiao 
48*2ee67178SXianjun Jiao static int nl80211_init(struct nl80211_state *state)
49*2ee67178SXianjun Jiao {
50*2ee67178SXianjun Jiao 	int err;
51*2ee67178SXianjun Jiao 
52*2ee67178SXianjun Jiao 	state->nl_sock = nl_socket_alloc();
53*2ee67178SXianjun Jiao 	if (!state->nl_sock) {
54*2ee67178SXianjun Jiao 		fprintf(stderr, "Failed to allocate netlink socket.\n");
55*2ee67178SXianjun Jiao 		return -ENOMEM;
56*2ee67178SXianjun Jiao 	}
57*2ee67178SXianjun Jiao 
58*2ee67178SXianjun Jiao 	nl_socket_set_buffer_size(state->nl_sock, 8192, 8192);
59*2ee67178SXianjun Jiao 
60*2ee67178SXianjun Jiao 	if (genl_connect(state->nl_sock)) {
61*2ee67178SXianjun Jiao 		fprintf(stderr, "Failed to connect to generic netlink.\n");
62*2ee67178SXianjun Jiao 		err = -ENOLINK;
63*2ee67178SXianjun Jiao 		goto out_handle_destroy;
64*2ee67178SXianjun Jiao 	}
65*2ee67178SXianjun Jiao 
66*2ee67178SXianjun Jiao 	state->nl80211_id = genl_ctrl_resolve(state->nl_sock, "nl80211");
67*2ee67178SXianjun Jiao 	if (state->nl80211_id < 0) {
68*2ee67178SXianjun Jiao 		fprintf(stderr, "nl80211 not found.\n");
69*2ee67178SXianjun Jiao 		err = -ENOENT;
70*2ee67178SXianjun Jiao 		goto out_handle_destroy;
71*2ee67178SXianjun Jiao 	}
72*2ee67178SXianjun Jiao 
73*2ee67178SXianjun Jiao 	return 0;
74*2ee67178SXianjun Jiao 
75*2ee67178SXianjun Jiao  out_handle_destroy:
76*2ee67178SXianjun Jiao 	nl_socket_free(state->nl_sock);
77*2ee67178SXianjun Jiao 	return err;
78*2ee67178SXianjun Jiao }
79*2ee67178SXianjun Jiao 
80*2ee67178SXianjun Jiao static void nl80211_cleanup(struct nl80211_state *state)
81*2ee67178SXianjun Jiao {
82*2ee67178SXianjun Jiao 	nl_socket_free(state->nl_sock);
83*2ee67178SXianjun Jiao }
84*2ee67178SXianjun Jiao 
85*2ee67178SXianjun Jiao static int cmd_size;
86*2ee67178SXianjun Jiao 
87*2ee67178SXianjun Jiao extern struct cmd __start___cmd;
88*2ee67178SXianjun Jiao extern struct cmd __stop___cmd;
89*2ee67178SXianjun Jiao 
90*2ee67178SXianjun Jiao #define for_each_cmd(_cmd)					\
91*2ee67178SXianjun Jiao 	for (_cmd = &__start___cmd; _cmd < &__stop___cmd;		\
92*2ee67178SXianjun Jiao 	     _cmd = (const struct cmd *)((char *)_cmd + cmd_size))
93*2ee67178SXianjun Jiao 
94*2ee67178SXianjun Jiao 
95*2ee67178SXianjun Jiao static void __usage_cmd(const struct cmd *cmd, char *indent, bool full)
96*2ee67178SXianjun Jiao {
97*2ee67178SXianjun Jiao 	const char *start, *lend, *end;
98*2ee67178SXianjun Jiao 
99*2ee67178SXianjun Jiao 	printf("%s", indent);
100*2ee67178SXianjun Jiao 
101*2ee67178SXianjun Jiao 	switch (cmd->idby) {
102*2ee67178SXianjun Jiao 	case CIB_NONE:
103*2ee67178SXianjun Jiao 		break;
104*2ee67178SXianjun Jiao 	case CIB_PHY:
105*2ee67178SXianjun Jiao 		printf("phy <phyname> ");
106*2ee67178SXianjun Jiao 		break;
107*2ee67178SXianjun Jiao 	case CIB_NETDEV:
108*2ee67178SXianjun Jiao 		printf("dev <devname> ");
109*2ee67178SXianjun Jiao 		break;
110*2ee67178SXianjun Jiao 	case CIB_WDEV:
111*2ee67178SXianjun Jiao 		printf("wdev <idx> ");
112*2ee67178SXianjun Jiao 		break;
113*2ee67178SXianjun Jiao 	}
114*2ee67178SXianjun Jiao 	if (cmd->parent && cmd->parent->name)
115*2ee67178SXianjun Jiao 		printf("%s ", cmd->parent->name);
116*2ee67178SXianjun Jiao 	printf("%s", cmd->name);
117*2ee67178SXianjun Jiao 
118*2ee67178SXianjun Jiao 	if (cmd->args) {
119*2ee67178SXianjun Jiao 		/* print line by line */
120*2ee67178SXianjun Jiao 		start = cmd->args;
121*2ee67178SXianjun Jiao 		end = strchr(start, '\0');
122*2ee67178SXianjun Jiao 		printf(" ");
123*2ee67178SXianjun Jiao 		do {
124*2ee67178SXianjun Jiao 			lend = strchr(start, '\n');
125*2ee67178SXianjun Jiao 			if (!lend)
126*2ee67178SXianjun Jiao 				lend = end;
127*2ee67178SXianjun Jiao 			if (start != cmd->args) {
128*2ee67178SXianjun Jiao 				printf("\t");
129*2ee67178SXianjun Jiao 				switch (cmd->idby) {
130*2ee67178SXianjun Jiao 				case CIB_NONE:
131*2ee67178SXianjun Jiao 					break;
132*2ee67178SXianjun Jiao 				case CIB_PHY:
133*2ee67178SXianjun Jiao 					printf("phy <phyname> ");
134*2ee67178SXianjun Jiao 					break;
135*2ee67178SXianjun Jiao 				case CIB_NETDEV:
136*2ee67178SXianjun Jiao 					printf("dev <devname> ");
137*2ee67178SXianjun Jiao 					break;
138*2ee67178SXianjun Jiao 				case CIB_WDEV:
139*2ee67178SXianjun Jiao 					printf("wdev <idx> ");
140*2ee67178SXianjun Jiao 					break;
141*2ee67178SXianjun Jiao 				}
142*2ee67178SXianjun Jiao 				if (cmd->parent && cmd->parent->name)
143*2ee67178SXianjun Jiao 					printf("%s ", cmd->parent->name);
144*2ee67178SXianjun Jiao 				printf("%s ", cmd->name);
145*2ee67178SXianjun Jiao 			}
146*2ee67178SXianjun Jiao 			printf("%.*s\n", (int)(lend - start), start);
147*2ee67178SXianjun Jiao 			start = lend + 1;
148*2ee67178SXianjun Jiao 		} while (end != lend);
149*2ee67178SXianjun Jiao 	} else
150*2ee67178SXianjun Jiao 		printf("\n");
151*2ee67178SXianjun Jiao 
152*2ee67178SXianjun Jiao 	if (!full || !cmd->help)
153*2ee67178SXianjun Jiao 		return;
154*2ee67178SXianjun Jiao 
155*2ee67178SXianjun Jiao 	/* hack */
156*2ee67178SXianjun Jiao 	if (strlen(indent))
157*2ee67178SXianjun Jiao 		indent = "\t\t";
158*2ee67178SXianjun Jiao 	else
159*2ee67178SXianjun Jiao 		printf("\n");
160*2ee67178SXianjun Jiao 
161*2ee67178SXianjun Jiao 	/* print line by line */
162*2ee67178SXianjun Jiao 	start = cmd->help;
163*2ee67178SXianjun Jiao 	end = strchr(start, '\0');
164*2ee67178SXianjun Jiao 	do {
165*2ee67178SXianjun Jiao 		lend = strchr(start, '\n');
166*2ee67178SXianjun Jiao 		if (!lend)
167*2ee67178SXianjun Jiao 			lend = end;
168*2ee67178SXianjun Jiao 		printf("%s", indent);
169*2ee67178SXianjun Jiao 		printf("%.*s\n", (int)(lend - start), start);
170*2ee67178SXianjun Jiao 		start = lend + 1;
171*2ee67178SXianjun Jiao 	} while (end != lend);
172*2ee67178SXianjun Jiao 
173*2ee67178SXianjun Jiao 	printf("\n");
174*2ee67178SXianjun Jiao }
175*2ee67178SXianjun Jiao 
176*2ee67178SXianjun Jiao static void usage_options(void)
177*2ee67178SXianjun Jiao {
178*2ee67178SXianjun Jiao 	printf("Options:\n");
179*2ee67178SXianjun Jiao 	printf("\t--debug\t\tenable netlink debugging\n");
180*2ee67178SXianjun Jiao }
181*2ee67178SXianjun Jiao 
182*2ee67178SXianjun Jiao static const char *argv0;
183*2ee67178SXianjun Jiao 
184*2ee67178SXianjun Jiao static void usage(int argc, char **argv)
185*2ee67178SXianjun Jiao {
186*2ee67178SXianjun Jiao 	const struct cmd *section, *cmd;
187*2ee67178SXianjun Jiao 	bool full = argc >= 0;
188*2ee67178SXianjun Jiao 	const char *sect_filt = NULL;
189*2ee67178SXianjun Jiao 	const char *cmd_filt = NULL;
190*2ee67178SXianjun Jiao 
191*2ee67178SXianjun Jiao 	if (argc > 0)
192*2ee67178SXianjun Jiao 		sect_filt = argv[0];
193*2ee67178SXianjun Jiao 
194*2ee67178SXianjun Jiao 	if (argc > 1)
195*2ee67178SXianjun Jiao 		cmd_filt = argv[1];
196*2ee67178SXianjun Jiao 
197*2ee67178SXianjun Jiao 	printf("Usage:\t%s [options] command\n", argv0);
198*2ee67178SXianjun Jiao 	usage_options();
199*2ee67178SXianjun Jiao 	printf("\t--version\tshow version (%s)\n", sdrctl_version);
200*2ee67178SXianjun Jiao 	printf("Commands:\n");
201*2ee67178SXianjun Jiao 	for_each_cmd(section) {
202*2ee67178SXianjun Jiao 		if (section->parent)
203*2ee67178SXianjun Jiao 			continue;
204*2ee67178SXianjun Jiao 
205*2ee67178SXianjun Jiao 		if (sect_filt && strcmp(section->name, sect_filt))
206*2ee67178SXianjun Jiao 			continue;
207*2ee67178SXianjun Jiao 
208*2ee67178SXianjun Jiao 		if (section->handler && !section->hidden)
209*2ee67178SXianjun Jiao 			__usage_cmd(section, "\t", full);
210*2ee67178SXianjun Jiao 
211*2ee67178SXianjun Jiao 		for_each_cmd(cmd) {
212*2ee67178SXianjun Jiao 			if (section != cmd->parent)
213*2ee67178SXianjun Jiao 				continue;
214*2ee67178SXianjun Jiao 			if (!cmd->handler || cmd->hidden)
215*2ee67178SXianjun Jiao 				continue;
216*2ee67178SXianjun Jiao 			if (cmd_filt && strcmp(cmd->name, cmd_filt))
217*2ee67178SXianjun Jiao 				continue;
218*2ee67178SXianjun Jiao 			__usage_cmd(cmd, "\t", full);
219*2ee67178SXianjun Jiao 		}
220*2ee67178SXianjun Jiao 	}
221*2ee67178SXianjun Jiao 	printf("\nCommands that use the netdev ('dev') can also be given the\n"
222*2ee67178SXianjun Jiao 	       "'wdev' instead to identify the device.\n");
223*2ee67178SXianjun Jiao 	printf("\nYou can omit the 'phy' or 'dev' if "
224*2ee67178SXianjun Jiao 			"the identification is unique,\n"
225*2ee67178SXianjun Jiao 			"e.g. \"./sdrctl sdr0 get rssi_th\" or \"./sdrctl sdr0 get gap\". "
226*2ee67178SXianjun Jiao 			"(Don't when scripting.)\n\n"
227*2ee67178SXianjun Jiao 			"Do NOT screenscrape this tool, we don't "
228*2ee67178SXianjun Jiao 			"consider its output stable.\n\n");
229*2ee67178SXianjun Jiao }
230*2ee67178SXianjun Jiao 
231*2ee67178SXianjun Jiao static int print_help(struct nl80211_state *state,
232*2ee67178SXianjun Jiao 		      struct nl_cb *cb,
233*2ee67178SXianjun Jiao 		      struct nl_msg *msg,
234*2ee67178SXianjun Jiao 		      int argc, char **argv,
235*2ee67178SXianjun Jiao 		      enum id_input id)
236*2ee67178SXianjun Jiao {
237*2ee67178SXianjun Jiao 	exit(3);
238*2ee67178SXianjun Jiao }
239*2ee67178SXianjun Jiao TOPLEVEL(help, "[command]", 0, 0, CIB_NONE, print_help,
240*2ee67178SXianjun Jiao 	 "Print usage for all or a specific command, e.g.\n"
241*2ee67178SXianjun Jiao 	 "\"help wowlan\" or \"help wowlan enable\".");
242*2ee67178SXianjun Jiao 
243*2ee67178SXianjun Jiao static void usage_cmd(const struct cmd *cmd)
244*2ee67178SXianjun Jiao {
245*2ee67178SXianjun Jiao 	printf("Usage:\t%s [options] ", argv0);
246*2ee67178SXianjun Jiao 	__usage_cmd(cmd, "", true);
247*2ee67178SXianjun Jiao 	usage_options();
248*2ee67178SXianjun Jiao }
249*2ee67178SXianjun Jiao 
250*2ee67178SXianjun Jiao static void version(void)
251*2ee67178SXianjun Jiao {
252*2ee67178SXianjun Jiao 	printf("iw version %s\n", sdrctl_version);
253*2ee67178SXianjun Jiao }
254*2ee67178SXianjun Jiao 
255*2ee67178SXianjun Jiao static int phy_lookup(char *name)
256*2ee67178SXianjun Jiao {
257*2ee67178SXianjun Jiao 	char buf[200];
258*2ee67178SXianjun Jiao 	int fd, pos;
259*2ee67178SXianjun Jiao 
260*2ee67178SXianjun Jiao 	snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index", name);
261*2ee67178SXianjun Jiao 
262*2ee67178SXianjun Jiao 	fd = open(buf, O_RDONLY);
263*2ee67178SXianjun Jiao 	if (fd < 0)
264*2ee67178SXianjun Jiao 		return -1;
265*2ee67178SXianjun Jiao 	pos = read(fd, buf, sizeof(buf) - 1);
266*2ee67178SXianjun Jiao 	if (pos < 0) {
267*2ee67178SXianjun Jiao 		close(fd);
268*2ee67178SXianjun Jiao 		return -1;
269*2ee67178SXianjun Jiao 	}
270*2ee67178SXianjun Jiao 	buf[pos] = '\0';
271*2ee67178SXianjun Jiao 	close(fd);
272*2ee67178SXianjun Jiao 	return atoi(buf);
273*2ee67178SXianjun Jiao }
274*2ee67178SXianjun Jiao 
275*2ee67178SXianjun Jiao static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
276*2ee67178SXianjun Jiao 			 void *arg)
277*2ee67178SXianjun Jiao {
278*2ee67178SXianjun Jiao 	int *ret = arg;
279*2ee67178SXianjun Jiao 	*ret = err->error;
280*2ee67178SXianjun Jiao 	return NL_STOP;
281*2ee67178SXianjun Jiao }
282*2ee67178SXianjun Jiao 
283*2ee67178SXianjun Jiao static int finish_handler(struct nl_msg *msg, void *arg)
284*2ee67178SXianjun Jiao {
285*2ee67178SXianjun Jiao 	int *ret = arg;
286*2ee67178SXianjun Jiao 	*ret = 0;
287*2ee67178SXianjun Jiao 	return NL_SKIP;
288*2ee67178SXianjun Jiao }
289*2ee67178SXianjun Jiao 
290*2ee67178SXianjun Jiao static int ack_handler(struct nl_msg *msg, void *arg)
291*2ee67178SXianjun Jiao {
292*2ee67178SXianjun Jiao 	int *ret = arg;
293*2ee67178SXianjun Jiao 	*ret = 0;
294*2ee67178SXianjun Jiao 	return NL_STOP;
295*2ee67178SXianjun Jiao }
296*2ee67178SXianjun Jiao 
297*2ee67178SXianjun Jiao static int __handle_cmd(struct nl80211_state *state, enum id_input idby,
298*2ee67178SXianjun Jiao 			int argc, char **argv, const struct cmd **cmdout)
299*2ee67178SXianjun Jiao {
300*2ee67178SXianjun Jiao 	const struct cmd *cmd, *match = NULL, *sectcmd;
301*2ee67178SXianjun Jiao 	struct nl_cb *cb;
302*2ee67178SXianjun Jiao 	struct nl_cb *s_cb;
303*2ee67178SXianjun Jiao 	struct nl_msg *msg;
304*2ee67178SXianjun Jiao 	signed long long devidx = 0;
305*2ee67178SXianjun Jiao 	int err, o_argc;
306*2ee67178SXianjun Jiao 	const char *command, *section;
307*2ee67178SXianjun Jiao 	char *tmp, **o_argv;
308*2ee67178SXianjun Jiao 	enum command_identify_by command_idby = CIB_NONE;
309*2ee67178SXianjun Jiao 
310*2ee67178SXianjun Jiao 	if (argc <= 1 && idby != II_NONE)
311*2ee67178SXianjun Jiao 		return 1;
312*2ee67178SXianjun Jiao 
313*2ee67178SXianjun Jiao 	o_argc = argc;
314*2ee67178SXianjun Jiao 	o_argv = argv;
315*2ee67178SXianjun Jiao 
316*2ee67178SXianjun Jiao 	switch (idby) {
317*2ee67178SXianjun Jiao 	case II_PHY_IDX:
318*2ee67178SXianjun Jiao 		command_idby = CIB_PHY;
319*2ee67178SXianjun Jiao 		devidx = strtoul(*argv + 4, &tmp, 0);
320*2ee67178SXianjun Jiao 		if (*tmp != '\0')
321*2ee67178SXianjun Jiao 			return 1;
322*2ee67178SXianjun Jiao 		argc--;
323*2ee67178SXianjun Jiao 		argv++;
324*2ee67178SXianjun Jiao 		break;
325*2ee67178SXianjun Jiao 	case II_PHY_NAME:
326*2ee67178SXianjun Jiao 		command_idby = CIB_PHY;
327*2ee67178SXianjun Jiao 		devidx = phy_lookup(*argv);
328*2ee67178SXianjun Jiao 		argc--;
329*2ee67178SXianjun Jiao 		argv++;
330*2ee67178SXianjun Jiao 		break;
331*2ee67178SXianjun Jiao 	case II_NETDEV:
332*2ee67178SXianjun Jiao 		command_idby = CIB_NETDEV;
333*2ee67178SXianjun Jiao 		devidx = if_nametoindex(*argv);
334*2ee67178SXianjun Jiao 		if (devidx == 0)
335*2ee67178SXianjun Jiao 			devidx = -1;
336*2ee67178SXianjun Jiao 		argc--;
337*2ee67178SXianjun Jiao 		argv++;
338*2ee67178SXianjun Jiao 		break;
339*2ee67178SXianjun Jiao 	case II_WDEV:
340*2ee67178SXianjun Jiao 		command_idby = CIB_WDEV;
341*2ee67178SXianjun Jiao 		devidx = strtoll(*argv, &tmp, 0);
342*2ee67178SXianjun Jiao 		if (*tmp != '\0')
343*2ee67178SXianjun Jiao 			return 1;
344*2ee67178SXianjun Jiao 		argc--;
345*2ee67178SXianjun Jiao 		argv++;
346*2ee67178SXianjun Jiao 	default:
347*2ee67178SXianjun Jiao 		break;
348*2ee67178SXianjun Jiao 	}
349*2ee67178SXianjun Jiao 
350*2ee67178SXianjun Jiao 	if (devidx < 0)
351*2ee67178SXianjun Jiao 		return -errno;
352*2ee67178SXianjun Jiao 
353*2ee67178SXianjun Jiao 	section = *argv;
354*2ee67178SXianjun Jiao 	argc--;
355*2ee67178SXianjun Jiao 	argv++;
356*2ee67178SXianjun Jiao 
357*2ee67178SXianjun Jiao 	for_each_cmd(sectcmd) {
358*2ee67178SXianjun Jiao 		if (sectcmd->parent)
359*2ee67178SXianjun Jiao 			continue;
360*2ee67178SXianjun Jiao 		/* ok ... bit of a hack for the dupe 'info' section */
361*2ee67178SXianjun Jiao 		if (match && sectcmd->idby != command_idby)
362*2ee67178SXianjun Jiao 			continue;
363*2ee67178SXianjun Jiao 		if (strcmp(sectcmd->name, section) == 0)
364*2ee67178SXianjun Jiao 			match = sectcmd;
365*2ee67178SXianjun Jiao 	}
366*2ee67178SXianjun Jiao 
367*2ee67178SXianjun Jiao 	sectcmd = match;
368*2ee67178SXianjun Jiao 	match = NULL;
369*2ee67178SXianjun Jiao 	if (!sectcmd)
370*2ee67178SXianjun Jiao 		return 1;
371*2ee67178SXianjun Jiao 
372*2ee67178SXianjun Jiao 	if (argc > 0) {
373*2ee67178SXianjun Jiao 		command = *argv;
374*2ee67178SXianjun Jiao 
375*2ee67178SXianjun Jiao 		for_each_cmd(cmd) {
376*2ee67178SXianjun Jiao 			if (!cmd->handler)
377*2ee67178SXianjun Jiao 				continue;
378*2ee67178SXianjun Jiao 			if (cmd->parent != sectcmd)
379*2ee67178SXianjun Jiao 				continue;
380*2ee67178SXianjun Jiao 			/*
381*2ee67178SXianjun Jiao 			 * ignore mismatch id by, but allow WDEV
382*2ee67178SXianjun Jiao 			 * in place of NETDEV
383*2ee67178SXianjun Jiao 			 */
384*2ee67178SXianjun Jiao 			if (cmd->idby != command_idby &&
385*2ee67178SXianjun Jiao 			    !(cmd->idby == CIB_NETDEV &&
386*2ee67178SXianjun Jiao 			      command_idby == CIB_WDEV))
387*2ee67178SXianjun Jiao 				continue;
388*2ee67178SXianjun Jiao 			if (strcmp(cmd->name, command))
389*2ee67178SXianjun Jiao 				continue;
390*2ee67178SXianjun Jiao 			if (argc > 1 && !cmd->args)
391*2ee67178SXianjun Jiao 				continue;
392*2ee67178SXianjun Jiao 			match = cmd;
393*2ee67178SXianjun Jiao 			break;
394*2ee67178SXianjun Jiao 		}
395*2ee67178SXianjun Jiao 
396*2ee67178SXianjun Jiao 		if (match) {
397*2ee67178SXianjun Jiao 			argc--;
398*2ee67178SXianjun Jiao 			argv++;
399*2ee67178SXianjun Jiao 		}
400*2ee67178SXianjun Jiao 	}
401*2ee67178SXianjun Jiao 
402*2ee67178SXianjun Jiao 	if (match)
403*2ee67178SXianjun Jiao 		cmd = match;
404*2ee67178SXianjun Jiao 	else {
405*2ee67178SXianjun Jiao 		/* Use the section itself, if possible. */
406*2ee67178SXianjun Jiao 		cmd = sectcmd;
407*2ee67178SXianjun Jiao 		if (argc && !cmd->args)
408*2ee67178SXianjun Jiao 			return 1;
409*2ee67178SXianjun Jiao 		if (cmd->idby != command_idby &&
410*2ee67178SXianjun Jiao 		    !(cmd->idby == CIB_NETDEV && command_idby == CIB_WDEV))
411*2ee67178SXianjun Jiao 			return 1;
412*2ee67178SXianjun Jiao 		if (!cmd->handler)
413*2ee67178SXianjun Jiao 			return 1;
414*2ee67178SXianjun Jiao 	}
415*2ee67178SXianjun Jiao 
416*2ee67178SXianjun Jiao 	if (cmd->selector) {
417*2ee67178SXianjun Jiao 		cmd = cmd->selector(argc, argv);
418*2ee67178SXianjun Jiao 		if (!cmd)
419*2ee67178SXianjun Jiao 			return 1;
420*2ee67178SXianjun Jiao 	}
421*2ee67178SXianjun Jiao 
422*2ee67178SXianjun Jiao 	if (cmdout)
423*2ee67178SXianjun Jiao 		*cmdout = cmd;
424*2ee67178SXianjun Jiao 
425*2ee67178SXianjun Jiao 	if (!cmd->cmd) {
426*2ee67178SXianjun Jiao 		argc = o_argc;
427*2ee67178SXianjun Jiao 		argv = o_argv;
428*2ee67178SXianjun Jiao 		return cmd->handler(state, NULL, NULL, argc, argv, idby);
429*2ee67178SXianjun Jiao 	}
430*2ee67178SXianjun Jiao 
431*2ee67178SXianjun Jiao 	msg = nlmsg_alloc();
432*2ee67178SXianjun Jiao 	if (!msg) {
433*2ee67178SXianjun Jiao 		fprintf(stderr, "failed to allocate netlink message\n");
434*2ee67178SXianjun Jiao 		return 2;
435*2ee67178SXianjun Jiao 	}
436*2ee67178SXianjun Jiao 
437*2ee67178SXianjun Jiao 	cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
438*2ee67178SXianjun Jiao 	s_cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
439*2ee67178SXianjun Jiao 	if (!cb || !s_cb) {
440*2ee67178SXianjun Jiao 		fprintf(stderr, "failed to allocate netlink callbacks\n");
441*2ee67178SXianjun Jiao 		err = 2;
442*2ee67178SXianjun Jiao 		goto out_free_msg;
443*2ee67178SXianjun Jiao 	}
444*2ee67178SXianjun Jiao 
445*2ee67178SXianjun Jiao 	genlmsg_put(msg, 0, 0, state->nl80211_id, 0,
446*2ee67178SXianjun Jiao 		    cmd->nl_msg_flags, cmd->cmd, 0);
447*2ee67178SXianjun Jiao 
448*2ee67178SXianjun Jiao 	switch (command_idby) {
449*2ee67178SXianjun Jiao 	case CIB_PHY:
450*2ee67178SXianjun Jiao 		NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, devidx);
451*2ee67178SXianjun Jiao 		break;
452*2ee67178SXianjun Jiao 	case CIB_NETDEV:
453*2ee67178SXianjun Jiao 		NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
454*2ee67178SXianjun Jiao 		break;
455*2ee67178SXianjun Jiao 	case CIB_WDEV:
456*2ee67178SXianjun Jiao 		NLA_PUT_U64(msg, NL80211_ATTR_WDEV, devidx);
457*2ee67178SXianjun Jiao 		break;
458*2ee67178SXianjun Jiao 	default:
459*2ee67178SXianjun Jiao 		break;
460*2ee67178SXianjun Jiao 	}
461*2ee67178SXianjun Jiao 
462*2ee67178SXianjun Jiao 	err = cmd->handler(state, cb, msg, argc, argv, idby);
463*2ee67178SXianjun Jiao 	if (err)
464*2ee67178SXianjun Jiao 		goto out;
465*2ee67178SXianjun Jiao 
466*2ee67178SXianjun Jiao 	nl_socket_set_cb(state->nl_sock, s_cb);
467*2ee67178SXianjun Jiao 
468*2ee67178SXianjun Jiao 	err = nl_send_auto_complete(state->nl_sock, msg);
469*2ee67178SXianjun Jiao 	if (err < 0)
470*2ee67178SXianjun Jiao 		goto out;
471*2ee67178SXianjun Jiao 
472*2ee67178SXianjun Jiao 	err = 1;
473*2ee67178SXianjun Jiao 
474*2ee67178SXianjun Jiao 	nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
475*2ee67178SXianjun Jiao 	nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
476*2ee67178SXianjun Jiao 	nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
477*2ee67178SXianjun Jiao 
478*2ee67178SXianjun Jiao 	while (err > 0)
479*2ee67178SXianjun Jiao 		nl_recvmsgs(state->nl_sock, cb);
480*2ee67178SXianjun Jiao  out:
481*2ee67178SXianjun Jiao 	nl_cb_put(cb);
482*2ee67178SXianjun Jiao  out_free_msg:
483*2ee67178SXianjun Jiao 	nlmsg_free(msg);
484*2ee67178SXianjun Jiao 	return err;
485*2ee67178SXianjun Jiao  nla_put_failure:
486*2ee67178SXianjun Jiao 	fprintf(stderr, "building message failed\n");
487*2ee67178SXianjun Jiao 	return 2;
488*2ee67178SXianjun Jiao }
489*2ee67178SXianjun Jiao 
490*2ee67178SXianjun Jiao int handle_cmd(struct nl80211_state *state, enum id_input idby,
491*2ee67178SXianjun Jiao 	       int argc, char **argv)
492*2ee67178SXianjun Jiao {
493*2ee67178SXianjun Jiao 	return __handle_cmd(state, idby, argc, argv, NULL);
494*2ee67178SXianjun Jiao }
495*2ee67178SXianjun Jiao 
496*2ee67178SXianjun Jiao int main(int argc, char **argv)
497*2ee67178SXianjun Jiao {
498*2ee67178SXianjun Jiao 	struct nl80211_state nlstate;
499*2ee67178SXianjun Jiao 	int err;
500*2ee67178SXianjun Jiao 	const struct cmd *cmd = NULL;
501*2ee67178SXianjun Jiao 
502*2ee67178SXianjun Jiao 	/* calculate command size including padding */
503*2ee67178SXianjun Jiao 	cmd_size = abs((long)&__section_set - (long)&__section_get);
504*2ee67178SXianjun Jiao 	/* strip off self */
505*2ee67178SXianjun Jiao 	argc--;
506*2ee67178SXianjun Jiao 	argv0 = *argv++;
507*2ee67178SXianjun Jiao 
508*2ee67178SXianjun Jiao 	if (argc > 0 && strcmp(*argv, "--debug") == 0) {
509*2ee67178SXianjun Jiao 		iw_debug = 1;
510*2ee67178SXianjun Jiao 		argc--;
511*2ee67178SXianjun Jiao 		argv++;
512*2ee67178SXianjun Jiao 	}
513*2ee67178SXianjun Jiao 
514*2ee67178SXianjun Jiao 	if (argc > 0 && strcmp(*argv, "--version") == 0) {
515*2ee67178SXianjun Jiao 		version();
516*2ee67178SXianjun Jiao 		return 0;
517*2ee67178SXianjun Jiao 	}
518*2ee67178SXianjun Jiao 
519*2ee67178SXianjun Jiao 	/* need to treat "help" command specially so it works w/o nl80211 */
520*2ee67178SXianjun Jiao 	if (argc == 0 || strcmp(*argv, "help") == 0) {
521*2ee67178SXianjun Jiao 		usage(argc - 1, argv + 1);
522*2ee67178SXianjun Jiao 		return 0;
523*2ee67178SXianjun Jiao 	}
524*2ee67178SXianjun Jiao 
525*2ee67178SXianjun Jiao 	err = nl80211_init(&nlstate);
526*2ee67178SXianjun Jiao 	if (err)
527*2ee67178SXianjun Jiao 		return 1;
528*2ee67178SXianjun Jiao 
529*2ee67178SXianjun Jiao 	if (strcmp(*argv, "dev") == 0 && argc > 1) {
530*2ee67178SXianjun Jiao 		argc--;
531*2ee67178SXianjun Jiao 		argv++;
532*2ee67178SXianjun Jiao 		err = __handle_cmd(&nlstate, II_NETDEV, argc, argv, &cmd);
533*2ee67178SXianjun Jiao 	} else if (strncmp(*argv, "phy", 3) == 0 && argc > 1) {
534*2ee67178SXianjun Jiao 		if (strlen(*argv) == 3) {
535*2ee67178SXianjun Jiao 			argc--;
536*2ee67178SXianjun Jiao 			argv++;
537*2ee67178SXianjun Jiao 			err = __handle_cmd(&nlstate, II_PHY_NAME, argc, argv, &cmd);
538*2ee67178SXianjun Jiao 		} else if (*(*argv + 3) == '#')
539*2ee67178SXianjun Jiao 			err = __handle_cmd(&nlstate, II_PHY_IDX, argc, argv, &cmd);
540*2ee67178SXianjun Jiao 		else
541*2ee67178SXianjun Jiao 			goto detect;
542*2ee67178SXianjun Jiao 	} else if (strcmp(*argv, "wdev") == 0 && argc > 1) {
543*2ee67178SXianjun Jiao 		argc--;
544*2ee67178SXianjun Jiao 		argv++;
545*2ee67178SXianjun Jiao 		err = __handle_cmd(&nlstate, II_WDEV, argc, argv, &cmd);
546*2ee67178SXianjun Jiao 	} else {
547*2ee67178SXianjun Jiao 		int idx;
548*2ee67178SXianjun Jiao 		enum id_input idby = II_NONE;
549*2ee67178SXianjun Jiao  detect:
550*2ee67178SXianjun Jiao 		if ((idx = if_nametoindex(argv[0])) != 0)
551*2ee67178SXianjun Jiao 			idby = II_NETDEV;
552*2ee67178SXianjun Jiao 		else if ((idx = phy_lookup(argv[0])) >= 0)
553*2ee67178SXianjun Jiao 			idby = II_PHY_NAME;
554*2ee67178SXianjun Jiao 		err = __handle_cmd(&nlstate, idby, argc, argv, &cmd);
555*2ee67178SXianjun Jiao 	}
556*2ee67178SXianjun Jiao 
557*2ee67178SXianjun Jiao 	if (err == 1) {
558*2ee67178SXianjun Jiao 		if (cmd)
559*2ee67178SXianjun Jiao 			usage_cmd(cmd);
560*2ee67178SXianjun Jiao 		else
561*2ee67178SXianjun Jiao 			usage(0, NULL);
562*2ee67178SXianjun Jiao 	} else if (err < 0)
563*2ee67178SXianjun Jiao 		fprintf(stderr, "command failed: %s (%d)\n", strerror(-err), err);
564*2ee67178SXianjun Jiao 
565*2ee67178SXianjun Jiao 	nl80211_cleanup(&nlstate);
566*2ee67178SXianjun Jiao 
567*2ee67178SXianjun Jiao 	return err;
568*2ee67178SXianjun Jiao }
569