1 /* 2 * hostapd - command line interface for hostapd daemon 3 * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9 #include "includes.h" 10 #include <dirent.h> 11 12 #include "common/wpa_ctrl.h" 13 #include "common/ieee802_11_defs.h" 14 #include "utils/common.h" 15 #include "utils/eloop.h" 16 #include "utils/edit.h" 17 #include "common/version.h" 18 #include "common/cli.h" 19 20 #ifndef CONFIG_NO_CTRL_IFACE 21 22 static const char *const hostapd_cli_version = 23 "hostapd_cli v" VERSION_STR "\n" 24 "Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> and contributors"; 25 26 static struct wpa_ctrl *ctrl_conn; 27 static int hostapd_cli_quit = 0; 28 static int hostapd_cli_attached = 0; 29 30 #ifndef CONFIG_CTRL_IFACE_DIR 31 #define CONFIG_CTRL_IFACE_DIR "/var/run/hostapd" 32 #endif /* CONFIG_CTRL_IFACE_DIR */ 33 static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR; 34 static const char *client_socket_dir = NULL; 35 36 static char *ctrl_ifname = NULL; 37 static const char *pid_file = NULL; 38 static const char *action_file = NULL; 39 static int ping_interval = 5; 40 static int interactive = 0; 41 static int event_handler_registered = 0; 42 43 static DEFINE_DL_LIST(stations); /* struct cli_txt_entry */ 44 45 static void print_help(FILE *stream, const char *cmd); 46 static char ** list_cmd_list(void); 47 static void hostapd_cli_receive(int sock, void *eloop_ctx, void *sock_ctx); 48 49 50 static void usage(void) 51 { 52 fprintf(stderr, "%s\n", hostapd_cli_version); 53 fprintf(stderr, 54 "\n" 55 "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] " 56 "[-a<path>] \\\n" 57 " [-P<pid file>] [-G<ping interval>] [command..]\n" 58 "\n" 59 "Options:\n" 60 " -h help (show this usage text)\n" 61 " -v shown version information\n" 62 " -p<path> path to find control sockets (default: " 63 "/var/run/hostapd)\n" 64 " -s<dir_path> dir path to open client sockets (default: " 65 CONFIG_CTRL_IFACE_DIR ")\n" 66 " -a<file> run in daemon mode executing the action file " 67 "based on events\n" 68 " from hostapd\n" 69 " -B run a daemon in the background\n" 70 " -i<ifname> Interface to listen on (default: first " 71 "interface found in the\n" 72 " socket path)\n\n"); 73 print_help(stderr, NULL); 74 } 75 76 77 static void register_event_handler(struct wpa_ctrl *ctrl) 78 { 79 if (!ctrl_conn) 80 return; 81 if (interactive) { 82 event_handler_registered = 83 !eloop_register_read_sock(wpa_ctrl_get_fd(ctrl), 84 hostapd_cli_receive, 85 NULL, NULL); 86 } 87 } 88 89 90 static void unregister_event_handler(struct wpa_ctrl *ctrl) 91 { 92 if (!ctrl_conn) 93 return; 94 if (interactive && event_handler_registered) { 95 eloop_unregister_read_sock(wpa_ctrl_get_fd(ctrl)); 96 event_handler_registered = 0; 97 } 98 } 99 100 101 static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname) 102 { 103 #ifndef CONFIG_CTRL_IFACE_UDP 104 char *cfile; 105 int flen; 106 #endif /* !CONFIG_CTRL_IFACE_UDP */ 107 108 if (ifname == NULL) 109 return NULL; 110 111 #ifdef CONFIG_CTRL_IFACE_UDP 112 ctrl_conn = wpa_ctrl_open(ifname); 113 return ctrl_conn; 114 #else /* CONFIG_CTRL_IFACE_UDP */ 115 flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2; 116 cfile = malloc(flen); 117 if (cfile == NULL) 118 return NULL; 119 snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname); 120 121 if (client_socket_dir && client_socket_dir[0] && 122 access(client_socket_dir, F_OK) < 0) { 123 perror(client_socket_dir); 124 free(cfile); 125 return NULL; 126 } 127 128 ctrl_conn = wpa_ctrl_open2(cfile, client_socket_dir); 129 free(cfile); 130 return ctrl_conn; 131 #endif /* CONFIG_CTRL_IFACE_UDP */ 132 } 133 134 135 static void hostapd_cli_close_connection(void) 136 { 137 if (ctrl_conn == NULL) 138 return; 139 140 unregister_event_handler(ctrl_conn); 141 if (hostapd_cli_attached) { 142 wpa_ctrl_detach(ctrl_conn); 143 hostapd_cli_attached = 0; 144 } 145 wpa_ctrl_close(ctrl_conn); 146 ctrl_conn = NULL; 147 } 148 149 150 static void hostapd_cli_msg_cb(char *msg, size_t len) 151 { 152 printf("%s\n", msg); 153 } 154 155 156 static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print) 157 { 158 char buf[4096]; 159 size_t len; 160 int ret; 161 162 if (ctrl_conn == NULL) { 163 printf("Not connected to hostapd - command dropped.\n"); 164 return -1; 165 } 166 len = sizeof(buf) - 1; 167 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len, 168 hostapd_cli_msg_cb); 169 if (ret == -2) { 170 printf("'%s' command timed out.\n", cmd); 171 return -2; 172 } else if (ret < 0) { 173 printf("'%s' command failed.\n", cmd); 174 return -1; 175 } 176 if (print) { 177 buf[len] = '\0'; 178 printf("%s", buf); 179 } 180 return 0; 181 } 182 183 184 static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd) 185 { 186 return _wpa_ctrl_command(ctrl, cmd, 1); 187 } 188 189 190 static int hostapd_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd, 191 int min_args, int argc, char *argv[]) 192 { 193 char buf[4096]; 194 195 if (argc < min_args) { 196 printf("Invalid %s command - at least %d argument%s required.\n", 197 cmd, min_args, min_args > 1 ? "s are" : " is"); 198 return -1; 199 } 200 if (write_cmd(buf, sizeof(buf), cmd, argc, argv) < 0) 201 return -1; 202 return wpa_ctrl_command(ctrl, buf); 203 } 204 205 206 static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[]) 207 { 208 return wpa_ctrl_command(ctrl, "PING"); 209 } 210 211 212 static int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[]) 213 { 214 return wpa_ctrl_command(ctrl, "RELOG"); 215 } 216 217 218 static int hostapd_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[]) 219 { 220 if (argc > 0 && os_strcmp(argv[0], "driver") == 0) 221 return wpa_ctrl_command(ctrl, "STATUS-DRIVER"); 222 return wpa_ctrl_command(ctrl, "STATUS"); 223 } 224 225 226 static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[]) 227 { 228 if (argc > 0) { 229 char buf[100]; 230 os_snprintf(buf, sizeof(buf), "MIB %s", argv[0]); 231 return wpa_ctrl_command(ctrl, buf); 232 } 233 return wpa_ctrl_command(ctrl, "MIB"); 234 } 235 236 237 static int hostapd_cli_exec(const char *program, const char *arg1, 238 const char *arg2) 239 { 240 char *arg; 241 size_t len; 242 int res; 243 244 len = os_strlen(arg1) + os_strlen(arg2) + 2; 245 arg = os_malloc(len); 246 if (arg == NULL) 247 return -1; 248 os_snprintf(arg, len, "%s %s", arg1, arg2); 249 res = os_exec(program, arg, 1); 250 os_free(arg); 251 252 return res; 253 } 254 255 256 static void hostapd_cli_action_process(char *msg, size_t len) 257 { 258 const char *pos; 259 260 pos = msg; 261 if (*pos == '<') { 262 pos = os_strchr(pos, '>'); 263 if (pos) 264 pos++; 265 else 266 pos = msg; 267 } 268 269 hostapd_cli_exec(action_file, ctrl_ifname, pos); 270 } 271 272 273 static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[]) 274 { 275 char buf[64]; 276 if (argc < 1) { 277 printf("Invalid 'sta' command - at least one argument, STA " 278 "address, is required.\n"); 279 return -1; 280 } 281 if (argc > 1) 282 snprintf(buf, sizeof(buf), "STA %s %s", argv[0], argv[1]); 283 else 284 snprintf(buf, sizeof(buf), "STA %s", argv[0]); 285 return wpa_ctrl_command(ctrl, buf); 286 } 287 288 289 static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc, 290 char *argv[]) 291 { 292 char buf[64]; 293 if (argc != 1) { 294 printf("Invalid 'new_sta' command - exactly one argument, STA " 295 "address, is required.\n"); 296 return -1; 297 } 298 snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]); 299 return wpa_ctrl_command(ctrl, buf); 300 } 301 302 303 static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc, 304 char *argv[]) 305 { 306 char buf[64]; 307 if (argc < 1) { 308 printf("Invalid 'deauthenticate' command - exactly one " 309 "argument, STA address, is required.\n"); 310 return -1; 311 } 312 if (argc > 1) 313 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s", 314 argv[0], argv[1]); 315 else 316 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]); 317 return wpa_ctrl_command(ctrl, buf); 318 } 319 320 321 static char ** hostapd_complete_deauthenticate(const char *str, int pos) 322 { 323 int arg = get_cmd_arg_num(str, pos); 324 char **res = NULL; 325 326 switch (arg) { 327 case 1: 328 res = cli_txt_list_array(&stations); 329 break; 330 } 331 332 return res; 333 } 334 335 336 static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc, 337 char *argv[]) 338 { 339 char buf[64]; 340 if (argc < 1) { 341 printf("Invalid 'disassociate' command - exactly one " 342 "argument, STA address, is required.\n"); 343 return -1; 344 } 345 if (argc > 1) 346 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s", 347 argv[0], argv[1]); 348 else 349 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]); 350 return wpa_ctrl_command(ctrl, buf); 351 } 352 353 354 static char ** hostapd_complete_disassociate(const char *str, int pos) 355 { 356 int arg = get_cmd_arg_num(str, pos); 357 char **res = NULL; 358 359 switch (arg) { 360 case 1: 361 res = cli_txt_list_array(&stations); 362 break; 363 } 364 365 return res; 366 } 367 368 369 #ifdef CONFIG_TAXONOMY 370 static int hostapd_cli_cmd_signature(struct wpa_ctrl *ctrl, int argc, 371 char *argv[]) 372 { 373 char buf[64]; 374 375 if (argc != 1) { 376 printf("Invalid 'signature' command - exactly one argument, STA address, is required.\n"); 377 return -1; 378 } 379 os_snprintf(buf, sizeof(buf), "SIGNATURE %s", argv[0]); 380 return wpa_ctrl_command(ctrl, buf); 381 } 382 #endif /* CONFIG_TAXONOMY */ 383 384 385 #ifdef CONFIG_IEEE80211W 386 static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc, 387 char *argv[]) 388 { 389 char buf[64]; 390 if (argc != 1) { 391 printf("Invalid 'sa_query' command - exactly one argument, " 392 "STA address, is required.\n"); 393 return -1; 394 } 395 snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]); 396 return wpa_ctrl_command(ctrl, buf); 397 } 398 #endif /* CONFIG_IEEE80211W */ 399 400 401 #ifdef CONFIG_WPS 402 static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, 403 char *argv[]) 404 { 405 char buf[256]; 406 if (argc < 2) { 407 printf("Invalid 'wps_pin' command - at least two arguments, " 408 "UUID and PIN, are required.\n"); 409 return -1; 410 } 411 if (argc > 3) 412 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s %s", 413 argv[0], argv[1], argv[2], argv[3]); 414 else if (argc > 2) 415 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s", 416 argv[0], argv[1], argv[2]); 417 else 418 snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]); 419 return wpa_ctrl_command(ctrl, buf); 420 } 421 422 423 static int hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc, 424 char *argv[]) 425 { 426 char cmd[256]; 427 int res; 428 429 if (argc != 1 && argc != 2) { 430 printf("Invalid WPS_CHECK_PIN command: needs one argument:\n" 431 "- PIN to be verified\n"); 432 return -1; 433 } 434 435 if (argc == 2) 436 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s", 437 argv[0], argv[1]); 438 else 439 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s", 440 argv[0]); 441 if (os_snprintf_error(sizeof(cmd), res)) { 442 printf("Too long WPS_CHECK_PIN command.\n"); 443 return -1; 444 } 445 return wpa_ctrl_command(ctrl, cmd); 446 } 447 448 449 static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc, 450 char *argv[]) 451 { 452 return wpa_ctrl_command(ctrl, "WPS_PBC"); 453 } 454 455 456 static int hostapd_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc, 457 char *argv[]) 458 { 459 return wpa_ctrl_command(ctrl, "WPS_CANCEL"); 460 } 461 462 463 #ifdef CONFIG_WPS_NFC 464 static int hostapd_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc, 465 char *argv[]) 466 { 467 int ret; 468 char *buf; 469 size_t buflen; 470 471 if (argc != 1) { 472 printf("Invalid 'wps_nfc_tag_read' command - one argument " 473 "is required.\n"); 474 return -1; 475 } 476 477 buflen = 18 + os_strlen(argv[0]); 478 buf = os_malloc(buflen); 479 if (buf == NULL) 480 return -1; 481 os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]); 482 483 ret = wpa_ctrl_command(ctrl, buf); 484 os_free(buf); 485 486 return ret; 487 } 488 489 490 static int hostapd_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl, 491 int argc, char *argv[]) 492 { 493 char cmd[64]; 494 int res; 495 496 if (argc != 1) { 497 printf("Invalid 'wps_nfc_config_token' command - one argument " 498 "is required.\n"); 499 return -1; 500 } 501 502 res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_CONFIG_TOKEN %s", 503 argv[0]); 504 if (os_snprintf_error(sizeof(cmd), res)) { 505 printf("Too long WPS_NFC_CONFIG_TOKEN command.\n"); 506 return -1; 507 } 508 return wpa_ctrl_command(ctrl, cmd); 509 } 510 511 512 static int hostapd_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl, 513 int argc, char *argv[]) 514 { 515 char cmd[64]; 516 int res; 517 518 if (argc != 1) { 519 printf("Invalid 'wps_nfc_token' command - one argument is " 520 "required.\n"); 521 return -1; 522 } 523 524 res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s", argv[0]); 525 if (os_snprintf_error(sizeof(cmd), res)) { 526 printf("Too long WPS_NFC_TOKEN command.\n"); 527 return -1; 528 } 529 return wpa_ctrl_command(ctrl, cmd); 530 } 531 532 533 static int hostapd_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl, 534 int argc, char *argv[]) 535 { 536 char cmd[64]; 537 int res; 538 539 if (argc != 2) { 540 printf("Invalid 'nfc_get_handover_sel' command - two arguments " 541 "are required.\n"); 542 return -1; 543 } 544 545 res = os_snprintf(cmd, sizeof(cmd), "NFC_GET_HANDOVER_SEL %s %s", 546 argv[0], argv[1]); 547 if (os_snprintf_error(sizeof(cmd), res)) { 548 printf("Too long NFC_GET_HANDOVER_SEL command.\n"); 549 return -1; 550 } 551 return wpa_ctrl_command(ctrl, cmd); 552 } 553 554 #endif /* CONFIG_WPS_NFC */ 555 556 557 static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc, 558 char *argv[]) 559 { 560 char buf[64]; 561 if (argc < 1) { 562 printf("Invalid 'wps_ap_pin' command - at least one argument " 563 "is required.\n"); 564 return -1; 565 } 566 if (argc > 2) 567 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s", 568 argv[0], argv[1], argv[2]); 569 else if (argc > 1) 570 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s", 571 argv[0], argv[1]); 572 else 573 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]); 574 return wpa_ctrl_command(ctrl, buf); 575 } 576 577 578 static int hostapd_cli_cmd_wps_get_status(struct wpa_ctrl *ctrl, int argc, 579 char *argv[]) 580 { 581 return wpa_ctrl_command(ctrl, "WPS_GET_STATUS"); 582 } 583 584 585 static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc, 586 char *argv[]) 587 { 588 char buf[256]; 589 char ssid_hex[2 * SSID_MAX_LEN + 1]; 590 char key_hex[2 * 64 + 1]; 591 int i; 592 593 if (argc < 1) { 594 printf("Invalid 'wps_config' command - at least two arguments " 595 "are required.\n"); 596 return -1; 597 } 598 599 ssid_hex[0] = '\0'; 600 for (i = 0; i < SSID_MAX_LEN; i++) { 601 if (argv[0][i] == '\0') 602 break; 603 os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]); 604 } 605 606 key_hex[0] = '\0'; 607 if (argc > 3) { 608 for (i = 0; i < 64; i++) { 609 if (argv[3][i] == '\0') 610 break; 611 os_snprintf(&key_hex[i * 2], 3, "%02x", 612 argv[3][i]); 613 } 614 } 615 616 if (argc > 3) 617 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s %s", 618 ssid_hex, argv[1], argv[2], key_hex); 619 else if (argc > 2) 620 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s", 621 ssid_hex, argv[1], argv[2]); 622 else 623 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s", 624 ssid_hex, argv[1]); 625 return wpa_ctrl_command(ctrl, buf); 626 } 627 #endif /* CONFIG_WPS */ 628 629 630 static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc, 631 char *argv[]) 632 { 633 char buf[300]; 634 int res; 635 636 if (argc < 2) { 637 printf("Invalid 'disassoc_imminent' command - two arguments " 638 "(STA addr and Disassociation Timer) are needed\n"); 639 return -1; 640 } 641 642 res = os_snprintf(buf, sizeof(buf), "DISASSOC_IMMINENT %s %s", 643 argv[0], argv[1]); 644 if (os_snprintf_error(sizeof(buf), res)) 645 return -1; 646 return wpa_ctrl_command(ctrl, buf); 647 } 648 649 650 static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc, 651 char *argv[]) 652 { 653 char buf[300]; 654 int res; 655 656 if (argc < 3) { 657 printf("Invalid 'ess_disassoc' command - three arguments (STA " 658 "addr, disassoc timer, and URL) are needed\n"); 659 return -1; 660 } 661 662 res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s %s", 663 argv[0], argv[1], argv[2]); 664 if (os_snprintf_error(sizeof(buf), res)) 665 return -1; 666 return wpa_ctrl_command(ctrl, buf); 667 } 668 669 670 static int hostapd_cli_cmd_bss_tm_req(struct wpa_ctrl *ctrl, int argc, 671 char *argv[]) 672 { 673 char buf[2000], *tmp; 674 int res, i, total; 675 676 if (argc < 1) { 677 printf("Invalid 'bss_tm_req' command - at least one argument (STA addr) is needed\n"); 678 return -1; 679 } 680 681 res = os_snprintf(buf, sizeof(buf), "BSS_TM_REQ %s", argv[0]); 682 if (os_snprintf_error(sizeof(buf), res)) 683 return -1; 684 685 total = res; 686 for (i = 1; i < argc; i++) { 687 tmp = &buf[total]; 688 res = os_snprintf(tmp, sizeof(buf) - total, " %s", argv[i]); 689 if (os_snprintf_error(sizeof(buf) - total, res)) 690 return -1; 691 total += res; 692 } 693 return wpa_ctrl_command(ctrl, buf); 694 } 695 696 697 static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc, 698 char *argv[]) 699 { 700 return wpa_ctrl_command(ctrl, "GET_CONFIG"); 701 } 702 703 704 static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd, 705 char *addr, size_t addr_len) 706 { 707 char buf[4096], *pos; 708 size_t len; 709 int ret; 710 711 if (ctrl_conn == NULL) { 712 printf("Not connected to hostapd - command dropped.\n"); 713 return -1; 714 } 715 len = sizeof(buf) - 1; 716 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len, 717 hostapd_cli_msg_cb); 718 if (ret == -2) { 719 printf("'%s' command timed out.\n", cmd); 720 return -2; 721 } else if (ret < 0) { 722 printf("'%s' command failed.\n", cmd); 723 return -1; 724 } 725 726 buf[len] = '\0'; 727 if (memcmp(buf, "FAIL", 4) == 0) 728 return -1; 729 printf("%s", buf); 730 731 pos = buf; 732 while (*pos != '\0' && *pos != '\n') 733 pos++; 734 *pos = '\0'; 735 os_strlcpy(addr, buf, addr_len); 736 return 0; 737 } 738 739 740 static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, 741 char *argv[]) 742 { 743 char addr[32], cmd[64]; 744 745 if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr))) 746 return 0; 747 do { 748 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr); 749 } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0); 750 751 return -1; 752 } 753 754 755 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[]) 756 { 757 print_help(stdout, argc > 0 ? argv[0] : NULL); 758 return 0; 759 } 760 761 762 static char ** hostapd_cli_complete_help(const char *str, int pos) 763 { 764 int arg = get_cmd_arg_num(str, pos); 765 char **res = NULL; 766 767 switch (arg) { 768 case 1: 769 res = list_cmd_list(); 770 break; 771 } 772 773 return res; 774 } 775 776 777 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, 778 char *argv[]) 779 { 780 printf("%s\n\n%s\n", hostapd_cli_version, cli_full_license); 781 return 0; 782 } 783 784 785 static int hostapd_cli_cmd_set_qos_map_set(struct wpa_ctrl *ctrl, 786 int argc, char *argv[]) 787 { 788 char buf[200]; 789 int res; 790 791 if (argc != 1) { 792 printf("Invalid 'set_qos_map_set' command - " 793 "one argument (comma delimited QoS map set) " 794 "is needed\n"); 795 return -1; 796 } 797 798 res = os_snprintf(buf, sizeof(buf), "SET_QOS_MAP_SET %s", argv[0]); 799 if (os_snprintf_error(sizeof(buf), res)) 800 return -1; 801 return wpa_ctrl_command(ctrl, buf); 802 } 803 804 805 static int hostapd_cli_cmd_send_qos_map_conf(struct wpa_ctrl *ctrl, 806 int argc, char *argv[]) 807 { 808 char buf[50]; 809 int res; 810 811 if (argc != 1) { 812 printf("Invalid 'send_qos_map_conf' command - " 813 "one argument (STA addr) is needed\n"); 814 return -1; 815 } 816 817 res = os_snprintf(buf, sizeof(buf), "SEND_QOS_MAP_CONF %s", argv[0]); 818 if (os_snprintf_error(sizeof(buf), res)) 819 return -1; 820 return wpa_ctrl_command(ctrl, buf); 821 } 822 823 824 static int hostapd_cli_cmd_hs20_wnm_notif(struct wpa_ctrl *ctrl, int argc, 825 char *argv[]) 826 { 827 char buf[300]; 828 int res; 829 830 if (argc < 2) { 831 printf("Invalid 'hs20_wnm_notif' command - two arguments (STA " 832 "addr and URL) are needed\n"); 833 return -1; 834 } 835 836 res = os_snprintf(buf, sizeof(buf), "HS20_WNM_NOTIF %s %s", 837 argv[0], argv[1]); 838 if (os_snprintf_error(sizeof(buf), res)) 839 return -1; 840 return wpa_ctrl_command(ctrl, buf); 841 } 842 843 844 static int hostapd_cli_cmd_hs20_deauth_req(struct wpa_ctrl *ctrl, int argc, 845 char *argv[]) 846 { 847 char buf[300]; 848 int res; 849 850 if (argc < 3) { 851 printf("Invalid 'hs20_deauth_req' command - at least three arguments (STA addr, Code, Re-auth Delay) are needed\n"); 852 return -1; 853 } 854 855 if (argc > 3) 856 res = os_snprintf(buf, sizeof(buf), 857 "HS20_DEAUTH_REQ %s %s %s %s", 858 argv[0], argv[1], argv[2], argv[3]); 859 else 860 res = os_snprintf(buf, sizeof(buf), 861 "HS20_DEAUTH_REQ %s %s %s", 862 argv[0], argv[1], argv[2]); 863 if (os_snprintf_error(sizeof(buf), res)) 864 return -1; 865 return wpa_ctrl_command(ctrl, buf); 866 } 867 868 869 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[]) 870 { 871 hostapd_cli_quit = 1; 872 if (interactive) 873 eloop_terminate(); 874 return 0; 875 } 876 877 878 static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[]) 879 { 880 char cmd[256]; 881 if (argc != 1) { 882 printf("Invalid LEVEL command: needs one argument (debug " 883 "level)\n"); 884 return 0; 885 } 886 snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]); 887 return wpa_ctrl_command(ctrl, cmd); 888 } 889 890 891 static void hostapd_cli_get_interfaces(struct wpa_ctrl *ctrl, 892 struct dl_list *interfaces) 893 { 894 struct dirent *dent; 895 DIR *dir; 896 897 if (!ctrl || !interfaces) 898 return; 899 dir = opendir(ctrl_iface_dir); 900 if (dir == NULL) 901 return; 902 903 while ((dent = readdir(dir))) { 904 if (strcmp(dent->d_name, ".") == 0 || 905 strcmp(dent->d_name, "..") == 0) 906 continue; 907 cli_txt_list_add(interfaces, dent->d_name); 908 } 909 closedir(dir); 910 } 911 912 913 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl) 914 { 915 struct dirent *dent; 916 DIR *dir; 917 918 dir = opendir(ctrl_iface_dir); 919 if (dir == NULL) { 920 printf("Control interface directory '%s' could not be " 921 "openned.\n", ctrl_iface_dir); 922 return; 923 } 924 925 printf("Available interfaces:\n"); 926 while ((dent = readdir(dir))) { 927 if (strcmp(dent->d_name, ".") == 0 || 928 strcmp(dent->d_name, "..") == 0) 929 continue; 930 printf("%s\n", dent->d_name); 931 } 932 closedir(dir); 933 } 934 935 936 static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc, 937 char *argv[]) 938 { 939 if (argc < 1) { 940 hostapd_cli_list_interfaces(ctrl); 941 return 0; 942 } 943 944 hostapd_cli_close_connection(); 945 os_free(ctrl_ifname); 946 ctrl_ifname = os_strdup(argv[0]); 947 if (ctrl_ifname == NULL) 948 return -1; 949 950 if (hostapd_cli_open_connection(ctrl_ifname)) { 951 printf("Connected to interface '%s.\n", ctrl_ifname); 952 if (wpa_ctrl_attach(ctrl_conn) == 0) { 953 hostapd_cli_attached = 1; 954 register_event_handler(ctrl_conn); 955 } else { 956 printf("Warning: Failed to attach to " 957 "hostapd.\n"); 958 } 959 } else { 960 printf("Could not connect to interface '%s' - re-trying\n", 961 ctrl_ifname); 962 } 963 return 0; 964 } 965 966 967 static char ** hostapd_complete_interface(const char *str, int pos) 968 { 969 int arg = get_cmd_arg_num(str, pos); 970 char **res = NULL; 971 DEFINE_DL_LIST(interfaces); 972 973 switch (arg) { 974 case 1: 975 hostapd_cli_get_interfaces(ctrl_conn, &interfaces); 976 res = cli_txt_list_array(&interfaces); 977 cli_txt_list_flush(&interfaces); 978 break; 979 } 980 981 return res; 982 } 983 984 985 static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[]) 986 { 987 char cmd[256]; 988 int res; 989 990 if (argc != 2) { 991 printf("Invalid SET command: needs two arguments (variable " 992 "name and value)\n"); 993 return -1; 994 } 995 996 res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]); 997 if (os_snprintf_error(sizeof(cmd), res)) { 998 printf("Too long SET command.\n"); 999 return -1; 1000 } 1001 return wpa_ctrl_command(ctrl, cmd); 1002 } 1003 1004 1005 static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1006 { 1007 char cmd[256]; 1008 int res; 1009 1010 if (argc != 1) { 1011 printf("Invalid GET command: needs one argument (variable " 1012 "name)\n"); 1013 return -1; 1014 } 1015 1016 res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]); 1017 if (os_snprintf_error(sizeof(cmd), res)) { 1018 printf("Too long GET command.\n"); 1019 return -1; 1020 } 1021 return wpa_ctrl_command(ctrl, cmd); 1022 } 1023 1024 1025 #ifdef CONFIG_FST 1026 static int hostapd_cli_cmd_fst(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1027 { 1028 char cmd[256]; 1029 int res; 1030 int i; 1031 int total; 1032 1033 if (argc <= 0) { 1034 printf("FST command: parameters are required.\n"); 1035 return -1; 1036 } 1037 1038 total = os_snprintf(cmd, sizeof(cmd), "FST-MANAGER"); 1039 1040 for (i = 0; i < argc; i++) { 1041 res = os_snprintf(cmd + total, sizeof(cmd) - total, " %s", 1042 argv[i]); 1043 if (os_snprintf_error(sizeof(cmd) - total, res)) { 1044 printf("Too long fst command.\n"); 1045 return -1; 1046 } 1047 total += res; 1048 } 1049 return wpa_ctrl_command(ctrl, cmd); 1050 } 1051 #endif /* CONFIG_FST */ 1052 1053 1054 static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl, 1055 int argc, char *argv[]) 1056 { 1057 char cmd[256]; 1058 int res; 1059 int i; 1060 char *tmp; 1061 int total; 1062 1063 if (argc < 2) { 1064 printf("Invalid chan_switch command: needs at least two " 1065 "arguments (count and freq)\n" 1066 "usage: <cs_count> <freq> [sec_channel_offset=] " 1067 "[center_freq1=] [center_freq2=] [bandwidth=] " 1068 "[blocktx] [ht|vht]\n"); 1069 return -1; 1070 } 1071 1072 res = os_snprintf(cmd, sizeof(cmd), "CHAN_SWITCH %s %s", 1073 argv[0], argv[1]); 1074 if (os_snprintf_error(sizeof(cmd), res)) { 1075 printf("Too long CHAN_SWITCH command.\n"); 1076 return -1; 1077 } 1078 1079 total = res; 1080 for (i = 2; i < argc; i++) { 1081 tmp = cmd + total; 1082 res = os_snprintf(tmp, sizeof(cmd) - total, " %s", argv[i]); 1083 if (os_snprintf_error(sizeof(cmd) - total, res)) { 1084 printf("Too long CHAN_SWITCH command.\n"); 1085 return -1; 1086 } 1087 total += res; 1088 } 1089 return wpa_ctrl_command(ctrl, cmd); 1090 } 1091 1092 1093 static int hostapd_cli_cmd_enable(struct wpa_ctrl *ctrl, int argc, 1094 char *argv[]) 1095 { 1096 return wpa_ctrl_command(ctrl, "ENABLE"); 1097 } 1098 1099 1100 static int hostapd_cli_cmd_reload(struct wpa_ctrl *ctrl, int argc, 1101 char *argv[]) 1102 { 1103 return wpa_ctrl_command(ctrl, "RELOAD"); 1104 } 1105 1106 1107 static int hostapd_cli_cmd_disable(struct wpa_ctrl *ctrl, int argc, 1108 char *argv[]) 1109 { 1110 return wpa_ctrl_command(ctrl, "DISABLE"); 1111 } 1112 1113 1114 static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1115 { 1116 char cmd[256]; 1117 int res; 1118 1119 if (argc < 2 || argc > 3) { 1120 printf("Invalid vendor command\n" 1121 "usage: <vendor id> <command id> [<hex formatted command argument>]\n"); 1122 return -1; 1123 } 1124 1125 res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s", argv[0], argv[1], 1126 argc == 3 ? argv[2] : ""); 1127 if (os_snprintf_error(sizeof(cmd), res)) { 1128 printf("Too long VENDOR command.\n"); 1129 return -1; 1130 } 1131 return wpa_ctrl_command(ctrl, cmd); 1132 } 1133 1134 1135 static int hostapd_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc, 1136 char *argv[]) 1137 { 1138 return wpa_ctrl_command(ctrl, "ERP_FLUSH"); 1139 } 1140 1141 1142 static int hostapd_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc, 1143 char *argv[]) 1144 { 1145 char cmd[256]; 1146 int res; 1147 1148 res = os_snprintf(cmd, sizeof(cmd), "LOG_LEVEL%s%s%s%s", 1149 argc >= 1 ? " " : "", 1150 argc >= 1 ? argv[0] : "", 1151 argc == 2 ? " " : "", 1152 argc == 2 ? argv[1] : ""); 1153 if (os_snprintf_error(sizeof(cmd), res)) { 1154 printf("Too long option\n"); 1155 return -1; 1156 } 1157 return wpa_ctrl_command(ctrl, cmd); 1158 } 1159 1160 1161 static int hostapd_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1162 { 1163 if (argc == 0) 1164 return -1; 1165 return hostapd_cli_cmd(ctrl, argv[0], 0, argc - 1, &argv[1]); 1166 } 1167 1168 1169 static int hostapd_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1170 { 1171 return wpa_ctrl_command(ctrl, "PMKSA"); 1172 } 1173 1174 1175 static int hostapd_cli_cmd_pmksa_flush(struct wpa_ctrl *ctrl, int argc, 1176 char *argv[]) 1177 { 1178 return wpa_ctrl_command(ctrl, "PMKSA_FLUSH"); 1179 } 1180 1181 1182 static int hostapd_cli_cmd_set_neighbor(struct wpa_ctrl *ctrl, int argc, 1183 char *argv[]) 1184 { 1185 char cmd[2048]; 1186 int res; 1187 1188 if (argc < 3 || argc > 5) { 1189 printf("Invalid set_neighbor command: needs 3-5 arguments\n"); 1190 return -1; 1191 } 1192 1193 res = os_snprintf(cmd, sizeof(cmd), "SET_NEIGHBOR %s %s %s %s %s", 1194 argv[0], argv[1], argv[2], argc >= 4 ? argv[3] : "", 1195 argc == 5 ? argv[4] : ""); 1196 if (os_snprintf_error(sizeof(cmd), res)) { 1197 printf("Too long SET_NEIGHBOR command.\n"); 1198 return -1; 1199 } 1200 return wpa_ctrl_command(ctrl, cmd); 1201 } 1202 1203 1204 static int hostapd_cli_cmd_remove_neighbor(struct wpa_ctrl *ctrl, int argc, 1205 char *argv[]) 1206 { 1207 char cmd[400]; 1208 int res; 1209 1210 if (argc != 2) { 1211 printf("Invalid remove_neighbor command: needs 2 arguments\n"); 1212 return -1; 1213 } 1214 1215 res = os_snprintf(cmd, sizeof(cmd), "REMOVE_NEIGHBOR %s %s", 1216 argv[0], argv[1]); 1217 if (os_snprintf_error(sizeof(cmd), res)) { 1218 printf("Too long REMOVE_NEIGHBOR command.\n"); 1219 return -1; 1220 } 1221 return wpa_ctrl_command(ctrl, cmd); 1222 } 1223 1224 1225 static int hostapd_cli_cmd_req_lci(struct wpa_ctrl *ctrl, int argc, 1226 char *argv[]) 1227 { 1228 char cmd[256]; 1229 int res; 1230 1231 if (argc != 1) { 1232 printf("Invalid req_lci command - requires destination address\n"); 1233 return -1; 1234 } 1235 1236 res = os_snprintf(cmd, sizeof(cmd), "REQ_LCI %s", argv[0]); 1237 if (os_snprintf_error(sizeof(cmd), res)) { 1238 printf("Too long REQ_LCI command.\n"); 1239 return -1; 1240 } 1241 return wpa_ctrl_command(ctrl, cmd); 1242 } 1243 1244 1245 static int hostapd_cli_cmd_req_range(struct wpa_ctrl *ctrl, int argc, 1246 char *argv[]) 1247 { 1248 if (argc < 4) { 1249 printf("Invalid req_range command: needs at least 4 arguments - dest address, randomization interval, min AP count, and 1 to 16 AP addresses\n"); 1250 return -1; 1251 } 1252 1253 return hostapd_cli_cmd(ctrl, "REQ_RANGE", 4, argc, argv); 1254 } 1255 1256 1257 static int hostapd_cli_cmd_driver_flags(struct wpa_ctrl *ctrl, int argc, 1258 char *argv[]) 1259 { 1260 return wpa_ctrl_command(ctrl, "DRIVER_FLAGS"); 1261 } 1262 1263 1264 struct hostapd_cli_cmd { 1265 const char *cmd; 1266 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]); 1267 char ** (*completion)(const char *str, int pos); 1268 const char *usage; 1269 }; 1270 1271 static const struct hostapd_cli_cmd hostapd_cli_commands[] = { 1272 { "ping", hostapd_cli_cmd_ping, NULL, 1273 "= pings hostapd" }, 1274 { "mib", hostapd_cli_cmd_mib, NULL, 1275 "= get MIB variables (dot1x, dot11, radius)" }, 1276 { "relog", hostapd_cli_cmd_relog, NULL, NULL }, 1277 { "status", hostapd_cli_cmd_status, NULL, NULL }, 1278 { "sta", hostapd_cli_cmd_sta, NULL, 1279 "<addr> = get MIB variables for one station" }, 1280 { "all_sta", hostapd_cli_cmd_all_sta, NULL, 1281 "= get MIB variables for all stations" }, 1282 { "new_sta", hostapd_cli_cmd_new_sta, NULL, 1283 "<addr> = add a new station" }, 1284 { "deauthenticate", hostapd_cli_cmd_deauthenticate, 1285 hostapd_complete_deauthenticate, 1286 "<addr> = deauthenticate a station" }, 1287 { "disassociate", hostapd_cli_cmd_disassociate, 1288 hostapd_complete_disassociate, 1289 "<addr> = disassociate a station" }, 1290 #ifdef CONFIG_TAXONOMY 1291 { "signature", hostapd_cli_cmd_signature, NULL, 1292 "<addr> = get taxonomy signature for a station" }, 1293 #endif /* CONFIG_TAXONOMY */ 1294 #ifdef CONFIG_IEEE80211W 1295 { "sa_query", hostapd_cli_cmd_sa_query, NULL, 1296 "<addr> = send SA Query to a station" }, 1297 #endif /* CONFIG_IEEE80211W */ 1298 #ifdef CONFIG_WPS 1299 { "wps_pin", hostapd_cli_cmd_wps_pin, NULL, 1300 "<uuid> <pin> [timeout] [addr] = add WPS Enrollee PIN" }, 1301 { "wps_check_pin", hostapd_cli_cmd_wps_check_pin, NULL, 1302 "<PIN> = verify PIN checksum" }, 1303 { "wps_pbc", hostapd_cli_cmd_wps_pbc, NULL, 1304 "= indicate button pushed to initiate PBC" }, 1305 { "wps_cancel", hostapd_cli_cmd_wps_cancel, NULL, 1306 "= cancel the pending WPS operation" }, 1307 #ifdef CONFIG_WPS_NFC 1308 { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read, NULL, 1309 "<hexdump> = report read NFC tag with WPS data" }, 1310 { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token, NULL, 1311 "<WPS/NDEF> = build NFC configuration token" }, 1312 { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token, NULL, 1313 "<WPS/NDEF/enable/disable> = manager NFC password token" }, 1314 { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel, NULL, 1315 NULL }, 1316 #endif /* CONFIG_WPS_NFC */ 1317 { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin, NULL, 1318 "<cmd> [params..] = enable/disable AP PIN" }, 1319 { "wps_config", hostapd_cli_cmd_wps_config, NULL, 1320 "<SSID> <auth> <encr> <key> = configure AP" }, 1321 { "wps_get_status", hostapd_cli_cmd_wps_get_status, NULL, 1322 "= show current WPS status" }, 1323 #endif /* CONFIG_WPS */ 1324 { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent, NULL, NULL }, 1325 { "ess_disassoc", hostapd_cli_cmd_ess_disassoc, NULL, NULL }, 1326 { "bss_tm_req", hostapd_cli_cmd_bss_tm_req, NULL, NULL }, 1327 { "get_config", hostapd_cli_cmd_get_config, NULL, 1328 "= show current configuration" }, 1329 { "help", hostapd_cli_cmd_help, hostapd_cli_complete_help, 1330 "= show this usage help" }, 1331 { "interface", hostapd_cli_cmd_interface, hostapd_complete_interface, 1332 "[ifname] = show interfaces/select interface" }, 1333 #ifdef CONFIG_FST 1334 { "fst", hostapd_cli_cmd_fst, NULL, NULL }, 1335 #endif /* CONFIG_FST */ 1336 { "raw", hostapd_cli_cmd_raw, NULL, NULL }, 1337 { "level", hostapd_cli_cmd_level, NULL, 1338 "<debug level> = change debug level" }, 1339 { "license", hostapd_cli_cmd_license, NULL, 1340 "= show full hostapd_cli license" }, 1341 { "quit", hostapd_cli_cmd_quit, NULL, 1342 "= exit hostapd_cli" }, 1343 { "set", hostapd_cli_cmd_set, NULL, NULL }, 1344 { "get", hostapd_cli_cmd_get, NULL, NULL }, 1345 { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set, NULL, NULL }, 1346 { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf, NULL, NULL }, 1347 { "chan_switch", hostapd_cli_cmd_chan_switch, NULL, NULL }, 1348 { "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif, NULL, NULL }, 1349 { "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req, NULL, NULL }, 1350 { "vendor", hostapd_cli_cmd_vendor, NULL, NULL }, 1351 { "enable", hostapd_cli_cmd_enable, NULL, NULL }, 1352 { "reload", hostapd_cli_cmd_reload, NULL, NULL }, 1353 { "disable", hostapd_cli_cmd_disable, NULL, NULL }, 1354 { "erp_flush", hostapd_cli_cmd_erp_flush, NULL, NULL }, 1355 { "log_level", hostapd_cli_cmd_log_level, NULL, NULL }, 1356 { "pmksa", hostapd_cli_cmd_pmksa, NULL, NULL }, 1357 { "pmksa_flush", hostapd_cli_cmd_pmksa_flush, NULL, NULL }, 1358 { "set_neighbor", hostapd_cli_cmd_set_neighbor, NULL, NULL }, 1359 { "remove_neighbor", hostapd_cli_cmd_remove_neighbor, NULL, NULL }, 1360 { "req_lci", hostapd_cli_cmd_req_lci, NULL, NULL }, 1361 { "req_range", hostapd_cli_cmd_req_range, NULL, NULL }, 1362 { "driver_flags", hostapd_cli_cmd_driver_flags, NULL, NULL }, 1363 { NULL, NULL, NULL, NULL } 1364 }; 1365 1366 1367 /* 1368 * Prints command usage, lines are padded with the specified string. 1369 */ 1370 static void print_cmd_help(FILE *stream, const struct hostapd_cli_cmd *cmd, 1371 const char *pad) 1372 { 1373 char c; 1374 size_t n; 1375 1376 if (cmd->usage == NULL) 1377 return; 1378 fprintf(stream, "%s%s ", pad, cmd->cmd); 1379 for (n = 0; (c = cmd->usage[n]); n++) { 1380 fprintf(stream, "%c", c); 1381 if (c == '\n') 1382 fprintf(stream, "%s", pad); 1383 } 1384 fprintf(stream, "\n"); 1385 } 1386 1387 1388 static void print_help(FILE *stream, const char *cmd) 1389 { 1390 int n; 1391 1392 fprintf(stream, "commands:\n"); 1393 for (n = 0; hostapd_cli_commands[n].cmd; n++) { 1394 if (cmd == NULL || str_starts(hostapd_cli_commands[n].cmd, cmd)) 1395 print_cmd_help(stream, &hostapd_cli_commands[n], " "); 1396 } 1397 } 1398 1399 1400 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1401 { 1402 const struct hostapd_cli_cmd *cmd, *match = NULL; 1403 int count; 1404 1405 count = 0; 1406 cmd = hostapd_cli_commands; 1407 while (cmd->cmd) { 1408 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) { 1409 match = cmd; 1410 if (os_strcasecmp(cmd->cmd, argv[0]) == 0) { 1411 /* we have an exact match */ 1412 count = 1; 1413 break; 1414 } 1415 count++; 1416 } 1417 cmd++; 1418 } 1419 1420 if (count > 1) { 1421 printf("Ambiguous command '%s'; possible commands:", argv[0]); 1422 cmd = hostapd_cli_commands; 1423 while (cmd->cmd) { 1424 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 1425 0) { 1426 printf(" %s", cmd->cmd); 1427 } 1428 cmd++; 1429 } 1430 printf("\n"); 1431 } else if (count == 0) { 1432 printf("Unknown command '%s'\n", argv[0]); 1433 } else { 1434 match->handler(ctrl, argc - 1, &argv[1]); 1435 } 1436 } 1437 1438 1439 static void cli_event(const char *str) 1440 { 1441 const char *start, *s; 1442 1443 start = os_strchr(str, '>'); 1444 if (start == NULL) 1445 return; 1446 1447 start++; 1448 1449 if (str_starts(start, AP_STA_CONNECTED)) { 1450 s = os_strchr(start, ' '); 1451 if (s == NULL) 1452 return; 1453 cli_txt_list_add(&stations, s + 1); 1454 return; 1455 } 1456 1457 if (str_starts(start, AP_STA_DISCONNECTED)) { 1458 s = os_strchr(start, ' '); 1459 if (s == NULL) 1460 return; 1461 cli_txt_list_del_addr(&stations, s + 1); 1462 return; 1463 } 1464 } 1465 1466 1467 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read, 1468 int action_monitor) 1469 { 1470 int first = 1; 1471 if (ctrl_conn == NULL) 1472 return; 1473 while (wpa_ctrl_pending(ctrl)) { 1474 char buf[256]; 1475 size_t len = sizeof(buf) - 1; 1476 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) { 1477 buf[len] = '\0'; 1478 if (action_monitor) 1479 hostapd_cli_action_process(buf, len); 1480 else { 1481 cli_event(buf); 1482 if (in_read && first) 1483 printf("\n"); 1484 first = 0; 1485 printf("%s\n", buf); 1486 } 1487 } else { 1488 printf("Could not read pending message.\n"); 1489 break; 1490 } 1491 } 1492 } 1493 1494 1495 static void hostapd_cli_receive(int sock, void *eloop_ctx, void *sock_ctx) 1496 { 1497 hostapd_cli_recv_pending(ctrl_conn, 0, 0); 1498 } 1499 1500 1501 static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx) 1502 { 1503 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) { 1504 printf("Connection to hostapd lost - trying to reconnect\n"); 1505 hostapd_cli_close_connection(); 1506 } 1507 if (!ctrl_conn) { 1508 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname); 1509 if (ctrl_conn) { 1510 printf("Connection to hostapd re-established\n"); 1511 if (wpa_ctrl_attach(ctrl_conn) == 0) { 1512 hostapd_cli_attached = 1; 1513 register_event_handler(ctrl_conn); 1514 } else { 1515 printf("Warning: Failed to attach to " 1516 "hostapd.\n"); 1517 } 1518 } 1519 } 1520 if (ctrl_conn) 1521 hostapd_cli_recv_pending(ctrl_conn, 1, 0); 1522 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL); 1523 } 1524 1525 1526 static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx) 1527 { 1528 eloop_terminate(); 1529 } 1530 1531 1532 static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd) 1533 { 1534 char *argv[max_args]; 1535 int argc; 1536 argc = tokenize_cmd(cmd, argv); 1537 if (argc) 1538 wpa_request(ctrl_conn, argc, argv); 1539 } 1540 1541 1542 static void hostapd_cli_edit_eof_cb(void *ctx) 1543 { 1544 eloop_terminate(); 1545 } 1546 1547 1548 static char ** list_cmd_list(void) 1549 { 1550 char **res; 1551 int i, count; 1552 1553 count = ARRAY_SIZE(hostapd_cli_commands); 1554 res = os_calloc(count + 1, sizeof(char *)); 1555 if (res == NULL) 1556 return NULL; 1557 1558 for (i = 0; hostapd_cli_commands[i].cmd; i++) { 1559 res[i] = os_strdup(hostapd_cli_commands[i].cmd); 1560 if (res[i] == NULL) 1561 break; 1562 } 1563 1564 return res; 1565 } 1566 1567 1568 static char ** hostapd_cli_cmd_completion(const char *cmd, const char *str, 1569 int pos) 1570 { 1571 int i; 1572 1573 for (i = 0; hostapd_cli_commands[i].cmd; i++) { 1574 if (os_strcasecmp(hostapd_cli_commands[i].cmd, cmd) != 0) 1575 continue; 1576 if (hostapd_cli_commands[i].completion) 1577 return hostapd_cli_commands[i].completion(str, pos); 1578 if (!hostapd_cli_commands[i].usage) 1579 return NULL; 1580 edit_clear_line(); 1581 printf("\r%s\n", hostapd_cli_commands[i].usage); 1582 edit_redraw(); 1583 break; 1584 } 1585 1586 return NULL; 1587 } 1588 1589 1590 static char ** hostapd_cli_edit_completion_cb(void *ctx, const char *str, 1591 int pos) 1592 { 1593 char **res; 1594 const char *end; 1595 char *cmd; 1596 1597 end = os_strchr(str, ' '); 1598 if (end == NULL || str + pos < end) 1599 return list_cmd_list(); 1600 1601 cmd = os_malloc(pos + 1); 1602 if (cmd == NULL) 1603 return NULL; 1604 os_memcpy(cmd, str, pos); 1605 cmd[end - str] = '\0'; 1606 res = hostapd_cli_cmd_completion(cmd, str, pos); 1607 os_free(cmd); 1608 return res; 1609 } 1610 1611 1612 static void hostapd_cli_interactive(void) 1613 { 1614 printf("\nInteractive mode\n\n"); 1615 1616 eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL); 1617 edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb, 1618 hostapd_cli_edit_completion_cb, NULL, NULL, NULL); 1619 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL); 1620 1621 eloop_run(); 1622 1623 cli_txt_list_flush(&stations); 1624 edit_deinit(NULL, NULL); 1625 eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL); 1626 } 1627 1628 1629 static void hostapd_cli_cleanup(void) 1630 { 1631 hostapd_cli_close_connection(); 1632 if (pid_file) 1633 os_daemonize_terminate(pid_file); 1634 1635 os_program_deinit(); 1636 } 1637 1638 1639 static void hostapd_cli_action(struct wpa_ctrl *ctrl) 1640 { 1641 fd_set rfds; 1642 int fd, res; 1643 struct timeval tv; 1644 char buf[256]; 1645 size_t len; 1646 1647 fd = wpa_ctrl_get_fd(ctrl); 1648 1649 while (!hostapd_cli_quit) { 1650 FD_ZERO(&rfds); 1651 FD_SET(fd, &rfds); 1652 tv.tv_sec = ping_interval; 1653 tv.tv_usec = 0; 1654 res = select(fd + 1, &rfds, NULL, NULL, &tv); 1655 if (res < 0 && errno != EINTR) { 1656 perror("select"); 1657 break; 1658 } 1659 1660 if (FD_ISSET(fd, &rfds)) 1661 hostapd_cli_recv_pending(ctrl, 0, 1); 1662 else { 1663 len = sizeof(buf) - 1; 1664 if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len, 1665 hostapd_cli_action_process) < 0 || 1666 len < 4 || os_memcmp(buf, "PONG", 4) != 0) { 1667 printf("hostapd did not reply to PING " 1668 "command - exiting\n"); 1669 break; 1670 } 1671 } 1672 } 1673 } 1674 1675 1676 int main(int argc, char *argv[]) 1677 { 1678 int warning_displayed = 0; 1679 int c; 1680 int daemonize = 0; 1681 1682 if (os_program_init()) 1683 return -1; 1684 1685 for (;;) { 1686 c = getopt(argc, argv, "a:BhG:i:p:P:s:v"); 1687 if (c < 0) 1688 break; 1689 switch (c) { 1690 case 'a': 1691 action_file = optarg; 1692 break; 1693 case 'B': 1694 daemonize = 1; 1695 break; 1696 case 'G': 1697 ping_interval = atoi(optarg); 1698 break; 1699 case 'h': 1700 usage(); 1701 return 0; 1702 case 'v': 1703 printf("%s\n", hostapd_cli_version); 1704 return 0; 1705 case 'i': 1706 os_free(ctrl_ifname); 1707 ctrl_ifname = os_strdup(optarg); 1708 break; 1709 case 'p': 1710 ctrl_iface_dir = optarg; 1711 break; 1712 case 'P': 1713 pid_file = optarg; 1714 break; 1715 case 's': 1716 client_socket_dir = optarg; 1717 break; 1718 default: 1719 usage(); 1720 return -1; 1721 } 1722 } 1723 1724 interactive = (argc == optind) && (action_file == NULL); 1725 1726 if (interactive) { 1727 printf("%s\n\n%s\n\n", hostapd_cli_version, cli_license); 1728 } 1729 1730 if (eloop_init()) 1731 return -1; 1732 1733 for (;;) { 1734 if (ctrl_ifname == NULL) { 1735 struct dirent *dent; 1736 DIR *dir = opendir(ctrl_iface_dir); 1737 if (dir) { 1738 while ((dent = readdir(dir))) { 1739 if (os_strcmp(dent->d_name, ".") == 0 1740 || 1741 os_strcmp(dent->d_name, "..") == 0) 1742 continue; 1743 printf("Selected interface '%s'\n", 1744 dent->d_name); 1745 ctrl_ifname = os_strdup(dent->d_name); 1746 break; 1747 } 1748 closedir(dir); 1749 } 1750 } 1751 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname); 1752 if (ctrl_conn) { 1753 if (warning_displayed) 1754 printf("Connection established.\n"); 1755 break; 1756 } 1757 1758 if (!interactive) { 1759 perror("Failed to connect to hostapd - " 1760 "wpa_ctrl_open"); 1761 return -1; 1762 } 1763 1764 if (!warning_displayed) { 1765 printf("Could not connect to hostapd - re-trying\n"); 1766 warning_displayed = 1; 1767 } 1768 os_sleep(1, 0); 1769 continue; 1770 } 1771 1772 if (interactive || action_file) { 1773 if (wpa_ctrl_attach(ctrl_conn) == 0) { 1774 hostapd_cli_attached = 1; 1775 register_event_handler(ctrl_conn); 1776 } else { 1777 printf("Warning: Failed to attach to hostapd.\n"); 1778 if (action_file) 1779 return -1; 1780 } 1781 } 1782 1783 if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue()) 1784 return -1; 1785 1786 if (interactive) 1787 hostapd_cli_interactive(); 1788 else if (action_file) 1789 hostapd_cli_action(ctrl_conn); 1790 else 1791 wpa_request(ctrl_conn, argc - optind, &argv[optind]); 1792 1793 unregister_event_handler(ctrl_conn); 1794 os_free(ctrl_ifname); 1795 eloop_destroy(); 1796 hostapd_cli_cleanup(); 1797 return 0; 1798 } 1799 1800 #else /* CONFIG_NO_CTRL_IFACE */ 1801 1802 int main(int argc, char *argv[]) 1803 { 1804 return -1; 1805 } 1806 1807 #endif /* CONFIG_NO_CTRL_IFACE */ 1808