diff options
Diffstat (limited to 'wpa_supplicant/ctrl_iface.c')
-rw-r--r-- | wpa_supplicant/ctrl_iface.c | 1391 |
1 files changed, 1332 insertions, 59 deletions
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index d814fdf7fd2d4..77a3133d8d560 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -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,7 @@ #include "offchannel.h" #include "drivers/driver.h" #include "mesh.h" +#include "dpp_supplicant.h" static int wpa_supplicant_global_iface_list(struct wpa_global *global, char *buf, int len); @@ -61,6 +65,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; @@ -339,6 +344,75 @@ static int wpas_ctrl_iface_set_lci(struct wpa_supplicant *wpa_s, } +static int +wpas_ctrl_set_relative_rssi(struct wpa_supplicant *wpa_s, const char *cmd) +{ + int relative_rssi; + + if (os_strcmp(cmd, "disable") == 0) { + wpa_s->srp.relative_rssi_set = 0; + return 0; + } + + relative_rssi = atoi(cmd); + if (relative_rssi < 0 || relative_rssi > 100) + return -1; + wpa_s->srp.relative_rssi = relative_rssi; + wpa_s->srp.relative_rssi_set = 1; + return 0; +} + + +static int wpas_ctrl_set_relative_band_adjust(struct wpa_supplicant *wpa_s, + const char *cmd) +{ + char *pos; + int adjust_rssi; + + /* <band>:adjust_value */ + pos = os_strchr(cmd, ':'); + if (!pos) + return -1; + pos++; + adjust_rssi = atoi(pos); + if (adjust_rssi < -100 || adjust_rssi > 100) + return -1; + + if (os_strncmp(cmd, "2G", 2) == 0) + wpa_s->srp.relative_adjust_band = WPA_SETBAND_2G; + else if (os_strncmp(cmd, "5G", 2) == 0) + wpa_s->srp.relative_adjust_band = WPA_SETBAND_5G; + else + return -1; + + wpa_s->srp.relative_adjust_rssi = adjust_rssi; + + return 0; +} + + +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) { @@ -365,16 +439,29 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, -1, -1, -1, atoi(value)); } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKLifetime") == 0) { if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME, - atoi(value))) + atoi(value))) { ret = -1; + } else { + value[-1] = '='; + wpa_config_process_global(wpa_s->conf, cmd, -1); + } } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKReauthThreshold") == 0) { if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD, - atoi(value))) + atoi(value))) { ret = -1; + } else { + value[-1] = '='; + wpa_config_process_global(wpa_s->conf, cmd, -1); + } } else if (os_strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) { - if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, atoi(value))) + if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, + atoi(value))) { ret = -1; + } else { + value[-1] = '='; + wpa_config_process_global(wpa_s->conf, cmd, -1); + } } else if (os_strcasecmp(cmd, "wps_fragment_size") == 0) { wpa_s->wps_fragment_size = atoi(value); #ifdef CONFIG_WPS_TESTING @@ -494,6 +581,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); @@ -515,9 +655,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); @@ -527,11 +712,53 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, #ifdef CONFIG_MBO } else if (os_strcasecmp(cmd, "non_pref_chan") == 0) { ret = wpas_mbo_update_non_pref_chan(wpa_s, value); + if (ret == 0) { + value[-1] = '='; + wpa_config_process_global(wpa_s->conf, cmd, -1); + } } 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); + } else if (os_strcasecmp(cmd, "tdls_trigger_control") == 0) { + ret = wpa_drv_set_tdls_mode(wpa_s, atoi(value)); + } else if (os_strcasecmp(cmd, "relative_rssi") == 0) { + 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); @@ -577,6 +804,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); } @@ -610,27 +843,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( @@ -1914,6 +2126,7 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s, #endif /* CONFIG_AP */ pos += wpa_sm_get_status(wpa_s->wpa, pos, end - pos, verbose); } +#ifdef CONFIG_SME #ifdef CONFIG_SAE if (wpa_s->wpa_state >= WPA_ASSOCIATED && #ifdef CONFIG_AP @@ -1927,6 +2140,7 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s, pos += ret; } #endif /* CONFIG_SAE */ +#endif /* CONFIG_SME */ ret = os_snprintf(pos, end - pos, "wpa_state=%s\n", wpa_supplicant_state_txt(wpa_s->wpa_state)); if (os_snprintf_error(end - pos, ret)) @@ -2048,6 +2262,12 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s, pos += res; } +#ifdef CONFIG_MACSEC + res = ieee802_1x_kay_get_status(wpa_s->kay, pos, end - pos); + if (res > 0) + pos += res; +#endif /* CONFIG_MACSEC */ + sess_id = eapol_sm_get_session_id(wpa_s->eapol, &sess_id_len); if (sess_id) { char *start = pos; @@ -2081,6 +2301,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, @@ -2437,6 +2664,59 @@ static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto, } #endif /* CONFIG_SUITEB192 */ +#ifdef CONFIG_FILS + if (data.key_mgmt & WPA_KEY_MGMT_FILS_SHA256) { + ret = os_snprintf(pos, end - pos, "%sFILS-SHA256", + pos == start ? "" : "+"); + if (os_snprintf_error(end - pos, ret)) + return pos; + pos += ret; + } + if (data.key_mgmt & WPA_KEY_MGMT_FILS_SHA384) { + ret = os_snprintf(pos, end - pos, "%sFILS-SHA384", + pos == start ? "" : "+"); + if (os_snprintf_error(end - pos, ret)) + return pos; + pos += ret; + } +#ifdef CONFIG_IEEE80211R + if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) { + ret = os_snprintf(pos, end - pos, "%sFT-FILS-SHA256", + pos == start ? "" : "+"); + if (os_snprintf_error(end - pos, ret)) + return pos; + pos += ret; + } + if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) { + ret = os_snprintf(pos, end - pos, "%sFT-FILS-SHA384", + pos == start ? "" : "+"); + if (os_snprintf_error(end - pos, ret)) + return pos; + pos += ret; + } +#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 ? "" : "+"); @@ -2512,7 +2792,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); @@ -2543,6 +2823,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]"); @@ -2608,6 +2896,14 @@ static int wpa_supplicant_ctrl_iface_scan_result( pos += ret; } #endif /* CONFIG_HS20 */ +#ifdef CONFIG_FILS + if (wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION)) { + ret = os_snprintf(pos, end - pos, "[FILS]"); + if (os_snprintf_error(end - pos, ret)) + return -1; + 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]"); @@ -2835,9 +3131,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; } } @@ -3012,6 +3307,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); @@ -3647,6 +3943,50 @@ 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 */ return pos - buf; } @@ -3749,6 +4089,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; } @@ -4006,6 +4366,27 @@ static int wpa_supplicant_ctrl_iface_get_capability( } #endif /* CONFIG_ACS */ +#ifdef CONFIG_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 */ + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'", field); @@ -4048,13 +4429,85 @@ static char * anqp_add_hex(char *pos, char *end, const char *title, #endif /* CONFIG_INTERWORKING */ +#ifdef CONFIG_FILS +static int print_fils_indication(struct wpa_bss *bss, char *pos, char *end) +{ + char *start = pos; + const u8 *ie, *ie_end; + u16 info, realms; + int ret; + + ie = wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION); + if (!ie) + return 0; + ie_end = ie + 2 + ie[1]; + ie += 2; + if (ie_end - ie < 2) + return -1; + + info = WPA_GET_LE16(ie); + ie += 2; + ret = os_snprintf(pos, end - pos, "fils_info=%04x\n", info); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + + if (info & BIT(7)) { + /* Cache Identifier Included */ + if (ie_end - ie < 2) + return -1; + ret = os_snprintf(pos, end - pos, "fils_cache_id=%02x%02x\n", + ie[0], ie[1]); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + ie += 2; + } + + if (info & BIT(8)) { + /* HESSID Included */ + if (ie_end - ie < ETH_ALEN) + return -1; + ret = os_snprintf(pos, end - pos, "fils_hessid=" MACSTR "\n", + MAC2STR(ie)); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + ie += ETH_ALEN; + } + + realms = (info & (BIT(3) | BIT(4) | BIT(5))) >> 3; + if (realms) { + if (ie_end - ie < realms * 2) + return -1; + ret = os_snprintf(pos, end - pos, "fils_realms="); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + + ret = wpa_snprintf_hex(pos, end - pos, ie, realms * 2); + if (ret <= 0) + return 0; + pos += ret; + ie += realms * 2; + ret = os_snprintf(pos, end - pos, "\n"); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + } + + return pos - start; +} +#endif /* CONFIG_FILS */ + + static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, unsigned long mask, char *buf, size_t buflen) { size_t i; int ret; char *pos, *end; - const u8 *ie, *ie2, *osen_ie; + const u8 *ie, *ie2, *osen_ie, *mesh, *owe; pos = buf; end = buf + buflen; @@ -4163,18 +4616,30 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, return 0; pos += ret; + mesh = wpa_bss_get_ie(bss, WLAN_EID_MESH_ID); + ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); if (ie) pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]); ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN); if (ie2) - pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, + 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]); + 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)) { @@ -4183,6 +4648,14 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, return 0; pos += ret; } + + if (mesh) { + ret = os_snprintf(pos, end - pos, "[MESH]"); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + } + if (bss_is_dmg(bss)) { const char *s; ret = os_snprintf(pos, end - pos, "[DMG]"); @@ -4236,6 +4709,14 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, pos += ret; } #endif /* CONFIG_HS20 */ +#ifdef CONFIG_FILS + if (wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION)) { + ret = os_snprintf(pos, end - pos, "[FILS]"); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + } +#endif /* CONFIG_FILS */ ret = os_snprintf(pos, end - pos, "\n"); if (os_snprintf_error(end - pos, ret)) @@ -4320,6 +4801,8 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, pos = anqp_add_hex(pos, end, "anqp_3gpp", anqp->anqp_3gpp); pos = anqp_add_hex(pos, end, "anqp_domain_name", anqp->domain_name); + pos = anqp_add_hex(pos, end, "anqp_fils_realm_info", + anqp->fils_realm_info); #ifdef CONFIG_HS20 pos = anqp_add_hex(pos, end, "hs20_capability_list", anqp->hs20_capability_list); @@ -4333,6 +4816,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, @@ -4381,6 +4868,44 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, } #endif /* CONFIG_FST */ + if (mask & WPA_BSS_MASK_UPDATE_IDX) { + ret = os_snprintf(pos, end - pos, "update_idx=%u\n", + bss->last_update_idx); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + } + + if ((mask & WPA_BSS_MASK_BEACON_IE) && bss->beacon_ie_len) { + ret = os_snprintf(pos, end - pos, "beacon_ie="); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + + ie = (const u8 *) (bss + 1); + ie += bss->ie_len; + for (i = 0; i < bss->beacon_ie_len; i++) { + ret = os_snprintf(pos, end - pos, "%02x", *ie++); + 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)) + return 0; + pos += ret; + } + +#ifdef CONFIG_FILS + if (mask & WPA_BSS_MASK_FILS_INDICATION) { + ret = print_fils_indication(bss, pos, end); + if (ret < 0) + return 0; + pos += ret; + } +#endif /* CONFIG_FILS */ + if (mask & WPA_BSS_MASK_DELIM) { ret = os_snprintf(pos, end - pos, "====\n"); if (os_snprintf_error(end - pos, ret)) @@ -4471,6 +4996,8 @@ static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s, bss = dl_list_entry(next, struct wpa_bss, list_id); } + } else if (os_strncmp(cmd, "CURRENT", 7) == 0) { + bss = wpa_s->current_bss; #ifdef CONFIG_P2P } else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) { if (hwaddr_aton(cmd + 13, bssid) == 0) @@ -5768,13 +6295,21 @@ static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd) int ht40 = wpa_s->conf->p2p_go_ht40 || vht; 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) { @@ -5790,6 +6325,24 @@ 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; + } + } +#endif /* CONFIG_ACS */ + max_oper_chwidth = parse_freq(chwidth, freq2); if (max_oper_chwidth < 0) return -1; @@ -5827,10 +6380,24 @@ static int p2p_ctrl_group_member(struct wpa_supplicant *wpa_s, const char *cmd, } +static int wpas_find_p2p_dev_addr_bss(struct wpa_global *global, + const u8 *p2p_dev_addr) +{ + struct wpa_supplicant *wpa_s; + + for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { + if (wpa_bss_get_p2p_dev_addr(wpa_s, p2p_dev_addr)) + return 1; + } + + return 0; +} + + static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) { - u8 addr[ETH_ALEN], *addr_ptr; + u8 addr[ETH_ALEN], *addr_ptr, group_capab; int next, res; const struct p2p_peer_info *info; char *pos, *end; @@ -5859,6 +6426,16 @@ static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd, info = p2p_get_peer_info(wpa_s->global->p2p, addr_ptr, next); if (info == NULL) return -1; + group_capab = info->group_capab; + + if (group_capab && + !wpas_find_p2p_dev_addr_bss(wpa_s->global, info->p2p_device_addr)) { + wpa_printf(MSG_DEBUG, + "P2P: Could not find any BSS with p2p_dev_addr " + MACSTR ", hence override group_capab from 0x%x to 0", + MAC2STR(info->p2p_device_addr), group_capab); + group_capab = 0; + } pos = buf; end = buf + buflen; @@ -5884,7 +6461,7 @@ static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd, info->serial_number, info->config_methods, info->dev_capab, - info->group_capab, + group_capab, info->level); if (os_snprintf_error(end - pos, res)) return pos - buf; @@ -6165,6 +6742,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); @@ -6176,6 +6767,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) @@ -6383,7 +6980,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) @@ -6404,9 +7001,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 */ @@ -6421,11 +7019,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); } @@ -6762,6 +7360,9 @@ static int wpa_supplicant_ctrl_iface_autoscan(struct wpa_supplicant *wpa_s, autoscan_init(wpa_s, 1); else if (state == WPA_SCANNING) wpa_supplicant_reinit_autoscan(wpa_s); + else + wpa_printf(MSG_DEBUG, "No autoscan update in state %s", + wpa_supplicant_state_txt(state)); return 0; } @@ -6824,26 +7425,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 */ @@ -6879,10 +7495,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; @@ -6930,6 +7553,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) { @@ -7116,7 +7779,8 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) wpa_dbg(wpa_s, MSG_DEBUG, "Flush all wpa_supplicant state"); - wpas_abort_ongoing_scan(wpa_s); + if (wpas_abort_ongoing_scan(wpa_s) == 0) + wpa_s->ignore_post_flush_scan_res = 1; if (wpa_s->wpa_state >= WPA_AUTHENTICATING) { /* @@ -7157,6 +7821,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; @@ -7218,13 +7898,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)) { @@ -7242,6 +7938,9 @@ 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; } @@ -7539,6 +8238,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) { @@ -7824,6 +8536,124 @@ static int wpas_ctrl_iface_mgmt_rx_process(struct wpa_supplicant *wpa_s, } +static int wpas_ctrl_iface_driver_scan_res(struct wpa_supplicant *wpa_s, + char *param) +{ + struct wpa_scan_res *res; + struct os_reltime now; + char *pos, *end; + int ret = -1; + + if (!param) + return -1; + + if (os_strcmp(param, "START") == 0) { + wpa_bss_update_start(wpa_s); + return 0; + } + + if (os_strcmp(param, "END") == 0) { + wpa_bss_update_end(wpa_s, NULL, 1); + return 0; + } + + if (os_strncmp(param, "BSS ", 4) != 0) + return -1; + param += 3; + + res = os_zalloc(sizeof(*res) + os_strlen(param) / 2); + if (!res) + return -1; + + pos = os_strstr(param, " flags="); + if (pos) + res->flags = strtol(pos + 7, NULL, 16); + + pos = os_strstr(param, " bssid="); + if (pos && hwaddr_aton(pos + 7, res->bssid)) + goto fail; + + pos = os_strstr(param, " freq="); + if (pos) + res->freq = atoi(pos + 6); + + pos = os_strstr(param, " beacon_int="); + if (pos) + res->beacon_int = atoi(pos + 12); + + pos = os_strstr(param, " caps="); + if (pos) + res->caps = strtol(pos + 6, NULL, 16); + + pos = os_strstr(param, " qual="); + if (pos) + res->qual = atoi(pos + 6); + + pos = os_strstr(param, " noise="); + if (pos) + res->noise = atoi(pos + 7); + + pos = os_strstr(param, " level="); + if (pos) + res->level = atoi(pos + 7); + + pos = os_strstr(param, " tsf="); + if (pos) + res->tsf = strtoll(pos + 5, NULL, 16); + + pos = os_strstr(param, " age="); + if (pos) + res->age = atoi(pos + 5); + + pos = os_strstr(param, " est_throughput="); + if (pos) + res->est_throughput = atoi(pos + 16); + + pos = os_strstr(param, " snr="); + if (pos) + res->snr = atoi(pos + 5); + + pos = os_strstr(param, " parent_tsf="); + if (pos) + res->parent_tsf = strtoll(pos + 7, NULL, 16); + + pos = os_strstr(param, " tsf_bssid="); + if (pos && hwaddr_aton(pos + 11, res->tsf_bssid)) + goto fail; + + pos = os_strstr(param, " ie="); + if (pos) { + pos += 4; + end = os_strchr(pos, ' '); + if (!end) + end = pos + os_strlen(pos); + res->ie_len = (end - pos) / 2; + if (hexstr2bin(pos, (u8 *) (res + 1), res->ie_len)) + goto fail; + } + + pos = os_strstr(param, " beacon_ie="); + if (pos) { + pos += 11; + end = os_strchr(pos, ' '); + if (!end) + end = pos + os_strlen(pos); + res->beacon_ie_len = (end - pos) / 2; + if (hexstr2bin(pos, ((u8 *) (res + 1)) + res->ie_len, + res->beacon_ie_len)) + goto fail; + } + + os_get_reltime(&now); + wpa_bss_update_scan_res(wpa_s, res, &now); + ret = 0; +fail: + os_free(res); + + return ret; +} + + static int wpas_ctrl_iface_driver_event(struct wpa_supplicant *wpa_s, char *cmd) { char *pos, *param; @@ -7854,6 +8684,8 @@ static int wpas_ctrl_iface_driver_event(struct wpa_supplicant *wpa_s, char *cmd) wpa_supplicant_event(wpa_s, ev, &event); os_free(event.freq_range.range); return 0; + } else if (os_strcmp(cmd, "SCAN_RES") == 0) { + return wpas_ctrl_iface_driver_scan_res(wpa_s, param); } else { wpa_dbg(wpa_s, MSG_DEBUG, "Testing - unknown driver event: %s", cmd); @@ -8218,6 +9050,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(¶ms, 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, ¶ms); + wpa_s->testing_resend_assoc = 1; + return ret; +#else /* CONFIG_SME */ + return -1; +#endif /* CONFIG_SME */ +} + #endif /* CONFIG_TESTING_OPTIONS */ @@ -8641,6 +9546,248 @@ static void wpas_ctrl_iface_pmksa_flush(struct wpa_supplicant *wpa_s) } +#ifdef CONFIG_PMKSA_CACHE_EXTERNAL + +static int wpas_ctrl_iface_pmksa_get(struct wpa_supplicant *wpa_s, + const char *cmd, char *buf, size_t buflen) +{ + struct rsn_pmksa_cache_entry *entry; + struct wpa_ssid *ssid; + char *pos, *pos2, *end; + int ret; + struct os_reltime now; + + ssid = wpa_config_get_network(wpa_s->conf, atoi(cmd)); + if (!ssid) + return -1; + + pos = buf; + end = buf + buflen; + + os_get_reltime(&now); + + /* + * 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; + entry = entry->next) { + if (entry->network_ctx != ssid) + continue; + + pos2 = pos; + ret = os_snprintf(pos2, end - pos2, MACSTR " ", + MAC2STR(entry->aa)); + if (os_snprintf_error(end - pos2, ret)) + break; + pos2 += ret; + + pos2 += wpa_snprintf_hex(pos2, end - pos2, entry->pmkid, + PMKID_LEN); + + ret = os_snprintf(pos2, end - pos2, " "); + if (os_snprintf_error(end - pos2, ret)) + break; + pos2 += ret; + + pos2 += wpa_snprintf_hex(pos2, end - pos2, entry->pmk, + entry->pmk_len); + + ret = os_snprintf(pos2, end - pos2, " %d %d %d %d", + (int) (entry->reauth_time - now.sec), + (int) (entry->expiration - now.sec), + entry->akmp, + entry->opportunistic); + if (os_snprintf_error(end - pos2, ret)) + 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; + pos2 += ret; + + pos = pos2; + } + + return pos - buf; +} + + +static int wpas_ctrl_iface_pmksa_add(struct wpa_supplicant *wpa_s, + char *cmd) +{ + struct rsn_pmksa_cache_entry *entry; + struct wpa_ssid *ssid; + char *pos, *pos2; + int ret = -1; + struct os_reltime now; + 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)); + if (!ssid) + return -1; + + pos = os_strchr(cmd, ' '); + if (!pos) + return -1; + pos++; + + entry = os_zalloc(sizeof(*entry)); + if (!entry) + return -1; + + if (hwaddr_aton(pos, entry->aa)) + goto fail; + + pos = os_strchr(pos, ' '); + if (!pos) + goto fail; + pos++; + + if (hexstr2bin(pos, entry->pmkid, PMKID_LEN) < 0) + goto fail; + + pos = os_strchr(pos, ' '); + if (!pos) + goto fail; + pos++; + + pos2 = os_strchr(pos, ' '); + if (!pos2) + goto fail; + entry->pmk_len = (pos2 - pos) / 2; + if (entry->pmk_len < PMK_LEN || entry->pmk_len > PMK_LEN_MAX || + hexstr2bin(pos, entry->pmk, entry->pmk_len) < 0) + goto fail; + + pos = os_strchr(pos, ' '); + if (!pos) + goto fail; + pos++; + + 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; + + entry->network_ctx = ssid; + + wpa_sm_pmksa_cache_add_entry(wpa_s->wpa, entry); + entry = NULL; + ret = 0; +fail: + os_free(entry); + return ret; +} + + +#ifdef CONFIG_MESH + +static int wpas_ctrl_iface_mesh_pmksa_get(struct wpa_supplicant *wpa_s, + const char *cmd, char *buf, + size_t buflen) +{ + u8 spa[ETH_ALEN]; + + if (!wpa_s->ifmsh) + return -1; + + if (os_strcasecmp(cmd, "any") == 0) + return wpas_ap_pmksa_cache_list_mesh(wpa_s, NULL, buf, buflen); + + if (hwaddr_aton(cmd, spa)) + return -1; + + return wpas_ap_pmksa_cache_list_mesh(wpa_s, spa, buf, buflen); +} + + +static int wpas_ctrl_iface_mesh_pmksa_add(struct wpa_supplicant *wpa_s, + char *cmd) +{ + /* + * We do not check mesh interface existance because PMKSA should be + * stored before wpa_s->ifmsh creation to suppress commit message + * creation. + */ + return wpas_ap_pmksa_cache_add_external(wpa_s, cmd); +} + +#endif /* CONFIG_MESH */ +#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ + + +#ifdef CONFIG_FILS +static int wpas_ctrl_iface_fils_hlp_req_add(struct wpa_supplicant *wpa_s, + const char *cmd) +{ + struct fils_hlp_req *req; + const char *pos; + + /* format: <dst> <packet starting from ethertype> */ + + req = os_zalloc(sizeof(*req)); + if (!req) + return -1; + + if (hwaddr_aton(cmd, req->dst)) + goto fail; + + pos = os_strchr(cmd, ' '); + if (!pos) + goto fail; + pos++; + req->pkt = wpabuf_parse_bin(pos); + if (!req->pkt) + goto fail; + + dl_list_add_tail(&wpa_s->fils_hlp_req, &req->list); + return 0; +fail: + wpabuf_free(req->pkt); + os_free(req); + return -1; +} +#endif /* CONFIG_FILS */ + + static int wpas_ctrl_cmd_debug_level(const char *cmd) { if (os_strcmp(cmd, "PING") == 0 || @@ -8662,7 +9809,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); @@ -8671,7 +9820,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", @@ -8715,6 +9866,22 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, reply_len = wpas_ctrl_iface_pmksa(wpa_s, reply, reply_size); } else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) { wpas_ctrl_iface_pmksa_flush(wpa_s); +#ifdef CONFIG_PMKSA_CACHE_EXTERNAL + } else if (os_strncmp(buf, "PMKSA_GET ", 10) == 0) { + reply_len = wpas_ctrl_iface_pmksa_get(wpa_s, buf + 10, + reply, reply_size); + } else if (os_strncmp(buf, "PMKSA_ADD ", 10) == 0) { + if (wpas_ctrl_iface_pmksa_add(wpa_s, buf + 10) < 0) + reply_len = -1; +#ifdef CONFIG_MESH + } else if (os_strncmp(buf, "MESH_PMKSA_GET ", 15) == 0) { + reply_len = wpas_ctrl_iface_mesh_pmksa_get(wpa_s, buf + 15, + reply, reply_size); + } else if (os_strncmp(buf, "MESH_PMKSA_ADD ", 15) == 0) { + if (wpas_ctrl_iface_mesh_pmksa_add(wpa_s, buf + 15) < 0) + reply_len = -1; +#endif /* CONFIG_MESH */ +#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ } else if (os_strncmp(buf, "SET ", 4) == 0) { if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4)) reply_len = -1; @@ -8751,11 +9918,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)) @@ -9286,6 +10448,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); @@ -9332,6 +10497,15 @@ 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; #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) @@ -9353,6 +10527,97 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "GET_PREF_FREQ_LIST ", 19) == 0) { reply_len = wpas_ctrl_iface_get_pref_freq_list( wpa_s, buf + 19, reply, reply_size); +#ifdef CONFIG_FILS + } else if (os_strncmp(buf, "FILS_HLP_REQ_ADD ", 17) == 0) { + if (wpas_ctrl_iface_fils_hlp_req_add(wpa_s, buf + 17)) + reply_len = -1; + } 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 = wpas_dpp_bootstrap_gen(wpa_s, 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 (wpas_dpp_bootstrap_remove(wpa_s, buf + 21) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "DPP_BOOTSTRAP_GET_URI ", 22) == 0) { + const char *uri; + + uri = wpas_dpp_bootstrap_get_uri(wpa_s, 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 = wpas_dpp_bootstrap_info(wpa_s, 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 = wpas_dpp_configurator_add(wpa_s, 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 (wpas_dpp_configurator_remove(wpa_s, buf + 24) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "DPP_CONFIGURATOR_SIGN ", 22) == 0) { + if (wpas_dpp_configurator_sign(wpa_s, buf + 22) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "DPP_CONFIGURATOR_GET_KEY ", 25) == 0) { + reply_len = wpas_dpp_configurator_get_key(wpa_s, 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; +#endif /* CONFIG_DPP */ } else { os_memcpy(reply, "UNKNOWN COMMAND\n", 16); reply_len = 16; @@ -9662,12 +10927,16 @@ static char * wpas_global_ctrl_iface_redir_p2p(struct wpa_global *global, "P2P_CANCEL", "P2P_PRESENCE_REQ", "P2P_EXT_LISTEN", +#ifdef CONFIG_AP + "STA-FIRST", +#endif /* CONFIG_AP */ NULL }; static const char * prefix[] = { #ifdef ANDROID "DRIVER ", #endif /* ANDROID */ + "GET_CAPABILITY ", "GET_NETWORK ", "REMOVE_NETWORK ", "P2P_FIND ", @@ -9699,6 +10968,10 @@ static char * wpas_global_ctrl_iface_redir_p2p(struct wpa_global *global, "NFC_REPORT_HANDOVER ", "P2P_ASP_PROVISION ", "P2P_ASP_PROVISION_RESP ", +#ifdef CONFIG_AP + "STA ", + "STA-NEXT ", +#endif /* CONFIG_AP */ NULL }; int found = 0; |