Updated to hostap_2_6
[mech_eap.git] / libeap / wpa_supplicant / ctrl_iface.c
index 3b97806..d814fdf 100644 (file)
@@ -15,6 +15,7 @@
 #include "utils/common.h"
 #include "utils/eloop.h"
 #include "utils/uuid.h"
+#include "utils/module_tests.h"
 #include "common/version.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
@@ -55,6 +56,7 @@
 static int wpa_supplicant_global_iface_list(struct wpa_global *global,
                                            char *buf, int len);
 static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
+                                                 const char *input,
                                                  char *buf, int len);
 static int * freq_range_to_channel_list(struct wpa_supplicant *wpa_s,
                                        char *val);
@@ -310,6 +312,33 @@ static int wpas_ctrl_set_band(struct wpa_supplicant *wpa_s, char *band)
 }
 
 
+static int wpas_ctrl_iface_set_lci(struct wpa_supplicant *wpa_s,
+                                  const char *cmd)
+{
+       struct wpabuf *lci;
+
+       if (*cmd == '\0' || os_strcmp(cmd, "\"\"") == 0) {
+               wpabuf_free(wpa_s->lci);
+               wpa_s->lci = NULL;
+               return 0;
+       }
+
+       lci = wpabuf_parse_bin(cmd);
+       if (!lci)
+               return -1;
+
+       if (os_get_reltime(&wpa_s->lci_time)) {
+               wpabuf_free(lci);
+               return -1;
+       }
+
+       wpabuf_free(wpa_s->lci);
+       wpa_s->lci = lci;
+
+       return 0;
+}
+
+
 static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
                                         char *cmd)
 {
@@ -371,6 +400,20 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
                wps_corrupt_pkhash = atoi(value);
                wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d",
                           wps_corrupt_pkhash);
