12ee67178SXianjun Jiao /* 22ee67178SXianjun Jiao * nl80211 userspace tool 32ee67178SXianjun Jiao * 4*a6085186SLina Ceballos * SPDX-FileCopyrightText: Copyright 2007, 2008 Johannes Berg <[email protected]> 5*a6085186SLina Ceballos * Modified by Xianjun jiao. [email protected]; [email protected] 6*a6085186SLina 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) 302ee67178SXianjun Jiao static inline struct nl_handle *nl_socket_alloc(void) 312ee67178SXianjun Jiao { 322ee67178SXianjun Jiao return nl_handle_alloc(); 332ee67178SXianjun Jiao } 342ee67178SXianjun Jiao 352ee67178SXianjun Jiao static inline void nl_socket_free(struct nl_sock *h) 362ee67178SXianjun Jiao { 372ee67178SXianjun Jiao nl_handle_destroy(h); 382ee67178SXianjun Jiao } 392ee67178SXianjun Jiao 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 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 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 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 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 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 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 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 2512ee67178SXianjun Jiao static void version(void) 2522ee67178SXianjun Jiao { 2532ee67178SXianjun Jiao printf("iw version %s\n", sdrctl_version); 2542ee67178SXianjun Jiao } 2552ee67178SXianjun Jiao 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 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 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 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 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 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 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