QCA vendor command support to set band to driver
[mech_eap.git] / wpa_supplicant / ctrl_iface.c
index 34cbe74..41f9090 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / Control interface (shared code for all backends)
- * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -19,6 +19,7 @@
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
 #include "common/wpa_ctrl.h"
+#include "crypto/tls.h"
 #include "ap/hostapd.h"
 #include "eap_peer/eap.h"
 #include "eapol_supp/eapol_supp_sm.h"
@@ -27,6 +28,8 @@
 #include "rsn_supp/pmksa_cache.h"
 #include "l2_packet/l2_packet.h"
 #include "wps/wps.h"
+#include "fst/fst.h"
+#include "fst/fst_ctrl_iface.h"
 #include "config.h"
 #include "wpa_supplicant_i.h"
 #include "driver_i.h"
@@ -152,7 +155,8 @@ static int set_disallow_aps(struct wpa_supplicant *wpa_s, char *val)
                        }
                        ssid = ns;
 
-                       if ((end - pos) & 0x01 || end - pos > 2 * 32 ||
+                       if ((end - pos) & 0x01 ||
+                           end - pos > 2 * SSID_MAX_LEN ||
                            hexstr2bin(pos, ssid[ssid_count].ssid,
                                       (end - pos) / 2) < 0) {
                                os_free(ssid);
@@ -208,6 +212,7 @@ static int set_disallow_aps(struct wpa_supplicant *wpa_s, char *val)
        wpa_s->sme.prev_bssid_set = 0;
 #endif /* CONFIG_SME */
        wpa_s->reassociate = 1;
+       wpa_s->own_disconnect_req = 1;
        wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
        wpa_supplicant_req_scan(wpa_s, 0, 0);
 
@@ -281,6 +286,30 @@ static int wpas_ctrl_pno(struct wpa_supplicant *wpa_s, char *cmd)
 }
 
 
+static int wpas_ctrl_set_band(struct wpa_supplicant *wpa_s, char *band)
+{
+       union wpa_event_data event;
+
+       if (os_strcmp(band, "AUTO") == 0)
+               wpa_s->setband = WPA_SETBAND_AUTO;
+       else if (os_strcmp(band, "5G") == 0)
+               wpa_s->setband = WPA_SETBAND_5G;
+       else if (os_strcmp(band, "2G") == 0)
+               wpa_s->setband = WPA_SETBAND_2G;
+       else
+               return -1;
+
+       if (wpa_drv_setband(wpa_s, wpa_s->setband) == 0) {
+               os_memset(&event, 0, sizeof(event));
+               event.channel_list_changed.initiator = REGDOM_SET_BY_USER;
+               event.channel_list_changed.type = REGDOM_TYPE_UNKNOWN;
+               wpa_supplicant_event(wpa_s, EVENT_CHANNEL_LIST_CHANGED, &event);
+       }
+
+       return 0;
+}
+
+
 static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
                                         char *cmd)
 {
@@ -436,11 +465,15 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_AP */
        } else if (os_strcasecmp(cmd, "extra_roc_dur") == 0) {
                wpa_s->extra_roc_dur = atoi(value);
+       } else if (os_strcasecmp(cmd, "test_failure") == 0) {
+               wpa_s->test_failure = atoi(value);
 #endif /* CONFIG_TESTING_OPTIONS */
 #ifndef CONFIG_NO_CONFIG_BLOBS
        } else if (os_strcmp(cmd, "blob") == 0) {
                ret = wpas_ctrl_set_blob(wpa_s, value);
 #endif /* CONFIG_NO_CONFIG_BLOBS */
+       } else if (os_strcasecmp(cmd, "setband") == 0) {
+               ret = wpas_ctrl_set_band(wpa_s, value);
        } else {
                value[-1] = '=';
                ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
@@ -484,6 +517,10 @@ static int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s,
                                       wpa_s->last_gtk_len);
                return res;
 #endif /* CONFIG_TESTING_GET_GTK */
+       } else if (os_strcmp(cmd, "tls_library") == 0) {
+               res = tls_get_library_version(buf, buflen);
+       } else {
+               res = wpa_config_get_value(cmd, wpa_s->conf, buf, buflen);
        }
 
        if (os_snprintf_error(buflen, res))
@@ -644,6 +681,131 @@ static int ctrl_iface_get_capability_tdls(
        return ret;
 }
 
+
+static int wpa_supplicant_ctrl_iface_tdls_chan_switch(
+       struct wpa_supplicant *wpa_s, char *cmd)
+{
+       u8 peer[ETH_ALEN];
+       struct hostapd_freq_params freq_params;
+       u8 oper_class;
+       char *pos, *end;
+
+       if (!wpa_tdls_is_external_setup(wpa_s->wpa)) {
+               wpa_printf(MSG_INFO,
+                          "tdls_chanswitch: Only supported with external setup");
+               return -1;
+       }
+
+       os_memset(&freq_params, 0, sizeof(freq_params));
+
+       pos = os_strchr(cmd, ' ');
+       if (pos == NULL)
+               return -1;
+       *pos++ = '\0';
+
+       oper_class = strtol(pos, &end, 10);
+       if (pos == end) {
+               wpa_printf(MSG_INFO,
+                          "tdls_chanswitch: Invalid op class provided");
+               return -1;
+       }
+
+       pos = end;
+       freq_params.freq = atoi(pos);
+       if (freq_params.freq == 0) {
+               wpa_printf(MSG_INFO, "tdls_chanswitch: Invalid freq provided");
+               return -1;
+       }
+
+#define SET_FREQ_SETTING(str) \
+       do { \
+               const char *pos2 = os_strstr(pos, " " #str "="); \
+               if (pos2) { \
+                       pos2 += sizeof(" " #str "=") - 1; \
+                       freq_params.str = atoi(pos2); \
+               } \
+       } while (0)
+
+       SET_FREQ_SETTING(center_freq1);
+       SET_FREQ_SETTING(center_freq2);
+       SET_FREQ_SETTING(bandwidth);
+       SET_FREQ_SETTING(sec_channel_offset);
+#undef SET_FREQ_SETTING
+
+       freq_params.ht_enabled = !!os_strstr(pos, " ht");
+       freq_params.vht_enabled = !!os_strstr(pos, " vht");
+
+       if (hwaddr_aton(cmd, peer)) {
+               wpa_printf(MSG_DEBUG,
+                          "CTRL_IFACE TDLS_CHAN_SWITCH: Invalid address '%s'",
+                          cmd);
+               return -1;
+       }
+
+       wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_CHAN_SWITCH " MACSTR
+                  " OP CLASS %d FREQ %d CENTER1 %d CENTER2 %d BW %d SEC_OFFSET %d%s%s",
+                  MAC2STR(peer), oper_class, freq_params.freq,
+                  freq_params.center_freq1, freq_params.center_freq2,
+                  freq_params.bandwidth, freq_params.sec_channel_offset,
+                  freq_params.ht_enabled ? " HT" : "",
+                  freq_params.vht_enabled ? " VHT" : "");
+
+       return wpa_tdls_enable_chan_switch(wpa_s->wpa, peer, oper_class,
+                                          &freq_params);
+}
+
+
+static int wpa_supplicant_ctrl_iface_tdls_cancel_chan_switch(
+       struct wpa_supplicant *wpa_s, char *cmd)
+{
+       u8 peer[ETH_ALEN];
+
+       if (!wpa_tdls_is_external_setup(wpa_s->wpa)) {
+               wpa_printf(MSG_INFO,
+                          "tdls_chanswitch: Only supported with external setup");
+               return -1;
+       }
+
+       if (hwaddr_aton(cmd, peer)) {
+               wpa_printf(MSG_DEBUG,
+                          "CTRL_IFACE TDLS_CANCEL_CHAN_SWITCH: Invalid address '%s'",
+                          cmd);
+               return -1;
+       }
+
+       wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_CANCEL_CHAN_SWITCH " MACSTR,
+                  MAC2STR(peer));
+
+       return wpa_tdls_disable_chan_switch(wpa_s->wpa, peer);
+}
+
+
+static int wpa_supplicant_ctrl_iface_tdls_link_status(
+       struct wpa_supplicant *wpa_s, const char *addr,
+       char *buf, size_t buflen)
+{
+       u8 peer[ETH_ALEN];
+       const char *tdls_status;
+       int ret;
+
+       if (hwaddr_aton(addr, peer)) {
+               wpa_printf(MSG_DEBUG,
+                          "CTRL_IFACE TDLS_LINK_STATUS: Invalid address '%s'",
+                          addr);
+               return -1;
+       }
+       wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_LINK_STATUS " MACSTR,
+                  MAC2STR(peer));
+
+       tdls_status = wpa_tdls_get_link_status(wpa_s->wpa, peer);
+       wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_LINK_STATUS: %s", tdls_status);
+       ret = os_snprintf(buf, buflen, "TDLS link status: %s\n", tdls_status);
+       if (os_snprintf_error(buflen, ret))
+               return -1;
+
+       return ret;
+}
+
 #endif /* CONFIG_TDLS */
 
 
@@ -1589,6 +1751,8 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
 #ifdef CONFIG_HS20
        const u8 *hs20;
 #endif /* CONFIG_HS20 */
+       const u8 *sess_id;
+       size_t sess_id_len;
 
        if (os_strcmp(params, "-DRIVER") == 0)
                return wpa_drv_status(wpa_s, buf, buflen);
@@ -1611,7 +1775,7 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
                if (ssid) {
                        u8 *_ssid = ssid->ssid;
                        size_t ssid_len = ssid->ssid_len;
-                       u8 ssid_buf[MAX_SSID_LEN];
+                       u8 ssid_buf[SSID_MAX_LEN];
                        if (ssid_len == 0) {
                                int _res = wpa_drv_get_ssid(wpa_s, ssid_buf);
                                if (_res < 0)
@@ -1821,6 +1985,24 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
                        pos += res;
        }
 
+       sess_id = eapol_sm_get_session_id(wpa_s->eapol, &sess_id_len);
+       if (sess_id) {
+               char *start = pos;
+
+               ret = os_snprintf(pos, end - pos, "eap_session_id=");
+               if (os_snprintf_error(end - pos, ret))
+                       return start - buf;
+               pos += ret;
+               ret = wpa_snprintf_hex(pos, end - pos, sess_id, sess_id_len);
+               if (ret <= 0)
+                       return start - buf;
+               pos += ret;
+               ret = os_snprintf(pos, end - pos, "\n");
+               if (os_snprintf_error(end - pos, ret))
+                       return start - buf;
+               pos += ret;
+       }
+
        res = rsn_preauth_get_status(wpa_s->wpa, pos, end - pos, verbose);
        if (res >= 0)
                pos += res;
@@ -2211,6 +2393,7 @@ static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
        }
 #endif /* CONFIG_IEEE80211W */
 