+       } else if (os_strcasecmp(cmd, "wps_force_auth_types") == 0) {
+               if (value[0] == '\0') {
+                       wps_force_auth_types_in_use = 0;
+               } else {
+                       wps_force_auth_types = strtol(value, NULL, 0);
+                       wps_force_auth_types_in_use = 1;
+               }
+       } else if (os_strcasecmp(cmd, "wps_force_encr_types") == 0) {
+               if (value[0] == '\0') {
+                       wps_force_encr_types_in_use = 0;
+               } else {
+                       wps_force_encr_types = strtol(value, NULL, 0);
+                       wps_force_encr_types_in_use = 1;
+               }
 #endif /* CONFIG_WPS_TESTING */
        } else if (os_strcasecmp(cmd, "ampdu") == 0) {
                if (wpa_drv_ampdu(wpa_s, atoi(value)) < 0)
@@ -378,7 +421,6 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
 #ifdef CONFIG_TDLS
 #ifdef CONFIG_TDLS_TESTING
        } else if (os_strcasecmp(cmd, "tdls_testing") == 0) {
-               extern unsigned int tdls_testing;
                tdls_testing = strtol(value, NULL, 0);
                wpa_printf(MSG_DEBUG, "TDLS: tdls_testing=0x%x", tdls_testing);
 #endif /* CONFIG_TDLS_TESTING */
@@ -467,6 +509,14 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
                wpa_s->extra_roc_dur = atoi(value);
        } else if (os_strcasecmp(cmd, "test_failure") == 0) {
                wpa_s->test_failure = atoi(value);
+       } else if (os_strcasecmp(cmd, "p2p_go_csa_on_inv") == 0) {
+               wpa_s->p2p_go_csa_on_inv = !!atoi(value);
+       } else if (os_strcasecmp(cmd, "ignore_auth_resp") == 0) {
+               wpa_s->ignore_auth_resp = !!atoi(value);
+       } else if (os_strcasecmp(cmd, "ignore_assoc_disallow") == 0) {
+               wpa_s->ignore_assoc_disallow = !!atoi(value);
+       } else if (os_strcasecmp(cmd, "reject_btm_req_reason") == 0) {
+               wpa_s->reject_btm_req_reason = atoi(value);
 #endif /* CONFIG_TESTING_OPTIONS */
 #ifndef CONFIG_NO_CONFIG_BLOBS
        } else if (os_strcmp(cmd, "blob") == 0) {
@@ -474,6 +524,14 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_NO_CONFIG_BLOBS */
        } else if (os_strcasecmp(cmd, "setband") == 0) {
                ret = wpas_ctrl_set_band(wpa_s, value);
+#ifdef CONFIG_MBO
+       } else if (os_strcasecmp(cmd, "non_pref_chan") == 0) {
+               ret = wpas_mbo_update_non_pref_chan(wpa_s, value);
+       } else if (os_strcasecmp(cmd, "mbo_cell_capa") == 0) {
+               wpas_mbo_update_cell_capa(wpa_s, atoi(value));
+#endif /* CONFIG_MBO */
+       } else if (os_strcasecmp(cmd, "lci") == 0) {
+               ret = wpas_ctrl_iface_set_lci(wpa_s, value);
        } else {
                value[-1] = '=';
                ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
@@ -940,7 +998,8 @@ static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
        if (os_strcmp(cmd, "any") == 0)
                _bssid = NULL;
        else if (os_strcmp(cmd, "get") == 0) {
-               ret = wps_generate_pin();
+               if (wps_generate_pin((unsigned int *) &ret) < 0)
+                       return -1;
                goto done;
        } else if (hwaddr_aton(cmd, bssid)) {
                wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PIN: invalid BSSID '%s'",
@@ -1833,6 +1892,10 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
                                                  "mode=P2P GO - group "
                                                  "formation\n");
                                break;
+                       case WPAS_MODE_MESH:
+                               ret = os_snprintf(pos, end - pos,
+                                                 "mode=mesh\n");
+                               break;
                        default:
                                ret = 0;
                                break;
@@ -2703,6 +2766,40 @@ static int wpa_supplicant_ctrl_iface_mesh_group_remove(
        return 0;
 }
 
+
+static int wpa_supplicant_ctrl_iface_mesh_peer_remove(
+       struct wpa_supplicant *wpa_s, char *cmd)
+{
+       u8 addr[ETH_ALEN];
+
+       if (hwaddr_aton(cmd, addr) < 0)
+               return -1;
+
+       return wpas_mesh_peer_remove(wpa_s, addr);
+}
+
+
+static int wpa_supplicant_ctrl_iface_mesh_peer_add(
+       struct wpa_supplicant *wpa_s, char *cmd)
+{
+       u8 addr[ETH_ALEN];
+       int duration;
+       char *pos;
+
+       pos = os_strstr(cmd, " duration=");
+       if (pos) {
+               *pos = '\0';
+               duration = atoi(pos + 10);
+       } else {
+               duration = -1;
+       }
+
+       if (hwaddr_aton(cmd, addr))
+               return -1;
+
+       return wpas_mesh_peer_add(wpa_s, addr, duration);
+}
+
 #endif /* CONFIG_MESH */
 
 
@@ -2832,15 +2929,10 @@ static int wpa_supplicant_ctrl_iface_add_network(
 
        wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK");
 
-       ssid = wpa_config_add_network(wpa_s->conf);
+       ssid = wpa_supplicant_add_network(wpa_s);
        if (ssid == NULL)
                return -1;
 
-       wpas_notify_network_added(wpa_s, ssid);
-
-       ssid->disabled = 1;
-       wpa_config_set_network_defaults(ssid);
-
        ret = os_snprintf(buf, buflen, "%d\n", ssid->id);
        if (os_snprintf_error(buflen, ret))
                return -1;
@@ -2853,7 +2945,7 @@ static int wpa_supplicant_ctrl_iface_remove_network(
 {
        int id;
        struct wpa_ssid *ssid;
-       int was_disabled;
+       int result;
 
        /* cmd: "<network id>" or "all" */
        if (os_strcmp(cmd, "all") == 0) {
@@ -2889,54 +2981,17 @@ static int wpa_supplicant_ctrl_iface_remove_network(
        id = atoi(cmd);
        wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id);
 
-       ssid = wpa_config_get_network(wpa_s->conf, id);
-       if (ssid)
-               wpas_notify_network_removed(wpa_s, ssid);
-       if (ssid == NULL) {
+       result = wpa_supplicant_remove_network(wpa_s, id);
+       if (result == -1) {
                wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
                           "id=%d", id);
                return -1;
        }
-
-       if (wpa_s->last_ssid == ssid)
-               wpa_s->last_ssid = NULL;
-
-       if (ssid == wpa_s->current_ssid || wpa_s->current_ssid == NULL) {
-#ifdef CONFIG_SME
-               wpa_s->sme.prev_bssid_set = 0;
-#endif /* CONFIG_SME */
-               /*
-                * Invalidate the EAP session cache if the current or
-                * previously used network is removed.
-                */
-               eapol_sm_invalidate_cached_session(wpa_s->eapol);
-       }
-
-       if (ssid == wpa_s->current_ssid) {
-               wpa_sm_set_config(wpa_s->wpa, NULL);
-               eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
-
-               if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
-                       wpa_s->own_disconnect_req = 1;
-               wpa_supplicant_deauthenticate(wpa_s,
-                                             WLAN_REASON_DEAUTH_LEAVING);
-       }
-
-       was_disabled = ssid->disabled;
-
-       if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
+       if (result == -2) {
                wpa_printf(MSG_DEBUG, "CTRL_IFACE: Not able to remove the "
                           "network id=%d", id);
                return -1;
        }
-
-       if (!was_disabled && wpa_s->sched_scanning) {
-               wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to remove "
-                          "network from filters");
-               wpa_supplicant_cancel_sched_scan(wpa_s);
-               wpa_supplicant_req_scan(wpa_s, 0, 0);
-       }
-
        return 0;
 }
 
@@ -2945,22 +3000,29 @@ static int wpa_supplicant_ctrl_iface_update_network(
        struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
        char *name, char *value)
 {
-       if (wpa_config_set(ssid, name, value, 0) < 0) {
+       int ret;
+
+       ret = wpa_config_set(ssid, name, value, 0);
+       if (ret < 0) {
                wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network "
                           "variable '%s'", name);
                return -1;
        }
+       if (ret == 1)
+               return 0; /* No change to the previously configured value */
 
        if (os_strcmp(name, "bssid") != 0 &&
-           os_strcmp(name, "priority") != 0)
+           os_strcmp(name, "priority") != 0) {
                wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
 
-       if (wpa_s->current_ssid == ssid || wpa_s->current_ssid == NULL) {
-               /*
-                * Invalidate the EAP session cache if anything in the current
-                * or previously used configuration changes.
-                */
-               eapol_sm_invalidate_cached_session(wpa_s->eapol);
+               if (wpa_s->current_ssid == ssid ||
+                   wpa_s->current_ssid == NULL) {
+                       /*
+                        * Invalidate the EAP session cache if anything in the
+                        * current or previously used configuration changes.
+                        */
+                       eapol_sm_invalidate_cached_session(wpa_s->eapol);
+               }
        }
 
        if ((os_strcmp(name, "psk") == 0 &&
@@ -3935,6 +3997,15 @@ static int wpa_supplicant_ctrl_iface_get_capability(
        }
 #endif /* CONFIG_FIPS */
 
+#ifdef CONFIG_ACS
+       if (os_strcmp(field, "acs") == 0) {
+               res = os_snprintf(buf, buflen, "ACS");
+               if (os_snprintf_error(buflen, res))
+                       return -1;
+               return res;
+       }
+#endif /* CONFIG_ACS */
+
        wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
                   field);
 
@@ -4195,9 +4266,10 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
        if (mask & WPA_BSS_MASK_P2P_SCAN) {
                ie = (const u8 *) (bss + 1);
                ret = wpas_p2p_scan_result_text(ie, bss->ie_len, pos, end);
-               if (ret < 0 || ret >= end - pos)
+               if (ret >= end - pos)
                        return 0;
-               pos += ret;
+               if (ret > 0)
+                       pos += ret;
        }
 #endif /* CONFIG_P2P */
 
@@ -4231,6 +4303,8 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
 #ifdef CONFIG_INTERWORKING
        if ((mask & WPA_BSS_MASK_INTERNETW) && bss->anqp) {
                struct wpa_bss_anqp *anqp = bss->anqp;
+               struct wpa_bss_anqp_elem *elem;
+
                pos = anqp_add_hex(pos, end, "anqp_capability_list",
                                   anqp->capability_list);
                pos = anqp_add_hex(pos, end, "anqp_venue_name",
@@ -4260,6 +4334,15 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
                pos = anqp_add_hex(pos, end, "hs20_osu_providers_list",
                                   anqp->hs20_osu_providers_list);
 #endif /* CONFIG_HS20 */
+
+               dl_list_for_each(elem, &anqp->anqp_elems,
+                                struct wpa_bss_anqp_elem, list) {
+                       char title[20];
+
+                       os_snprintf(title, sizeof(title), "anqp[%u]",
+                                   elem->infoid);
+                       pos = anqp_add_hex(pos, end, title, elem->payload);
+               }
        }
 #endif /* CONFIG_INTERWORKING */
 
@@ -4267,9 +4350,10 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
        if (mask & WPA_BSS_MASK_MESH_SCAN) {
                ie = (const u8 *) (bss + 1);
                ret = wpas_mesh_scan_result_text(ie, bss->ie_len, pos, end);
-               if (ret < 0 || ret >= end - pos)
+               if (ret >= end - pos)
                        return 0;
-               pos += ret;
+               if (ret > 0)
+                       pos += ret;
        }
 #endif /* CONFIG_MESH */
 
@@ -4676,7 +4760,7 @@ static int p2ps_ctrl_parse_cpt_priority(const char *pos, u8 *cpt)
                        return -1;
                }
 
-               if (isblank(*last)) {
+               if (isblank((unsigned char) *last)) {
                        i++;
                        break;
                }
@@ -4848,6 +4932,30 @@ static int p2p_ctrl_asp_provision(struct wpa_supplicant *wpa_s, char *cmd)
 }
 
 
+static int parse_freq(int chwidth, int freq2)
+{
+       if (freq2 < 0)
+               return -1;
+       if (freq2)
+               return VHT_CHANWIDTH_80P80MHZ;
+
+       switch (chwidth) {
+       case 0:
+       case 20:
+       case 40:
+               return VHT_CHANWIDTH_USE_HT;
+       case 80:
+               return VHT_CHANWIDTH_80MHZ;
+       case 160:
+               return VHT_CHANWIDTH_160MHZ;
+       default:
+               wpa_printf(MSG_DEBUG, "Unknown max oper bandwidth: %d",
+                          chwidth);
+               return -1;
+       }
+}
+
+
 static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
                            char *buf, size_t buflen)
 {
@@ -4864,7 +4972,9 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
        int go_intent = -1;
        int freq = 0;
        int pd;
-       int ht40, vht;
+       int ht40, vht, max_oper_chwidth, chwidth = 0, freq2 = 0;
+       u8 _group_ssid[SSID_MAX_LEN], *group_ssid = NULL;
+       size_t group_ssid_len = 0;
 
        if (!wpa_s->global->p2p_init_wpa_s)
                return -1;
@@ -4877,7 +4987,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
        /* <addr> <"pbc" | "pin" | PIN> [label|display|keypad|p2ps]
         * [persistent|persistent=<network id>]
         * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
-        * [ht40] [vht] [auto] */
+        * [ht40] [vht] [auto] [ssid=<hexdump>] */
 
        if (hwaddr_aton(cmd, addr))
                return -1;
@@ -4925,11 +5035,41 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
                        return -1;
        }
 
+       pos2 = os_strstr(pos, " freq2=");
+       if (pos2)
+               freq2 = atoi(pos2 + 7);
+
+       pos2 = os_strstr(pos, " max_oper_chwidth=");
+       if (pos2)
+               chwidth = atoi(pos2 + 18);
+
+       max_oper_chwidth = parse_freq(chwidth, freq2);
+       if (max_oper_chwidth < 0)
+               return -1;
+
+       pos2 = os_strstr(pos, " ssid=");
+       if (pos2) {
+               char *end;
+
+               pos2 += 6;
+               end = os_strchr(pos2, ' ');
+               if (!end)
+                       group_ssid_len = os_strlen(pos2) / 2;
+               else
+                       group_ssid_len = (end - pos2) / 2;
+               if (group_ssid_len == 0 || group_ssid_len > SSID_MAX_LEN ||
+                   hexstr2bin(pos2, _group_ssid, group_ssid_len) < 0)
+                       return -1;
+               group_ssid = _group_ssid;
+       }
+
        if (os_strncmp(pos, "pin", 3) == 0) {
                /* Request random PIN (to be displayed) and enable the PIN */
                wps_method = WPS_PIN_DISPLAY;
        } else if (os_strncmp(pos, "pbc", 3) == 0) {
                wps_method = WPS_PBC;
+       } else if (os_strstr(pos, "p2ps") != NULL) {
+               wps_method = WPS_P2PS;
        } else {
                pin = pos;
                pos = os_strchr(pin, ' ');
@@ -4938,8 +5078,6 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
                        *pos++ = '\0';
                        if (os_strncmp(pos, "display", 7) == 0)
                                wps_method = WPS_PIN_DISPLAY;
-                       else if (os_strncmp(pos, "p2ps", 4) == 0)
-                               wps_method = WPS_P2PS;
                }
                if (!wps_pin_str_valid(pin)) {
                        os_memcpy(buf, "FAIL-INVALID-PIN\n", 17);
@@ -4949,8 +5087,9 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
 
        new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
                                   persistent_group, automatic, join,
-                                  auth, go_intent, freq, persistent_id, pd,
-                                  ht40, vht);
+                                  auth, go_intent, freq, freq2, persistent_id,
+                                  pd, ht40, vht, max_oper_chwidth,
+                                  group_ssid, group_ssid_len);
        if (new_pin == -2) {
                os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
                return 25;
@@ -5505,7 +5644,7 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
        struct wpa_ssid *ssid;
        u8 *_peer = NULL, peer[ETH_ALEN];
        int freq = 0, pref_freq = 0;
-       int ht40, vht;
+       int ht40, vht, max_oper_chwidth, chwidth = 0, freq2 = 0;
 
        id = atoi(cmd);
        pos = os_strstr(cmd, " peer=");
@@ -5543,8 +5682,20 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
        ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
                vht;
 
-       return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40, vht,
-                              pref_freq);
+       pos = os_strstr(cmd, "freq2=");
+       if (pos)
+               freq2 = atoi(pos + 6);
+
+       pos = os_strstr(cmd, " max_oper_chwidth=");
+       if (pos)
+               chwidth = atoi(pos + 18);
+
+       max_oper_chwidth = parse_freq(chwidth, freq2);
+       if (max_oper_chwidth < 0)
+               return -1;
+
+       return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, freq2, ht40, vht,
+                              max_oper_chwidth, pref_freq);
 }
 
 
@@ -5591,7 +5742,8 @@ static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd)
 
 
 static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
