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