+#ifdef CONFIG_SUITEB
        if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
                ret = os_snprintf(pos, end - pos, "%sEAP-SUITE-B",
                                  pos == start ? "" : "+");
@@ -2218,6 +2401,25 @@ static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
                        return pos;
                pos += ret;
        }
+#endif /* CONFIG_SUITEB */
+
+#ifdef CONFIG_SUITEB192
+       if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+               ret = os_snprintf(pos, end - pos, "%sEAP-SUITE-B-192",
+                                 pos == start ? "" : "+");
+               if (os_snprintf_error(end - pos, ret))
+                       return pos;
+               pos += ret;
+       }
+#endif /* CONFIG_SUITEB192 */
+
+       if (data.key_mgmt & WPA_KEY_MGMT_OSEN) {
+               ret = os_snprintf(pos, end - pos, "%sOSEN",
+                                 pos == start ? "" : "+");
+               if (os_snprintf_error(end - pos, ret))
+                       return pos;
+               pos += ret;
+       }
 
        pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher);
 
@@ -2286,7 +2488,7 @@ static int wpa_supplicant_ctrl_iface_scan_result(
 {
        char *pos, *end;
        int ret;
-       const u8 *ie, *ie2, *p2p, *mesh;
+       const u8 *ie, *ie2, *osen_ie, *p2p, *mesh;
 
        mesh = wpa_bss_get_ie(bss, WLAN_EID_MESH_ID);
        p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
@@ -2313,8 +2515,12 @@ static int wpa_supplicant_ctrl_iface_scan_result(
                pos = wpa_supplicant_ie_txt(pos, end, mesh ? "RSN" : "WPA2",
                                            ie2, 2 + ie2[1]);
        }
+       osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
+       if (osen_ie)
+               pos = wpa_supplicant_ie_txt(pos, end, "OSEN",
+                                           osen_ie, 2 + osen_ie[1]);
        pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
-       if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
+       if (!ie && !ie2 && !osen_ie && (bss->caps & IEEE80211_CAP_PRIVACY)) {
                ret = os_snprintf(pos, end - pos, "[WEP]");
                if (os_snprintf_error(end - pos, ret))
                        return -1;
@@ -2378,6 +2584,14 @@ static int wpa_supplicant_ctrl_iface_scan_result(
                pos += ret;
        }
 #endif /* CONFIG_HS20 */
+#ifdef CONFIG_FST
+       if (wpa_bss_get_ie(bss, WLAN_EID_MULTI_BAND)) {
+               ret = os_snprintf(pos, end - pos, "[FST]");
+               if (os_snprintf_error(end - pos, ret))
+                       return -1;
+               pos += ret;
+       }
+#endif /* CONFIG_FST */
 
        ret = os_snprintf(pos, end - pos, "\t%s",
                          wpa_ssid_txt(bss->ssid, bss->ssid_len));
@@ -2423,6 +2637,27 @@ static int wpa_supplicant_ctrl_iface_scan_results(
 
 #ifdef CONFIG_MESH
 
+static int wpa_supplicant_ctrl_iface_mesh_interface_add(
+       struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
+{
+       char *pos, ifname[IFNAMSIZ + 1];
+
+       ifname[0] = '\0';
+
+       pos = os_strstr(cmd, "ifname=");
+       if (pos) {
+               pos += 7;
+               os_strlcpy(ifname, pos, sizeof(ifname));
+       }
+
+       if (wpas_mesh_add_interface(wpa_s, ifname, sizeof(ifname)) < 0)
+               return -1;
+
+       os_strlcpy(reply, ifname, max_len);
+       return os_strlen(ifname);
+}
+
+
 static int wpa_supplicant_ctrl_iface_mesh_group_add(
        struct wpa_supplicant *wpa_s, char *cmd)
 {
@@ -2463,17 +2698,32 @@ static int wpa_supplicant_ctrl_iface_mesh_group_add(
 static int wpa_supplicant_ctrl_iface_mesh_group_remove(
        struct wpa_supplicant *wpa_s, char *cmd)
 {
-       /*
-        * TODO: Support a multiple mesh and other iface type combinations
-        */
-       if (os_strcmp(cmd, wpa_s->ifname) != 0) {
-               wpa_printf(MSG_DEBUG,
-                          "CTRL_IFACE: MESH_GROUP_REMOVE unknown interface name: %s",
+       struct wpa_supplicant *orig;
+       struct wpa_global *global;
+       int found = 0;
+
+       wpa_printf(MSG_DEBUG, "CTRL_IFACE: MESH_GROUP_REMOVE ifname=%s", cmd);
+
+       global = wpa_s->global;
+       orig = wpa_s;
+
+       for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+               if (os_strcmp(wpa_s->ifname, cmd) == 0) {
+                       found = 1;
+                       break;
+               }
+       }
+       if (!found) {
+               wpa_printf(MSG_ERROR,
+                          "CTRL_IFACE: MESH_GROUP_REMOVE ifname=%s not found",
                           cmd);
                return -1;
        }
-
-       wpa_printf(MSG_DEBUG, "CTRL_IFACE: MESH_GROUP_REMOVE ifname=%s", cmd);
+       if (wpa_s->mesh_if_created && wpa_s == orig) {
+               wpa_printf(MSG_ERROR,
+                          "CTRL_IFACE: MESH_GROUP_REMOVE can't remove itself");
+               return -1;
+       }
 
        wpa_s->reassociate = 0;
        wpa_s->disconnected = 1;
@@ -2486,6 +2736,9 @@ static int wpa_supplicant_ctrl_iface_mesh_group_remove(
         */
        wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
 
+       if (wpa_s->mesh_if_created)
+               wpa_supplicant_remove_iface(global, wpa_s, 0);
+
        return 0;
 }
 
@@ -2650,6 +2903,8 @@ static int wpa_supplicant_ctrl_iface_remove_network(
 #endif /* CONFIG_SME */
                        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);
                }
@@ -2696,6 +2951,8 @@ static int wpa_supplicant_ctrl_iface_remove_network(
                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);
        }
@@ -2747,8 +3004,6 @@ static int wpa_supplicant_ctrl_iface_update_network(
                wpa_config_update_psk(ssid);
        else if (os_strcmp(name, "priority") == 0)
                wpa_config_update_prio_list(wpa_s->conf);
-       else if (os_strcmp(name, "no_auto_peer") == 0)
-               ssid->no_auto_peer = atoi(value);
 
        return 0;
 }
@@ -2757,7 +3012,7 @@ static int wpa_supplicant_ctrl_iface_update_network(
 static int wpa_supplicant_ctrl_iface_set_network(
        struct wpa_supplicant *wpa_s, char *cmd)
 {
-       int id, ret, prev_bssid_set;
+       int id, ret, prev_bssid_set, prev_disabled;
        struct wpa_ssid *ssid;
        char *name, *value;
        u8 prev_bssid[ETH_ALEN];
@@ -2787,6 +3042,7 @@ static int wpa_supplicant_ctrl_iface_set_network(
        }
 
        prev_bssid_set = ssid->bssid_set;
+       prev_disabled = ssid->disabled;
        os_memcpy(prev_bssid, ssid->bssid, ETH_ALEN);
        ret = wpa_supplicant_ctrl_iface_update_network(wpa_s, ssid, name,
                                                       value);
@@ -2794,6 +3050,11 @@ static int wpa_supplicant_ctrl_iface_set_network(
            (ssid->bssid_set != prev_bssid_set ||
             os_memcmp(ssid->bssid, prev_bssid, ETH_ALEN) != 0))
                wpas_notify_network_bssid_set_changed(wpa_s, ssid);
+
+       if (prev_disabled != ssid->disabled &&
+           (prev_disabled == 2 || ssid->disabled == 2))
+               wpas_notify_network_type_changed(wpa_s, ssid);
+
        return ret;
 }
 
@@ -2843,7 +3104,8 @@ static int wpa_supplicant_ctrl_iface_get_network(
 
 
 static int wpa_supplicant_ctrl_iface_dup_network(
-       struct wpa_supplicant *wpa_s, char *cmd)
+       struct wpa_supplicant *wpa_s, char *cmd,
+       struct wpa_supplicant *dst_wpa_s)
 {
        struct wpa_ssid *ssid_s, *ssid_d;
        char *name, *id, *value;
@@ -2862,8 +3124,10 @@ static int wpa_supplicant_ctrl_iface_dup_network(
 
        id_s = atoi(cmd);
        id_d = atoi(id);
-       wpa_printf(MSG_DEBUG, "CTRL_IFACE: DUP_NETWORK id=%d -> %d name='%s'",
-                  id_s, id_d, name);
+
+       wpa_printf(MSG_DEBUG,
+                  "CTRL_IFACE: DUP_NETWORK ifname=%s->%s id=%d->%d name='%s'",
+                  wpa_s->ifname, dst_wpa_s->ifname, id_s, id_d, name);
 
        ssid_s = wpa_config_get_network(wpa_s->conf, id_s);
        if (ssid_s == NULL) {
@@ -2872,7 +3136,7 @@ static int wpa_supplicant_ctrl_iface_dup_network(
                return -1;
        }
 
-       ssid_d = wpa_config_get_network(wpa_s->conf, id_d);
+       ssid_d = wpa_config_get_network(dst_wpa_s->conf, id_d);
        if (ssid_d == NULL) {
                wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
                           "network id=%d", id_d);
@@ -2886,7 +3150,7 @@ static int wpa_supplicant_ctrl_iface_dup_network(
                return -1;
        }
 
-       ret = wpa_supplicant_ctrl_iface_update_network(wpa_s, ssid_d, name,
+       ret = wpa_supplicant_ctrl_iface_update_network(dst_wpa_s, ssid_d, name,
                                                       value);
 
        os_free(value);
@@ -3182,6 +3446,13 @@ static const struct cipher_info ciphers[] = {
        { WPA_DRIVER_CAPA_ENC_WEP40, "WEP40", 1 }
 };
 
+static const struct cipher_info ciphers_group_mgmt[] = {
+       { WPA_DRIVER_CAPA_ENC_BIP, "AES-128-CMAC", 1 },
+       { WPA_DRIVER_CAPA_ENC_BIP_GMAC_128, "BIP-GMAC-128", 1 },
+       { WPA_DRIVER_CAPA_ENC_BIP_GMAC_256, "BIP-GMAC-256", 1 },
+       { WPA_DRIVER_CAPA_ENC_BIP_CMAC_256, "BIP-CMAC-256", 1 },
+};
+
 
 static int ctrl_iface_get_capability_pairwise(int res, char *strict,
                                              struct wpa_driver_capa *capa,
@@ -3255,6 +3526,35 @@ static int ctrl_iface_get_capability_group(int res, char *strict,
 }
 
 
+static int ctrl_iface_get_capability_group_mgmt(int res, char *strict,
+                                               struct wpa_driver_capa *capa,
+                                               char *buf, size_t buflen)
+{
+       int ret;
+       char *pos, *end;
+       unsigned int i;
+
+       pos = buf;
+       end = pos + buflen;
+
+       if (res < 0)
+               return 0;
+
+       for (i = 0; i < ARRAY_SIZE(ciphers_group_mgmt); i++) {
+               if (capa->enc & ciphers_group_mgmt[i].capa) {
+                       ret = os_snprintf(pos, end - pos, "%s%s",
+                                         pos == buf ? "" : " ",
+                                         ciphers_group_mgmt[i].name);
+                       if (os_snprintf_error(end - pos, ret))
+                               return pos - buf;
+                       pos += ret;
+               }
+       }
+
+       return pos - buf;
+}
+
+
 static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
                                              struct wpa_driver_capa *capa,
                                              char *buf, size_t buflen)
@@ -3304,6 +3604,23 @@ static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
                pos += ret;
        }
 
+#ifdef CONFIG_SUITEB
+       if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B) {
+               ret = os_snprintf(pos, end - pos, " WPA-EAP-SUITE-B");
+               if (os_snprintf_error(end - pos, ret))
+                       return pos - buf;
+               pos += ret;
+       }
+#endif /* CONFIG_SUITEB */
+#ifdef CONFIG_SUITEB192
+       if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192) {
+               ret = os_snprintf(pos, end - pos, " WPA-EAP-SUITE-B-192");
+               if (os_snprintf_error(end - pos, ret))
+                       return pos - buf;
+               pos += ret;
+       }
+#endif /* CONFIG_SUITEB192 */
+
        return pos - buf;
 }
 
@@ -3350,7 +3667,8 @@ static int ctrl_iface_get_capability_proto(int res, char *strict,
 }
 
 
-static int ctrl_iface_get_capability_auth_alg(int res, char *strict,
+static int ctrl_iface_get_capability_auth_alg(struct wpa_supplicant *wpa_s,
+                                             int res, char *strict,
                                              struct wpa_driver_capa *capa,
                                              char *buf, size_t buflen)
 {
@@ -3394,6 +3712,16 @@ static int ctrl_iface_get_capability_auth_alg(int res, char *strict,
                pos += ret;
        }
 
+#ifdef CONFIG_SAE
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE) {
+               ret = os_snprintf(pos, end - pos, "%sSAE",
+                                 pos == buf ? "" : " ");
+               if (os_snprintf_error(end - pos, ret))
+                       return pos - buf;
+               pos += ret;
+       }
+#endif /* CONFIG_SAE */
+
        return pos - buf;
 }
 
@@ -3434,6 +3762,16 @@ static int ctrl_iface_get_capability_modes(int res, char *strict,
                pos += ret;
        }
 
+#ifdef CONFIG_MESH
+       if (capa->flags & WPA_DRIVER_FLAGS_MESH) {
+               ret = os_snprintf(pos, end - pos, "%sMESH",
+                                 pos == buf ? "" : " ");
+               if (os_snprintf_error(end - pos, ret))
+                       return pos - buf;
+               pos += ret;
+       }
+#endif /* CONFIG_MESH */
+
        return pos - buf;
 }
 
@@ -3583,6 +3921,10 @@ static int wpa_supplicant_ctrl_iface_get_capability(
                return ctrl_iface_get_capability_group(res, strict, &capa,
                                                       buf, buflen);
 
+       if (os_strcmp(field, "group_mgmt") == 0)
+               return ctrl_iface_get_capability_group_mgmt(res, strict, &capa,
+                                                           buf, buflen);
+
        if (os_strcmp(field, "key_mgmt") == 0)
                return ctrl_iface_get_capability_key_mgmt(res, strict, &capa,
                                                          buf, buflen);
@@ -3592,8 +3934,8 @@ static int wpa_supplicant_ctrl_iface_get_capability(
                                                       buf, buflen);
 
        if (os_strcmp(field, "auth_alg") == 0)
-               return ctrl_iface_get_capability_auth_alg(res, strict, &capa,
-                                                         buf, buflen);
+               return ctrl_iface_get_capability_auth_alg(wpa_s, res, strict,
+                                                         &capa, buf, buflen);
 
        if (os_strcmp(field, "modes") == 0)
                return ctrl_iface_get_capability_modes(res, strict, &capa,
@@ -3667,7 +4009,7 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
        size_t i;
        int ret;
        char *pos, *end;
-       const u8 *ie, *ie2;
+       const u8 *ie, *ie2, *osen_ie;
 
        pos = buf;
        end = buf + buflen;
@@ -3784,8 +4126,13 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
                if (ie2)
                        pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2,
                                                    2 + ie2[1]);
+               osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
+               if (osen_ie)
+                       pos = wpa_supplicant_ie_txt(pos, end, "OSEN",
+                                                   osen_ie, 2 + osen_ie[1]);
                pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
-               if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
+               if (!ie && !ie2 && !osen_ie &&
+                   (bss->caps & IEEE80211_CAP_PRIVACY)) {
                        ret = os_snprintf(pos, end - pos, "[WEP]");
                        if (os_snprintf_error(end - pos, ret))
                                return 0;
@@ -3909,6 +4256,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;
+               pos = anqp_add_hex(pos, end, "anqp_capability_list",
+                                  anqp->capability_list);
                pos = anqp_add_hex(pos, end, "anqp_venue_name",
                                   anqp->venue_name);
                pos = anqp_add_hex(pos, end, "anqp_network_auth_type",
@@ -3923,6 +4272,8 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
                pos = anqp_add_hex(pos, end, "anqp_domain_name",
                                   anqp->domain_name);
 #ifdef CONFIG_HS20
+               pos = anqp_add_hex(pos, end, "hs20_capability_list",
+                                  anqp->hs20_capability_list);
                pos = anqp_add_hex(pos, end, "hs20_operator_friendly_name",
                                   anqp->hs20_operator_friendly_name);
                pos = anqp_add_hex(pos, end, "hs20_wan_metrics",
@@ -3947,6 +4298,30 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
        }
 #endif /* CONFIG_MESH */
 
+       if (mask & WPA_BSS_MASK_SNR) {
+               ret = os_snprintf(pos, end - pos, "snr=%d\n", bss->snr);
+               if (os_snprintf_error(end - pos, ret))
+                       return 0;
+               pos += ret;
+       }
+
+       if (mask & WPA_BSS_MASK_EST_THROUGHPUT) {
+               ret = os_snprintf(pos, end - pos, "est_throughput=%d\n",
+                                 bss->est_throughput);
+               if (os_snprintf_error(end - pos, ret))
+                       return 0;
+               pos += ret;
+       }
+
+#ifdef CONFIG_FST
+       if (mask & WPA_BSS_MASK_FST) {
+               ret = fst_ctrl_iface_mb_info(bss->bssid, pos, end - pos);
+               if (ret < 0 || ret >= end - pos)
+                       return 0;
+               pos += ret;
+       }
+#endif /* CONFIG_FST */
+
        if (mask & WPA_BSS_MASK_DELIM) {
                ret = os_snprintf(pos, end - pos, "====\n");
                if (os_snprintf_error(end - pos, ret))
@@ -4222,6 +4597,9 @@ static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd)
        u8 dev_type[WPS_DEV_TYPE_LEN], *_dev_type = NULL;
        char *pos;
        unsigned int search_delay;
+       const char *_seek[P2P_MAX_QUERY_HASH + 1], **seek = NULL;
+       u8 seek_count = 0;
+       int freq = 0;
 
        if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
                wpa_dbg(wpa_s, MSG_INFO,
@@ -4256,41 +4634,281 @@ static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd)
        } else
                search_delay = wpas_p2p_search_delay(wpa_s);
 
+       pos = os_strstr(cmd, "freq=");
+       if (pos) {
+               pos += 5;
+               freq = atoi(pos);
+               if (freq <= 0)
+                       return -1;
+       }
+
+       /* Must be searched for last, because it adds nul termination */
+       pos = os_strstr(cmd, " seek=");
+       if (pos)
+               pos += 6;
+       while (pos && seek_count < P2P_MAX_QUERY_HASH + 1) {
+               char *term;
+
+               _seek[seek_count++] = pos;
+               seek = _seek;
+               term = os_strchr(pos, ' ');
+               if (!term)
+                       break;
+               *term = '\0';
+               pos = os_strstr(term + 1, "seek=");
+               if (pos)
+                       pos += 5;
+       }
+       if (seek_count > P2P_MAX_QUERY_HASH) {
+               seek[0] = NULL;
+               seek_count = 1;
+       }
+
        return wpas_p2p_find(wpa_s, timeout, type, _dev_type != NULL, _dev_type,
-                            _dev_id, search_delay);
+                            _dev_id, search_delay, seek_count, seek, freq);
 }
 
 
-static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
-                           char *buf, size_t buflen)
+static int p2ps_ctrl_parse_cpt_priority(const char *pos, u8 *cpt)
 {
-       u8 addr[ETH_ALEN];
-       char *pos, *pos2;
-       char *pin = NULL;
-       enum p2p_wps_method wps_method;
-       int new_pin;
-       int ret;
-       int persistent_group, persistent_id = -1;
-       int join;
-       int auth;
-       int automatic;
-       int go_intent = -1;
-       int freq = 0;
-       int pd;
-       int ht40, vht;
-
-       /* <addr> <"pbc" | "pin" | PIN> [label|display|keypad]
-        * [persistent|persistent=<network id>]
-        * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
-        * [ht40] [vht] */
+       const char *last = NULL;
+       const char *token;
+       long int token_len;
+       unsigned int i;
 
-       if (hwaddr_aton(cmd, addr))
-               return -1;
+       /* Expected predefined CPT names delimited by ':' */
+       for (i = 0; (token = cstr_token(pos, ": \t", &last)); i++) {
+               if (i >= P2PS_FEATURE_CAPAB_CPT_MAX) {
+                       wpa_printf(MSG_ERROR,
+                                  "P2PS: CPT name list is too long, expected up to %d names",
+                                  P2PS_FEATURE_CAPAB_CPT_MAX);
+                       cpt[0] = 0;
+                       return -1;
+               }
 
-       pos = cmd + 17;
-       if (*pos != ' ')
-               return -1;
-       pos++;
+               token_len = last - token;
+
+               if (token_len  == 3 &&
+                   os_memcmp(token, "UDP", token_len) == 0) {
+                       cpt[i] = P2PS_FEATURE_CAPAB_UDP_TRANSPORT;
+               } else if (token_len == 3 &&
+                          os_memcmp(token, "MAC", token_len) == 0) {
+                       cpt[i] = P2PS_FEATURE_CAPAB_MAC_TRANSPORT;
+               } else {
+                       wpa_printf(MSG_ERROR,
+                                  "P2PS: Unsupported CPT name '%s'", token);
+                       cpt[0] = 0;
+                       return -1;
+               }
+
+               if (isblank(*last)) {
+                       i++;
+                       break;
+               }
+       }
+       cpt[i] = 0;
+       return 0;
+}
+
+
+static struct p2ps_provision * p2p_parse_asp_provision_cmd(const char *cmd)
+{
+       struct p2ps_provision *p2ps_prov;
+       char *pos;
+       size_t info_len = 0;
+       char *info = NULL;
+       u8 role = P2PS_SETUP_NONE;
+       long long unsigned val;
+       int i;
+
+       pos = os_strstr(cmd, "info=");
+       if (pos) {
+               pos += 5;
+               info_len = os_strlen(pos);
+
+               if (info_len) {
+                       info = os_malloc(info_len + 1);
+                       if (info) {
+                               info_len = utf8_unescape(pos, info_len,
+                                                        info, info_len + 1);
+                       } else
+                               info_len = 0;
+               }
+       }
+
+       p2ps_prov = os_zalloc(sizeof(struct p2ps_provision) + info_len + 1);
+       if (p2ps_prov == NULL) {
+               os_free(info);
+               return NULL;
+       }
+
+       if (info) {
+               os_memcpy(p2ps_prov->info, info, info_len);
+               p2ps_prov->info[info_len] = '\0';
+               os_free(info);
+       }
+
+       pos = os_strstr(cmd, "status=");
+       if (pos)
+               p2ps_prov->status = atoi(pos + 7);
+       else
+               p2ps_prov->status = -1;
+
+       pos = os_strstr(cmd, "adv_id=");
+       if (!pos || sscanf(pos + 7, "%llx", &val) != 1 || val > 0xffffffffULL)
+               goto invalid_args;
+       p2ps_prov->adv_id = val;
+
+       pos = os_strstr(cmd, "method=");
+       if (pos)
+               p2ps_prov->method = strtol(pos + 7, NULL, 16);
+       else
+               p2ps_prov->method = 0;
+
+       pos = os_strstr(cmd, "session=");
+       if (!pos || sscanf(pos + 8, "%llx", &val) != 1 || val > 0xffffffffULL)
+               goto invalid_args;
+       p2ps_prov->session_id = val;
+
+       pos = os_strstr(cmd, "adv_mac=");
+       if (!pos || hwaddr_aton(pos + 8, p2ps_prov->adv_mac))
+               goto invalid_args;
+
+       pos = os_strstr(cmd, "session_mac=");
+       if (!pos || hwaddr_aton(pos + 12, p2ps_prov->session_mac))
+               goto invalid_args;
+
+       pos = os_strstr(cmd, "cpt=");
+       if (pos) {
+               if (p2ps_ctrl_parse_cpt_priority(pos + 4,
+                                                p2ps_prov->cpt_priority))
+                       goto invalid_args;
+       } else {
+               p2ps_prov->cpt_priority[0] = P2PS_FEATURE_CAPAB_UDP_TRANSPORT;
+       }
+
+       for (i = 0; p2ps_prov->cpt_priority[i]; i++)
+               p2ps_prov->cpt_mask |= p2ps_prov->cpt_priority[i];
+
+       /* force conncap with tstCap (no sanity checks) */
+       pos = os_strstr(cmd, "tstCap=");
+       if (pos) {
+               role = strtol(pos + 7, NULL, 16);
+       } else {
+               pos = os_strstr(cmd, "role=");
+               if (pos) {
+                       role = strtol(pos + 5, NULL, 16);
+                       if (role != P2PS_SETUP_CLIENT &&
+                           role != P2PS_SETUP_GROUP_OWNER)
+                               role = P2PS_SETUP_NONE;
+               }
+       }
+       p2ps_prov->role = role;
+
+       return p2ps_prov;
+
+invalid_args:
+       os_free(p2ps_prov);
+       return NULL;
+}
+
+
+static int p2p_ctrl_asp_provision_resp(struct wpa_supplicant *wpa_s, char *cmd)
+{
+       u8 addr[ETH_ALEN];
+       struct p2ps_provision *p2ps_prov;
+       char *pos;
+
+       /* <addr> id=<adv_id> [role=<conncap>] [info=<infodata>] */
+
+       wpa_printf(MSG_DEBUG, "%s: %s", __func__, cmd);
+
+       if (hwaddr_aton(cmd, addr))
+               return -1;
+
+       pos = cmd + 17;
+       if (*pos != ' ')
+               return -1;
+
+       p2ps_prov = p2p_parse_asp_provision_cmd(pos);
+       if (!p2ps_prov)
+               return -1;
+
+       if (p2ps_prov->status < 0) {
+               os_free(p2ps_prov);
+               return -1;
+       }
+
+       return wpas_p2p_prov_disc(wpa_s, addr, NULL, WPAS_P2P_PD_FOR_ASP,
+                                 p2ps_prov);
+}
+
+
+static int p2p_ctrl_asp_provision(struct wpa_supplicant *wpa_s, char *cmd)
+{
+       u8 addr[ETH_ALEN];
+       struct p2ps_provision *p2ps_prov;
+       char *pos;
+
+       /* <addr> id=<adv_id> adv_mac=<adv_mac> conncap=<conncap>
+        *        session=<ses_id> mac=<ses_mac> [info=<infodata>]
+        */
+
+       wpa_printf(MSG_DEBUG, "%s: %s", __func__, cmd);
+       if (hwaddr_aton(cmd, addr))
+               return -1;
+
+       pos = cmd + 17;
+       if (*pos != ' ')
+               return -1;
+
+       p2ps_prov = p2p_parse_asp_provision_cmd(pos);
+       if (!p2ps_prov)
+               return -1;
+
+       return wpas_p2p_prov_disc(wpa_s, addr, NULL, WPAS_P2P_PD_FOR_ASP,
+                                 p2ps_prov);
+}
+
+
+static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
+                           char *buf, size_t buflen)
+{
+       u8 addr[ETH_ALEN];
+       char *pos, *pos2;
+       char *pin = NULL;
+       enum p2p_wps_method wps_method;
+       int new_pin;
+       int ret;
+       int persistent_group, persistent_id = -1;
+       int join;
+       int auth;
+       int automatic;
+       int go_intent = -1;
+       int freq = 0;
+       int pd;
+       int ht40, vht;
+
+       if (!wpa_s->global->p2p_init_wpa_s)
+               return -1;
+       if (wpa_s->global->p2p_init_wpa_s != wpa_s) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "Direct P2P_CONNECT command to %s",
+                       wpa_s->global->p2p_init_wpa_s->ifname);
+               wpa_s = wpa_s->global->p2p_init_wpa_s;
+       }
+
+       /* <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] */
+
+       if (hwaddr_aton(cmd, addr))
+               return -1;
+
+       pos = cmd + 17;
+       if (*pos != ' ')
+               return -1;
+       pos++;
 
        persistent_group = os_strstr(pos, " persistent") != NULL;
        pos2 = os_strstr(pos, " persistent=");
@@ -4343,6 +4961,8 @@ 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);
@@ -4409,7 +5029,7 @@ static int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd)
        else if (os_strstr(pos, " auto") != NULL)
                use = WPAS_P2P_PD_AUTO;
 
-       return wpas_p2p_prov_disc(wpa_s, addr, pos, use);
+       return wpas_p2p_prov_disc(wpa_s, addr, pos, use, NULL);
 }
 
 
@@ -4462,6 +5082,40 @@ static int p2p_ctrl_serv_disc_req(struct wpa_supplicant *wpa_s, char *cmd,
        } else if (os_strncmp(pos, "wifi-display ", 13) == 0) {
                ref = wpas_p2p_sd_request_wifi_display(wpa_s, dst, pos + 13);
 #endif /* CONFIG_WIFI_DISPLAY */
+       } else if (os_strncmp(pos, "asp ", 4) == 0) {
+               char *svc_str;
+               char *svc_info = NULL;
+               u32 id;
+
+               pos += 4;
+               if (sscanf(pos, "%x", &id) != 1 || id > 0xff)
+                       return -1;
+
+               pos = os_strchr(pos, ' ');
+               if (pos == NULL || pos[1] == '\0' || pos[1] == ' ')
+                       return -1;
+
+               svc_str = pos + 1;
+
+               pos = os_strchr(svc_str, ' ');
+
+               if (pos)
+                       *pos++ = '\0';
+
+               /* All remaining data is the svc_info string */
+               if (pos && pos[0] && pos[0] != ' ') {
+                       len = os_strlen(pos);
+
+                       /* Unescape in place */
+                       len = utf8_unescape(pos, len, pos, len);
+                       if (len > 0xff)
+                               return -1;
+
+                       svc_info = pos;
+               }
+
+               ref = wpas_p2p_sd_request_asp(wpa_s, dst, (u8) id,
+                                             svc_str, svc_info);
        } else {
                len = os_strlen(pos);
                if (len & 1)
@@ -4624,6 +5278,121 @@ static int p2p_ctrl_service_add_upnp(struct wpa_supplicant *wpa_s, char *cmd)
 }
 
 
+static int p2p_ctrl_service_add_asp(struct wpa_supplicant *wpa_s,
+                                   u8 replace, char *cmd)
+{
+       char *pos;
+       char *adv_str;
+       u32 auto_accept, adv_id, svc_state, config_methods;
+       char *svc_info = NULL;
+       char *cpt_prio_str;
+       u8 cpt_prio[P2PS_FEATURE_CAPAB_CPT_MAX + 1];
+
+       pos = os_strchr(cmd, ' ');
+       if (pos == NULL)
+               return -1;
+       *pos++ = '\0';
+
+       /* Auto-Accept value is mandatory, and must be one of the
+        * single values (0, 1, 2, 4) */
+       auto_accept = atoi(cmd);
+       switch (auto_accept) {
+       case P2PS_SETUP_NONE: /* No auto-accept */
+       case P2PS_SETUP_NEW:
+       case P2PS_SETUP_CLIENT:
+       case P2PS_SETUP_GROUP_OWNER:
+               break;
+       default:
+               return -1;
+       }
+
+       /* Advertisement ID is mandatory */
+       cmd = pos;
+       pos = os_strchr(cmd, ' ');
+       if (pos == NULL)
+               return -1;
+       *pos++ = '\0';
+
+       /* Handle Adv_ID == 0 (wildcard "org.wi-fi.wfds") internally. */
+       if (sscanf(cmd, "%x", &adv_id) != 1 || adv_id == 0)
+               return -1;
+
+       /* Only allow replacements if exist, and adds if not */
+       if (wpas_p2p_service_p2ps_id_exists(wpa_s, adv_id)) {
+               if (!replace)
+                       return -1;
+       } else {
+               if (replace)
+                       return -1;
+       }
+
+       /* svc_state between 0 - 0xff is mandatory */
+       if (sscanf(pos, "%x", &svc_state) != 1 || svc_state > 0xff)
+               return -1;
+
+       pos = os_strchr(pos, ' ');
+       if (pos == NULL)
+               return -1;
+
+       /* config_methods is mandatory */
+       pos++;
+       if (sscanf(pos, "%x", &config_methods) != 1)
+               return -1;
+
+       if (!(config_methods &
+             (WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD | WPS_CONFIG_P2PS)))
+               return -1;
+
+       pos = os_strchr(pos, ' ');
+       if (pos == NULL)
+               return -1;
+
+       pos++;
+       adv_str = pos;
+
+       /* Advertisement string is mandatory */
+       if (!pos[0] || pos[0] == ' ')
+               return -1;
+
+       /* Terminate svc string */
+       pos = os_strchr(pos, ' ');
+       if (pos != NULL)
+               *pos++ = '\0';
+
+       cpt_prio_str = (pos && pos[0]) ? os_strstr(pos, "cpt=") : NULL;
+       if (cpt_prio_str) {
+               pos = os_strchr(pos, ' ');
+               if (pos != NULL)
+                       *pos++ = '\0';
+
+               if (p2ps_ctrl_parse_cpt_priority(cpt_prio_str + 4, cpt_prio))
+                       return -1;
+       } else {
+               cpt_prio[0] = P2PS_FEATURE_CAPAB_UDP_TRANSPORT;
+               cpt_prio[1] = 0;
+       }
+
+       /* Service and Response Information are optional */
+       if (pos && pos[0]) {
+               size_t len;
+
+               /* Note the bare ' included, which cannot exist legally
+                * in unescaped string. */
+               svc_info = os_strstr(pos, "svc_info='");
+
+               if (svc_info) {
+                       svc_info += 9;
+                       len = os_strlen(svc_info);
+                       utf8_unescape(svc_info, len, svc_info, len);
+               }
+       }
+
+       return wpas_p2p_service_add_asp(wpa_s, auto_accept, adv_id, adv_str,
+                                       (u8) svc_state, (u16) config_methods,
+                                       svc_info, cpt_prio);
+}
+
+
 static int p2p_ctrl_service_add(struct wpa_supplicant *wpa_s, char *cmd)
 {
        char *pos;
@@ -4637,6 +5406,8 @@ static int p2p_ctrl_service_add(struct wpa_supplicant *wpa_s, char *cmd)
                return p2p_ctrl_service_add_bonjour(wpa_s, pos);
        if (os_strcmp(cmd, "upnp") == 0)
                return p2p_ctrl_service_add_upnp(wpa_s, pos);
+       if (os_strcmp(cmd, "asp") == 0)
+               return p2p_ctrl_service_add_asp(wpa_s, 0, pos);
        wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
        return -1;
 }
@@ -4684,6 +5455,22 @@ static int p2p_ctrl_service_del_upnp(struct wpa_supplicant *wpa_s, char *cmd)
 }
 
 
