]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - wpa_supplicant/ctrl_iface.c
tests: Remove testing of EAP-pwd with Brainpool curves
[thirdparty/hostap.git] / wpa_supplicant / ctrl_iface.c
index 295e50fa8ffad017d8a03eeffc143026ed4ac1da..8efc08d4d906161cb41af106808581b402147471 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / Control interface (shared code for all backends)
- * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -8,10 +8,10 @@
 
 #include "utils/includes.h"
 #ifdef CONFIG_TESTING_OPTIONS
-#include <net/ethernet.h>
 #include <netinet/ip.h>
 #endif /* CONFIG_TESTING_OPTIONS */
 
+#include <net/ethernet.h>
 #include "utils/common.h"
 #include "utils/eloop.h"
 #include "utils/uuid.h"
@@ -20,6 +20,9 @@
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
 #include "common/wpa_ctrl.h"
+#ifdef CONFIG_DPP
+#include "common/dpp.h"
+#endif /* CONFIG_DPP */
 #include "crypto/tls.h"
 #include "ap/hostapd.h"
 #include "eap_peer/eap.h"
@@ -52,6 +55,8 @@
 #include "offchannel.h"
 #include "drivers/driver.h"
 #include "mesh.h"
+#include "dpp_supplicant.h"
+#include "sme.h"
 
 static int wpa_supplicant_global_iface_list(struct wpa_global *global,
                                            char *buf, int len);
@@ -61,6 +66,7 @@ static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
 static int * freq_range_to_channel_list(struct wpa_supplicant *wpa_s,
                                        char *val);
 
+
 static int set_bssid_filter(struct wpa_supplicant *wpa_s, char *val)
 {
        char *pos;
@@ -386,6 +392,28 @@ static int wpas_ctrl_set_relative_band_adjust(struct wpa_supplicant *wpa_s,
 }
 
 
+static int wpas_ctrl_iface_set_ric_ies(struct wpa_supplicant *wpa_s,
+                                  const char *cmd)
+{
+       struct wpabuf *ric_ies;
+
+       if (*cmd == '\0' || os_strcmp(cmd, "\"\"") == 0) {
+               wpabuf_free(wpa_s->ric_ies);
+               wpa_s->ric_ies = NULL;
+               return 0;
+       }
+
+       ric_ies = wpabuf_parse_bin(cmd);
+       if (!ric_ies)
+               return -1;
+
+       wpabuf_free(wpa_s->ric_ies);
+       wpa_s->ric_ies = ric_ies;
+
+       return 0;
+}
+
+
 static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
                                         char *cmd)
 {
@@ -554,6 +582,59 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
                ret = set_disallow_aps(wpa_s, value);
        } else if (os_strcasecmp(cmd, "no_keep_alive") == 0) {
                wpa_s->no_keep_alive = !!atoi(value);
+#ifdef CONFIG_DPP
+       } else if (os_strcasecmp(cmd, "dpp_configurator_params") == 0) {
+               os_free(wpa_s->dpp_configurator_params);
+               wpa_s->dpp_configurator_params = os_strdup(value);
+       } else if (os_strcasecmp(cmd, "dpp_init_max_tries") == 0) {
+               wpa_s->dpp_init_max_tries = atoi(value);
+       } else if (os_strcasecmp(cmd, "dpp_init_retry_time") == 0) {
+               wpa_s->dpp_init_retry_time = atoi(value);
+       } else if (os_strcasecmp(cmd, "dpp_resp_wait_time") == 0) {
+               wpa_s->dpp_resp_wait_time = atoi(value);
+       } else if (os_strcasecmp(cmd, "dpp_resp_max_tries") == 0) {
+               wpa_s->dpp_resp_max_tries = atoi(value);
+       } else if (os_strcasecmp(cmd, "dpp_resp_retry_time") == 0) {
+               wpa_s->dpp_resp_retry_time = atoi(value);
+#ifdef CONFIG_TESTING_OPTIONS
+       } else if (os_strcasecmp(cmd, "dpp_pkex_own_mac_override") == 0) {
+               if (hwaddr_aton(value, dpp_pkex_own_mac_override))
+                       ret = -1;
+       } else if (os_strcasecmp(cmd, "dpp_pkex_peer_mac_override") == 0) {
+               if (hwaddr_aton(value, dpp_pkex_peer_mac_override))
+                       ret = -1;
+       } else if (os_strcasecmp(cmd, "dpp_pkex_ephemeral_key_override") == 0) {
+               size_t hex_len = os_strlen(value);
+
+               if (hex_len >
+                   2 * sizeof(dpp_pkex_ephemeral_key_override))
+                       ret = -1;
+               else if (hexstr2bin(value, dpp_pkex_ephemeral_key_override,
+                                   hex_len / 2))
+                       ret = -1;
+               else
+                       dpp_pkex_ephemeral_key_override_len = hex_len / 2;
+       } else if (os_strcasecmp(cmd, "dpp_protocol_key_override") == 0) {
+               size_t hex_len = os_strlen(value);
+
+               if (hex_len > 2 * sizeof(dpp_protocol_key_override))
+                       ret = -1;
+               else if (hexstr2bin(value, dpp_protocol_key_override,
+                                   hex_len / 2))
+                       ret = -1;
+               else
+                       dpp_protocol_key_override_len = hex_len / 2;
+       } else if (os_strcasecmp(cmd, "dpp_nonce_override") == 0) {
+               size_t hex_len = os_strlen(value);
+
+               if (hex_len > 2 * sizeof(dpp_nonce_override))
+                       ret = -1;
+               else if (hexstr2bin(value, dpp_nonce_override, hex_len / 2))
+                       ret = -1;
+               else
+                       dpp_nonce_override_len = hex_len / 2;
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_DPP */
 #ifdef CONFIG_TESTING_OPTIONS
        } else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) {
                wpa_s->ext_mgmt_frame_handling = !!atoi(value);
@@ -575,9 +656,54 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
                wpa_s->ignore_auth_resp = !!atoi(value);
        } else if (os_strcasecmp(cmd, "ignore_assoc_disallow") == 0) {
                wpa_s->ignore_assoc_disallow = !!atoi(value);
+               wpa_drv_ignore_assoc_disallow(wpa_s,
+                                             wpa_s->ignore_assoc_disallow);
        } else if (os_strcasecmp(cmd, "reject_btm_req_reason") == 0) {
                wpa_s->reject_btm_req_reason = atoi(value);
+       } else if (os_strcasecmp(cmd, "get_pref_freq_list_override") == 0) {
+               os_free(wpa_s->get_pref_freq_list_override);
+               if (!value[0])
+                       wpa_s->get_pref_freq_list_override = NULL;
+               else
+                       wpa_s->get_pref_freq_list_override = os_strdup(value);
+       } else if (os_strcasecmp(cmd, "sae_commit_override") == 0) {
+               wpabuf_free(wpa_s->sae_commit_override);
+               if (value[0] == '\0')
+                       wpa_s->sae_commit_override = NULL;
+               else
+                       wpa_s->sae_commit_override = wpabuf_parse_bin(value);
+#ifdef CONFIG_DPP
+       } else if (os_strcasecmp(cmd, "dpp_config_obj_override") == 0) {
+               os_free(wpa_s->dpp_config_obj_override);
+               if (value[0] == '\0')
+                       wpa_s->dpp_config_obj_override = NULL;
+               else
+                       wpa_s->dpp_config_obj_override = os_strdup(value);
+       } else if (os_strcasecmp(cmd, "dpp_discovery_override") == 0) {
+               os_free(wpa_s->dpp_discovery_override);
+               if (value[0] == '\0')
+                       wpa_s->dpp_discovery_override = NULL;
+               else
+                       wpa_s->dpp_discovery_override = os_strdup(value);
+       } else if (os_strcasecmp(cmd, "dpp_groups_override") == 0) {
+               os_free(wpa_s->dpp_groups_override);
+               if (value[0] == '\0')
+                       wpa_s->dpp_groups_override = NULL;
+               else
+                       wpa_s->dpp_groups_override = os_strdup(value);
+       } else if (os_strcasecmp(cmd,
+                                "dpp_ignore_netaccesskey_mismatch") == 0) {
+               wpa_s->dpp_ignore_netaccesskey_mismatch = atoi(value);
+       } else if (os_strcasecmp(cmd, "dpp_test") == 0) {
+               dpp_test = atoi(value);
+#endif /* CONFIG_DPP */
 #endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_FILS
+       } else if (os_strcasecmp(cmd, "disable_fils") == 0) {
+               wpa_s->disable_fils = !!atoi(value);
+               wpa_drv_disable_fils(wpa_s, wpa_s->disable_fils);
+               wpa_supplicant_set_default_scan_ies(wpa_s);
+#endif /* CONFIG_FILS */
 #ifndef CONFIG_NO_CONFIG_BLOBS
        } else if (os_strcmp(cmd, "blob") == 0) {
                ret = wpas_ctrl_set_blob(wpa_s, value);
@@ -593,6 +719,25 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
                }
        } else if (os_strcasecmp(cmd, "mbo_cell_capa") == 0) {
                wpas_mbo_update_cell_capa(wpa_s, atoi(value));
+       } else if (os_strcasecmp(cmd, "oce") == 0) {
+               wpa_s->conf->oce = atoi(value);
+               if (wpa_s->conf->oce) {
+                       if ((wpa_s->conf->oce & OCE_STA) &&
+                           (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OCE_STA))
+                               wpa_s->enable_oce = OCE_STA;
+
+                       if ((wpa_s->conf->oce & OCE_STA_CFON) &&
+                           (wpa_s->drv_flags &
+                            WPA_DRIVER_FLAGS_OCE_STA_CFON)) {
+                               /* TODO: Need to add STA-CFON support */
+                               wpa_printf(MSG_ERROR,
+                                          "OCE STA-CFON feature is not yet supported");
+                               return -1;
+                       }
+               } else {
+                       wpa_s->enable_oce = 0;
+               }
+               wpa_supplicant_set_default_scan_ies(wpa_s);
 #endif /* CONFIG_MBO */
        } else if (os_strcasecmp(cmd, "lci") == 0) {
                ret = wpas_ctrl_iface_set_lci(wpa_s, value);
@@ -602,6 +747,19 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
                ret = wpas_ctrl_set_relative_rssi(wpa_s, value);
        } else if (os_strcasecmp(cmd, "relative_band_adjust") == 0) {
                ret = wpas_ctrl_set_relative_band_adjust(wpa_s, value);
+       } else if (os_strcasecmp(cmd, "ric_ies") == 0) {
+               ret = wpas_ctrl_iface_set_ric_ies(wpa_s, value);
+       } else if (os_strcasecmp(cmd, "roaming") == 0) {
+               ret = wpa_drv_roaming(wpa_s, atoi(value), NULL);
+#ifdef CONFIG_WNM
+       } else if (os_strcasecmp(cmd, "coloc_intf_elems") == 0) {
+               struct wpabuf *elems;
+
+               elems = wpabuf_parse_bin(value);
+               if (!elems)
+                       return -1;
+               wnm_set_coloc_intf_elems(wpa_s, elems);
+#endif /* CONFIG_WNM */
        } else {
                value[-1] = '=';
                ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
@@ -647,6 +805,12 @@ static int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_TESTING_GET_GTK */
        } else if (os_strcmp(cmd, "tls_library") == 0) {
                res = tls_get_library_version(buf, buflen);
+#ifdef CONFIG_TESTING_OPTIONS
+       } else if (os_strcmp(cmd, "anonce") == 0) {
+               return wpa_snprintf_hex(buf, buflen,
+                                       wpa_sm_get_anonce(wpa_s->wpa),
+                                       WPA_NONCE_LEN);
+#endif /* CONFIG_TESTING_OPTIONS */
        } else {
                res = wpa_config_get_value(cmd, wpa_s->conf, buf, buflen);
        }
