1 /* 2 * WPA Supplicant - command line interface for wpa_supplicant daemon 3 * Copyright (c) 2004-2013, 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 11 #ifdef CONFIG_CTRL_IFACE 12 13 #ifdef CONFIG_CTRL_IFACE_UNIX 14 #include <dirent.h> 15 #endif /* CONFIG_CTRL_IFACE_UNIX */ 16 17 #include "common/wpa_ctrl.h" 18 #include "utils/common.h" 19 #include "utils/eloop.h" 20 #include "utils/edit.h" 21 #include "utils/list.h" 22 #include "common/version.h" 23 #include "common/ieee802_11_defs.h" 24 #ifdef ANDROID 25 #include <cutils/properties.h> 26 #endif /* ANDROID */ 27 28 29 static const char *wpa_cli_version = 30 "wpa_cli v" VERSION_STR "\n" 31 "Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> and contributors"; 32 33 34 static const char *wpa_cli_license = 35 "This software may be distributed under the terms of the BSD license.\n" 36 "See README for more details.\n"; 37 38 static const char *wpa_cli_full_license = 39 "This software may be distributed under the terms of the BSD license.\n" 40 "\n" 41 "Redistribution and use in source and binary forms, with or without\n" 42 "modification, are permitted provided that the following conditions are\n" 43 "met:\n" 44 "\n" 45 "1. Redistributions of source code must retain the above copyright\n" 46 " notice, this list of conditions and the following disclaimer.\n" 47 "\n" 48 "2. Redistributions in binary form must reproduce the above copyright\n" 49 " notice, this list of conditions and the following disclaimer in the\n" 50 " documentation and/or other materials provided with the distribution.\n" 51 "\n" 52 "3. Neither the name(s) of the above-listed copyright holder(s) nor the\n" 53 " names of its contributors may be used to endorse or promote products\n" 54 " derived from this software without specific prior written permission.\n" 55 "\n" 56 "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n" 57 "\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n" 58 "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n" 59 "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n" 60 "OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n" 61 "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n" 62 "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n" 63 "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n" 64 "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n" 65 "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n" 66 "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" 67 "\n"; 68 69 static struct wpa_ctrl *ctrl_conn; 70 static struct wpa_ctrl *mon_conn; 71 static int wpa_cli_quit = 0; 72 static int wpa_cli_attached = 0; 73 static int wpa_cli_connected = -1; 74 static int wpa_cli_last_id = 0; 75 #ifndef CONFIG_CTRL_IFACE_DIR 76 #define CONFIG_CTRL_IFACE_DIR "/var/run/wpa_supplicant" 77 #endif /* CONFIG_CTRL_IFACE_DIR */ 78 static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR; 79 static char *ctrl_ifname = NULL; 80 static const char *pid_file = NULL; 81 static const char *action_file = NULL; 82 static int ping_interval = 5; 83 static int interactive = 0; 84 static char *ifname_prefix = NULL; 85 86 struct cli_txt_entry { 87 struct dl_list list; 88 char *txt; 89 }; 90 91 static DEFINE_DL_LIST(bsses); /* struct cli_txt_entry */ 92 static DEFINE_DL_LIST(p2p_peers); /* struct cli_txt_entry */ 93 static DEFINE_DL_LIST(p2p_groups); /* struct cli_txt_entry */ 94 static DEFINE_DL_LIST(ifnames); /* struct cli_txt_entry */ 95 96 97 static void print_help(const char *cmd); 98 static void wpa_cli_mon_receive(int sock, void *eloop_ctx, void *sock_ctx); 99 static void wpa_cli_close_connection(void); 100 static char * wpa_cli_get_default_ifname(void); 101 static char ** wpa_list_cmd_list(void); 102 103 104 static void usage(void) 105 { 106 printf("wpa_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hvB] " 107 "[-a<action file>] \\\n" 108 " [-P<pid file>] [-g<global ctrl>] [-G<ping interval>] " 109 "[command..]\n" 110 " -h = help (show this usage text)\n" 111 " -v = shown version information\n" 112 " -a = run in daemon mode executing the action file based on " 113 "events from\n" 114 " wpa_supplicant\n" 115 " -B = run a daemon in the background\n" 116 " default path: " CONFIG_CTRL_IFACE_DIR "\n" 117 " default interface: first interface found in socket path\n"); 118 print_help(NULL); 119 } 120 121 122 static void cli_txt_list_free(struct cli_txt_entry *e) 123 { 124 dl_list_del(&e->list); 125 os_free(e->txt); 126 os_free(e); 127 } 128 129 130 static void cli_txt_list_flush(struct dl_list *list) 131 { 132 struct cli_txt_entry *e; 133 while ((e = dl_list_first(list, struct cli_txt_entry, list))) 134 cli_txt_list_free(e); 135 } 136 137 138 static struct cli_txt_entry * cli_txt_list_get(struct dl_list *txt_list, 139 const char *txt) 140 { 141 struct cli_txt_entry *e; 142 dl_list_for_each(e, txt_list, struct cli_txt_entry, list) { 143 if (os_strcmp(e->txt, txt) == 0) 144 return e; 145 } 146 return NULL; 147 } 148 149 150 static void cli_txt_list_del(struct dl_list *txt_list, const char *txt) 151 { 152 struct cli_txt_entry *e; 153 e = cli_txt_list_get(txt_list, txt); 154 if (e) 155 cli_txt_list_free(e); 156 } 157 158 159 static void cli_txt_list_del_addr(struct dl_list *txt_list, const char *txt) 160 { 161 u8 addr[ETH_ALEN]; 162 char buf[18]; 163 if (hwaddr_aton(txt, addr) < 0) 164 return; 165 os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); 166 cli_txt_list_del(txt_list, buf); 167 } 168 169 170 #ifdef CONFIG_P2P 171 static void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt) 172 { 173 const char *end; 174 char *buf; 175 end = os_strchr(txt, ' '); 176 if (end == NULL) 177 end = txt + os_strlen(txt); 178 buf = dup_binstr(txt, end - txt); 179 if (buf == NULL) 180 return; 181 cli_txt_list_del(txt_list, buf); 182 os_free(buf); 183 } 184 #endif /* CONFIG_P2P */ 185 186 187 static int cli_txt_list_add(struct dl_list *txt_list, const char *txt) 188 { 189 struct cli_txt_entry *e; 190 e = cli_txt_list_get(txt_list, txt); 191 if (e) 192 return 0; 193 e = os_zalloc(sizeof(*e)); 194 if (e == NULL) 195 return -1; 196 e->txt = os_strdup(txt); 197 if (e->txt == NULL) { 198 os_free(e); 199 return -1; 200 } 201 dl_list_add(txt_list, &e->list); 202 return 0; 203 } 204 205 206 #ifdef CONFIG_P2P 207 static int cli_txt_list_add_addr(struct dl_list *txt_list, const char *txt) 208 { 209 u8 addr[ETH_ALEN]; 210 char buf[18]; 211 if (hwaddr_aton(txt, addr) < 0) 212 return -1; 213 os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); 214 return cli_txt_list_add(txt_list, buf); 215 } 216 217 218 static int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt) 219 { 220 const char *end; 221 char *buf; 222 int ret; 223 end = os_strchr(txt, ' '); 224 if (end == NULL) 225 end = txt + os_strlen(txt); 226 buf = dup_binstr(txt, end - txt); 227 if (buf == NULL) 228 return -1; 229 ret = cli_txt_list_add(txt_list, buf); 230 os_free(buf); 231 return ret; 232 } 233 #endif /* CONFIG_P2P */ 234 235 236 static char ** cli_txt_list_array(struct dl_list *txt_list) 237 { 238 unsigned int i, count = dl_list_len(txt_list); 239 char **res; 240 struct cli_txt_entry *e; 241 242 res = os_calloc(count + 1, sizeof(char *)); 243 if (res == NULL) 244 return NULL; 245 246 i = 0; 247 dl_list_for_each(e, txt_list, struct cli_txt_entry, list) { 248 res[i] = os_strdup(e->txt); 249 if (res[i] == NULL) 250 break; 251 i++; 252 } 253 254 return res; 255 } 256 257 258 static int get_cmd_arg_num(const char *str, int pos) 259 { 260 int arg = 0, i; 261 262 for (i = 0; i <= pos; i++) { 263 if (str[i] != ' ') { 264 arg++; 265 while (i <= pos && str[i] != ' ') 266 i++; 267 } 268 } 269 270 if (arg > 0) 271 arg--; 272 return arg; 273 } 274 275 276 static int str_starts(const char *src, const char *match) 277 { 278 return os_strncmp(src, match, os_strlen(match)) == 0; 279 } 280 281 282 static int wpa_cli_show_event(const char *event) 283 { 284 const char *start; 285 286 start = os_strchr(event, '>'); 287 if (start == NULL) 288 return 1; 289 290 start++; 291 /* 292 * Skip BSS added/removed events since they can be relatively frequent 293 * and are likely of not much use for an interactive user. 294 */ 295 if (str_starts(start, WPA_EVENT_BSS_ADDED) || 296 str_starts(start, WPA_EVENT_BSS_REMOVED)) 297 return 0; 298 299 return 1; 300 } 301 302 303 static int wpa_cli_open_connection(const char *ifname, int attach) 304 { 305 #if defined(CONFIG_CTRL_IFACE_UDP) || defined(CONFIG_CTRL_IFACE_NAMED_PIPE) 306 ctrl_conn = wpa_ctrl_open(ifname); 307 if (ctrl_conn == NULL) 308 return -1; 309 310 if (attach && interactive) 311 mon_conn = wpa_ctrl_open(ifname); 312 else 313 mon_conn = NULL; 314 #else /* CONFIG_CTRL_IFACE_UDP || CONFIG_CTRL_IFACE_NAMED_PIPE */ 315 char *cfile = NULL; 316 int flen, res; 317 318 if (ifname == NULL) 319 return -1; 320 321 #ifdef ANDROID 322 if (access(ctrl_iface_dir, F_OK) < 0) { 323 cfile = os_strdup(ifname); 324 if (cfile == NULL) 325 return -1; 326 } 327 #endif /* ANDROID */ 328 329 if (cfile == NULL) { 330 flen = os_strlen(ctrl_iface_dir) + os_strlen(ifname) + 2; 331 cfile = os_malloc(flen); 332 if (cfile == NULL) 333 return -1; 334 res = os_snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, 335 ifname); 336 if (res < 0 || res >= flen) { 337 os_free(cfile); 338 return -1; 339 } 340 } 341 342 ctrl_conn = wpa_ctrl_open(cfile); 343 if (ctrl_conn == NULL) { 344 os_free(cfile); 345 return -1; 346 } 347 348 if (attach && interactive) 349 mon_conn = wpa_ctrl_open(cfile); 350 else 351 mon_conn = NULL; 352 os_free(cfile); 353 #endif /* CONFIG_CTRL_IFACE_UDP || CONFIG_CTRL_IFACE_NAMED_PIPE */ 354 355 if (mon_conn) { 356 if (wpa_ctrl_attach(mon_conn) == 0) { 357 wpa_cli_attached = 1; 358 if (interactive) 359 eloop_register_read_sock( 360 wpa_ctrl_get_fd(mon_conn), 361 wpa_cli_mon_receive, NULL, NULL); 362 } else { 363 printf("Warning: Failed to attach to " 364 "wpa_supplicant.\n"); 365 wpa_cli_close_connection(); 366 return -1; 367 } 368 } 369 370 return 0; 371 } 372 373 374 static void wpa_cli_close_connection(void) 375 { 376 if (ctrl_conn == NULL) 377 return; 378 379 if (wpa_cli_attached) { 380 wpa_ctrl_detach(interactive ? mon_conn : ctrl_conn); 381 wpa_cli_attached = 0; 382 } 383 wpa_ctrl_close(ctrl_conn); 384 ctrl_conn = NULL; 385 if (mon_conn) { 386 eloop_unregister_read_sock(wpa_ctrl_get_fd(mon_conn)); 387 wpa_ctrl_close(mon_conn); 388 mon_conn = NULL; 389 } 390 } 391 392 393 static void wpa_cli_msg_cb(char *msg, size_t len) 394 { 395 printf("%s\n", msg); 396 } 397 398 399 static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print) 400 { 401 char buf[4096]; 402 size_t len; 403 int ret; 404 405 if (ctrl_conn == NULL) { 406 printf("Not connected to wpa_supplicant - command dropped.\n"); 407 return -1; 408 } 409 if (ifname_prefix) { 410 os_snprintf(buf, sizeof(buf), "IFNAME=%s %s", 411 ifname_prefix, cmd); 412 buf[sizeof(buf) - 1] = '\0'; 413 cmd = buf; 414 } 415 len = sizeof(buf) - 1; 416 ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, 417 wpa_cli_msg_cb); 418 if (ret == -2) { 419 printf("'%s' command timed out.\n", cmd); 420 return -2; 421 } else if (ret < 0) { 422 printf("'%s' command failed.\n", cmd); 423 return -1; 424 } 425 if (print) { 426 buf[len] = '\0'; 427 printf("%s", buf); 428 if (interactive && len > 0 && buf[len - 1] != '\n') 429 printf("\n"); 430 } 431 return 0; 432 } 433 434 435 static int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd) 436 { 437 return _wpa_ctrl_command(ctrl, cmd, 1); 438 } 439 440 441 static int write_cmd(char *buf, size_t buflen, const char *cmd, int argc, 442 char *argv[]) 443 { 444 int i, res; 445 char *pos, *end; 446 447 pos = buf; 448 end = buf + buflen; 449 450 res = os_snprintf(pos, end - pos, "%s", cmd); 451 if (res < 0 || res >= end - pos) 452 goto fail; 453 pos += res; 454 455 for (i = 0; i < argc; i++) { 456 res = os_snprintf(pos, end - pos, " %s", argv[i]); 457 if (res < 0 || res >= end - pos) 458 goto fail; 459 pos += res; 460 } 461 462 buf[buflen - 1] = '\0'; 463 return 0; 464 465 fail: 466 printf("Too long command\n"); 467 return -1; 468 } 469 470 471 static int wpa_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd, int min_args, 472 int argc, char *argv[]) 473 { 474 char buf[4096]; 475 if (argc < min_args) { 476 printf("Invalid %s command - at least %d argument%s " 477 "required.\n", cmd, min_args, 478 min_args > 1 ? "s are" : " is"); 479 return -1; 480 } 481 if (write_cmd(buf, sizeof(buf), cmd, argc, argv) < 0) 482 return -1; 483 return wpa_ctrl_command(ctrl, buf); 484 } 485 486 487 static int wpa_cli_cmd_ifname(struct wpa_ctrl *ctrl, int argc, char *argv[]) 488 { 489 return wpa_ctrl_command(ctrl, "IFNAME"); 490 } 491 492 493 static int wpa_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[]) 494 { 495 if (argc > 0 && os_strcmp(argv[0], "verbose") == 0) 496 return wpa_ctrl_command(ctrl, "STATUS-VERBOSE"); 497 if (argc > 0 && os_strcmp(argv[0], "wps") == 0) 498 return wpa_ctrl_command(ctrl, "STATUS-WPS"); 499 if (argc > 0 && os_strcmp(argv[0], "driver") == 0) 500 return wpa_ctrl_command(ctrl, "STATUS-DRIVER"); 501 return wpa_ctrl_command(ctrl, "STATUS"); 502 } 503 504 505 static int wpa_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[]) 506 { 507 return wpa_ctrl_command(ctrl, "PING"); 508 } 509 510 511 static int wpa_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[]) 512 { 513 return wpa_ctrl_command(ctrl, "RELOG"); 514 } 515 516 517 static int wpa_cli_cmd_note(struct wpa_ctrl *ctrl, int argc, char *argv[]) 518 { 519 return wpa_cli_cmd(ctrl, "NOTE", 1, argc, argv); 520 } 521 522 523 static int wpa_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[]) 524 { 525 return wpa_ctrl_command(ctrl, "MIB"); 526 } 527 528 529 static int wpa_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[]) 530 { 531 return wpa_ctrl_command(ctrl, "PMKSA"); 532 } 533 534 535 static int wpa_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[]) 536 { 537 print_help(argc > 0 ? argv[0] : NULL); 538 return 0; 539 } 540 541 542 static char ** wpa_cli_complete_help(const char *str, int pos) 543 { 544 int arg = get_cmd_arg_num(str, pos); 545 char **res = NULL; 546 547 switch (arg) { 548 case 1: 549 res = wpa_list_cmd_list(); 550 break; 551 } 552 553 return res; 554 } 555 556 557 static int wpa_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, char *argv[]) 558 { 559 printf("%s\n\n%s\n", wpa_cli_version, wpa_cli_full_license); 560 return 0; 561 } 562 563 564 static int wpa_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[]) 565 { 566 wpa_cli_quit = 1; 567 if (interactive) 568 eloop_terminate(); 569 return 0; 570 } 571 572 573 static int wpa_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[]) 574 { 575 char cmd[256]; 576 int res; 577 578 if (argc == 1) { 579 res = os_snprintf(cmd, sizeof(cmd), "SET %s ", argv[0]); 580 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { 581 printf("Too long SET command.\n"); 582 return -1; 583 } 584 return wpa_ctrl_command(ctrl, cmd); 585 } 586 587 return wpa_cli_cmd(ctrl, "SET", 2, argc, argv); 588 } 589 590 591 static char ** wpa_cli_complete_set(const char *str, int pos) 592 { 593 int arg = get_cmd_arg_num(str, pos); 594 const char *fields[] = { 595 /* runtime values */ 596 "EAPOL::heldPeriod", "EAPOL::authPeriod", "EAPOL::startPeriod", 597 "EAPOL::maxStart", "dot11RSNAConfigPMKLifetime", 598 "dot11RSNAConfigPMKReauthThreshold", "dot11RSNAConfigSATimeout", 599 "wps_fragment_size", "wps_version_number", "ampdu", 600 "tdls_testing", "tdls_disabled", "pno", "radio_disabled", 601 "uapsd", "ps", "wifi_display", "bssid_filter", "disallow_aps", 602 "no_keep_alive", 603 /* global configuration parameters */ 604 "eapol_version", "ap_scan", "disable_scan_offload", 605 "fast_reauth", "opensc_engine_path", "pkcs11_engine_path", 606 "pkcs11_module_path", "pcsc_reader", "pcsc_pin", 607 "driver_param", "dot11RSNAConfigPMKLifetime", 608 "dot11RSNAConfigPMKReauthThreshold", 609 "dot11RSNAConfigSATimeout", 610 "update_config", "load_dynamic_eap", "uuid", "device_name", 611 "manufacturer", "model_name", "model_number", "serial_number", 612 "device_type", "os_version", "config_methods", 613 "wps_cred_processing", "wps_vendor_ext_m1", "sec_device_type", 614 "p2p_listen_reg_class", "p2p_listen_channel", 615 "p2p_oper_reg_class", "p2p_oper_channel", 616 "p2p_go_intent", "p2p_ssid_postfix", "persistent_reconnect", 617 "p2p_intra_bss", "p2p_group_idle", "p2p_pref_chan", 618 "p2p_no_go_freq", 619 "p2p_go_ht40", "p2p_disabled", "p2p_no_group_iface", 620 "p2p_go_vht", 621 "p2p_ignore_shared_freq", "country", "bss_max_count", 622 "bss_expiration_age", "bss_expiration_scan_count", 623 "filter_ssids", "filter_rssi", "max_num_sta", 624 "disassoc_low_ack", "hs20", "interworking", "hessid", 625 "access_network_type", "pbc_in_m1", "autoscan", 626 "wps_nfc_dev_pw_id", "wps_nfc_dh_pubkey", "wps_nfc_dh_privkey", 627 "wps_nfc_dev_pw", "ext_password_backend", 628 "p2p_go_max_inactivity", "auto_interworking", "okc", "pmf", 629 "sae_groups", "dtim_period", "beacon_int", "ap_vendor_elements", 630 "ignore_old_scan_res", "freq_list", "external_sim", 631 "tdls_external_control" 632 }; 633 int i, num_fields = ARRAY_SIZE(fields); 634 635 if (arg == 1) { 636 char **res = os_calloc(num_fields + 1, sizeof(char *)); 637 if (res == NULL) 638 return NULL; 639 for (i = 0; i < num_fields; i++) { 640 res[i] = os_strdup(fields[i]); 641 if (res[i] == NULL) 642 return res; 643 } 644 return res; 645 } 646 647 if (arg > 1 && os_strncasecmp(str, "set bssid_filter ", 17) == 0) 648 return cli_txt_list_array(&bsses); 649 650 return NULL; 651 } 652 653 654 static int wpa_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[]) 655 { 656 return wpa_cli_cmd(ctrl, "GET", 1, argc, argv); 657 } 658 659 660 static int wpa_cli_cmd_logoff(struct wpa_ctrl *ctrl, int argc, char *argv[]) 661 { 662 return wpa_ctrl_command(ctrl, "LOGOFF"); 663 } 664 665 666 static int wpa_cli_cmd_logon(struct wpa_ctrl *ctrl, int argc, char *argv[]) 667 { 668 return wpa_ctrl_command(ctrl, "LOGON"); 669 } 670 671 672 static int wpa_cli_cmd_reassociate(struct wpa_ctrl *ctrl, int argc, 673 char *argv[]) 674 { 675 return wpa_ctrl_command(ctrl, "REASSOCIATE"); 676 } 677 678 679 static int wpa_cli_cmd_preauthenticate(struct wpa_ctrl *ctrl, int argc, 680 char *argv[]) 681 { 682 return wpa_cli_cmd(ctrl, "PREAUTH", 1, argc, argv); 683 } 684 685 686 static int wpa_cli_cmd_ap_scan(struct wpa_ctrl *ctrl, int argc, char *argv[]) 687 { 688 return wpa_cli_cmd(ctrl, "AP_SCAN", 1, argc, argv); 689 } 690 691 692 static int wpa_cli_cmd_scan_interval(struct wpa_ctrl *ctrl, int argc, 693 char *argv[]) 694 { 695 return wpa_cli_cmd(ctrl, "SCAN_INTERVAL", 1, argc, argv); 696 } 697 698 699 static int wpa_cli_cmd_bss_expire_age(struct wpa_ctrl *ctrl, int argc, 700 char *argv[]) 701 { 702 return wpa_cli_cmd(ctrl, "BSS_EXPIRE_AGE", 1, argc, argv); 703 } 704 705 706 static int wpa_cli_cmd_bss_expire_count(struct wpa_ctrl *ctrl, int argc, 707 char *argv[]) 708 { 709 return wpa_cli_cmd(ctrl, "BSS_EXPIRE_COUNT", 1, argc, argv); 710 } 711 712 713 static int wpa_cli_cmd_bss_flush(struct wpa_ctrl *ctrl, int argc, char *argv[]) 714 { 715 char cmd[256]; 716 int res; 717 718 if (argc < 1) 719 res = os_snprintf(cmd, sizeof(cmd), "BSS_FLUSH 0"); 720 else 721 res = os_snprintf(cmd, sizeof(cmd), "BSS_FLUSH %s", argv[0]); 722 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { 723 printf("Too long BSS_FLUSH command.\n"); 724 return -1; 725 } 726 return wpa_ctrl_command(ctrl, cmd); 727 } 728 729 730 static int wpa_cli_cmd_stkstart(struct wpa_ctrl *ctrl, int argc, 731 char *argv[]) 732 { 733 return wpa_cli_cmd(ctrl, "STKSTART", 1, argc, argv); 734 } 735 736 737 static int wpa_cli_cmd_ft_ds(struct wpa_ctrl *ctrl, int argc, char *argv[]) 738 { 739 return wpa_cli_cmd(ctrl, "FT_DS", 1, argc, argv); 740 } 741 742 743 static int wpa_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc, char *argv[]) 744 { 745 return wpa_cli_cmd(ctrl, "WPS_PBC", 0, argc, argv); 746 } 747 748 749 static int wpa_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, char *argv[]) 750 { 751 if (argc == 0) { 752 printf("Invalid WPS_PIN command: need one or two arguments:\n" 753 "- BSSID: use 'any' to select any\n" 754 "- PIN: optional, used only with devices that have no " 755 "display\n"); 756 return -1; 757 } 758 759 return wpa_cli_cmd(ctrl, "WPS_PIN", 1, argc, argv); 760 } 761 762 763 static int wpa_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc, 764 char *argv[]) 765 { 766 return wpa_cli_cmd(ctrl, "WPS_CHECK_PIN", 1, argc, argv); 767 } 768 769 770 static int wpa_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc, 771 char *argv[]) 772 { 773 return wpa_ctrl_command(ctrl, "WPS_CANCEL"); 774 } 775 776 777 #ifdef CONFIG_WPS_NFC 778 779 static int wpa_cli_cmd_wps_nfc(struct wpa_ctrl *ctrl, int argc, char *argv[]) 780 { 781 return wpa_cli_cmd(ctrl, "WPS_NFC", 0, argc, argv); 782 } 783 784 785 static int wpa_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl, int argc, 786 char *argv[]) 787 { 788 return wpa_cli_cmd(ctrl, "WPS_NFC_CONFIG_TOKEN", 1, argc, argv); 789 } 790 791 792 static int wpa_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl, int argc, 793 char *argv[]) 794 { 795 return wpa_cli_cmd(ctrl, "WPS_NFC_TOKEN", 1, argc, argv); 796 } 797 798 799 static int wpa_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc, 800 char *argv[]) 801 { 802 int ret; 803 char *buf; 804 size_t buflen; 805 806 if (argc != 1) { 807 printf("Invalid 'wps_nfc_tag_read' command - one argument " 808 "is required.\n"); 809 return -1; 810 } 811 812 buflen = 18 + os_strlen(argv[0]); 813 buf = os_malloc(buflen); 814 if (buf == NULL) 815 return -1; 816 os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]); 817 818 ret = wpa_ctrl_command(ctrl, buf); 819 os_free(buf); 820 821 return ret; 822 } 823 824 825 static int wpa_cli_cmd_nfc_get_handover_req(struct wpa_ctrl *ctrl, int argc, 826 char *argv[]) 827 { 828 return wpa_cli_cmd(ctrl, "NFC_GET_HANDOVER_REQ", 2, argc, argv); 829 } 830 831 832 static int wpa_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl, int argc, 833 char *argv[]) 834 { 835 return wpa_cli_cmd(ctrl, "NFC_GET_HANDOVER_SEL", 2, argc, argv); 836 } 837 838 839 static int wpa_cli_cmd_nfc_rx_handover_req(struct wpa_ctrl *ctrl, int argc, 840 char *argv[]) 841 { 842 int ret; 843 char *buf; 844 size_t buflen; 845 846 if (argc != 1) { 847 printf("Invalid 'nfc_rx_handover_req' command - one argument " 848 "is required.\n"); 849 return -1; 850 } 851 852 buflen = 21 + os_strlen(argv[0]); 853 buf = os_malloc(buflen); 854 if (buf == NULL) 855 return -1; 856 os_snprintf(buf, buflen, "NFC_RX_HANDOVER_REQ %s", argv[0]); 857 858 ret = wpa_ctrl_command(ctrl, buf); 859 os_free(buf); 860 861 return ret; 862 } 863 864 865 static int wpa_cli_cmd_nfc_rx_handover_sel(struct wpa_ctrl *ctrl, int argc, 866 char *argv[]) 867 { 868 int ret; 869 char *buf; 870 size_t buflen; 871 872 if (argc != 1) { 873 printf("Invalid 'nfc_rx_handover_sel' command - one argument " 874 "is required.\n"); 875 return -1; 876 } 877 878 buflen = 21 + os_strlen(argv[0]); 879 buf = os_malloc(buflen); 880 if (buf == NULL) 881 return -1; 882 os_snprintf(buf, buflen, "NFC_RX_HANDOVER_SEL %s", argv[0]); 883 884 ret = wpa_ctrl_command(ctrl, buf); 885 os_free(buf); 886 887 return ret; 888 } 889 890 891 static int wpa_cli_cmd_nfc_report_handover(struct wpa_ctrl *ctrl, int argc, 892 char *argv[]) 893 { 894 return wpa_cli_cmd(ctrl, "NFC_REPORT_HANDOVER", 4, argc, argv); 895 } 896 897 #endif /* CONFIG_WPS_NFC */ 898 899 900 static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[]) 901 { 902 char cmd[256]; 903 int res; 904 905 if (argc == 2) 906 res = os_snprintf(cmd, sizeof(cmd), "WPS_REG %s %s", 907 argv[0], argv[1]); 908 else if (argc == 5 || argc == 6) { 909 char ssid_hex[2 * 32 + 1]; 910 char key_hex[2 * 64 + 1]; 911 int i; 912 913 ssid_hex[0] = '\0'; 914 for (i = 0; i < 32; i++) { 915 if (argv[2][i] == '\0') 916 break; 917 os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[2][i]); 918 } 919 920 key_hex[0] = '\0'; 921 if (argc == 6) { 922 for (i = 0; i < 64; i++) { 923 if (argv[5][i] == '\0') 924 break; 925 os_snprintf(&key_hex[i * 2], 3, "%02x", 926 argv[5][i]); 927 } 928 } 929 930 res = os_snprintf(cmd, sizeof(cmd), 931 "WPS_REG %s %s %s %s %s %s", 932 argv[0], argv[1], ssid_hex, argv[3], argv[4], 933 key_hex); 934 } else { 935 printf("Invalid WPS_REG command: need two arguments:\n" 936 "- BSSID of the target AP\n" 937 "- AP PIN\n"); 938 printf("Alternatively, six arguments can be used to " 939 "reconfigure the AP:\n" 940 "- BSSID of the target AP\n" 941 "- AP PIN\n" 942 "- new SSID\n" 943 "- new auth (OPEN, WPAPSK, WPA2PSK)\n" 944 "- new encr (NONE, WEP, TKIP, CCMP)\n" 945 "- new key\n"); 946 return -1; 947 } 948 949 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { 950 printf("Too long WPS_REG command.\n"); 951 return -1; 952 } 953 return wpa_ctrl_command(ctrl, cmd); 954 } 955 956 957 static int wpa_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc, 958 char *argv[]) 959 { 960 return wpa_cli_cmd(ctrl, "WPS_AP_PIN", 1, argc, argv); 961 } 962 963 964 static int wpa_cli_cmd_wps_er_start(struct wpa_ctrl *ctrl, int argc, 965 char *argv[]) 966 { 967 return wpa_cli_cmd(ctrl, "WPS_ER_START", 0, argc, argv); 968 } 969 970 971 static int wpa_cli_cmd_wps_er_stop(struct wpa_ctrl *ctrl, int argc, 972 char *argv[]) 973 { 974 return wpa_ctrl_command(ctrl, "WPS_ER_STOP"); 975 976 } 977 978 979 static int wpa_cli_cmd_wps_er_pin(struct wpa_ctrl *ctrl, int argc, 980 char *argv[]) 981 { 982 if (argc < 2) { 983 printf("Invalid WPS_ER_PIN command: need at least two " 984 "arguments:\n" 985 "- UUID: use 'any' to select any\n" 986 "- PIN: Enrollee PIN\n" 987 "optional: - Enrollee MAC address\n"); 988 return -1; 989 } 990 991 return wpa_cli_cmd(ctrl, "WPS_ER_PIN", 2, argc, argv); 992 } 993 994 995 static int wpa_cli_cmd_wps_er_pbc(struct wpa_ctrl *ctrl, int argc, 996 char *argv[]) 997 { 998 return wpa_cli_cmd(ctrl, "WPS_ER_PBC", 1, argc, argv); 999 } 1000 1001 1002 static int wpa_cli_cmd_wps_er_learn(struct wpa_ctrl *ctrl, int argc, 1003 char *argv[]) 1004 { 1005 if (argc != 2) { 1006 printf("Invalid WPS_ER_LEARN command: need two arguments:\n" 1007 "- UUID: specify which AP to use\n" 1008 "- PIN: AP PIN\n"); 1009 return -1; 1010 } 1011 1012 return wpa_cli_cmd(ctrl, "WPS_ER_LEARN", 2, argc, argv); 1013 } 1014 1015 1016 static int wpa_cli_cmd_wps_er_set_config(struct wpa_ctrl *ctrl, int argc, 1017 char *argv[]) 1018 { 1019 if (argc != 2) { 1020 printf("Invalid WPS_ER_SET_CONFIG command: need two " 1021 "arguments:\n" 1022 "- UUID: specify which AP to use\n" 1023 "- Network configuration id\n"); 1024 return -1; 1025 } 1026 1027 return wpa_cli_cmd(ctrl, "WPS_ER_SET_CONFIG", 2, argc, argv); 1028 } 1029 1030 1031 static int wpa_cli_cmd_wps_er_config(struct wpa_ctrl *ctrl, int argc, 1032 char *argv[]) 1033 { 1034 char cmd[256]; 1035 int res; 1036 1037 if (argc == 5 || argc == 6) { 1038 char ssid_hex[2 * 32 + 1]; 1039 char key_hex[2 * 64 + 1]; 1040 int i; 1041 1042 ssid_hex[0] = '\0'; 1043 for (i = 0; i < 32; i++) { 1044 if (argv[2][i] == '\0') 1045 break; 1046 os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[2][i]); 1047 } 1048 1049 key_hex[0] = '\0'; 1050 if (argc == 6) { 1051 for (i = 0; i < 64; i++) { 1052 if (argv[5][i] == '\0') 1053 break; 1054 os_snprintf(&key_hex[i * 2], 3, "%02x", 1055 argv[5][i]); 1056 } 1057 } 1058 1059 res = os_snprintf(cmd, sizeof(cmd), 1060 "WPS_ER_CONFIG %s %s %s %s %s %s", 1061 argv[0], argv[1], ssid_hex, argv[3], argv[4], 1062 key_hex); 1063 } else { 1064 printf("Invalid WPS_ER_CONFIG command: need six arguments:\n" 1065 "- AP UUID\n" 1066 "- AP PIN\n" 1067 "- new SSID\n" 1068 "- new auth (OPEN, WPAPSK, WPA2PSK)\n" 1069 "- new encr (NONE, WEP, TKIP, CCMP)\n" 1070 "- new key\n"); 1071 return -1; 1072 } 1073 1074 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { 1075 printf("Too long WPS_ER_CONFIG command.\n"); 1076 return -1; 1077 } 1078 return wpa_ctrl_command(ctrl, cmd); 1079 } 1080 1081 1082 #ifdef CONFIG_WPS_NFC 1083 static int wpa_cli_cmd_wps_er_nfc_config_token(struct wpa_ctrl *ctrl, int argc, 1084 char *argv[]) 1085 { 1086 if (argc != 2) { 1087 printf("Invalid WPS_ER_NFC_CONFIG_TOKEN command: need two " 1088 "arguments:\n" 1089 "- WPS/NDEF: token format\n" 1090 "- UUID: specify which AP to use\n"); 1091 return -1; 1092 } 1093 1094 return wpa_cli_cmd(ctrl, "WPS_ER_NFC_CONFIG_TOKEN", 2, argc, argv); 1095 } 1096 #endif /* CONFIG_WPS_NFC */ 1097 1098 1099 static int wpa_cli_cmd_ibss_rsn(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1100 { 1101 return wpa_cli_cmd(ctrl, "IBSS_RSN", 1, argc, argv); 1102 } 1103 1104 1105 static int wpa_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1106 { 1107 return wpa_cli_cmd(ctrl, "LEVEL", 1, argc, argv); 1108 } 1109 1110 1111 static int wpa_cli_cmd_identity(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1112 { 1113 char cmd[256], *pos, *end; 1114 int i, ret; 1115 1116 if (argc < 2) { 1117 printf("Invalid IDENTITY command: needs two arguments " 1118 "(network id and identity)\n"); 1119 return -1; 1120 } 1121 1122 end = cmd + sizeof(cmd); 1123 pos = cmd; 1124 ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "IDENTITY-%s:%s", 1125 argv[0], argv[1]); 1126 if (ret < 0 || ret >= end - pos) { 1127 printf("Too long IDENTITY command.\n"); 1128 return -1; 1129 } 1130 pos += ret; 1131 for (i = 2; i < argc; i++) { 1132 ret = os_snprintf(pos, end - pos, " %s", argv[i]); 1133 if (ret < 0 || ret >= end - pos) { 1134 printf("Too long IDENTITY command.\n"); 1135 return -1; 1136 } 1137 pos += ret; 1138 } 1139 1140 return wpa_ctrl_command(ctrl, cmd); 1141 } 1142 1143 1144 static int wpa_cli_cmd_password(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1145 { 1146 char cmd[256], *pos, *end; 1147 int i, ret; 1148 1149 if (argc < 2) { 1150 printf("Invalid PASSWORD command: needs two arguments " 1151 "(network id and password)\n"); 1152 return -1; 1153 } 1154 1155 end = cmd + sizeof(cmd); 1156 pos = cmd; 1157 ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSWORD-%s:%s", 1158 argv[0], argv[1]); 1159 if (ret < 0 || ret >= end - pos) { 1160 printf("Too long PASSWORD command.\n"); 1161 return -1; 1162 } 1163 pos += ret; 1164 for (i = 2; i < argc; i++) { 1165 ret = os_snprintf(pos, end - pos, " %s", argv[i]); 1166 if (ret < 0 || ret >= end - pos) { 1167 printf("Too long PASSWORD command.\n"); 1168 return -1; 1169 } 1170 pos += ret; 1171 } 1172 1173 return wpa_ctrl_command(ctrl, cmd); 1174 } 1175 1176 1177 static int wpa_cli_cmd_new_password(struct wpa_ctrl *ctrl, int argc, 1178 char *argv[]) 1179 { 1180 char cmd[256], *pos, *end; 1181 int i, ret; 1182 1183 if (argc < 2) { 1184 printf("Invalid NEW_PASSWORD command: needs two arguments " 1185 "(network id and password)\n"); 1186 return -1; 1187 } 1188 1189 end = cmd + sizeof(cmd); 1190 pos = cmd; 1191 ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "NEW_PASSWORD-%s:%s", 1192 argv[0], argv[1]); 1193 if (ret < 0 || ret >= end - pos) { 1194 printf("Too long NEW_PASSWORD command.\n"); 1195 return -1; 1196 } 1197 pos += ret; 1198 for (i = 2; i < argc; i++) { 1199 ret = os_snprintf(pos, end - pos, " %s", argv[i]); 1200 if (ret < 0 || ret >= end - pos) { 1201 printf("Too long NEW_PASSWORD command.\n"); 1202 return -1; 1203 } 1204 pos += ret; 1205 } 1206 1207 return wpa_ctrl_command(ctrl, cmd); 1208 } 1209 1210 1211 static int wpa_cli_cmd_pin(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1212 { 1213 char cmd[256], *pos, *end; 1214 int i, ret; 1215 1216 if (argc < 2) { 1217 printf("Invalid PIN command: needs two arguments " 1218 "(network id and pin)\n"); 1219 return -1; 1220 } 1221 1222 end = cmd + sizeof(cmd); 1223 pos = cmd; 1224 ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PIN-%s:%s", 1225 argv[0], argv[1]); 1226 if (ret < 0 || ret >= end - pos) { 1227 printf("Too long PIN command.\n"); 1228 return -1; 1229 } 1230 pos += ret; 1231 for (i = 2; i < argc; i++) { 1232 ret = os_snprintf(pos, end - pos, " %s", argv[i]); 1233 if (ret < 0 || ret >= end - pos) { 1234 printf("Too long PIN command.\n"); 1235 return -1; 1236 } 1237 pos += ret; 1238 } 1239 return wpa_ctrl_command(ctrl, cmd); 1240 } 1241 1242 1243 static int wpa_cli_cmd_otp(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1244 { 1245 char cmd[256], *pos, *end; 1246 int i, ret; 1247 1248 if (argc < 2) { 1249 printf("Invalid OTP command: needs two arguments (network " 1250 "id and password)\n"); 1251 return -1; 1252 } 1253 1254 end = cmd + sizeof(cmd); 1255 pos = cmd; 1256 ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "OTP-%s:%s", 1257 argv[0], argv[1]); 1258 if (ret < 0 || ret >= end - pos) { 1259 printf("Too long OTP command.\n"); 1260 return -1; 1261 } 1262 pos += ret; 1263 for (i = 2; i < argc; i++) { 1264 ret = os_snprintf(pos, end - pos, " %s", argv[i]); 1265 if (ret < 0 || ret >= end - pos) { 1266 printf("Too long OTP command.\n"); 1267 return -1; 1268 } 1269 pos += ret; 1270 } 1271 1272 return wpa_ctrl_command(ctrl, cmd); 1273 } 1274 1275 1276 static int wpa_cli_cmd_sim(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1277 { 1278 char cmd[256], *pos, *end; 1279 int i, ret; 1280 1281 if (argc < 2) { 1282 printf("Invalid SIM command: needs two arguments " 1283 "(network id and SIM operation response)\n"); 1284 return -1; 1285 } 1286 1287 end = cmd + sizeof(cmd); 1288 pos = cmd; 1289 ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "SIM-%s:%s", 1290 argv[0], argv[1]); 1291 if (ret < 0 || ret >= end - pos) { 1292 printf("Too long SIM command.\n"); 1293 return -1; 1294 } 1295 pos += ret; 1296 for (i = 2; i < argc; i++) { 1297 ret = os_snprintf(pos, end - pos, " %s", argv[i]); 1298 if (ret < 0 || ret >= end - pos) { 1299 printf("Too long SIM command.\n"); 1300 return -1; 1301 } 1302 pos += ret; 1303 } 1304 return wpa_ctrl_command(ctrl, cmd); 1305 } 1306 1307 1308 static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc, 1309 char *argv[]) 1310 { 1311 char cmd[256], *pos, *end; 1312 int i, ret; 1313 1314 if (argc < 2) { 1315 printf("Invalid PASSPHRASE command: needs two arguments " 1316 "(network id and passphrase)\n"); 1317 return -1; 1318 } 1319 1320 end = cmd + sizeof(cmd); 1321 pos = cmd; 1322 ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSPHRASE-%s:%s", 1323 argv[0], argv[1]); 1324 if (ret < 0 || ret >= end - pos) { 1325 printf("Too long PASSPHRASE command.\n"); 1326 return -1; 1327 } 1328 pos += ret; 1329 for (i = 2; i < argc; i++) { 1330 ret = os_snprintf(pos, end - pos, " %s", argv[i]); 1331 if (ret < 0 || ret >= end - pos) { 1332 printf("Too long PASSPHRASE command.\n"); 1333 return -1; 1334 } 1335 pos += ret; 1336 } 1337 1338 return wpa_ctrl_command(ctrl, cmd); 1339 } 1340 1341 1342 static int wpa_cli_cmd_bssid(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1343 { 1344 if (argc < 2) { 1345 printf("Invalid BSSID command: needs two arguments (network " 1346 "id and BSSID)\n"); 1347 return -1; 1348 } 1349 1350 return wpa_cli_cmd(ctrl, "BSSID", 2, argc, argv); 1351 } 1352 1353 1354 static int wpa_cli_cmd_blacklist(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1355 { 1356 return wpa_cli_cmd(ctrl, "BLACKLIST", 0, argc, argv); 1357 } 1358 1359 1360 static int wpa_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1361 { 1362 return wpa_cli_cmd(ctrl, "LOG_LEVEL", 0, argc, argv); 1363 } 1364 1365 1366 static int wpa_cli_cmd_list_networks(struct wpa_ctrl *ctrl, int argc, 1367 char *argv[]) 1368 { 1369 return wpa_ctrl_command(ctrl, "LIST_NETWORKS"); 1370 } 1371 1372 1373 static int wpa_cli_cmd_select_network(struct wpa_ctrl *ctrl, int argc, 1374 char *argv[]) 1375 { 1376 return wpa_cli_cmd(ctrl, "SELECT_NETWORK", 1, argc, argv); 1377 } 1378 1379 1380 static int wpa_cli_cmd_enable_network(struct wpa_ctrl *ctrl, int argc, 1381 char *argv[]) 1382 { 1383 return wpa_cli_cmd(ctrl, "ENABLE_NETWORK", 1, argc, argv); 1384 } 1385 1386 1387 static int wpa_cli_cmd_disable_network(struct wpa_ctrl *ctrl, int argc, 1388 char *argv[]) 1389 { 1390 return wpa_cli_cmd(ctrl, "DISABLE_NETWORK", 1, argc, argv); 1391 } 1392 1393 1394 static int wpa_cli_cmd_add_network(struct wpa_ctrl *ctrl, int argc, 1395 char *argv[]) 1396 { 1397 return wpa_ctrl_command(ctrl, "ADD_NETWORK"); 1398 } 1399 1400 1401 static int wpa_cli_cmd_remove_network(struct wpa_ctrl *ctrl, int argc, 1402 char *argv[]) 1403 { 1404 return wpa_cli_cmd(ctrl, "REMOVE_NETWORK", 1, argc, argv); 1405 } 1406 1407 1408 static void wpa_cli_show_network_variables(void) 1409 { 1410 printf("set_network variables:\n" 1411 " ssid (network name, SSID)\n" 1412 " psk (WPA passphrase or pre-shared key)\n" 1413 " key_mgmt (key management protocol)\n" 1414 " identity (EAP identity)\n" 1415 " password (EAP password)\n" 1416 " ...\n" 1417 "\n" 1418 "Note: Values are entered in the same format as the " 1419 "configuration file is using,\n" 1420 "i.e., strings values need to be inside double quotation " 1421 "marks.\n" 1422 "For example: set_network 1 ssid \"network name\"\n" 1423 "\n" 1424 "Please see wpa_supplicant.conf documentation for full list " 1425 "of\navailable variables.\n"); 1426 } 1427 1428 1429 static int wpa_cli_cmd_set_network(struct wpa_ctrl *ctrl, int argc, 1430 char *argv[]) 1431 { 1432 if (argc == 0) { 1433 wpa_cli_show_network_variables(); 1434 return 0; 1435 } 1436 1437 if (argc < 3) { 1438 printf("Invalid SET_NETWORK command: needs three arguments\n" 1439 "(network id, variable name, and value)\n"); 1440 return -1; 1441 } 1442 1443 return wpa_cli_cmd(ctrl, "SET_NETWORK", 3, argc, argv); 1444 } 1445 1446 1447 static int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc, 1448 char *argv[]) 1449 { 1450 if (argc == 0) { 1451 wpa_cli_show_network_variables(); 1452 return 0; 1453 } 1454 1455 if (argc != 2) { 1456 printf("Invalid GET_NETWORK command: needs two arguments\n" 1457 "(network id and variable name)\n"); 1458 return -1; 1459 } 1460 1461 return wpa_cli_cmd(ctrl, "GET_NETWORK", 2, argc, argv); 1462 } 1463 1464 1465 static int wpa_cli_cmd_list_creds(struct wpa_ctrl *ctrl, int argc, 1466 char *argv[]) 1467 { 1468 return wpa_ctrl_command(ctrl, "LIST_CREDS"); 1469 } 1470 1471 1472 static int wpa_cli_cmd_add_cred(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1473 { 1474 return wpa_ctrl_command(ctrl, "ADD_CRED"); 1475 } 1476 1477 1478 static int wpa_cli_cmd_remove_cred(struct wpa_ctrl *ctrl, int argc, 1479 char *argv[]) 1480 { 1481 return wpa_cli_cmd(ctrl, "REMOVE_CRED", 1, argc, argv); 1482 } 1483 1484 1485 static int wpa_cli_cmd_set_cred(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1486 { 1487 if (argc != 3) { 1488 printf("Invalid SET_CRED command: needs three arguments\n" 1489 "(cred id, variable name, and value)\n"); 1490 return -1; 1491 } 1492 1493 return wpa_cli_cmd(ctrl, "SET_CRED", 3, argc, argv); 1494 } 1495 1496 1497 static int wpa_cli_cmd_disconnect(struct wpa_ctrl *ctrl, int argc, 1498 char *argv[]) 1499 { 1500 return wpa_ctrl_command(ctrl, "DISCONNECT"); 1501 } 1502 1503 1504 static int wpa_cli_cmd_reconnect(struct wpa_ctrl *ctrl, int argc, 1505 char *argv[]) 1506 { 1507 return wpa_ctrl_command(ctrl, "RECONNECT"); 1508 } 1509 1510 1511 static int wpa_cli_cmd_save_config(struct wpa_ctrl *ctrl, int argc, 1512 char *argv[]) 1513 { 1514 return wpa_ctrl_command(ctrl, "SAVE_CONFIG"); 1515 } 1516 1517 1518 static int wpa_cli_cmd_scan(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1519 { 1520 return wpa_cli_cmd(ctrl, "SCAN", 0, argc, argv); 1521 } 1522 1523 1524 static int wpa_cli_cmd_scan_results(struct wpa_ctrl *ctrl, int argc, 1525 char *argv[]) 1526 { 1527 return wpa_ctrl_command(ctrl, "SCAN_RESULTS"); 1528 } 1529 1530 1531 static int wpa_cli_cmd_bss(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1532 { 1533 return wpa_cli_cmd(ctrl, "BSS", 1, argc, argv); 1534 } 1535 1536 1537 static char ** wpa_cli_complete_bss(const char *str, int pos) 1538 { 1539 int arg = get_cmd_arg_num(str, pos); 1540 char **res = NULL; 1541 1542 switch (arg) { 1543 case 1: 1544 res = cli_txt_list_array(&bsses); 1545 break; 1546 } 1547 1548 return res; 1549 } 1550 1551 1552 static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc, 1553 char *argv[]) 1554 { 1555 if (argc < 1 || argc > 2) { 1556 printf("Invalid GET_CAPABILITY command: need either one or " 1557 "two arguments\n"); 1558 return -1; 1559 } 1560 1561 if ((argc == 2) && os_strcmp(argv[1], "strict") != 0) { 1562 printf("Invalid GET_CAPABILITY command: second argument, " 1563 "if any, must be 'strict'\n"); 1564 return -1; 1565 } 1566 1567 return wpa_cli_cmd(ctrl, "GET_CAPABILITY", 1, argc, argv); 1568 } 1569 1570 1571 static int wpa_cli_list_interfaces(struct wpa_ctrl *ctrl) 1572 { 1573 printf("Available interfaces:\n"); 1574 return wpa_ctrl_command(ctrl, "INTERFACES"); 1575 } 1576 1577 1578 static int wpa_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1579 { 1580 if (argc < 1) { 1581 wpa_cli_list_interfaces(ctrl); 1582 return 0; 1583 } 1584 1585 wpa_cli_close_connection(); 1586 os_free(ctrl_ifname); 1587 ctrl_ifname = os_strdup(argv[0]); 1588 1589 if (wpa_cli_open_connection(ctrl_ifname, 1)) { 1590 printf("Connected to interface '%s.\n", ctrl_ifname); 1591 } else { 1592 printf("Could not connect to interface '%s' - re-trying\n", 1593 ctrl_ifname); 1594 } 1595 return 0; 1596 } 1597 1598 1599 static int wpa_cli_cmd_reconfigure(struct wpa_ctrl *ctrl, int argc, 1600 char *argv[]) 1601 { 1602 return wpa_ctrl_command(ctrl, "RECONFIGURE"); 1603 } 1604 1605 1606 static int wpa_cli_cmd_terminate(struct wpa_ctrl *ctrl, int argc, 1607 char *argv[]) 1608 { 1609 return wpa_ctrl_command(ctrl, "TERMINATE"); 1610 } 1611 1612 1613 static int wpa_cli_cmd_interface_add(struct wpa_ctrl *ctrl, int argc, 1614 char *argv[]) 1615 { 1616 char cmd[256]; 1617 int res; 1618 1619 if (argc < 1) { 1620 printf("Invalid INTERFACE_ADD command: needs at least one " 1621 "argument (interface name)\n" 1622 "All arguments: ifname confname driver ctrl_interface " 1623 "driver_param bridge_name\n"); 1624 return -1; 1625 } 1626 1627 /* 1628 * INTERFACE_ADD <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB 1629 * <driver_param>TAB<bridge_name> 1630 */ 1631 res = os_snprintf(cmd, sizeof(cmd), 1632 "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s", 1633 argv[0], 1634 argc > 1 ? argv[1] : "", argc > 2 ? argv[2] : "", 1635 argc > 3 ? argv[3] : "", argc > 4 ? argv[4] : "", 1636 argc > 5 ? argv[5] : ""); 1637 if (res < 0 || (size_t) res >= sizeof(cmd)) 1638 return -1; 1639 cmd[sizeof(cmd) - 1] = '\0'; 1640 return wpa_ctrl_command(ctrl, cmd); 1641 } 1642 1643 1644 static int wpa_cli_cmd_interface_remove(struct wpa_ctrl *ctrl, int argc, 1645 char *argv[]) 1646 { 1647 return wpa_cli_cmd(ctrl, "INTERFACE_REMOVE", 1, argc, argv); 1648 } 1649 1650 1651 static int wpa_cli_cmd_interface_list(struct wpa_ctrl *ctrl, int argc, 1652 char *argv[]) 1653 { 1654 return wpa_ctrl_command(ctrl, "INTERFACE_LIST"); 1655 } 1656 1657 1658 #ifdef CONFIG_AP 1659 static int wpa_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1660 { 1661 return wpa_cli_cmd(ctrl, "STA", 1, argc, argv); 1662 } 1663 1664 1665 static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd, 1666 char *addr, size_t addr_len) 1667 { 1668 char buf[4096], *pos; 1669 size_t len; 1670 int ret; 1671 1672 if (ctrl_conn == NULL) { 1673 printf("Not connected to hostapd - command dropped.\n"); 1674 return -1; 1675 } 1676 len = sizeof(buf) - 1; 1677 ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, 1678 wpa_cli_msg_cb); 1679 if (ret == -2) { 1680 printf("'%s' command timed out.\n", cmd); 1681 return -2; 1682 } else if (ret < 0) { 1683 printf("'%s' command failed.\n", cmd); 1684 return -1; 1685 } 1686 1687 buf[len] = '\0'; 1688 if (os_memcmp(buf, "FAIL", 4) == 0) 1689 return -1; 1690 printf("%s", buf); 1691 1692 pos = buf; 1693 while (*pos != '\0' && *pos != '\n') 1694 pos++; 1695 *pos = '\0'; 1696 os_strlcpy(addr, buf, addr_len); 1697 return 0; 1698 } 1699 1700 1701 static int wpa_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1702 { 1703 char addr[32], cmd[64]; 1704 1705 if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr))) 1706 return 0; 1707 do { 1708 os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr); 1709 } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0); 1710 1711 return -1; 1712 } 1713 1714 1715 static int wpa_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc, 1716 char *argv[]) 1717 { 1718 return wpa_cli_cmd(ctrl, "DEAUTHENTICATE", 1, argc, argv); 1719 } 1720 1721 1722 static int wpa_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc, 1723 char *argv[]) 1724 { 1725 return wpa_cli_cmd(ctrl, "DISASSOCIATE", 1, argc, argv); 1726 } 1727 1728 static int wpa_cli_cmd_chanswitch(struct wpa_ctrl *ctrl, int argc, 1729 char *argv[]) 1730 { 1731 return wpa_cli_cmd(ctrl, "CHAN_SWITCH", 2, argc, argv); 1732 } 1733 1734 #endif /* CONFIG_AP */ 1735 1736 1737 static int wpa_cli_cmd_suspend(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1738 { 1739 return wpa_ctrl_command(ctrl, "SUSPEND"); 1740 } 1741 1742 1743 static int wpa_cli_cmd_resume(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1744 { 1745 return wpa_ctrl_command(ctrl, "RESUME"); 1746 } 1747 1748 1749 static int wpa_cli_cmd_drop_sa(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1750 { 1751 return wpa_ctrl_command(ctrl, "DROP_SA"); 1752 } 1753 1754 1755 static int wpa_cli_cmd_roam(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1756 { 1757 return wpa_cli_cmd(ctrl, "ROAM", 1, argc, argv); 1758 } 1759 1760 1761 #ifdef CONFIG_P2P 1762 1763 static int wpa_cli_cmd_p2p_find(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1764 { 1765 return wpa_cli_cmd(ctrl, "P2P_FIND", 0, argc, argv); 1766 } 1767 1768 1769 static char ** wpa_cli_complete_p2p_find(const char *str, int pos) 1770 { 1771 char **res = NULL; 1772 int arg = get_cmd_arg_num(str, pos); 1773 1774 res = os_calloc(6, sizeof(char *)); 1775 if (res == NULL) 1776 return NULL; 1777 res[0] = os_strdup("type=social"); 1778 if (res[0] == NULL) { 1779 os_free(res); 1780 return NULL; 1781 } 1782 res[1] = os_strdup("type=progressive"); 1783 if (res[1] == NULL) 1784 return res; 1785 res[2] = os_strdup("delay="); 1786 if (res[2] == NULL) 1787 return res; 1788 res[3] = os_strdup("dev_id="); 1789 if (res[3] == NULL) 1790 return res; 1791 if (arg == 1) 1792 res[4] = os_strdup("[timeout]"); 1793 1794 return res; 1795 } 1796 1797 1798 static int wpa_cli_cmd_p2p_stop_find(struct wpa_ctrl *ctrl, int argc, 1799 char *argv[]) 1800 { 1801 return wpa_ctrl_command(ctrl, "P2P_STOP_FIND"); 1802 } 1803 1804 1805 static int wpa_cli_cmd_p2p_connect(struct wpa_ctrl *ctrl, int argc, 1806 char *argv[]) 1807 { 1808 return wpa_cli_cmd(ctrl, "P2P_CONNECT", 2, argc, argv); 1809 } 1810 1811 1812 static char ** wpa_cli_complete_p2p_connect(const char *str, int pos) 1813 { 1814 int arg = get_cmd_arg_num(str, pos); 1815 char **res = NULL; 1816 1817 switch (arg) { 1818 case 1: 1819 res = cli_txt_list_array(&p2p_peers); 1820 break; 1821 } 1822 1823 return res; 1824 } 1825 1826 1827 static int wpa_cli_cmd_p2p_listen(struct wpa_ctrl *ctrl, int argc, 1828 char *argv[]) 1829 { 1830 return wpa_cli_cmd(ctrl, "P2P_LISTEN", 0, argc, argv); 1831 } 1832 1833 1834 static int wpa_cli_cmd_p2p_group_remove(struct wpa_ctrl *ctrl, int argc, 1835 char *argv[]) 1836 { 1837 return wpa_cli_cmd(ctrl, "P2P_GROUP_REMOVE", 1, argc, argv); 1838 } 1839 1840 1841 static char ** wpa_cli_complete_p2p_group_remove(const char *str, int pos) 1842 { 1843 int arg = get_cmd_arg_num(str, pos); 1844 char **res = NULL; 1845 1846 switch (arg) { 1847 case 1: 1848 res = cli_txt_list_array(&p2p_groups); 1849 break; 1850 } 1851 1852 return res; 1853 } 1854 1855 1856 static int wpa_cli_cmd_p2p_group_add(struct wpa_ctrl *ctrl, int argc, 1857 char *argv[]) 1858 { 1859 return wpa_cli_cmd(ctrl, "P2P_GROUP_ADD", 0, argc, argv); 1860 } 1861 1862 1863 static int wpa_cli_cmd_p2p_prov_disc(struct wpa_ctrl *ctrl, int argc, 1864 char *argv[]) 1865 { 1866 if (argc != 2 && argc != 3) { 1867 printf("Invalid P2P_PROV_DISC command: needs at least " 1868 "two arguments, address and config method\n" 1869 "(display, keypad, or pbc) and an optional join\n"); 1870 return -1; 1871 } 1872 1873 return wpa_cli_cmd(ctrl, "P2P_PROV_DISC", 2, argc, argv); 1874 } 1875 1876 1877 static int wpa_cli_cmd_p2p_get_passphrase(struct wpa_ctrl *ctrl, int argc, 1878 char *argv[]) 1879 { 1880 return wpa_ctrl_command(ctrl, "P2P_GET_PASSPHRASE"); 1881 } 1882 1883 1884 static int wpa_cli_cmd_p2p_serv_disc_req(struct wpa_ctrl *ctrl, int argc, 1885 char *argv[]) 1886 { 1887 char cmd[4096]; 1888 1889 if (argc != 2 && argc != 4) { 1890 printf("Invalid P2P_SERV_DISC_REQ command: needs two " 1891 "arguments (address and TLVs) or four arguments " 1892 "(address, \"upnp\", version, search target " 1893 "(SSDP ST:)\n"); 1894 return -1; 1895 } 1896 1897 if (write_cmd(cmd, sizeof(cmd), "P2P_SERV_DISC_REQ", argc, argv) < 0) 1898 return -1; 1899 return wpa_ctrl_command(ctrl, cmd); 1900 } 1901 1902 1903 static int wpa_cli_cmd_p2p_serv_disc_cancel_req(struct wpa_ctrl *ctrl, 1904 int argc, char *argv[]) 1905 { 1906 return wpa_cli_cmd(ctrl, "P2P_SERV_DISC_CANCEL_REQ", 1, argc, argv); 1907 } 1908 1909 1910 static int wpa_cli_cmd_p2p_serv_disc_resp(struct wpa_ctrl *ctrl, int argc, 1911 char *argv[]) 1912 { 1913 char cmd[4096]; 1914 int res; 1915 1916 if (argc != 4) { 1917 printf("Invalid P2P_SERV_DISC_RESP command: needs four " 1918 "arguments (freq, address, dialog token, and TLVs)\n"); 1919 return -1; 1920 } 1921 1922 res = os_snprintf(cmd, sizeof(cmd), "P2P_SERV_DISC_RESP %s %s %s %s", 1923 argv[0], argv[1], argv[2], argv[3]); 1924 if (res < 0 || (size_t) res >= sizeof(cmd)) 1925 return -1; 1926 cmd[sizeof(cmd) - 1] = '\0'; 1927 return wpa_ctrl_command(ctrl, cmd); 1928 } 1929 1930 1931 static int wpa_cli_cmd_p2p_service_update(struct wpa_ctrl *ctrl, int argc, 1932 char *argv[]) 1933 { 1934 return wpa_ctrl_command(ctrl, "P2P_SERVICE_UPDATE"); 1935 } 1936 1937 1938 static int wpa_cli_cmd_p2p_serv_disc_external(struct wpa_ctrl *ctrl, 1939 int argc, char *argv[]) 1940 { 1941 return wpa_cli_cmd(ctrl, "P2P_SERV_DISC_EXTERNAL", 1, argc, argv); 1942 } 1943 1944 1945 static int wpa_cli_cmd_p2p_service_flush(struct wpa_ctrl *ctrl, int argc, 1946 char *argv[]) 1947 { 1948 return wpa_ctrl_command(ctrl, "P2P_SERVICE_FLUSH"); 1949 } 1950 1951 1952 static int wpa_cli_cmd_p2p_service_add(struct wpa_ctrl *ctrl, int argc, 1953 char *argv[]) 1954 { 1955 char cmd[4096]; 1956 int res; 1957 1958 if (argc != 3 && argc != 4) { 1959 printf("Invalid P2P_SERVICE_ADD command: needs three or four " 1960 "arguments\n"); 1961 return -1; 1962 } 1963 1964 if (argc == 4) 1965 res = os_snprintf(cmd, sizeof(cmd), 1966 "P2P_SERVICE_ADD %s %s %s %s", 1967 argv[0], argv[1], argv[2], argv[3]); 1968 else 1969 res = os_snprintf(cmd, sizeof(cmd), 1970 "P2P_SERVICE_ADD %s %s %s", 1971 argv[0], argv[1], argv[2]); 1972 if (res < 0 || (size_t) res >= sizeof(cmd)) 1973 return -1; 1974 cmd[sizeof(cmd) - 1] = '\0'; 1975 return wpa_ctrl_command(ctrl, cmd); 1976 } 1977 1978 1979 static int wpa_cli_cmd_p2p_service_del(struct wpa_ctrl *ctrl, int argc, 1980 char *argv[]) 1981 { 1982 char cmd[4096]; 1983 int res; 1984 1985 if (argc != 2 && argc != 3) { 1986 printf("Invalid P2P_SERVICE_DEL command: needs two or three " 1987 "arguments\n"); 1988 return -1; 1989 } 1990 1991 if (argc == 3) 1992 res = os_snprintf(cmd, sizeof(cmd), 1993 "P2P_SERVICE_DEL %s %s %s", 1994 argv[0], argv[1], argv[2]); 1995 else 1996 res = os_snprintf(cmd, sizeof(cmd), 1997 "P2P_SERVICE_DEL %s %s", 1998 argv[0], argv[1]); 1999 if (res < 0 || (size_t) res >= sizeof(cmd)) 2000 return -1; 2001 cmd[sizeof(cmd) - 1] = '\0'; 2002 return wpa_ctrl_command(ctrl, cmd); 2003 } 2004 2005 2006 static int wpa_cli_cmd_p2p_reject(struct wpa_ctrl *ctrl, 2007 int argc, char *argv[]) 2008 { 2009 return wpa_cli_cmd(ctrl, "P2P_REJECT", 1, argc, argv); 2010 } 2011 2012 2013 static int wpa_cli_cmd_p2p_invite(struct wpa_ctrl *ctrl, 2014 int argc, char *argv[]) 2015 { 2016 return wpa_cli_cmd(ctrl, "P2P_INVITE", 1, argc, argv); 2017 } 2018 2019 2020 static int wpa_cli_cmd_p2p_peer(struct wpa_ctrl *ctrl, int argc, char *argv[]) 2021 { 2022 return wpa_cli_cmd(ctrl, "P2P_PEER", 1, argc, argv); 2023 } 2024 2025 2026 static char ** wpa_cli_complete_p2p_peer(const char *str, int pos) 2027 { 2028 int arg = get_cmd_arg_num(str, pos); 2029 char **res = NULL; 2030 2031 switch (arg) { 2032 case 1: 2033 res = cli_txt_list_array(&p2p_peers); 2034 break; 2035 } 2036 2037 return res; 2038 } 2039 2040 2041 static int wpa_ctrl_command_p2p_peer(struct wpa_ctrl *ctrl, char *cmd, 2042 char *addr, size_t addr_len, 2043 int discovered) 2044 { 2045 char buf[4096], *pos; 2046 size_t len; 2047 int ret; 2048 2049 if (ctrl_conn == NULL) 2050 return -1; 2051 len = sizeof(buf) - 1; 2052 ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, 2053 wpa_cli_msg_cb); 2054 if (ret == -2) { 2055 printf("'%s' command timed out.\n", cmd); 2056 return -2; 2057 } else if (ret < 0) { 2058 printf("'%s' command failed.\n", cmd); 2059 return -1; 2060 } 2061 2062 buf[len] = '\0'; 2063 if (os_memcmp(buf, "FAIL", 4) == 0) 2064 return -1; 2065 2066 pos = buf; 2067 while (*pos != '\0' && *pos != '\n') 2068 pos++; 2069 *pos++ = '\0'; 2070 os_strlcpy(addr, buf, addr_len); 2071 if (!discovered || os_strstr(pos, "[PROBE_REQ_ONLY]") == NULL) 2072 printf("%s\n", addr); 2073 return 0; 2074 } 2075 2076 2077 static int wpa_cli_cmd_p2p_peers(struct wpa_ctrl *ctrl, int argc, char *argv[]) 2078 { 2079 char addr[32], cmd[64]; 2080 int discovered; 2081 2082 discovered = argc > 0 && os_strcmp(argv[0], "discovered") == 0; 2083 2084 if (wpa_ctrl_command_p2p_peer(ctrl, "P2P_PEER FIRST", 2085 addr, sizeof(addr), discovered)) 2086 return -1; 2087 do { 2088 os_snprintf(cmd, sizeof(cmd), "P2P_PEER NEXT-%s", addr); 2089 } while (wpa_ctrl_command_p2p_peer(ctrl, cmd, addr, sizeof(addr), 2090 discovered) == 0); 2091 2092 return 0; 2093 } 2094 2095 2096 static int wpa_cli_cmd_p2p_set(struct wpa_ctrl *ctrl, int argc, char *argv[]) 2097 { 2098 return wpa_cli_cmd(ctrl, "P2P_SET", 2, argc, argv); 2099 } 2100 2101 2102 static char ** wpa_cli_complete_p2p_set(const char *str, int pos) 2103 { 2104 int arg = get_cmd_arg_num(str, pos); 2105 const char *fields[] = { 2106 "discoverability", 2107 "managed", 2108 "listen_channel", 2109 "ssid_postfix", 2110 "noa", 2111 "ps", 2112 "oppps", 2113 "ctwindow", 2114 "disabled", 2115 "conc_pref", 2116 "force_long_sd", 2117 "peer_filter", 2118 "cross_connect", 2119 "go_apsd", 2120 "client_apsd", 2121 "disallow_freq", 2122 "disc_int", 2123 "per_sta_psk", 2124 }; 2125 int i, num_fields = ARRAY_SIZE(fields); 2126 2127 if (arg == 1) { 2128 char **res = os_calloc(num_fields + 1, sizeof(char *)); 2129 if (res == NULL) 2130 return NULL; 2131 for (i = 0; i < num_fields; i++) { 2132 res[i] = os_strdup(fields[i]); 2133 if (res[i] == NULL) 2134 return res; 2135 } 2136 return res; 2137 } 2138 2139 if (arg == 2 && os_strncasecmp(str, "p2p_set peer_filter ", 20) == 0) 2140 return cli_txt_list_array(&p2p_peers); 2141 2142 return NULL; 2143 } 2144 2145 2146 static int wpa_cli_cmd_p2p_flush(struct wpa_ctrl *ctrl, int argc, char *argv[]) 2147 { 2148 return wpa_ctrl_command(ctrl, "P2P_FLUSH"); 2149 } 2150 2151 2152 static int wpa_cli_cmd_p2p_cancel(struct wpa_ctrl *ctrl, int argc, 2153 char *argv[]) 2154 { 2155 return wpa_ctrl_command(ctrl, "P2P_CANCEL"); 2156 } 2157 2158 2159 static int wpa_cli_cmd_p2p_unauthorize(struct wpa_ctrl *ctrl, int argc, 2160 char *argv[]) 2161 { 2162 return wpa_cli_cmd(ctrl, "P2P_UNAUTHORIZE", 1, argc, argv); 2163 } 2164 2165 2166 static int wpa_cli_cmd_p2p_presence_req(struct wpa_ctrl *ctrl, int argc, 2167 char *argv[]) 2168 { 2169 if (argc != 0 && argc != 2 && argc != 4) { 2170 printf("Invalid P2P_PRESENCE_REQ command: needs two arguments " 2171 "(preferred duration, interval; in microsecods).\n" 2172 "Optional second pair can be used to provide " 2173 "acceptable values.\n"); 2174 return -1; 2175 } 2176 2177 return wpa_cli_cmd(ctrl, "P2P_PRESENCE_REQ", 0, argc, argv); 2178 } 2179 2180 2181 static int wpa_cli_cmd_p2p_ext_listen(struct wpa_ctrl *ctrl, int argc, 2182 char *argv[]) 2183 { 2184 if (argc != 0 && argc != 2) { 2185 printf("Invalid P2P_EXT_LISTEN command: needs two arguments " 2186 "(availability period, availability interval; in " 2187 "millisecods).\n" 2188 "Extended Listen Timing can be cancelled with this " 2189 "command when used without parameters.\n"); 2190 return -1; 2191 } 2192 2193 return wpa_cli_cmd(ctrl, "P2P_EXT_LISTEN", 0, argc, argv); 2194 } 2195 2196 2197 static int wpa_cli_cmd_p2p_remove_client(struct wpa_ctrl *ctrl, int argc, 2198 char *argv[]) 2199 { 2200 return wpa_cli_cmd(ctrl, "P2P_REMOVE_CLIENT", 1, argc, argv); 2201 } 2202 2203 #endif /* CONFIG_P2P */ 2204 2205 #ifdef CONFIG_WIFI_DISPLAY 2206 2207 static int wpa_cli_cmd_wfd_subelem_set(struct wpa_ctrl *ctrl, int argc, 2208 char *argv[]) 2209 { 2210 char cmd[100]; 2211 int res; 2212 2213 if (argc != 1 && argc != 2) { 2214 printf("Invalid WFD_SUBELEM_SET command: needs one or two " 2215 "arguments (subelem, hexdump)\n"); 2216 return -1; 2217 } 2218 2219 res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_SET %s %s", 2220 argv[0], argc > 1 ? argv[1] : ""); 2221 if (res < 0 || (size_t) res >= sizeof(cmd)) 2222 return -1; 2223 cmd[sizeof(cmd) - 1] = '\0'; 2224 return wpa_ctrl_command(ctrl, cmd); 2225 } 2226 2227 2228 static int wpa_cli_cmd_wfd_subelem_get(struct wpa_ctrl *ctrl, int argc, 2229 char *argv[]) 2230 { 2231 char cmd[100]; 2232 int res; 2233 2234 if (argc != 1) { 2235 printf("Invalid WFD_SUBELEM_GET command: needs one " 2236 "argument (subelem)\n"); 2237 return -1; 2238 } 2239 2240 res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_GET %s", 2241 argv[0]); 2242 if (res < 0 || (size_t) res >= sizeof(cmd)) 2243 return -1; 2244 cmd[sizeof(cmd) - 1] = '\0'; 2245 return wpa_ctrl_command(ctrl, cmd); 2246 } 2247 #endif /* CONFIG_WIFI_DISPLAY */ 2248 2249 2250 #ifdef CONFIG_INTERWORKING 2251 static int wpa_cli_cmd_fetch_anqp(struct wpa_ctrl *ctrl, int argc, 2252 char *argv[]) 2253 { 2254 return wpa_ctrl_command(ctrl, "FETCH_ANQP"); 2255 } 2256 2257 2258 static int wpa_cli_cmd_stop_fetch_anqp(struct wpa_ctrl *ctrl, int argc, 2259 char *argv[]) 2260 { 2261 return wpa_ctrl_command(ctrl, "STOP_FETCH_ANQP"); 2262 } 2263 2264 2265 static int wpa_cli_cmd_interworking_select(struct wpa_ctrl *ctrl, int argc, 2266 char *argv[]) 2267 { 2268 return wpa_cli_cmd(ctrl, "INTERWORKING_SELECT", 0, argc, argv); 2269 } 2270 2271 2272 static int wpa_cli_cmd_interworking_connect(struct wpa_ctrl *ctrl, int argc, 2273 char *argv[]) 2274 { 2275 return wpa_cli_cmd(ctrl, "INTERWORKING_CONNECT", 1, argc, argv); 2276 } 2277 2278 2279 static int wpa_cli_cmd_anqp_get(struct wpa_ctrl *ctrl, int argc, char *argv[]) 2280 { 2281 return wpa_cli_cmd(ctrl, "ANQP_GET", 2, argc, argv); 2282 } 2283 2284 2285 static int wpa_cli_cmd_gas_request(struct wpa_ctrl *ctrl, int argc, 2286 char *argv[]) 2287 { 2288 return wpa_cli_cmd(ctrl, "GAS_REQUEST", 2, argc, argv); 2289 } 2290 2291 2292 static int wpa_cli_cmd_gas_response_get(struct wpa_ctrl *ctrl, int argc, 2293 char *argv[]) 2294 { 2295 return wpa_cli_cmd(ctrl, "GAS_RESPONSE_GET", 2, argc, argv); 2296 } 2297 #endif /* CONFIG_INTERWORKING */ 2298 2299 2300 #ifdef CONFIG_HS20 2301 2302 static int wpa_cli_cmd_hs20_anqp_get(struct wpa_ctrl *ctrl, int argc, 2303 char *argv[]) 2304 { 2305 return wpa_cli_cmd(ctrl, "HS20_ANQP_GET", 2, argc, argv); 2306 } 2307 2308 2309 static int wpa_cli_cmd_get_nai_home_realm_list(struct wpa_ctrl *ctrl, int argc, 2310 char *argv[]) 2311 { 2312 char cmd[512]; 2313 2314 if (argc == 0) { 2315 printf("Command needs one or two arguments (dst mac addr and " 2316 "optional home realm)\n"); 2317 return -1; 2318 } 2319 2320 if (write_cmd(cmd, sizeof(cmd), "HS20_GET_NAI_HOME_REALM_LIST", 2321 argc, argv) < 0) 2322 return -1; 2323 2324 return wpa_ctrl_command(ctrl, cmd); 2325 } 2326 2327 #endif /* CONFIG_HS20 */ 2328 2329 2330 static int wpa_cli_cmd_sta_autoconnect(struct wpa_ctrl *ctrl, int argc, 2331 char *argv[]) 2332 { 2333 return wpa_cli_cmd(ctrl, "STA_AUTOCONNECT", 1, argc, argv); 2334 } 2335 2336 2337 static int wpa_cli_cmd_tdls_discover(struct wpa_ctrl *ctrl, int argc, 2338 char *argv[]) 2339 { 2340 return wpa_cli_cmd(ctrl, "TDLS_DISCOVER", 1, argc, argv); 2341 } 2342 2343 2344 static int wpa_cli_cmd_tdls_setup(struct wpa_ctrl *ctrl, int argc, 2345 char *argv[]) 2346 { 2347 return wpa_cli_cmd(ctrl, "TDLS_SETUP", 1, argc, argv); 2348 } 2349 2350 2351 static int wpa_cli_cmd_tdls_teardown(struct wpa_ctrl *ctrl, int argc, 2352 char *argv[]) 2353 { 2354 return wpa_cli_cmd(ctrl, "TDLS_TEARDOWN", 1, argc, argv); 2355 } 2356 2357 2358 static int wpa_cli_cmd_signal_poll(struct wpa_ctrl *ctrl, int argc, 2359 char *argv[]) 2360 { 2361 return wpa_ctrl_command(ctrl, "SIGNAL_POLL"); 2362 } 2363 2364 2365 static int wpa_cli_cmd_pktcnt_poll(struct wpa_ctrl *ctrl, int argc, 2366 char *argv[]) 2367 { 2368 return wpa_ctrl_command(ctrl, "PKTCNT_POLL"); 2369 } 2370 2371 2372 static int wpa_cli_cmd_reauthenticate(struct wpa_ctrl *ctrl, int argc, 2373 char *argv[]) 2374 { 2375 return wpa_ctrl_command(ctrl, "REAUTHENTICATE"); 2376 } 2377 2378 2379 #ifdef CONFIG_AUTOSCAN 2380 2381 static int wpa_cli_cmd_autoscan(struct wpa_ctrl *ctrl, int argc, char *argv[]) 2382 { 2383 if (argc == 0) 2384 return wpa_ctrl_command(ctrl, "AUTOSCAN "); 2385 2386 return wpa_cli_cmd(ctrl, "AUTOSCAN", 0, argc, argv); 2387 } 2388 2389 #endif /* CONFIG_AUTOSCAN */ 2390 2391 2392 #ifdef CONFIG_WNM 2393 2394 static int wpa_cli_cmd_wnm_sleep(struct wpa_ctrl *ctrl, int argc, char *argv[]) 2395 { 2396 return wpa_cli_cmd(ctrl, "WNM_SLEEP", 0, argc, argv); 2397 } 2398 2399 2400 static int wpa_cli_cmd_wnm_bss_query(struct wpa_ctrl *ctrl, int argc, char *argv[]) 2401 { 2402 return wpa_cli_cmd(ctrl, "WNM_BSS_QUERY", 1, argc, argv); 2403 } 2404 2405 #endif /* CONFIG_WNM */ 2406 2407 2408 static int wpa_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[]) 2409 { 2410 if (argc == 0) 2411 return -1; 2412 return wpa_cli_cmd(ctrl, argv[0], 0, argc - 1, &argv[1]); 2413 } 2414 2415 2416 #ifdef ANDROID 2417 static int wpa_cli_cmd_driver(struct wpa_ctrl *ctrl, int argc, char *argv[]) 2418 { 2419 return wpa_cli_cmd(ctrl, "DRIVER", 1, argc, argv); 2420 } 2421 #endif /* ANDROID */ 2422 2423 2424 static int wpa_cli_cmd_flush(struct wpa_ctrl *ctrl, int argc, char *argv[]) 2425 { 2426 return wpa_ctrl_command(ctrl, "FLUSH"); 2427 } 2428 2429 2430 static int wpa_cli_cmd_radio_work(struct wpa_ctrl *ctrl, int argc, char *argv[]) 2431 { 2432 return wpa_cli_cmd(ctrl, "RADIO_WORK", 1, argc, argv); 2433 } 2434 2435 2436 enum wpa_cli_cmd_flags { 2437 cli_cmd_flag_none = 0x00, 2438 cli_cmd_flag_sensitive = 0x01 2439 }; 2440 2441 struct wpa_cli_cmd { 2442 const char *cmd; 2443 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]); 2444 char ** (*completion)(const char *str, int pos); 2445 enum wpa_cli_cmd_flags flags; 2446 const char *usage; 2447 }; 2448 2449 static struct wpa_cli_cmd wpa_cli_commands[] = { 2450 { "status", wpa_cli_cmd_status, NULL, 2451 cli_cmd_flag_none, 2452 "[verbose] = get current WPA/EAPOL/EAP status" }, 2453 { "ifname", wpa_cli_cmd_ifname, NULL, 2454 cli_cmd_flag_none, 2455 "= get current interface name" }, 2456 { "ping", wpa_cli_cmd_ping, NULL, 2457 cli_cmd_flag_none, 2458 "= pings wpa_supplicant" }, 2459 { "relog", wpa_cli_cmd_relog, NULL, 2460 cli_cmd_flag_none, 2461 "= re-open log-file (allow rolling logs)" }, 2462 { "note", wpa_cli_cmd_note, NULL, 2463 cli_cmd_flag_none, 2464 "<text> = add a note to wpa_supplicant debug log" }, 2465 { "mib", wpa_cli_cmd_mib, NULL, 2466 cli_cmd_flag_none, 2467 "= get MIB variables (dot1x, dot11)" }, 2468 { "help", wpa_cli_cmd_help, wpa_cli_complete_help, 2469 cli_cmd_flag_none, 2470 "[command] = show usage help" }, 2471 { "interface", wpa_cli_cmd_interface, NULL, 2472 cli_cmd_flag_none, 2473 "[ifname] = show interfaces/select interface" }, 2474 { "level", wpa_cli_cmd_level, NULL, 2475 cli_cmd_flag_none, 2476 "<debug level> = change debug level" }, 2477 { "license", wpa_cli_cmd_license, NULL, 2478 cli_cmd_flag_none, 2479 "= show full wpa_cli license" }, 2480 { "quit", wpa_cli_cmd_quit, NULL, 2481 cli_cmd_flag_none, 2482 "= exit wpa_cli" }, 2483 { "set", wpa_cli_cmd_set, wpa_cli_complete_set, 2484 cli_cmd_flag_none, 2485 "= set variables (shows list of variables when run without " 2486 "arguments)" }, 2487 { "get", wpa_cli_cmd_get, NULL, 2488 cli_cmd_flag_none, 2489 "<name> = get information" }, 2490 { "logon", wpa_cli_cmd_logon, NULL, 2491 cli_cmd_flag_none, 2492 "= IEEE 802.1X EAPOL state machine logon" }, 2493 { "logoff", wpa_cli_cmd_logoff, NULL, 2494 cli_cmd_flag_none, 2495 "= IEEE 802.1X EAPOL state machine logoff" }, 2496 { "pmksa", wpa_cli_cmd_pmksa, NULL, 2497 cli_cmd_flag_none, 2498 "= show PMKSA cache" }, 2499 { "reassociate", wpa_cli_cmd_reassociate, NULL, 2500 cli_cmd_flag_none, 2501 "= force reassociation" }, 2502 { "preauthenticate", wpa_cli_cmd_preauthenticate, wpa_cli_complete_bss, 2503 cli_cmd_flag_none, 2504 "<BSSID> = force preauthentication" }, 2505 { "identity", wpa_cli_cmd_identity, NULL, 2506 cli_cmd_flag_none, 2507 "<network id> <identity> = configure identity for an SSID" }, 2508 { "password", wpa_cli_cmd_password, NULL, 2509 cli_cmd_flag_sensitive, 2510 "<network id> <password> = configure password for an SSID" }, 2511 { "new_password", wpa_cli_cmd_new_password, NULL, 2512 cli_cmd_flag_sensitive, 2513 "<network id> <password> = change password for an SSID" }, 2514 { "pin", wpa_cli_cmd_pin, NULL, 2515 cli_cmd_flag_sensitive, 2516 "<network id> <pin> = configure pin for an SSID" }, 2517 { "otp", wpa_cli_cmd_otp, NULL, 2518 cli_cmd_flag_sensitive, 2519 "<network id> <password> = configure one-time-password for an SSID" 2520 }, 2521 { "passphrase", wpa_cli_cmd_passphrase, NULL, 2522 cli_cmd_flag_sensitive, 2523 "<network id> <passphrase> = configure private key passphrase\n" 2524 " for an SSID" }, 2525 { "sim", wpa_cli_cmd_sim, NULL, 2526 cli_cmd_flag_sensitive, 2527 "<network id> <pin> = report SIM operation result" }, 2528 { "bssid", wpa_cli_cmd_bssid, NULL, 2529 cli_cmd_flag_none, 2530 "<network id> <BSSID> = set preferred BSSID for an SSID" }, 2531 { "blacklist", wpa_cli_cmd_blacklist, wpa_cli_complete_bss, 2532 cli_cmd_flag_none, 2533 "<BSSID> = add a BSSID to the blacklist\n" 2534 "blacklist clear = clear the blacklist\n" 2535 "blacklist = display the blacklist" }, 2536 { "log_level", wpa_cli_cmd_log_level, NULL, 2537 cli_cmd_flag_none, 2538 "<level> [<timestamp>] = update the log level/timestamp\n" 2539 "log_level = display the current log level and log options" }, 2540 { "list_networks", wpa_cli_cmd_list_networks, NULL, 2541 cli_cmd_flag_none, 2542 "= list configured networks" }, 2543 { "select_network", wpa_cli_cmd_select_network, NULL, 2544 cli_cmd_flag_none, 2545 "<network id> = select a network (disable others)" }, 2546 { "enable_network", wpa_cli_cmd_enable_network, NULL, 2547 cli_cmd_flag_none, 2548 "<network id> = enable a network" }, 2549 { "disable_network", wpa_cli_cmd_disable_network, NULL, 2550 cli_cmd_flag_none, 2551 "<network id> = disable a network" }, 2552 { "add_network", wpa_cli_cmd_add_network, NULL, 2553 cli_cmd_flag_none, 2554 "= add a network" }, 2555 { "remove_network", wpa_cli_cmd_remove_network, NULL, 2556 cli_cmd_flag_none, 2557 "<network id> = remove a network" }, 2558 { "set_network", wpa_cli_cmd_set_network, NULL, 2559 cli_cmd_flag_sensitive, 2560 "<network id> <variable> <value> = set network variables (shows\n" 2561 " list of variables when run without arguments)" }, 2562 { "get_network", wpa_cli_cmd_get_network, NULL, 2563 cli_cmd_flag_none, 2564 "<network id> <variable> = get network variables" }, 2565 { "list_creds", wpa_cli_cmd_list_creds, NULL, 2566 cli_cmd_flag_none, 2567 "= list configured credentials" }, 2568 { "add_cred", wpa_cli_cmd_add_cred, NULL, 2569 cli_cmd_flag_none, 2570 "= add a credential" }, 2571 { "remove_cred", wpa_cli_cmd_remove_cred, NULL, 2572 cli_cmd_flag_none, 2573 "<cred id> = remove a credential" }, 2574 { "set_cred", wpa_cli_cmd_set_cred, NULL, 2575 cli_cmd_flag_sensitive, 2576 "<cred id> <variable> <value> = set credential variables" }, 2577 { "save_config", wpa_cli_cmd_save_config, NULL, 2578 cli_cmd_flag_none, 2579 "= save the current configuration" }, 2580 { "disconnect", wpa_cli_cmd_disconnect, NULL, 2581 cli_cmd_flag_none, 2582 "= disconnect and wait for reassociate/reconnect command before\n" 2583 " connecting" }, 2584 { "reconnect", wpa_cli_cmd_reconnect, NULL, 2585 cli_cmd_flag_none, 2586 "= like reassociate, but only takes effect if already disconnected" 2587 }, 2588 { "scan", wpa_cli_cmd_scan, NULL, 2589 cli_cmd_flag_none, 2590 "= request new BSS scan" }, 2591 { "scan_results", wpa_cli_cmd_scan_results, NULL, 2592 cli_cmd_flag_none, 2593 "= get latest scan results" }, 2594 { "bss", wpa_cli_cmd_bss, wpa_cli_complete_bss, 2595 cli_cmd_flag_none, 2596 "<<idx> | <bssid>> = get detailed scan result info" }, 2597 { "get_capability", wpa_cli_cmd_get_capability, NULL, 2598 cli_cmd_flag_none, 2599 "<eap/pairwise/group/key_mgmt/proto/auth_alg/channels/freq/modes> " 2600 "= get capabilies" }, 2601 { "reconfigure", wpa_cli_cmd_reconfigure, NULL, 2602 cli_cmd_flag_none, 2603 "= force wpa_supplicant to re-read its configuration file" }, 2604 { "terminate", wpa_cli_cmd_terminate, NULL, 2605 cli_cmd_flag_none, 2606 "= terminate wpa_supplicant" }, 2607 { "interface_add", wpa_cli_cmd_interface_add, NULL, 2608 cli_cmd_flag_none, 2609 "<ifname> <confname> <driver> <ctrl_interface> <driver_param>\n" 2610 " <bridge_name> = adds new interface, all parameters but <ifname>\n" 2611 " are optional" }, 2612 { "interface_remove", wpa_cli_cmd_interface_remove, NULL, 2613 cli_cmd_flag_none, 2614 "<ifname> = removes the interface" }, 2615 { "interface_list", wpa_cli_cmd_interface_list, NULL, 2616 cli_cmd_flag_none, 2617 "= list available interfaces" }, 2618 { "ap_scan", wpa_cli_cmd_ap_scan, NULL, 2619 cli_cmd_flag_none, 2620 "<value> = set ap_scan parameter" }, 2621 { "scan_interval", wpa_cli_cmd_scan_interval, NULL, 2622 cli_cmd_flag_none, 2623 "<value> = set scan_interval parameter (in seconds)" }, 2624 { "bss_expire_age", wpa_cli_cmd_bss_expire_age, NULL, 2625 cli_cmd_flag_none, 2626 "<value> = set BSS expiration age parameter" }, 2627 { "bss_expire_count", wpa_cli_cmd_bss_expire_count, NULL, 2628 cli_cmd_flag_none, 2629 "<value> = set BSS expiration scan count parameter" }, 2630 { "bss_flush", wpa_cli_cmd_bss_flush, NULL, 2631 cli_cmd_flag_none, 2632 "<value> = set BSS flush age (0 by default)" }, 2633 { "stkstart", wpa_cli_cmd_stkstart, NULL, 2634 cli_cmd_flag_none, 2635 "<addr> = request STK negotiation with <addr>" }, 2636 { "ft_ds", wpa_cli_cmd_ft_ds, wpa_cli_complete_bss, 2637 cli_cmd_flag_none, 2638 "<addr> = request over-the-DS FT with <addr>" }, 2639 { "wps_pbc", wpa_cli_cmd_wps_pbc, wpa_cli_complete_bss, 2640 cli_cmd_flag_none, 2641 "[BSSID] = start Wi-Fi Protected Setup: Push Button Configuration" }, 2642 { "wps_pin", wpa_cli_cmd_wps_pin, wpa_cli_complete_bss, 2643 cli_cmd_flag_sensitive, 2644 "<BSSID> [PIN] = start WPS PIN method (returns PIN, if not " 2645 "hardcoded)" }, 2646 { "wps_check_pin", wpa_cli_cmd_wps_check_pin, NULL, 2647 cli_cmd_flag_sensitive, 2648 "<PIN> = verify PIN checksum" }, 2649 { "wps_cancel", wpa_cli_cmd_wps_cancel, NULL, cli_cmd_flag_none, 2650 "Cancels the pending WPS operation" }, 2651 #ifdef CONFIG_WPS_NFC 2652 { "wps_nfc", wpa_cli_cmd_wps_nfc, wpa_cli_complete_bss, 2653 cli_cmd_flag_none, 2654 "[BSSID] = start Wi-Fi Protected Setup: NFC" }, 2655 { "wps_nfc_config_token", wpa_cli_cmd_wps_nfc_config_token, NULL, 2656 cli_cmd_flag_none, 2657 "<WPS|NDEF> = build configuration token" }, 2658 { "wps_nfc_token", wpa_cli_cmd_wps_nfc_token, NULL, 2659 cli_cmd_flag_none, 2660 "<WPS|NDEF> = create password token" }, 2661 { "wps_nfc_tag_read", wpa_cli_cmd_wps_nfc_tag_read, NULL, 2662 cli_cmd_flag_sensitive, 2663 "<hexdump of payload> = report read NFC tag with WPS data" }, 2664 { "nfc_get_handover_req", wpa_cli_cmd_nfc_get_handover_req, NULL, 2665 cli_cmd_flag_none, 2666 "<NDEF> <WPS> = create NFC handover request" }, 2667 { "nfc_get_handover_sel", wpa_cli_cmd_nfc_get_handover_sel, NULL, 2668 cli_cmd_flag_none, 2669 "<NDEF> <WPS> = create NFC handover select" }, 2670 { "nfc_rx_handover_req", wpa_cli_cmd_nfc_rx_handover_req, NULL, 2671 cli_cmd_flag_none, 2672 "<hexdump of payload> = report received NFC handover request" }, 2673 { "nfc_rx_handover_sel", wpa_cli_cmd_nfc_rx_handover_sel, NULL, 2674 cli_cmd_flag_none, 2675 "<hexdump of payload> = report received NFC handover select" }, 2676 { "nfc_report_handover", wpa_cli_cmd_nfc_report_handover, NULL, 2677 cli_cmd_flag_none, 2678 "<role> <type> <hexdump of req> <hexdump of sel> = report completed " 2679 "NFC handover" }, 2680 #endif /* CONFIG_WPS_NFC */ 2681 { "wps_reg", wpa_cli_cmd_wps_reg, wpa_cli_complete_bss, 2682 cli_cmd_flag_sensitive, 2683 "<BSSID> <AP PIN> = start WPS Registrar to configure an AP" }, 2684 { "wps_ap_pin", wpa_cli_cmd_wps_ap_pin, NULL, 2685 cli_cmd_flag_sensitive, 2686 "[params..] = enable/disable AP PIN" }, 2687 { "wps_er_start", wpa_cli_cmd_wps_er_start, NULL, 2688 cli_cmd_flag_none, 2689 "[IP address] = start Wi-Fi Protected Setup External Registrar" }, 2690 { "wps_er_stop", wpa_cli_cmd_wps_er_stop, NULL, 2691 cli_cmd_flag_none, 2692 "= stop Wi-Fi Protected Setup External Registrar" }, 2693 { "wps_er_pin", wpa_cli_cmd_wps_er_pin, NULL, 2694 cli_cmd_flag_sensitive, 2695 "<UUID> <PIN> = add an Enrollee PIN to External Registrar" }, 2696 { "wps_er_pbc", wpa_cli_cmd_wps_er_pbc, NULL, 2697 cli_cmd_flag_none, 2698 "<UUID> = accept an Enrollee PBC using External Registrar" }, 2699 { "wps_er_learn", wpa_cli_cmd_wps_er_learn, NULL, 2700 cli_cmd_flag_sensitive, 2701 "<UUID> <PIN> = learn AP configuration" }, 2702 { "wps_er_set_config", wpa_cli_cmd_wps_er_set_config, NULL, 2703 cli_cmd_flag_none, 2704 "<UUID> <network id> = set AP configuration for enrolling" }, 2705 { "wps_er_config", wpa_cli_cmd_wps_er_config, NULL, 2706 cli_cmd_flag_sensitive, 2707 "<UUID> <PIN> <SSID> <auth> <encr> <key> = configure AP" }, 2708 #ifdef CONFIG_WPS_NFC 2709 { "wps_er_nfc_config_token", wpa_cli_cmd_wps_er_nfc_config_token, NULL, 2710 cli_cmd_flag_none, 2711 "<WPS/NDEF> <UUID> = build NFC configuration token" }, 2712 #endif /* CONFIG_WPS_NFC */ 2713 { "ibss_rsn", wpa_cli_cmd_ibss_rsn, NULL, 2714 cli_cmd_flag_none, 2715 "<addr> = request RSN authentication with <addr> in IBSS" }, 2716 #ifdef CONFIG_AP 2717 { "sta", wpa_cli_cmd_sta, NULL, 2718 cli_cmd_flag_none, 2719 "<addr> = get information about an associated station (AP)" }, 2720 { "all_sta", wpa_cli_cmd_all_sta, NULL, 2721 cli_cmd_flag_none, 2722 "= get information about all associated stations (AP)" }, 2723 { "deauthenticate", wpa_cli_cmd_deauthenticate, NULL, 2724 cli_cmd_flag_none, 2725 "<addr> = deauthenticate a station" }, 2726 { "disassociate", wpa_cli_cmd_disassociate, NULL, 2727 cli_cmd_flag_none, 2728 "<addr> = disassociate a station" }, 2729 { "chan_switch", wpa_cli_cmd_chanswitch, NULL, 2730 cli_cmd_flag_none, 2731 "<cs_count> <freq> [sec_channel_offset=] [center_freq1=]" 2732 " [center_freq2=] [bandwidth=] [blocktx] [ht|vht]" 2733 " = CSA parameters" }, 2734 #endif /* CONFIG_AP */ 2735 { "suspend", wpa_cli_cmd_suspend, NULL, cli_cmd_flag_none, 2736 "= notification of suspend/hibernate" }, 2737 { "resume", wpa_cli_cmd_resume, NULL, cli_cmd_flag_none, 2738 "= notification of resume/thaw" }, 2739 { "drop_sa", wpa_cli_cmd_drop_sa, NULL, cli_cmd_flag_none, 2740 "= drop SA without deauth/disassoc (test command)" }, 2741 { "roam", wpa_cli_cmd_roam, wpa_cli_complete_bss, 2742 cli_cmd_flag_none, 2743 "<addr> = roam to the specified BSS" }, 2744 #ifdef CONFIG_P2P 2745 { "p2p_find", wpa_cli_cmd_p2p_find, wpa_cli_complete_p2p_find, 2746 cli_cmd_flag_none, 2747 "[timeout] [type=*] = find P2P Devices for up-to timeout seconds" }, 2748 { "p2p_stop_find", wpa_cli_cmd_p2p_stop_find, NULL, cli_cmd_flag_none, 2749 "= stop P2P Devices search" }, 2750 { "p2p_connect", wpa_cli_cmd_p2p_connect, wpa_cli_complete_p2p_connect, 2751 cli_cmd_flag_none, 2752 "<addr> <\"pbc\"|PIN> [ht40] = connect to a P2P Device" }, 2753 { "p2p_listen", wpa_cli_cmd_p2p_listen, NULL, cli_cmd_flag_none, 2754 "[timeout] = listen for P2P Devices for up-to timeout seconds" }, 2755 { "p2p_group_remove", wpa_cli_cmd_p2p_group_remove, 2756 wpa_cli_complete_p2p_group_remove, cli_cmd_flag_none, 2757 "<ifname> = remove P2P group interface (terminate group if GO)" }, 2758 { "p2p_group_add", wpa_cli_cmd_p2p_group_add, NULL, cli_cmd_flag_none, 2759 "[ht40] = add a new P2P group (local end as GO)" }, 2760 { "p2p_prov_disc", wpa_cli_cmd_p2p_prov_disc, 2761 wpa_cli_complete_p2p_peer, cli_cmd_flag_none, 2762 "<addr> <method> = request provisioning discovery" }, 2763 { "p2p_get_passphrase", wpa_cli_cmd_p2p_get_passphrase, NULL, 2764 cli_cmd_flag_none, 2765 "= get the passphrase for a group (GO only)" }, 2766 { "p2p_serv_disc_req", wpa_cli_cmd_p2p_serv_disc_req, 2767 wpa_cli_complete_p2p_peer, cli_cmd_flag_none, 2768 "<addr> <TLVs> = schedule service discovery request" }, 2769 { "p2p_serv_disc_cancel_req", wpa_cli_cmd_p2p_serv_disc_cancel_req, 2770 NULL, cli_cmd_flag_none, 2771 "<id> = cancel pending service discovery request" }, 2772 { "p2p_serv_disc_resp", wpa_cli_cmd_p2p_serv_disc_resp, NULL, 2773 cli_cmd_flag_none, 2774 "<freq> <addr> <dialog token> <TLVs> = service discovery response" }, 2775 { "p2p_service_update", wpa_cli_cmd_p2p_service_update, NULL, 2776 cli_cmd_flag_none, 2777 "= indicate change in local services" }, 2778 { "p2p_serv_disc_external", wpa_cli_cmd_p2p_serv_disc_external, NULL, 2779 cli_cmd_flag_none, 2780 "<external> = set external processing of service discovery" }, 2781 { "p2p_service_flush", wpa_cli_cmd_p2p_service_flush, NULL, 2782 cli_cmd_flag_none, 2783 "= remove all stored service entries" }, 2784 { "p2p_service_add", wpa_cli_cmd_p2p_service_add, NULL, 2785 cli_cmd_flag_none, 2786 "<bonjour|upnp> <query|version> <response|service> = add a local " 2787 "service" }, 2788 { "p2p_service_del", wpa_cli_cmd_p2p_service_del, NULL, 2789 cli_cmd_flag_none, 2790 "<bonjour|upnp> <query|version> [|service] = remove a local " 2791 "service" }, 2792 { "p2p_reject", wpa_cli_cmd_p2p_reject, wpa_cli_complete_p2p_peer, 2793 cli_cmd_flag_none, 2794 "<addr> = reject connection attempts from a specific peer" }, 2795 { "p2p_invite", wpa_cli_cmd_p2p_invite, NULL, 2796 cli_cmd_flag_none, 2797 "<cmd> [peer=addr] = invite peer" }, 2798 { "p2p_peers", wpa_cli_cmd_p2p_peers, NULL, cli_cmd_flag_none, 2799 "[discovered] = list known (optionally, only fully discovered) P2P " 2800 "peers" }, 2801 { "p2p_peer", wpa_cli_cmd_p2p_peer, wpa_cli_complete_p2p_peer, 2802 cli_cmd_flag_none, 2803 "<address> = show information about known P2P peer" }, 2804 { "p2p_set", wpa_cli_cmd_p2p_set, wpa_cli_complete_p2p_set, 2805 cli_cmd_flag_none, 2806 "<field> <value> = set a P2P parameter" }, 2807 { "p2p_flush", wpa_cli_cmd_p2p_flush, NULL, cli_cmd_flag_none, 2808 "= flush P2P state" }, 2809 { "p2p_cancel", wpa_cli_cmd_p2p_cancel, NULL, cli_cmd_flag_none, 2810 "= cancel P2P group formation" }, 2811 { "p2p_unauthorize", wpa_cli_cmd_p2p_unauthorize, 2812 wpa_cli_complete_p2p_peer, cli_cmd_flag_none, 2813 "<address> = unauthorize a peer" }, 2814 { "p2p_presence_req", wpa_cli_cmd_p2p_presence_req, NULL, 2815 cli_cmd_flag_none, 2816 "[<duration> <interval>] [<duration> <interval>] = request GO " 2817 "presence" }, 2818 { "p2p_ext_listen", wpa_cli_cmd_p2p_ext_listen, NULL, 2819 cli_cmd_flag_none, 2820 "[<period> <interval>] = set extended listen timing" }, 2821 { "p2p_remove_client", wpa_cli_cmd_p2p_remove_client, 2822 wpa_cli_complete_p2p_peer, cli_cmd_flag_none, 2823 "<address|iface=address> = remove a peer from all groups" }, 2824 #endif /* CONFIG_P2P */ 2825 #ifdef CONFIG_WIFI_DISPLAY 2826 { "wfd_subelem_set", wpa_cli_cmd_wfd_subelem_set, NULL, 2827 cli_cmd_flag_none, 2828 "<subelem> [contents] = set Wi-Fi Display subelement" }, 2829 { "wfd_subelem_get", wpa_cli_cmd_wfd_subelem_get, NULL, 2830 cli_cmd_flag_none, 2831 "<subelem> = get Wi-Fi Display subelement" }, 2832 #endif /* CONFIG_WIFI_DISPLAY */ 2833 #ifdef CONFIG_INTERWORKING 2834 { "fetch_anqp", wpa_cli_cmd_fetch_anqp, NULL, cli_cmd_flag_none, 2835 "= fetch ANQP information for all APs" }, 2836 { "stop_fetch_anqp", wpa_cli_cmd_stop_fetch_anqp, NULL, 2837 cli_cmd_flag_none, 2838 "= stop fetch_anqp operation" }, 2839 { "interworking_select", wpa_cli_cmd_interworking_select, NULL, 2840 cli_cmd_flag_none, 2841 "[auto] = perform Interworking network selection" }, 2842 { "interworking_connect", wpa_cli_cmd_interworking_connect, 2843 wpa_cli_complete_bss, cli_cmd_flag_none, 2844 "<BSSID> = connect using Interworking credentials" }, 2845 { "anqp_get", wpa_cli_cmd_anqp_get, wpa_cli_complete_bss, 2846 cli_cmd_flag_none, 2847 "<addr> <info id>[,<info id>]... = request ANQP information" }, 2848 { "gas_request", wpa_cli_cmd_gas_request, wpa_cli_complete_bss, 2849 cli_cmd_flag_none, 2850 "<addr> <AdvProtoID> [QueryReq] = GAS request" }, 2851 { "gas_response_get", wpa_cli_cmd_gas_response_get, 2852 wpa_cli_complete_bss, cli_cmd_flag_none, 2853 "<addr> <dialog token> [start,len] = Fetch last GAS response" }, 2854 #endif /* CONFIG_INTERWORKING */ 2855 #ifdef CONFIG_HS20 2856 { "hs20_anqp_get", wpa_cli_cmd_hs20_anqp_get, wpa_cli_complete_bss, 2857 cli_cmd_flag_none, 2858 "<addr> <subtype>[,<subtype>]... = request HS 2.0 ANQP information" 2859 }, 2860 { "nai_home_realm_list", wpa_cli_cmd_get_nai_home_realm_list, 2861 wpa_cli_complete_bss, cli_cmd_flag_none, 2862 "<addr> <home realm> = get HS20 nai home realm list" }, 2863 #endif /* CONFIG_HS20 */ 2864 { "sta_autoconnect", wpa_cli_cmd_sta_autoconnect, NULL, 2865 cli_cmd_flag_none, 2866 "<0/1> = disable/enable automatic reconnection" }, 2867 { "tdls_discover", wpa_cli_cmd_tdls_discover, NULL, 2868 cli_cmd_flag_none, 2869 "<addr> = request TDLS discovery with <addr>" }, 2870 { "tdls_setup", wpa_cli_cmd_tdls_setup, NULL, 2871 cli_cmd_flag_none, 2872 "<addr> = request TDLS setup with <addr>" }, 2873 { "tdls_teardown", wpa_cli_cmd_tdls_teardown, NULL, 2874 cli_cmd_flag_none, 2875 "<addr> = tear down TDLS with <addr>" }, 2876 { "signal_poll", wpa_cli_cmd_signal_poll, NULL, 2877 cli_cmd_flag_none, 2878 "= get signal parameters" }, 2879 { "pktcnt_poll", wpa_cli_cmd_pktcnt_poll, NULL, 2880 cli_cmd_flag_none, 2881 "= get TX/RX packet counters" }, 2882 { "reauthenticate", wpa_cli_cmd_reauthenticate, NULL, 2883 cli_cmd_flag_none, 2884 "= trigger IEEE 802.1X/EAPOL reauthentication" }, 2885 #ifdef CONFIG_AUTOSCAN 2886 { "autoscan", wpa_cli_cmd_autoscan, NULL, cli_cmd_flag_none, 2887 "[params] = Set or unset (if none) autoscan parameters" }, 2888 #endif /* CONFIG_AUTOSCAN */ 2889 #ifdef CONFIG_WNM 2890 { "wnm_sleep", wpa_cli_cmd_wnm_sleep, NULL, cli_cmd_flag_none, 2891 "<enter/exit> [interval=#] = enter/exit WNM-Sleep mode" }, 2892 { "wnm_bss_query", wpa_cli_cmd_wnm_bss_query, NULL, cli_cmd_flag_none, 2893 "<query reason> = Send BSS Transition Management Query" }, 2894 #endif /* CONFIG_WNM */ 2895 { "raw", wpa_cli_cmd_raw, NULL, cli_cmd_flag_sensitive, 2896 "<params..> = Sent unprocessed command" }, 2897 { "flush", wpa_cli_cmd_flush, NULL, cli_cmd_flag_none, 2898 "= flush wpa_supplicant state" }, 2899 #ifdef ANDROID 2900 { "driver", wpa_cli_cmd_driver, NULL, cli_cmd_flag_none, 2901 "<command> = driver private commands" }, 2902 #endif /* ANDROID */ 2903 { "radio_work", wpa_cli_cmd_radio_work, NULL, cli_cmd_flag_none, 2904 "= radio_work <show/add/done>" }, 2905 { NULL, NULL, NULL, cli_cmd_flag_none, NULL } 2906 }; 2907 2908 2909 /* 2910 * Prints command usage, lines are padded with the specified string. 2911 */ 2912 static void print_cmd_help(struct wpa_cli_cmd *cmd, const char *pad) 2913 { 2914 char c; 2915 size_t n; 2916 2917 printf("%s%s ", pad, cmd->cmd); 2918 for (n = 0; (c = cmd->usage[n]); n++) { 2919 printf("%c", c); 2920 if (c == '\n') 2921 printf("%s", pad); 2922 } 2923 printf("\n"); 2924 } 2925 2926 2927 static void print_help(const char *cmd) 2928 { 2929 int n; 2930 printf("commands:\n"); 2931 for (n = 0; wpa_cli_commands[n].cmd; n++) { 2932 if (cmd == NULL || str_starts(wpa_cli_commands[n].cmd, cmd)) 2933 print_cmd_help(&wpa_cli_commands[n], " "); 2934 } 2935 } 2936 2937 2938 static int wpa_cli_edit_filter_history_cb(void *ctx, const char *cmd) 2939 { 2940 const char *c, *delim; 2941 int n; 2942 size_t len; 2943 2944 delim = os_strchr(cmd, ' '); 2945 if (delim) 2946 len = delim - cmd; 2947 else 2948 len = os_strlen(cmd); 2949 2950 for (n = 0; (c = wpa_cli_commands[n].cmd); n++) { 2951 if (os_strncasecmp(cmd, c, len) == 0 && len == os_strlen(c)) 2952 return (wpa_cli_commands[n].flags & 2953 cli_cmd_flag_sensitive); 2954 } 2955 return 0; 2956 } 2957 2958 2959 static char ** wpa_list_cmd_list(void) 2960 { 2961 char **res; 2962 int i, count; 2963 struct cli_txt_entry *e; 2964 2965 count = ARRAY_SIZE(wpa_cli_commands); 2966 count += dl_list_len(&p2p_groups); 2967 count += dl_list_len(&ifnames); 2968 res = os_calloc(count + 1, sizeof(char *)); 2969 if (res == NULL) 2970 return NULL; 2971 2972 for (i = 0; wpa_cli_commands[i].cmd; i++) { 2973 res[i] = os_strdup(wpa_cli_commands[i].cmd); 2974 if (res[i] == NULL) 2975 break; 2976 } 2977 2978 dl_list_for_each(e, &p2p_groups, struct cli_txt_entry, list) { 2979 size_t len = 8 + os_strlen(e->txt); 2980 res[i] = os_malloc(len); 2981 if (res[i] == NULL) 2982 break; 2983 os_snprintf(res[i], len, "ifname=%s", e->txt); 2984 i++; 2985 } 2986 2987 dl_list_for_each(e, &ifnames, struct cli_txt_entry, list) { 2988 res[i] = os_strdup(e->txt); 2989 if (res[i] == NULL) 2990 break; 2991 i++; 2992 } 2993 2994 return res; 2995 } 2996 2997 2998 static char ** wpa_cli_cmd_completion(const char *cmd, const char *str, 2999 int pos) 3000 { 3001 int i; 3002 3003 for (i = 0; wpa_cli_commands[i].cmd; i++) { 3004 if (os_strcasecmp(wpa_cli_commands[i].cmd, cmd) == 0) { 3005 if (wpa_cli_commands[i].completion) 3006 return wpa_cli_commands[i].completion(str, 3007 pos); 3008 edit_clear_line(); 3009 printf("\r%s\n", wpa_cli_commands[i].usage); 3010 edit_redraw(); 3011 break; 3012 } 3013 } 3014 3015 return NULL; 3016 } 3017 3018 3019 static char ** wpa_cli_edit_completion_cb(void *ctx, const char *str, int pos) 3020 { 3021 char **res; 3022 const char *end; 3023 char *cmd; 3024 3025 if (pos > 7 && os_strncasecmp(str, "IFNAME=", 7) == 0) { 3026 end = os_strchr(str, ' '); 3027 if (end && pos > end - str) { 3028 pos -= end - str + 1; 3029 str = end + 1; 3030 } 3031 } 3032 3033 end = os_strchr(str, ' '); 3034 if (end == NULL || str + pos < end) 3035 return wpa_list_cmd_list(); 3036 3037 cmd = os_malloc(pos + 1); 3038 if (cmd == NULL) 3039 return NULL; 3040 os_memcpy(cmd, str, pos); 3041 cmd[end - str] = '\0'; 3042 res = wpa_cli_cmd_completion(cmd, str, pos); 3043 os_free(cmd); 3044 return res; 3045 } 3046 3047 3048 static int wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[]) 3049 { 3050 struct wpa_cli_cmd *cmd, *match = NULL; 3051 int count; 3052 int ret = 0; 3053 3054 if (argc > 1 && os_strncasecmp(argv[0], "IFNAME=", 7) == 0) { 3055 ifname_prefix = argv[0] + 7; 3056 argv = &argv[1]; 3057 argc--; 3058 } else 3059 ifname_prefix = NULL; 3060 3061 if (argc == 0) 3062 return -1; 3063 3064 count = 0; 3065 cmd = wpa_cli_commands; 3066 while (cmd->cmd) { 3067 if (os_strncasecmp(cmd->cmd, argv[0], os_strlen(argv[0])) == 0) 3068 { 3069 match = cmd; 3070 if (os_strcasecmp(cmd->cmd, argv[0]) == 0) { 3071 /* we have an exact match */ 3072 count = 1; 3073 break; 3074 } 3075 count++; 3076 } 3077 cmd++; 3078 } 3079 3080 if (count > 1) { 3081 printf("Ambiguous command '%s'; possible commands:", argv[0]); 3082 cmd = wpa_cli_commands; 3083 while (cmd->cmd) { 3084 if (os_strncasecmp(cmd->cmd, argv[0], 3085 os_strlen(argv[0])) == 0) { 3086 printf(" %s", cmd->cmd); 3087 } 3088 cmd++; 3089 } 3090 printf("\n"); 3091 ret = 1; 3092 } else if (count == 0) { 3093 printf("Unknown command '%s'\n", argv[0]); 3094 ret = 1; 3095 } else { 3096 ret = match->handler(ctrl, argc - 1, &argv[1]); 3097 } 3098 3099 return ret; 3100 } 3101 3102 3103 static int str_match(const char *a, const char *b) 3104 { 3105 return os_strncmp(a, b, os_strlen(b)) == 0; 3106 } 3107 3108 3109 static int wpa_cli_exec(const char *program, const char *arg1, 3110 const char *arg2) 3111 { 3112 char *cmd; 3113 size_t len; 3114 int res; 3115 int ret = 0; 3116 3117 len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3; 3118 cmd = os_malloc(len); 3119 if (cmd == NULL) 3120 return -1; 3121 res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2); 3122 if (res < 0 || (size_t) res >= len) { 3123 os_free(cmd); 3124 return -1; 3125 } 3126 cmd[len - 1] = '\0'; 3127 #ifndef _WIN32_WCE 3128 if (system(cmd) < 0) 3129 ret = -1; 3130 #endif /* _WIN32_WCE */ 3131 os_free(cmd); 3132 3133 return ret; 3134 } 3135 3136 3137 static void wpa_cli_action_process(const char *msg) 3138 { 3139 const char *pos; 3140 char *copy = NULL, *id, *pos2; 3141 3142 pos = msg; 3143 if (*pos == '<') { 3144 /* skip priority */ 3145 pos = os_strchr(pos, '>'); 3146 if (pos) 3147 pos++; 3148 else 3149 pos = msg; 3150 } 3151 3152 if (str_match(pos, WPA_EVENT_CONNECTED)) { 3153 int new_id = -1; 3154 os_unsetenv("WPA_ID"); 3155 os_unsetenv("WPA_ID_STR"); 3156 os_unsetenv("WPA_CTRL_DIR"); 3157 3158 pos = os_strstr(pos, "[id="); 3159 if (pos) 3160 copy = os_strdup(pos + 4); 3161 3162 if (copy) { 3163 pos2 = id = copy; 3164 while (*pos2 && *pos2 != ' ') 3165 pos2++; 3166 *pos2++ = '\0'; 3167 new_id = atoi(id); 3168 os_setenv("WPA_ID", id, 1); 3169 while (*pos2 && *pos2 != '=') 3170 pos2++; 3171 if (*pos2 == '=') 3172 pos2++; 3173 id = pos2; 3174 while (*pos2 && *pos2 != ']') 3175 pos2++; 3176 *pos2 = '\0'; 3177 os_setenv("WPA_ID_STR", id, 1); 3178 os_free(copy); 3179 } 3180 3181 os_setenv("WPA_CTRL_DIR", ctrl_iface_dir, 1); 3182 3183 if (wpa_cli_connected <= 0 || new_id != wpa_cli_last_id) { 3184 wpa_cli_connected = 1; 3185 wpa_cli_last_id = new_id; 3186 wpa_cli_exec(action_file, ctrl_ifname, "CONNECTED"); 3187 } 3188 } else if (str_match(pos, WPA_EVENT_DISCONNECTED)) { 3189 if (wpa_cli_connected) { 3190 wpa_cli_connected = 0; 3191 wpa_cli_exec(action_file, ctrl_ifname, "DISCONNECTED"); 3192 } 3193 } else if (str_match(pos, P2P_EVENT_GROUP_STARTED)) { 3194 wpa_cli_exec(action_file, ctrl_ifname, pos); 3195 } else if (str_match(pos, P2P_EVENT_GROUP_REMOVED)) { 3196 wpa_cli_exec(action_file, ctrl_ifname, pos); 3197 } else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_ENABLE)) { 3198 wpa_cli_exec(action_file, ctrl_ifname, pos); 3199 } else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_DISABLE)) { 3200 wpa_cli_exec(action_file, ctrl_ifname, pos); 3201 } else if (str_match(pos, P2P_EVENT_GO_NEG_FAILURE)) { 3202 wpa_cli_exec(action_file, ctrl_ifname, pos); 3203 } else if (str_match(pos, WPS_EVENT_SUCCESS)) { 3204 wpa_cli_exec(action_file, ctrl_ifname, pos); 3205 } else if (str_match(pos, WPS_EVENT_FAIL)) { 3206 wpa_cli_exec(action_file, ctrl_ifname, pos); 3207 } else if (str_match(pos, AP_STA_CONNECTED)) { 3208 wpa_cli_exec(action_file, ctrl_ifname, pos); 3209 } else if (str_match(pos, AP_STA_DISCONNECTED)) { 3210 wpa_cli_exec(action_file, ctrl_ifname, pos); 3211 } else if (str_match(pos, ESS_DISASSOC_IMMINENT)) { 3212 wpa_cli_exec(action_file, ctrl_ifname, pos); 3213 } else if (str_match(pos, WPA_EVENT_TERMINATING)) { 3214 printf("wpa_supplicant is terminating - stop monitoring\n"); 3215 wpa_cli_quit = 1; 3216 } 3217 } 3218 3219 3220 #ifndef CONFIG_ANSI_C_EXTRA 3221 static void wpa_cli_action_cb(char *msg, size_t len) 3222 { 3223 wpa_cli_action_process(msg); 3224 } 3225 #endif /* CONFIG_ANSI_C_EXTRA */ 3226 3227 3228 static void wpa_cli_reconnect(void) 3229 { 3230 wpa_cli_close_connection(); 3231 if (wpa_cli_open_connection(ctrl_ifname, 1) < 0) 3232 return; 3233 3234 if (interactive) { 3235 edit_clear_line(); 3236 printf("\rConnection to wpa_supplicant re-established\n"); 3237 edit_redraw(); 3238 } 3239 } 3240 3241 3242 static void cli_event(const char *str) 3243 { 3244 const char *start, *s; 3245 3246 start = os_strchr(str, '>'); 3247 if (start == NULL) 3248 return; 3249 3250 start++; 3251 3252 if (str_starts(start, WPA_EVENT_BSS_ADDED)) { 3253 s = os_strchr(start, ' '); 3254 if (s == NULL) 3255 return; 3256 s = os_strchr(s + 1, ' '); 3257 if (s == NULL) 3258 return; 3259 cli_txt_list_add(&bsses, s + 1); 3260 return; 3261 } 3262 3263 if (str_starts(start, WPA_EVENT_BSS_REMOVED)) { 3264 s = os_strchr(start, ' '); 3265 if (s == NULL) 3266 return; 3267 s = os_strchr(s + 1, ' '); 3268 if (s == NULL) 3269 return; 3270 cli_txt_list_del_addr(&bsses, s + 1); 3271 return; 3272 } 3273 3274 #ifdef CONFIG_P2P 3275 if (str_starts(start, P2P_EVENT_DEVICE_FOUND)) { 3276 s = os_strstr(start, " p2p_dev_addr="); 3277 if (s == NULL) 3278 return; 3279 cli_txt_list_add_addr(&p2p_peers, s + 14); 3280 return; 3281 } 3282 3283 if (str_starts(start, P2P_EVENT_DEVICE_LOST)) { 3284 s = os_strstr(start, " p2p_dev_addr="); 3285 if (s == NULL) 3286 return; 3287 cli_txt_list_del_addr(&p2p_peers, s + 14); 3288 return; 3289 } 3290 3291 if (str_starts(start, P2P_EVENT_GROUP_STARTED)) { 3292 s = os_strchr(start, ' '); 3293 if (s == NULL) 3294 return; 3295 cli_txt_list_add_word(&p2p_groups, s + 1); 3296 return; 3297 } 3298 3299 if (str_starts(start, P2P_EVENT_GROUP_REMOVED)) { 3300 s = os_strchr(start, ' '); 3301 if (s == NULL) 3302 return; 3303 cli_txt_list_del_word(&p2p_groups, s + 1); 3304 return; 3305 } 3306 #endif /* CONFIG_P2P */ 3307 } 3308 3309 3310 static int check_terminating(const char *msg) 3311 { 3312 const char *pos = msg; 3313 3314 if (*pos == '<') { 3315 /* skip priority */ 3316 pos = os_strchr(pos, '>'); 3317 if (pos) 3318 pos++; 3319 else 3320 pos = msg; 3321 } 3322 3323 if (str_match(pos, WPA_EVENT_TERMINATING) && ctrl_conn) { 3324 edit_clear_line(); 3325 printf("\rConnection to wpa_supplicant lost - trying to " 3326 "reconnect\n"); 3327 edit_redraw(); 3328 wpa_cli_attached = 0; 3329 wpa_cli_close_connection(); 3330 return 1; 3331 } 3332 3333 return 0; 3334 } 3335 3336 3337 static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int action_monitor) 3338 { 3339 if (ctrl_conn == NULL) { 3340 wpa_cli_reconnect(); 3341 return; 3342 } 3343 while (wpa_ctrl_pending(ctrl) > 0) { 3344 char buf[256]; 3345 size_t len = sizeof(buf) - 1; 3346 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) { 3347 buf[len] = '\0'; 3348 if (action_monitor) 3349 wpa_cli_action_process(buf); 3350 else { 3351 cli_event(buf); 3352 if (wpa_cli_show_event(buf)) { 3353 edit_clear_line(); 3354 printf("\r%s\n", buf); 3355 edit_redraw(); 3356 } 3357 3358 if (interactive && check_terminating(buf) > 0) 3359 return; 3360 } 3361 } else { 3362 printf("Could not read pending message.\n"); 3363 break; 3364 } 3365 } 3366 3367 if (wpa_ctrl_pending(ctrl) < 0) { 3368 printf("Connection to wpa_supplicant lost - trying to " 3369 "reconnect\n"); 3370 wpa_cli_reconnect(); 3371 } 3372 } 3373 3374 #define max_args 10 3375 3376 static int tokenize_cmd(char *cmd, char *argv[]) 3377 { 3378 char *pos; 3379 int argc = 0; 3380 3381 pos = cmd; 3382 for (;;) { 3383 while (*pos == ' ') 3384 pos++; 3385 if (*pos == '\0') 3386 break; 3387 argv[argc] = pos; 3388 argc++; 3389 if (argc == max_args) 3390 break; 3391 if (*pos == '"') { 3392 char *pos2 = os_strrchr(pos, '"'); 3393 if (pos2) 3394 pos = pos2 + 1; 3395 } 3396 while (*pos != '\0' && *pos != ' ') 3397 pos++; 3398 if (*pos == ' ') 3399 *pos++ = '\0'; 3400 } 3401 3402 return argc; 3403 } 3404 3405 3406 static void wpa_cli_ping(void *eloop_ctx, void *timeout_ctx) 3407 { 3408 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) { 3409 printf("Connection to wpa_supplicant lost - trying to " 3410 "reconnect\n"); 3411 wpa_cli_close_connection(); 3412 } 3413 if (!ctrl_conn) 3414 wpa_cli_reconnect(); 3415 eloop_register_timeout(ping_interval, 0, wpa_cli_ping, NULL, NULL); 3416 } 3417 3418 3419 static void wpa_cli_mon_receive(int sock, void *eloop_ctx, void *sock_ctx) 3420 { 3421 wpa_cli_recv_pending(mon_conn, 0); 3422 } 3423 3424 3425 static void wpa_cli_edit_cmd_cb(void *ctx, char *cmd) 3426 { 3427 char *argv[max_args]; 3428 int argc; 3429 argc = tokenize_cmd(cmd, argv); 3430 if (argc) 3431 wpa_request(ctrl_conn, argc, argv); 3432 } 3433 3434 3435 static void wpa_cli_edit_eof_cb(void *ctx) 3436 { 3437 eloop_terminate(); 3438 } 3439 3440 3441 static int warning_displayed = 0; 3442 static char *hfile = NULL; 3443 static int edit_started = 0; 3444 3445 static void start_edit(void) 3446 { 3447 char *home; 3448 char *ps = NULL; 3449 3450 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE 3451 ps = wpa_ctrl_get_remote_ifname(ctrl_conn); 3452 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ 3453 3454 home = getenv("HOME"); 3455 if (home) { 3456 const char *fname = ".wpa_cli_history"; 3457 int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1; 3458 hfile = os_malloc(hfile_len); 3459 if (hfile) 3460 os_snprintf(hfile, hfile_len, "%s/%s", home, fname); 3461 } 3462 3463 if (edit_init(wpa_cli_edit_cmd_cb, wpa_cli_edit_eof_cb, 3464 wpa_cli_edit_completion_cb, NULL, hfile, ps) < 0) { 3465 eloop_terminate(); 3466 return; 3467 } 3468 3469 edit_started = 1; 3470 eloop_register_timeout(ping_interval, 0, wpa_cli_ping, NULL, NULL); 3471 } 3472 3473 3474 static void update_bssid_list(struct wpa_ctrl *ctrl) 3475 { 3476 char buf[4096]; 3477 size_t len = sizeof(buf); 3478 int ret; 3479 char *cmd = "BSS RANGE=ALL MASK=0x2"; 3480 char *pos, *end; 3481 3482 if (ctrl == NULL) 3483 return; 3484 ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, NULL); 3485 if (ret < 0) 3486 return; 3487 buf[len] = '\0'; 3488 3489 pos = buf; 3490 while (pos) { 3491 pos = os_strstr(pos, "bssid="); 3492 if (pos == NULL) 3493 break; 3494 pos += 6; 3495 end = os_strchr(pos, '\n'); 3496 if (end == NULL) 3497 break; 3498 *end = '\0'; 3499 cli_txt_list_add(&bsses, pos); 3500 pos = end + 1; 3501 } 3502 } 3503 3504 3505 static void update_ifnames(struct wpa_ctrl *ctrl) 3506 { 3507 char buf[4096]; 3508 size_t len = sizeof(buf); 3509 int ret; 3510 char *cmd = "INTERFACES"; 3511 char *pos, *end; 3512 char txt[200]; 3513 3514 cli_txt_list_flush(&ifnames); 3515 3516 if (ctrl == NULL) 3517 return; 3518 ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, NULL); 3519 if (ret < 0) 3520 return; 3521 buf[len] = '\0'; 3522 3523 pos = buf; 3524 while (pos) { 3525 end = os_strchr(pos, '\n'); 3526 if (end == NULL) 3527 break; 3528 *end = '\0'; 3529 ret = os_snprintf(txt, sizeof(txt), "ifname=%s", pos); 3530 if (ret > 0 && ret < (int) sizeof(txt)) 3531 cli_txt_list_add(&ifnames, txt); 3532 pos = end + 1; 3533 } 3534 } 3535 3536 3537 static void try_connection(void *eloop_ctx, void *timeout_ctx) 3538 { 3539 if (ctrl_conn) 3540 goto done; 3541 3542 if (ctrl_ifname == NULL) 3543 ctrl_ifname = wpa_cli_get_default_ifname(); 3544 3545 if (!wpa_cli_open_connection(ctrl_ifname, 1) == 0) { 3546 if (!warning_displayed) { 3547 printf("Could not connect to wpa_supplicant: " 3548 "%s - re-trying\n", ctrl_ifname); 3549 warning_displayed = 1; 3550 } 3551 eloop_register_timeout(1, 0, try_connection, NULL, NULL); 3552 return; 3553 } 3554 3555 update_bssid_list(ctrl_conn); 3556 3557 if (warning_displayed) 3558 printf("Connection established.\n"); 3559 3560 done: 3561 start_edit(); 3562 } 3563 3564 3565 static void wpa_cli_interactive(void) 3566 { 3567 printf("\nInteractive mode\n\n"); 3568 3569 eloop_register_timeout(0, 0, try_connection, NULL, NULL); 3570 eloop_run(); 3571 eloop_cancel_timeout(try_connection, NULL, NULL); 3572 3573 cli_txt_list_flush(&p2p_peers); 3574 cli_txt_list_flush(&p2p_groups); 3575 cli_txt_list_flush(&bsses); 3576 cli_txt_list_flush(&ifnames); 3577 if (edit_started) 3578 edit_deinit(hfile, wpa_cli_edit_filter_history_cb); 3579 os_free(hfile); 3580 eloop_cancel_timeout(wpa_cli_ping, NULL, NULL); 3581 wpa_cli_close_connection(); 3582 } 3583 3584 3585 static void wpa_cli_action(struct wpa_ctrl *ctrl) 3586 { 3587 #ifdef CONFIG_ANSI_C_EXTRA 3588 /* TODO: ANSI C version(?) */ 3589 printf("Action processing not supported in ANSI C build.\n"); 3590 #else /* CONFIG_ANSI_C_EXTRA */ 3591 fd_set rfds; 3592 int fd, res; 3593 struct timeval tv; 3594 char buf[256]; /* note: large enough to fit in unsolicited messages */ 3595 size_t len; 3596 3597 fd = wpa_ctrl_get_fd(ctrl); 3598 3599 while (!wpa_cli_quit) { 3600 FD_ZERO(&rfds); 3601 FD_SET(fd, &rfds); 3602 tv.tv_sec = ping_interval; 3603 tv.tv_usec = 0; 3604 res = select(fd + 1, &rfds, NULL, NULL, &tv); 3605 if (res < 0 && errno != EINTR) { 3606 perror("select"); 3607 break; 3608 } 3609 3610 if (FD_ISSET(fd, &rfds)) 3611 wpa_cli_recv_pending(ctrl, 1); 3612 else { 3613 /* verify that connection is still working */ 3614 len = sizeof(buf) - 1; 3615 if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len, 3616 wpa_cli_action_cb) < 0 || 3617 len < 4 || os_memcmp(buf, "PONG", 4) != 0) { 3618 printf("wpa_supplicant did not reply to PING " 3619 "command - exiting\n"); 3620 break; 3621 } 3622 } 3623 } 3624 #endif /* CONFIG_ANSI_C_EXTRA */ 3625 } 3626 3627 3628 static void wpa_cli_cleanup(void) 3629 { 3630 wpa_cli_close_connection(); 3631 if (pid_file) 3632 os_daemonize_terminate(pid_file); 3633 3634 os_program_deinit(); 3635 } 3636 3637 3638 static void wpa_cli_terminate(int sig, void *ctx) 3639 { 3640 eloop_terminate(); 3641 } 3642 3643 3644 static char * wpa_cli_get_default_ifname(void) 3645 { 3646 char *ifname = NULL; 3647 3648 #ifdef CONFIG_CTRL_IFACE_UNIX 3649 struct dirent *dent; 3650 DIR *dir = opendir(ctrl_iface_dir); 3651 if (!dir) { 3652 #ifdef ANDROID 3653 char ifprop[PROPERTY_VALUE_MAX]; 3654 if (property_get("wifi.interface", ifprop, NULL) != 0) { 3655 ifname = os_strdup(ifprop); 3656 printf("Using interface '%s'\n", ifname); 3657 return ifname; 3658 } 3659 #endif /* ANDROID */ 3660 return NULL; 3661 } 3662 while ((dent = readdir(dir))) { 3663 #ifdef _DIRENT_HAVE_D_TYPE 3664 /* 3665 * Skip the file if it is not a socket. Also accept 3666 * DT_UNKNOWN (0) in case the C library or underlying 3667 * file system does not support d_type. 3668 */ 3669 if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN) 3670 continue; 3671 #endif /* _DIRENT_HAVE_D_TYPE */ 3672 if (os_strcmp(dent->d_name, ".") == 0 || 3673 os_strcmp(dent->d_name, "..") == 0) 3674 continue; 3675 printf("Selected interface '%s'\n", dent->d_name); 3676 ifname = os_strdup(dent->d_name); 3677 break; 3678 } 3679 closedir(dir); 3680 #endif /* CONFIG_CTRL_IFACE_UNIX */ 3681 3682 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE 3683 char buf[4096], *pos; 3684 size_t len; 3685 struct wpa_ctrl *ctrl; 3686 int ret; 3687 3688 ctrl = wpa_ctrl_open(NULL); 3689 if (ctrl == NULL) 3690 return NULL; 3691 3692 len = sizeof(buf) - 1; 3693 ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf, &len, NULL); 3694 if (ret >= 0) { 3695 buf[len] = '\0'; 3696 pos = os_strchr(buf, '\n'); 3697 if (pos) 3698 *pos = '\0'; 3699 ifname = os_strdup(buf); 3700 } 3701 wpa_ctrl_close(ctrl); 3702 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ 3703 3704 return ifname; 3705 } 3706 3707 3708 int main(int argc, char *argv[]) 3709 { 3710 int c; 3711 int daemonize = 0; 3712 int ret = 0; 3713 const char *global = NULL; 3714 3715 if (os_program_init()) 3716 return -1; 3717 3718 for (;;) { 3719 c = getopt(argc, argv, "a:Bg:G:hi:p:P:v"); 3720 if (c < 0) 3721 break; 3722 switch (c) { 3723 case 'a': 3724 action_file = optarg; 3725 break; 3726 case 'B': 3727 daemonize = 1; 3728 break; 3729 case 'g': 3730 global = optarg; 3731 break; 3732 case 'G': 3733 ping_interval = atoi(optarg); 3734 break; 3735 case 'h': 3736 usage(); 3737 return 0; 3738 case 'v': 3739 printf("%s\n", wpa_cli_version); 3740 return 0; 3741 case 'i': 3742 os_free(ctrl_ifname); 3743 ctrl_ifname = os_strdup(optarg); 3744 break; 3745 case 'p': 3746 ctrl_iface_dir = optarg; 3747 break; 3748 case 'P': 3749 pid_file = optarg; 3750 break; 3751 default: 3752 usage(); 3753 return -1; 3754 } 3755 } 3756 3757 interactive = (argc == optind) && (action_file == NULL); 3758 3759 if (interactive) 3760 printf("%s\n\n%s\n\n", wpa_cli_version, wpa_cli_license); 3761 3762 if (eloop_init()) 3763 return -1; 3764 3765 if (global) { 3766 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE 3767 ctrl_conn = wpa_ctrl_open(NULL); 3768 #else /* CONFIG_CTRL_IFACE_NAMED_PIPE */ 3769 ctrl_conn = wpa_ctrl_open(global); 3770 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ 3771 if (ctrl_conn == NULL) { 3772 fprintf(stderr, "Failed to connect to wpa_supplicant " 3773 "global interface: %s error: %s\n", 3774 global, strerror(errno)); 3775 return -1; 3776 } 3777 3778 if (interactive) { 3779 update_ifnames(ctrl_conn); 3780 mon_conn = wpa_ctrl_open(global); 3781 if (mon_conn) { 3782 if (wpa_ctrl_attach(mon_conn) == 0) { 3783 wpa_cli_attached = 1; 3784 eloop_register_read_sock( 3785 wpa_ctrl_get_fd(mon_conn), 3786 wpa_cli_mon_receive, 3787 NULL, NULL); 3788 } else { 3789 printf("Failed to open monitor " 3790 "connection through global " 3791 "control interface\n"); 3792 } 3793 } 3794 } 3795 } 3796 3797 eloop_register_signal_terminate(wpa_cli_terminate, NULL); 3798 3799 if (ctrl_ifname == NULL) 3800 ctrl_ifname = wpa_cli_get_default_ifname(); 3801 3802 if (interactive) { 3803 wpa_cli_interactive(); 3804 } else { 3805 if (!global && 3806 wpa_cli_open_connection(ctrl_ifname, 0) < 0) { 3807 fprintf(stderr, "Failed to connect to non-global " 3808 "ctrl_ifname: %s error: %s\n", 3809 ctrl_ifname, strerror(errno)); 3810 return -1; 3811 } 3812 3813 if (action_file) { 3814 if (wpa_ctrl_attach(ctrl_conn) == 0) { 3815 wpa_cli_attached = 1; 3816 } else { 3817 printf("Warning: Failed to attach to " 3818 "wpa_supplicant.\n"); 3819 return -1; 3820 } 3821 } 3822 3823 if (daemonize && os_daemonize(pid_file)) 3824 return -1; 3825 3826 if (action_file) 3827 wpa_cli_action(ctrl_conn); 3828 else 3829 ret = wpa_request(ctrl_conn, argc - optind, 3830 &argv[optind]); 3831 } 3832 3833 os_free(ctrl_ifname); 3834 eloop_destroy(); 3835 wpa_cli_cleanup(); 3836 3837 return ret; 3838 } 3839 3840 #else /* CONFIG_CTRL_IFACE */ 3841 int main(int argc, char *argv[]) 3842 { 3843 printf("CONFIG_CTRL_IFACE not defined - wpa_cli disabled\n"); 3844 return -1; 3845 } 3846 #endif /* CONFIG_CTRL_IFACE */ 3847