-                                        int id, int freq, int ht40, int vht)
+                                        int id, int freq, int vht_center_freq2,
+                                        int ht40, int vht, int vht_chwidth)
 {
        struct wpa_ssid *ssid;
 
@@ -5603,8 +5755,9 @@ static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
                return -1;
        }
 
-       return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, ht40, vht,
-                                            NULL, 0, 0);
+       return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq,
+                                            vht_center_freq2, 0, ht40, vht,
+                                            vht_chwidth, NULL, 0, 0);
 }
 
 
@@ -5613,11 +5766,14 @@ static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
        int freq = 0, persistent = 0, group_id = -1;
        int vht = wpa_s->conf->p2p_go_vht;
        int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
+       int max_oper_chwidth, chwidth = 0, freq2 = 0;
        char *token, *context = NULL;
 
        while ((token = str_token(cmd, " ", &context))) {
                if (sscanf(token, "freq=%d", &freq) == 1 ||
-                   sscanf(token, "persistent=%d", &group_id) == 1) {
+                   sscanf(token, "freq2=%d", &freq2) == 1 ||
+                   sscanf(token, "persistent=%d", &group_id) == 1 ||
+                   sscanf(token, "max_oper_chwidth=%d", &chwidth) == 1) {
                        continue;
                } else if (os_strcmp(token, "ht40") == 0) {
                        ht40 = 1;
@@ -5634,11 +5790,40 @@ static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
                }
        }
 
+       max_oper_chwidth = parse_freq(chwidth, freq2);
+       if (max_oper_chwidth < 0)
+               return -1;
+
        if (group_id >= 0)
                return p2p_ctrl_group_add_persistent(wpa_s, group_id,
-                                                    freq, ht40, vht);
+                                                    freq, freq2, ht40, vht,
+                                                    max_oper_chwidth);
+
+       return wpas_p2p_group_add(wpa_s, persistent, freq, freq2, ht40, vht,
+                                 max_oper_chwidth);
+}
+
+
+static int p2p_ctrl_group_member(struct wpa_supplicant *wpa_s, const char *cmd,
+                                char *buf, size_t buflen)
+{
+       u8 dev_addr[ETH_ALEN];
+       struct wpa_ssid *ssid;
+       int res;
+       const u8 *iaddr;
+
+       ssid = wpa_s->current_ssid;
+       if (!wpa_s->global->p2p || !ssid || ssid->mode != WPAS_MODE_P2P_GO ||
+           hwaddr_aton(cmd, dev_addr))
+               return -1;
 
-       return wpas_p2p_group_add(wpa_s, persistent, freq, ht40, vht);
+       iaddr = p2p_group_get_client_interface_addr(wpa_s->p2p_group, dev_addr);
+       if (!iaddr)
+               return -1;
+       res = os_snprintf(buf, buflen, MACSTR, MAC2STR(iaddr));
+       if (os_snprintf_error(buflen, res))
+               return -1;
+       return res;
 }
 
 
@@ -5797,8 +5982,15 @@ static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
        }
 
        if (os_strcmp(cmd, "listen_channel") == 0) {
-               return p2p_set_listen_channel(wpa_s->global->p2p, 81,
-                                             atoi(param), 1);
+               char *pos;
+               u8 channel, op_class;
+
+               channel = atoi(param);
+               pos = os_strchr(param, ' ');
+               op_class = pos ? atoi(pos) : 81;
+
+               return p2p_set_listen_channel(wpa_s->global->p2p, op_class,
+                                             channel, 1);
        }
 
        if (os_strcmp(cmd, "ssid_postfix") == 0) {
@@ -6059,6 +6251,21 @@ static int p2p_ctrl_remove_client(struct wpa_supplicant *wpa_s, const char *cmd)
        return 0;
 }
 
+
+static int p2p_ctrl_iface_p2p_lo_start(struct wpa_supplicant *wpa_s, char *cmd)
+{
+       int freq = 0, period = 0, interval = 0, count = 0;
+
+       if (sscanf(cmd, "%d %d %d %d", &freq, &period, &interval, &count) != 4)
+       {
+               wpa_printf(MSG_DEBUG,
+                          "CTRL: Invalid P2P LO Start parameter: '%s'", cmd);
+               return -1;
+       }
+
+       return wpas_p2p_lo_start(wpa_s, freq, period, interval, count);
+}
+
 #endif /* CONFIG_P2P */
 
 
@@ -6176,6 +6383,7 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
        u16 id[MAX_ANQP_INFO_ID];
        size_t num_id = 0;
        u32 subtypes = 0;
+       int get_cell_pref = 0;
 
        used = hwaddr_aton2(dst, dst_addr);
        if (used < 0)
@@ -6193,6 +6401,15 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
 #else /* CONFIG_HS20 */
                        return -1;
 #endif /* CONFIG_HS20 */
+               } else if (os_strncmp(pos, "mbo:", 4) == 0) {
+#ifdef CONFIG_MBO
+                       int num = atoi(pos + 4);
+                       if (num != MBO_ANQP_SUBTYPE_CELL_CONN_PREF)
+                               return -1;
+                       get_cell_pref = 1;
+#else /* CONFIG_MBO */
+                       return -1;
+#endif /* CONFIG_MBO */
                } else {
                        id[num_id] = atoi(pos);
                        if (id[num_id])
@@ -6207,7 +6424,8 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
        if (num_id == 0)
                return -1;
 
-       return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes);
+       return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes,
+                            get_cell_pref);
 }
 
 
@@ -6378,7 +6596,7 @@ static int get_hs20_anqp(struct wpa_supplicant *wpa_s, char *dst)
        if (subtypes == 0)
                return -1;
 
-       return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0);
+       return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0, 0);
 }
 
 
@@ -6401,7 +6619,7 @@ static int hs20_nai_home_realm_list(struct wpa_supplicant *wpa_s,
 
        ret = hs20_anqp_send_req(wpa_s, addr,
                                 BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
-                                buf, len);
+                                buf, len, 0);
 
        os_free(buf);
 
@@ -6447,14 +6665,59 @@ static int hs20_get_nai_home_realm_list(struct wpa_supplicant *wpa_s,
 
        ret = hs20_anqp_send_req(wpa_s, dst_addr,
                                 BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
-                                buf, len);
+                                buf, len, 0);
        os_free(buf);
 
        return ret;
 }
 
 
