Add 'SCAN TYPE=ONLY' functionality
[mech_eap.git] / wpa_supplicant / wpa_cli.c
index 794b20b..1a764bb 100644 (file)
@@ -28,7 +28,7 @@
 
 static const char *wpa_cli_version =
 "wpa_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi> and contributors";
 
 
 static const char *wpa_cli_license =
@@ -92,10 +92,11 @@ static DEFINE_DL_LIST(p2p_peers); /* struct cli_txt_entry */
 static DEFINE_DL_LIST(p2p_groups); /* struct cli_txt_entry */
 
 
-static void print_help(void);
+static void print_help(const char *cmd);
 static void wpa_cli_mon_receive(int sock, void *eloop_ctx, void *sock_ctx);
 static void wpa_cli_close_connection(void);
 static char * wpa_cli_get_default_ifname(void);
+static char ** wpa_list_cmd_list(void);
 
 
 static void usage(void)
@@ -112,7 +113,7 @@ static void usage(void)
               "  -B = run a daemon in the background\n"
               "  default path: " CONFIG_CTRL_IFACE_DIR "\n"
               "  default interface: first interface found in socket path\n");
-       print_help();
+       print_help(NULL);
 }
 
 
@@ -527,11 +528,26 @@ static int wpa_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[])
 
 static int wpa_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
-       print_help();
+       print_help(argc > 0 ? argv[0] : NULL);
        return 0;
 }
 
 
+static char ** wpa_cli_complete_help(const char *str, int pos)
+{
+       int arg = get_cmd_arg_num(str, pos);
+       char **res = NULL;
+
+       switch (arg) {
+       case 1:
+               res = wpa_list_cmd_list();
+               break;
+       }
+
+       return res;
+}
+
+
 static int wpa_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
        printf("%s\n\n%s\n", wpa_cli_version, wpa_cli_full_license);
@@ -720,26 +736,6 @@ static int wpa_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
 }
 
 
-#ifdef CONFIG_WPS_OOB
-static int wpa_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-       if (argc != 3 && argc != 4) {
-               printf("Invalid WPS_OOB command: need three or four "
-                      "arguments:\n"
-                      "- DEV_TYPE: use 'ufd' or 'nfc'\n"
-                      "- PATH: path of OOB device like '/mnt'\n"
-                      "- METHOD: OOB method 'pin-e' or 'pin-r', "
-                      "'cred'\n"
-                      "- DEV_NAME: (only for NFC) device name like "
-                      "'pn531'\n");
-               return -1;
-       }
-
-       return wpa_cli_cmd(ctrl, "WPS_OOB", 3, argc, argv);
-}
-#endif /* CONFIG_WPS_OOB */
-
-
 #ifdef CONFIG_WPS_NFC
 
 static int wpa_cli_cmd_wps_nfc(struct wpa_ctrl *ctrl, int argc, char *argv[])
@@ -780,6 +776,72 @@ static int wpa_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc,
        return ret;
 }
 