+static int p2p_ctrl_service_del_asp(struct wpa_supplicant *wpa_s, char *cmd)
+{
+       u32 adv_id;
+
+       if (os_strcmp(cmd, "all") == 0) {
+               wpas_p2p_service_flush_asp(wpa_s);
+               return 0;
+       }
+
+       if (sscanf(cmd, "%x", &adv_id) != 1)
+               return -1;
+
+       return wpas_p2p_service_del_asp(wpa_s, adv_id);
+}
+
+
 static int p2p_ctrl_service_del(struct wpa_supplicant *wpa_s, char *cmd)
 {
        char *pos;
@@ -4697,6 +5484,25 @@ static int p2p_ctrl_service_del(struct wpa_supplicant *wpa_s, char *cmd)
                return p2p_ctrl_service_del_bonjour(wpa_s, pos);
        if (os_strcmp(cmd, "upnp") == 0)
                return p2p_ctrl_service_del_upnp(wpa_s, pos);
+       if (os_strcmp(cmd, "asp") == 0)
+               return p2p_ctrl_service_del_asp(wpa_s, pos);
+       wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
+       return -1;
+}
+
+
+static int p2p_ctrl_service_replace(struct wpa_supplicant *wpa_s, char *cmd)
+{
+       char *pos;
+
+       pos = os_strchr(cmd, ' ');
+       if (pos == NULL)
+               return -1;
+       *pos++ = '\0';
+
+       if (os_strcmp(cmd, "asp") == 0)
+               return p2p_ctrl_service_add_asp(wpa_s, 1, pos);
+
        wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
        return -1;
 }
