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