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