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