1 /* 2 * hostapd - command line interface for hostapd daemon 3 * Copyright (c) 2004-2017, Jouni Malinen <j (at) 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-2017, Jouni Malinen <j (at) 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 static void update_stations(struct wpa_ctrl *ctrl); 49 static void cli_event(const char *str); 50 51 52 static 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 79 static 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 92 static 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 103 static 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 137 static 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 152 static 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 183 static void hostapd_cli_msg_cb(char *msg, size_t len) 184 { 185 cli_event(msg); 186 printf("%s\n", msg); 187 } 188 189 190 static 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 218 static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, const char *cmd) 219 { 220 return _wpa_ctrl_command(ctrl, cmd, 1); 221 } 222 223 224 static 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 240 static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[]) 241 { 242 return wpa_ctrl_command(ctrl, "PING"); 243 } 244 245 246 static int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[]) 247 { 248 return wpa_ctrl_command(ctrl, "RELOG"); 249 } 250 251 252 static 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 260 static 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 271 static 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 290 static 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 307 static 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 323 static 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 338 static 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 352 static 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 370 static 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 389 static 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 405 static 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 421 static 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 442 static 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 468 static 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 475 static 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 483 static 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 509 static 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 531 static 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 552 static 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 576 static 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 597 static 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 604 static 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 649 static 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 669 static 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 689 static 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 716 static 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 723 static 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 760 static 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 775 static 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 792 static 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 799 static 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 814 static 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 822 static 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 842 static 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 861 static 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 881 static 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 906 static 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 915 static 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 928 static 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 947 static 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 969 static 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 992 static 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 1007 static 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 1025 static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1026 { 1027 char cmd[2048]; 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 1045 static 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 1083 static 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 1103 static 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 1129 static 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 1157 static 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 1196 static 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 1203 static 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 1210 static 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 1217 static 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 1238 static 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 1245 static 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 1264 static 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 1272 static int hostapd_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1273 { 1274 return wpa_ctrl_command(ctrl, "PMKSA"); 1275 } 1276 1277 1278 static 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 1285 static 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 1307 static 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 1328 static 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 1348 static 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 1360 static 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 1367 #ifdef CONFIG_DPP 1368 1369 static int hostapd_cli_cmd_dpp_qr_code(struct wpa_ctrl *ctrl, int argc, 1370 char *argv[]) 1371 { 1372 return hostapd_cli_cmd(ctrl, "DPP_QR_CODE", 1, argc, argv); 1373 } 1374 1375 1376 static int hostapd_cli_cmd_dpp_bootstrap_gen(struct wpa_ctrl *ctrl, int argc, 1377 char *argv[]) 1378 { 1379 return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_GEN", 1, argc, argv); 1380 } 1381 1382 1383 static int hostapd_cli_cmd_dpp_bootstrap_remove(struct wpa_ctrl *ctrl, int argc, 1384 char *argv[]) 1385 { 1386 return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_REMOVE", 1, argc, argv); 1387 } 1388 1389 1390 static int hostapd_cli_cmd_dpp_bootstrap_get_uri(struct wpa_ctrl *ctrl, 1391 int argc, char *argv[]) 1392 { 1393 return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_GET_URI", 1, argc, argv); 1394 } 1395 1396 1397 static int hostapd_cli_cmd_dpp_bootstrap_info(struct wpa_ctrl *ctrl, int argc, 1398 char *argv[]) 1399 { 1400 return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_INFO", 1, argc, argv); 1401 } 1402 1403 1404 static int hostapd_cli_cmd_dpp_auth_init(struct wpa_ctrl *ctrl, int argc, 1405 char *argv[]) 1406 { 1407 return hostapd_cli_cmd(ctrl, "DPP_AUTH_INIT", 1, argc, argv); 1408 } 1409 1410 1411 static int hostapd_cli_cmd_dpp_configurator_add(struct wpa_ctrl *ctrl, int argc, 1412 char *argv[]) 1413 { 1414 return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_ADD", 0, argc, argv); 1415 } 1416 1417 1418 static int hostapd_cli_cmd_dpp_configurator_remove(struct wpa_ctrl *ctrl, 1419 int argc, char *argv[]) 1420 { 1421 return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_REMOVE", 1, argc, argv); 1422 } 1423 1424 1425 static int hostapd_cli_cmd_dpp_pkex_add(struct wpa_ctrl *ctrl, int argc, 1426 char *argv[]) 1427 { 1428 return hostapd_cli_cmd(ctrl, "DPP_PKEX_ADD", 1, argc, argv); 1429 } 1430 1431 1432 static int hostapd_cli_cmd_dpp_pkex_remove(struct wpa_ctrl *ctrl, int argc, 1433 char *argv[]) 1434 { 1435 return hostapd_cli_cmd(ctrl, "DPP_PKEX_REMOVE", 1, argc, argv); 1436 } 1437 1438 #endif /* CONFIG_DPP */ 1439 1440 1441 struct hostapd_cli_cmd { 1442 const char *cmd; 1443 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]); 1444 char ** (*completion)(const char *str, int pos); 1445 const char *usage; 1446 }; 1447 1448 static const struct hostapd_cli_cmd hostapd_cli_commands[] = { 1449 { "ping", hostapd_cli_cmd_ping, NULL, 1450 "= pings hostapd" }, 1451 { "mib", hostapd_cli_cmd_mib, NULL, 1452 "= get MIB variables (dot1x, dot11, radius)" }, 1453 { "relog", hostapd_cli_cmd_relog, NULL, 1454 "= reload/truncate debug log output file" }, 1455 { "status", hostapd_cli_cmd_status, NULL, 1456 "= show interface status info" }, 1457 { "sta", hostapd_cli_cmd_sta, hostapd_complete_stations, 1458 "<addr> = get MIB variables for one station" }, 1459 { "all_sta", hostapd_cli_cmd_all_sta, NULL, 1460 "= get MIB variables for all stations" }, 1461 { "list_sta", hostapd_cli_cmd_list_sta, NULL, 1462 "= list all stations" }, 1463 { "new_sta", hostapd_cli_cmd_new_sta, NULL, 1464 "<addr> = add a new station" }, 1465 { "deauthenticate", hostapd_cli_cmd_deauthenticate, 1466 hostapd_complete_stations, 1467 "<addr> = deauthenticate a station" }, 1468 { "disassociate", hostapd_cli_cmd_disassociate, 1469 hostapd_complete_stations, 1470 "<addr> = disassociate a station" }, 1471 #ifdef CONFIG_TAXONOMY 1472 { "signature", hostapd_cli_cmd_signature, hostapd_complete_stations, 1473 "<addr> = get taxonomy signature for a station" }, 1474 #endif /* CONFIG_TAXONOMY */ 1475 #ifdef CONFIG_IEEE80211W 1476 { "sa_query", hostapd_cli_cmd_sa_query, hostapd_complete_stations, 1477 "<addr> = send SA Query to a station" }, 1478 #endif /* CONFIG_IEEE80211W */ 1479 #ifdef CONFIG_WPS 1480 { "wps_pin", hostapd_cli_cmd_wps_pin, NULL, 1481 "<uuid> <pin> [timeout] [addr] = add WPS Enrollee PIN" }, 1482 { "wps_check_pin", hostapd_cli_cmd_wps_check_pin, NULL, 1483 "<PIN> = verify PIN checksum" }, 1484 { "wps_pbc", hostapd_cli_cmd_wps_pbc, NULL, 1485 "= indicate button pushed to initiate PBC" }, 1486 { "wps_cancel", hostapd_cli_cmd_wps_cancel, NULL, 1487 "= cancel the pending WPS operation" }, 1488 #ifdef CONFIG_WPS_NFC 1489 { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read, NULL, 1490 "<hexdump> = report read NFC tag with WPS data" }, 1491 { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token, NULL, 1492 "<WPS/NDEF> = build NFC configuration token" }, 1493 { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token, NULL, 1494 "<WPS/NDEF/enable/disable> = manager NFC password token" }, 1495 { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel, NULL, 1496 NULL }, 1497 #endif /* CONFIG_WPS_NFC */ 1498 { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin, NULL, 1499 "<cmd> [params..] = enable/disable AP PIN" }, 1500 { "wps_config", hostapd_cli_cmd_wps_config, NULL, 1501 "<SSID> <auth> <encr> <key> = configure AP" }, 1502 { "wps_get_status", hostapd_cli_cmd_wps_get_status, NULL, 1503 "= show current WPS status" }, 1504 #endif /* CONFIG_WPS */ 1505 { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent, NULL, 1506 "= send Disassociation Imminent notification" }, 1507 { "ess_disassoc", hostapd_cli_cmd_ess_disassoc, NULL, 1508 "= send ESS Dissassociation Imminent notification" }, 1509 { "bss_tm_req", hostapd_cli_cmd_bss_tm_req, NULL, 1510 "= send BSS Transition Management Request" }, 1511 { "get_config", hostapd_cli_cmd_get_config, NULL, 1512 "= show current configuration" }, 1513 { "help", hostapd_cli_cmd_help, hostapd_cli_complete_help, 1514 "= show this usage help" }, 1515 { "interface", hostapd_cli_cmd_interface, hostapd_complete_interface, 1516 "[ifname] = show interfaces/select interface" }, 1517 #ifdef CONFIG_FST 1518 { "fst", hostapd_cli_cmd_fst, NULL, 1519 "<params...> = send FST-MANAGER control interface command" }, 1520 #endif /* CONFIG_FST */ 1521 { "raw", hostapd_cli_cmd_raw, NULL, 1522 "<params..> = send unprocessed command" }, 1523 { "level", hostapd_cli_cmd_level, NULL, 1524 "<debug level> = change debug level" }, 1525 { "license", hostapd_cli_cmd_license, NULL, 1526 "= show full hostapd_cli license" }, 1527 { "quit", hostapd_cli_cmd_quit, NULL, 1528 "= exit hostapd_cli" }, 1529 { "set", hostapd_cli_cmd_set, hostapd_complete_set, 1530 "<name> <value> = set runtime variables" }, 1531 { "get", hostapd_cli_cmd_get, hostapd_complete_get, 1532 "<name> = get runtime info" }, 1533 { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set, NULL, 1534 "<arg,arg,...> = set QoS Map set element" }, 1535 { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf, 1536 hostapd_complete_stations, 1537 "<addr> = send QoS Map Configure frame" }, 1538 { "chan_switch", hostapd_cli_cmd_chan_switch, NULL, 1539 "<cs_count> <freq> [sec_channel_offset=] [center_freq1=]\n" 1540 " [center_freq2=] [bandwidth=] [blocktx] [ht|vht]\n" 1541 " = initiate channel switch announcement" }, 1542 { "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif, NULL, 1543 "<addr> <url>\n" 1544 " = send WNM-Notification Subscription Remediation Request" }, 1545 { "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req, NULL, 1546 "<addr> <code (0/1)> <Re-auth-Delay(sec)> [url]\n" 1547 " = send WNM-Notification imminent deauthentication indication" }, 1548 { "vendor", hostapd_cli_cmd_vendor, NULL, 1549 "<vendor id> <sub command id> [<hex formatted data>]\n" 1550 " = send vendor driver command" }, 1551 { "enable", hostapd_cli_cmd_enable, NULL, 1552 "= enable hostapd on current interface" }, 1553 { "reload", hostapd_cli_cmd_reload, NULL, 1554 "= reload configuration for current interface" }, 1555 { "disable", hostapd_cli_cmd_disable, NULL, 1556 "= disable hostapd on current interface" }, 1557 { "erp_flush", hostapd_cli_cmd_erp_flush, NULL, 1558 "= drop all ERP keys"}, 1559 { "log_level", hostapd_cli_cmd_log_level, NULL, 1560 "[level] = show/change log verbosity level" }, 1561 { "pmksa", hostapd_cli_cmd_pmksa, NULL, 1562 " = show PMKSA cache entries" }, 1563 { "pmksa_flush", hostapd_cli_cmd_pmksa_flush, NULL, 1564 " = flush PMKSA cache" }, 1565 { "set_neighbor", hostapd_cli_cmd_set_neighbor, NULL, 1566 "<addr> <ssid=> <nr=> [lci=] [civic=] [stat]\n" 1567 " = add AP to neighbor database" }, 1568 { "remove_neighbor", hostapd_cli_cmd_remove_neighbor, NULL, 1569 "<addr> <ssid=> = remove AP from neighbor database" }, 1570 { "req_lci", hostapd_cli_cmd_req_lci, hostapd_complete_stations, 1571 "<addr> = send LCI request to a station"}, 1572 { "req_range", hostapd_cli_cmd_req_range, NULL, 1573 " = send FTM range request"}, 1574 { "driver_flags", hostapd_cli_cmd_driver_flags, NULL, 1575 " = show supported driver flags"}, 1576 #ifdef CONFIG_DPP 1577 { "dpp_qr_code", hostapd_cli_cmd_dpp_qr_code, NULL, 1578 "report a scanned DPP URI from a QR Code" }, 1579 { "dpp_bootstrap_gen", hostapd_cli_cmd_dpp_bootstrap_gen, NULL, 1580 "type=<qrcode> [chan=..] [mac=..] [info=..] [curve=..] [key=..] = generate DPP bootstrap information" }, 1581 { "dpp_bootstrap_remove", hostapd_cli_cmd_dpp_bootstrap_remove, NULL, 1582 "*|<id> = remove DPP bootstrap information" }, 1583 { "dpp_bootstrap_get_uri", hostapd_cli_cmd_dpp_bootstrap_get_uri, NULL, 1584 "<id> = get DPP bootstrap URI" }, 1585 { "dpp_bootstrap_info", hostapd_cli_cmd_dpp_bootstrap_info, NULL, 1586 "<id> = show DPP bootstrap information" }, 1587 { "dpp_auth_init", hostapd_cli_cmd_dpp_auth_init, NULL, 1588 "peer=<id> [own=<id>] = initiate DPP bootstrapping" }, 1589 { "dpp_configurator_add", hostapd_cli_cmd_dpp_configurator_add, NULL, 1590 "[curve=..] [key=..] = add DPP configurator" }, 1591 { "dpp_configurator_remove", hostapd_cli_cmd_dpp_configurator_remove, 1592 NULL, 1593 "*|<id> = remove DPP configurator" }, 1594 { "dpp_pkex_add", hostapd_cli_cmd_dpp_pkex_add, NULL, 1595 "add PKEX code" }, 1596 { "dpp_pkex_remove", hostapd_cli_cmd_dpp_pkex_remove, NULL, 1597 "*|<id> = remove DPP pkex information" }, 1598 #endif /* CONFIG_DPP */ 1599 { NULL, NULL, NULL, NULL } 1600 }; 1601 1602 1603 /* 1604 * Prints command usage, lines are padded with the specified string. 1605 */ 1606 static void print_cmd_help(FILE *stream, const struct hostapd_cli_cmd *cmd, 1607 const char *pad) 1608 { 1609 char c; 1610 size_t n; 1611 1612 if (cmd->usage == NULL) 1613 return; 1614 fprintf(stream, "%s%s ", pad, cmd->cmd); 1615 for (n = 0; (c = cmd->usage[n]); n++) { 1616 fprintf(stream, "%c", c); 1617 if (c == '\n') 1618 fprintf(stream, "%s", pad); 1619 } 1620 fprintf(stream, "\n"); 1621 } 1622 1623 1624 static void print_help(FILE *stream, const char *cmd) 1625 { 1626 int n; 1627 1628 fprintf(stream, "commands:\n"); 1629 for (n = 0; hostapd_cli_commands[n].cmd; n++) { 1630 if (cmd == NULL || str_starts(hostapd_cli_commands[n].cmd, cmd)) 1631 print_cmd_help(stream, &hostapd_cli_commands[n], " "); 1632 } 1633 } 1634 1635 1636 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1637 { 1638 const struct hostapd_cli_cmd *cmd, *match = NULL; 1639 int count; 1640 1641 count = 0; 1642 cmd = hostapd_cli_commands; 1643 while (cmd->cmd) { 1644 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) { 1645 match = cmd; 1646 if (os_strcasecmp(cmd->cmd, argv[0]) == 0) { 1647 /* we have an exact match */ 1648 count = 1; 1649 break; 1650 } 1651 count++; 1652 } 1653 cmd++; 1654 } 1655 1656 if (count > 1) { 1657 printf("Ambiguous command '%s'; possible commands:", argv[0]); 1658 cmd = hostapd_cli_commands; 1659 while (cmd->cmd) { 1660 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 1661 0) { 1662 printf(" %s", cmd->cmd); 1663 } 1664 cmd++; 1665 } 1666 printf("\n"); 1667 } else if (count == 0) { 1668 printf("Unknown command '%s'\n", argv[0]); 1669 } else { 1670 match->handler(ctrl, argc - 1, &argv[1]); 1671 } 1672 } 1673 1674 1675 static void cli_event(const char *str) 1676 { 1677 const char *start, *s; 1678 1679 start = os_strchr(str, '>'); 1680 if (start == NULL) 1681 return; 1682 1683 start++; 1684 1685 if (str_starts(start, AP_STA_CONNECTED)) { 1686 s = os_strchr(start, ' '); 1687 if (s == NULL) 1688 return; 1689 cli_txt_list_add(&stations, s + 1); 1690 return; 1691 } 1692 1693 if (str_starts(start, AP_STA_DISCONNECTED)) { 1694 s = os_strchr(start, ' '); 1695 if (s == NULL) 1696 return; 1697 cli_txt_list_del_addr(&stations, s + 1); 1698 return; 1699 } 1700 } 1701 1702 1703 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read, 1704 int action_monitor) 1705 { 1706 int first = 1; 1707 if (ctrl_conn == NULL) 1708 return; 1709 while (wpa_ctrl_pending(ctrl)) { 1710 char buf[4096]; 1711 size_t len = sizeof(buf) - 1; 1712 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) { 1713 buf[len] = '\0'; 1714 if (action_monitor) 1715 hostapd_cli_action_process(buf, len); 1716 else { 1717 cli_event(buf); 1718 if (in_read && first) 1719 printf("\n"); 1720 first = 0; 1721 printf("%s\n", buf); 1722 } 1723 } else { 1724 printf("Could not read pending message.\n"); 1725 break; 1726 } 1727 } 1728 } 1729 1730 1731 static void hostapd_cli_receive(int sock, void *eloop_ctx, void *sock_ctx) 1732 { 1733 hostapd_cli_recv_pending(ctrl_conn, 0, 0); 1734 } 1735 1736 1737 static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx) 1738 { 1739 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) { 1740 printf("Connection to hostapd lost - trying to reconnect\n"); 1741 hostapd_cli_close_connection(); 1742 } 1743 if (!ctrl_conn && hostapd_cli_reconnect(ctrl_ifname) == 0) 1744 printf("Connection to hostapd re-established\n"); 1745 if (ctrl_conn) 1746 hostapd_cli_recv_pending(ctrl_conn, 1, 0); 1747 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL); 1748 } 1749 1750 1751 static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx) 1752 { 1753 eloop_terminate(); 1754 } 1755 1756 1757 static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd) 1758 { 1759 char *argv[max_args]; 1760 int argc; 1761 argc = tokenize_cmd(cmd, argv); 1762 if (argc) 1763 wpa_request(ctrl_conn, argc, argv); 1764 } 1765 1766 1767 static void hostapd_cli_edit_eof_cb(void *ctx) 1768 { 1769 eloop_terminate(); 1770 } 1771 1772 1773 static char ** list_cmd_list(void) 1774 { 1775 char **res; 1776 int i, count; 1777 1778 count = ARRAY_SIZE(hostapd_cli_commands); 1779 res = os_calloc(count + 1, sizeof(char *)); 1780 if (res == NULL) 1781 return NULL; 1782 1783 for (i = 0; hostapd_cli_commands[i].cmd; i++) { 1784 res[i] = os_strdup(hostapd_cli_commands[i].cmd); 1785 if (res[i] == NULL) 1786 break; 1787 } 1788 1789 return res; 1790 } 1791 1792 1793 static char ** hostapd_cli_cmd_completion(const char *cmd, const char *str, 1794 int pos) 1795 { 1796 int i; 1797 1798 for (i = 0; hostapd_cli_commands[i].cmd; i++) { 1799 if (os_strcasecmp(hostapd_cli_commands[i].cmd, cmd) != 0) 1800 continue; 1801 if (hostapd_cli_commands[i].completion) 1802 return hostapd_cli_commands[i].completion(str, pos); 1803 if (!hostapd_cli_commands[i].usage) 1804 return NULL; 1805 edit_clear_line(); 1806 printf("\r%s\n", hostapd_cli_commands[i].usage); 1807 edit_redraw(); 1808 break; 1809 } 1810 1811 return NULL; 1812 } 1813 1814 1815 static char ** hostapd_cli_edit_completion_cb(void *ctx, const char *str, 1816 int pos) 1817 { 1818 char **res; 1819 const char *end; 1820 char *cmd; 1821 1822 end = os_strchr(str, ' '); 1823 if (end == NULL || str + pos < end) 1824 return list_cmd_list(); 1825 1826 cmd = os_malloc(pos + 1); 1827 if (cmd == NULL) 1828 return NULL; 1829 os_memcpy(cmd, str, pos); 1830 cmd[end - str] = '\0'; 1831 res = hostapd_cli_cmd_completion(cmd, str, pos); 1832 os_free(cmd); 1833 return res; 1834 } 1835 1836 1837 static void hostapd_cli_interactive(void) 1838 { 1839 char *hfile = NULL; 1840 char *home; 1841 1842 printf("\nInteractive mode\n\n"); 1843 1844 #ifdef CONFIG_HOSTAPD_CLI_HISTORY_DIR 1845 home = CONFIG_HOSTAPD_CLI_HISTORY_DIR; 1846 #else /* CONFIG_HOSTAPD_CLI_HISTORY_DIR */ 1847 home = getenv("HOME"); 1848 #endif /* CONFIG_HOSTAPD_CLI_HISTORY_DIR */ 1849 if (home) { 1850 const char *fname = ".hostapd_cli_history"; 1851 int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1; 1852 hfile = os_malloc(hfile_len); 1853 if (hfile) 1854 os_snprintf(hfile, hfile_len, "%s/%s", home, fname); 1855 } 1856 1857 eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL); 1858 edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb, 1859 hostapd_cli_edit_completion_cb, NULL, hfile, NULL); 1860 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL); 1861 1862 eloop_run(); 1863 1864 cli_txt_list_flush(&stations); 1865 edit_deinit(hfile, NULL); 1866 os_free(hfile); 1867 eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL); 1868 } 1869 1870 1871 static void hostapd_cli_cleanup(void) 1872 { 1873 hostapd_cli_close_connection(); 1874 if (pid_file) 1875 os_daemonize_terminate(pid_file); 1876 1877 os_program_deinit(); 1878 } 1879 1880 1881 static void hostapd_cli_action(struct wpa_ctrl *ctrl) 1882 { 1883 fd_set rfds; 1884 int fd, res; 1885 struct timeval tv; 1886 char buf[256]; 1887 size_t len; 1888 1889 fd = wpa_ctrl_get_fd(ctrl); 1890 1891 while (!hostapd_cli_quit) { 1892 FD_ZERO(&rfds); 1893 FD_SET(fd, &rfds); 1894 tv.tv_sec = ping_interval; 1895 tv.tv_usec = 0; 1896 res = select(fd + 1, &rfds, NULL, NULL, &tv); 1897 if (res < 0 && errno != EINTR) { 1898 perror("select"); 1899 break; 1900 } 1901 1902 if (FD_ISSET(fd, &rfds)) 1903 hostapd_cli_recv_pending(ctrl, 0, 1); 1904 else { 1905 len = sizeof(buf) - 1; 1906 if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len, 1907 hostapd_cli_action_process) < 0 || 1908 len < 4 || os_memcmp(buf, "PONG", 4) != 0) { 1909 printf("hostapd did not reply to PING " 1910 "command - exiting\n"); 1911 break; 1912 } 1913 } 1914 } 1915 } 1916 1917 1918 int main(int argc, char *argv[]) 1919 { 1920 int warning_displayed = 0; 1921 int c; 1922 int daemonize = 0; 1923 1924 if (os_program_init()) 1925 return -1; 1926 1927 for (;;) { 1928 c = getopt(argc, argv, "a:BhG:i:p:P:s:v"); 1929 if (c < 0) 1930 break; 1931 switch (c) { 1932 case 'a': 1933 action_file = optarg; 1934 break; 1935 case 'B': 1936 daemonize = 1; 1937 break; 1938 case 'G': 1939 ping_interval = atoi(optarg); 1940 break; 1941 case 'h': 1942 usage(); 1943 return 0; 1944 case 'v': 1945 printf("%s\n", hostapd_cli_version); 1946 return 0; 1947 case 'i': 1948 os_free(ctrl_ifname); 1949 ctrl_ifname = os_strdup(optarg); 1950 break; 1951 case 'p': 1952 ctrl_iface_dir = optarg; 1953 break; 1954 case 'P': 1955 pid_file = optarg; 1956 break; 1957 case 's': 1958 client_socket_dir = optarg; 1959 break; 1960 default: 1961 usage(); 1962 return -1; 1963 } 1964 } 1965 1966 interactive = (argc == optind) && (action_file == NULL); 1967 1968 if (interactive) { 1969 printf("%s\n\n%s\n\n", hostapd_cli_version, cli_license); 1970 } 1971 1972 if (eloop_init()) 1973 return -1; 1974 1975 for (;;) { 1976 if (ctrl_ifname == NULL) { 1977 struct dirent *dent; 1978 DIR *dir = opendir(ctrl_iface_dir); 1979 if (dir) { 1980 while ((dent = readdir(dir))) { 1981 if (os_strcmp(dent->d_name, ".") == 0 1982 || 1983 os_strcmp(dent->d_name, "..") == 0) 1984 continue; 1985 printf("Selected interface '%s'\n", 1986 dent->d_name); 1987 ctrl_ifname = os_strdup(dent->d_name); 1988 break; 1989 } 1990 closedir(dir); 1991 } 1992 } 1993 hostapd_cli_reconnect(ctrl_ifname); 1994 if (ctrl_conn) { 1995 if (warning_displayed) 1996 printf("Connection established.\n"); 1997 break; 1998 } 1999 2000 if (!interactive) { 2001 perror("Failed to connect to hostapd - " 2002 "wpa_ctrl_open"); 2003 return -1; 2004 } 2005 2006 if (!warning_displayed) { 2007 printf("Could not connect to hostapd - re-trying\n"); 2008 warning_displayed = 1; 2009 } 2010 os_sleep(1, 0); 2011 continue; 2012 } 2013 2014 if (action_file && !hostapd_cli_attached) 2015 return -1; 2016 if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue()) 2017 return -1; 2018 2019 if (interactive) 2020 hostapd_cli_interactive(); 2021 else if (action_file) 2022 hostapd_cli_action(ctrl_conn); 2023 else 2024 wpa_request(ctrl_conn, argc - optind, &argv[optind]); 2025 2026 unregister_event_handler(ctrl_conn); 2027 os_free(ctrl_ifname); 2028 eloop_destroy(); 2029 hostapd_cli_cleanup(); 2030 return 0; 2031 } 2032 2033 #else /* CONFIG_NO_CTRL_IFACE */ 2034 2035 int main(int argc, char *argv[]) 2036 { 2037 return -1; 2038 } 2039 2040 #endif /* CONFIG_NO_CTRL_IFACE */ 2041