xref: /openwifi/user_space/sdrctl_src/sdrctl.c (revision d41937caf80967a83362193cc9518f570dda1f1a)
12ee67178SXianjun Jiao /*
22ee67178SXianjun Jiao  * nl80211 userspace tool
32ee67178SXianjun Jiao  *
4a6085186SLina Ceballos  * SPDX-FileCopyrightText: Copyright 2007, 2008 Johannes Berg <[email protected]>
5*d41937caSJiao Xianjun  * Modified by Xianjun jiao
6a6085186SLina Ceballos  * SPDX-License-Identifier: AGPL-3.0-or-later
72ee67178SXianjun Jiao  */
82ee67178SXianjun Jiao 
92ee67178SXianjun Jiao #include <errno.h>
102ee67178SXianjun Jiao #include <stdio.h>
112ee67178SXianjun Jiao #include <string.h>
122ee67178SXianjun Jiao #include <net/if.h>
132ee67178SXianjun Jiao #include <sys/types.h>
142ee67178SXianjun Jiao #include <sys/stat.h>
152ee67178SXianjun Jiao #include <fcntl.h>
162ee67178SXianjun Jiao #include <unistd.h>
172ee67178SXianjun Jiao #include <stdbool.h>
182ee67178SXianjun Jiao 
192ee67178SXianjun Jiao #include <netlink/genl/genl.h>
202ee67178SXianjun Jiao #include <netlink/genl/family.h>
212ee67178SXianjun Jiao #include <netlink/genl/ctrl.h>
222ee67178SXianjun Jiao #include <netlink/msg.h>
232ee67178SXianjun Jiao #include <netlink/attr.h>
242ee67178SXianjun Jiao 
252ee67178SXianjun Jiao #include "nl80211.h"
262ee67178SXianjun Jiao #include "sdrctl.h"
272ee67178SXianjun Jiao 
282ee67178SXianjun Jiao /* libnl 1.x compatibility code */
292ee67178SXianjun Jiao #if !defined(CONFIG_LIBNL20) && !defined(CONFIG_LIBNL30)
nl_socket_alloc(void)302ee67178SXianjun Jiao static inline struct nl_handle *nl_socket_alloc(void)
312ee67178SXianjun Jiao {
322ee67178SXianjun Jiao 	return nl_handle_alloc();
332ee67178SXianjun Jiao }
342ee67178SXianjun Jiao 
nl_socket_free(struct nl_sock * h)352ee67178SXianjun Jiao static inline void nl_socket_free(struct nl_sock *h)
362ee67178SXianjun Jiao {
372ee67178SXianjun Jiao 	nl_handle_destroy(h);
382ee67178SXianjun Jiao }
392ee67178SXianjun Jiao 
nl_socket_set_buffer_size(struct nl_sock * sk,int rxbuf,int txbuf)402ee67178SXianjun Jiao static inline int nl_socket_set_buffer_size(struct nl_sock *sk,
412ee67178SXianjun Jiao 					    int rxbuf, int txbuf)
422ee67178SXianjun Jiao {
432ee67178SXianjun Jiao 	return nl_set_buffer_size(sk, rxbuf, txbuf);
442ee67178SXianjun Jiao }
452ee67178SXianjun Jiao #endif /* CONFIG_LIBNL20 && CONFIG_LIBNL30 */
462ee67178SXianjun Jiao 
472ee67178SXianjun Jiao int iw_debug = 0;
482ee67178SXianjun Jiao 
nl80211_init(struct nl80211_state * state)492ee67178SXianjun Jiao static int nl80211_init(struct nl80211_state *state)
502ee67178SXianjun Jiao {
512ee67178SXianjun Jiao 	int err;
522ee67178SXianjun Jiao 
532ee67178SXianjun Jiao 	state->nl_sock = nl_socket_alloc();
542ee67178SXianjun Jiao 	if (!state->nl_sock) {
552ee67178SXianjun Jiao 		fprintf(stderr, "Failed to allocate netlink socket.\n");
562ee67178SXianjun Jiao 		return -ENOMEM;
572ee67178SXianjun Jiao 	}
582ee67178SXianjun Jiao 
592ee67178SXianjun Jiao 	nl_socket_set_buffer_size(state->nl_sock, 8192, 8192);
602ee67178SXianjun Jiao 
612ee67178SXianjun Jiao 	if (genl_connect(state->nl_sock)) {
622ee67178SXianjun Jiao 		fprintf(stderr, "Failed to connect to generic netlink.\n");
632ee67178SXianjun Jiao 		err = -ENOLINK;
642ee67178SXianjun Jiao 		goto out_handle_destroy;
652ee67178SXianjun Jiao 	}
662ee67178SXianjun Jiao 
672ee67178SXianjun Jiao 	state->nl80211_id = genl_ctrl_resolve(state->nl_sock, "nl80211");
682ee67178SXianjun Jiao 	if (state->nl80211_id < 0) {
692ee67178SXianjun Jiao 		fprintf(stderr, "nl80211 not found.\n");
702ee67178SXianjun Jiao 		err = -ENOENT;
712ee67178SXianjun Jiao 		goto out_handle_destroy;
722ee67178SXianjun Jiao 	}
732ee67178SXianjun Jiao 
742ee67178SXianjun Jiao 	return 0;
752ee67178SXianjun Jiao 
762ee67178SXianjun Jiao  out_handle_destroy:
772ee67178SXianjun Jiao 	nl_socket_free(state->nl_sock);
782ee67178SXianjun Jiao 	return err;
792ee67178SXianjun Jiao }
802ee67178SXianjun Jiao 
nl80211_cleanup(struct nl80211_state * state)812ee67178SXianjun Jiao static void nl80211_cleanup(struct nl80211_state *state)
822ee67178SXianjun Jiao {
832ee67178SXianjun Jiao 	nl_socket_free(state->nl_sock);
842ee67178SXianjun Jiao }
852ee67178SXianjun Jiao 
862ee67178SXianjun Jiao static int cmd_size;
872ee67178SXianjun Jiao 
882ee67178SXianjun Jiao extern struct cmd __start___cmd;
892ee67178SXianjun Jiao extern struct cmd __stop___cmd;
902ee67178SXianjun Jiao 
912ee67178SXianjun Jiao #define for_each_cmd(_cmd)					\
922ee67178SXianjun Jiao 	for (_cmd = &__start___cmd; _cmd < &__stop___cmd;		\
932ee67178SXianjun Jiao 	     _cmd = (const struct cmd *)((char *)_cmd + cmd_size))
942ee67178SXianjun Jiao 
952ee67178SXianjun Jiao 
__usage_cmd(const struct cmd * cmd,char * indent,bool full)962ee67178SXianjun Jiao static void __usage_cmd(const struct cmd *cmd, char *indent, bool full)
972ee67178SXianjun Jiao {
982ee67178SXianjun Jiao 	const char *start, *lend, *end;
992ee67178SXianjun Jiao 
1002ee67178SXianjun Jiao 	printf("%s", indent);
1012ee67178SXianjun Jiao 
1022ee67178SXianjun Jiao 	switch (cmd->idby) {
1032ee67178SXianjun Jiao 	case CIB_NONE:
1042ee67178SXianjun Jiao 		break;
1052ee67178SXianjun Jiao 	case CIB_PHY:
1062ee67178SXianjun Jiao 		printf("phy <phyname> ");
1072ee67178SXianjun Jiao 		break;
1082ee67178SXianjun Jiao 	case CIB_NETDEV:
1092ee67178SXianjun Jiao 		printf("dev <devname> ");
1102ee67178SXianjun Jiao 		break;
1112ee67178SXianjun Jiao 	case CIB_WDEV:
1122ee67178SXianjun Jiao 		printf("wdev <idx> ");
1132ee67178SXianjun Jiao 		break;
1142ee67178SXianjun Jiao 	}
1152ee67178SXianjun Jiao 	if (cmd->parent && cmd->parent->name)
1162ee67178SXianjun Jiao 		printf("%s ", cmd->parent->name);
1172ee67178SXianjun Jiao 	printf("%s", cmd->name);
1182ee67178SXianjun Jiao 
1192ee67178SXianjun Jiao 	if (cmd->args) {
1202ee67178SXianjun Jiao 		/* print line by line */
1212ee67178SXianjun Jiao 		start = cmd->args;
1222ee67178SXianjun Jiao 		end = strchr(start, '\0');
1232ee67178SXianjun Jiao 		printf(" ");
1242ee67178SXianjun Jiao 		do {
1252ee67178SXianjun Jiao 			lend = strchr(start, '\n');
1262ee67178SXianjun Jiao 			if (!lend)
1272ee67178SXianjun Jiao 				lend = end;
1282ee67178SXianjun Jiao 			if (start != cmd->args) {
1292ee67178SXianjun Jiao 				printf("\t");
1302ee67178SXianjun Jiao 				switch (cmd->idby) {
1312ee67178SXianjun Jiao 				case CIB_NONE:
1322ee67178SXianjun Jiao 					break;
1332ee67178SXianjun Jiao 				case CIB_PHY:
1342ee67178SXianjun Jiao 					printf("phy <phyname> ");
1352ee67178SXianjun Jiao 					break;
1362ee67178SXianjun Jiao 				case CIB_NETDEV:
1372ee67178SXianjun Jiao 					printf("dev <devname> ");
1382ee67178SXianjun Jiao 					break;
1392ee67178SXianjun Jiao 				case CIB_WDEV:
1402ee67178SXianjun Jiao 					printf("wdev <idx> ");
1412ee67178SXianjun Jiao 					break;
1422ee67178SXianjun Jiao 				}
1432ee67178SXianjun Jiao 				if (cmd->parent && cmd->parent->name)
1442ee67178SXianjun Jiao 					printf("%s ", cmd->parent->name);
1452ee67178SXianjun Jiao 				printf("%s ", cmd->name);
1462ee67178SXianjun Jiao 			}
1472ee67178SXianjun Jiao 			printf("%.*s\n", (int)(lend - start), start);
1482ee67178SXianjun Jiao 			start = lend + 1;
1492ee67178SXianjun Jiao 		} while (end != lend);
1502ee67178SXianjun Jiao 	} else
1512ee67178SXianjun Jiao 		printf("\n");
1522ee67178SXianjun Jiao 
1532ee67178SXianjun Jiao 	if (!full || !cmd->help)
1542ee67178SXianjun Jiao 		return;
1552ee67178SXianjun Jiao 
1562ee67178SXianjun Jiao 	/* hack */
1572ee67178SXianjun Jiao 	if (strlen(indent))
1582ee67178SXianjun Jiao 		indent = "\t\t";
1592ee67178SXianjun Jiao 	else
1602ee67178SXianjun Jiao 		printf("\n");
1612ee67178SXianjun Jiao 
1622ee67178SXianjun Jiao 	/* print line by line */
1632ee67178SXianjun Jiao 	start = cmd->help;
1642ee67178SXianjun Jiao 	end = strchr(start, '\0');
1652ee67178SXianjun Jiao 	do {
1662ee67178SXianjun Jiao 		lend = strchr(start, '\n');
1672ee67178SXianjun Jiao 		if (!lend)
1682ee67178SXianjun Jiao 			lend = end;
1692ee67178SXianjun Jiao 		printf("%s", indent);
1702ee67178SXianjun Jiao 		printf("%.*s\n", (int)(lend - start), start);
1712ee67178SXianjun Jiao 		start = lend + 1;
1722ee67178SXianjun Jiao 	} while (end != lend);
1732ee67178SXianjun Jiao 
1742ee67178SXianjun Jiao 	printf("\n");
1752ee67178SXianjun Jiao }
1762ee67178SXianjun Jiao 
usage_options(void)1772ee67178SXianjun Jiao static void usage_options(void)
1782ee67178SXianjun Jiao {
1792ee67178SXianjun Jiao 	printf("Options:\n");
1802ee67178SXianjun Jiao 	printf("\t--debug\t\tenable netlink debugging\n");
1812ee67178SXianjun Jiao }
1822ee67178SXianjun Jiao 
1832ee67178SXianjun Jiao static const char *argv0;
1842ee67178SXianjun Jiao 
usage(int argc,char ** argv)1852ee67178SXianjun Jiao static void usage(int argc, char **argv)
1862ee67178SXianjun Jiao {
1872ee67178SXianjun Jiao 	const struct cmd *section, *cmd;
1882ee67178SXianjun Jiao 	bool full = argc >= 0;
1892ee67178SXianjun Jiao 	const char *sect_filt = NULL;
1902ee67178SXianjun Jiao 	const char *cmd_filt = NULL;
1912ee67178SXianjun Jiao 
1922ee67178SXianjun Jiao 	if (argc > 0)
1932ee67178SXianjun Jiao 		sect_filt = argv[0];
1942ee67178SXianjun Jiao 
1952ee67178SXianjun Jiao 	if (argc > 1)
1962ee67178SXianjun Jiao 		cmd_filt = argv[1];
1972ee67178SXianjun Jiao 
1982ee67178SXianjun Jiao 	printf("Usage:\t%s [options] command\n", argv0);
1992ee67178SXianjun Jiao 	usage_options();
2002ee67178SXianjun Jiao 	printf("\t--version\tshow version (%s)\n", sdrctl_version);
2012ee67178SXianjun Jiao 	printf("Commands:\n");
2022ee67178SXianjun Jiao 	for_each_cmd(section) {
2032ee67178SXianjun Jiao 		if (section->parent)
2042ee67178SXianjun Jiao 			continue;
2052ee67178SXianjun Jiao 
2062ee67178SXianjun Jiao 		if (sect_filt && strcmp(section->name, sect_filt))
2072ee67178SXianjun Jiao 			continue;
2082ee67178SXianjun Jiao 
2092ee67178SXianjun Jiao 		if (section->handler && !section->hidden)
2102ee67178SXianjun Jiao 			__usage_cmd(section, "\t", full);
2112ee67178SXianjun Jiao 
2122ee67178SXianjun Jiao 		for_each_cmd(cmd) {
2132ee67178SXianjun Jiao 			if (section != cmd->parent)
2142ee67178SXianjun Jiao 				continue;
2152ee67178SXianjun Jiao 			if (!cmd->handler || cmd->hidden)
2162ee67178SXianjun Jiao 				continue;
2172ee67178SXianjun Jiao 			if (cmd_filt && strcmp(cmd->name, cmd_filt))
2182ee67178SXianjun Jiao 				continue;
2192ee67178SXianjun Jiao 			__usage_cmd(cmd, "\t", full);
2202ee67178SXianjun Jiao 		}
2212ee67178SXianjun Jiao 	}
2222ee67178SXianjun Jiao 	printf("\nCommands that use the netdev ('dev') can also be given the\n"
2232ee67178SXianjun Jiao 	       "'wdev' instead to identify the device.\n");
2242ee67178SXianjun Jiao 	printf("\nYou can omit the 'phy' or 'dev' if "
2252ee67178SXianjun Jiao 			"the identification is unique,\n"
2262ee67178SXianjun Jiao 			"e.g. \"./sdrctl sdr0 get rssi_th\" or \"./sdrctl sdr0 get gap\". "
2272ee67178SXianjun Jiao 			"(Don't when scripting.)\n\n"
2282ee67178SXianjun Jiao 			"Do NOT screenscrape this tool, we don't "
2292ee67178SXianjun Jiao 			"consider its output stable.\n\n");
2302ee67178SXianjun Jiao }
2312ee67178SXianjun Jiao 
print_help(struct nl80211_state * state,struct nl_cb * cb,struct nl_msg * msg,int argc,char ** argv,enum id_input id)2322ee67178SXianjun Jiao static int print_help(struct nl80211_state *state,
2332ee67178SXianjun Jiao 		      struct nl_cb *cb,
2342ee67178SXianjun Jiao 		      struct nl_msg *msg,
2352ee67178SXianjun Jiao 		      int argc, char **argv,
2362ee67178SXianjun Jiao 		      enum id_input id)
2372ee67178SXianjun Jiao {
2382ee67178SXianjun Jiao 	exit(3);
2392ee67178SXianjun Jiao }
2402ee67178SXianjun Jiao TOPLEVEL(help, "[command]", 0, 0, CIB_NONE, print_help,
2412ee67178SXianjun Jiao 	 "Print usage for all or a specific command, e.g.\n"
2422ee67178SXianjun Jiao 	 "\"help wowlan\" or \"help wowlan enable\".");
2432ee67178SXianjun Jiao 
usage_cmd(const struct cmd * cmd)2442ee67178SXianjun Jiao static void usage_cmd(const struct cmd *cmd)
2452ee67178SXianjun Jiao {
2462ee67178SXianjun Jiao 	printf("Usage:\t%s [options] ", argv0);
2472ee67178SXianjun Jiao 	__usage_cmd(cmd, "", true);
2482ee67178SXianjun Jiao 	usage_options();
2492ee67178SXianjun Jiao }
2502ee67178SXianjun Jiao 
version(void)2512ee67178SXianjun Jiao static void version(void)
2522ee67178SXianjun Jiao {
2532ee67178SXianjun Jiao 	printf("iw version %s\n", sdrctl_version);
2542ee67178SXianjun Jiao }
2552ee67178SXianjun Jiao 
phy_lookup(char * name)2562ee67178SXianjun Jiao static int phy_lookup(char *name)
2572ee67178SXianjun Jiao {
2582ee67178SXianjun Jiao 	char buf[200];
2592ee67178SXianjun Jiao 	int fd, pos;
2602ee67178SXianjun Jiao 
2612ee67178SXianjun Jiao 	snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index", name);
2622ee67178SXianjun Jiao 
2632ee67178SXianjun Jiao 	fd = open(buf, O_RDONLY);
2642ee67178SXianjun Jiao 	if (fd < 0)
2652ee67178SXianjun Jiao 		return -1;
2662ee67178SXianjun Jiao 	pos = read(fd, buf, sizeof(buf) - 1);
2672ee67178SXianjun Jiao 	if (pos < 0) {
2682ee67178SXianjun Jiao 		close(fd);
2692ee67178SXianjun Jiao 		return -1;
2702ee67178SXianjun Jiao 	}
2712ee67178SXianjun Jiao 	buf[pos] = '\0';
2722ee67178SXianjun Jiao 	close(fd);
2732ee67178SXianjun Jiao 	return atoi(buf);
2742ee67178SXianjun Jiao }
2752ee67178SXianjun Jiao 
error_handler(struct sockaddr_nl * nla,struct nlmsgerr * err,void * arg)2762ee67178SXianjun Jiao static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
2772ee67178SXianjun Jiao 			 void *arg)
2782ee67178SXianjun Jiao {
2792ee67178SXianjun Jiao 	int *ret = arg;
2802ee67178SXianjun Jiao 	*ret = err->error;
2812ee67178SXianjun Jiao 	return NL_STOP;
2822ee67178SXianjun Jiao }
2832ee67178SXianjun Jiao 
finish_handler(struct nl_msg * msg,void * arg)2842ee67178SXianjun Jiao static int finish_handler(struct nl_msg *msg, void *arg)
2852ee67178SXianjun Jiao {
2862ee67178SXianjun Jiao 	int *ret = arg;
2872ee67178SXianjun Jiao 	*ret = 0;
2882ee67178SXianjun Jiao 	return NL_SKIP;
2892ee67178SXianjun Jiao }
2902ee67178SXianjun Jiao 
ack_handler(struct nl_msg * msg,void * arg)2912ee67178SXianjun Jiao static int ack_handler(struct nl_msg *msg, void *arg)
2922ee67178SXianjun Jiao {
2932ee67178SXianjun Jiao 	int *ret = arg;
2942ee67178SXianjun Jiao 	*ret = 0;
2952ee67178SXianjun Jiao 	return NL_STOP;
2962ee67178SXianjun Jiao }
2972ee67178SXianjun Jiao 
__handle_cmd(struct nl80211_state * state,enum id_input idby,int argc,char ** argv,const struct cmd ** cmdout)2982ee67178SXianjun Jiao static int __handle_cmd(struct nl80211_state *state, enum id_input idby,
2992ee67178SXianjun Jiao 			int argc, char **argv, const struct cmd **cmdout)
3002ee67178SXianjun Jiao {
3012ee67178SXianjun Jiao 	const struct cmd *cmd, *match = NULL, *sectcmd;
3022ee67178SXianjun Jiao 	struct nl_cb *cb;
3032ee67178SXianjun Jiao 	struct nl_cb *s_cb;
3042ee67178SXianjun Jiao 	struct nl_msg *msg;
3052ee67178SXianjun Jiao 	signed long long devidx = 0;
3062ee67178SXianjun Jiao 	int err, o_argc;
3072ee67178SXianjun Jiao 	const char *command, *section;
3082ee67178SXianjun Jiao 	char *tmp, **o_argv;
3092ee67178SXianjun Jiao 	enum command_identify_by command_idby = CIB_NONE;
3102ee67178SXianjun Jiao 
3112ee67178SXianjun Jiao 	if (argc <= 1 && idby != II_NONE)
3122ee67178SXianjun Jiao 		return 1;
3132ee67178SXianjun Jiao 
3142ee67178SXianjun Jiao 	o_argc = argc;
3152ee67178SXianjun Jiao 	o_argv = argv;
3162ee67178SXianjun Jiao 
3172ee67178SXianjun Jiao 	switch (idby) {
3182ee67178SXianjun Jiao 	case II_PHY_IDX:
3192ee67178SXianjun Jiao 		command_idby = CIB_PHY;
3202ee67178SXianjun Jiao 		devidx = strtoul(*argv + 4, &tmp, 0);
3212ee67178SXianjun Jiao 		if (*tmp != '\0')
3222ee67178SXianjun Jiao 			return 1;
3232ee67178SXianjun Jiao 		argc--;
3242ee67178SXianjun Jiao 		argv++;
3252ee67178SXianjun Jiao 		break;
3262ee67178SXianjun Jiao 	case II_PHY_NAME:
3272ee67178SXianjun Jiao 		command_idby = CIB_PHY;
3282ee67178SXianjun Jiao 		devidx = phy_lookup(*argv);
3292ee67178SXianjun Jiao 		argc--;
3302ee67178SXianjun Jiao 		argv++;
3312ee67178SXianjun Jiao 		break;
3322ee67178SXianjun Jiao 	case II_NETDEV:
3332ee67178SXianjun Jiao 		command_idby = CIB_NETDEV;
3342ee67178SXianjun Jiao 		devidx = if_nametoindex(*argv);
3352ee67178SXianjun Jiao 		if (devidx == 0)
3362ee67178SXianjun Jiao 			devidx = -1;
3372ee67178SXianjun Jiao 		argc--;
3382ee67178SXianjun Jiao 		argv++;
3392ee67178SXianjun Jiao 		break;
3402ee67178SXianjun Jiao 	case II_WDEV:
3412ee67178SXianjun Jiao 		command_idby = CIB_WDEV;
3422ee67178SXianjun Jiao 		devidx = strtoll(*argv, &tmp, 0);
3432ee67178SXianjun Jiao 		if (*tmp != '\0')
3442ee67178SXianjun Jiao 			return 1;
3452ee67178SXianjun Jiao 		argc--;
3462ee67178SXianjun Jiao 		argv++;
3472ee67178SXianjun Jiao 	default:
3482ee67178SXianjun Jiao 		break;
3492ee67178SXianjun Jiao 	}
3502ee67178SXianjun Jiao 
3512ee67178SXianjun Jiao 	if (devidx < 0)
3522ee67178SXianjun Jiao 		return -errno;
3532ee67178SXianjun Jiao 
3542ee67178SXianjun Jiao 	section = *argv;
3552ee67178SXianjun Jiao 	argc--;
3562ee67178SXianjun Jiao 	argv++;
3572ee67178SXianjun Jiao 
3582ee67178SXianjun Jiao 	for_each_cmd(sectcmd) {
3592ee67178SXianjun Jiao 		if (sectcmd->parent)
3602ee67178SXianjun Jiao 			continue;
3612ee67178SXianjun Jiao 		/* ok ... bit of a hack for the dupe 'info' section */
3622ee67178SXianjun Jiao 		if (match && sectcmd->idby != command_idby)
3632ee67178SXianjun Jiao 			continue;
3642ee67178SXianjun Jiao 		if (strcmp(sectcmd->name, section) == 0)
3652ee67178SXianjun Jiao 			match = sectcmd;
3662ee67178SXianjun Jiao 	}
3672ee67178SXianjun Jiao 
3682ee67178SXianjun Jiao 	sectcmd = match;
3692ee67178SXianjun Jiao 	match = NULL;
3702ee67178SXianjun Jiao 	if (!sectcmd)
3712ee67178SXianjun Jiao 		return 1;
3722ee67178SXianjun Jiao 
3732ee67178SXianjun Jiao 	if (argc > 0) {
3742ee67178SXianjun Jiao 		command = *argv;
3752ee67178SXianjun Jiao 
3762ee67178SXianjun Jiao 		for_each_cmd(cmd) {
3772ee67178SXianjun Jiao 			if (!cmd->handler)
3782ee67178SXianjun Jiao 				continue;
3792ee67178SXianjun Jiao 			if (cmd->parent != sectcmd)
3802ee67178SXianjun Jiao 				continue;
3812ee67178SXianjun Jiao 			/*
3822ee67178SXianjun Jiao 			 * ignore mismatch id by, but allow WDEV
3832ee67178SXianjun Jiao 			 * in place of NETDEV
3842ee67178SXianjun Jiao 			 */
3852ee67178SXianjun Jiao 			if (cmd->idby != command_idby &&
3862ee67178SXianjun Jiao 			    !(cmd->idby == CIB_NETDEV &&
3872ee67178SXianjun Jiao 			      command_idby == CIB_WDEV))
3882ee67178SXianjun Jiao 				continue;
3892ee67178SXianjun Jiao 			if (strcmp(cmd->name, command))
3902ee67178SXianjun Jiao 				continue;
3912ee67178SXianjun Jiao 			if (argc > 1 && !cmd->args)
3922ee67178SXianjun Jiao 				continue;
3932ee67178SXianjun Jiao 			match = cmd;
3942ee67178SXianjun Jiao 			break;
3952ee67178SXianjun Jiao 		}
3962ee67178SXianjun Jiao 
3972ee67178SXianjun Jiao 		if (match) {
3982ee67178SXianjun Jiao 			argc--;
3992ee67178SXianjun Jiao 			argv++;
4002ee67178SXianjun Jiao 		}
4012ee67178SXianjun Jiao 	}
4022ee67178SXianjun Jiao 
4032ee67178SXianjun Jiao 	if (match)
4042ee67178SXianjun Jiao 		cmd = match;
4052ee67178SXianjun Jiao 	else {
4062ee67178SXianjun Jiao 		/* Use the section itself, if possible. */
4072ee67178SXianjun Jiao 		cmd = sectcmd;
4082ee67178SXianjun Jiao 		if (argc && !cmd->args)
4092ee67178SXianjun Jiao 			return 1;
4102ee67178SXianjun Jiao 		if (cmd->idby != command_idby &&
4112ee67178SXianjun Jiao 		    !(cmd->idby == CIB_NETDEV && command_idby == CIB_WDEV))
4122ee67178SXianjun Jiao 			return 1;
4132ee67178SXianjun Jiao 		if (!cmd->handler)
4142ee67178SXianjun Jiao 			return 1;
4152ee67178SXianjun Jiao 	}
4162ee67178SXianjun Jiao 
4172ee67178SXianjun Jiao 	if (cmd->selector) {
4182ee67178SXianjun Jiao 		cmd = cmd->selector(argc, argv);
4192ee67178SXianjun Jiao 		if (!cmd)
4202ee67178SXianjun Jiao 			return 1;
4212ee67178SXianjun Jiao 	}
4222ee67178SXianjun Jiao 
4232ee67178SXianjun Jiao 	if (cmdout)
4242ee67178SXianjun Jiao 		*cmdout = cmd;
4252ee67178SXianjun Jiao 
4262ee67178SXianjun Jiao 	if (!cmd->cmd) {
4272ee67178SXianjun Jiao 		argc = o_argc;
4282ee67178SXianjun Jiao 		argv = o_argv;
4292ee67178SXianjun Jiao 		return cmd->handler(state, NULL, NULL, argc, argv, idby);
4302ee67178SXianjun Jiao 	}
4312ee67178SXianjun Jiao 
4322ee67178SXianjun Jiao 	msg = nlmsg_alloc();
4332ee67178SXianjun Jiao 	if (!msg) {
4342ee67178SXianjun Jiao 		fprintf(stderr, "failed to allocate netlink message\n");
4352ee67178SXianjun Jiao 		return 2;
4362ee67178SXianjun Jiao 	}
4372ee67178SXianjun Jiao 
4382ee67178SXianjun Jiao 	cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
4392ee67178SXianjun Jiao 	s_cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
4402ee67178SXianjun Jiao 	if (!cb || !s_cb) {
4412ee67178SXianjun Jiao 		fprintf(stderr, "failed to allocate netlink callbacks\n");
4422ee67178SXianjun Jiao 		err = 2;
4432ee67178SXianjun Jiao 		goto out_free_msg;
4442ee67178SXianjun Jiao 	}
4452ee67178SXianjun Jiao 
4462ee67178SXianjun Jiao 	genlmsg_put(msg, 0, 0, state->nl80211_id, 0,
4472ee67178SXianjun Jiao 		    cmd->nl_msg_flags, cmd->cmd, 0);
4482ee67178SXianjun Jiao 
4492ee67178SXianjun Jiao 	switch (command_idby) {
4502ee67178SXianjun Jiao 	case CIB_PHY:
4512ee67178SXianjun Jiao 		NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, devidx);
4522ee67178SXianjun Jiao 		break;
4532ee67178SXianjun Jiao 	case CIB_NETDEV:
4542ee67178SXianjun Jiao 		NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
4552ee67178SXianjun Jiao 		break;
4562ee67178SXianjun Jiao 	case CIB_WDEV:
4572ee67178SXianjun Jiao 		NLA_PUT_U64(msg, NL80211_ATTR_WDEV, devidx);
4582ee67178SXianjun Jiao 		break;
4592ee67178SXianjun Jiao 	default:
4602ee67178SXianjun Jiao 		break;
4612ee67178SXianjun Jiao 	}
4622ee67178SXianjun Jiao 
4632ee67178SXianjun Jiao 	err = cmd->handler(state, cb, msg, argc, argv, idby);
4642ee67178SXianjun Jiao 	if (err)
4652ee67178SXianjun Jiao 		goto out;
4662ee67178SXianjun Jiao 
4672ee67178SXianjun Jiao 	nl_socket_set_cb(state->nl_sock, s_cb);
4682ee67178SXianjun Jiao 
4692ee67178SXianjun Jiao 	err = nl_send_auto_complete(state->nl_sock, msg);
4702ee67178SXianjun Jiao 	if (err < 0)
4712ee67178SXianjun Jiao 		goto out;
4722ee67178SXianjun Jiao 
4732ee67178SXianjun Jiao 	err = 1;
4742ee67178SXianjun Jiao 
4752ee67178SXianjun Jiao 	nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
4762ee67178SXianjun Jiao 	nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
4772ee67178SXianjun Jiao 	nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
4782ee67178SXianjun Jiao 
4792ee67178SXianjun Jiao 	while (err > 0)
4802ee67178SXianjun Jiao 		nl_recvmsgs(state->nl_sock, cb);
4812ee67178SXianjun Jiao  out:
4822ee67178SXianjun Jiao 	nl_cb_put(cb);
4832ee67178SXianjun Jiao  out_free_msg:
4842ee67178SXianjun Jiao 	nlmsg_free(msg);
4852ee67178SXianjun Jiao 	return err;
4862ee67178SXianjun Jiao  nla_put_failure:
4872ee67178SXianjun Jiao 	fprintf(stderr, "building message failed\n");
4882ee67178SXianjun Jiao 	return 2;
4892ee67178SXianjun Jiao }
4902ee67178SXianjun Jiao 
handle_cmd(struct nl80211_state * state,enum id_input idby,int argc,char ** argv)4912ee67178SXianjun Jiao int handle_cmd(struct nl80211_state *state, enum id_input idby,
4922ee67178SXianjun Jiao 	       int argc, char **argv)
4932ee67178SXianjun Jiao {
4942ee67178SXianjun Jiao 	return __handle_cmd(state, idby, argc, argv, NULL);
4952ee67178SXianjun Jiao }
4962ee67178SXianjun Jiao 
main(int argc,char ** argv)4972ee67178SXianjun Jiao int main(int argc, char **argv)
4982ee67178SXianjun Jiao {
4992ee67178SXianjun Jiao 	struct nl80211_state nlstate;
5002ee67178SXianjun Jiao 	int err;
5012ee67178SXianjun Jiao 	const struct cmd *cmd = NULL;
5022ee67178SXianjun Jiao 
5032ee67178SXianjun Jiao 	/* calculate command size including padding */
5042ee67178SXianjun Jiao 	cmd_size = abs((long)&__section_set - (long)&__section_get);
5052ee67178SXianjun Jiao 	/* strip off self */
5062ee67178SXianjun Jiao 	argc--;
5072ee67178SXianjun Jiao 	argv0 = *argv++;
5082ee67178SXianjun Jiao 
5092ee67178SXianjun Jiao 	if (argc > 0 && strcmp(*argv, "--debug") == 0) {
5102ee67178SXianjun Jiao 		iw_debug = 1;
5112ee67178SXianjun Jiao 		argc--;
5122ee67178SXianjun Jiao 		argv++;
5132ee67178SXianjun Jiao 	}
5142ee67178SXianjun Jiao 
5152ee67178SXianjun Jiao 	if (argc > 0 && strcmp(*argv, "--version") == 0) {
5162ee67178SXianjun Jiao 		version();
5172ee67178SXianjun Jiao 		return 0;
5182ee67178SXianjun Jiao 	}
5192ee67178SXianjun Jiao 
5202ee67178SXianjun Jiao 	/* need to treat "help" command specially so it works w/o nl80211 */
5212ee67178SXianjun Jiao 	if (argc == 0 || strcmp(*argv, "help") == 0) {
5222ee67178SXianjun Jiao 		usage(argc - 1, argv + 1);
5232ee67178SXianjun Jiao 		return 0;
5242ee67178SXianjun Jiao 	}
5252ee67178SXianjun Jiao 
5262ee67178SXianjun Jiao 	err = nl80211_init(&nlstate);
5272ee67178SXianjun Jiao 	if (err)
5282ee67178SXianjun Jiao 		return 1;
5292ee67178SXianjun Jiao 
5302ee67178SXianjun Jiao 	if (strcmp(*argv, "dev") == 0 && argc > 1) {
5312ee67178SXianjun Jiao 		argc--;
5322ee67178SXianjun Jiao 		argv++;
5332ee67178SXianjun Jiao 		err = __handle_cmd(&nlstate, II_NETDEV, argc, argv, &cmd);
5342ee67178SXianjun Jiao 	} else if (strncmp(*argv, "phy", 3) == 0 && argc > 1) {
5352ee67178SXianjun Jiao 		if (strlen(*argv) == 3) {
5362ee67178SXianjun Jiao 			argc--;
5372ee67178SXianjun Jiao 			argv++;
5382ee67178SXianjun Jiao 			err = __handle_cmd(&nlstate, II_PHY_NAME, argc, argv, &cmd);
5392ee67178SXianjun Jiao 		} else if (*(*argv + 3) == '#')
5402ee67178SXianjun Jiao 			err = __handle_cmd(&nlstate, II_PHY_IDX, argc, argv, &cmd);
5412ee67178SXianjun Jiao 		else
5422ee67178SXianjun Jiao 			goto detect;
5432ee67178SXianjun Jiao 	} else if (strcmp(*argv, "wdev") == 0 && argc > 1) {
5442ee67178SXianjun Jiao 		argc--;
5452ee67178SXianjun Jiao 		argv++;
5462ee67178SXianjun Jiao 		err = __handle_cmd(&nlstate, II_WDEV, argc, argv, &cmd);
5472ee67178SXianjun Jiao 	} else {
5482ee67178SXianjun Jiao 		int idx;
5492ee67178SXianjun Jiao 		enum id_input idby = II_NONE;
5502ee67178SXianjun Jiao  detect:
5512ee67178SXianjun Jiao 		if ((idx = if_nametoindex(argv[0])) != 0)
5522ee67178SXianjun Jiao 			idby = II_NETDEV;
5532ee67178SXianjun Jiao 		else if ((idx = phy_lookup(argv[0])) >= 0)
5542ee67178SXianjun Jiao 			idby = II_PHY_NAME;
5552ee67178SXianjun Jiao 		err = __handle_cmd(&nlstate, idby, argc, argv, &cmd);
5562ee67178SXianjun Jiao 	}
5572ee67178SXianjun Jiao 
5582ee67178SXianjun Jiao 	if (err == 1) {
5592ee67178SXianjun Jiao 		if (cmd)
5602ee67178SXianjun Jiao 			usage_cmd(cmd);
5612ee67178SXianjun Jiao 		else
5622ee67178SXianjun Jiao 			usage(0, NULL);
5632ee67178SXianjun Jiao 	} else if (err < 0)
5642ee67178SXianjun Jiao 		fprintf(stderr, "command failed: %s (%d)\n", strerror(-err), err);
5652ee67178SXianjun Jiao 
5662ee67178SXianjun Jiao 	nl80211_cleanup(&nlstate);
5672ee67178SXianjun Jiao 
5682ee67178SXianjun Jiao 	return err;
5692ee67178SXianjun Jiao }
570