@@ -680,27 +844,6 @@ static int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s,
 #endif /* IEEE8021X_EAPOL */
 
 
-#ifdef CONFIG_PEERKEY
-/* MLME-STKSTART.request(peer) */
-static int wpa_supplicant_ctrl_iface_stkstart(
-       struct wpa_supplicant *wpa_s, char *addr)
-{
-       u8 peer[ETH_ALEN];
-
-       if (hwaddr_aton(addr, peer)) {
-               wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART: invalid "
-                          "address '%s'", addr);
-               return -1;
-       }
-
-       wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART " MACSTR,
-                  MAC2STR(peer));
-
-       return wpa_sm_stkstart(wpa_s->wpa, peer);
-}
-#endif /* CONFIG_PEERKEY */
-
-
 #ifdef CONFIG_TDLS
 
 static int wpa_supplicant_ctrl_iface_tdls_discover(
@@ -1025,8 +1168,11 @@ static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s,
 #ifdef CONFIG_AP
        u8 *_p2p_dev_addr = NULL;
 #endif /* CONFIG_AP */
+       char *pos;
+       int multi_ap = 0;
 
-       if (cmd == NULL || os_strcmp(cmd, "any") == 0) {
+       if (!cmd || os_strcmp(cmd, "any") == 0 ||
+           os_strncmp(cmd, "any ", 4) == 0) {
                _bssid = NULL;
 #ifdef CONFIG_P2P
        } else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
@@ -1038,18 +1184,29 @@ static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s,
                }
                _p2p_dev_addr = p2p_dev_addr;
 #endif /* CONFIG_P2P */
+       } else if (os_strncmp(cmd, "multi_ap=", 9) == 0) {
+               _bssid = NULL;
+               multi_ap = atoi(cmd + 9);
        } else if (hwaddr_aton(cmd, bssid)) {
                wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'",
                           cmd);
                return -1;
        }
 
+       if (cmd) {
+               pos = os_strstr(cmd, " multi_ap=");
+               if (pos) {
+                       pos += 10;
+                       multi_ap = atoi(pos);
+               }
+       }
+
 #ifdef CONFIG_AP
        if (wpa_s->ap_iface)
                return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid, _p2p_dev_addr);
 #endif /* CONFIG_AP */
 
-       return wpas_wps_start_pbc(wpa_s, _bssid, 0);
+       return wpas_wps_start_pbc(wpa_s, _bssid, 0, multi_ap);
 }
 
 
@@ -1975,6 +2132,18 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
                        pos += ret;
                }
 
