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