@@ -4808,13 +5614,10 @@ static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd)
 
 
 static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
-                                        char *cmd, int freq, int ht40,
-                                        int vht)
+                                        int id, int freq, int ht40, int vht)
 {
-       int id;
        struct wpa_ssid *ssid;
 
-       id = atoi(cmd);
        ssid = wpa_config_get_network(wpa_s->conf, id);
        if (ssid == NULL || ssid->disabled != 2) {
                wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
@@ -4830,31 +5633,35 @@ static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
 
 static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
 {
-       int freq = 0, ht40, vht;
-       char *pos;
+       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;
+       char *token, *context = NULL;
 
-       pos = os_strstr(cmd, "freq=");
-       if (pos)
-               freq = atoi(pos + 5);
+       while ((token = str_token(cmd, " ", &context))) {
+               if (sscanf(token, "freq=%d", &freq) == 1 ||
+                   sscanf(token, "persistent=%d", &group_id) == 1) {
+                       continue;
+               } else if (os_strcmp(token, "ht40") == 0) {
+                       ht40 = 1;
+               } else if (os_strcmp(token, "vht") == 0) {
+                       vht = 1;
+                       ht40 = 1;
+               } else if (os_strcmp(token, "persistent") == 0) {
+                       persistent = 1;
+               } else {
+                       wpa_printf(MSG_DEBUG,
+                                  "CTRL: Invalid P2P_GROUP_ADD parameter: '%s'",
+                                  token);
+                       return -1;
+               }
+       }
 
-       vht = (os_strstr(cmd, "vht") != NULL) || wpa_s->conf->p2p_go_vht;
-       ht40 = (os_strstr(cmd, "ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
-               vht;
+       if (group_id >= 0)
+               return p2p_ctrl_group_add_persistent(wpa_s, group_id,
+                                                    freq, ht40, vht);
 
-       if (os_strncmp(cmd, "persistent=", 11) == 0)
-               return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq,
-                                                    ht40, vht);
-       if (os_strcmp(cmd, "persistent") == 0 ||
-           os_strncmp(cmd, "persistent ", 11) == 0)
-               return wpas_p2p_group_add(wpa_s, 1, freq, ht40, vht);
-       if (os_strncmp(cmd, "freq=", 5) == 0)
-               return wpas_p2p_group_add(wpa_s, 0, freq, ht40, vht);
-       if (ht40)
-               return wpas_p2p_group_add(wpa_s, 0, freq, ht40, vht);
-
-       wpa_printf(MSG_DEBUG, "CTRL: Invalid P2P_GROUP_ADD parameters '%s'",
-                  cmd);
-       return -1;
+       return wpas_p2p_group_add(wpa_s, persistent, freq, ht40, vht);
 }
 
 
@@ -5339,7 +6146,8 @@ static int ctrl_interworking_select(struct wpa_supplicant *wpa_s, char *param)
 }
 
 
-static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst)
+static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst,
+                                    int only_add)
 {
        u8 bssid[ETH_ALEN];
        struct wpa_bss *bss;
@@ -5356,7 +6164,28 @@ static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst)
                return -1;
        }
 
