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