+               if (wpa_s->connection_set &&
+                   (wpa_s->connection_ht || wpa_s->connection_vht ||
+                    wpa_s->connection_he)) {
+                       ret = os_snprintf(pos, end - pos,
+                                         "wifi_generation=%u\n",
+                                         wpa_s->connection_he ? 6 :
+                                         (wpa_s->connection_vht ? 5 : 4));
+                       if (os_snprintf_error(end - pos, ret))
+                               return pos - buf;
+                       pos += ret;
+               }
+
 #ifdef CONFIG_AP
                if (wpa_s->ap_iface) {
                        pos += ap_ctrl_iface_wpa_get_status(wpa_s, pos,
@@ -2159,6 +2328,13 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
        }
 #endif /* CONFIG_WPS */
 
+       if (wpa_s->ieee80211ac) {
+               ret = os_snprintf(pos, end - pos, "ieee80211ac=1\n");
+               if (os_snprintf_error(end - pos, ret))
+                       return pos - buf;
+               pos += ret;
+       }
+
 #ifdef ANDROID
        /*
         * Allow using the STATUS command with default behavior, say for debug,
@@ -2548,6 +2724,26 @@ static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
 #endif /* CONFIG_IEEE80211R */
 #endif /* CONFIG_FILS */
 
+#ifdef CONFIG_OWE
+       if (data.key_mgmt & WPA_KEY_MGMT_OWE) {
+               ret = os_snprintf(pos, end - pos, "%sOWE",
+                                 pos == start ? "" : "+");
+               if (os_snprintf_error(end - pos, ret))
+                       return pos;
+               pos += ret;
+       }
+#endif /* CONFIG_OWE */
+
+#ifdef CONFIG_DPP
+       if (data.key_mgmt & WPA_KEY_MGMT_DPP) {
+               ret = os_snprintf(pos, end - pos, "%sDPP",
+                                 pos == start ? "" : "+");
+               if (os_snprintf_error(end - pos, ret))
+                       return pos;
+               pos += ret;
+       }
+#endif /* CONFIG_DPP */
+
        if (data.key_mgmt & WPA_KEY_MGMT_OSEN) {
                ret = os_snprintf(pos, end - pos, "%sOSEN",
                                  pos == start ? "" : "+");
@@ -2623,7 +2819,7 @@ static int wpa_supplicant_ctrl_iface_scan_result(
 {
        char *pos, *end;
        int ret;
-       const u8 *ie, *ie2, *osen_ie, *p2p, *mesh;
+       const u8 *ie, *ie2, *osen_ie, *p2p, *mesh, *owe;
 
        mesh = wpa_bss_get_ie(bss, WLAN_EID_MESH_ID);
        p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
@@ -2654,6 +2850,14 @@ static int wpa_supplicant_ctrl_iface_scan_result(
        if (osen_ie)
                pos = wpa_supplicant_ie_txt(pos, end, "OSEN",
                                            osen_ie, 2 + osen_ie[1]);
+       owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE);
+       if (owe) {
+               ret = os_snprintf(pos, end - pos,
+                                 ie2 ? "[OWE-TRANS]" : "[OWE-TRANS-OPEN]");
+               if (os_snprintf_error(end - pos, ret))
+                       return -1;
+               pos += ret;
+       }
        pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
        if (!ie && !ie2 && !osen_ie && (bss->caps & IEEE80211_CAP_PRIVACY)) {
                ret = os_snprintf(pos, end - pos, "[WEP]");
@@ -2735,6 +2939,12 @@ static int wpa_supplicant_ctrl_iface_scan_result(
                pos += ret;
        }
 #endif /* CONFIG_FST */
+       if (wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_UTF_8_SSID)) {
+               ret = os_snprintf(pos, end - pos, "[UTF-8]");
+               if (os_snprintf_error(end - pos, ret))
+                       return -1;
+               pos += ret;
+       }
 
        ret = os_snprintf(pos, end - pos, "\t%s",
                          wpa_ssid_txt(bss->ssid, bss->ssid_len));
@@ -2919,6 +3129,49 @@ static int wpa_supplicant_ctrl_iface_mesh_peer_add(
        return wpas_mesh_peer_add(wpa_s, addr, duration);
 }
 
+
+static int wpa_supplicant_ctrl_iface_mesh_link_probe(
+       struct wpa_supplicant *wpa_s, char *cmd)
+{
+       struct ether_header *eth;
+       u8 addr[ETH_ALEN];
+       u8 *buf;
+       char *pos;
+       size_t payload_len = 0, len;
+       int ret = -1;
+
+       if (hwaddr_aton(cmd, addr))
+               return -1;
+
+       pos = os_strstr(cmd, " payload=");
+       if (pos) {
+               pos = pos + 9;
+               payload_len = os_strlen(pos);
+               if (payload_len & 1)
+                       return -1;
+
+               payload_len /= 2;
+       }
+
+       len = ETH_HLEN + payload_len;
+       buf = os_malloc(len);
+       if (!buf)
+               return -1;
+
+       eth = (struct ether_header *) buf;
+       os_memcpy(eth->ether_dhost, addr, ETH_ALEN);
+       os_memcpy(eth->ether_shost, wpa_s->own_addr, ETH_ALEN);
+       eth->ether_type = htons(ETH_P_802_3);
+
+       if (payload_len && hexstr2bin(pos, buf + ETH_HLEN, payload_len) < 0)
+               goto fail;
+
+       ret = wpa_drv_mesh_link_probe(wpa_s, addr, buf, len);
+fail:
+       os_free(buf);
+       return -ret;
+}
+
 #endif /* CONFIG_MESH */
 
 
@@ -2954,9 +3207,8 @@ static int wpa_supplicant_ctrl_iface_select_network(
        if (pos) {
                int *freqs = freq_range_to_channel_list(wpa_s, pos + 6);
                if (freqs) {
-                       wpa_s->scan_req = MANUAL_SCAN_REQ;
-                       os_free(wpa_s->manual_scan_freqs);
-                       wpa_s->manual_scan_freqs = freqs;
+                       os_free(wpa_s->select_network_scan_freqs);
+                       wpa_s->select_network_scan_freqs = freqs;
                }
        }
 
@@ -3131,6 +3383,7 @@ static int wpa_supplicant_ctrl_iface_update_network(
                return 0; /* No change to the previously configured value */
 
        if (os_strcmp(name, "bssid") != 0 &&
+           os_strcmp(name, "bssid_hint") != 0 &&
            os_strcmp(name, "priority") != 0) {
                wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
 
@@ -3766,6 +4019,66 @@ static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
                pos += ret;
        }
 #endif /* CONFIG_SUITEB192 */
+#ifdef CONFIG_OWE
+       if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_OWE) {
+               ret = os_snprintf(pos, end - pos, " OWE");
+               if (os_snprintf_error(end - pos, ret))
+                       return pos - buf;
+               pos += ret;
+       }
+#endif /* CONFIG_OWE */
+#ifdef CONFIG_DPP
+       if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_DPP) {
+               ret = os_snprintf(pos, end - pos, " DPP");
+               if (os_snprintf_error(end - pos, ret))
+                       return pos - buf;
+               pos += ret;
+       }
+#endif /* CONFIG_DPP */
+#ifdef CONFIG_FILS
+       if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256) {
+               ret = os_snprintf(pos, end - pos, " FILS-SHA256");
+               if (os_snprintf_error(end - pos, ret))
+                       return pos - buf;
+               pos += ret;
+       }
+       if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384) {
+               ret = os_snprintf(pos, end - pos, " FILS-SHA384");
+               if (os_snprintf_error(end - pos, ret))
+                       return pos - buf;
+               pos += ret;
+       }
+#ifdef CONFIG_IEEE80211R
+       if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256) {
+               ret = os_snprintf(pos, end - pos, " FT-FILS-SHA256");
+               if (os_snprintf_error(end - pos, ret))
+                       return pos - buf;
+               pos += ret;
+       }
+       if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384) {
+               ret = os_snprintf(pos, end - pos, " FT-FILS-SHA384");
+               if (os_snprintf_error(end - pos, ret))
+                       return pos - buf;
+               pos += ret;
+       }
+#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211R
+       if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK) {
+               ret = os_snprintf(pos, end - pos, " FT-PSK");
+               if (os_snprintf_error(end - pos, ret))
+                       return pos - buf;
+               pos += ret;
+       }
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SAE
+       if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE) {
+               ret = os_snprintf(pos, end - pos, " SAE");
+               if (os_snprintf_error(end - pos, ret))
+                       return pos - buf;
+               pos += ret;
+       }
+#endif /* CONFIG_SAE */
 
        return pos - buf;
 }
@@ -3868,6 +4181,26 @@ static int ctrl_iface_get_capability_auth_alg(struct wpa_supplicant *wpa_s,
        }
 #endif /* CONFIG_SAE */
 
+#ifdef CONFIG_FILS
+       if (wpa_is_fils_supported(wpa_s)) {
+               ret = os_snprintf(pos, end - pos, "%sFILS_SK_WITHOUT_PFS",
+                                 pos == buf ? "" : " ");
+               if (os_snprintf_error(end - pos, ret))
+                       return pos - buf;
+               pos += ret;
+       }
+
+#ifdef CONFIG_FILS_SK_PFS
+       if (wpa_is_fils_sk_pfs_supported(wpa_s)) {
+               ret = os_snprintf(pos, end - pos, "%sFILS_SK_WITH_PFS",
+                                 pos == buf ? "" : " ");
+               if (os_snprintf_error(end - pos, ret))
+                       return pos - buf;
+               pos += ret;
+       }
+#endif /* CONFIG_FILS_SK_PFS */
+#endif /* CONFIG_FILS */
+
        return pos - buf;
 }
 