-static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd)
+static int get_hs20_icon(struct wpa_supplicant *wpa_s, char *cmd, char *reply,
+                        int buflen)
+{
+       u8 dst_addr[ETH_ALEN];
+       int used;
+       char *ctx = NULL, *icon, *poffset, *psize;
+
+       used = hwaddr_aton2(cmd, dst_addr);
+       if (used < 0)
+               return -1;
+       cmd += used;
+
+       icon = str_token(cmd, " ", &ctx);
+       poffset = str_token(cmd, " ", &ctx);
+       psize = str_token(cmd, " ", &ctx);
+       if (!icon || !poffset || !psize)
+               return -1;
+
+       wpa_s->fetch_osu_icon_in_progress = 0;
+       return hs20_get_icon(wpa_s, dst_addr, icon, atoi(poffset), atoi(psize),
+                            reply, buflen);
+}
+
+
+static int del_hs20_icon(struct wpa_supplicant *wpa_s, char *cmd)
+{
+       u8 dst_addr[ETH_ALEN];
+       int used;
+       char *icon;
+
+       if (!cmd[0])
+               return hs20_del_icon(wpa_s, NULL, NULL);
+
+       used = hwaddr_aton2(cmd, dst_addr);
+       if (used < 0)
+               return -1;
+
+       while (cmd[used] == ' ')
+               used++;
+       icon = cmd[used] ? &cmd[used] : NULL;
+
+       return hs20_del_icon(wpa_s, dst_addr, icon);
+}
+
+
+static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd, int inmem)
 {
        u8 dst_addr[ETH_ALEN];
        int used;
@@ -6470,7 +6733,7 @@ static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd)
 
        wpa_s->fetch_osu_icon_in_progress = 0;
        return hs20_anqp_send_req(wpa_s, dst_addr, BIT(HS20_STYPE_ICON_REQUEST),
-                                 (u8 *) icon, os_strlen(icon));
+                                 (u8 *) icon, os_strlen(icon), inmem);
 }
 
 #endif /* CONFIG_HS20 */
@@ -6560,14 +6823,27 @@ static int wpas_ctrl_iface_wnm_sleep(struct wpa_supplicant *wpa_s, char *cmd)
 
 static int wpas_ctrl_iface_wnm_bss_query(struct wpa_supplicant *wpa_s, char *cmd)
 {
-       int query_reason;
+       int query_reason, list = 0;
 
        query_reason = atoi(cmd);
 
-       wpa_printf(MSG_DEBUG, "CTRL_IFACE: WNM_BSS_QUERY query_reason=%d",
-                  query_reason);
+       cmd = os_strchr(cmd, ' ');
+       if (cmd) {
+               cmd++;
+               if (os_strncmp(cmd, "list", 4) == 0) {
+                       list = 1;
+               } else {
+                       wpa_printf(MSG_DEBUG, "WNM Query: Invalid option %s",
+                                  cmd);
+                       return -1;
+               }
+       }
 
-       return wnm_send_bss_transition_mgmt_query(wpa_s, query_reason);
+       wpa_printf(MSG_DEBUG,
+                  "CTRL_IFACE: WNM_BSS_QUERY query_reason=%d%s",
+                  query_reason, list ? " candidate list" : "");
+
+       return wnm_send_bss_transition_mgmt_query(wpa_s, query_reason, list);
 }
 
 #endif /* CONFIG_WNM */
@@ -6632,6 +6908,28 @@ static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf,
 }
 
 
+static int wpas_ctrl_iface_signal_monitor(struct wpa_supplicant *wpa_s,
+                                         const char *cmd)
+{
+       const char *pos;
+       int threshold = 0;
+       int hysteresis = 0;
+
+       if (wpa_s->bgscan && wpa_s->bgscan_priv) {
+               wpa_printf(MSG_DEBUG,
+                          "Reject SIGNAL_MONITOR command - bgscan is active");
+               return -1;
+       }
+       pos = os_strstr(cmd, "THRESHOLD=");
+       if (pos)
+               threshold = atoi(pos + 10);
+       pos = os_strstr(cmd, "HYSTERESIS=");
+       if (pos)
+               hysteresis = atoi(pos + 11);
+       return wpa_drv_signal_monitor(wpa_s, threshold, hysteresis);
+}
+
+
 static int wpas_ctrl_iface_get_pref_freq_list(
        struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
 {
@@ -6679,6 +6977,34 @@ static int wpas_ctrl_iface_get_pref_freq_list(
 }
 
 
+static int wpas_ctrl_iface_driver_flags(struct wpa_supplicant *wpa_s,
+                                       char *buf, size_t buflen)
+{
+       int ret, i;
+       char *pos, *end;
+
+       ret = os_snprintf(buf, buflen, "%016llX:\n",
+                         (long long unsigned) wpa_s->drv_flags);
+       if (os_snprintf_error(buflen, ret))
+               return -1;
+
+       pos = buf + ret;
+       end = buf + buflen;
+
+       for (i = 0; i < 64; i++) {
+               if (wpa_s->drv_flags & (1LLU << i)) {
+                       ret = os_snprintf(pos, end - pos, "%s\n",
+                                         driver_flag_to_string(1LLU << i));
+                       if (os_snprintf_error(end - pos, ret))
+                               return -1;
+                       pos += ret;
+               }
+       }
+
+       return pos - buf;
+}
+
+
 static int wpa_supplicant_pktcnt_poll(struct wpa_supplicant *wpa_s, char *buf,
                                      size_t buflen)
 {
@@ -6736,13 +7062,13 @@ static int wpa_supplicant_vendor_cmd(struct wpa_supplicant *wpa_s, char *cmd,
 
        /* cmd: <vendor id> <subcommand id> [<hex formatted data>] */
        vendor_id = strtoul(cmd, &pos, 16);
-       if (!isblank(*pos))
+       if (!isblank((unsigned char) *pos))
                return -EINVAL;
 
        subcmd = strtoul(pos, &pos, 10);
 
        if (*pos != '\0') {
-               if (!isblank(*pos++))
+               if (!isblank((unsigned char) *pos++))
                        return -EINVAL;
                data_len = os_strlen(pos);
        }
@@ -6790,10 +7116,20 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
 
        wpa_dbg(wpa_s, MSG_DEBUG, "Flush all wpa_supplicant state");
 
+       wpas_abort_ongoing_scan(wpa_s);
+
+       if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
+               /*
+                * Avoid possible auto connect re-connection on getting
+                * disconnected due to state flush.
+                */
+               wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+       }
+
 #ifdef CONFIG_P2P
+       wpas_p2p_group_remove(p2p_wpa_s, "*");
        wpas_p2p_cancel(p2p_wpa_s);
        p2p_ctrl_flush(p2p_wpa_s);
-       wpas_p2p_group_remove(p2p_wpa_s, "*");
        wpas_p2p_service_flush(p2p_wpa_s);
        p2p_wpa_s->global->p2p_disabled = 0;
        p2p_wpa_s->global->p2p_per_sta_psk = 0;
@@ -6803,12 +7139,15 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
        p2p_wpa_s->global->p2p_go_avoid_freq.range = NULL;
        p2p_wpa_s->global->p2p_go_avoid_freq.num = 0;
        p2p_wpa_s->global->pending_p2ps_group = 0;
+       p2p_wpa_s->global->pending_p2ps_group_freq = 0;
 #endif /* CONFIG_P2P */
 
 #ifdef CONFIG_WPS_TESTING
        wps_version_number = 0x20;
        wps_testing_dummy_cred = 0;
        wps_corrupt_pkhash = 0;
+       wps_force_auth_types_in_use = 0;
+       wps_force_encr_types_in_use = 0;
 #endif /* CONFIG_WPS_TESTING */
 #ifdef CONFIG_WPS
        wpa_s->wps_fragment_size = 0;
@@ -6820,7 +7159,6 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
 
 #ifdef CONFIG_TDLS
 #ifdef CONFIG_TDLS_TESTING
-       extern unsigned int tdls_testing;
        tdls_testing = 0;
 #endif /* CONFIG_TDLS_TESTING */
        wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL);
@@ -6866,7 +7204,10 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
        wpa_s->next_ssid = NULL;
 
 #ifdef CONFIG_INTERWORKING
+#ifdef CONFIG_HS20
        hs20_cancel_fetch_osu(wpa_s);
+       hs20_del_icon(wpa_s, NULL, NULL);
+#endif /* CONFIG_HS20 */
 #endif /* CONFIG_INTERWORKING */
 
        wpa_s->ext_mgmt_frame_handling = 0;
@@ -6874,6 +7215,11 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
 #ifdef CONFIG_TESTING_OPTIONS
        wpa_s->extra_roc_dur = 0;
        wpa_s->test_failure = WPAS_TEST_FAILURE_NONE;
+       wpa_s->p2p_go_csa_on_inv = 0;
+       wpa_s->ignore_auth_resp = 0;
+       wpa_s->ignore_assoc_disallow = 0;
+       wpa_s->reject_btm_req_reason = 0;
+       wpa_sm_set_test_assoc_ie(wpa_s->wpa, NULL);
 #endif /* CONFIG_TESTING_OPTIONS */
 
        wpa_s->disconnected = 0;
@@ -6891,6 +7237,11 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
        }
 
        eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+       wpa_s->wnmsleep_used = 0;
+
+#ifdef CONFIG_SME
+       wpa_s->sme.last_unprot_disconnect.sec = 0;
+#endif /* CONFIG_SME */
 }
 
 
@@ -6947,6 +7298,13 @@ static void wpas_ctrl_radio_work_cb(struct wpa_radio_work *work, int deinit)
                        eloop_cancel_timeout(wpas_ctrl_radio_work_timeout,
                                             work, NULL);
 