-       return interworking_connect(wpa_s, bss);
+       if (bss->ssid_len == 0) {
+               int found = 0;
+
+               wpa_printf(MSG_DEBUG, "Selected BSS entry for " MACSTR
+                          " does not have SSID information", MAC2STR(bssid));
+
+               dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss,
+                                        list) {
+                       if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
+                           bss->ssid_len > 0) {
+                               found = 1;
+                               break;
+                       }
+               }
+
+               if (!found)
+                       return -1;
+               wpa_printf(MSG_DEBUG,
+                          "Found another matching BSS entry with SSID");
+       }
+
+       return interworking_connect(wpa_s, bss, only_add);
 }
 
 
@@ -5813,6 +6642,14 @@ static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf,
                pos += ret;
        }
 
+       if (si.avg_beacon_signal) {
+               ret = os_snprintf(pos, end - pos,
+                                 "AVG_BEACON_RSSI=%d\n", si.avg_beacon_signal);
+               if (os_snprintf_error(end - pos, ret))
+                       return -1;
+               pos += ret;
+       }
+
        return pos - buf;
 }
 
@@ -5921,20 +6758,25 @@ static int wpa_supplicant_vendor_cmd(struct wpa_supplicant *wpa_s, char *cmd,
 
 static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
 {
+#ifdef CONFIG_P2P
+       struct wpa_supplicant *p2p_wpa_s = wpa_s->global->p2p_init_wpa_s ?
+               wpa_s->global->p2p_init_wpa_s : wpa_s;
+#endif /* CONFIG_P2P */
+
        wpa_dbg(wpa_s, MSG_DEBUG, "Flush all wpa_supplicant state");
 
 #ifdef CONFIG_P2P
-       wpas_p2p_cancel(wpa_s);
-       wpas_p2p_stop_find(wpa_s);
-       p2p_ctrl_flush(wpa_s);
-       wpas_p2p_group_remove(wpa_s, "*");
-       wpas_p2p_service_flush(wpa_s);
-       wpa_s->global->p2p_disabled = 0;
-       wpa_s->global->p2p_per_sta_psk = 0;
-       wpa_s->conf->num_sec_device_types = 0;
-       wpa_s->p2p_disable_ip_addr_req = 0;
-       os_free(wpa_s->global->p2p_go_avoid_freq.range);
-       wpa_s->global->p2p_go_avoid_freq.range = NULL;
+       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;
+       p2p_wpa_s->conf->num_sec_device_types = 0;
+       p2p_wpa_s->p2p_disable_ip_addr_req = 0;
+       os_free(p2p_wpa_s->global->p2p_go_avoid_freq.range);
+       p2p_wpa_s->global->p2p_go_avoid_freq.range = NULL;
+       p2p_wpa_s->global->pending_p2ps_group = 0;
 #endif /* CONFIG_P2P */
 
 #ifdef CONFIG_WPS_TESTING
@@ -5945,6 +6787,7 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
 #ifdef CONFIG_WPS
        wpa_s->wps_fragment_size = 0;
        wpas_wps_cancel(wpa_s);
+       wps_registrar_flush(wpa_s->wps->registrar);
 #endif /* CONFIG_WPS */
        wpa_s->after_wps = 0;
        wpa_s->known_wps_freq = 0;
@@ -5962,6 +6805,7 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
        wpa_supplicant_stop_countermeasures(wpa_s, NULL);
 
        wpa_s->no_keep_alive = 0;
+       wpa_s->own_disconnect_req = 0;
 
        os_free(wpa_s->disallow_aps_bssid);
        wpa_s->disallow_aps_bssid = NULL;
@@ -5974,8 +6818,6 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
        wpa_s->sta_uapsd = 0;
 
        wpa_drv_radio_disable(wpa_s, 0);
-
-       wpa_bss_flush(wpa_s);
        wpa_blacklist_clear(wpa_s);
        wpa_s->extra_blacklist_count = 0;
        wpa_supplicant_ctrl_iface_remove_network(wpa_s, "all");
@@ -6005,9 +6847,24 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
        wpa_s->ext_eapol_frame_io = 0;
 #ifdef CONFIG_TESTING_OPTIONS
        wpa_s->extra_roc_dur = 0;
+       wpa_s->test_failure = WPAS_TEST_FAILURE_NONE;
 #endif /* CONFIG_TESTING_OPTIONS */
 
        wpa_s->disconnected = 0;
+       os_free(wpa_s->next_scan_freqs);
+       wpa_s->next_scan_freqs = NULL;
+
+       wpa_bss_flush(wpa_s);
+       if (!dl_list_empty(&wpa_s->bss)) {
+               wpa_printf(MSG_DEBUG,
+                          "BSS table not empty after flush: %u entries, current_bss=%p bssid="
+                          MACSTR " pending_bssid=" MACSTR,
+                          dl_list_len(&wpa_s->bss), wpa_s->current_bss,
+                          MAC2STR(wpa_s->bssid),
+                          MAC2STR(wpa_s->pending_bssid));
+       }
+
+       eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
 }
 
 
@@ -6241,12 +7098,30 @@ static void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params,
        void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
                                 struct wpa_scan_results *scan_res);
        int *manual_scan_freqs = NULL;
