1 /* 2 * hostapd - command line interface for hostapd daemon 3 * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi> 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9 #include "includes.h" 10 #include <dirent.h> 11 12 #include "common/wpa_ctrl.h" 13 #include "utils/common.h" 14 #include "utils/eloop.h" 15 #include "utils/edit.h" 16 #include "common/version.h" 17 18 19 static const char *hostapd_cli_version = 20 "hostapd_cli v" VERSION_STR "\n" 21 "Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi> and contributors"; 22 23 24 static const char *hostapd_cli_license = 25 "This software may be distributed under the terms of the BSD license.\n" 26 "See README for more details.\n"; 27 28 static const char *hostapd_cli_full_license = 29 "This software may be distributed under the terms of the BSD license.\n" 30 "\n" 31 "Redistribution and use in source and binary forms, with or without\n" 32 "modification, are permitted provided that the following conditions are\n" 33 "met:\n" 34 "\n" 35 "1. Redistributions of source code must retain the above copyright\n" 36 " notice, this list of conditions and the following disclaimer.\n" 37 "\n" 38 "2. Redistributions in binary form must reproduce the above copyright\n" 39 " notice, this list of conditions and the following disclaimer in the\n" 40 " documentation and/or other materials provided with the distribution.\n" 41 "\n" 42 "3. Neither the name(s) of the above-listed copyright holder(s) nor the\n" 43 " names of its contributors may be used to endorse or promote products\n" 44 " derived from this software without specific prior written permission.\n" 45 "\n" 46 "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n" 47 "\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n" 48 "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n" 49 "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n" 50 "OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n" 51 "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n" 52 "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n" 53 "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n" 54 "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n" 55 "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n" 56 "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" 57 "\n"; 58 59 static const char *commands_help = 60 "Commands:\n" 61 " mib get MIB variables (dot1x, dot11, radius)\n" 62 " sta <addr> get MIB variables for one station\n" 63 " all_sta get MIB variables for all stations\n" 64 " new_sta <addr> add a new station\n" 65 " deauthenticate <addr> deauthenticate a station\n" 66 " disassociate <addr> disassociate a station\n" 67 #ifdef CONFIG_IEEE80211W 68 " sa_query <addr> send SA Query to a station\n" 69 #endif /* CONFIG_IEEE80211W */ 70 #ifdef CONFIG_WPS 71 " wps_pin <uuid> <pin> [timeout] [addr] add WPS Enrollee PIN\n" 72 " wps_check_pin <PIN> verify PIN checksum\n" 73 " wps_pbc indicate button pushed to initiate PBC\n" 74 " wps_cancel cancel the pending WPS operation\n" 75 #ifdef CONFIG_WPS_NFC 76 " wps_nfc_tag_read <hexdump> report read NFC tag with WPS data\n" 77 " wps_nfc_config_token <WPS/NDEF> build NFC configuration token\n" 78 " wps_nfc_token <WPS/NDEF/enable/disable> manager NFC password token\n" 79 #endif /* CONFIG_WPS_NFC */ 80 " wps_ap_pin <cmd> [params..] enable/disable AP PIN\n" 81 " wps_config <SSID> <auth> <encr> <key> configure AP\n" 82 #endif /* CONFIG_WPS */ 83 " get_config show current configuration\n" 84 " help show this usage help\n" 85 " interface [ifname] show interfaces/select interface\n" 86 " level <debug level> change debug level\n" 87 " license show full hostapd_cli license\n" 88 " quit exit hostapd_cli\n"; 89 90 static struct wpa_ctrl *ctrl_conn; 91 static int hostapd_cli_quit = 0; 92 static int hostapd_cli_attached = 0; 93 static const char *ctrl_iface_dir = "/var/run/hostapd"; 94 static char *ctrl_ifname = NULL; 95 static const char *pid_file = NULL; 96 static const char *action_file = NULL; 97 static int ping_interval = 5; 98 static int interactive = 0; 99 100 101 static void usage(void) 102 { 103 fprintf(stderr, "%s\n", hostapd_cli_version); 104 fprintf(stderr, 105 "\n" 106 "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] " 107 "[-a<path>] \\\n" 108 " [-G<ping interval>] [command..]\n" 109 "\n" 110 "Options:\n" 111 " -h help (show this usage text)\n" 112 " -v shown version information\n" 113 " -p<path> path to find control sockets (default: " 114 "/var/run/hostapd)\n" 115 " -a<file> run in daemon mode executing the action file " 116 "based on events\n" 117 " from hostapd\n" 118 " -B run a daemon in the background\n" 119 " -i<ifname> Interface to listen on (default: first " 120 "interface found in the\n" 121 " socket path)\n\n" 122 "%s", 123 commands_help); 124 } 125 126 127 static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname) 128 { 129 char *cfile; 130 int flen; 131 132 if (ifname == NULL) 133 return NULL; 134 135 flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2; 136 cfile = malloc(flen); 137 if (cfile == NULL) 138 return NULL; 139 snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname); 140 141 ctrl_conn = wpa_ctrl_open(cfile); 142 free(cfile); 143 return ctrl_conn; 144 } 145 146 147 static void hostapd_cli_close_connection(void) 148 { 149 if (ctrl_conn == NULL) 150 return; 151 152 if (hostapd_cli_attached) { 153 wpa_ctrl_detach(ctrl_conn); 154 hostapd_cli_attached = 0; 155 } 156 wpa_ctrl_close(ctrl_conn); 157 ctrl_conn = NULL; 158 } 159 160 161 static void hostapd_cli_msg_cb(char *msg, size_t len) 162 { 163 printf("%s\n", msg); 164 } 165 166 167 static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print) 168 { 169 char buf[4096]; 170 size_t len; 171 int ret; 172 173 if (ctrl_conn == NULL) { 174 printf("Not connected to hostapd - command dropped.\n"); 175 return -1; 176 } 177 len = sizeof(buf) - 1; 178 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len, 179 hostapd_cli_msg_cb); 180 if (ret == -2) { 181 printf("'%s' command timed out.\n", cmd); 182 return -2; 183 } else if (ret < 0) { 184 printf("'%s' command failed.\n", cmd); 185 return -1; 186 } 187 if (print) { 188 buf[len] = '\0'; 189 printf("%s", buf); 190 } 191 return 0; 192 } 193 194 195 static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd) 196 { 197 return _wpa_ctrl_command(ctrl, cmd, 1); 198 } 199 200 201 static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[]) 202 { 203 return wpa_ctrl_command(ctrl, "PING"); 204 } 205 206 207 static int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[]) 208 { 209 return wpa_ctrl_command(ctrl, "RELOG"); 210 } 211 212 213 static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[]) 214 { 215 return wpa_ctrl_command(ctrl, "MIB"); 216 } 217 218 219 static int hostapd_cli_exec(const char *program, const char *arg1, 220 const char *arg2) 221 { 222 char *cmd; 223 size_t len; 224 int res; 225 int ret = 0; 226 227 len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3; 228 cmd = os_malloc(len); 229 if (cmd == NULL) 230 return -1; 231 res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2); 232 if (res < 0 || (size_t) res >= len) { 233 os_free(cmd); 234 return -1; 235 } 236 cmd[len - 1] = '\0'; 237 #ifndef _WIN32_WCE 238 if (system(cmd) < 0) 239 ret = -1; 240 #endif /* _WIN32_WCE */ 241 os_free(cmd); 242 243 return ret; 244 } 245 246 247 static void hostapd_cli_action_process(char *msg, size_t len) 248 { 249 const char *pos; 250 251 pos = msg; 252 if (*pos == '<') { 253 pos = os_strchr(pos, '>'); 254 if (pos) 255 pos++; 256 else 257 pos = msg; 258 } 259 260 hostapd_cli_exec(action_file, ctrl_ifname, pos); 261 } 262 263 264 static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[]) 265 { 266 char buf[64]; 267 if (argc != 1) { 268 printf("Invalid 'sta' command - exactly one argument, STA " 269 "address, is required.\n"); 270 return -1; 271 } 272 snprintf(buf, sizeof(buf), "STA %s", argv[0]); 273 return wpa_ctrl_command(ctrl, buf); 274 } 275 276 277 static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc, 278 char *argv[]) 279 { 280 char buf[64]; 281 if (argc != 1) { 282 printf("Invalid 'new_sta' command - exactly one argument, STA " 283 "address, is required.\n"); 284 return -1; 285 } 286 snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]); 287 return wpa_ctrl_command(ctrl, buf); 288 } 289 290 291 static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc, 292 char *argv[]) 293 { 294 char buf[64]; 295 if (argc < 1) { 296 printf("Invalid 'deauthenticate' command - exactly one " 297 "argument, STA address, is required.\n"); 298 return -1; 299 } 300 if (argc > 1) 301 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s", 302 argv[0], argv[1]); 303 else 304 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]); 305 return wpa_ctrl_command(ctrl, buf); 306 } 307 308 309 static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc, 310 char *argv[]) 311 { 312 char buf[64]; 313 if (argc < 1) { 314 printf("Invalid 'disassociate' command - exactly one " 315 "argument, STA address, is required.\n"); 316 return -1; 317 } 318 if (argc > 1) 319 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s", 320 argv[0], argv[1]); 321 else 322 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]); 323 return wpa_ctrl_command(ctrl, buf); 324 } 325 326 327 #ifdef CONFIG_IEEE80211W 328 static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc, 329 char *argv[]) 330 { 331 char buf[64]; 332 if (argc != 1) { 333 printf("Invalid 'sa_query' command - exactly one argument, " 334 "STA address, is required.\n"); 335 return -1; 336 } 337 snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]); 338 return wpa_ctrl_command(ctrl, buf); 339 } 340 #endif /* CONFIG_IEEE80211W */ 341 342 343 #ifdef CONFIG_WPS 344 static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, 345 char *argv[]) 346 { 347 char buf[256]; 348 if (argc < 2) { 349 printf("Invalid 'wps_pin' command - at least two arguments, " 350 "UUID and PIN, are required.\n"); 351 return -1; 352 } 353 if (argc > 3) 354 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s %s", 355 argv[0], argv[1], argv[2], argv[3]); 356 else if (argc > 2) 357 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s", 358 argv[0], argv[1], argv[2]); 359 else 360 snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]); 361 return wpa_ctrl_command(ctrl, buf); 362 } 363 364 365 static int hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc, 366 char *argv[]) 367 { 368 char cmd[256]; 369 int res; 370 371 if (argc != 1 && argc != 2) { 372 printf("Invalid WPS_CHECK_PIN command: needs one argument:\n" 373 "- PIN to be verified\n"); 374 return -1; 375 } 376 377 if (argc == 2) 378 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s", 379 argv[0], argv[1]); 380 else 381 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s", 382 argv[0]); 383 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { 384 printf("Too long WPS_CHECK_PIN command.\n"); 385 return -1; 386 } 387 return wpa_ctrl_command(ctrl, cmd); 388 } 389 390 391 static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc, 392 char *argv[]) 393 { 394 return wpa_ctrl_command(ctrl, "WPS_PBC"); 395 } 396 397 398 static int hostapd_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc, 399 char *argv[]) 400 { 401 return wpa_ctrl_command(ctrl, "WPS_CANCEL"); 402 } 403 404 405 #ifdef CONFIG_WPS_NFC 406 static int hostapd_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc, 407 char *argv[]) 408 { 409 int ret; 410 char *buf; 411 size_t buflen; 412 413 if (argc != 1) { 414 printf("Invalid 'wps_nfc_tag_read' command - one argument " 415 "is required.\n"); 416 return -1; 417 } 418 419 buflen = 18 + os_strlen(argv[0]); 420 buf = os_malloc(buflen); 421 if (buf == NULL) 422 return -1; 423 os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]); 424 425 ret = wpa_ctrl_command(ctrl, buf); 426 os_free(buf); 427 428 return ret; 429 } 430 431 432 static int hostapd_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl, 433 int argc, char *argv[]) 434 { 435 char cmd[64]; 436 int res; 437 438 if (argc != 1) { 439 printf("Invalid 'wps_nfc_config_token' command - one argument " 440 "is required.\n"); 441 return -1; 442 } 443 444 res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_CONFIG_TOKEN %s", 445 argv[0]); 446 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { 447 printf("Too long WPS_NFC_CONFIG_TOKEN command.\n"); 448 return -1; 449 } 450 return wpa_ctrl_command(ctrl, cmd); 451 } 452 453 454 static int hostapd_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl, 455 int argc, char *argv[]) 456 { 457 char cmd[64]; 458 int res; 459 460 if (argc != 1) { 461 printf("Invalid 'wps_nfc_token' command - one argument is " 462 "required.\n"); 463 return -1; 464 } 465 466 res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s", argv[0]); 467 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { 468 printf("Too long WPS_NFC_TOKEN command.\n"); 469 return -1; 470 } 471 return wpa_ctrl_command(ctrl, cmd); 472 } 473 #endif /* CONFIG_WPS_NFC */ 474 475 476 static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc, 477 char *argv[]) 478 { 479 char buf[64]; 480 if (argc < 1) { 481 printf("Invalid 'wps_ap_pin' command - at least one argument " 482 "is required.\n"); 483 return -1; 484 } 485 if (argc > 2) 486 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s", 487 argv[0], argv[1], argv[2]); 488 else if (argc > 1) 489 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s", 490 argv[0], argv[1]); 491 else 492 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]); 493 return wpa_ctrl_command(ctrl, buf); 494 } 495 496 497 static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc, 498 char *argv[]) 499 { 500 char buf[256]; 501 char ssid_hex[2 * 32 + 1]; 502 char key_hex[2 * 64 + 1]; 503 int i; 504 505 if (argc < 1) { 506 printf("Invalid 'wps_config' command - at least two arguments " 507 "are required.\n"); 508 return -1; 509 } 510 511 ssid_hex[0] = '\0'; 512 for (i = 0; i < 32; i++) { 513 if (argv[0][i] == '\0') 514 break; 515 os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]); 516 } 517 518 key_hex[0] = '\0'; 519 if (argc > 3) { 520 for (i = 0; i < 64; i++) { 521 if (argv[3][i] == '\0') 522 break; 523 os_snprintf(&key_hex[i * 2], 3, "%02x", 524 argv[3][i]); 525 } 526 } 527 528 if (argc > 3) 529 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s %s", 530 ssid_hex, argv[1], argv[2], key_hex); 531 else if (argc > 2) 532 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s", 533 ssid_hex, argv[1], argv[2]); 534 else 535 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s", 536 ssid_hex, argv[1]); 537 return wpa_ctrl_command(ctrl, buf); 538 } 539 #endif /* CONFIG_WPS */ 540 541 542 static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc, 543 char *argv[]) 544 { 545 char buf[300]; 546 int res; 547 548 if (argc < 2) { 549 printf("Invalid 'disassoc_imminent' command - two arguments " 550 "(STA addr and Disassociation Timer) are needed\n"); 551 return -1; 552 } 553 554 res = os_snprintf(buf, sizeof(buf), "DISASSOC_IMMINENT %s %s", 555 argv[0], argv[1]); 556 if (res < 0 || res >= (int) sizeof(buf)) 557 return -1; 558 return wpa_ctrl_command(ctrl, buf); 559 } 560 561 562 static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc, 563 char *argv[]) 564 { 565 char buf[300]; 566 int res; 567 568 if (argc < 2) { 569 printf("Invalid 'ess_disassoc' command - two arguments (STA " 570 "addr and URL) are needed\n"); 571 return -1; 572 } 573 574 res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s", 575 argv[0], argv[1]); 576 if (res < 0 || res >= (int) sizeof(buf)) 577 return -1; 578 return wpa_ctrl_command(ctrl, buf); 579 } 580 581 582 static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc, 583 char *argv[]) 584 { 585 return wpa_ctrl_command(ctrl, "GET_CONFIG"); 586 } 587 588 589 static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd, 590 char *addr, size_t addr_len) 591 { 592 char buf[4096], *pos; 593 size_t len; 594 int ret; 595 596 if (ctrl_conn == NULL) { 597 printf("Not connected to hostapd - command dropped.\n"); 598 return -1; 599 } 600 len = sizeof(buf) - 1; 601 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len, 602 hostapd_cli_msg_cb); 603 if (ret == -2) { 604 printf("'%s' command timed out.\n", cmd); 605 return -2; 606 } else if (ret < 0) { 607 printf("'%s' command failed.\n", cmd); 608 return -1; 609 } 610 611 buf[len] = '\0'; 612 if (memcmp(buf, "FAIL", 4) == 0) 613 return -1; 614 printf("%s", buf); 615 616 pos = buf; 617 while (*pos != '\0' && *pos != '\n') 618 pos++; 619 *pos = '\0'; 620 os_strlcpy(addr, buf, addr_len); 621 return 0; 622 } 623 624 625 static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, 626 char *argv[]) 627 { 628 char addr[32], cmd[64]; 629 630 if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr))) 631 return 0; 632 do { 633 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr); 634 } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0); 635 636 return -1; 637 } 638 639 640 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[]) 641 { 642 printf("%s", commands_help); 643 return 0; 644 } 645 646 647 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, 648 char *argv[]) 649 { 650 printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license); 651 return 0; 652 } 653 654 655 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[]) 656 { 657 hostapd_cli_quit = 1; 658 if (interactive) 659 eloop_terminate(); 660 return 0; 661 } 662 663 664 static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[]) 665 { 666 char cmd[256]; 667 if (argc != 1) { 668 printf("Invalid LEVEL command: needs one argument (debug " 669 "level)\n"); 670 return 0; 671 } 672 snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]); 673 return wpa_ctrl_command(ctrl, cmd); 674 } 675 676 677 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl) 678 { 679 struct dirent *dent; 680 DIR *dir; 681 682 dir = opendir(ctrl_iface_dir); 683 if (dir == NULL) { 684 printf("Control interface directory '%s' could not be " 685 "openned.\n", ctrl_iface_dir); 686 return; 687 } 688 689 printf("Available interfaces:\n"); 690 while ((dent = readdir(dir))) { 691 if (strcmp(dent->d_name, ".") == 0 || 692 strcmp(dent->d_name, "..") == 0) 693 continue; 694 printf("%s\n", dent->d_name); 695 } 696 closedir(dir); 697 } 698 699 700 static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc, 701 char *argv[]) 702 { 703 if (argc < 1) { 704 hostapd_cli_list_interfaces(ctrl); 705 return 0; 706 } 707 708 hostapd_cli_close_connection(); 709 free(ctrl_ifname); 710 ctrl_ifname = strdup(argv[0]); 711 712 if (hostapd_cli_open_connection(ctrl_ifname)) { 713 printf("Connected to interface '%s.\n", ctrl_ifname); 714 if (wpa_ctrl_attach(ctrl_conn) == 0) { 715 hostapd_cli_attached = 1; 716 } else { 717 printf("Warning: Failed to attach to " 718 "hostapd.\n"); 719 } 720 } else { 721 printf("Could not connect to interface '%s' - re-trying\n", 722 ctrl_ifname); 723 } 724 return 0; 725 } 726 727 728 static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[]) 729 { 730 char cmd[256]; 731 int res; 732 733 if (argc != 2) { 734 printf("Invalid SET command: needs two arguments (variable " 735 "name and value)\n"); 736 return -1; 737 } 738 739 res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]); 740 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { 741 printf("Too long SET command.\n"); 742 return -1; 743 } 744 return wpa_ctrl_command(ctrl, cmd); 745 } 746 747 748 static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[]) 749 { 750 char cmd[256]; 751 int res; 752 753 if (argc != 1) { 754 printf("Invalid GET command: needs one argument (variable " 755 "name)\n"); 756 return -1; 757 } 758 759 res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]); 760 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { 761 printf("Too long GET command.\n"); 762 return -1; 763 } 764 return wpa_ctrl_command(ctrl, cmd); 765 } 766 767 768 struct hostapd_cli_cmd { 769 const char *cmd; 770 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]); 771 }; 772 773 static struct hostapd_cli_cmd hostapd_cli_commands[] = { 774 { "ping", hostapd_cli_cmd_ping }, 775 { "mib", hostapd_cli_cmd_mib }, 776 { "relog", hostapd_cli_cmd_relog }, 777 { "sta", hostapd_cli_cmd_sta }, 778 { "all_sta", hostapd_cli_cmd_all_sta }, 779 { "new_sta", hostapd_cli_cmd_new_sta }, 780 { "deauthenticate", hostapd_cli_cmd_deauthenticate }, 781 { "disassociate", hostapd_cli_cmd_disassociate }, 782 #ifdef CONFIG_IEEE80211W 783 { "sa_query", hostapd_cli_cmd_sa_query }, 784 #endif /* CONFIG_IEEE80211W */ 785 #ifdef CONFIG_WPS 786 { "wps_pin", hostapd_cli_cmd_wps_pin }, 787 { "wps_check_pin", hostapd_cli_cmd_wps_check_pin }, 788 { "wps_pbc", hostapd_cli_cmd_wps_pbc }, 789 { "wps_cancel", hostapd_cli_cmd_wps_cancel }, 790 #ifdef CONFIG_WPS_NFC 791 { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read }, 792 { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token }, 793 { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token }, 794 #endif /* CONFIG_WPS_NFC */ 795 { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin }, 796 { "wps_config", hostapd_cli_cmd_wps_config }, 797 #endif /* CONFIG_WPS */ 798 { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent }, 799 { "ess_disassoc", hostapd_cli_cmd_ess_disassoc }, 800 { "get_config", hostapd_cli_cmd_get_config }, 801 { "help", hostapd_cli_cmd_help }, 802 { "interface", hostapd_cli_cmd_interface }, 803 { "level", hostapd_cli_cmd_level }, 804 { "license", hostapd_cli_cmd_license }, 805 { "quit", hostapd_cli_cmd_quit }, 806 { "set", hostapd_cli_cmd_set }, 807 { "get", hostapd_cli_cmd_get }, 808 { NULL, NULL } 809 }; 810 811 812 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[]) 813 { 814 struct hostapd_cli_cmd *cmd, *match = NULL; 815 int count; 816 817 count = 0; 818 cmd = hostapd_cli_commands; 819 while (cmd->cmd) { 820 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) { 821 match = cmd; 822 if (os_strcasecmp(cmd->cmd, argv[0]) == 0) { 823 /* we have an exact match */ 824 count = 1; 825 break; 826 } 827 count++; 828 } 829 cmd++; 830 } 831 832 if (count > 1) { 833 printf("Ambiguous command '%s'; possible commands:", argv[0]); 834 cmd = hostapd_cli_commands; 835 while (cmd->cmd) { 836 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 837 0) { 838 printf(" %s", cmd->cmd); 839 } 840 cmd++; 841 } 842 printf("\n"); 843 } else if (count == 0) { 844 printf("Unknown command '%s'\n", argv[0]); 845 } else { 846 match->handler(ctrl, argc - 1, &argv[1]); 847 } 848 } 849 850 851 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read, 852 int action_monitor) 853 { 854 int first = 1; 855 if (ctrl_conn == NULL) 856 return; 857 while (wpa_ctrl_pending(ctrl)) { 858 char buf[256]; 859 size_t len = sizeof(buf) - 1; 860 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) { 861 buf[len] = '\0'; 862 if (action_monitor) 863 hostapd_cli_action_process(buf, len); 864 else { 865 if (in_read && first) 866 printf("\n"); 867 first = 0; 868 printf("%s\n", buf); 869 } 870 } else { 871 printf("Could not read pending message.\n"); 872 break; 873 } 874 } 875 } 876 877 878 #define max_args 10 879 880 static int tokenize_cmd(char *cmd, char *argv[]) 881 { 882 char *pos; 883 int argc = 0; 884 885 pos = cmd; 886 for (;;) { 887 while (*pos == ' ') 888 pos++; 889 if (*pos == '\0') 890 break; 891 argv[argc] = pos; 892 argc++; 893 if (argc == max_args) 894 break; 895 if (*pos == '"') { 896 char *pos2 = os_strrchr(pos, '"'); 897 if (pos2) 898 pos = pos2 + 1; 899 } 900 while (*pos != '\0' && *pos != ' ') 901 pos++; 902 if (*pos == ' ') 903 *pos++ = '\0'; 904 } 905 906 return argc; 907 } 908 909 910 static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx) 911 { 912 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) { 913 printf("Connection to hostapd lost - trying to reconnect\n"); 914 hostapd_cli_close_connection(); 915 } 916 if (!ctrl_conn) { 917 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname); 918 if (ctrl_conn) { 919 printf("Connection to hostapd re-established\n"); 920 if (wpa_ctrl_attach(ctrl_conn) == 0) { 921 hostapd_cli_attached = 1; 922 } else { 923 printf("Warning: Failed to attach to " 924 "hostapd.\n"); 925 } 926 } 927 } 928 if (ctrl_conn) 929 hostapd_cli_recv_pending(ctrl_conn, 1, 0); 930 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL); 931 } 932 933 934 static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx) 935 { 936 eloop_terminate(); 937 } 938 939 940 static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd) 941 { 942 char *argv[max_args]; 943 int argc; 944 argc = tokenize_cmd(cmd, argv); 945 if (argc) 946 wpa_request(ctrl_conn, argc, argv); 947 } 948 949 950 static void hostapd_cli_edit_eof_cb(void *ctx) 951 { 952 eloop_terminate(); 953 } 954 955 956 static void hostapd_cli_interactive(void) 957 { 958 printf("\nInteractive mode\n\n"); 959 960 eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL); 961 edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb, 962 NULL, NULL, NULL, NULL); 963 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL); 964 965 eloop_run(); 966 967 edit_deinit(NULL, NULL); 968 eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL); 969 } 970 971 972 static void hostapd_cli_cleanup(void) 973 { 974 hostapd_cli_close_connection(); 975 if (pid_file) 976 os_daemonize_terminate(pid_file); 977 978 os_program_deinit(); 979 } 980 981 982 static void hostapd_cli_action(struct wpa_ctrl *ctrl) 983 { 984 fd_set rfds; 985 int fd, res; 986 struct timeval tv; 987 char buf[256]; 988 size_t len; 989 990 fd = wpa_ctrl_get_fd(ctrl); 991 992 while (!hostapd_cli_quit) { 993 FD_ZERO(&rfds); 994 FD_SET(fd, &rfds); 995 tv.tv_sec = ping_interval; 996 tv.tv_usec = 0; 997 res = select(fd + 1, &rfds, NULL, NULL, &tv); 998 if (res < 0 && errno != EINTR) { 999 perror("select"); 1000 break; 1001 } 1002 1003 if (FD_ISSET(fd, &rfds)) 1004 hostapd_cli_recv_pending(ctrl, 0, 1); 1005 else { 1006 len = sizeof(buf) - 1; 1007 if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len, 1008 hostapd_cli_action_process) < 0 || 1009 len < 4 || os_memcmp(buf, "PONG", 4) != 0) { 1010 printf("hostapd did not reply to PING " 1011 "command - exiting\n"); 1012 break; 1013 } 1014 } 1015 } 1016 } 1017 1018 1019 int main(int argc, char *argv[]) 1020 { 1021 int warning_displayed = 0; 1022 int c; 1023 int daemonize = 0; 1024 1025 if (os_program_init()) 1026 return -1; 1027 1028 for (;;) { 1029 c = getopt(argc, argv, "a:BhG:i:p:v"); 1030 if (c < 0) 1031 break; 1032 switch (c) { 1033 case 'a': 1034 action_file = optarg; 1035 break; 1036 case 'B': 1037 daemonize = 1; 1038 break; 1039 case 'G': 1040 ping_interval = atoi(optarg); 1041 break; 1042 case 'h': 1043 usage(); 1044 return 0; 1045 case 'v': 1046 printf("%s\n", hostapd_cli_version); 1047 return 0; 1048 case 'i': 1049 os_free(ctrl_ifname); 1050 ctrl_ifname = os_strdup(optarg); 1051 break; 1052 case 'p': 1053 ctrl_iface_dir = optarg; 1054 break; 1055 default: 1056 usage(); 1057 return -1; 1058 } 1059 } 1060 1061 interactive = (argc == optind) && (action_file == NULL); 1062 1063 if (interactive) { 1064 printf("%s\n\n%s\n\n", hostapd_cli_version, 1065 hostapd_cli_license); 1066 } 1067 1068 if (eloop_init()) 1069 return -1; 1070 1071 for (;;) { 1072 if (ctrl_ifname == NULL) { 1073 struct dirent *dent; 1074 DIR *dir = opendir(ctrl_iface_dir); 1075 if (dir) { 1076 while ((dent = readdir(dir))) { 1077 if (os_strcmp(dent->d_name, ".") == 0 1078 || 1079 os_strcmp(dent->d_name, "..") == 0) 1080 continue; 1081 printf("Selected interface '%s'\n", 1082 dent->d_name); 1083 ctrl_ifname = os_strdup(dent->d_name); 1084 break; 1085 } 1086 closedir(dir); 1087 } 1088 } 1089 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname); 1090 if (ctrl_conn) { 1091 if (warning_displayed) 1092 printf("Connection established.\n"); 1093 break; 1094 } 1095 1096 if (!interactive) { 1097 perror("Failed to connect to hostapd - " 1098 "wpa_ctrl_open"); 1099 return -1; 1100 } 1101 1102 if (!warning_displayed) { 1103 printf("Could not connect to hostapd - re-trying\n"); 1104 warning_displayed = 1; 1105 } 1106 os_sleep(1, 0); 1107 continue; 1108 } 1109 1110 if (interactive || action_file) { 1111 if (wpa_ctrl_attach(ctrl_conn) == 0) { 1112 hostapd_cli_attached = 1; 1113 } else { 1114 printf("Warning: Failed to attach to hostapd.\n"); 1115 if (action_file) 1116 return -1; 1117 } 1118 } 1119 1120 if (daemonize && os_daemonize(pid_file)) 1121 return -1; 1122 1123 if (interactive) 1124 hostapd_cli_interactive(); 1125 else if (action_file) 1126 hostapd_cli_action(ctrl_conn); 1127 else 1128 wpa_request(ctrl_conn, argc - optind, &argv[optind]); 1129 1130 os_free(ctrl_ifname); 1131 eloop_destroy(); 1132 hostapd_cli_cleanup(); 1133 return 0; 1134 } 1135