+               /*
+                * work->type points to a buffer in ework, so need to replace
+                * that here with a fixed string to avoid use of freed memory
+                * in debug prints.
+                */
+               work->type = "freed-ext-work";
+               work->ctx = NULL;
                os_free(ework);
                return;
        }
@@ -7396,6 +7754,76 @@ static void wpas_ctrl_iface_mgmt_tx_done(struct wpa_supplicant *wpa_s)
 }
 
 
+static int wpas_ctrl_iface_mgmt_rx_process(struct wpa_supplicant *wpa_s,
+                                          char *cmd)
+{
+       char *pos, *param;
+       size_t len;
+       u8 *buf;
+       int freq = 0, datarate = 0, ssi_signal = 0;
+       union wpa_event_data event;
+
+       if (!wpa_s->ext_mgmt_frame_handling)
+               return -1;
+
+       /* freq=<MHz> datarate=<val> ssi_signal=<val> frame=<frame hexdump> */
+
+       wpa_printf(MSG_DEBUG, "External MGMT RX process: %s", cmd);
+
+       pos = cmd;
+       param = os_strstr(pos, "freq=");
+       if (param) {
+               param += 5;
+               freq = atoi(param);
+       }
+
+       param = os_strstr(pos, " datarate=");
+       if (param) {
+               param += 10;
+               datarate = atoi(param);
+       }
+
+       param = os_strstr(pos, " ssi_signal=");
+       if (param) {
+               param += 12;
+               ssi_signal = atoi(param);
+       }
+
+       param = os_strstr(pos, " frame=");
+       if (param == NULL)
+               return -1;
+       param += 7;
+
+       len = os_strlen(param);
+       if (len & 1)
+               return -1;
+       len /= 2;
+
+       buf = os_malloc(len);
+       if (buf == NULL)
+               return -1;
+
+       if (hexstr2bin(param, buf, len) < 0) {
+               os_free(buf);
+               return -1;
+       }
+
+       os_memset(&event, 0, sizeof(event));
+       event.rx_mgmt.freq = freq;
+       event.rx_mgmt.frame = buf;
+       event.rx_mgmt.frame_len = len;
+       event.rx_mgmt.ssi_signal = ssi_signal;
+       event.rx_mgmt.datarate = datarate;
+       wpa_s->ext_mgmt_frame_handling = 0;
+       wpa_supplicant_event(wpa_s, EVENT_RX_MGMT, &event);
+       wpa_s->ext_mgmt_frame_handling = 1;
+
+       os_free(buf);
+
+       return 0;
+}
+
+
 static int wpas_ctrl_iface_driver_event(struct wpa_supplicant *wpa_s, char *cmd)
 {
        char *pos, *param;
@@ -7495,7 +7923,8 @@ static u16 ipv4_hdr_checksum(const void *buf, size_t len)
 #define HWSIM_PACKETLEN 1500
 #define HWSIM_IP_LEN (HWSIM_PACKETLEN - sizeof(struct ether_header))
 
-void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
+static void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
+                             size_t len)
 {
        struct wpa_supplicant *wpa_s = ctx;
        const struct ether_header *eth;
@@ -7529,6 +7958,8 @@ static int wpas_ctrl_iface_data_test_config(struct wpa_supplicant *wpa_s,
                                            char *cmd)
 {
        int enabled = atoi(cmd);
+       char *pos;
+       const char *ifname;
 
        if (!enabled) {
                if (wpa_s->l2_test) {
@@ -7542,7 +7973,13 @@ static int wpas_ctrl_iface_data_test_config(struct wpa_supplicant *wpa_s,
        if (wpa_s->l2_test)
                return 0;
 
-       wpa_s->l2_test = l2_packet_init(wpa_s->ifname, wpa_s->own_addr,
+       pos = os_strstr(cmd, " ifname=");
+       if (pos)
+               ifname = pos + 8;
+       else
+               ifname = wpa_s->ifname;
+
+       wpa_s->l2_test = l2_packet_init(ifname, wpa_s->own_addr,
                                        ETHERTYPE_IP, wpas_data_test_rx,
                                        wpa_s, 1);
        if (wpa_s->l2_test == NULL)
@@ -7663,8 +8100,6 @@ done:
 static int wpas_ctrl_test_alloc_fail(struct wpa_supplicant *wpa_s, char *cmd)
 {
 #ifdef WPA_TRACE_BFD
-       extern char wpa_trace_fail_func[256];
-       extern unsigned int wpa_trace_fail_after;
        char *pos;
 
        wpa_trace_fail_after = atoi(cmd);
@@ -7687,9 +8122,6 @@ static int wpas_ctrl_get_alloc_fail(struct wpa_supplicant *wpa_s,
                                    char *buf, size_t buflen)
 {
 #ifdef WPA_TRACE_BFD
-       extern char wpa_trace_fail_func[256];
-       extern unsigned int wpa_trace_fail_after;
-
        return os_snprintf(buf, buflen, "%u:%s", wpa_trace_fail_after,
                           wpa_trace_fail_func);
 #else /* WPA_TRACE_BFD */
@@ -7701,8 +8133,6 @@ static int wpas_ctrl_get_alloc_fail(struct wpa_supplicant *wpa_s,
 static int wpas_ctrl_test_fail(struct wpa_supplicant *wpa_s, char *cmd)
 {
 #ifdef WPA_TRACE_BFD
-       extern char wpa_trace_test_fail_func[256];
-       extern unsigned int wpa_trace_test_fail_after;
        char *pos;
 
        wpa_trace_test_fail_after = atoi(cmd);
@@ -7725,9 +8155,6 @@ static int wpas_ctrl_get_fail(struct wpa_supplicant *wpa_s,
                                    char *buf, size_t buflen)
 {
 #ifdef WPA_TRACE_BFD
-       extern char wpa_trace_test_fail_func[256];
-       extern unsigned int wpa_trace_test_fail_after;
-
        return os_snprintf(buf, buflen, "%u:%s", wpa_trace_test_fail_after,
                           wpa_trace_test_fail_func);
 #else /* WPA_TRACE_BFD */
@@ -7735,62 +8162,64 @@ static int wpas_ctrl_get_fail(struct wpa_supplicant *wpa_s,
 #endif /* WPA_TRACE_BFD */
 }
 
-#endif /* CONFIG_TESTING_OPTIONS */
-
 
-static void wpas_ctrl_vendor_elem_update(struct wpa_supplicant *wpa_s)
+static void wpas_ctrl_event_test_cb(void *eloop_ctx, void *timeout_ctx)
 {
-       unsigned int i;
-       char buf[30];
+       struct wpa_supplicant *wpa_s = eloop_ctx;
+       int i, count = (intptr_t) timeout_ctx;
 
-       wpa_printf(MSG_DEBUG, "Update vendor elements");
+       wpa_printf(MSG_DEBUG, "TEST: Send %d control interface event messages",
+                  count);
+       for (i = 0; i < count; i++) {
+               wpa_msg_ctrl(wpa_s, MSG_INFO, "TEST-EVENT-MESSAGE %d/%d",
+                            i + 1, count);
+       }
+}
 
-       for (i = 0; i < NUM_VENDOR_ELEM_FRAMES; i++) {
-               if (wpa_s->vendor_elem[i]) {
-                       int res;
 
-                       res = os_snprintf(buf, sizeof(buf), "frame[%u]", i);
-                       if (!os_snprintf_error(sizeof(buf), res)) {
-                               wpa_hexdump_buf(MSG_DEBUG, buf,
-                                               wpa_s->vendor_elem[i]);
-                       }
-               }
-       }
+static int wpas_ctrl_event_test(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+       int count;
 
-#ifdef CONFIG_P2P
-       if (wpa_s->parent == wpa_s &&
-           wpa_s->global->p2p &&
-           !wpa_s->global->p2p_disabled)
-               p2p_set_vendor_elems(wpa_s->global->p2p, wpa_s->vendor_elem);
-#endif /* CONFIG_P2P */
+       count = atoi(cmd);
+       if (count <= 0)
+               return -1;
+
+       return eloop_register_timeout(0, 0, wpas_ctrl_event_test_cb, wpa_s,
+                                     (void *) (intptr_t) count);
 }
 
 
-static struct wpa_supplicant *
-wpas_ctrl_vendor_elem_iface(struct wpa_supplicant *wpa_s,
-                           enum wpa_vendor_elem_frame frame)
+static int wpas_ctrl_test_assoc_ie(struct wpa_supplicant *wpa_s,
+                                  const char *cmd)
 {
-       switch (frame) {
-#ifdef CONFIG_P2P
-       case VENDOR_ELEM_PROBE_REQ_P2P:
-       case VENDOR_ELEM_PROBE_RESP_P2P:
-       case VENDOR_ELEM_PROBE_RESP_P2P_GO:
-       case VENDOR_ELEM_BEACON_P2P_GO:
-       case VENDOR_ELEM_P2P_PD_REQ:
-       case VENDOR_ELEM_P2P_PD_RESP:
-       case VENDOR_ELEM_P2P_GO_NEG_REQ:
-       case VENDOR_ELEM_P2P_GO_NEG_RESP:
-       case VENDOR_ELEM_P2P_GO_NEG_CONF:
-       case VENDOR_ELEM_P2P_INV_REQ:
-       case VENDOR_ELEM_P2P_INV_RESP:
-       case VENDOR_ELEM_P2P_ASSOC_REQ:
-               return wpa_s->parent;
-#endif /* CONFIG_P2P */
-       default:
-               return wpa_s;
+       struct wpabuf *buf;
+       size_t len;
+
+       len = os_strlen(cmd);
+       if (len & 1)
+               return -1;
+       len /= 2;
+
+       if (len == 0) {
+               buf = NULL;
+       } else {
+               buf = wpabuf_alloc(len);
+               if (buf == NULL)
+                       return -1;
+
+               if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
+                       wpabuf_free(buf);
+                       return -1;
+               }
        }
+
+       wpa_sm_set_test_assoc_ie(wpa_s->wpa, buf);
+       return 0;
 }
 
+#endif /* CONFIG_TESTING_OPTIONS */
+
 
 static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd)
 {
@@ -7803,7 +8232,7 @@ static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd)
        frame = atoi(pos);
        if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
                return -1;
-       wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame);
+       wpa_s = wpas_vendor_elem(wpa_s, frame);
 
        pos = os_strchr(pos, ' ');
        if (pos == NULL)
@@ -7834,7 +8263,7 @@ static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd)
 
        if (wpa_s->vendor_elem[frame] == NULL) {
                wpa_s->vendor_elem[frame] = buf;
-               wpas_ctrl_vendor_elem_update(wpa_s);
+               wpas_vendor_elem_update(wpa_s);
                return 0;
        }
 
@@ -7845,7 +8274,7 @@ static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd)
 
        wpabuf_put_buf(wpa_s->vendor_elem[frame], buf);
        wpabuf_free(buf);
-       wpas_ctrl_vendor_elem_update(wpa_s);
+       wpas_vendor_elem_update(wpa_s);
 
        return 0;
 }
@@ -7858,7 +8287,7 @@ static int wpas_ctrl_vendor_elem_get(struct wpa_supplicant *wpa_s, char *cmd,
 
        if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
                return -1;
-       wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame);
+       wpa_s = wpas_vendor_elem(wpa_s, frame);
 
        if (wpa_s->vendor_elem[frame] == NULL)
                return 0;
@@ -7876,12 +8305,12 @@ static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd)
        size_t len;
        u8 *buf;
        struct ieee802_11_elems elems;
-       u8 *ie, *end;
+       int res;
 
        frame = atoi(pos);
        if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
                return -1;
-       wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame);
+       wpa_s = wpas_vendor_elem(wpa_s, frame);
 
        pos = os_strchr(pos, ' ');
        if (pos == NULL)
@@ -7891,7 +8320,7 @@ static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd)
        if (*pos == '*') {
                wpabuf_free(wpa_s->vendor_elem[frame]);
                wpa_s->vendor_elem[frame] = NULL;
-               wpas_ctrl_vendor_elem_update(wpa_s);
+               wpas_vendor_elem_update(wpa_s);
                return 0;
        }
 
@@ -7919,65 +8348,149 @@ static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd)
                return -1;
        }
 
-       ie = wpabuf_mhead_u8(wpa_s->vendor_elem[frame]);
-       end = ie + wpabuf_len(wpa_s->vendor_elem[frame]);
-
-       for (; ie + 1 < end; ie += 2 + ie[1]) {
-               if (ie + len > end)
-                       break;
-               if (os_memcmp(ie, buf, len) != 0)
-                       continue;
-
-               if (wpabuf_len(wpa_s->vendor_elem[frame]) == len) {
-                       wpabuf_free(wpa_s->vendor_elem[frame]);
-                       wpa_s->vendor_elem[frame] = NULL;
-               } else {
-                       os_memmove(ie, ie + len,
-                                  end - (ie + len));
-                       wpa_s->vendor_elem[frame]->used -= len;
-               }
-               os_free(buf);
-               wpas_ctrl_vendor_elem_update(wpa_s);
-               return 0;
-       }
-
+       res = wpas_vendor_elem_remove(wpa_s, frame, buf, len);
        os_free(buf);
-
-       return -1;
+       return res;
 }
 
 
 static void wpas_ctrl_neighbor_rep_cb(void *ctx, struct wpabuf *neighbor_rep)
 {
        struct wpa_supplicant *wpa_s = ctx;
+       size_t len;
+       const u8 *data;
 
-       if (neighbor_rep) {
-               wpa_msg_ctrl(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_RXED
-                            "length=%u",
-                            (unsigned int) wpabuf_len(neighbor_rep));
-               wpabuf_free(neighbor_rep);
-       } else {
+       /*
+        * Neighbor Report element (IEEE P802.11-REVmc/D5.0)
+        * BSSID[6]
+        * BSSID Information[4]
+        * Operating Class[1]
+        * Channel Number[1]
+        * PHY Type[1]
+        * Optional Subelements[variable]
+        */
+#define NR_IE_MIN_LEN (ETH_ALEN + 4 + 1 + 1 + 1)
+
+       if (!neighbor_rep || wpabuf_len(neighbor_rep) == 0) {
                wpa_msg_ctrl(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_FAILED);
+               goto out;
+       }
+
+       data = wpabuf_head_u8(neighbor_rep);
+       len = wpabuf_len(neighbor_rep);
+
+       while (len >= 2 + NR_IE_MIN_LEN) {
+               const u8 *nr;
+               char lci[256 * 2 + 1];
+               char civic[256 * 2 + 1];
+               u8 nr_len = data[1];
+               const u8 *pos = data, *end;
+
+               if (pos[0] != WLAN_EID_NEIGHBOR_REPORT ||
+                   nr_len < NR_IE_MIN_LEN) {
+                       wpa_printf(MSG_DEBUG,
+                                  "CTRL: Invalid Neighbor Report element: id=%u len=%u",
+                                  data[0], nr_len);
+                       goto out;
+               }
+
+               if (2U + nr_len > len) {
+                       wpa_printf(MSG_DEBUG,
+                                  "CTRL: Invalid Neighbor Report element: id=%u len=%zu nr_len=%u",
+                                  data[0], len, nr_len);
+                       goto out;
+               }
+               pos += 2;
+               end = pos + nr_len;
+
+               nr = pos;
+               pos += NR_IE_MIN_LEN;
+
+               lci[0] = '\0';
+               civic[0] = '\0';
+               while (end - pos > 2) {
+                       u8 s_id, s_len;
+
+                       s_id = *pos++;
+                       s_len = *pos++;
+                       if (s_len > end - pos)
+                               goto out;
+                       if (s_id == WLAN_EID_MEASURE_REPORT && s_len > 3) {
+                               /* Measurement Token[1] */
+                               /* Measurement Report Mode[1] */
+                               /* Measurement Type[1] */
+                               /* Measurement Report[variable] */
+                               switch (pos[2]) {
+                               case MEASURE_TYPE_LCI:
+                                       if (lci[0])
+                                               break;
+                                       wpa_snprintf_hex(lci, sizeof(lci),
+                                                        pos, s_len);
+                                       break;
+                               case MEASURE_TYPE_LOCATION_CIVIC:
+                                       if (civic[0])
+                                               break;
+                                       wpa_snprintf_hex(civic, sizeof(civic),
+                                                        pos, s_len);
+                                       break;
+                               }
+                       }
+
+                       pos += s_len;
+               }
+
+               wpa_msg(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_RXED
+                       "bssid=" MACSTR
+                       " info=0x%x op_class=%u chan=%u phy_type=%u%s%s%s%s",
+                       MAC2STR(nr), WPA_GET_LE32(nr + ETH_ALEN),
+                       nr[ETH_ALEN + 4], nr[ETH_ALEN + 5],
+                       nr[ETH_ALEN + 6],
+                       lci[0] ? " lci=" : "", lci,
+                       civic[0] ? " civic=" : "", civic);
+
+               data = end;
+               len -= 2 + nr_len;
        }
+
+out:
+       wpabuf_free(neighbor_rep);
 }
 
 
-static int wpas_ctrl_iface_send_neigbor_rep(struct wpa_supplicant *wpa_s,
-                                           char *cmd)
+static int wpas_ctrl_iface_send_neighbor_rep(struct wpa_supplicant *wpa_s,
+                                            char *cmd)
 {
-       struct wpa_ssid ssid;
-       struct wpa_ssid *ssid_p = NULL;
-       int ret = 0;
+       struct wpa_ssid_value ssid, *ssid_p = NULL;
+       int ret, lci = 0, civic = 0;
+       char *ssid_s;
 
-       if (os_strncmp(cmd, " ssid=", 6) == 0) {
-               ssid.ssid_len = os_strlen(cmd + 6);
-               if (ssid.ssid_len > SSID_MAX_LEN)
+       ssid_s = os_strstr(cmd, "ssid=");
+       if (ssid_s) {
+               if (ssid_parse(ssid_s + 5, &ssid)) {
+                       wpa_printf(MSG_ERROR,
+                                  "CTRL: Send Neighbor Report: bad SSID");
                        return -1;
-               ssid.ssid = (u8 *) (cmd + 6);
+               }
+
                ssid_p = &ssid;
+
+               /*
+                * Move cmd after the SSID text that may include "lci" or
+                * "civic".
+                */
+               cmd = os_strchr(ssid_s + 6, ssid_s[5] == '"' ? '"' : ' ');
+               if (cmd)
+                       cmd++;
+
        }
 
-       ret = wpas_rrm_send_neighbor_rep_request(wpa_s, ssid_p,
+       if (cmd && os_strstr(cmd, "lci"))
+               lci = 1;
+
+       if (cmd && os_strstr(cmd, "civic"))
+               civic = 1;
+
+       ret = wpas_rrm_send_neighbor_rep_request(wpa_s, ssid_p, lci, civic,
                                                 wpas_ctrl_neighbor_rep_cb,
                                                 wpa_s);
 
@@ -8062,10 +8575,7 @@ static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s,
                        }
                } else if (wpa_s->sched_scanning &&
                           (type & MAC_ADDR_RAND_SCHED_SCAN)) {
-                       /* simulate timeout to restart the sched scan */
-                       wpa_s->sched_scan_timed_out = 1;
-                       wpa_s->prev_sched_ssid = NULL;
-                       wpa_supplicant_cancel_sched_scan(wpa_s);
+                       wpas_scan_restart_sched_scan(wpa_s);
                }
                return 0;
        }
@@ -8091,12 +8601,8 @@ static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s,
                wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN,
                                            addr, mask);
 