+       struct wpa_ssid_value *ssid = NULL, *ns;
+       unsigned int ssid_count = 0;
 
        if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
                *reply_len = -1;
                return;
        }
 
+       if (radio_work_pending(wpa_s, "scan")) {
+               wpa_printf(MSG_DEBUG,
+                          "Pending scan scheduled - reject new request");
+               *reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n");
+               return;
+       }
+
+#ifdef CONFIG_INTERWORKING
+       if (wpa_s->fetch_anqp_in_progress || wpa_s->network_select) {
+               wpa_printf(MSG_DEBUG,
+                          "Interworking select in progress - reject new scan");
+               *reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n");
+               return;
+       }
+#endif /* CONFIG_INTERWORKING */
+
        if (params) {
                if (os_strncasecmp(params, "TYPE=ONLY", 9) == 0)
                        scan_only = 1;
@@ -6279,6 +7154,60 @@ static void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params,
                        *reply_len = -1;
                        goto done;
                }
+
+               pos = params;
+               while (pos && *pos != '\0') {
+                       if (os_strncmp(pos, "ssid ", 5) == 0) {
+                               char *end;
+
+                               pos += 5;
+                               end = pos;
+                               while (*end) {
+                                       if (*end == '\0' || *end == ' ')
+                                               break;
+                                       end++;
+                               }
+
+                               ns = os_realloc_array(
+                                       ssid, ssid_count + 1,
+                                       sizeof(struct wpa_ssid_value));
+                               if (ns == NULL) {
+                                       *reply_len = -1;
+                                       goto done;
+                               }
+                               ssid = ns;
+
+                               if ((end - pos) & 0x01 ||
+                                   end - pos > 2 * SSID_MAX_LEN ||
+                                   hexstr2bin(pos, ssid[ssid_count].ssid,
+                                              (end - pos) / 2) < 0) {
+                                       wpa_printf(MSG_DEBUG,
+                                                  "Invalid SSID value '%s'",
+                                                  pos);
+                                       *reply_len = -1;
+                                       goto done;
+                               }
+                               ssid[ssid_count].ssid_len = (end - pos) / 2;
+                               wpa_hexdump_ascii(MSG_DEBUG, "scan SSID",
+                                                 ssid[ssid_count].ssid,
+                                                 ssid[ssid_count].ssid_len);
+                               ssid_count++;
+                               pos = end;
+                       }
+
+                       pos = os_strchr(pos, ' ');
+                       if (pos)
+                               pos++;
+               }
+       }
+
+       wpa_s->num_ssids_from_scan_req = ssid_count;
+       os_free(wpa_s->ssids_from_scan_req);
+       if (ssid_count) {
+               wpa_s->ssids_from_scan_req = ssid;
+               ssid = NULL;
+       } else {
+               wpa_s->ssids_from_scan_req = NULL;
        }
 
        if (scan_only)
@@ -6342,6 +7271,7 @@ static void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params,
 
 done:
        os_free(manual_scan_freqs);
+       os_free(ssid);
 }
 
 
@@ -6543,7 +7473,7 @@ 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;
-       const struct iphdr *ip;
+       struct iphdr ip;
        const u8 *pos;
        unsigned int i;
 
@@ -6551,14 +7481,14 @@ void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
                return;
 
        eth = (const struct ether_header *) buf;
-       ip = (const struct iphdr *) (eth + 1);
-       pos = (const u8 *) (ip + 1);
+       os_memcpy(&ip, eth + 1, sizeof(ip));
+       pos = &buf[sizeof(*eth) + sizeof(ip)];
 
-       if (ip->ihl != 5 || ip->version != 4 ||
-           ntohs(ip->tot_len) != HWSIM_IP_LEN)
+       if (ip.ihl != 5 || ip.version != 4 ||
+           ntohs(ip.tot_len) != HWSIM_IP_LEN)
                return;
 
-       for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++) {
+       for (i = 0; i < HWSIM_IP_LEN - sizeof(ip); i++) {
                if (*pos != (u8) i)
                        return;
                pos++;
@@ -6605,7 +7535,7 @@ static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd)
        int used;
        long int val;
        u8 tos;
-       u8 buf[HWSIM_PACKETLEN];
+       u8 buf[2 + HWSIM_PACKETLEN];
        struct ether_header *eth;
        struct iphdr *ip;
        u8 *dpos;
@@ -6633,7 +7563,7 @@ static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd)
                return -1;
        tos = val;
 
-       eth = (struct ether_header *) buf;
+       eth = (struct ether_header *) &buf[2];
        os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
        os_memcpy(eth->ether_shost, src, ETH_ALEN);
        eth->ether_type = htons(ETHERTYPE_IP);
@@ -6645,14 +7575,14 @@ static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd)
        ip->tos = tos;
        ip->tot_len = htons(HWSIM_IP_LEN);
        ip->protocol = 1;
-       ip->saddr = htonl(192 << 24 | 168 << 16 | 1 << 8 | 1);
-       ip->daddr = htonl(192 << 24 | 168 << 16 | 1 << 8 | 2);
+       ip->saddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1);
+       ip->daddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2);
        ip->check = ipv4_hdr_checksum(ip, sizeof(*ip));
        dpos = (u8 *) (ip + 1);
        for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++)
                *dpos++ = i;
 
-       if (l2_packet_send(wpa_s->l2_test, dst, ETHERTYPE_IP, buf,
+       if (l2_packet_send(wpa_s->l2_test, dst, ETHERTYPE_IP, &buf[2],
                           HWSIM_PACKETLEN) < 0)
                return -1;
 
@@ -6703,6 +7633,82 @@ done:
        return res < 0 ? -1 : 0;
 }
 
+
+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);
+       pos = os_strchr(cmd, ':');
+       if (pos) {
+               pos++;
+               os_strlcpy(wpa_trace_fail_func, pos,
+                          sizeof(wpa_trace_fail_func));
+       } else {
+               wpa_trace_fail_after = 0;
+       }
+       return 0;
+#else /* WPA_TRACE_BFD */
+       return -1;
+#endif /* WPA_TRACE_BFD */
+}
+
+
+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 */
+       return -1;
+#endif /* WPA_TRACE_BFD */
+}
+
+
+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);
+       pos = os_strchr(cmd, ':');
+       if (pos) {
+               pos++;
+               os_strlcpy(wpa_trace_test_fail_func, pos,
+                          sizeof(wpa_trace_test_fail_func));
+       } else {
+               wpa_trace_test_fail_after = 0;
+       }
+       return 0;
+#else /* WPA_TRACE_BFD */
+       return -1;
+#endif /* WPA_TRACE_BFD */
+}
+
+
+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 */
+       return -1;
+#endif /* WPA_TRACE_BFD */
+}
+
 #endif /* CONFIG_TESTING_OPTIONS */
 
 