@@ -4126,14 +4459,45 @@ static int wpa_supplicant_ctrl_iface_get_capability(
 #endif /* CONFIG_ACS */
 
 #ifdef CONFIG_FILS
-       if (os_strcmp(field, "fils") == 0 &&
-           (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_FILS)) {
-               res = os_snprintf(buf, buflen, "FILS");
+       if (os_strcmp(field, "fils") == 0) {
+#ifdef CONFIG_FILS_SK_PFS
+               if (wpa_is_fils_supported(wpa_s) &&
+                   wpa_is_fils_sk_pfs_supported(wpa_s)) {
+                       res = os_snprintf(buf, buflen, "FILS FILS-SK-PFS");
+                       if (os_snprintf_error(buflen, res))
+                               return -1;
+                       return res;
+               }
+#endif /* CONFIG_FILS_SK_PFS */
+
+               if (wpa_is_fils_supported(wpa_s)) {
+                       res = os_snprintf(buf, buflen, "FILS");
+                       if (os_snprintf_error(buflen, res))
+                               return -1;
+                       return res;
+               }
+       }
+#endif /* CONFIG_FILS */
+
+       if (os_strcmp(field, "multibss") == 0 && wpa_s->multi_bss_support) {
+               res = os_snprintf(buf, buflen, "MULTIBSS-STA");
                if (os_snprintf_error(buflen, res))
                        return -1;
                return res;
        }
-#endif /* CONFIG_FILS */
+
+#ifdef CONFIG_DPP
+       if (os_strcmp(field, "dpp") == 0) {
+#ifdef CONFIG_DPP2
+               res = os_snprintf(buf, buflen, "DPP=2");
+#else /* CONFIG_DPP2 */
+               res = os_snprintf(buf, buflen, "DPP=1");
+#endif /* CONFIG_DPP2 */
+               if (os_snprintf_error(buflen, res))
+                       return -1;
+               return res;
+       }
+#endif /* CONFIG_DPP */
 
        wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
                   field);
@@ -4255,7 +4619,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, *osen_ie, *mesh;
+       const u8 *ie, *ie2, *osen_ie, *mesh, *owe;
 
        pos = buf;
        end = buf + buflen;
@@ -4379,6 +4743,15 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
                if (osen_ie)
                        pos = wpa_supplicant_ie_txt(pos, end, "OSEN",
                                                    osen_ie, 2 + osen_ie[1]);
+               owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE);
+               if (owe) {
+                       ret = os_snprintf(
+                               pos, end - pos,
+                               ie2 ? "[OWE-TRANS]" : "[OWE-TRANS-OPEN]");
+                       if (os_snprintf_error(end - pos, ret))
+                               return 0;
+                       pos += ret;
+               }
                pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
                if (!ie && !ie2 && !osen_ie &&
                    (bss->caps & IEEE80211_CAP_PRIVACY)) {
@@ -4456,6 +4829,20 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
                        pos += ret;
                }
 #endif /* CONFIG_FILS */
+#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 0;
+                       pos += ret;
+               }
+#endif /* CONFIG_FST */
+               if (wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_UTF_8_SSID)) {
+                       ret = os_snprintf(pos, end - pos, "[UTF-8]");
+                       if (os_snprintf_error(end - pos, ret))
+                               return 0;
+                       pos += ret;
+               }
 
                ret = os_snprintf(pos, end - pos, "\n");
                if (os_snprintf_error(end - pos, ret))
@@ -4555,6 +4942,10 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
                                   anqp->hs20_operating_class);
                pos = anqp_add_hex(pos, end, "hs20_osu_providers_list",
                                   anqp->hs20_osu_providers_list);
+               pos = anqp_add_hex(pos, end, "hs20_operator_icon_metadata",
+                                  anqp->hs20_operator_icon_metadata);
+               pos = anqp_add_hex(pos, end, "hs20_osu_providers_nai_list",
+                                  anqp->hs20_osu_providers_nai_list);
 #endif /* CONFIG_HS20 */
 
                dl_list_for_each(elem, &anqp->anqp_elems,
@@ -4748,10 +5139,11 @@ static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
                bss = NULL;
                dl_list_for_each(tmp, &wpa_s->bss_id, struct wpa_bss, list_id)
                {
-                       if (i-- == 0) {
+                       if (i == 0) {
                                bss = tmp;
                                break;
                        }
+                       i--;
                }
        }
 
@@ -5199,17 +5591,17 @@ static int parse_freq(int chwidth, int freq2)
        if (freq2 < 0)
                return -1;
        if (freq2)
-               return VHT_CHANWIDTH_80P80MHZ;
+               return CHANWIDTH_80P80MHZ;
 
        switch (chwidth) {
        case 0:
        case 20:
        case 40:
-               return VHT_CHANWIDTH_USE_HT;
+               return CHANWIDTH_USE_HT;
        case 80:
-               return VHT_CHANWIDTH_80MHZ;
+               return CHANWIDTH_80MHZ;
        case 160:
-               return VHT_CHANWIDTH_160MHZ;
+               return CHANWIDTH_160MHZ;
        default:
                wpa_printf(MSG_DEBUG, "Unknown max oper bandwidth: %d",
                           chwidth);
@@ -5237,6 +5629,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
        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;
+       int he;
 
        if (!wpa_s->global->p2p_init_wpa_s)
                return -1;
@@ -5249,7 +5642,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] [ssid=<hexdump>] */
+        * [ht40] [vht] [he] [auto] [ssid=<hexdump>] */
 
        if (hwaddr_aton(cmd, addr))
                return -1;
@@ -5280,6 +5673,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
        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;
+       he = (os_strstr(cmd, " he") != NULL) || wpa_s->conf->p2p_go_he;
 
        pos2 = os_strstr(pos, " go_intent=");
        if (pos2) {
@@ -5350,7 +5744,7 @@ 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, freq2, persistent_id,
-                                  pd, ht40, vht, max_oper_chwidth,
+                                  pd, ht40, vht, max_oper_chwidth, he,
                                   group_ssid, group_ssid_len);
        if (new_pin == -2) {
                os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
@@ -5906,7 +6300,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, max_oper_chwidth, chwidth = 0, freq2 = 0;
+       int ht40, vht, he, max_oper_chwidth, chwidth = 0, freq2 = 0;
 
        id = atoi(cmd);
        pos = os_strstr(cmd, " peer=");
@@ -5943,6 +6337,7 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
        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;
+       he = (os_strstr(cmd, " he") != NULL) || wpa_s->conf->p2p_go_he;
 
        pos = os_strstr(cmd, "freq2=");
        if (pos)
@@ -5957,7 +6352,7 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
                return -1;
 
        return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, freq2, ht40, vht,
-                              max_oper_chwidth, pref_freq);
+                              max_oper_chwidth, pref_freq, he);
 }
 
 
@@ -6005,7 +6400,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 vht_center_freq2,
-                                        int ht40, int vht, int vht_chwidth)
+                                        int ht40, int vht, int vht_chwidth,
+                                        int he)
 {
        struct wpa_ssid *ssid;
 
@@ -6019,7 +6415,7 @@ static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
 
        return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq,
                                             vht_center_freq2, 0, ht40, vht,
-                                            vht_chwidth, NULL, 0, 0);
+                                            vht_chwidth, he, NULL, 0, 0);
 }
 
 
@@ -6028,20 +6424,31 @@ 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 he = wpa_s->conf->p2p_go_he;
        int max_oper_chwidth, chwidth = 0, freq2 = 0;
        char *token, *context = NULL;
