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