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