+#ifdef CONFIG_ACS
+       int acs = 0;
+#endif /* CONFIG_ACS */
 
        while ((token = str_token(cmd, " ", &context))) {
-               if (sscanf(token, "freq=%d", &freq) == 1 ||
-                   sscanf(token, "freq2=%d", &freq2) == 1 ||
+               if (sscanf(token, "freq2=%d", &freq2) == 1 ||
                    sscanf(token, "persistent=%d", &group_id) == 1 ||
                    sscanf(token, "max_oper_chwidth=%d", &chwidth) == 1) {
                        continue;
+#ifdef CONFIG_ACS
+               } else if (os_strcmp(token, "freq=acs") == 0) {
+                       acs = 1;
+#endif /* CONFIG_ACS */
+               } else if (sscanf(token, "freq=%d", &freq) == 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, "he") == 0) {
+                       he = 1;
                } else if (os_strcmp(token, "persistent") == 0) {
                        persistent = 1;
                } else {
@@ -6052,6 +6459,26 @@ static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
                }
        }
 
+#ifdef CONFIG_ACS
+       if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) &&
+           (acs || freq == 2 || freq == 5)) {
+               if (freq == 2 && wpa_s->best_24_freq <= 0) {
+                       wpa_s->p2p_go_acs_band = HOSTAPD_MODE_IEEE80211G;
+                       wpa_s->p2p_go_do_acs = 1;
+                       freq = 0;
+               } else if (freq == 5 && wpa_s->best_5_freq <= 0) {
+                       wpa_s->p2p_go_acs_band = HOSTAPD_MODE_IEEE80211A;
+                       wpa_s->p2p_go_do_acs = 1;
+                       freq = 0;
+               } else {
+                       wpa_s->p2p_go_acs_band = HOSTAPD_MODE_IEEE80211ANY;
+                       wpa_s->p2p_go_do_acs = 1;
+               }
+       } else {
+               wpa_s->p2p_go_do_acs = 0;
+       }
+#endif /* CONFIG_ACS */
+
        max_oper_chwidth = parse_freq(chwidth, freq2);
        if (max_oper_chwidth < 0)
                return -1;
@@ -6059,10 +6486,10 @@ static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
        if (group_id >= 0)
                return p2p_ctrl_group_add_persistent(wpa_s, group_id,
                                                     freq, freq2, ht40, vht,
-                                                    max_oper_chwidth);
+                                                    max_oper_chwidth, he);
 
        return wpas_p2p_group_add(wpa_s, persistent, freq, freq2, ht40, vht,
-                                 max_oper_chwidth);
+                                 max_oper_chwidth, he);
 }
 
 
@@ -6451,6 +6878,20 @@ static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
                return 0;
        }
 
+       if (os_strcmp(cmd, "override_pref_op_chan") == 0) {
+               int op_class, chan;
+
+               op_class = atoi(param);
+               param = os_strchr(param, ':');
+               if (!param)
+                       return -1;
+               param++;
+               chan = atoi(param);
+               p2p_set_override_pref_op_chan(wpa_s->global->p2p, op_class,
+                                             chan);
+               return 0;
+       }
+
        wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'",
                   cmd);
 
@@ -6462,6 +6903,12 @@ static void p2p_ctrl_flush(struct wpa_supplicant *wpa_s)
 {
        os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
        wpa_s->force_long_sd = 0;
+
+#ifdef CONFIG_TESTING_OPTIONS
+       os_free(wpa_s->get_pref_freq_list_override);
+       wpa_s->get_pref_freq_list_override = NULL;
+#endif /* CONFIG_TESTING_OPTIONS */
+
        wpas_p2p_stop_find(wpa_s);
        wpa_s->parent->p2ps_method_config_any = 0;
        if (wpa_s->global->p2p)
@@ -6669,7 +7116,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;
+       u32 mbo_subtypes = 0;
 
        used = hwaddr_aton2(dst, dst_addr);
        if (used < 0)
@@ -6690,9 +7137,10 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
                } else if (os_strncmp(pos, "mbo:", 4) == 0) {
 #ifdef CONFIG_MBO
                        int num = atoi(pos + 4);
-                       if (num != MBO_ANQP_SUBTYPE_CELL_CONN_PREF)
+
+                       if (num <= 0 || num > MAX_MBO_ANQP_SUBTYPE)
                                return -1;
-                       get_cell_pref = 1;
+                       mbo_subtypes |= BIT(num);
 #else /* CONFIG_MBO */
                        return -1;
 #endif /* CONFIG_MBO */
@@ -6707,11 +7155,11 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
                pos++;
        }
 
-       if (num_id == 0)
+       if (num_id == 0 && !subtypes && !mbo_subtypes)
                return -1;
 
        return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes,
-                            get_cell_pref);
+                            mbo_subtypes);
 }
 
 
@@ -7113,26 +7561,41 @@ 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, list = 0;
+       char *btm_candidates = NULL;
 
        query_reason = atoi(cmd);
 
        cmd = os_strchr(cmd, ' ');
        if (cmd) {
-               cmd++;
-               if (os_strncmp(cmd, "list", 4) == 0) {
+               if (os_strncmp(cmd, " list", 5) == 0)
                        list = 1;
-               } else {
-                       wpa_printf(MSG_DEBUG, "WNM Query: Invalid option %s",
-                                  cmd);
-                       return -1;
-               }
+               else
+                       btm_candidates = cmd;
        }
 
        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);
+       return wnm_send_bss_transition_mgmt_query(wpa_s, query_reason,
+                                                 btm_candidates,
+                                                 list);
+}
+
+
+static int wpas_ctrl_iface_coloc_intf_report(struct wpa_supplicant *wpa_s,
+                                            char *cmd)
+{
+       struct wpabuf *elems;
+       int ret;
+
+       elems = wpabuf_parse_bin(cmd);
+       if (!elems)
+               return -1;
+
+       ret = wnm_send_coloc_intf_report(wpa_s, 0, elems);
+       wpabuf_free(elems);
+       return ret;
 }
 
 #endif /* CONFIG_WNM */
@@ -7168,10 +7631,17 @@ static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf,
                pos += ret;
        }
 