@@ -6939,7 +7945,7 @@ static int wpas_ctrl_iface_send_neigbor_rep(struct wpa_supplicant *wpa_s,
 
        if (os_strncmp(cmd, " ssid=", 6) == 0) {
                ssid.ssid_len = os_strlen(cmd + 6);
-               if (ssid.ssid_len > 32)
+               if (ssid.ssid_len > SSID_MAX_LEN)
                        return -1;
                ssid.ssid = (u8 *) (cmd + 6);
                ssid_p = &ssid;
@@ -6960,6 +7966,126 @@ static int wpas_ctrl_iface_erp_flush(struct wpa_supplicant *wpa_s)
 }
 
 
+static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s,
+                                        char *cmd)
+{
+       char *token, *context = NULL;
+       unsigned int enable = ~0, type = 0;
+       u8 _addr[ETH_ALEN], _mask[ETH_ALEN];
+       u8 *addr = NULL, *mask = NULL;
+
+       while ((token = str_token(cmd, " ", &context))) {
+               if (os_strcasecmp(token, "scan") == 0) {
+                       type |= MAC_ADDR_RAND_SCAN;
+               } else if (os_strcasecmp(token, "sched") == 0) {
+                       type |= MAC_ADDR_RAND_SCHED_SCAN;
+               } else if (os_strcasecmp(token, "pno") == 0) {
+                       type |= MAC_ADDR_RAND_PNO;
+               } else if (os_strcasecmp(token, "all") == 0) {
+                       type = wpa_s->mac_addr_rand_supported;
+               } else if (os_strncasecmp(token, "enable=", 7) == 0) {
+                       enable = atoi(token + 7);
+               } else if (os_strncasecmp(token, "addr=", 5) == 0) {
+                       addr = _addr;
+                       if (hwaddr_aton(token + 5, addr)) {
+                               wpa_printf(MSG_INFO,
+                                          "CTRL: Invalid MAC address: %s",
+                                          token);
+                               return -1;
+                       }
+               } else if (os_strncasecmp(token, "mask=", 5) == 0) {
+                       mask = _mask;
+                       if (hwaddr_aton(token + 5, mask)) {
+                               wpa_printf(MSG_INFO,
+                                          "CTRL: Invalid MAC address mask: %s",
+                                          token);
+                               return -1;
+                       }
+               } else {
+                       wpa_printf(MSG_INFO,
+                                  "CTRL: Invalid MAC_RAND_SCAN parameter: %s",
+                                  token);
+                       return -1;
+               }
+       }
+
+       if (!type) {
+               wpa_printf(MSG_INFO, "CTRL: MAC_RAND_SCAN no type specified");
+               return -1;
+       }
+
+       if ((wpa_s->mac_addr_rand_supported & type) != type) {
+               wpa_printf(MSG_INFO,
+                          "CTRL: MAC_RAND_SCAN types=%u != supported=%u",
+                          type, wpa_s->mac_addr_rand_supported);
+               return -1;
+       }
+
+       if (enable > 1) {
+               wpa_printf(MSG_INFO,
+                          "CTRL: MAC_RAND_SCAN enable=<0/1> not specified");
+               return -1;
+       }
+
+       if (!enable) {
+               wpas_mac_addr_rand_scan_clear(wpa_s, type);
+               if (wpa_s->pno) {
+                       if (type & MAC_ADDR_RAND_PNO) {
+                               wpas_stop_pno(wpa_s);
+                               wpas_start_pno(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);
+               }
+               return 0;
+       }
+
+       if ((addr && !mask) || (!addr && mask)) {
+               wpa_printf(MSG_INFO,
+                          "CTRL: MAC_RAND_SCAN invalid addr/mask combination");
+               return -1;
+       }
+
+       if (addr && mask && (!(mask[0] & 0x01) || (addr[0] & 0x01))) {
+               wpa_printf(MSG_INFO,
+                          "CTRL: MAC_RAND_SCAN cannot allow multicast address");
+               return -1;
+       }
+
+       if (type & MAC_ADDR_RAND_SCAN) {
+               wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCAN,
+                                           addr, mask);
+       }
+
+       if (type & MAC_ADDR_RAND_SCHED_SCAN) {
+               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 (type & MAC_ADDR_RAND_PNO) {
+               wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_PNO,
+                                           addr, mask);
+               if (wpa_s->pno) {
+                       wpas_stop_pno(wpa_s);
+                       wpas_start_pno(wpa_s);
+               }
+       }
+
+       return 0;
+}
+
+
 char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                                         char *buf, size_t *resp_len)
 {
@@ -7027,6 +8153,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strncmp(buf, "SET ", 4) == 0) {
                if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
                        reply_len = -1;
+       } else if (os_strncmp(buf, "DUMP", 4) == 0) {
+               reply_len = wpa_config_dump_values(wpa_s->conf,
+                                                  reply, reply_size);
        } else if (os_strncmp(buf, "GET ", 4) == 0) {
                reply_len = wpa_supplicant_ctrl_iface_get(wpa_s, buf + 4,
                                                          reply, reply_size);
@@ -7175,6 +8304,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                        reply_len = -1;
 #endif /* CONFIG_IBSS_RSN */
 #ifdef CONFIG_MESH
+       } else if (os_strncmp(buf, "MESH_INTERFACE_ADD ", 19) == 0) {
+               reply_len = wpa_supplicant_ctrl_iface_mesh_interface_add(
+                       wpa_s, buf + 19, reply, reply_size);
+       } else if (os_strcmp(buf, "MESH_INTERFACE_ADD") == 0) {
+               reply_len = wpa_supplicant_ctrl_iface_mesh_interface_add(
+                       wpa_s, "", reply, reply_size);
        } else if (os_strncmp(buf, "MESH_GROUP_ADD ", 15) == 0) {
                if (wpa_supplicant_ctrl_iface_mesh_group_add(wpa_s, buf + 15))
                        reply_len = -1;
@@ -7185,13 +8320,19 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_MESH */
 #ifdef CONFIG_P2P
        } else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) {
-               if (p2p_ctrl_find(wpa_s, buf + 9))
+               if (p2p_ctrl_find(wpa_s, buf + 8))
                        reply_len = -1;
        } else if (os_strcmp(buf, "P2P_FIND") == 0) {
                if (p2p_ctrl_find(wpa_s, ""))
                        reply_len = -1;
        } else if (os_strcmp(buf, "P2P_STOP_FIND") == 0) {
                wpas_p2p_stop_find(wpa_s);
+       } else if (os_strncmp(buf, "P2P_ASP_PROVISION ", 18) == 0) {
+               if (p2p_ctrl_asp_provision(wpa_s, buf + 18))
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "P2P_ASP_PROVISION_RESP ", 23) == 0) {
+               if (p2p_ctrl_asp_provision_resp(wpa_s, buf + 23))
+                       reply_len = -1;
        } else if (os_strncmp(buf, "P2P_CONNECT ", 12) == 0) {
                reply_len = p2p_ctrl_connect(wpa_s, buf + 12, reply,
                                             reply_size);
@@ -7205,7 +8346,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                if (wpas_p2p_group_remove(wpa_s, buf + 17))
                        reply_len = -1;
        } else if (os_strcmp(buf, "P2P_GROUP_ADD") == 0) {
-               if (wpas_p2p_group_add(wpa_s, 0, 0, 0, 0))
+               if (p2p_ctrl_group_add(wpa_s, ""))
                        reply_len = -1;
        } else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) {
                if (p2p_ctrl_group_add(wpa_s, buf + 14))
@@ -7237,6 +8378,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strncmp(buf, "P2P_SERVICE_DEL ", 16) == 0) {
                if (p2p_ctrl_service_del(wpa_s, buf + 16) < 0)
                        reply_len = -1;
+       } else if (os_strncmp(buf, "P2P_SERVICE_REP ", 16) == 0) {
+               if (p2p_ctrl_service_replace(wpa_s, buf + 16) < 0)
+                       reply_len = -1;
        } else if (os_strncmp(buf, "P2P_REJECT ", 11) == 0) {
                if (p2p_ctrl_reject(wpa_s, buf + 11) < 0)
                        reply_len = -1;
@@ -7294,8 +8438,19 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                if (ctrl_interworking_select(wpa_s, buf + 20) < 0)
                        reply_len = -1;
        } else if (os_strncmp(buf, "INTERWORKING_CONNECT ", 21) == 0) {
-               if (ctrl_interworking_connect(wpa_s, buf + 21) < 0)
+               if (ctrl_interworking_connect(wpa_s, buf + 21, 0) < 0)
                        reply_len = -1;
+       } else if (os_strncmp(buf, "INTERWORKING_ADD_NETWORK ", 25) == 0) {
+               int id;
+
+               id = ctrl_interworking_connect(wpa_s, buf + 25, 1);
+               if (id < 0)
+                       reply_len = -1;
+               else {
+                       reply_len = os_snprintf(reply, reply_size, "%d\n", id);
+                       if (os_snprintf_error(reply_size, reply_len))
+                               reply_len = -1;
+               }
        } else if (os_strncmp(buf, "ANQP_GET ", 9) == 0) {
                if (get_anqp(wpa_s, buf + 9) < 0)
                        reply_len = -1;
@@ -7365,6 +8520,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *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);
        } 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) {
@@ -7394,7 +8550,8 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                reply_len = wpa_supplicant_ctrl_iface_get_network(
                        wpa_s, buf + 12, reply, reply_size);
        } else if (os_strncmp(buf, "DUP_NETWORK ", 12) == 0) {
-               if (wpa_supplicant_ctrl_iface_dup_network(wpa_s, buf + 12))
+               if (wpa_supplicant_ctrl_iface_dup_network(wpa_s, buf + 12,
+                                                         wpa_s))
                        reply_len = -1;
        } else if (os_strcmp(buf, "LIST_CREDS") == 0) {
                reply_len = wpa_supplicant_ctrl_iface_list_creds(
@@ -7453,6 +8610,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
                if (ap_ctrl_iface_chanswitch(wpa_s, buf + 12))
                        reply_len = -1;
+       } else if (os_strcmp(buf, "STOP_AP") == 0) {
+               if (wpas_ap_stop_ap(wpa_s))
+                       reply_len = -1;
 #endif /* CONFIG_AP */
        } else if (os_strcmp(buf, "SUSPEND") == 0) {
                wpas_notify_suspend(wpa_s->global);
@@ -7486,6 +8646,17 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strncmp(buf, "TDLS_TEARDOWN ", 14) == 0) {
                if (wpa_supplicant_ctrl_iface_tdls_teardown(wpa_s, buf + 14))
                        reply_len = -1;
+       } else if (os_strncmp(buf, "TDLS_CHAN_SWITCH ", 17) == 0) {
+               if (wpa_supplicant_ctrl_iface_tdls_chan_switch(wpa_s,
+                                                              buf + 17))
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "TDLS_CANCEL_CHAN_SWITCH ", 24) == 0) {
+               if (wpa_supplicant_ctrl_iface_tdls_cancel_chan_switch(wpa_s,
+                                                                     buf + 24))
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "TDLS_LINK_STATUS ", 17) == 0) {
+               reply_len = wpa_supplicant_ctrl_iface_tdls_link_status(
+                       wpa_s, buf + 17, reply, reply_size);
 #endif /* CONFIG_TDLS */
        } else if (os_strcmp(buf, "WMM_AC_STATUS") == 0) {
                reply_len = wpas_wmm_ac_status(wpa_s, reply, reply_size);
@@ -7521,8 +8692,8 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strncmp(buf, "WNM_SLEEP ", 10) == 0) {
                if (wpas_ctrl_iface_wnm_sleep(wpa_s, buf + 10))
                        reply_len = -1;
-       } else if (os_strncmp(buf, "WNM_BSS_QUERY ", 10) == 0) {
-               if (wpas_ctrl_iface_wnm_bss_query(wpa_s, buf + 10))
+       } else if (os_strncmp(buf, "WNM_BSS_QUERY ", 14) == 0) {
+               if (wpas_ctrl_iface_wnm_bss_query(wpa_s, buf + 14))
                                reply_len = -1;
 #endif /* CONFIG_WNM */
        } else if (os_strcmp(buf, "FLUSH") == 0) {
@@ -7551,6 +8722,16 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strncmp(buf, "DATA_TEST_FRAME ", 16) == 0) {
                if (wpas_ctrl_iface_data_test_frame(wpa_s, buf + 16) < 0)
                        reply_len = -1;
+       } else if (os_strncmp(buf, "TEST_ALLOC_FAIL ", 16) == 0) {
+               if (wpas_ctrl_test_alloc_fail(wpa_s, buf + 16) < 0)
+                       reply_len = -1;
+       } else if (os_strcmp(buf, "GET_ALLOC_FAIL") == 0) {
+               reply_len = wpas_ctrl_get_alloc_fail(wpa_s, reply, reply_size);
+       } else if (os_strncmp(buf, "TEST_FAIL ", 10) == 0) {
+               if (wpas_ctrl_test_fail(wpa_s, buf + 10) < 0)
+                       reply_len = -1;
+       } else if (os_strcmp(buf, "GET_FAIL") == 0) {
+               reply_len = wpas_ctrl_get_fail(wpa_s, reply, reply_size);
 #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)
@@ -7566,6 +8747,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                        reply_len = -1;
        } else if (os_strcmp(buf, "ERP_FLUSH") == 0) {
                wpas_ctrl_iface_erp_flush(wpa_s);
+       } else if (os_strncmp(buf, "MAC_RAND_SCAN ", 14) == 0) {
+               if (wpas_ctrl_iface_mac_rand_scan(wpa_s, buf + 14))
+                       reply_len = -1;
        } else {
                os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
                reply_len = 16;
@@ -7585,11 +8769,14 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global,
                                           char *cmd)
 {
        struct wpa_interface iface;
-       char *pos;
+       char *pos, *extra;
+       struct wpa_supplicant *wpa_s;
+       unsigned int create_iface = 0;
+       u8 mac_addr[ETH_ALEN];
 
        /*
         * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param>
-        * TAB<bridge_ifname>
+        * TAB<bridge_ifname>[TAB<create>]
         */
        wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd);
 
