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