wpa_cli: Implement completion routine for get_network/set_network
[mech_eap.git] / wpa_supplicant / wpa_cli.c
index 911effe..a161536 100644 (file)
@@ -92,6 +92,7 @@ static DEFINE_DL_LIST(bsses); /* struct cli_txt_entry */
 static DEFINE_DL_LIST(p2p_peers); /* struct cli_txt_entry */
 static DEFINE_DL_LIST(p2p_groups); /* struct cli_txt_entry */
 static DEFINE_DL_LIST(ifnames); /* struct cli_txt_entry */
+static DEFINE_DL_LIST(networks); /* struct cli_txt_entry */
 
 
 static void print_help(const char *cmd);
@@ -99,6 +100,7 @@ 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 update_networks(struct wpa_ctrl *ctrl);
 
 
 static void usage(void)
@@ -174,6 +176,8 @@ static void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt)
        char *buf;
        end = os_strchr(txt, ' ');
        if (end == NULL)
+               end = os_strchr(txt, '\t');
+       if (end == NULL)
                end = txt + os_strlen(txt);
        buf = dup_binstr(txt, end - txt);
        if (buf == NULL)
@@ -213,6 +217,7 @@ static int cli_txt_list_add_addr(struct dl_list *txt_list, const char *txt)
        os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
        return cli_txt_list_add(txt_list, buf);
 }
+#endif /* CONFIG_P2P */
 
 
 static int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt)
@@ -222,6 +227,8 @@ static int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt)
        int ret;
        end = os_strchr(txt, ' ');
        if (end == NULL)
+               end = os_strchr(txt, '\t');
+       if (end == NULL)
                end = txt + os_strlen(txt);
        buf = dup_binstr(txt, end - txt);
        if (buf == NULL)
@@ -230,7 +237,6 @@ static int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt)
        os_free(buf);
        return ret;
 }
-#endif /* CONFIG_P2P */
 
 
 static char ** cli_txt_list_array(struct dl_list *txt_list)
@@ -608,35 +614,57 @@ static char ** wpa_cli_complete_set(const char *str, int pos)
                "uapsd", "ps", "wifi_display", "bssid_filter", "disallow_aps",
                "no_keep_alive",
                /* global configuration parameters */
-               "eapol_version", "ap_scan", "disable_scan_offload",
-               "fast_reauth", "opensc_engine_path", "pkcs11_engine_path",
-               "pkcs11_module_path", "openssl_ciphers",
-               "pcsc_reader", "pcsc_pin",
-               "driver_param", "dot11RSNAConfigPMKLifetime",
+#ifdef CONFIG_CTRL_IFACE
+               "ctrl_interface", "no_ctrl_interface", "ctrl_interface_group",
+#endif /* CONFIG_CTRL_IFACE */
+               "eapol_version", "ap_scan", "bgscan",
+#ifdef CONFIG_MESH
+               "user_mpm", "max_peer_links", "mesh_max_inactivity",
+#endif /* CONFIG_MESH */
+               "disable_scan_offload", "fast_reauth", "opensc_engine_path",
+               "pkcs11_engine_path", "pkcs11_module_path", "openssl_ciphers",
+               "pcsc_reader", "pcsc_pin", "external_sim", "driver_param",
+               "dot11RSNAConfigPMKLifetime",
                "dot11RSNAConfigPMKReauthThreshold",
                "dot11RSNAConfigSATimeout",
-               "update_config", "load_dynamic_eap", "uuid", "device_name",
-               "manufacturer", "model_name", "model_number", "serial_number",
-               "device_type", "os_version", "config_methods",
-               "wps_cred_processing", "wps_vendor_ext_m1", "sec_device_type",
+#ifndef CONFIG_NO_CONFIG_WRITE
+               "update_config",
+#endif /* CONFIG_NO_CONFIG_WRITE */
+               "load_dynamic_eap",
+#ifdef CONFIG_WPS
+               "uuid", "device_name", "manufacturer", "model_name",
+               "model_number", "serial_number", "device_type", "os_version",
+               "config_methods", "wps_cred_processing", "wps_vendor_ext_m1",
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+               "sec_device_type",
                "p2p_listen_reg_class", "p2p_listen_channel",
