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