@@ -7649,12 +8836,54 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global,
                        iface.bridge_ifname = NULL;
                if (pos == NULL)
                        break;
+
+               extra = pos;
+               pos = os_strchr(pos, '\t');
+               if (pos)
+                       *pos++ = '\0';
+               if (!extra[0])
+                       break;
+
+               if (os_strcmp(extra, "create") == 0)
+                       create_iface = 1;
+               else {
+                       wpa_printf(MSG_DEBUG,
+                                  "INTERFACE_ADD unsupported extra parameter: '%s'",
+                                  extra);
+                       return -1;
+               }
        } while (0);
 
+       if (create_iface) {
+               wpa_printf(MSG_DEBUG, "CTRL_IFACE creating interface '%s'",
+                          iface.ifname);
+               if (!global->ifaces)
+                       return -1;
+               if (wpa_drv_if_add(global->ifaces, WPA_IF_STATION, iface.ifname,
+                                  NULL, NULL, NULL, mac_addr, NULL) < 0) {
+                       wpa_printf(MSG_ERROR,
+                                  "CTRL_IFACE interface creation failed");
+                       return -1;
+               }
+
+               wpa_printf(MSG_DEBUG,
+                          "CTRL_IFACE interface '%s' created with MAC addr: "
+                          MACSTR, iface.ifname, MAC2STR(mac_addr));
+       }
+
        if (wpa_supplicant_get_iface(global, iface.ifname))
-               return -1;
+               goto fail;
 
-       return wpa_supplicant_add_iface(global, &iface) ? 0 : -1;
+       wpa_s = wpa_supplicant_add_iface(global, &iface, NULL);
+       if (!wpa_s)
+               goto fail;
+       wpa_s->added_vif = create_iface;
+       return 0;
+
+fail:
+       if (create_iface)
+               wpa_drv_if_remove(global->ifaces, WPA_IF_STATION, iface.ifname);
+       return -1;
 }
 
 
@@ -7662,13 +8891,22 @@ static int wpa_supplicant_global_iface_remove(struct wpa_global *global,
                                              char *cmd)
 {
        struct wpa_supplicant *wpa_s;
+       int ret;
+       unsigned int delete_iface;
 
        wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_REMOVE '%s'", cmd);
 
        wpa_s = wpa_supplicant_get_iface(global, cmd);
        if (wpa_s == NULL)
                return -1;
-       return wpa_supplicant_remove_iface(global, wpa_s, 0);
+       delete_iface = wpa_s->added_vif;
+       ret = wpa_supplicant_remove_iface(global, wpa_s, 0);
+       if (!ret && delete_iface) {
+               wpa_printf(MSG_DEBUG, "CTRL_IFACE deleting the interface '%s'",
+                          cmd);
+               ret = wpa_drv_if_remove(global->ifaces, WPA_IF_STATION, cmd);
+       }
+       return ret;
 }
 
 
@@ -7695,7 +8933,7 @@ static int wpa_supplicant_global_iface_list(struct wpa_global *global,
        char *pos, *end;
 
        for (i = 0; wpa_drivers[i]; i++) {
-               struct wpa_driver_ops *drv = wpa_drivers[i];
+               const struct wpa_driver_ops *drv = wpa_drivers[i];
                if (drv->get_interfaces == NULL)
                        continue;
                tmp = drv->get_interfaces(global->drv_priv[i]);
@@ -7814,6 +9052,7 @@ static char * wpas_global_ctrl_iface_redir_p2p(struct wpa_global *global,
                "P2P_SERV_DISC_EXTERNAL ",
                "P2P_SERVICE_ADD ",
                "P2P_SERVICE_DEL ",
+               "P2P_SERVICE_REP ",
                "P2P_REJECT ",
                "P2P_INVITE ",
                "P2P_PEER ",
@@ -7822,9 +9061,13 @@ static char * wpas_global_ctrl_iface_redir_p2p(struct wpa_global *global,
                "P2P_PRESENCE_REQ ",
                "P2P_EXT_LISTEN ",
                "P2P_REMOVE_CLIENT ",
+               "WPS_NFC_TOKEN ",
+               "WPS_NFC_TAG_READ ",
                "NFC_GET_HANDOVER_SEL ",
                "NFC_GET_HANDOVER_REQ ",
                "NFC_REPORT_HANDOVER ",
+               "P2P_ASP_PROVISION ",
+               "P2P_ASP_PROVISION_RESP ",
                NULL
        };
        int found = 0;
@@ -7908,6 +9151,41 @@ static int wpas_global_ctrl_iface_set(struct wpa_global *global, char *cmd)
 }
 
 
+static int wpas_global_ctrl_iface_dup_network(struct wpa_global *global,
+                                             char *cmd)
+{
+       struct wpa_supplicant *wpa_s[2]; /* src, dst */
+       char *p;
+       unsigned int i;
+
+       /* cmd: "<src ifname> <dst ifname> <src network id> <dst network id>
+        * <variable name> */
+
+       for (i = 0; i < ARRAY_SIZE(wpa_s) ; i++) {
+               p = os_strchr(cmd, ' ');
+               if (p == NULL)
+                       return -1;
+               *p = '\0';
+
+               wpa_s[i] = global->ifaces;
+               for (; wpa_s[i]; wpa_s[i] = wpa_s[i]->next) {
+                       if (os_strcmp(cmd, wpa_s[i]->ifname) == 0)
+                               break;
+               }
+
+               if (!wpa_s[i]) {
+                       wpa_printf(MSG_DEBUG,
+                                  "CTRL_IFACE: Could not find iface=%s", cmd);
+                       return -1;
+               }
+
+               cmd = p + 1;
+       }
+
+       return wpa_supplicant_ctrl_iface_dup_network(wpa_s[0], cmd, wpa_s[1]);
+}
+
+
 #ifndef CONFIG_NO_CONFIG_WRITE
 static int wpas_global_ctrl_iface_save_config(struct wpa_global *global)
 {
@@ -7989,6 +9267,59 @@ static int wpas_global_ctrl_iface_status(struct wpa_global *global,
 }
 
 
+#ifdef CONFIG_FST
+
+static int wpas_global_ctrl_iface_fst_attach(struct wpa_global *global,
+                                            char *cmd, char *buf,
+                                            size_t reply_size)
+{
+       char ifname[IFNAMSIZ + 1];
+       struct fst_iface_cfg cfg;
+       struct wpa_supplicant *wpa_s;
+       struct fst_wpa_obj iface_obj;
+
+       if (!fst_parse_attach_command(cmd, ifname, sizeof(ifname), &cfg)) {
+               wpa_s = wpa_supplicant_get_iface(global, ifname);
+               if (wpa_s) {
+                       if (wpa_s->fst) {
+                               wpa_printf(MSG_INFO, "FST: Already attached");
+                               return -1;
+                       }
+                       fst_wpa_supplicant_fill_iface_obj(wpa_s, &iface_obj);
+                       wpa_s->fst = fst_attach(ifname, wpa_s->own_addr,
+                                               &iface_obj, &cfg);
+                       if (wpa_s->fst)
+                               return os_snprintf(buf, reply_size, "OK\n");
+               }
+       }
+
+       return -1;
+}
+
+
+static int wpas_global_ctrl_iface_fst_detach(struct wpa_global *global,
+                                            char *cmd, char *buf,
+                                            size_t reply_size)
+{
+       char ifname[IFNAMSIZ + 1];
+       struct wpa_supplicant *wpa_s;
+
+       if (!fst_parse_detach_command(cmd, ifname, sizeof(ifname))) {
+               wpa_s = wpa_supplicant_get_iface(global, ifname);
+               if (wpa_s) {
+                       if (!fst_iface_detach(ifname)) {
+                               wpa_s->fst = NULL;
+                               return os_snprintf(buf, reply_size, "OK\n");
+                       }
+               }
+       }
+
+       return -1;
+}
+
+#endif /* CONFIG_FST */
+
+
 char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
                                                char *buf, size_t *resp_len)
 {
@@ -8040,6 +9371,18 @@ char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
        } else if (os_strcmp(buf, "INTERFACES") == 0) {
                reply_len = wpa_supplicant_global_iface_interfaces(
                        global, 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,
+                                                             reply,
+                                                             reply_size);
+       } else if (os_strncmp(buf, "FST-DETACH ", 11) == 0) {
+               reply_len = wpas_global_ctrl_iface_fst_detach(global, buf + 11,
+                                                             reply,
+                                                             reply_size);
+       } else if (os_strncmp(buf, "FST-MANAGER ", 12) == 0) {
+               reply_len = fst_ctrl_iface_receive(buf + 12, reply, reply_size);
+#endif /* CONFIG_FST */
        } else if (os_strcmp(buf, "TERMINATE") == 0) {
                wpa_supplicant_terminate_proc(global);
        } else if (os_strcmp(buf, "SUSPEND") == 0) {
@@ -8060,6 +9403,9 @@ char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
 #endif /* CONFIG_P2P */
                        reply_len = -1;
                }
+       } else if (os_strncmp(buf, "DUP_NETWORK ", 12) == 0) {
+               if (wpas_global_ctrl_iface_dup_network(global, buf + 12))
+                       reply_len = -1;
 #ifndef CONFIG_NO_CONFIG_WRITE
        } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
                if (wpas_global_ctrl_iface_save_config(global))