-               "p2p_oper_reg_class", "p2p_oper_channel",
-               "p2p_go_intent", "p2p_ssid_postfix", "persistent_reconnect",
-               "p2p_intra_bss", "p2p_group_idle", "p2p_pref_chan",
-               "p2p_no_go_freq",
-               "p2p_go_ht40", "p2p_disabled", "p2p_no_group_iface",
-               "p2p_go_vht",
-               "p2p_ignore_shared_freq", "country", "bss_max_count",
-               "bss_expiration_age", "bss_expiration_scan_count",
-               "filter_ssids", "filter_rssi", "max_num_sta",
-               "disassoc_low_ack", "hs20", "interworking", "hessid",
-               "access_network_type", "pbc_in_m1", "autoscan",
-               "wps_nfc_dev_pw_id", "wps_nfc_dh_pubkey", "wps_nfc_dh_privkey",
-               "wps_nfc_dev_pw", "ext_password_backend",
+               "p2p_oper_reg_class", "p2p_oper_channel", "p2p_go_intent",
+               "p2p_ssid_postfix", "persistent_reconnect", "p2p_intra_bss",
+               "p2p_group_idle", "p2p_passphrase_len", "p2p_pref_chan",
+               "p2p_no_go_freq", "p2p_add_cli_chan",
+               "p2p_optimize_listen_chan", "p2p_go_ht40", "p2p_go_vht",
+               "p2p_disabled", "p2p_go_ctwindow", "p2p_no_group_iface",
+               "p2p_ignore_shared_freq", "ip_addr_go", "ip_addr_mask",
+               "ip_addr_start", "ip_addr_end",
+#endif /* CONFIG_P2P */
+               "country", "bss_max_count", "bss_expiration_age",
+               "bss_expiration_scan_count", "filter_ssids", "filter_rssi",
+               "max_num_sta", "disassoc_low_ack",
+#ifdef CONFIG_HS20
+               "hs20",
+#endif /* CONFIG_HS20 */
+               "interworking", "hessid", "access_network_type", "pbc_in_m1",
+               "autoscan", "wps_nfc_dev_pw_id", "wps_nfc_dh_pubkey",
+               "wps_nfc_dh_privkey", "wps_nfc_dev_pw", "ext_password_backend",
                "p2p_go_max_inactivity", "auto_interworking", "okc", "pmf",
-               "sae_groups", "dtim_period", "beacon_int", "ap_vendor_elements",
-               "ignore_old_scan_res", "freq_list", "external_sim",
-               "tdls_external_control", "p2p_search_delay"
+               "sae_groups", "dtim_period", "beacon_int",
+               "ap_vendor_elements", "ignore_old_scan_res", "freq_list",
+               "scan_cur_freq", "sched_scan_interval",
+               "tdls_external_control", "osu_dir", "wowlan_triggers",
+               "p2p_search_delay", "mac_addr", "rand_addr_lifetime",
+               "preassoc_mac_addr", "key_mgmt_offload", "passive_scan",
+               "reassoc_same_bss_optim"
        };
        int i, num_fields = ARRAY_SIZE(fields);
 
@@ -658,6 +686,11 @@ static char ** wpa_cli_complete_set(const char *str, int pos)
        return NULL;
 }
 
+static int wpa_cli_cmd_dump(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "DUMP");
+}
+
 
 static int wpa_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
@@ -665,6 +698,74 @@ static int wpa_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
 }
 
 
