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