1 /* 2 * hostapd - command line interface for hostapd daemon 3 * Copyright (c) 2004-2019, 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-2019, 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>] [-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_update_beacon(struct wpa_ctrl *ctrl, int argc, 1218 char *argv[]) 1219 { 1220 return wpa_ctrl_command(ctrl, "UPDATE_BEACON"); 1221 } 1222 1223 1224 static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1225 { 1226 char cmd[256]; 1227 int res; 1228 1229 if (argc < 2 || argc > 3) { 1230 printf("Invalid vendor command\n" 1231 "usage: <vendor id> <command id> [<hex formatted command argument>]\n"); 1232 return -1; 1233 } 1234 1235 res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s", argv[0], argv[1], 1236 argc == 3 ? argv[2] : ""); 1237 if (os_snprintf_error(sizeof(cmd), res)) { 1238 printf("Too long VENDOR command.\n"); 1239 return -1; 1240 } 1241 return wpa_ctrl_command(ctrl, cmd); 1242 } 1243 1244 1245 static int hostapd_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc, 1246 char *argv[]) 1247 { 1248 return wpa_ctrl_command(ctrl, "ERP_FLUSH"); 1249 } 1250 1251 1252 static int hostapd_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc, 1253 char *argv[]) 1254 { 1255 char cmd[256]; 1256 int res; 1257 1258 res = os_snprintf(cmd, sizeof(cmd), "LOG_LEVEL%s%s%s%s", 1259 argc >= 1 ? " " : "", 1260 argc >= 1 ? argv[0] : "", 1261 argc == 2 ? " " : "", 1262 argc == 2 ? argv[1] : ""); 1263 if (os_snprintf_error(sizeof(cmd), res)) { 1264 printf("Too long option\n"); 1265 return -1; 1266 } 1267 return wpa_ctrl_command(ctrl, cmd); 1268 } 1269 1270 1271 static int hostapd_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1272 { 1273 if (argc == 0) 1274 return -1; 1275 return hostapd_cli_cmd(ctrl, argv[0], 0, argc - 1, &argv[1]); 1276 } 1277 1278 1279 static int hostapd_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1280 { 1281 return wpa_ctrl_command(ctrl, "PMKSA"); 1282 } 1283 1284 1285 static int hostapd_cli_cmd_pmksa_flush(struct wpa_ctrl *ctrl, int argc, 1286 char *argv[]) 1287 { 1288 return wpa_ctrl_command(ctrl, "PMKSA_FLUSH"); 1289 } 1290 1291 1292 static int hostapd_cli_cmd_set_neighbor(struct wpa_ctrl *ctrl, int argc, 1293 char *argv[]) 1294 { 1295 char cmd[2048]; 1296 int res; 1297 1298 if (argc < 3 || argc > 6) { 1299 printf("Invalid set_neighbor command: needs 3-6 arguments\n"); 1300 return -1; 1301 } 1302 1303 res = os_snprintf(cmd, sizeof(cmd), "SET_NEIGHBOR %s %s %s %s %s %s", 1304 argv[0], argv[1], argv[2], argc >= 4 ? argv[3] : "", 1305 argc >= 5 ? argv[4] : "", argc == 6 ? argv[5] : ""); 1306 if (os_snprintf_error(sizeof(cmd), res)) { 1307 printf("Too long SET_NEIGHBOR command.\n"); 1308 return -1; 1309 } 1310 return wpa_ctrl_command(ctrl, cmd); 1311 } 1312 1313 1314 static int hostapd_cli_cmd_remove_neighbor(struct wpa_ctrl *ctrl, int argc, 1315 char *argv[]) 1316 { 1317 char cmd[400]; 1318 int res; 1319 1320 if (argc != 2) { 1321 printf("Invalid remove_neighbor command: needs 2 arguments\n"); 1322 return -1; 1323 } 1324 1325 res = os_snprintf(cmd, sizeof(cmd), "REMOVE_NEIGHBOR %s %s", 1326 argv[0], argv[1]); 1327 if (os_snprintf_error(sizeof(cmd), res)) { 1328 printf("Too long REMOVE_NEIGHBOR command.\n"); 1329 return -1; 1330 } 1331 return wpa_ctrl_command(ctrl, cmd); 1332 } 1333 1334 1335 static int hostapd_cli_cmd_req_lci(struct wpa_ctrl *ctrl, int argc, 1336 char *argv[]) 1337 { 1338 char cmd[256]; 1339 int res; 1340 1341 if (argc != 1) { 1342 printf("Invalid req_lci command - requires destination address\n"); 1343 return -1; 1344 } 1345 1346 res = os_snprintf(cmd, sizeof(cmd), "REQ_LCI %s", argv[0]); 1347 if (os_snprintf_error(sizeof(cmd), res)) { 1348 printf("Too long REQ_LCI command.\n"); 1349 return -1; 1350 } 1351 return wpa_ctrl_command(ctrl, cmd); 1352 } 1353 1354 1355 static int hostapd_cli_cmd_req_range(struct wpa_ctrl *ctrl, int argc, 1356 char *argv[]) 1357 { 1358 if (argc < 4) { 1359 printf("Invalid req_range command: needs at least 4 arguments - dest address, randomization interval, min AP count, and 1 to 16 AP addresses\n"); 1360 return -1; 1361 } 1362 1363 return hostapd_cli_cmd(ctrl, "REQ_RANGE", 4, argc, argv); 1364 } 1365 1366 1367 static int hostapd_cli_cmd_driver_flags(struct wpa_ctrl *ctrl, int argc, 1368 char *argv[]) 1369 { 1370 return wpa_ctrl_command(ctrl, "DRIVER_FLAGS"); 1371 } 1372 1373 1374 #ifdef CONFIG_DPP 1375 1376 static int hostapd_cli_cmd_dpp_qr_code(struct wpa_ctrl *ctrl, int argc, 1377 char *argv[]) 1378 { 1379 return hostapd_cli_cmd(ctrl, "DPP_QR_CODE", 1, argc, argv); 1380 } 1381 1382 1383 static int hostapd_cli_cmd_dpp_bootstrap_gen(struct wpa_ctrl *ctrl, int argc, 1384 char *argv[]) 1385 { 1386 return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_GEN", 1, argc, argv); 1387 } 1388 1389 1390 static int hostapd_cli_cmd_dpp_bootstrap_remove(struct wpa_ctrl *ctrl, int argc, 1391 char *argv[]) 1392 { 1393 return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_REMOVE", 1, argc, argv); 1394 } 1395 1396 1397 static int hostapd_cli_cmd_dpp_bootstrap_get_uri(struct wpa_ctrl *ctrl, 1398 int argc, char *argv[]) 1399 { 1400 return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_GET_URI", 1, argc, argv); 1401 } 1402 1403 1404 static int hostapd_cli_cmd_dpp_bootstrap_info(struct wpa_ctrl *ctrl, int argc, 1405 char *argv[]) 1406 { 1407 return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_INFO", 1, argc, argv); 1408 } 1409 1410 1411 static int hostapd_cli_cmd_dpp_auth_init(struct wpa_ctrl *ctrl, int argc, 1412 char *argv[]) 1413 { 1414 return hostapd_cli_cmd(ctrl, "DPP_AUTH_INIT", 1, argc, argv); 1415 } 1416 1417 1418 static int hostapd_cli_cmd_dpp_listen(struct wpa_ctrl *ctrl, int argc, 1419 char *argv[]) 1420 { 1421 return hostapd_cli_cmd(ctrl, "DPP_LISTEN", 1, argc, argv); 1422 } 1423 1424 1425 static int hostapd_cli_cmd_dpp_stop_listen(struct wpa_ctrl *ctrl, int argc, 1426 char *argv[]) 1427 { 1428 return wpa_ctrl_command(ctrl, "DPP_STOP_LISTEN"); 1429 } 1430 1431 1432 static int hostapd_cli_cmd_dpp_configurator_add(struct wpa_ctrl *ctrl, int argc, 1433 char *argv[]) 1434 { 1435 return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_ADD", 0, argc, argv); 1436 } 1437 1438 1439 static int hostapd_cli_cmd_dpp_configurator_remove(struct wpa_ctrl *ctrl, 1440 int argc, char *argv[]) 1441 { 1442 return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_REMOVE", 1, argc, argv); 1443 } 1444 1445 1446 static int hostapd_cli_cmd_dpp_configurator_get_key(struct wpa_ctrl *ctrl, 1447 int argc, char *argv[]) 1448 { 1449 return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_GET_KEY", 1, argc, argv); 1450 } 1451 1452 1453 static int hostapd_cli_cmd_dpp_configurator_sign(struct wpa_ctrl *ctrl, 1454 int argc, char *argv[]) 1455 { 1456 return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_SIGN", 1, argc, argv); 1457 } 1458 1459 1460 static int hostapd_cli_cmd_dpp_pkex_add(struct wpa_ctrl *ctrl, int argc, 1461 char *argv[]) 1462 { 1463 return hostapd_cli_cmd(ctrl, "DPP_PKEX_ADD", 1, argc, argv); 1464 } 1465 1466 1467 static int hostapd_cli_cmd_dpp_pkex_remove(struct wpa_ctrl *ctrl, int argc, 1468 char *argv[]) 1469 { 1470 return hostapd_cli_cmd(ctrl, "DPP_PKEX_REMOVE", 1, argc, argv); 1471 } 1472 1473 #endif /* CONFIG_DPP */ 1474 1475 1476 static int hostapd_cli_cmd_accept_macacl(struct wpa_ctrl *ctrl, int argc, 1477 char *argv[]) 1478 { 1479 return hostapd_cli_cmd(ctrl, "ACCEPT_ACL", 1, argc, argv); 1480 } 1481 1482 1483 static int hostapd_cli_cmd_deny_macacl(struct wpa_ctrl *ctrl, int argc, 1484 char *argv[]) 1485 { 1486 return hostapd_cli_cmd(ctrl, "DENY_ACL", 1, argc, argv); 1487 } 1488 1489 1490 static int hostapd_cli_cmd_poll_sta(struct wpa_ctrl *ctrl, int argc, 1491 char *argv[]) 1492 { 1493 return hostapd_cli_cmd(ctrl, "POLL_STA", 1, argc, argv); 1494 } 1495 1496 1497 static int hostapd_cli_cmd_req_beacon(struct wpa_ctrl *ctrl, int argc, 1498 char *argv[]) 1499 { 1500 return hostapd_cli_cmd(ctrl, "REQ_BEACON", 2, argc, argv); 1501 } 1502 1503 1504 static int hostapd_cli_cmd_reload_wpa_psk(struct wpa_ctrl *ctrl, int argc, 1505 char *argv[]) 1506 { 1507 return wpa_ctrl_command(ctrl, "RELOAD_WPA_PSK"); 1508 } 1509 1510 1511 struct hostapd_cli_cmd { 1512 const char *cmd; 1513 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]); 1514 char ** (*completion)(const char *str, int pos); 1515 const char *usage; 1516 }; 1517 1518 static const struct hostapd_cli_cmd hostapd_cli_commands[] = { 1519 { "ping", hostapd_cli_cmd_ping, NULL, 1520 "= pings hostapd" }, 1521 { "mib", hostapd_cli_cmd_mib, NULL, 1522 "= get MIB variables (dot1x, dot11, radius)" }, 1523 { "relog", hostapd_cli_cmd_relog, NULL, 1524 "= reload/truncate debug log output file" }, 1525 { "status", hostapd_cli_cmd_status, NULL, 1526 "= show interface status info" }, 1527 { "sta", hostapd_cli_cmd_sta, hostapd_complete_stations, 1528 "<addr> = get MIB variables for one station" }, 1529 { "all_sta", hostapd_cli_cmd_all_sta, NULL, 1530 "= get MIB variables for all stations" }, 1531 { "list_sta", hostapd_cli_cmd_list_sta, NULL, 1532 "= list all stations" }, 1533 { "new_sta", hostapd_cli_cmd_new_sta, NULL, 1534 "<addr> = add a new station" }, 1535 { "deauthenticate", hostapd_cli_cmd_deauthenticate, 1536 hostapd_complete_stations, 1537 "<addr> = deauthenticate a station" }, 1538 { "disassociate", hostapd_cli_cmd_disassociate, 1539 hostapd_complete_stations, 1540 "<addr> = disassociate a station" }, 1541 #ifdef CONFIG_TAXONOMY 1542 { "signature", hostapd_cli_cmd_signature, hostapd_complete_stations, 1543 "<addr> = get taxonomy signature for a station" }, 1544 #endif /* CONFIG_TAXONOMY */ 1545 #ifdef CONFIG_IEEE80211W 1546 { "sa_query", hostapd_cli_cmd_sa_query, hostapd_complete_stations, 1547 "<addr> = send SA Query to a station" }, 1548 #endif /* CONFIG_IEEE80211W */ 1549 #ifdef CONFIG_WPS 1550 { "wps_pin", hostapd_cli_cmd_wps_pin, NULL, 1551 "<uuid> <pin> [timeout] [addr] = add WPS Enrollee PIN" }, 1552 { "wps_check_pin", hostapd_cli_cmd_wps_check_pin, NULL, 1553 "<PIN> = verify PIN checksum" }, 1554 { "wps_pbc", hostapd_cli_cmd_wps_pbc, NULL, 1555 "= indicate button pushed to initiate PBC" }, 1556 { "wps_cancel", hostapd_cli_cmd_wps_cancel, NULL, 1557 "= cancel the pending WPS operation" }, 1558 #ifdef CONFIG_WPS_NFC 1559 { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read, NULL, 1560 "<hexdump> = report read NFC tag with WPS data" }, 1561 { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token, NULL, 1562 "<WPS/NDEF> = build NFC configuration token" }, 1563 { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token, NULL, 1564 "<WPS/NDEF/enable/disable> = manager NFC password token" }, 1565 { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel, NULL, 1566 NULL }, 1567 #endif /* CONFIG_WPS_NFC */ 1568 { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin, NULL, 1569 "<cmd> [params..] = enable/disable AP PIN" }, 1570 { "wps_config", hostapd_cli_cmd_wps_config, NULL, 1571 "<SSID> <auth> <encr> <key> = configure AP" }, 1572 { "wps_get_status", hostapd_cli_cmd_wps_get_status, NULL, 1573 "= show current WPS status" }, 1574 #endif /* CONFIG_WPS */ 1575 { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent, NULL, 1576 "= send Disassociation Imminent notification" }, 1577 { "ess_disassoc", hostapd_cli_cmd_ess_disassoc, NULL, 1578 "= send ESS Dissassociation Imminent notification" }, 1579 { "bss_tm_req", hostapd_cli_cmd_bss_tm_req, NULL, 1580 "= send BSS Transition Management Request" }, 1581 { "get_config", hostapd_cli_cmd_get_config, NULL, 1582 "= show current configuration" }, 1583 { "help", hostapd_cli_cmd_help, hostapd_cli_complete_help, 1584 "= show this usage help" }, 1585 { "interface", hostapd_cli_cmd_interface, hostapd_complete_interface, 1586 "[ifname] = show interfaces/select interface" }, 1587 #ifdef CONFIG_FST 1588 { "fst", hostapd_cli_cmd_fst, NULL, 1589 "<params...> = send FST-MANAGER control interface command" }, 1590 #endif /* CONFIG_FST */ 1591 { "raw", hostapd_cli_cmd_raw, NULL, 1592 "<params..> = send unprocessed command" }, 1593 { "level", hostapd_cli_cmd_level, NULL, 1594 "<debug level> = change debug level" }, 1595 { "license", hostapd_cli_cmd_license, NULL, 1596 "= show full hostapd_cli license" }, 1597 { "quit", hostapd_cli_cmd_quit, NULL, 1598 "= exit hostapd_cli" }, 1599 { "set", hostapd_cli_cmd_set, hostapd_complete_set, 1600 "<name> <value> = set runtime variables" }, 1601 { "get", hostapd_cli_cmd_get, hostapd_complete_get, 1602 "<name> = get runtime info" }, 1603 { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set, NULL, 1604 "<arg,arg,...> = set QoS Map set element" }, 1605 { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf, 1606 hostapd_complete_stations, 1607 "<addr> = send QoS Map Configure frame" }, 1608 { "chan_switch", hostapd_cli_cmd_chan_switch, NULL, 1609 "<cs_count> <freq> [sec_channel_offset=] [center_freq1=]\n" 1610 " [center_freq2=] [bandwidth=] [blocktx] [ht|vht]\n" 1611 " = initiate channel switch announcement" }, 1612 { "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif, NULL, 1613 "<addr> <url>\n" 1614 " = send WNM-Notification Subscription Remediation Request" }, 1615 { "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req, NULL, 1616 "<addr> <code (0/1)> <Re-auth-Delay(sec)> [url]\n" 1617 " = send WNM-Notification imminent deauthentication indication" }, 1618 { "vendor", hostapd_cli_cmd_vendor, NULL, 1619 "<vendor id> <sub command id> [<hex formatted data>]\n" 1620 " = send vendor driver command" }, 1621 { "enable", hostapd_cli_cmd_enable, NULL, 1622 "= enable hostapd on current interface" }, 1623 { "reload", hostapd_cli_cmd_reload, NULL, 1624 "= reload configuration for current interface" }, 1625 { "disable", hostapd_cli_cmd_disable, NULL, 1626 "= disable hostapd on current interface" }, 1627 { "update_beacon", hostapd_cli_cmd_update_beacon, NULL, 1628 "= update Beacon frame contents\n"}, 1629 { "erp_flush", hostapd_cli_cmd_erp_flush, NULL, 1630 "= drop all ERP keys"}, 1631 { "log_level", hostapd_cli_cmd_log_level, NULL, 1632 "[level] = show/change log verbosity level" }, 1633 { "pmksa", hostapd_cli_cmd_pmksa, NULL, 1634 " = show PMKSA cache entries" }, 1635 { "pmksa_flush", hostapd_cli_cmd_pmksa_flush, NULL, 1636 " = flush PMKSA cache" }, 1637 { "set_neighbor", hostapd_cli_cmd_set_neighbor, NULL, 1638 "<addr> <ssid=> <nr=> [lci=] [civic=] [stat]\n" 1639 " = add AP to neighbor database" }, 1640 { "remove_neighbor", hostapd_cli_cmd_remove_neighbor, NULL, 1641 "<addr> <ssid=> = remove AP from neighbor database" }, 1642 { "req_lci", hostapd_cli_cmd_req_lci, hostapd_complete_stations, 1643 "<addr> = send LCI request to a station"}, 1644 { "req_range", hostapd_cli_cmd_req_range, NULL, 1645 " = send FTM range request"}, 1646 { "driver_flags", hostapd_cli_cmd_driver_flags, NULL, 1647 " = show supported driver flags"}, 1648 #ifdef CONFIG_DPP 1649 { "dpp_qr_code", hostapd_cli_cmd_dpp_qr_code, NULL, 1650 "report a scanned DPP URI from a QR Code" }, 1651 { "dpp_bootstrap_gen", hostapd_cli_cmd_dpp_bootstrap_gen, NULL, 1652 "type=<qrcode> [chan=..] [mac=..] [info=..] [curve=..] [key=..] = generate DPP bootstrap information" }, 1653 { "dpp_bootstrap_remove", hostapd_cli_cmd_dpp_bootstrap_remove, NULL, 1654 "*|<id> = remove DPP bootstrap information" }, 1655 { "dpp_bootstrap_get_uri", hostapd_cli_cmd_dpp_bootstrap_get_uri, NULL, 1656 "<id> = get DPP bootstrap URI" }, 1657 { "dpp_bootstrap_info", hostapd_cli_cmd_dpp_bootstrap_info, NULL, 1658 "<id> = show DPP bootstrap information" }, 1659 { "dpp_auth_init", hostapd_cli_cmd_dpp_auth_init, NULL, 1660 "peer=<id> [own=<id>] = initiate DPP bootstrapping" }, 1661 { "dpp_listen", hostapd_cli_cmd_dpp_listen, NULL, 1662 "<freq in MHz> = start DPP listen" }, 1663 { "dpp_stop_listen", hostapd_cli_cmd_dpp_stop_listen, NULL, 1664 "= stop DPP listen" }, 1665 { "dpp_configurator_add", hostapd_cli_cmd_dpp_configurator_add, NULL, 1666 "[curve=..] [key=..] = add DPP configurator" }, 1667 { "dpp_configurator_remove", hostapd_cli_cmd_dpp_configurator_remove, 1668 NULL, 1669 "*|<id> = remove DPP configurator" }, 1670 { "dpp_configurator_get_key", hostapd_cli_cmd_dpp_configurator_get_key, 1671 NULL, 1672 "<id> = Get DPP configurator's private key" }, 1673 { "dpp_configurator_sign", hostapd_cli_cmd_dpp_configurator_sign, NULL, 1674 "conf=<role> configurator=<id> = generate self DPP configuration" }, 1675 { "dpp_pkex_add", hostapd_cli_cmd_dpp_pkex_add, NULL, 1676 "add PKEX code" }, 1677 { "dpp_pkex_remove", hostapd_cli_cmd_dpp_pkex_remove, NULL, 1678 "*|<id> = remove DPP pkex information" }, 1679 #endif /* CONFIG_DPP */ 1680 { "accept_acl", hostapd_cli_cmd_accept_macacl, NULL, 1681 "=Add/Delete/Show/Clear accept MAC ACL" }, 1682 { "deny_acl", hostapd_cli_cmd_deny_macacl, NULL, 1683 "=Add/Delete/Show/Clear deny MAC ACL" }, 1684 { "poll_sta", hostapd_cli_cmd_poll_sta, hostapd_complete_stations, 1685 "<addr> = poll a STA to check connectivity with a QoS null frame" }, 1686 { "req_beacon", hostapd_cli_cmd_req_beacon, NULL, 1687 "<addr> [req_mode=] <measurement request hexdump> = send a Beacon report request to a station" }, 1688 { "reload_wpa_psk", hostapd_cli_cmd_reload_wpa_psk, NULL, 1689 "= reload wpa_psk_file only" }, 1690 { NULL, NULL, NULL, NULL } 1691 }; 1692 1693 1694 /* 1695 * Prints command usage, lines are padded with the specified string. 1696 */ 1697 static void print_cmd_help(FILE *stream, const struct hostapd_cli_cmd *cmd, 1698 const char *pad) 1699 { 1700 char c; 1701 size_t n; 1702 1703 if (cmd->usage == NULL) 1704 return; 1705 fprintf(stream, "%s%s ", pad, cmd->cmd); 1706 for (n = 0; (c = cmd->usage[n]); n++) { 1707 fprintf(stream, "%c", c); 1708 if (c == '\n') 1709 fprintf(stream, "%s", pad); 1710 } 1711 fprintf(stream, "\n"); 1712 } 1713 1714 1715 static void print_help(FILE *stream, const char *cmd) 1716 { 1717 int n; 1718 1719 fprintf(stream, "commands:\n"); 1720 for (n = 0; hostapd_cli_commands[n].cmd; n++) { 1721 if (cmd == NULL || str_starts(hostapd_cli_commands[n].cmd, cmd)) 1722 print_cmd_help(stream, &hostapd_cli_commands[n], " "); 1723 } 1724 } 1725 1726 1727 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1728 { 1729 const struct hostapd_cli_cmd *cmd, *match = NULL; 1730 int count; 1731 1732 count = 0; 1733 cmd = hostapd_cli_commands; 1734 while (cmd->cmd) { 1735 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) { 1736 match = cmd; 1737 if (os_strcasecmp(cmd->cmd, argv[0]) == 0) { 1738 /* we have an exact match */ 1739 count = 1; 1740 break; 1741 } 1742 count++; 1743 } 1744 cmd++; 1745 } 1746 1747 if (count > 1) { 1748 printf("Ambiguous command '%s'; possible commands:", argv[0]); 1749 cmd = hostapd_cli_commands; 1750 while (cmd->cmd) { 1751 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 1752 0) { 1753 printf(" %s", cmd->cmd); 1754 } 1755 cmd++; 1756 } 1757 printf("\n"); 1758 } else if (count == 0) { 1759 printf("Unknown command '%s'\n", argv[0]); 1760 } else { 1761 match->handler(ctrl, argc - 1, &argv[1]); 1762 } 1763 } 1764 1765 1766 static void cli_event(const char *str) 1767 { 1768 const char *start, *s; 1769 1770 start = os_strchr(str, '>'); 1771 if (start == NULL) 1772 return; 1773 1774 start++; 1775 1776 if (str_starts(start, AP_STA_CONNECTED)) { 1777 s = os_strchr(start, ' '); 1778 if (s == NULL) 1779 return; 1780 cli_txt_list_add(&stations, s + 1); 1781 return; 1782 } 1783 1784 if (str_starts(start, AP_STA_DISCONNECTED)) { 1785 s = os_strchr(start, ' '); 1786 if (s == NULL) 1787 return; 1788 cli_txt_list_del_addr(&stations, s + 1); 1789 return; 1790 } 1791 } 1792 1793 1794 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read, 1795 int action_monitor) 1796 { 1797 int first = 1; 1798 if (ctrl_conn == NULL) 1799 return; 1800 while (wpa_ctrl_pending(ctrl)) { 1801 char buf[4096]; 1802 size_t len = sizeof(buf) - 1; 1803 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) { 1804 buf[len] = '\0'; 1805 if (action_monitor) 1806 hostapd_cli_action_process(buf, len); 1807 else { 1808 cli_event(buf); 1809 if (in_read && first) 1810 printf("\n"); 1811 first = 0; 1812 printf("%s\n", buf); 1813 } 1814 } else { 1815 printf("Could not read pending message.\n"); 1816 break; 1817 } 1818 } 1819 } 1820 1821 1822 static void hostapd_cli_receive(int sock, void *eloop_ctx, void *sock_ctx) 1823 { 1824 hostapd_cli_recv_pending(ctrl_conn, 0, 0); 1825 } 1826 1827 1828 static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx) 1829 { 1830 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) { 1831 printf("Connection to hostapd lost - trying to reconnect\n"); 1832 hostapd_cli_close_connection(); 1833 } 1834 if (!ctrl_conn && hostapd_cli_reconnect(ctrl_ifname) == 0) 1835 printf("Connection to hostapd re-established\n"); 1836 if (ctrl_conn) 1837 hostapd_cli_recv_pending(ctrl_conn, 1, 0); 1838 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL); 1839 } 1840 1841 1842 static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx) 1843 { 1844 eloop_terminate(); 1845 } 1846 1847 1848 static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd) 1849 { 1850 char *argv[max_args]; 1851 int argc; 1852 argc = tokenize_cmd(cmd, argv); 1853 if (argc) 1854 wpa_request(ctrl_conn, argc, argv); 1855 } 1856 1857 1858 static void hostapd_cli_edit_eof_cb(void *ctx) 1859 { 1860 eloop_terminate(); 1861 } 1862 1863 1864 static char ** list_cmd_list(void) 1865 { 1866 char **res; 1867 int i, count; 1868 1869 count = ARRAY_SIZE(hostapd_cli_commands); 1870 res = os_calloc(count + 1, sizeof(char *)); 1871 if (res == NULL) 1872 return NULL; 1873 1874 for (i = 0; hostapd_cli_commands[i].cmd; i++) { 1875 res[i] = os_strdup(hostapd_cli_commands[i].cmd); 1876 if (res[i] == NULL) 1877 break; 1878 } 1879 1880 return res; 1881 } 1882 1883 1884 static char ** hostapd_cli_cmd_completion(const char *cmd, const char *str, 1885 int pos) 1886 { 1887 int i; 1888 1889 for (i = 0; hostapd_cli_commands[i].cmd; i++) { 1890 if (os_strcasecmp(hostapd_cli_commands[i].cmd, cmd) != 0) 1891 continue; 1892 if (hostapd_cli_commands[i].completion) 1893 return hostapd_cli_commands[i].completion(str, pos); 1894 if (!hostapd_cli_commands[i].usage) 1895 return NULL; 1896 edit_clear_line(); 1897 printf("\r%s\n", hostapd_cli_commands[i].usage); 1898 edit_redraw(); 1899 break; 1900 } 1901 1902 return NULL; 1903 } 1904 1905 1906 static char ** hostapd_cli_edit_completion_cb(void *ctx, const char *str, 1907 int pos) 1908 { 1909 char **res; 1910 const char *end; 1911 char *cmd; 1912 1913 end = os_strchr(str, ' '); 1914 if (end == NULL || str + pos < end) 1915 return list_cmd_list(); 1916 1917 cmd = os_malloc(pos + 1); 1918 if (cmd == NULL) 1919 return NULL; 1920 os_memcpy(cmd, str, pos); 1921 cmd[end - str] = '\0'; 1922 res = hostapd_cli_cmd_completion(cmd, str, pos); 1923 os_free(cmd); 1924 return res; 1925 } 1926 1927 1928 static void hostapd_cli_interactive(void) 1929 { 1930 char *hfile = NULL; 1931 char *home; 1932 1933 printf("\nInteractive mode\n\n"); 1934 1935 #ifdef CONFIG_HOSTAPD_CLI_HISTORY_DIR 1936 home = CONFIG_HOSTAPD_CLI_HISTORY_DIR; 1937 #else /* CONFIG_HOSTAPD_CLI_HISTORY_DIR */ 1938 home = getenv("HOME"); 1939 #endif /* CONFIG_HOSTAPD_CLI_HISTORY_DIR */ 1940 if (home) { 1941 const char *fname = ".hostapd_cli_history"; 1942 int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1; 1943 hfile = os_malloc(hfile_len); 1944 if (hfile) 1945 os_snprintf(hfile, hfile_len, "%s/%s", home, fname); 1946 } 1947 1948 eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL); 1949 edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb, 1950 hostapd_cli_edit_completion_cb, NULL, hfile, NULL); 1951 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL); 1952 1953 eloop_run(); 1954 1955 cli_txt_list_flush(&stations); 1956 edit_deinit(hfile, NULL); 1957 os_free(hfile); 1958 eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL); 1959 } 1960 1961 1962 static void hostapd_cli_cleanup(void) 1963 { 1964 hostapd_cli_close_connection(); 1965 if (pid_file) 1966 os_daemonize_terminate(pid_file); 1967 1968 os_program_deinit(); 1969 } 1970 1971 1972 static void hostapd_cli_action(struct wpa_ctrl *ctrl) 1973 { 1974 fd_set rfds; 1975 int fd, res; 1976 struct timeval tv; 1977 char buf[256]; 1978 size_t len; 1979 1980 fd = wpa_ctrl_get_fd(ctrl); 1981 1982 while (!hostapd_cli_quit) { 1983 FD_ZERO(&rfds); 1984 FD_SET(fd, &rfds); 1985 tv.tv_sec = ping_interval; 1986 tv.tv_usec = 0; 1987 res = select(fd + 1, &rfds, NULL, NULL, &tv); 1988 if (res < 0 && errno != EINTR) { 1989 perror("select"); 1990 break; 1991 } 1992 1993 if (FD_ISSET(fd, &rfds)) 1994 hostapd_cli_recv_pending(ctrl, 0, 1); 1995 else { 1996 len = sizeof(buf) - 1; 1997 if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len, 1998 hostapd_cli_action_process) < 0 || 1999 len < 4 || os_memcmp(buf, "PONG", 4) != 0) { 2000 printf("hostapd did not reply to PING " 2001 "command - exiting\n"); 2002 break; 2003 } 2004 } 2005 } 2006 } 2007 2008 2009 int main(int argc, char *argv[]) 2010 { 2011 int warning_displayed = 0; 2012 int c; 2013 int daemonize = 0; 2014 2015 if (os_program_init()) 2016 return -1; 2017 2018 for (;;) { 2019 c = getopt(argc, argv, "a:BhG:i:p:P:s:v"); 2020 if (c < 0) 2021 break; 2022 switch (c) { 2023 case 'a': 2024 action_file = optarg; 2025 break; 2026 case 'B': 2027 daemonize = 1; 2028 break; 2029 case 'G': 2030 ping_interval = atoi(optarg); 2031 break; 2032 case 'h': 2033 usage(); 2034 return 0; 2035 case 'v': 2036 printf("%s\n", hostapd_cli_version); 2037 return 0; 2038 case 'i': 2039 os_free(ctrl_ifname); 2040 ctrl_ifname = os_strdup(optarg); 2041 break; 2042 case 'p': 2043 ctrl_iface_dir = optarg; 2044 break; 2045 case 'P': 2046 pid_file = optarg; 2047 break; 2048 case 's': 2049 client_socket_dir = optarg; 2050 break; 2051 default: 2052 usage(); 2053 return -1; 2054 } 2055 } 2056 2057 interactive = (argc == optind) && (action_file == NULL); 2058 2059 if (interactive) { 2060 printf("%s\n\n%s\n\n", hostapd_cli_version, cli_license); 2061 } 2062 2063 if (eloop_init()) 2064 return -1; 2065 2066 for (;;) { 2067 if (ctrl_ifname == NULL) { 2068 struct dirent *dent; 2069 DIR *dir = opendir(ctrl_iface_dir); 2070 if (dir) { 2071 while ((dent = readdir(dir))) { 2072 if (os_strcmp(dent->d_name, ".") == 0 2073 || 2074 os_strcmp(dent->d_name, "..") == 0) 2075 continue; 2076 printf("Selected interface '%s'\n", 2077 dent->d_name); 2078 ctrl_ifname = os_strdup(dent->d_name); 2079 break; 2080 } 2081 closedir(dir); 2082 } 2083 } 2084 hostapd_cli_reconnect(ctrl_ifname); 2085 if (ctrl_conn) { 2086 if (warning_displayed) 2087 printf("Connection established.\n"); 2088 break; 2089 } 2090 2091 if (!interactive) { 2092 perror("Failed to connect to hostapd - " 2093 "wpa_ctrl_open"); 2094 return -1; 2095 } 2096 2097 if (!warning_displayed) { 2098 printf("Could not connect to hostapd - re-trying\n"); 2099 warning_displayed = 1; 2100 } 2101 os_sleep(1, 0); 2102 continue; 2103 } 2104 2105 if (action_file && !hostapd_cli_attached) 2106 return -1; 2107 if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue()) 2108 return -1; 2109 2110 if (interactive) 2111 hostapd_cli_interactive(); 2112 else if (action_file) 2113 hostapd_cli_action(ctrl_conn); 2114 else 2115 wpa_request(ctrl_conn, argc - optind, &argv[optind]); 2116 2117 unregister_event_handler(ctrl_conn); 2118 os_free(ctrl_ifname); 2119 eloop_destroy(); 2120 hostapd_cli_cleanup(); 2121 return 0; 2122 } 2123 2124 #else /* CONFIG_NO_CTRL_IFACE */ 2125 2126 int main(int argc, char *argv[]) 2127 { 2128 return -1; 2129 } 2130 2131 #endif /* CONFIG_NO_CTRL_IFACE */ 2132