+static char ** wpa_cli_complete_get(const char *str, int pos)
+{
+       int arg = get_cmd_arg_num(str, pos);
+       const char *fields[] = {
+#ifdef CONFIG_CTRL_IFACE
+               "ctrl_interface", "ctrl_interface_group",
+#endif /* CONFIG_CTRL_IFACE */
+               "eapol_version", "ap_scan",
+#ifdef CONFIG_MESH
+               "user_mpm", "max_peer_links", "mesh_max_inactivity",
+#endif /* CONFIG_MESH */
+               "disable_scan_offload", "fast_reauth", "opensc_engine_path",
+               "pkcs11_engine_path", "pkcs11_module_path", "openssl_ciphers",
+               "pcsc_reader", "pcsc_pin", "external_sim", "driver_param",
+               "dot11RSNAConfigPMKLifetime",
+               "dot11RSNAConfigPMKReauthThreshold",
+               "dot11RSNAConfigSATimeout",
+#ifndef CONFIG_NO_CONFIG_WRITE
+               "update_config",
+#endif /* CONFIG_NO_CONFIG_WRITE */
+#ifdef CONFIG_WPS
+               "device_name", "manufacturer", "model_name", "model_number",
+               "serial_number", "config_methods", "wps_cred_processing",
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+               "p2p_listen_reg_class", "p2p_listen_channel",
+               "p2p_oper_reg_class", "p2p_oper_channel", "p2p_go_intent",
+               "p2p_ssid_postfix", "persistent_reconnect", "p2p_intra_bss",
+               "p2p_group_idle", "p2p_passphrase_len", "p2p_add_cli_chan",
+               "p2p_optimize_listen_chan", "p2p_go_ht40", "p2p_go_vht",
+               "p2p_disabled", "p2p_go_ctwindow", "p2p_no_group_iface",
+               "p2p_ignore_shared_freq", "ip_addr_go", "ip_addr_mask",
+               "ip_addr_start", "ip_addr_end",
+#endif /* CONFIG_P2P */
+               "bss_max_count", "bss_expiration_age",
+               "bss_expiration_scan_count", "filter_ssids", "filter_rssi",
+               "max_num_sta", "disassoc_low_ack",
+#ifdef CONFIG_HS20
+               "hs20",
+#endif /* CONFIG_HS20 */
+               "interworking", "access_network_type", "pbc_in_m1", "autoscan",
+               "wps_nfc_dev_pw_id", "ext_password_backend",
+               "p2p_go_max_inactivity", "auto_interworking", "okc", "pmf",
+               "dtim_period", "beacon_int", "ignore_old_scan_res",
+               "scan_cur_freq", "sched_scan_interval",
+               "tdls_external_control", "osu_dir", "wowlan_triggers",
+               "p2p_search_delay", "mac_addr", "rand_addr_lifetime",
+               "preassoc_mac_addr", "key_mgmt_offload", "passive_scan",
+               "reassoc_same_bss_optim"
+       };
+       int i, num_fields = ARRAY_SIZE(fields);
+
+       if (arg == 1) {
+               char **res = os_calloc(num_fields + 1, sizeof(char *));
+               if (res == NULL)
+                       return NULL;
+               for (i = 0; i < num_fields; i++) {
+                       res[i] = os_strdup(fields[i]);
+                       if (res[i] == NULL)
+                               return res;
+               }
+               return res;
+       }
+
+       return NULL;
+}
+
+
 static int wpa_cli_cmd_logoff(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
        return wpa_ctrl_command(ctrl, "LOGOFF");
@@ -1356,14 +1457,18 @@ static int wpa_cli_cmd_disable_network(struct wpa_ctrl *ctrl, int argc,
 static int wpa_cli_cmd_add_network(struct wpa_ctrl *ctrl, int argc,
                                   char *argv[])
 {
-       return wpa_ctrl_command(ctrl, "ADD_NETWORK");
+       int res = wpa_ctrl_command(ctrl, "ADD_NETWORK");
+       update_networks(ctrl);
+       return res;
 }
 
 
 static int wpa_cli_cmd_remove_network(struct wpa_ctrl *ctrl, int argc,
                                      char *argv[])
 {
-       return wpa_cli_cmd(ctrl, "REMOVE_NETWORK", 1, argc, argv);
+       int res = wpa_cli_cmd(ctrl, "REMOVE_NETWORK", 1, argc, argv);
+       update_networks(ctrl);
+       return res;
 }
 
 
@@ -1424,6 +1529,96 @@ static int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc,
 }
 
 
+static const char *network_fields[] = {
+       "ssid", "scan_ssid", "bssid", "bssid_blacklist",
+       "bssid_whitelist", "psk", "proto", "key_mgmt",
+       "bg_scan_period", "pairwise", "group", "auth_alg", "scan_freq",
+       "freq_list",
+#ifdef IEEE8021X_EAPOL
+       "eap", "identity", "anonymous_identity", "password", "ca_cert",
+       "ca_path", "client_cert", "private_key", "private_key_passwd",
+       "dh_file", "subject_match", "altsubject_match",
+       "domain_suffix_match", "domain_match", "ca_cert2", "ca_path2",
+       "client_cert2", "private_key2", "private_key2_passwd",
+       "dh_file2", "subject_match2", "altsubject_match2",
+       "domain_suffix_match2", "domain_match2", "phase1", "phase2",
+       "pcsc", "pin", "engine_id", "key_id", "cert_id", "ca_cert_id",
+       "pin2", "engine2_id", "key2_id", "cert2_id", "ca_cert2_id",
+       "engine", "engine2", "eapol_flags", "sim_num",
+       "openssl_ciphers", "erp",
+#endif /* IEEE8021X_EAPOL */
+       "wep_key0", "wep_key1", "wep_key2", "wep_key3",
+       "wep_tx_keyidx", "priority",
+#ifdef IEEE8021X_EAPOL
+       "eap_workaround", "pac_file", "fragment_size", "ocsp",
+#endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_MESH
+       "mode", "no_auto_peer",
+#else /* CONFIG_MESH */
+       "mode",
+#endif /* CONFIG_MESH */
+       "proactive_key_caching", "disabled", "id_str",
+#ifdef CONFIG_IEEE80211W
+       "ieee80211w",
+#endif /* CONFIG_IEEE80211W */
+       "peerkey", "mixed_cell", "frequency", "fixed_freq",
+#ifdef CONFIG_MESH
+       "mesh_basic_rates", "dot11MeshMaxRetries",
+       "dot11MeshRetryTimeout", "dot11MeshConfirmTimeout",
+       "dot11MeshHoldingTimeout",
+#endif /* CONFIG_MESH */
+       "wpa_ptk_rekey", "bgscan", "ignore_broadcast_ssid",
+#ifdef CONFIG_P2P
+       "go_p2p_dev_addr", "p2p_client_list", "psk_list",
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_HT_OVERRIDES
+       "disable_ht", "disable_ht40", "disable_sgi", "disable_ldpc",
+       "ht40_intolerant", "disable_max_amsdu", "ampdu_factor",
+       "ampdu_density", "ht_mcs",
+#endif /* CONFIG_HT_OVERRIDES */
+#ifdef CONFIG_VHT_OVERRIDES
+       "disable_vht", "vht_capa", "vht_capa_mask", "vht_rx_mcs_nss_1",
+       "vht_rx_mcs_nss_2", "vht_rx_mcs_nss_3", "vht_rx_mcs_nss_4",
+       "vht_rx_mcs_nss_5", "vht_rx_mcs_nss_6", "vht_rx_mcs_nss_7",
+       "vht_rx_mcs_nss_8", "vht_tx_mcs_nss_1", "vht_tx_mcs_nss_2",
+       "vht_tx_mcs_nss_3", "vht_tx_mcs_nss_4", "vht_tx_mcs_nss_5",
+       "vht_tx_mcs_nss_6", "vht_tx_mcs_nss_7", "vht_tx_mcs_nss_8",
+#endif /* CONFIG_VHT_OVERRIDES */
+       "ap_max_inactivity", "dtim_period", "beacon_int",
+#ifdef CONFIG_MACSEC
+       "macsec_policy",
+#endif /* CONFIG_MACSEC */
+#ifdef CONFIG_HS20
+       "update_identifier",
+#endif /* CONFIG_HS20 */
+       "mac_addr"
+};
+
+
+static char ** wpa_cli_complete_network(const char *str, int pos)
+{
+       int arg = get_cmd_arg_num(str, pos);
+       int i, num_fields = ARRAY_SIZE(network_fields);
+       char **res = NULL;
+
+       switch (arg) {
+       case 1:
+               res = cli_txt_list_array(&networks);
+               break;
+       case 2:
+               res = os_calloc(num_fields + 1, sizeof(char *));
+               if (res == NULL)
+                       return NULL;
+               for (i = 0; i < num_fields; i++) {
+                       res[i] = os_strdup(network_fields[i]);
+                       if (res[i] == NULL)
+                               break;
+               }
+       }
+       return res;
+}
+
+
 static int wpa_cli_cmd_dup_network(struct wpa_ctrl *ctrl, int argc,
                                   char *argv[])
 {
@@ -1616,20 +1811,20 @@ static int wpa_cli_cmd_interface_add(struct wpa_ctrl *ctrl, int argc,
                printf("Invalid INTERFACE_ADD command: needs at least one "
                       "argument (interface name)\n"
                       "All arguments: ifname confname driver ctrl_interface "
-                      "driver_param bridge_name\n");
+                      "driver_param bridge_name [create]\n");
                return -1;
        }
 
        /*
         * INTERFACE_ADD <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB
-        * <driver_param>TAB<bridge_name>
+        * <driver_param>TAB<bridge_name>[TAB<create>]
         */
        res = os_snprintf(cmd, sizeof(cmd),
-                         "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s",
+                         "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s\t%s",
                          argv[0],
                          argc > 1 ? argv[1] : "", argc > 2 ? argv[2] : "",
                          argc > 3 ? argv[3] : "", argc > 4 ? argv[4] : "",
-                         argc > 5 ? argv[5] : "");
+                         argc > 5 ? argv[5] : "", argc > 6 ? argv[6] : "");
        if (os_snprintf_error(sizeof(cmd), res))
                return -1;
        cmd[sizeof(cmd) - 1] = '\0';