+
+static int wpa_cli_cmd_nfc_get_handover_req(struct wpa_ctrl *ctrl, int argc,
+                                           char *argv[])
+{
+       return wpa_cli_cmd(ctrl, "NFC_GET_HANDOVER_REQ", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl, int argc,
+                                           char *argv[])
+{
+       return wpa_cli_cmd(ctrl, "NFC_GET_HANDOVER_SEL", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_nfc_rx_handover_req(struct wpa_ctrl *ctrl, int argc,
+                                          char *argv[])
+{
+       int ret;
+       char *buf;
+       size_t buflen;
+
+       if (argc != 1) {
+               printf("Invalid 'nfc_rx_handover_req' command - one argument "
+                      "is required.\n");
+               return -1;
+       }
+
+       buflen = 21 + os_strlen(argv[0]);
+       buf = os_malloc(buflen);
+       if (buf == NULL)
+               return -1;
+       os_snprintf(buf, buflen, "NFC_RX_HANDOVER_REQ %s", argv[0]);
+
+       ret = wpa_ctrl_command(ctrl, buf);
+       os_free(buf);
+
+       return ret;
+}
+
+
+static int wpa_cli_cmd_nfc_rx_handover_sel(struct wpa_ctrl *ctrl, int argc,
+                                          char *argv[])
+{
+       int ret;
+       char *buf;
+       size_t buflen;
+
+       if (argc != 1) {
+               printf("Invalid 'nfc_rx_handover_sel' command - one argument "
+                      "is required.\n");
+               return -1;
+       }
+
+       buflen = 21 + os_strlen(argv[0]);
+       buf = os_malloc(buflen);
+       if (buf == NULL)
+               return -1;
+       os_snprintf(buf, buflen, "NFC_RX_HANDOVER_SEL %s", argv[0]);
+
+       ret = wpa_ctrl_command(ctrl, buf);
+       os_free(buf);
+
+       return ret;
+}
+
 #endif /* CONFIG_WPS_NFC */
 
 
@@ -1288,7 +1350,7 @@ static int wpa_cli_cmd_set_network(struct wpa_ctrl *ctrl, int argc,
                return 0;
        }
 
-       if (argc != 3) {
+       if (argc < 3) {
                printf("Invalid SET_NETWORK command: needs three arguments\n"
                       "(network id, variable name, and value)\n");
                return -1;
@@ -1371,7 +1433,7 @@ static int wpa_cli_cmd_save_config(struct wpa_ctrl *ctrl, int argc,
 
 static int wpa_cli_cmd_scan(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
-       return wpa_ctrl_command(ctrl, "SCAN");
+       return wpa_cli_cmd(ctrl, "SCAN", 0, argc, argv);
 }
 
 
@@ -1613,6 +1675,35 @@ static int wpa_cli_cmd_p2p_find(struct wpa_ctrl *ctrl, int argc, char *argv[])
 }
 
 
+static char ** wpa_cli_complete_p2p_find(const char *str, int pos)
+{
+       char **res = NULL;
+       int arg = get_cmd_arg_num(str, pos);
+
+       res = os_calloc(6, sizeof(char *));
+       if (res == NULL)
+               return NULL;
+       res[0] = os_strdup("type=social");
+       if (res[0] == NULL) {
+               os_free(res);
+               return NULL;
+       }
+       res[1] = os_strdup("type=progressive");
+       if (res[1] == NULL)
+               return res;
+       res[2] = os_strdup("delay=");
+       if (res[2] == NULL)
+               return res;
+       res[3] = os_strdup("dev_id=");
+       if (res[3] == NULL)
+               return res;
+       if (arg == 1)
+               res[4] = os_strdup("[timeout]");
+
+       return res;
+}
+
+
 static int wpa_cli_cmd_p2p_stop_find(struct wpa_ctrl *ctrl, int argc,
                                     char *argv[])
 {
@@ -1969,6 +2060,50 @@ static int wpa_cli_cmd_p2p_ext_listen(struct wpa_ctrl *ctrl, int argc,
 
 #endif /* CONFIG_P2P */
 
+#ifdef CONFIG_WIFI_DISPLAY
+
+static int wpa_cli_cmd_wfd_subelem_set(struct wpa_ctrl *ctrl, int argc,
+                                      char *argv[])
+{
+       char cmd[100];
+       int res;
+
+       if (argc != 1 && argc != 2) {
+               printf("Invalid WFD_SUBELEM_SET command: needs one or two "
+                      "arguments (subelem, hexdump)\n");
+               return -1;
+       }
+
+       res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_SET %s %s",
+                         argv[0], argc > 1 ? argv[1] : "");
+       if (res < 0 || (size_t) res >= sizeof(cmd))
+               return -1;
+       cmd[sizeof(cmd) - 1] = '\0';
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_wfd_subelem_get(struct wpa_ctrl *ctrl, int argc,
+                                      char *argv[])
+{
+       char cmd[100];
+       int res;
+
+       if (argc != 1) {
+               printf("Invalid WFD_SUBELEM_GET command: needs one "
+                      "argument (subelem)\n");
+               return -1;
+       }
+
+       res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_GET %s",
+                         argv[0]);
+       if (res < 0 || (size_t) res >= sizeof(cmd))
+               return -1;
+       cmd[sizeof(cmd) - 1] = '\0';
+       return wpa_ctrl_command(ctrl, cmd);
+}
+#endif /* CONFIG_WIFI_DISPLAY */
+
 
 #ifdef CONFIG_INTERWORKING
 static int wpa_cli_cmd_fetch_anqp(struct wpa_ctrl *ctrl, int argc,
@@ -2003,6 +2138,20 @@ static int wpa_cli_cmd_anqp_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
        return wpa_cli_cmd(ctrl, "ANQP_GET", 2, argc, argv);
 }
+
+
+static int wpa_cli_cmd_gas_request(struct wpa_ctrl *ctrl, int argc,
+                                  char *argv[])
+{
+       return wpa_cli_cmd(ctrl, "GAS_REQUEST", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_gas_response_get(struct wpa_ctrl *ctrl, int argc,
+                                       char *argv[])
+{
+       return wpa_cli_cmd(ctrl, "GAS_RESPONSE_GET", 2, argc, argv);
+}
 #endif /* CONFIG_INTERWORKING */
 
 
@@ -2071,6 +2220,13 @@ static int wpa_cli_cmd_signal_poll(struct wpa_ctrl *ctrl, int argc,
 }
 
 
+static int wpa_cli_cmd_pktcnt_poll(struct wpa_ctrl *ctrl, int argc,
+                                  char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "PKTCNT_POLL");
+}
+
+
 static int wpa_cli_cmd_reauthenticate(struct wpa_ctrl *ctrl, int argc,
                                      char *argv[])
 {
@@ -2091,6 +2247,16 @@ static int wpa_cli_cmd_autoscan(struct wpa_ctrl *ctrl, int argc, char *argv[])
 #endif /* CONFIG_AUTOSCAN */
 
 
+#ifdef CONFIG_WNM
+
+static int wpa_cli_cmd_wnm_sleep(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       return wpa_cli_cmd(ctrl, "WNM_SLEEP", 0, argc, argv);
+}
+
+#endif /* CONFIG_WNM */
+
+
 static int wpa_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
        if (argc == 0)
@@ -2107,398 +2273,439 @@ enum wpa_cli_cmd_flags {
 struct wpa_cli_cmd {
        const char *cmd;
        int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
+       char ** (*completion)(const char *str, int pos);
        enum wpa_cli_cmd_flags flags;
        const char *usage;
 };
 
 static struct wpa_cli_cmd wpa_cli_commands[] = {
-       { "status", wpa_cli_cmd_status,
+       { "status", wpa_cli_cmd_status, NULL,
          cli_cmd_flag_none,
          "[verbose] = get current WPA/EAPOL/EAP status" },
-       { "ifname", wpa_cli_cmd_ifname,
+       { "ifname", wpa_cli_cmd_ifname, NULL,
          cli_cmd_flag_none,
          "= get current interface name" },
-       { "ping", wpa_cli_cmd_ping,
+       { "ping", wpa_cli_cmd_ping, NULL,
          cli_cmd_flag_none,
          "= pings wpa_supplicant" },
-       { "relog", wpa_cli_cmd_relog,
+       { "relog", wpa_cli_cmd_relog, NULL,
          cli_cmd_flag_none,
          "= re-open log-file (allow rolling logs)" },
-       { "note", wpa_cli_cmd_note,
+       { "note", wpa_cli_cmd_note, NULL,
          cli_cmd_flag_none,
          "<text> = add a note to wpa_supplicant debug log" },
-       { "mib", wpa_cli_cmd_mib,
+       { "mib", wpa_cli_cmd_mib, NULL,
          cli_cmd_flag_none,
          "= get MIB variables (dot1x, dot11)" },
-       { "help", wpa_cli_cmd_help,
+       { "help", wpa_cli_cmd_help, wpa_cli_complete_help,
          cli_cmd_flag_none,
-         "= show this usage help" },
-       { "interface", wpa_cli_cmd_interface,
+         "[command] = show usage help" },
+       { "interface", wpa_cli_cmd_interface, NULL,
          cli_cmd_flag_none,
          "[ifname] = show interfaces/select interface" },
-       { "level", wpa_cli_cmd_level,
+       { "level", wpa_cli_cmd_level, NULL,
          cli_cmd_flag_none,
          "<debug level> = change debug level" },
-       { "license", wpa_cli_cmd_license,
+       { "license", wpa_cli_cmd_license, NULL,
          cli_cmd_flag_none,
          "= show full wpa_cli license" },
-       { "quit", wpa_cli_cmd_quit,
+       { "quit", wpa_cli_cmd_quit, NULL,
          cli_cmd_flag_none,
          "= exit wpa_cli" },
-       { "set", wpa_cli_cmd_set,
+       { "set", wpa_cli_cmd_set, NULL,
          cli_cmd_flag_none,
          "= set variables (shows list of variables when run without "
          "arguments)" },
-       { "get", wpa_cli_cmd_get,
+       { "get", wpa_cli_cmd_get, NULL,
          cli_cmd_flag_none,
          "<name> = get information" },
-       { "logon", wpa_cli_cmd_logon,
+       { "logon", wpa_cli_cmd_logon, NULL,
          cli_cmd_flag_none,
          "= IEEE 802.1X EAPOL state machine logon" },
-       { "logoff", wpa_cli_cmd_logoff,
+       { "logoff", wpa_cli_cmd_logoff, NULL,
          cli_cmd_flag_none,
          "= IEEE 802.1X EAPOL state machine logoff" },
-       { "pmksa", wpa_cli_cmd_pmksa,
+       { "pmksa", wpa_cli_cmd_pmksa, NULL,
          cli_cmd_flag_none,
          "= show PMKSA cache" },
-       { "reassociate", wpa_cli_cmd_reassociate,
+       { "reassociate", wpa_cli_cmd_reassociate, NULL,
          cli_cmd_flag_none,
          "= force reassociation" },
-       { "preauthenticate", wpa_cli_cmd_preauthenticate,
+       { "preauthenticate", wpa_cli_cmd_preauthenticate, wpa_cli_complete_bss,
          cli_cmd_flag_none,
          "<BSSID> = force preauthentication" },
-       { "identity", wpa_cli_cmd_identity,
+       { "identity", wpa_cli_cmd_identity, NULL,
          cli_cmd_flag_none,
          "<network id> <identity> = configure identity for an SSID" },
-       { "password", wpa_cli_cmd_password,
+       { "password", wpa_cli_cmd_password, NULL,
          cli_cmd_flag_sensitive,
          "<network id> <password> = configure password for an SSID" },
-       { "new_password", wpa_cli_cmd_new_password,
+       { "new_password", wpa_cli_cmd_new_password, NULL,
          cli_cmd_flag_sensitive,
          "<network id> <password> = change password for an SSID" },
-       { "pin", wpa_cli_cmd_pin,
+       { "pin", wpa_cli_cmd_pin, NULL,
          cli_cmd_flag_sensitive,
          "<network id> <pin> = configure pin for an SSID" },
-       { "otp", wpa_cli_cmd_otp,
+       { "otp", wpa_cli_cmd_otp, NULL,
          cli_cmd_flag_sensitive,
          "<network id> <password> = configure one-time-password for an SSID"
        },
-       { "passphrase", wpa_cli_cmd_passphrase,
+       { "passphrase", wpa_cli_cmd_passphrase, NULL,
          cli_cmd_flag_sensitive,
          "<network id> <passphrase> = configure private key passphrase\n"
          "  for an SSID" },
-       { "bssid", wpa_cli_cmd_bssid,
+       { "bssid", wpa_cli_cmd_bssid, NULL,
          cli_cmd_flag_none,
          "<network id> <BSSID> = set preferred BSSID for an SSID" },
-       { "blacklist", wpa_cli_cmd_blacklist,
+       { "blacklist", wpa_cli_cmd_blacklist, wpa_cli_complete_bss,
          cli_cmd_flag_none,
          "<BSSID> = add a BSSID to the blacklist\n"
          "blacklist clear = clear the blacklist\n"
          "blacklist = display the blacklist" },
-       { "log_level", wpa_cli_cmd_log_level,
+       { "log_level", wpa_cli_cmd_log_level, NULL,
          cli_cmd_flag_none,
          "<level> [<timestamp>] = update the log level/timestamp\n"
          "log_level = display the current log level and log options" },
-       { "list_networks", wpa_cli_cmd_list_networks,
+       { "list_networks", wpa_cli_cmd_list_networks, NULL,
          cli_cmd_flag_none,
          "= list configured networks" },
-       { "select_network", wpa_cli_cmd_select_network,
+       { "select_network", wpa_cli_cmd_select_network, NULL,
          cli_cmd_flag_none,
          "<network id> = select a network (disable others)" },
-       { "enable_network", wpa_cli_cmd_enable_network,
+       { "enable_network", wpa_cli_cmd_enable_network, NULL,
          cli_cmd_flag_none,
          "<network id> = enable a network" },
-       { "disable_network", wpa_cli_cmd_disable_network,
+       { "disable_network", wpa_cli_cmd_disable_network, NULL,
          cli_cmd_flag_none,
          "<network id> = disable a network" },
-       { "add_network", wpa_cli_cmd_add_network,
+       { "add_network", wpa_cli_cmd_add_network, NULL,
          cli_cmd_flag_none,
          "= add a network" },
-       { "remove_network", wpa_cli_cmd_remove_network,
+       { "remove_network", wpa_cli_cmd_remove_network, NULL,
          cli_cmd_flag_none,
          "<network id> = remove a network" },
-       { "set_network", wpa_cli_cmd_set_network,
+       { "set_network", wpa_cli_cmd_set_network, NULL,
          cli_cmd_flag_sensitive,
          "<network id> <variable> <value> = set network variables (shows\n"
          "  list of variables when run without arguments)" },
-       { "get_network", wpa_cli_cmd_get_network,
+       { "get_network", wpa_cli_cmd_get_network, NULL,
          cli_cmd_flag_none,
          "<network id> <variable> = get network variables" },
-       { "list_creds", wpa_cli_cmd_list_creds,
+       { "list_creds", wpa_cli_cmd_list_creds, NULL,
          cli_cmd_flag_none,
          "= list configured credentials" },
-       { "add_cred", wpa_cli_cmd_add_cred,
+       { "add_cred", wpa_cli_cmd_add_cred, NULL,
          cli_cmd_flag_none,
          "= add a credential" },
-       { "remove_cred", wpa_cli_cmd_remove_cred,
+       { "remove_cred", wpa_cli_cmd_remove_cred, NULL,
          cli_cmd_flag_none,
          "<cred id> = remove a credential" },
-       { "set_cred", wpa_cli_cmd_set_cred,
+       { "set_cred", wpa_cli_cmd_set_cred, NULL,
          cli_cmd_flag_sensitive,
          "<cred id> <variable> <value> = set credential variables" },
-       { "save_config", wpa_cli_cmd_save_config,
+       { "save_config", wpa_cli_cmd_save_config, NULL,
          cli_cmd_flag_none,
          "= save the current configuration" },
-       { "disconnect", wpa_cli_cmd_disconnect,
+       { "disconnect", wpa_cli_cmd_disconnect, NULL,
          cli_cmd_flag_none,
          "= disconnect and wait for reassociate/reconnect command before\n"
          "  connecting" },
-       { "reconnect", wpa_cli_cmd_reconnect,
+       { "reconnect", wpa_cli_cmd_reconnect, NULL,
          cli_cmd_flag_none,
          "= like reassociate, but only takes effect if already disconnected"
        },
-       { "scan", wpa_cli_cmd_scan,
+       { "scan", wpa_cli_cmd_scan, NULL,
          cli_cmd_flag_none,
          "= request new BSS scan" },
-       { "scan_results", wpa_cli_cmd_scan_results,
+       { "scan_results", wpa_cli_cmd_scan_results, NULL,
          cli_cmd_flag_none,
          "= get latest scan results" },
-       { "bss", wpa_cli_cmd_bss,
+       { "bss", wpa_cli_cmd_bss, wpa_cli_complete_bss,
          cli_cmd_flag_none,
          "<<idx> | <bssid>> = get detailed scan result info" },
-       { "get_capability", wpa_cli_cmd_get_capability,
+       { "get_capability", wpa_cli_cmd_get_capability, NULL,
          cli_cmd_flag_none,
          "<eap/pairwise/group/key_mgmt/proto/auth_alg/channels> "
          "= get capabilies" },
-       { "reconfigure", wpa_cli_cmd_reconfigure,
+       { "reconfigure", wpa_cli_cmd_reconfigure, NULL,
          cli_cmd_flag_none,
          "= force wpa_supplicant to re-read its configuration file" },
-       { "terminate", wpa_cli_cmd_terminate,
+       { "terminate", wpa_cli_cmd_terminate, NULL,
          cli_cmd_flag_none,
          "= terminate wpa_supplicant" },
-       { "interface_add", wpa_cli_cmd_interface_add,
+       { "interface_add", wpa_cli_cmd_interface_add, NULL,
          cli_cmd_flag_none,
          "<ifname> <confname> <driver> <ctrl_interface> <driver_param>\n"
          "  <bridge_name> = adds new interface, all parameters but <ifname>\n"
          "  are optional" },
-       { "interface_remove", wpa_cli_cmd_interface_remove,
+       { "interface_remove", wpa_cli_cmd_interface_remove, NULL,
          cli_cmd_flag_none,
          "<ifname> = removes the interface" },
-       { "interface_list", wpa_cli_cmd_interface_list,
+       { "interface_list", wpa_cli_cmd_interface_list, NULL,
          cli_cmd_flag_none,
          "= list available interfaces" },
-       { "ap_scan", wpa_cli_cmd_ap_scan,
+       { "ap_scan", wpa_cli_cmd_ap_scan, NULL,
          cli_cmd_flag_none,
          "<value> = set ap_scan parameter" },
-       { "scan_interval", wpa_cli_cmd_scan_interval,
+       { "scan_interval", wpa_cli_cmd_scan_interval, NULL,
          cli_cmd_flag_none,
          "<value> = set scan_interval parameter (in seconds)" },
-       { "bss_expire_age", wpa_cli_cmd_bss_expire_age,
+       { "bss_expire_age", wpa_cli_cmd_bss_expire_age, NULL,
          cli_cmd_flag_none,
          "<value> = set BSS expiration age parameter" },
-       { "bss_expire_count", wpa_cli_cmd_bss_expire_count,
+       { "bss_expire_count", wpa_cli_cmd_bss_expire_count, NULL,
          cli_cmd_flag_none,
          "<value> = set BSS expiration scan count parameter" },
-       { "bss_flush", wpa_cli_cmd_bss_flush,
+       { "bss_flush", wpa_cli_cmd_bss_flush, NULL,
          cli_cmd_flag_none,
          "<value> = set BSS flush age (0 by default)" },
-       { "stkstart", wpa_cli_cmd_stkstart,
+       { "stkstart", wpa_cli_cmd_stkstart, NULL,
          cli_cmd_flag_none,
          "<addr> = request STK negotiation with <addr>" },
-       { "ft_ds", wpa_cli_cmd_ft_ds,
+       { "ft_ds", wpa_cli_cmd_ft_ds, wpa_cli_complete_bss,
          cli_cmd_flag_none,
          "<addr> = request over-the-DS FT with <addr>" },
-       { "wps_pbc", wpa_cli_cmd_wps_pbc,
+       { "wps_pbc", wpa_cli_cmd_wps_pbc, wpa_cli_complete_bss,
          cli_cmd_flag_none,
          "[BSSID] = start Wi-Fi Protected Setup: Push Button Configuration" },
-       { "wps_pin", wpa_cli_cmd_wps_pin,
+       { "wps_pin", wpa_cli_cmd_wps_pin, wpa_cli_complete_bss,
          cli_cmd_flag_sensitive,
          "<BSSID> [PIN] = start WPS PIN method (returns PIN, if not "
          "hardcoded)" },
-       { "wps_check_pin", wpa_cli_cmd_wps_check_pin,
+       { "wps_check_pin", wpa_cli_cmd_wps_check_pin, NULL,
          cli_cmd_flag_sensitive,
          "<PIN> = verify PIN checksum" },
-       { "wps_cancel", wpa_cli_cmd_wps_cancel, cli_cmd_flag_none,
+       { "wps_cancel", wpa_cli_cmd_wps_cancel, NULL, cli_cmd_flag_none,
          "Cancels the pending WPS operation" },
-#ifdef CONFIG_WPS_OOB
-       { "wps_oob", wpa_cli_cmd_wps_oob,
-         cli_cmd_flag_sensitive,
-         "<DEV_TYPE> <PATH> <METHOD> [DEV_NAME] = start WPS OOB" },
-#endif /* CONFIG_WPS_OOB */
 #ifdef CONFIG_WPS_NFC
-       { "wps_nfc", wpa_cli_cmd_wps_nfc,
+       { "wps_nfc", wpa_cli_cmd_wps_nfc, wpa_cli_complete_bss,
          cli_cmd_flag_none,
          "[BSSID] = start Wi-Fi Protected Setup: NFC" },
-       { "wps_nfc_token", wpa_cli_cmd_wps_nfc_token,
+       { "wps_nfc_token", wpa_cli_cmd_wps_nfc_token, NULL,
          cli_cmd_flag_none,
          "<WPS|NDEF> = create password token" },
-       { "wps_nfc_tag_read", wpa_cli_cmd_wps_nfc_tag_read,
+       { "wps_nfc_tag_read", wpa_cli_cmd_wps_nfc_tag_read, NULL,
          cli_cmd_flag_sensitive,
          "<hexdump of payload> = report read NFC tag with WPS data" },
+       { "nfc_get_handover_req", wpa_cli_cmd_nfc_get_handover_req, NULL,
+         cli_cmd_flag_none,
+         "<NDEF> <WPS> = create NFC handover request" },
+       { "nfc_get_handover_sel", wpa_cli_cmd_nfc_get_handover_sel, NULL,
+         cli_cmd_flag_none,
+         "<NDEF> <WPS> = create NFC handover select" },
+       { "nfc_rx_handover_req", wpa_cli_cmd_nfc_rx_handover_req, NULL,
+         cli_cmd_flag_none,
+         "<hexdump of payload> = report received NFC handover request" },
+       { "nfc_rx_handover_sel", wpa_cli_cmd_nfc_rx_handover_sel, NULL,
+         cli_cmd_flag_none,
+         "<hexdump of payload> = report received NFC handover select" },
 #endif /* CONFIG_WPS_NFC */
-       { "wps_reg", wpa_cli_cmd_wps_reg,
+       { "wps_reg", wpa_cli_cmd_wps_reg, wpa_cli_complete_bss,
          cli_cmd_flag_sensitive,
          "<BSSID> <AP PIN> = start WPS Registrar to configure an AP" },
-       { "wps_ap_pin", wpa_cli_cmd_wps_ap_pin,
+       { "wps_ap_pin", wpa_cli_cmd_wps_ap_pin, NULL,
          cli_cmd_flag_sensitive,
          "[params..] = enable/disable AP PIN" },
-       { "wps_er_start", wpa_cli_cmd_wps_er_start,
+       { "wps_er_start", wpa_cli_cmd_wps_er_start, NULL,
          cli_cmd_flag_none,
          "[IP address] = start Wi-Fi Protected Setup External Registrar" },
-       { "wps_er_stop", wpa_cli_cmd_wps_er_stop,
+       { "wps_er_stop", wpa_cli_cmd_wps_er_stop, NULL,
          cli_cmd_flag_none,
          "= stop Wi-Fi Protected Setup External Registrar" },
-       { "wps_er_pin", wpa_cli_cmd_wps_er_pin,
+       { "wps_er_pin", wpa_cli_cmd_wps_er_pin, NULL,
          cli_cmd_flag_sensitive,
          "<UUID> <PIN> = add an Enrollee PIN to External Registrar" },
-       { "wps_er_pbc", wpa_cli_cmd_wps_er_pbc,
+       { "wps_er_pbc", wpa_cli_cmd_wps_er_pbc, NULL,
          cli_cmd_flag_none,
          "<UUID> = accept an Enrollee PBC using External Registrar" },
-       { "wps_er_learn", wpa_cli_cmd_wps_er_learn,
+       { "wps_er_learn", wpa_cli_cmd_wps_er_learn, NULL,
          cli_cmd_flag_sensitive,
          "<UUID> <PIN> = learn AP configuration" },
-       { "wps_er_set_config", wpa_cli_cmd_wps_er_set_config,
+       { "wps_er_set_config", wpa_cli_cmd_wps_er_set_config, NULL,
          cli_cmd_flag_none,
          "<UUID> <network id> = set AP configuration for enrolling" },
-       { "wps_er_config", wpa_cli_cmd_wps_er_config,
+       { "wps_er_config", wpa_cli_cmd_wps_er_config, NULL,
          cli_cmd_flag_sensitive,
          "<UUID> <PIN> <SSID> <auth> <encr> <key> = configure AP" },
 #ifdef CONFIG_WPS_NFC
-       { "wps_er_nfc_config_token", wpa_cli_cmd_wps_er_nfc_config_token,
+       { "wps_er_nfc_config_token", wpa_cli_cmd_wps_er_nfc_config_token, NULL,
          cli_cmd_flag_none,
          "<WPS/NDEF> <UUID> = build NFC configuration token" },
 #endif /* CONFIG_WPS_NFC */
-       { "ibss_rsn", wpa_cli_cmd_ibss_rsn,
+       { "ibss_rsn", wpa_cli_cmd_ibss_rsn, NULL,
          cli_cmd_flag_none,
          "<addr> = request RSN authentication with <addr> in IBSS" },
 #ifdef CONFIG_AP
-       { "sta", wpa_cli_cmd_sta,
+       { "sta", wpa_cli_cmd_sta, NULL,
          cli_cmd_flag_none,
          "<addr> = get information about an associated station (AP)" },
-       { "all_sta", wpa_cli_cmd_all_sta,
+       { "all_sta", wpa_cli_cmd_all_sta, NULL,
          cli_cmd_flag_none,
          "= get information about all associated stations (AP)" },
-       { "deauthenticate", wpa_cli_cmd_deauthenticate,
+       { "deauthenticate", wpa_cli_cmd_deauthenticate, NULL,
          cli_cmd_flag_none,
          "<addr> = deauthenticate a station" },
-       { "disassociate", wpa_cli_cmd_disassociate,
+       { "disassociate", wpa_cli_cmd_disassociate, NULL,
          cli_cmd_flag_none,
          "<addr> = disassociate a station" },
 #endif /* CONFIG_AP */
-       { "suspend", wpa_cli_cmd_suspend, cli_cmd_flag_none,
+       { "suspend", wpa_cli_cmd_suspend, NULL, cli_cmd_flag_none,
          "= notification of suspend/hibernate" },
-       { "resume", wpa_cli_cmd_resume, cli_cmd_flag_none,
+       { "resume", wpa_cli_cmd_resume, NULL, cli_cmd_flag_none,
          "= notification of resume/thaw" },
-       { "drop_sa", wpa_cli_cmd_drop_sa, cli_cmd_flag_none,
+       { "drop_sa", wpa_cli_cmd_drop_sa, NULL, cli_cmd_flag_none,
          "= drop SA without deauth/disassoc (test command)" },
-       { "roam", wpa_cli_cmd_roam,
+       { "roam", wpa_cli_cmd_roam, wpa_cli_complete_bss,
          cli_cmd_flag_none,
          "<addr> = roam to the specified BSS" },
 #ifdef CONFIG_P2P
-       { "p2p_find", wpa_cli_cmd_p2p_find, cli_cmd_flag_none,
+       { "p2p_find", wpa_cli_cmd_p2p_find, wpa_cli_complete_p2p_find,
+         cli_cmd_flag_none,
          "[timeout] [type=*] = find P2P Devices for up-to timeout seconds" },
-       { "p2p_stop_find", wpa_cli_cmd_p2p_stop_find, cli_cmd_flag_none,
+       { "p2p_stop_find", wpa_cli_cmd_p2p_stop_find, NULL, cli_cmd_flag_none,
          "= stop P2P Devices search" },
-       { "p2p_connect", wpa_cli_cmd_p2p_connect, cli_cmd_flag_none,
+       { "p2p_connect", wpa_cli_cmd_p2p_connect, wpa_cli_complete_p2p_connect,
+         cli_cmd_flag_none,
          "<addr> <\"pbc\"|PIN> [ht40] = connect to a P2P Device" },
-       { "p2p_listen", wpa_cli_cmd_p2p_listen, cli_cmd_flag_none,
+       { "p2p_listen", wpa_cli_cmd_p2p_listen, NULL, cli_cmd_flag_none,
          "[timeout] = listen for P2P Devices for up-to timeout seconds" },
-       { "p2p_group_remove", wpa_cli_cmd_p2p_group_remove, cli_cmd_flag_none,
+       { "p2p_group_remove", wpa_cli_cmd_p2p_group_remove,
+         wpa_cli_complete_p2p_group_remove, cli_cmd_flag_none,
          "<ifname> = remove P2P group interface (terminate group if GO)" },
-       { "p2p_group_add", wpa_cli_cmd_p2p_group_add, cli_cmd_flag_none,
+       { "p2p_group_add", wpa_cli_cmd_p2p_group_add, NULL, cli_cmd_flag_none,
          "[ht40] = add a new P2P group (local end as GO)" },
-       { "p2p_prov_disc", wpa_cli_cmd_p2p_prov_disc, cli_cmd_flag_none,
+       { "p2p_prov_disc", wpa_cli_cmd_p2p_prov_disc,
+         wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
          "<addr> <method> = request provisioning discovery" },
-       { "p2p_get_passphrase", wpa_cli_cmd_p2p_get_passphrase,
+       { "p2p_get_passphrase", wpa_cli_cmd_p2p_get_passphrase, NULL,
          cli_cmd_flag_none,
          "= get the passphrase for a group (GO only)" },
        { "p2p_serv_disc_req", wpa_cli_cmd_p2p_serv_disc_req,
-         cli_cmd_flag_none,
+         wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
          "<addr> <TLVs> = schedule service discovery request" },
        { "p2p_serv_disc_cancel_req", wpa_cli_cmd_p2p_serv_disc_cancel_req,
-         cli_cmd_flag_none,
+         NULL, cli_cmd_flag_none,
          "<id> = cancel pending service discovery request" },
-       { "p2p_serv_disc_resp", wpa_cli_cmd_p2p_serv_disc_resp,
+       { "p2p_serv_disc_resp", wpa_cli_cmd_p2p_serv_disc_resp, NULL,
          cli_cmd_flag_none,
          "<freq> <addr> <dialog token> <TLVs> = service discovery response" },
-       { "p2p_service_update", wpa_cli_cmd_p2p_service_update,
+       { "p2p_service_update", wpa_cli_cmd_p2p_service_update, NULL,
          cli_cmd_flag_none,
          "= indicate change in local services" },
-       { "p2p_serv_disc_external", wpa_cli_cmd_p2p_serv_disc_external,
+       { "p2p_serv_disc_external", wpa_cli_cmd_p2p_serv_disc_external, NULL,
          cli_cmd_flag_none,
          "<external> = set external processing of service discovery" },
-       { "p2p_service_flush", wpa_cli_cmd_p2p_service_flush,
+       { "p2p_service_flush", wpa_cli_cmd_p2p_service_flush, NULL,
          cli_cmd_flag_none,
          "= remove all stored service entries" },
-       { "p2p_service_add", wpa_cli_cmd_p2p_service_add,
+       { "p2p_service_add", wpa_cli_cmd_p2p_service_add, NULL,
          cli_cmd_flag_none,
          "<bonjour|upnp> <query|version> <response|service> = add a local "
          "service" },
-       { "p2p_service_del", wpa_cli_cmd_p2p_service_del,
+       { "p2p_service_del", wpa_cli_cmd_p2p_service_del, NULL,
          cli_cmd_flag_none,
          "<bonjour|upnp> <query|version> [|service] = remove a local "
          "service" },
-       { "p2p_reject", wpa_cli_cmd_p2p_reject,
+       { "p2p_reject", wpa_cli_cmd_p2p_reject, wpa_cli_complete_p2p_peer,
          cli_cmd_flag_none,
          "<addr> = reject connection attempts from a specific peer" },
-       { "p2p_invite", wpa_cli_cmd_p2p_invite,
+       { "p2p_invite", wpa_cli_cmd_p2p_invite, NULL,
          cli_cmd_flag_none,
          "<cmd> [peer=addr] = invite peer" },
-       { "p2p_peers", wpa_cli_cmd_p2p_peers, cli_cmd_flag_none,
+       { "p2p_peers", wpa_cli_cmd_p2p_peers, NULL, cli_cmd_flag_none,
          "[discovered] = list known (optionally, only fully discovered) P2P "
          "peers" },
-       { "p2p_peer", wpa_cli_cmd_p2p_peer, cli_cmd_flag_none,
+       { "p2p_peer", wpa_cli_cmd_p2p_peer, wpa_cli_complete_p2p_peer,
+         cli_cmd_flag_none,
          "<address> = show information about known P2P peer" },
-       { "p2p_set", wpa_cli_cmd_p2p_set, cli_cmd_flag_none,
+       { "p2p_set", wpa_cli_cmd_p2p_set, NULL, cli_cmd_flag_none,
          "<field> <value> = set a P2P parameter" },
-       { "p2p_flush", wpa_cli_cmd_p2p_flush, cli_cmd_flag_none,
+       { "p2p_flush", wpa_cli_cmd_p2p_flush, NULL, cli_cmd_flag_none,
          "= flush P2P state" },
-       { "p2p_cancel", wpa_cli_cmd_p2p_cancel, cli_cmd_flag_none,
+       { "p2p_cancel", wpa_cli_cmd_p2p_cancel, NULL, cli_cmd_flag_none,
          "= cancel P2P group formation" },
-       { "p2p_unauthorize", wpa_cli_cmd_p2p_unauthorize, cli_cmd_flag_none,
+       { "p2p_unauthorize", wpa_cli_cmd_p2p_unauthorize,
+         wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
          "<address> = unauthorize a peer" },
-       { "p2p_presence_req", wpa_cli_cmd_p2p_presence_req, cli_cmd_flag_none,
+       { "p2p_presence_req", wpa_cli_cmd_p2p_presence_req, NULL,
+         cli_cmd_flag_none,
          "[<duration> <interval>] [<duration> <interval>] = request GO "
          "presence" },
-       { "p2p_ext_listen", wpa_cli_cmd_p2p_ext_listen, cli_cmd_flag_none,
+       { "p2p_ext_listen", wpa_cli_cmd_p2p_ext_listen, NULL,
+         cli_cmd_flag_none,
          "[<period> <interval>] = set extended listen timing" },
 #endif /* CONFIG_P2P */
-
+#ifdef CONFIG_WIFI_DISPLAY
+       { "wfd_subelem_set", wpa_cli_cmd_wfd_subelem_set, NULL,
+         cli_cmd_flag_none,
+         "<subelem> [contents] = set Wi-Fi Display subelement" },
+       { "wfd_subelem_get", wpa_cli_cmd_wfd_subelem_get, NULL,
+         cli_cmd_flag_none,
+         "<subelem> = get Wi-Fi Display subelement" },
+#endif /* CONFIG_WIFI_DISPLAY */
 #ifdef CONFIG_INTERWORKING
-       { "fetch_anqp", wpa_cli_cmd_fetch_anqp, cli_cmd_flag_none,
+       { "fetch_anqp", wpa_cli_cmd_fetch_anqp, NULL, cli_cmd_flag_none,
          "= fetch ANQP information for all APs" },
-       { "stop_fetch_anqp", wpa_cli_cmd_stop_fetch_anqp, cli_cmd_flag_none,
+       { "stop_fetch_anqp", wpa_cli_cmd_stop_fetch_anqp, NULL,
+         cli_cmd_flag_none,
          "= stop fetch_anqp operation" },
-       { "interworking_select", wpa_cli_cmd_interworking_select,
+       { "interworking_select", wpa_cli_cmd_interworking_select, NULL,
          cli_cmd_flag_none,
          "[auto] = perform Interworking network selection" },
        { "interworking_connect", wpa_cli_cmd_interworking_connect,
-         cli_cmd_flag_none,
+         wpa_cli_complete_bss, cli_cmd_flag_none,
          "<BSSID> = connect using Interworking credentials" },
-       { "anqp_get", wpa_cli_cmd_anqp_get, cli_cmd_flag_none,
+       { "anqp_get", wpa_cli_cmd_anqp_get, wpa_cli_complete_bss,
+         cli_cmd_flag_none,
          "<addr> <info id>[,<info id>]... = request ANQP information" },
+       { "gas_request", wpa_cli_cmd_gas_request, wpa_cli_complete_bss,
+         cli_cmd_flag_none,
+         "<addr> <AdvProtoID> [QueryReq] = GAS request" },
+       { "gas_response_get", wpa_cli_cmd_gas_response_get,
+         wpa_cli_complete_bss, cli_cmd_flag_none,
+         "<addr> <dialog token> [start,len] = Fetch last GAS response" },
 #endif /* CONFIG_INTERWORKING */
 #ifdef CONFIG_HS20
-       { "hs20_anqp_get", wpa_cli_cmd_hs20_anqp_get, cli_cmd_flag_none,
+       { "hs20_anqp_get", wpa_cli_cmd_hs20_anqp_get, wpa_cli_complete_bss,
+         cli_cmd_flag_none,
          "<addr> <subtype>[,<subtype>]... = request HS 2.0 ANQP information"
        },
        { "nai_home_realm_list", wpa_cli_cmd_get_nai_home_realm_list,
-         cli_cmd_flag_none,
+         wpa_cli_complete_bss, cli_cmd_flag_none,
          "<addr> <home realm> = get HS20 nai home realm list" },
 #endif /* CONFIG_HS20 */
-       { "sta_autoconnect", wpa_cli_cmd_sta_autoconnect, cli_cmd_flag_none,
+       { "sta_autoconnect", wpa_cli_cmd_sta_autoconnect, NULL,
+         cli_cmd_flag_none,
          "<0/1> = disable/enable automatic reconnection" },
-       { "tdls_discover", wpa_cli_cmd_tdls_discover,
+       { "tdls_discover", wpa_cli_cmd_tdls_discover, NULL,
          cli_cmd_flag_none,
          "<addr> = request TDLS discovery with <addr>" },
-       { "tdls_setup", wpa_cli_cmd_tdls_setup,
+       { "tdls_setup", wpa_cli_cmd_tdls_setup, NULL,
          cli_cmd_flag_none,
          "<addr> = request TDLS setup with <addr>" },
-       { "tdls_teardown", wpa_cli_cmd_tdls_teardown,
+       { "tdls_teardown", wpa_cli_cmd_tdls_teardown, NULL,
          cli_cmd_flag_none,
          "<addr> = tear down TDLS with <addr>" },
-       { "signal_poll", wpa_cli_cmd_signal_poll,
+       { "signal_poll", wpa_cli_cmd_signal_poll, NULL,
          cli_cmd_flag_none,
          "= get signal parameters" },
-       { "reauthenticate", wpa_cli_cmd_reauthenticate, cli_cmd_flag_none,
+       { "pktcnt_poll", wpa_cli_cmd_pktcnt_poll, NULL,
+         cli_cmd_flag_none,
+         "= get TX/RX packet counters" },
+       { "reauthenticate", wpa_cli_cmd_reauthenticate, NULL,
+         cli_cmd_flag_none,
          "= trigger IEEE 802.1X/EAPOL reauthentication" },
 #ifdef CONFIG_AUTOSCAN
-       { "autoscan", wpa_cli_cmd_autoscan, cli_cmd_flag_none,
+       { "autoscan", wpa_cli_cmd_autoscan, NULL, cli_cmd_flag_none,
          "[params] = Set or unset (if none) autoscan parameters" },
 #endif /* CONFIG_AUTOSCAN */
-       { "raw", wpa_cli_cmd_raw, cli_cmd_flag_sensitive,
+#ifdef CONFIG_WNM
+       { "wnm_sleep", wpa_cli_cmd_wnm_sleep, NULL, cli_cmd_flag_none,
+         "<enter/exit> [interval=#] = enter/exit WNM-Sleep mode" },
+#endif /* CONFIG_WNM */
+       { "raw", wpa_cli_cmd_raw, NULL, cli_cmd_flag_sensitive,
          "<params..> = Sent unprocessed command" },
-       { NULL, NULL, cli_cmd_flag_none, NULL }
+       { NULL, NULL, NULL, cli_cmd_flag_none, NULL }
 };
 
 
@@ -2520,12 +2727,14 @@ static void print_cmd_help(struct wpa_cli_cmd *cmd, const char *pad)
 }
 
 
-static void print_help(void)
+static void print_help(const char *cmd)
 {
        int n;
        printf("commands:\n");
-       for (n = 0; wpa_cli_commands[n].cmd; n++)
-               print_cmd_help(&wpa_cli_commands[n], "  ");
+       for (n = 0; wpa_cli_commands[n].cmd; n++) {
+               if (cmd == NULL || str_starts(wpa_cli_commands[n].cmd, cmd))
+                       print_cmd_help(&wpa_cli_commands[n], "  ");
+       }
 }
 
 
@@ -2575,19 +2784,11 @@ static char ** wpa_cli_cmd_completion(const char *cmd, const char *str,
 {
        int i;
 
-       if (os_strcasecmp(cmd, "bss") == 0)
-               return wpa_cli_complete_bss(str, pos);
-#ifdef CONFIG_P2P
-       if (os_strcasecmp(cmd, "p2p_connect") == 0)
-               return wpa_cli_complete_p2p_connect(str, pos);
-       if (os_strcasecmp(cmd, "p2p_peer") == 0)
-               return wpa_cli_complete_p2p_peer(str, pos);
-       if (os_strcasecmp(cmd, "p2p_group_remove") == 0)
-               return wpa_cli_complete_p2p_group_remove(str, pos);
-#endif /* CONFIG_P2P */
-
        for (i = 0; wpa_cli_commands[i].cmd; i++) {
                if (os_strcasecmp(wpa_cli_commands[i].cmd, cmd) == 0) {
+                       if (wpa_cli_commands[i].completion)
+                               return wpa_cli_commands[i].completion(str,
+                                                                     pos);
                        edit_clear_line();
                        printf("\r%s\n", wpa_cli_commands[i].usage);
                        edit_redraw();