-       if (si.center_frq1 > 0 && si.center_frq2 > 0) {
-               ret = os_snprintf(pos, end - pos,
-                                 "CENTER_FRQ1=%d\nCENTER_FRQ2=%d\n",
-                                 si.center_frq1, si.center_frq2);
+       if (si.center_frq1 > 0) {
+               ret = os_snprintf(pos, end - pos, "CENTER_FRQ1=%d\n",
+                                 si.center_frq1);
+               if (os_snprintf_error(end - pos, ret))
+                       return -1;
+               pos += ret;
+       }
+
+       if (si.center_frq2 > 0) {
+               ret = os_snprintf(pos, end - pos, "CENTER_FRQ2=%d\n",
+                                 si.center_frq2);
                if (os_snprintf_error(end - pos, ret))
                        return -1;
                pos += ret;
@@ -7219,6 +7689,46 @@ static int wpas_ctrl_iface_signal_monitor(struct wpa_supplicant *wpa_s,
 }
 
 
+#ifdef CONFIG_TESTING_OPTIONS
+int wpas_ctrl_iface_get_pref_freq_list_override(struct wpa_supplicant *wpa_s,
+                                               enum wpa_driver_if_type if_type,
+                                               unsigned int *num,
+                                               unsigned int *freq_list)
+{
+       char *pos = wpa_s->get_pref_freq_list_override;
+       char *end;
+       unsigned int count = 0;
+
+       /* Override string format:
+        *  <if_type1>:<freq1>,<freq2>,... <if_type2>:... */
+
+       while (pos) {
+               if (atoi(pos) == (int) if_type)
+                       break;
+               pos = os_strchr(pos, ' ');
+               if (pos)
+                       pos++;
+       }
+       if (!pos)
+               return -1;
+       pos = os_strchr(pos, ':');
+       if (!pos)
+               return -1;
+       pos++;
+       end = os_strchr(pos, ' ');
+       while (pos && (!end || pos < end) && count < *num) {
+               freq_list[count++] = atoi(pos);
+               pos = os_strchr(pos, ',');
+               if (pos)
+                       pos++;
+       }
+
+       *num = count;
+       return 0;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
 static int wpas_ctrl_iface_get_pref_freq_list(
        struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
 {
@@ -7248,7 +7758,7 @@ static int wpas_ctrl_iface_get_pref_freq_list(
 
        wpa_printf(MSG_DEBUG,
                   "CTRL_IFACE: GET_PREF_FREQ_LIST iface_type=%d (%s)",
-                  iface_type, buf);
+                  iface_type, cmd);
 
        ret = wpa_drv_get_pref_freq_list(wpa_s, iface_type, &num, freq_list);
        if (ret)
@@ -7447,6 +7957,22 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
        wpa_s->after_wps = 0;
        wpa_s->known_wps_freq = 0;
 
+#ifdef CONFIG_DPP
+       wpas_dpp_deinit(wpa_s);
+       wpa_s->dpp_init_max_tries = 0;
+       wpa_s->dpp_init_retry_time = 0;
+       wpa_s->dpp_resp_wait_time = 0;
+       wpa_s->dpp_resp_max_tries = 0;
+       wpa_s->dpp_resp_retry_time = 0;
+#ifdef CONFIG_TESTING_OPTIONS
+       os_memset(dpp_pkex_own_mac_override, 0, ETH_ALEN);
+       os_memset(dpp_pkex_peer_mac_override, 0, ETH_ALEN);
+       dpp_pkex_ephemeral_key_override_len = 0;
+       dpp_protocol_key_override_len = 0;
+       dpp_nonce_override_len = 0;
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_DPP */
+
 #ifdef CONFIG_TDLS
 #ifdef CONFIG_TDLS_TESTING
        tdls_testing = 0;
@@ -7508,13 +8034,29 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
        wpa_s->p2p_go_csa_on_inv = 0;
        wpa_s->ignore_auth_resp = 0;
        wpa_s->ignore_assoc_disallow = 0;
+       wpa_s->testing_resend_assoc = 0;
        wpa_s->reject_btm_req_reason = 0;
        wpa_sm_set_test_assoc_ie(wpa_s->wpa, NULL);
+       os_free(wpa_s->get_pref_freq_list_override);
+       wpa_s->get_pref_freq_list_override = NULL;
+       wpabuf_free(wpa_s->sae_commit_override);
+       wpa_s->sae_commit_override = NULL;
+#ifdef CONFIG_DPP
+       os_free(wpa_s->dpp_config_obj_override);
+       wpa_s->dpp_config_obj_override = NULL;
+       os_free(wpa_s->dpp_discovery_override);
+       wpa_s->dpp_discovery_override = NULL;
+       os_free(wpa_s->dpp_groups_override);
+       wpa_s->dpp_groups_override = NULL;
+       dpp_test = DPP_TEST_DISABLED;
+#endif /* CONFIG_DPP */
 #endif /* CONFIG_TESTING_OPTIONS */
 
        wpa_s->disconnected = 0;
        os_free(wpa_s->next_scan_freqs);
        wpa_s->next_scan_freqs = NULL;
+       os_free(wpa_s->select_network_scan_freqs);
+       wpa_s->select_network_scan_freqs = NULL;
 
        wpa_bss_flush(wpa_s);
        if (!dl_list_empty(&wpa_s->bss)) {
@@ -7532,6 +8074,13 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
 #ifdef CONFIG_SME
        wpa_s->sme.last_unprot_disconnect.sec = 0;
 #endif /* CONFIG_SME */
+
+       wpabuf_free(wpa_s->ric_ies);
+       wpa_s->ric_ies = NULL;
+
+       wpa_supplicant_update_channel_list(wpa_s, NULL);
+
+       free_bss_tmp_disallowed(wpa_s);
 }
 
 
@@ -7829,6 +8378,19 @@ static void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params,
                        goto done;
                }
 
+               pos = os_strstr(params, "bssid=");
+               if (pos) {
+                       u8 bssid[ETH_ALEN];
+
+                       pos += 6;
+                       if (hwaddr_aton(pos, bssid)) {
+                               wpa_printf(MSG_ERROR, "Invalid BSSID %s", pos);
+                               *reply_len = -1;
+                               goto done;
+                       }
+                       os_memcpy(wpa_s->next_scan_bssid, bssid, ETH_ALEN);
+               }
+
                pos = params;
                while (pos && *pos != '\0') {
                        if (os_strncmp(pos, "ssid ", 5) == 0) {
@@ -8341,26 +8903,39 @@ static void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
        struct iphdr ip;
        const u8 *pos;
        unsigned int i;
+       char extra[30];
 
-       if (len != HWSIM_PACKETLEN)
+       if (len < sizeof(*eth) + sizeof(ip) || len > HWSIM_PACKETLEN) {
+               wpa_printf(MSG_DEBUG,
+                          "test data: RX - ignore unexpected length %d",
+                          (int) len);
                return;
+       }
 
        eth = (const struct ether_header *) buf;
        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)
+           ntohs(ip.tot_len) > HWSIM_IP_LEN) {
+               wpa_printf(MSG_DEBUG,
+                          "test data: RX - ignore unexpect IP header");
                return;
+       }
 
-       for (i = 0; i < HWSIM_IP_LEN - sizeof(ip); i++) {
-               if (*pos != (u8) i)
+       for (i = 0; i < ntohs(ip.tot_len) - sizeof(ip); i++) {
+               if (*pos != (u8) i) {
+                       wpa_printf(MSG_DEBUG,
+                                  "test data: RX - ignore mismatching payload");
                        return;
+               }
                pos++;
        }
-
-       wpa_msg(wpa_s, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR,
-               MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost));
+       extra[0] = '\0';
+       if (ntohs(ip.tot_len) != HWSIM_IP_LEN)
+               os_snprintf(extra, sizeof(extra), " len=%d", ntohs(ip.tot_len));
+       wpa_msg(wpa_s, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR "%s",
+               MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost), extra);
 }
 
 
@@ -8404,7 +8979,7 @@ static int wpas_ctrl_iface_data_test_config(struct wpa_supplicant *wpa_s,
 static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd)
 {
        u8 dst[ETH_ALEN], src[ETH_ALEN];
-       char *pos;
+       char *pos, *pos2;
        int used;
        long int val;
        u8 tos;
@@ -8413,11 +8988,12 @@ static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd)
        struct iphdr *ip;
        u8 *dpos;
        unsigned int i;
+       size_t send_len = HWSIM_IP_LEN;
 
        if (wpa_s->l2_test == NULL)
                return -1;
 
-       /* format: <dst> <src> <tos> */
+       /* format: <dst> <src> <tos> [len=<length>] */
 
        pos = cmd;
        used = hwaddr_aton2(pos, dst);
@@ -8431,11 +9007,19 @@ static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd)
                return -1;
        pos += used;
 
-       val = strtol(pos, NULL, 0);
+       val = strtol(pos, &pos2, 0);
        if (val < 0 || val > 0xff)
                return -1;
        tos = val;
 
+       pos = os_strstr(pos2, " len=");
+       if (pos) {
+               i = atoi(pos + 5);
+               if (i < sizeof(*ip) || i > HWSIM_IP_LEN)
+                       return -1;
+               send_len = i;
+       }
+
        eth = (struct ether_header *) &buf[2];
        os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
        os_memcpy(eth->ether_shost, src, ETH_ALEN);
@@ -8446,17 +9030,17 @@ static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd)
        ip->version = 4;
        ip->ttl = 64;
        ip->tos = tos;
-       ip->tot_len = htons(HWSIM_IP_LEN);
+       ip->tot_len = htons(send_len);
        ip->protocol = 1;
        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++)