-               if (wpa_s->sched_scanning && !wpa_s->pno) {
-                       /* simulate timeout to restart the sched scan */
-                       wpa_s->sched_scan_timed_out = 1;
-                       wpa_s->prev_sched_ssid = NULL;
-                       wpa_supplicant_cancel_sched_scan(wpa_s);
-               }
+               if (wpa_s->sched_scanning && !wpa_s->pno)
+                       wpas_scan_restart_sched_scan(wpa_s);
        }
 
        if (type & MAC_ADDR_RAND_PNO) {
@@ -8112,6 +8618,29 @@ static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s,
 }
 
 
+static int wpas_ctrl_iface_pmksa(struct wpa_supplicant *wpa_s,
+                                char *buf, size_t buflen)
+{
+       size_t reply_len;
+
+       reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, buf, buflen);
+#ifdef CONFIG_AP
+       reply_len += wpas_ap_pmksa_cache_list(wpa_s, &buf[reply_len],
+                                             buflen - reply_len);
+#endif /* CONFIG_AP */
+       return reply_len;
+}
+
+
+static void wpas_ctrl_iface_pmksa_flush(struct wpa_supplicant *wpa_s)
+{
+       wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
+#ifdef CONFIG_AP
+       wpas_ap_pmksa_cache_flush(wpa_s);
+#endif /* CONFIG_AP */
+}
+
+
 static int wpas_ctrl_cmd_debug_level(const char *cmd)
 {
        if (os_strcmp(cmd, "PING") == 0 ||
@@ -8183,10 +8712,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                reply_len = wpa_supplicant_ctrl_iface_status(
                        wpa_s, buf + 6, reply, reply_size);
        } else if (os_strcmp(buf, "PMKSA") == 0) {
-               reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, reply,
-                                                   reply_size);
+               reply_len = wpas_ctrl_iface_pmksa(wpa_s, reply, reply_size);
        } else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) {
-               wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
+               wpas_ctrl_iface_pmksa_flush(wpa_s);
        } else if (os_strncmp(buf, "SET ", 4) == 0) {
                if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
                        reply_len = -1;
@@ -8354,6 +8882,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                if (wpa_supplicant_ctrl_iface_mesh_group_remove(wpa_s,
                                                                buf + 18))
                        reply_len = -1;
+       } else if (os_strncmp(buf, "MESH_PEER_REMOVE ", 17) == 0) {
+               if (wpa_supplicant_ctrl_iface_mesh_peer_remove(wpa_s, buf + 17))
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "MESH_PEER_ADD ", 14) == 0) {
+               if (wpa_supplicant_ctrl_iface_mesh_peer_add(wpa_s, buf + 14))
+                       reply_len = -1;
 #endif /* CONFIG_MESH */
 #ifdef CONFIG_P2P
        } else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) {
@@ -8388,6 +8922,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) {
                if (p2p_ctrl_group_add(wpa_s, buf + 14))
                        reply_len = -1;
+       } else if (os_strncmp(buf, "P2P_GROUP_MEMBER ", 17) == 0) {
+               reply_len = p2p_ctrl_group_member(wpa_s, buf + 17, reply,
+                                                 reply_size);
        } else if (os_strncmp(buf, "P2P_PROV_DISC ", 14) == 0) {
                if (p2p_ctrl_prov_disc(wpa_s, buf + 14))
                        reply_len = -1;
@@ -8453,6 +8990,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strncmp(buf, "P2P_REMOVE_CLIENT ", 18) == 0) {
                if (p2p_ctrl_remove_client(wpa_s, buf + 18) < 0)
                        reply_len = -1;
+       } else if (os_strncmp(buf, "P2P_LO_START ", 13) == 0) {
+               if (p2p_ctrl_iface_p2p_lo_start(wpa_s, buf + 13))
+                       reply_len = -1;
+       } else if (os_strcmp(buf, "P2P_LO_STOP") == 0) {
+               if (wpas_p2p_lo_stop(wpa_s))
+                       reply_len = -1;
 #endif /* CONFIG_P2P */
 #ifdef CONFIG_WIFI_DISPLAY
        } else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) {
@@ -8506,10 +9049,21 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                if (hs20_get_nai_home_realm_list(wpa_s, buf + 29) < 0)
                        reply_len = -1;
        } else if (os_strncmp(buf, "HS20_ICON_REQUEST ", 18) == 0) {
-               if (hs20_icon_request(wpa_s, buf + 18) < 0)
+               if (hs20_icon_request(wpa_s, buf + 18, 0) < 0)
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "REQ_HS20_ICON ", 14) == 0) {
+               if (hs20_icon_request(wpa_s, buf + 14, 1) < 0)
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "GET_HS20_ICON ", 14) == 0) {
+               reply_len = get_hs20_icon(wpa_s, buf + 14, reply, reply_size);
+       } else if (os_strncmp(buf, "DEL_HS20_ICON ", 14) == 0) {
+               if (del_hs20_icon(wpa_s, buf + 14) < 0)
                        reply_len = -1;
        } else if (os_strcmp(buf, "FETCH_OSU") == 0) {
-               if (hs20_fetch_osu(wpa_s) < 0)
+               if (hs20_fetch_osu(wpa_s, 0) < 0)
+                       reply_len = -1;
+       } else if (os_strcmp(buf, "FETCH_OSU no-scan") == 0) {
+               if (hs20_fetch_osu(wpa_s, 1) < 0)
                        reply_len = -1;
        } else if (os_strcmp(buf, "CANCEL_FETCH_OSU") == 0) {
                hs20_cancel_fetch_osu(wpa_s);
@@ -8548,16 +9102,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                reply_len = wpa_supplicant_ctrl_iface_list_networks(
                        wpa_s, NULL, reply, reply_size);
        } else if (os_strcmp(buf, "DISCONNECT") == 0) {
-#ifdef CONFIG_SME
-               wpa_s->sme.prev_bssid_set = 0;
-#endif /* CONFIG_SME */
-               wpa_s->reassociate = 0;
-               wpa_s->disconnected = 1;
-               wpa_supplicant_cancel_sched_scan(wpa_s);
-               wpa_supplicant_cancel_scan(wpa_s);
-               wpa_supplicant_deauthenticate(wpa_s,
-                                             WLAN_REASON_DEAUTH_LEAVING);
-               eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+               wpas_request_disconnection(wpa_s);
        } else if (os_strcmp(buf, "SCAN") == 0) {
                wpas_ctrl_scan(wpa_s, NULL, reply, reply_size, &reply_len);
        } else if (os_strncmp(buf, "SCAN ", 5) == 0) {
@@ -8565,6 +9110,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
                reply_len = wpa_supplicant_ctrl_iface_scan_results(
                        wpa_s, reply, reply_size);
+       } else if (os_strcmp(buf, "ABORT_SCAN") == 0) {
+               if (wpas_abort_ongoing_scan(wpa_s) < 0)
+                       reply_len = -1;
        } else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) {
                if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15))
                        reply_len = -1;
