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