+       for (i = 0; i < send_len - sizeof(*ip); i++)
                *dpos++ = i;
 
        if (l2_packet_send(wpa_s->l2_test, dst, ETHERTYPE_IP, &buf[2],
-                          HWSIM_PACKETLEN) < 0)
+                          sizeof(struct ether_header) + send_len) < 0)
                return -1;
 
        wpa_dbg(wpa_s, MSG_DEBUG, "test data: TX dst=" MACSTR " src=" MACSTR
@@ -8628,6 +9212,79 @@ static int wpas_ctrl_test_assoc_ie(struct wpa_supplicant *wpa_s,
        return 0;
 }
 
+
+static int wpas_ctrl_reset_pn(struct wpa_supplicant *wpa_s)
+{
+       u8 zero[WPA_TK_MAX_LEN];
+
+       if (wpa_s->last_tk_alg == WPA_ALG_NONE)
+               return -1;
+
+       wpa_printf(MSG_INFO, "TESTING: Reset PN");
+       os_memset(zero, 0, sizeof(zero));
+
+       /* First, use a zero key to avoid any possible duplicate key avoidance
+        * in the driver. */
+       if (wpa_drv_set_key(wpa_s, wpa_s->last_tk_alg, wpa_s->last_tk_addr,
+                           wpa_s->last_tk_key_idx, 1, zero, 6,
+                           zero, wpa_s->last_tk_len) < 0)
+               return -1;
+
+       /* Set the previously configured key to reset its TSC/RSC */
+       return wpa_drv_set_key(wpa_s, wpa_s->last_tk_alg, wpa_s->last_tk_addr,
+                              wpa_s->last_tk_key_idx, 1, zero, 6,
+                              wpa_s->last_tk, wpa_s->last_tk_len);
+}
+
+
+static int wpas_ctrl_key_request(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+       const char *pos = cmd;
+       int error, pairwise;
+
+       error = atoi(pos);
+       pos = os_strchr(pos, ' ');
+       if (!pos)
+               return -1;
+       pairwise = atoi(pos);
+       wpa_sm_key_request(wpa_s->wpa, error, pairwise);
+       return 0;
+}
+
+
+static int wpas_ctrl_resend_assoc(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_SME
+       struct wpa_driver_associate_params params;
+       int ret;
+
+       os_memset(&params, 0, sizeof(params));
+       params.bssid = wpa_s->bssid;
+       params.ssid = wpa_s->sme.ssid;
+       params.ssid_len = wpa_s->sme.ssid_len;
+       params.freq.freq = wpa_s->sme.freq;
+       if (wpa_s->last_assoc_req_wpa_ie) {
+               params.wpa_ie = wpabuf_head(wpa_s->last_assoc_req_wpa_ie);
+               params.wpa_ie_len = wpabuf_len(wpa_s->last_assoc_req_wpa_ie);
+       }
+       params.pairwise_suite = wpa_s->pairwise_cipher;
+       params.group_suite = wpa_s->group_cipher;
+       params.mgmt_group_suite = wpa_s->mgmt_group_cipher;
+       params.key_mgmt_suite = wpa_s->key_mgmt;
+       params.wpa_proto = wpa_s->wpa_proto;
+       params.mgmt_frame_protection = wpa_s->sme.mfp;
+       params.rrm_used = wpa_s->rrm.rrm_used;
+       if (wpa_s->sme.prev_bssid_set)
+               params.prev_bssid = wpa_s->sme.prev_bssid;
+       wpa_printf(MSG_INFO, "TESTING: Resend association request");
+       ret = wpa_drv_associate(wpa_s, &params);
+       wpa_s->testing_resend_assoc = 1;
+       return ret;
+#else /* CONFIG_SME */
+       return -1;
+#endif /* CONFIG_SME */
+}
+
 #endif /* CONFIG_TESTING_OPTIONS */
 
 
@@ -8963,68 +9620,16 @@ static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s,
                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)) {
-                       wpas_scan_restart_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 (!enable)
+               return wpas_disable_mac_addr_randomization(wpa_s, type);
 
-               if (wpa_s->sched_scanning && !wpa_s->pno)
-                       wpas_scan_restart_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;
+       return wpas_enable_mac_addr_randomization(wpa_s, type, addr, mask);
 }
 
 