@@ -8623,9 +9171,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
                reply_len = wpa_supplicant_global_iface_list(
                        wpa_s->global, reply, reply_size);
-       } else if (os_strcmp(buf, "INTERFACES") == 0) {
+       } else if (os_strncmp(buf, "INTERFACES", 10) == 0) {
                reply_len = wpa_supplicant_global_iface_interfaces(
-                       wpa_s->global, reply, reply_size);
+                       wpa_s->global, buf + 10, reply, reply_size);
        } else if (os_strncmp(buf, "BSS ", 4) == 0) {
                reply_len = wpa_supplicant_ctrl_iface_bss(
                        wpa_s, buf + 4, reply, reply_size);
@@ -8706,6 +9254,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strncmp(buf, "SIGNAL_POLL", 11) == 0) {
                reply_len = wpa_supplicant_signal_poll(wpa_s, reply,
                                                       reply_size);
+       } else if (os_strncmp(buf, "SIGNAL_MONITOR", 14) == 0) {
+               if (wpas_ctrl_iface_signal_monitor(wpa_s, buf + 14))
+                       reply_len = -1;
        } else if (os_strncmp(buf, "PKTCNT_POLL", 11) == 0) {
                reply_len = wpa_supplicant_pktcnt_poll(wpa_s, reply,
                                                       reply_size);
@@ -8714,6 +9265,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                if (wpa_supplicant_ctrl_iface_autoscan(wpa_s, buf + 9))
                        reply_len = -1;
 #endif /* CONFIG_AUTOSCAN */
+       } else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) {
+               reply_len = wpas_ctrl_iface_driver_flags(wpa_s, reply,
+                                                        reply_size);
 #ifdef ANDROID
        } else if (os_strncmp(buf, "DRIVER ", 7) == 0) {
                reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply,
@@ -8744,6 +9298,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                        reply_len = -1;
        } else if (os_strcmp(buf, "MGMT_TX_DONE") == 0) {
                wpas_ctrl_iface_mgmt_tx_done(wpa_s);
+       } else if (os_strncmp(buf, "MGMT_RX_PROCESS ", 16) == 0) {
+               if (wpas_ctrl_iface_mgmt_rx_process(wpa_s, buf + 16) < 0)
+                       reply_len = -1;
        } else if (os_strncmp(buf, "DRIVER_EVENT ", 13) == 0) {
                if (wpas_ctrl_iface_driver_event(wpa_s, buf + 13) < 0)
                        reply_len = -1;
@@ -8769,6 +9326,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                        reply_len = -1;
        } else if (os_strcmp(buf, "GET_FAIL") == 0) {
                reply_len = wpas_ctrl_get_fail(wpa_s, reply, reply_size);
+       } else if (os_strncmp(buf, "EVENT_TEST ", 11) == 0) {
+               if (wpas_ctrl_event_test(wpa_s, buf + 11) < 0)
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "TEST_ASSOC_IE ", 14) == 0) {
+               if (wpas_ctrl_test_assoc_ie(wpa_s, buf + 14) < 0)
+                       reply_len = -1;
 #endif /* CONFIG_TESTING_OPTIONS */
        } else if (os_strncmp(buf, "VENDOR_ELEM_ADD ", 16) == 0) {
                if (wpas_ctrl_vendor_elem_add(wpa_s, buf + 16) < 0)
@@ -8780,7 +9343,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                if (wpas_ctrl_vendor_elem_remove(wpa_s, buf + 19) < 0)
                        reply_len = -1;
        } else if (os_strncmp(buf, "NEIGHBOR_REP_REQUEST", 20) == 0) {
-               if (wpas_ctrl_iface_send_neigbor_rep(wpa_s, buf + 20))
+               if (wpas_ctrl_iface_send_neighbor_rep(wpa_s, buf + 20))
                        reply_len = -1;
        } else if (os_strcmp(buf, "ERP_FLUSH") == 0) {
                wpas_ctrl_iface_erp_flush(wpa_s);
@@ -8813,10 +9376,11 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global,
        struct wpa_supplicant *wpa_s;
        unsigned int create_iface = 0;
        u8 mac_addr[ETH_ALEN];
+       enum wpa_driver_if_type type = WPA_IF_STATION;
 
        /*
         * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param>
-        * TAB<bridge_ifname>[TAB<create>]
+        * TAB<bridge_ifname>[TAB<create>[TAB<interface_type>]]
         */
        wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd);
 