@@ -1825,6 +2020,20 @@ static int wpa_cli_cmd_p2p_stop_find(struct wpa_ctrl *ctrl, int argc,
 }
 
 
+static int wpa_cli_cmd_p2p_asp_provision(struct wpa_ctrl *ctrl, int argc,
+                                        char *argv[])
+{
+       return wpa_cli_cmd(ctrl, "P2P_ASP_PROVISION", 3, argc, argv);
+}
+
+
+static int wpa_cli_cmd_p2p_asp_provision_resp(struct wpa_ctrl *ctrl, int argc,
+                                             char *argv[])
+{
+       return wpa_cli_cmd(ctrl, "P2P_ASP_PROVISION_RESP", 2, argc, argv);
+}
+
+
 static int wpa_cli_cmd_p2p_connect(struct wpa_ctrl *ctrl, int argc,
                                   char *argv[])
 {
@@ -1909,11 +2118,9 @@ static int wpa_cli_cmd_p2p_serv_disc_req(struct wpa_ctrl *ctrl, int argc,
 {
        char cmd[4096];
 
-       if (argc != 2 && argc != 4) {
+       if (argc < 2) {
                printf("Invalid P2P_SERV_DISC_REQ command: needs two "
-                      "arguments (address and TLVs) or four arguments "
-                      "(address, \"upnp\", version, search target "
-                      "(SSDP ST:)\n");
+                      "or more arguments (address and TLVs)\n");
                return -1;
        }
 
@@ -1975,27 +2182,25 @@ static int wpa_cli_cmd_p2p_service_flush(struct wpa_ctrl *ctrl, int argc,
 static int wpa_cli_cmd_p2p_service_add(struct wpa_ctrl *ctrl, int argc,
                                       char *argv[])
 {
-       char cmd[4096];
-       int res;
+       if (argc < 3) {
+               printf("Invalid P2P_SERVICE_ADD command: needs 3-6 arguments\n");
+               return -1;
+       }
 
-       if (argc != 3 && argc != 4) {
-               printf("Invalid P2P_SERVICE_ADD command: needs three or four "
+       return wpa_cli_cmd(ctrl, "P2P_SERVICE_ADD", 3, argc, argv);
+}
+
+
+static int wpa_cli_cmd_p2p_service_rep(struct wpa_ctrl *ctrl, int argc,
+                                      char *argv[])
+{
+       if (argc < 5 || argc > 6) {
+               printf("Invalid P2P_SERVICE_REP command: needs 5-6 "
                       "arguments\n");
                return -1;
        }
 
-       if (argc == 4)
-               res = os_snprintf(cmd, sizeof(cmd),
-                                 "P2P_SERVICE_ADD %s %s %s %s",
-                                 argv[0], argv[1], argv[2], argv[3]);
-       else
-               res = os_snprintf(cmd, sizeof(cmd),
-                                 "P2P_SERVICE_ADD %s %s %s",
-                                 argv[0], argv[1], argv[2]);
-       if (os_snprintf_error(sizeof(cmd), res))
-               return -1;
-       cmd[sizeof(cmd) - 1] = '\0';
-       return wpa_ctrl_command(ctrl, cmd);
+       return wpa_cli_cmd(ctrl, "P2P_SERVICE_REP", 5, argc, argv);
 }
 
 
@@ -2299,6 +2504,13 @@ static int wpa_cli_cmd_interworking_connect(struct wpa_ctrl *ctrl, int argc,
 }
 
 
+static int wpa_cli_cmd_interworking_add_network(struct wpa_ctrl *ctrl, int argc,
+                                               char *argv[])
+{
+       return wpa_cli_cmd(ctrl, "INTERWORKING_ADD_NETWORK", 1, argc, argv);
+}
+
+
 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);
@@ -2599,7 +2811,10 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
          cli_cmd_flag_none,
          "= set variables (shows list of variables when run without "
          "arguments)" },
-       { "get", wpa_cli_cmd_get, NULL,
+       { "dump", wpa_cli_cmd_dump, NULL,
+         cli_cmd_flag_none,
+         "= dump config variables" },
+       { "get", wpa_cli_cmd_get, wpa_cli_complete_get,
          cli_cmd_flag_none,
          "<name> = get information" },
        { "logon", wpa_cli_cmd_logon, NULL,
@@ -2676,11 +2891,11 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
        { "remove_network", wpa_cli_cmd_remove_network, NULL,
          cli_cmd_flag_none,
          "<network id> = remove a network" },
-       { "set_network", wpa_cli_cmd_set_network, NULL,
+       { "set_network", wpa_cli_cmd_set_network, wpa_cli_complete_network,
          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, NULL,
+       { "get_network", wpa_cli_cmd_get_network, wpa_cli_complete_network,
          cli_cmd_flag_none,
          "<network id> <variable> = get network variables" },
        { "dup_network", wpa_cli_cmd_dup_network, NULL,
@@ -2882,6 +3097,12 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
          "[timeout] [type=*] = find P2P Devices for up-to timeout seconds" },
        { "p2p_stop_find", wpa_cli_cmd_p2p_stop_find, NULL, cli_cmd_flag_none,
          "= stop P2P Devices search" },
+       { "p2p_asp_provision", wpa_cli_cmd_p2p_asp_provision, NULL,
+         cli_cmd_flag_none,
+         "<addr> adv_id=<adv_id> conncap=<conncap> [info=<infodata>] = provision with a P2P ASP Device" },
+       { "p2p_asp_provision_resp", wpa_cli_cmd_p2p_asp_provision_resp, NULL,
+         cli_cmd_flag_none,
+         "<addr> adv_id=<adv_id> [role<conncap>] [info=<infodata>] = provision with a P2P ASP Device" },
        { "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" },
@@ -2918,8 +3139,12 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
          "= remove all stored service entries" },
        { "p2p_service_add", wpa_cli_cmd_p2p_service_add, NULL,
          cli_cmd_flag_none,
-         "<bonjour|upnp> <query|version> <response|service> = add a local "
+         "<bonjour|upnp|asp> <query|version> <response|service> = add a local "
          "service" },
+       { "p2p_service_rep", wpa_cli_cmd_p2p_service_rep, NULL,
+         cli_cmd_flag_none,
+         "asp <auto> <adv_id> <svc_state> <svc_string> [<svc_info>] = replace "
+         "local ASP service" },
        { "p2p_service_del", wpa_cli_cmd_p2p_service_del, NULL,
          cli_cmd_flag_none,
          "<bonjour|upnp> <query|version> [|service] = remove a local "
@@ -2977,6 +3202,9 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
        { "interworking_connect", wpa_cli_cmd_interworking_connect,
          wpa_cli_complete_bss, cli_cmd_flag_none,
          "<BSSID> = connect using Interworking credentials" },
+       { "interworking_add_network", wpa_cli_cmd_interworking_add_network,
+         wpa_cli_complete_bss, cli_cmd_flag_none,
+         "<BSSID> = connect using Interworking credentials" },
        { "anqp_get", wpa_cli_cmd_anqp_get, wpa_cli_complete_bss,
          cli_cmd_flag_none,
          "<addr> <info id>[,<info id>]... = request ANQP information" },
@@ -3653,7 +3881,11 @@ static void start_edit(void)
        ps = wpa_ctrl_get_remote_ifname(ctrl_conn);
 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
 
+#ifdef CONFIG_WPA_CLI_HISTORY_DIR
+       home = CONFIG_WPA_CLI_HISTORY_DIR;
+#else /* CONFIG_WPA_CLI_HISTORY_DIR */
        home = getenv("HOME");
+#endif /* CONFIG_WPA_CLI_HISTORY_DIR */
        if (home) {
                const char *fname = ".wpa_cli_history";
                int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1;
@@ -3736,6 +3968,38 @@ static void update_ifnames(struct wpa_ctrl *ctrl)
 }
 
 
+static void update_networks(struct wpa_ctrl *ctrl)
+{
+       char buf[4096];
+       size_t len = sizeof(buf);
+       int ret;
+       char *cmd = "LIST_NETWORKS";
+       char *pos, *end;
+       int header = 1;
+
+       cli_txt_list_flush(&networks);
+
+       if (ctrl == NULL)
+               return;
+       ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, NULL);
+       if (ret < 0)
+               return;
+       buf[len] = '\0';
+
+       pos = buf;
+       while (pos) {
+               end = os_strchr(pos, '\n');
+               if (end == NULL)
+                       break;
+               *end = '\0';
+               if (!header)
+                       cli_txt_list_add_word(&networks, pos);
+               header = 0;
+               pos = end + 1;
+       }
+}
+
+
 static void try_connection(void *eloop_ctx, void *timeout_ctx)
 {
        if (ctrl_conn)
@@ -3756,6 +4020,7 @@ static void try_connection(void *eloop_ctx, void *timeout_ctx)
        }
 
        update_bssid_list(ctrl_conn);
+       update_networks(ctrl_conn);
 
        if (warning_displayed)
                printf("Connection established.\n");
@@ -3777,6 +4042,7 @@ static void wpa_cli_interactive(void)
        cli_txt_list_flush(&p2p_groups);
        cli_txt_list_flush(&bsses);
        cli_txt_list_flush(&ifnames);
+       cli_txt_list_flush(&networks);
        if (edit_started)
                edit_deinit(hfile, wpa_cli_edit_filter_history_cb);
        os_free(hfile);