@@ -9075,6 +9680,7 @@ static int wpas_ctrl_iface_pmksa_get(struct wpa_supplicant *wpa_s,
         * Entry format:
         * <BSSID> <PMKID> <PMK> <reauth_time in seconds>
         * <expiration in seconds> <akmp> <opportunistic>
+        * [FILS Cache Identifier]
         */
 
        for (entry = wpa_sm_pmksa_cache_head(wpa_s->wpa); entry;
@@ -9109,6 +9715,15 @@ static int wpas_ctrl_iface_pmksa_get(struct wpa_supplicant *wpa_s,
                        break;
                pos2 += ret;
 
+               if (entry->fils_cache_id_set) {
+                       ret = os_snprintf(pos2, end - pos2, " %02x%02x",
+                                         entry->fils_cache_id[0],
+                                         entry->fils_cache_id[1]);
+                       if (os_snprintf_error(end - pos2, ret))
+                               break;
+                       pos2 += ret;
+               }
+
                ret = os_snprintf(pos2, end - pos2, "\n");
                if (os_snprintf_error(end - pos2, ret))
                        break;
@@ -9129,12 +9744,13 @@ static int wpas_ctrl_iface_pmksa_add(struct wpa_supplicant *wpa_s,
        char *pos, *pos2;
        int ret = -1;
        struct os_reltime now;
-       int reauth_time = 0, expiration = 0;
+       int reauth_time = 0, expiration = 0, i;
 
        /*
         * Entry format:
         * <network_id> <BSSID> <PMKID> <PMK> <reauth_time in seconds>
         * <expiration in seconds> <akmp> <opportunistic>
+        * [FILS Cache Identifier]
         */
 
        ssid = wpa_config_get_network(wpa_s->conf, atoi(cmd));
@@ -9182,6 +9798,21 @@ static int wpas_ctrl_iface_pmksa_add(struct wpa_supplicant *wpa_s,
        if (sscanf(pos, "%d %d %d %d", &reauth_time, &expiration,
                   &entry->akmp, &entry->opportunistic) != 4)
                goto fail;
+       for (i = 0; i < 4; i++) {
+               pos = os_strchr(pos, ' ');
+               if (!pos) {
+                       if (i < 3)
+                               goto fail;
+                       break;
+               }
+               pos++;
+       }
+       if (pos) {
+               if (hexstr2bin(pos, entry->fils_cache_id,
+                              FILS_CACHE_ID_LEN) < 0)
+                       goto fail;
+               entry->fils_cache_id_set = 1;
+       }
        os_get_reltime(&now);
        entry->expiration = now.sec + expiration;
        entry->reauth_time = now.sec + reauth_time;
@@ -9288,7 +9919,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        int reply_len;
 
        if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
-           os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
+           os_strncmp(buf, "SET_NETWORK ", 12) == 0 ||
+           os_strncmp(buf, "PMKSA_ADD ", 10) == 0 ||
+           os_strncmp(buf, "MESH_PMKSA_ADD ", 15) == 0) {
                if (wpa_debug_show_keys)
                        wpa_dbg(wpa_s, MSG_DEBUG,
                                "Control interface command '%s'", buf);
@@ -9297,7 +9930,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                                "Control interface command '%s [REMOVED]'",
                                os_strncmp(buf, WPA_CTRL_RSP,
                                           os_strlen(WPA_CTRL_RSP)) == 0 ?
-                               WPA_CTRL_RSP : "SET_NETWORK");
+                               WPA_CTRL_RSP :
+                               (os_strncmp(buf, "SET_NETWORK ", 12) == 0 ?
+                                "SET_NETWORK" : "key-add"));
        } else if (os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 0 ||
                   os_strncmp(buf, "NFC_REPORT_HANDOVER", 19) == 0) {
                wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
@@ -9333,6 +9968,11 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                        reply_len += eapol_sm_get_mib(wpa_s->eapol,
                                                      reply + reply_len,
                                                      reply_size - reply_len);
+#ifdef CONFIG_MACSEC
+                       reply_len += ieee802_1x_kay_get_mib(
+                               wpa_s->kay, reply + reply_len,
+                               reply_size - reply_len);
+#endif /* CONFIG_MACSEC */
                }
        } else if (os_strncmp(buf, "STATUS", 6) == 0) {
                reply_len = wpa_supplicant_ctrl_iface_status(
@@ -9393,11 +10033,6 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
                        reply_len = -1;
 #endif /* IEEE8021X_EAPOL */
-#ifdef CONFIG_PEERKEY
-       } else if (os_strncmp(buf, "STKSTART ", 9) == 0) {
-               if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9))
-                       reply_len = -1;
-#endif /* CONFIG_PEERKEY */
 #ifdef CONFIG_IEEE80211R
        } else if (os_strncmp(buf, "FT_DS ", 6) == 0) {
                if (wpa_supplicant_ctrl_iface_ft_ds(wpa_s, buf + 6))
@@ -9530,6 +10165,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } 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;
+       } else if (os_strncmp(buf, "MESH_LINK_PROBE ", 16) == 0) {
+               if (wpa_supplicant_ctrl_iface_mesh_link_probe(wpa_s, buf + 16))
+                       reply_len = -1;
 #endif /* CONFIG_MESH */
 #ifdef CONFIG_P2P
        } else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) {
@@ -9928,6 +10566,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strncmp(buf, "WNM_BSS_QUERY ", 14) == 0) {
                if (wpas_ctrl_iface_wnm_bss_query(wpa_s, buf + 14))
                                reply_len = -1;
+       } else if (os_strncmp(buf, "COLOC_INTF_REPORT ", 18) == 0) {
+               if (wpas_ctrl_iface_coloc_intf_report(wpa_s, buf + 18))
+                       reply_len = -1;
 #endif /* CONFIG_WNM */
        } else if (os_strcmp(buf, "FLUSH") == 0) {
                wpa_supplicant_ctrl_iface_flush(wpa_s);
@@ -9974,6 +10615,21 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strncmp(buf, "TEST_ASSOC_IE ", 14) == 0) {
                if (wpas_ctrl_test_assoc_ie(wpa_s, buf + 14) < 0)
                        reply_len = -1;
+       } else if (os_strcmp(buf, "RESET_PN") == 0) {
+               if (wpas_ctrl_reset_pn(wpa_s) < 0)
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "KEY_REQUEST ", 12) == 0) {
+               if (wpas_ctrl_key_request(wpa_s, buf + 12) < 0)
+                       reply_len = -1;
+       } else if (os_strcmp(buf, "RESEND_ASSOC") == 0) {
+               if (wpas_ctrl_resend_assoc(wpa_s) < 0)
+                       reply_len = -1;
+#ifdef CONFIG_IEEE80211W
+       } else if (os_strcmp(buf, "UNPROT_DEAUTH") == 0) {
+               sme_event_unprot_disconnect(
+                       wpa_s, wpa_s->bssid, NULL,
+                       WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA);
+#endif /* CONFIG_IEEE80211W */
 #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)
@@ -10002,6 +10658,101 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strcmp(buf, "FILS_HLP_REQ_FLUSH") == 0) {
                wpas_flush_fils_hlp_req(wpa_s);
 #endif /* CONFIG_FILS */
+#ifdef CONFIG_DPP
+       } else if (os_strncmp(buf, "DPP_QR_CODE ", 12) == 0) {
+               int res;
+
+               res = wpas_dpp_qr_code(wpa_s, buf + 12);
+               if (res < 0) {
+                       reply_len = -1;
+               } else {
+                       reply_len = os_snprintf(reply, reply_size, "%d", res);
+                       if (os_snprintf_error(reply_size, reply_len))
+                               reply_len = -1;
+               }
+       } else if (os_strncmp(buf, "DPP_BOOTSTRAP_GEN ", 18) == 0) {
+               int res;
+
+               res = dpp_bootstrap_gen(wpa_s->dpp, buf + 18);
+               if (res < 0) {
+                       reply_len = -1;
+               } else {
+                       reply_len = os_snprintf(reply, reply_size, "%d", res);
+                       if (os_snprintf_error(reply_size, reply_len))
+                               reply_len = -1;
+               }
+       } else if (os_strncmp(buf, "DPP_BOOTSTRAP_REMOVE ", 21) == 0) {
+               if (dpp_bootstrap_remove(wpa_s->dpp, buf + 21) < 0)
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "DPP_BOOTSTRAP_GET_URI ", 22) == 0) {
+               const char *uri;
+
+               uri = dpp_bootstrap_get_uri(wpa_s->dpp, atoi(buf + 22));
+               if (!uri) {
+                       reply_len = -1;
+               } else {
+                       reply_len = os_snprintf(reply, reply_size, "%s", uri);
+                       if (os_snprintf_error(reply_size, reply_len))
+                               reply_len = -1;
+               }
+       } else if (os_strncmp(buf, "DPP_BOOTSTRAP_INFO ", 19) == 0) {
+               reply_len = dpp_bootstrap_info(wpa_s->dpp, atoi(buf + 19),
+                                              reply, reply_size);
+       } else if (os_strncmp(buf, "DPP_AUTH_INIT ", 14) == 0) {
+               if (wpas_dpp_auth_init(wpa_s, buf + 13) < 0)
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "DPP_LISTEN ", 11) == 0) {
+               if (wpas_dpp_listen(wpa_s, buf + 11) < 0)
+                       reply_len = -1;
+       } else if (os_strcmp(buf, "DPP_STOP_LISTEN") == 0) {
+               wpas_dpp_stop(wpa_s);
+               wpas_dpp_listen_stop(wpa_s);
+       } else if (os_strncmp(buf, "DPP_CONFIGURATOR_ADD", 20) == 0) {
+               int res;
+
+               res = dpp_configurator_add(wpa_s->dpp, buf + 20);
+               if (res < 0) {
+                       reply_len = -1;
+               } else {
+                       reply_len = os_snprintf(reply, reply_size, "%d", res);
+                       if (os_snprintf_error(reply_size, reply_len))
+                               reply_len = -1;
+               }
+       } else if (os_strncmp(buf, "DPP_CONFIGURATOR_REMOVE ", 24) == 0) {
+               if (dpp_configurator_remove(wpa_s->dpp, buf + 24) < 0)
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "DPP_CONFIGURATOR_SIGN ", 22) == 0) {
+               if (wpas_dpp_configurator_sign(wpa_s, buf + 21) < 0)
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "DPP_CONFIGURATOR_GET_KEY ", 25) == 0) {
+               reply_len = dpp_configurator_get_key_id(wpa_s->dpp,
+                                                       atoi(buf + 25),
+                                                       reply, reply_size);
+       } else if (os_strncmp(buf, "DPP_PKEX_ADD ", 13) == 0) {
+               int res;
+
+               res = wpas_dpp_pkex_add(wpa_s, buf + 12);
+               if (res < 0) {
+                       reply_len = -1;
+               } else {
+                       reply_len = os_snprintf(reply, reply_size, "%d", res);
+                       if (os_snprintf_error(reply_size, reply_len))
+                               reply_len = -1;
+               }
+       } else if (os_strncmp(buf, "DPP_PKEX_REMOVE ", 16) == 0) {
+               if (wpas_dpp_pkex_remove(wpa_s, buf + 16) < 0)
+                       reply_len = -1;
+#ifdef CONFIG_DPP2
+       } else if (os_strncmp(buf, "DPP_CONTROLLER_START ", 21) == 0) {
+               if (wpas_dpp_controller_start(wpa_s, buf + 20) < 0)
+                       reply_len = -1;
+       } else if (os_strcmp(buf, "DPP_CONTROLLER_START") == 0) {
+               if (wpas_dpp_controller_start(wpa_s, NULL) < 0)
+                       reply_len = -1;
+       } else if (os_strcmp(buf, "DPP_CONTROLLER_STOP") == 0) {
+               dpp_controller_stop(wpa_s->dpp);
+#endif /* CONFIG_DPP2 */
+#endif /* CONFIG_DPP */
        } else {
                os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
                reply_len = 16;
@@ -10320,6 +11071,7 @@ static char * wpas_global_ctrl_iface_redir_p2p(struct wpa_global *global,
 #ifdef ANDROID
                "DRIVER ",
 #endif /* ANDROID */
+               "GET_CAPABILITY ",
                "GET_NETWORK ",
                "REMOVE_NETWORK ",
                "P2P_FIND ",