Home | History | Annotate | Download | only in iw
      1 /*
      2  * nl80211 userspace tool
      3  *
      4  * Copyright 2007, 2008	Johannes Berg <johannes (at) 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)
     28 static inline struct nl_handle *nl_socket_alloc(void)
     29 {
     30 	return nl_handle_alloc();
     31 }
     32 
     33 static inline void nl_socket_free(struct nl_sock *h)
     34 {
     35 	nl_handle_destroy(h);
     36 }
     37 
     38 static 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 
     45 int iw_debug = 0;
     46 
     47 static 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 
     79 static void nl80211_cleanup(struct nl80211_state *state)
     80 {
     81 	nl_socket_free(state->nl_sock);
     82 }
     83 
     84 static int cmd_size;
     85 
     86 extern struct cmd __start___cmd;
     87 extern 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 
     94 static 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 
    175 static void usage_options(void)
    176 {
    177 	printf("Options:\n");
    178 	printf("\t--debug\t\tenable netlink debugging\n");
    179 }
    180 
    181 static const char *argv0;
    182 
    183 static 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 
    230 static 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 }
    238 TOPLEVEL(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 
    242 static 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 
    249 static void version(void)
    250 {
    251 	printf("iw version %s\n", iw_version);
    252 }
    253 
    254 static 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 
    274 static 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 
    282 static int finish_handler(struct nl_msg *msg, void *arg)
    283 {
    284 	int *ret = arg;
    285 	*ret = 0;
    286 	return NL_SKIP;
    287 }
    288 
    289 static int ack_handler(struct nl_msg *msg, void *arg)
    290 {
    291 	int *ret = arg;
    292 	*ret = 0;
    293 	return NL_STOP;
    294 }
    295 
    296 static 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 
    489 int 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 
    495 int 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