@@ -8884,9 +9448,22 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global,
                if (!extra[0])
                        break;
 
-               if (os_strcmp(extra, "create") == 0)
+               if (os_strcmp(extra, "create") == 0) {
                        create_iface = 1;
-               else {
+                       if (!pos)
+                               break;
+
+                       if (os_strcmp(pos, "sta") == 0) {
+                               type = WPA_IF_STATION;
+                       } else if (os_strcmp(pos, "ap") == 0) {
+                               type = WPA_IF_AP_BSS;
+                       } else {
+                               wpa_printf(MSG_DEBUG,
+                                          "INTERFACE_ADD unsupported interface type: '%s'",
+                                          pos);
+                               return -1;
+                       }
+               } else {
                        wpa_printf(MSG_DEBUG,
                                   "INTERFACE_ADD unsupported extra parameter: '%s'",
                                   extra);
@@ -8899,7 +9476,7 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global,
                           iface.ifname);
                if (!global->ifaces)
                        return -1;
-               if (wpa_drv_if_add(global->ifaces, WPA_IF_STATION, iface.ifname,
+               if (wpa_drv_if_add(global->ifaces, type, iface.ifname,
                                   NULL, NULL, NULL, mac_addr, NULL) < 0) {
                        wpa_printf(MSG_ERROR,
                                   "CTRL_IFACE interface creation failed");
@@ -9008,18 +9585,31 @@ static int wpa_supplicant_global_iface_list(struct wpa_global *global,
 
 
 static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
+                                                 const char *input,
                                                  char *buf, int len)
 {
        int res;
        char *pos, *end;
        struct wpa_supplicant *wpa_s;
+       int show_ctrl = 0;
+
+       if (input)
+               show_ctrl = !!os_strstr(input, "ctrl");
 
        wpa_s = global->ifaces;
        pos = buf;
        end = buf + len;
 
        while (wpa_s) {
-               res = os_snprintf(pos, end - pos, "%s\n", wpa_s->ifname);
+               if (show_ctrl)
+                       res = os_snprintf(pos, end - pos, "%s ctrl_iface=%s\n",
+                                         wpa_s->ifname,
+                                         wpa_s->conf->ctrl_interface ?
+                                         wpa_s->conf->ctrl_interface : "N/A");
+               else
+                       res = os_snprintf(pos, end - pos, "%s\n",
+                                         wpa_s->ifname);
+
                if (os_snprintf_error(end - pos, res)) {
                        *pos = '\0';
                        break;
@@ -9085,6 +9675,7 @@ static char * wpas_global_ctrl_iface_redir_p2p(struct wpa_global *global,
                "P2P_LISTEN ",
                "P2P_GROUP_REMOVE ",
                "P2P_GROUP_ADD ",
+               "P2P_GROUP_MEMBER ",
                "P2P_PROV_DISC ",
                "P2P_SERV_DISC_REQ ",
                "P2P_SERV_DISC_CANCEL_REQ ",
@@ -9408,9 +9999,9 @@ char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
        } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
                reply_len = wpa_supplicant_global_iface_list(
                        global, reply, reply_size);
-       } else if (os_strcmp(buf, "INTERFACES") == 0) {
+       } else if (os_strncmp(buf, "INTERFACES", 10) == 0) {
                reply_len = wpa_supplicant_global_iface_interfaces(
-                       global, reply, reply_size);
+                       global, buf + 10, reply, reply_size);
 #ifdef CONFIG_FST
        } else if (os_strncmp(buf, "FST-ATTACH ", 11) == 0) {
                reply_len = wpas_global_ctrl_iface_fst_attach(global, buf + 11,
@@ -9456,7 +10047,6 @@ char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
                                                          reply_size);
 #ifdef CONFIG_MODULE_TESTS
        } else if (os_strcmp(buf, "MODULE_TESTS") == 0) {
-               int wpas_module_tests(void);
                if (wpas_module_tests() < 0)
                        reply_len = -1;
 #endif /* CONFIG_MODULE_TESTS */