aboutsummaryrefslogtreecommitdiff
path: root/contrib/wpa/wpa_supplicant/wpa_supplicant.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/wpa/wpa_supplicant/wpa_supplicant.c')
-rw-r--r--contrib/wpa/wpa_supplicant/wpa_supplicant.c1644
1 files changed, 1380 insertions, 264 deletions
diff --git a/contrib/wpa/wpa_supplicant/wpa_supplicant.c b/contrib/wpa/wpa_supplicant/wpa_supplicant.c
index 31b1bc8e5c80..cf990f5a8f85 100644
--- a/contrib/wpa/wpa_supplicant/wpa_supplicant.c
+++ b/contrib/wpa/wpa_supplicant/wpa_supplicant.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant
- * Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2022, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -41,9 +41,10 @@
#include "common/hw_features_common.h"
#include "common/gas_server.h"
#include "common/dpp.h"
+#include "common/ptksa_cache.h"
#include "p2p/p2p.h"
#include "fst/fst.h"
-#include "blacklist.h"
+#include "bssid_ignore.h"
#include "wpas_glue.h"
#include "wps_supplicant.h"
#include "ibss_rsn.h"
@@ -70,7 +71,7 @@
const char *const wpa_supplicant_version =
"wpa_supplicant v" VERSION_STR "\n"
-"Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2003-2022, Jouni Malinen <j@w1.fi> and contributors";
const char *const wpa_supplicant_license =
"This software may be distributed under the terms of the BSD license.\n"
@@ -125,8 +126,12 @@ static void wpa_bss_tmp_disallow_timeout(void *eloop_ctx, void *timeout_ctx);
#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s);
#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
+#ifdef CONFIG_OWE
+static void wpas_update_owe_connect_params(struct wpa_supplicant *wpa_s);
+#endif /* CONFIG_OWE */
+#ifdef CONFIG_WEP
/* Configure default/group WEP keys for static WEP */
int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
{
@@ -139,11 +144,15 @@ int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
set = 1;
wpa_drv_set_key(wpa_s, WPA_ALG_WEP, NULL,
i, i == ssid->wep_tx_keyidx, NULL, 0,
- ssid->wep_key[i], ssid->wep_key_len[i]);
+ ssid->wep_key[i], ssid->wep_key_len[i],
+ i == ssid->wep_tx_keyidx ?
+ KEY_FLAG_GROUP_RX_TX_DEFAULT :
+ KEY_FLAG_GROUP_RX_TX);
}
return set;
}
+#endif /* CONFIG_WEP */
int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
@@ -197,7 +206,8 @@ int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
/* TODO: should actually remember the previously used seq#, both for TX
* and RX from each STA.. */
- ret = wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen);
+ ret = wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen,
+ KEY_FLAG_GROUP_RX_TX_DEFAULT);
os_memset(key, 0, sizeof(key));
return ret;
}
@@ -213,7 +223,7 @@ static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
bssid = wpa_s->pending_bssid;
wpa_msg(wpa_s, MSG_INFO, "Authentication with " MACSTR " timed out.",
MAC2STR(bssid));
- wpa_blacklist_add(wpa_s, bssid);
+ wpa_bssid_ignore_add(wpa_s, bssid);
wpa_sm_notify_disassoc(wpa_s->wpa);
wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
wpa_s->reassociate = 1;
@@ -281,7 +291,7 @@ void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s)
{
wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling authentication timeout");
eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
- wpa_blacklist_del(wpa_s, wpa_s->bssid);
+ wpa_bssid_ignore_del(wpa_s, wpa_s->bssid);
os_free(wpa_s->last_con_fail_realm);
wpa_s->last_con_fail_realm = NULL;
wpa_s->last_con_fail_realm_len = 0;
@@ -310,14 +320,14 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
* per-BSSID EAPOL authentication.
*/
eapol_sm_notify_portControl(wpa_s->eapol, ForceAuthorized);
- eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
- eapol_sm_notify_eap_fail(wpa_s->eapol, FALSE);
+ eapol_sm_notify_eap_success(wpa_s->eapol, true);
+ eapol_sm_notify_eap_fail(wpa_s->eapol, false);
return;
}
#endif /* CONFIG_IBSS_RSN */
- eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
- eapol_sm_notify_eap_fail(wpa_s->eapol, FALSE);
+ eapol_sm_notify_eap_success(wpa_s->eapol, false);
+ eapol_sm_notify_eap_fail(wpa_s->eapol, false);
if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE)
@@ -389,7 +399,9 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
+#ifdef CONFIG_WEP
int i;
+#endif /* CONFIG_WEP */
if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
wpa_s->key_mgmt = WPA_KEY_MGMT_WPS;
@@ -399,11 +411,15 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
wpa_s->key_mgmt = WPA_KEY_MGMT_NONE;
wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0);
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_ap_rsnxe(wpa_s->wpa, NULL, 0);
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
+ wpa_s->rsnxe_len = 0;
wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
wpa_s->group_cipher = WPA_CIPHER_NONE;
wpa_s->mgmt_group_cipher = 0;
+#ifdef CONFIG_WEP
for (i = 0; i < NUM_WEP_KEYS; i++) {
if (ssid->wep_key_len[i] > 5) {
wpa_s->pairwise_cipher = WPA_CIPHER_WEP104;
@@ -415,16 +431,15 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
break;
}
}
+#endif /* CONFIG_WEP */
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED, 0);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PAIRWISE,
wpa_s->pairwise_cipher);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
-#ifdef CONFIG_IEEE80211W
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
wpa_s->mgmt_group_cipher);
-#endif /* CONFIG_IEEE80211W */
pmksa_cache_clear_current(wpa_s->wpa);
}
@@ -446,16 +461,22 @@ void free_hw_features(struct wpa_supplicant *wpa_s)
}
+static void remove_bss_tmp_disallowed_entry(struct wpa_supplicant *wpa_s,
+ struct wpa_bss_tmp_disallowed *bss)
+{
+ eloop_cancel_timeout(wpa_bss_tmp_disallow_timeout, wpa_s, bss);
+ dl_list_del(&bss->list);
+ os_free(bss);
+}
+
+
void free_bss_tmp_disallowed(struct wpa_supplicant *wpa_s)
{
struct wpa_bss_tmp_disallowed *bss, *prev;
dl_list_for_each_safe(bss, prev, &wpa_s->bss_tmp_disallowed,
- struct wpa_bss_tmp_disallowed, list) {
- eloop_cancel_timeout(wpa_bss_tmp_disallow_timeout, wpa_s, bss);
- dl_list_del(&bss->list);
- os_free(bss);
- }
+ struct wpa_bss_tmp_disallowed, list)
+ remove_bss_tmp_disallowed_entry(wpa_s, bss);
}
@@ -472,6 +493,31 @@ void wpas_flush_fils_hlp_req(struct wpa_supplicant *wpa_s)
}
+void wpas_clear_disabled_interface(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+
+ if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED)
+ return;
+ wpa_dbg(wpa_s, MSG_DEBUG, "Clear cached state on disabled interface");
+ wpa_bss_flush(wpa_s);
+}
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+void wpas_clear_driver_signal_override(struct wpa_supplicant *wpa_s)
+{
+ struct driver_signal_override *dso;
+
+ while ((dso = dl_list_first(&wpa_s->drv_signal_override,
+ struct driver_signal_override, list))) {
+ dl_list_del(&dso->list);
+ os_free(dso);
+ }
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
{
int i;
@@ -495,6 +541,15 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
wpa_s->get_pref_freq_list_override = NULL;
wpabuf_free(wpa_s->last_assoc_req_wpa_ie);
wpa_s->last_assoc_req_wpa_ie = NULL;
+ os_free(wpa_s->extra_sae_rejected_groups);
+ wpa_s->extra_sae_rejected_groups = NULL;
+ wpabuf_free(wpa_s->rsne_override_eapol);
+ wpa_s->rsne_override_eapol = NULL;
+ wpabuf_free(wpa_s->rsnxe_override_assoc);
+ wpa_s->rsnxe_override_assoc = NULL;
+ wpabuf_free(wpa_s->rsnxe_override_eapol);
+ wpa_s->rsnxe_override_eapol = NULL;
+ wpas_clear_driver_signal_override(wpa_s);
#endif /* CONFIG_TESTING_OPTIONS */
if (wpa_s->conf != NULL) {
@@ -525,9 +580,15 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
wmm_ac_clear_saved_tspecs(wpa_s);
pmksa_candidate_free(wpa_s->wpa);
+ ptksa_cache_deinit(wpa_s->ptksa);
+ wpa_s->ptksa = NULL;
wpa_sm_deinit(wpa_s->wpa);
wpa_s->wpa = NULL;
- wpa_blacklist_clear(wpa_s);
+ wpa_bssid_ignore_clear(wpa_s);
+
+#ifdef CONFIG_PASN
+ wpas_pasn_auth_stop(wpa_s);
+#endif /* CONFIG_PASN */
wpa_bss_deinit(wpa_s);
@@ -541,6 +602,7 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
#endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */
eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_clear_disabled_interface, wpa_s, NULL);
wpas_wps_deinit(wpa_s);
@@ -677,6 +739,12 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
dpp_global_deinit(wpa_s->dpp);
wpa_s->dpp = NULL;
#endif /* CONFIG_DPP */
+
+#ifdef CONFIG_PASN
+ wpas_pasn_auth_stop(wpa_s);
+#endif /* CONFIG_PASN */
+ wpas_scs_deinit(wpa_s);
+ wpas_dscp_deinit(wpa_s);
}
@@ -690,25 +758,24 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
*/
void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
{
- int i, max;
-
-#ifdef CONFIG_IEEE80211W
- max = 6;
-#else /* CONFIG_IEEE80211W */
- max = 4;
-#endif /* CONFIG_IEEE80211W */
+ int i, max = 6;
/* MLME-DELETEKEYS.request */
for (i = 0; i < max; i++) {
if (wpa_s->keys_cleared & BIT(i))
continue;
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, i, 0, NULL, 0,
- NULL, 0);
+ NULL, 0, KEY_FLAG_GROUP);
}
- if (!(wpa_s->keys_cleared & BIT(0)) && addr &&
+ /* Pairwise Key ID 1 for Extended Key ID is tracked in bit 15 */
+ if (~wpa_s->keys_cleared & (BIT(0) | BIT(15)) && addr &&
!is_zero_ether_addr(addr)) {
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL,
- 0);
+ if (!(wpa_s->keys_cleared & BIT(0)))
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL,
+ 0, NULL, 0, KEY_FLAG_PAIRWISE);
+ if (!(wpa_s->keys_cleared & BIT(15)))
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 1, 0, NULL,
+ 0, NULL, 0, KEY_FLAG_PAIRWISE);
/* MLME-SETPROTECTION.request(None) */
wpa_drv_mlme_setprotection(
wpa_s, addr,
@@ -755,7 +822,22 @@ const char * wpa_supplicant_state_txt(enum wpa_states state)
#ifdef CONFIG_BGSCAN
-static void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s)
+static void wpa_supplicant_stop_bgscan(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->bgscan_ssid) {
+ bgscan_deinit(wpa_s);
+ wpa_s->bgscan_ssid = NULL;
+ }
+}
+
+
+/**
+ * wpa_supplicant_reset_bgscan - Reset the bgscan for the current SSID.
+ * @wpa_s: Pointer to the wpa_supplicant data
+ *
+ * Stop, start, or reconfigure the scan parameters depending on the method.
+ */
+void wpa_supplicant_reset_bgscan(struct wpa_supplicant *wpa_s)
{
const char *name;
@@ -763,12 +845,12 @@ static void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s)
name = wpa_s->current_ssid->bgscan;
else
name = wpa_s->conf->bgscan;
- if (name == NULL || name[0] == '\0')
+ if (!name || name[0] == '\0') {
+ wpa_supplicant_stop_bgscan(wpa_s);
return;
+ }
if (wpas_driver_bss_selection(wpa_s))
return;
- if (wpa_s->current_ssid == wpa_s->bgscan_ssid)
- return;
#ifdef CONFIG_P2P
if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE)
return;
@@ -798,15 +880,6 @@ static void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s)
wpa_s->bgscan_ssid = NULL;
}
-
-static void wpa_supplicant_stop_bgscan(struct wpa_supplicant *wpa_s)
-{
- if (wpa_s->bgscan_ssid != NULL) {
- bgscan_deinit(wpa_s);
- wpa_s->bgscan_ssid = NULL;
- }
-}
-
#endif /* CONFIG_BGSCAN */
@@ -845,6 +918,9 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
enum wpa_states state)
{
enum wpa_states old_state = wpa_s->wpa_state;
+#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
+ bool update_fils_connect_params = false;
+#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
wpa_dbg(wpa_s, MSG_DEBUG, "State: %s -> %s",
wpa_supplicant_state_txt(wpa_s->wpa_state),
@@ -927,8 +1003,7 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
fils_hlp_sent ? " FILS_HLP_SENT" : "");
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
wpas_clear_temp_disabled(wpa_s, ssid, 1);
- wpa_blacklist_clear(wpa_s);
- wpa_s->extra_blacklist_count = 0;
+ wpa_s->consecutive_conn_failures = 0;
wpa_s->new_connection = 0;
wpa_drv_set_operstate(wpa_s, 1);
#ifndef IEEE8021X_EAPOL
@@ -942,8 +1017,12 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
if (!fils_hlp_sent && ssid && ssid->eap.erp)
- wpas_update_fils_connect_params(wpa_s);
+ update_fils_connect_params = true;
#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
+#ifdef CONFIG_OWE
+ if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_OWE))
+ wpas_update_owe_connect_params(wpa_s);
+#endif /* CONFIG_OWE */
} else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
state == WPA_ASSOCIATED) {
wpa_s->new_connection = 1;
@@ -956,8 +1035,8 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
wpa_s->wpa_state = state;
#ifdef CONFIG_BGSCAN
- if (state == WPA_COMPLETED)
- wpa_supplicant_start_bgscan(wpa_s);
+ if (state == WPA_COMPLETED && wpa_s->current_ssid != wpa_s->bgscan_ssid)
+ wpa_supplicant_reset_bgscan(wpa_s);
else if (state < WPA_ASSOCIATED)
wpa_supplicant_stop_bgscan(wpa_s);
#endif /* CONFIG_BGSCAN */
@@ -983,7 +1062,15 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
if (wpa_s->wpa_state == WPA_COMPLETED ||
old_state == WPA_COMPLETED)
wpas_notify_auth_changed(wpa_s);
+#ifdef CONFIG_DPP2
+ if (wpa_s->wpa_state == WPA_COMPLETED)
+ wpas_dpp_connected(wpa_s);
+#endif /* CONFIG_DPP2 */
}
+#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
+ if (update_fils_connect_params)
+ wpas_update_fils_connect_params(wpa_s);
+#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
}
@@ -1020,13 +1107,19 @@ static void wpa_supplicant_terminate(int sig, void *signal_ctx)
void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s)
{
enum wpa_states old_state = wpa_s->wpa_state;
+ enum wpa_states new_state;
+
+ if (old_state == WPA_SCANNING)
+ new_state = WPA_SCANNING;
+ else
+ new_state = WPA_DISCONNECTED;
wpa_s->pairwise_cipher = 0;
wpa_s->group_cipher = 0;
wpa_s->mgmt_group_cipher = 0;
wpa_s->key_mgmt = 0;
if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED)
- wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+ wpa_supplicant_set_state(wpa_s, new_state);
if (wpa_s->wpa_state != old_state)
wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
@@ -1073,8 +1166,8 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
os_strcmp(conf->ctrl_interface,
wpa_s->conf->ctrl_interface) != 0);
- if (reconf_ctrl && wpa_s->ctrl_iface) {
- wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
+ if (reconf_ctrl) {
+ wpa_supplicant_ctrl_iface_deinit(wpa_s, wpa_s->ctrl_iface);
wpa_s->ctrl_iface = NULL;
}
@@ -1097,7 +1190,7 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
* Clear forced success to clear EAP state for next
* authentication.
*/
- eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
+ eapol_sm_notify_eap_success(wpa_s->eapol, false);
}
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
wpa_sm_set_config(wpa_s->wpa, NULL);
@@ -1121,6 +1214,7 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
wpa_s->reassociate = 1;
wpa_supplicant_req_scan(wpa_s, 0, 0);
}
+ wpa_bssid_ignore_clear(wpa_s);
wpa_dbg(wpa_s, MSG_DEBUG, "Reconfiguration completed");
return 0;
}
@@ -1179,7 +1273,6 @@ static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s,
return -1;
}
-#ifdef CONFIG_IEEE80211W
if (!(ie->capabilities & WPA_CAPABILITY_MFPC) &&
wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) {
wpa_msg(wpa_s, MSG_INFO, "WPA: Driver associated with an AP "
@@ -1187,7 +1280,6 @@ static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s,
"reject");
return -1;
}
-#endif /* CONFIG_IEEE80211W */
return 0;
}
@@ -1205,6 +1297,47 @@ static int matching_ciphers(struct wpa_ssid *ssid, struct wpa_ie_data *ie,
}
+void wpas_set_mgmt_group_cipher(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid, struct wpa_ie_data *ie)
+{
+ int sel;
+
+ sel = ie->mgmt_group_cipher;
+ if (ssid->group_mgmt_cipher)
+ sel &= ssid->group_mgmt_cipher;
+ if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION ||
+ !(ie->capabilities & WPA_CAPABILITY_MFPC))
+ sel = 0;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: AP mgmt_group_cipher 0x%x network profile mgmt_group_cipher 0x%x; available mgmt_group_cipher 0x%x",
+ ie->mgmt_group_cipher, ssid->group_mgmt_cipher, sel);
+ if (sel & WPA_CIPHER_AES_128_CMAC) {
+ wpa_s->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: using MGMT group cipher AES-128-CMAC");
+ } else if (sel & WPA_CIPHER_BIP_GMAC_128) {
+ wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_GMAC_128;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: using MGMT group cipher BIP-GMAC-128");
+ } else if (sel & WPA_CIPHER_BIP_GMAC_256) {
+ wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_GMAC_256;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: using MGMT group cipher BIP-GMAC-256");
+ } else if (sel & WPA_CIPHER_BIP_CMAC_256) {
+ wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_CMAC_256;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: using MGMT group cipher BIP-CMAC-256");
+ } else {
+ wpa_s->mgmt_group_cipher = 0;
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: not using MGMT group cipher");
+ }
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
+ wpa_s->mgmt_group_cipher);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP,
+ wpas_get_ssid_pmf(wpa_s, ssid));
+}
+
+
/**
* wpa_supplicant_set_suites - Set authentication and encryption parameters
* @wpa_s: Pointer to wpa_supplicant data
@@ -1224,15 +1357,17 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
u8 *wpa_ie, size_t *wpa_ie_len)
{
struct wpa_ie_data ie;
- int sel, proto;
- const u8 *bss_wpa, *bss_rsn, *bss_osen;
+ int sel, proto, sae_pwe;
+ const u8 *bss_wpa, *bss_rsn, *bss_rsnx, *bss_osen;
if (bss) {
bss_wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
bss_rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ bss_rsnx = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
bss_osen = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
- } else
- bss_wpa = bss_rsn = bss_osen = NULL;
+ } else {
+ bss_wpa = bss_rsn = bss_rsnx = bss_osen = NULL;
+ }
if (bss_rsn && (ssid->proto & WPA_PROTO_RSN) &&
wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 &&
@@ -1312,7 +1447,6 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
ie.group_cipher = ssid->group_cipher;
ie.pairwise_cipher = ssid->pairwise_cipher;
ie.key_mgmt = ssid->key_mgmt;
-#ifdef CONFIG_IEEE80211W
ie.mgmt_group_cipher = 0;
if (ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
if (ssid->group_mgmt_cipher &
@@ -1331,7 +1465,6 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
ie.mgmt_group_cipher =
WPA_CIPHER_AES_128_CMAC;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OWE
if ((ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
!ssid->owe_only &&
@@ -1351,12 +1484,10 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected cipher suites: group %d "
"pairwise %d key_mgmt %d proto %d",
ie.group_cipher, ie.pairwise_cipher, ie.key_mgmt, proto);
-#ifdef CONFIG_IEEE80211W
if (ssid->ieee80211w) {
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected mgmt group cipher %d",
ie.mgmt_group_cipher);
}
-#endif /* CONFIG_IEEE80211W */
wpa_s->wpa_proto = proto;
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, proto);
@@ -1367,7 +1498,9 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa,
bss_wpa ? 2 + bss_wpa[1] : 0) ||
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn,
- bss_rsn ? 2 + bss_rsn[1] : 0))
+ bss_rsn ? 2 + bss_rsn[1] : 0) ||
+ wpa_sm_set_ap_rsnxe(wpa_s->wpa, bss_rsnx,
+ bss_rsnx ? 2 + bss_rsnx[1] : 0))
return -1;
}
@@ -1403,17 +1536,23 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_NO_WPA */
sel = ie.key_mgmt & ssid->key_mgmt;
- wpa_dbg(wpa_s, MSG_DEBUG,
- "WPA: AP key_mgmt 0x%x network profile key_mgmt 0x%x; available key_mgmt 0x%x",
- ie.key_mgmt, ssid->key_mgmt, sel);
#ifdef CONFIG_SAE
if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE))
sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE);
#endif /* CONFIG_SAE */
+#ifdef CONFIG_IEEE80211R
+ if (!(wpa_s->drv_flags & (WPA_DRIVER_FLAGS_SME |
+ WPA_DRIVER_FLAGS_UPDATE_FT_IES)))
+ sel &= ~WPA_KEY_MGMT_FT;
+#endif /* CONFIG_IEEE80211R */
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: AP key_mgmt 0x%x network profile key_mgmt 0x%x; available key_mgmt 0x%x",
+ ie.key_mgmt, ssid->key_mgmt, sel);
if (0) {
#ifdef CONFIG_IEEE80211R
#ifdef CONFIG_SHA384
- } else if (sel & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
+ } else if ((sel & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) &&
+ os_strcmp(wpa_supplicant_get_eap_mode(wpa_s), "LEAP") != 0) {
wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
wpa_dbg(wpa_s, MSG_DEBUG,
"WPA: using KEY_MGMT FT/802.1X-SHA384");
@@ -1456,7 +1595,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FILS-SHA256");
#endif /* CONFIG_FILS */
#ifdef CONFIG_IEEE80211R
- } else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) {
+ } else if ((sel & WPA_KEY_MGMT_FT_IEEE8021X) &&
+ os_strcmp(wpa_supplicant_get_eap_mode(wpa_s), "LEAP") != 0) {
wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/802.1X");
if (!ssid->ft_eap_pmksa_caching &&
@@ -1486,7 +1626,6 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK");
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
} else if (sel & WPA_KEY_MGMT_IEEE8021X_SHA256) {
wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
wpa_dbg(wpa_s, MSG_DEBUG,
@@ -1495,7 +1634,6 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
wpa_s->key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
wpa_dbg(wpa_s, MSG_DEBUG,
"WPA: using KEY_MGMT PSK with SHA256");
-#endif /* CONFIG_IEEE80211W */
} else if (sel & WPA_KEY_MGMT_IEEE8021X) {
wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT 802.1X");
@@ -1526,55 +1664,89 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
wpa_s->pairwise_cipher);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
-#ifdef CONFIG_IEEE80211W
- sel = ie.mgmt_group_cipher;
- if (ssid->group_mgmt_cipher)
- sel &= ssid->group_mgmt_cipher;
- if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION ||
- !(ie.capabilities & WPA_CAPABILITY_MFPC))
- sel = 0;
- wpa_dbg(wpa_s, MSG_DEBUG,
- "WPA: AP mgmt_group_cipher 0x%x network profile mgmt_group_cipher 0x%x; available mgmt_group_cipher 0x%x",
- ie.mgmt_group_cipher, ssid->group_mgmt_cipher, sel);
- if (sel & WPA_CIPHER_AES_128_CMAC) {
- wpa_s->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
- "AES-128-CMAC");
- } else if (sel & WPA_CIPHER_BIP_GMAC_128) {
- wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_GMAC_128;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
- "BIP-GMAC-128");
- } else if (sel & WPA_CIPHER_BIP_GMAC_256) {
- wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_GMAC_256;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
- "BIP-GMAC-256");
- } else if (sel & WPA_CIPHER_BIP_CMAC_256) {
- wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_CMAC_256;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
- "BIP-CMAC-256");
- } else {
- wpa_s->mgmt_group_cipher = 0;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: not using MGMT group cipher");
+ if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
+ wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "RSN: Management frame protection required but the selected AP does not enable it");
+ return -1;
}
- wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
- wpa_s->mgmt_group_cipher);
- wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP,
- wpas_get_ssid_pmf(wpa_s, ssid));
-#endif /* CONFIG_IEEE80211W */
+
+ wpas_set_mgmt_group_cipher(wpa_s, ssid, &ie);
#ifdef CONFIG_OCV
- wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCV, ssid->ocv);
+ if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) ||
+ (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_OCV))
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCV, ssid->ocv);
#endif /* CONFIG_OCV */
+ sae_pwe = wpa_s->conf->sae_pwe;
+ if (ssid->sae_password_id && sae_pwe != 3)
+ sae_pwe = 1;
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SAE_PWE, sae_pwe);
+#ifdef CONFIG_SAE_PK
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SAE_PK,
+ wpa_key_mgmt_sae(ssid->key_mgmt) &&
+ ssid->sae_pk != SAE_PK_MODE_DISABLED &&
+ ((ssid->sae_password &&
+ sae_pk_valid_password(ssid->sae_password)) ||
+ (!ssid->sae_password && ssid->passphrase &&
+ sae_pk_valid_password(ssid->passphrase))));
+#endif /* CONFIG_SAE_PK */
+#ifdef CONFIG_TESTING_OPTIONS
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_FT_RSNXE_USED,
+ wpa_s->ft_rsnxe_used);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_EAPOL,
+ wpa_s->oci_freq_override_eapol);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_EAPOL_G2,
+ wpa_s->oci_freq_override_eapol_g2);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_FT_ASSOC,
+ wpa_s->oci_freq_override_ft_assoc);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_FILS_ASSOC,
+ wpa_s->oci_freq_override_fils_assoc);
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* Extended Key ID is only supported in infrastructure BSS so far */
+ if (ssid->mode == WPAS_MODE_INFRA && wpa_s->conf->extended_key_id &&
+ (ssid->proto & WPA_PROTO_RSN) &&
+ ssid->pairwise_cipher & (WPA_CIPHER_CCMP | WPA_CIPHER_CCMP_256 |
+ WPA_CIPHER_GCMP | WPA_CIPHER_GCMP_256) &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_EXTENDED_KEY_ID)) {
+ int use_ext_key_id = 0;
+
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "WPA: Enable Extended Key ID support");
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_EXT_KEY_ID,
+ wpa_s->conf->extended_key_id);
+ if (bss_rsn &&
+ wpa_s->conf->extended_key_id &&
+ wpa_s->pairwise_cipher != WPA_CIPHER_TKIP &&
+ (ie.capabilities & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST))
+ use_ext_key_id = 1;
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_USE_EXT_KEY_ID,
+ use_ext_key_id);
+ } else {
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_EXT_KEY_ID, 0);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_USE_EXT_KEY_ID, 0);
+ }
if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to generate WPA IE");
return -1;
}
+ wpa_s->rsnxe_len = sizeof(wpa_s->rsnxe);
+ if (wpa_sm_set_assoc_rsnxe_default(wpa_s->wpa, wpa_s->rsnxe,
+ &wpa_s->rsnxe_len)) {
+ wpa_msg(wpa_s, MSG_WARNING, "RSN: Failed to generate RSNXE");
+ return -1;
+ }
+
if (0) {
#ifdef CONFIG_DPP
} else if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP) {
/* Use PMK from DPP network introduction (PMKSA entry) */
wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
+#ifdef CONFIG_DPP2
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DPP_PFS, ssid->dpp_pfs);
+#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
} else if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
int psk_set = 0;
@@ -1691,12 +1863,28 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
} else
wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
+ if (ssid->mode != WPAS_MODE_IBSS &&
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED) &&
+ (ssid->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_NEVER ||
+ (ssid->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_LOCAL_OK &&
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAFE_PTK0_REKEYS)))) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Disable PTK0 rekey support - replaced with reconnect");
+ wpa_s->deny_ptk0_rekey = 1;
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DENY_PTK0_REKEY, 1);
+ } else {
+ wpa_s->deny_ptk0_rekey = 0;
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DENY_PTK0_REKEY, 0);
+ }
+
return 0;
}
static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
{
+ bool scs = true, mscs = true;
+
*pos = 0x00;
switch (idx) {
@@ -1711,7 +1899,7 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
case 2: /* Bits 16-23 */
#ifdef CONFIG_WNM
*pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
- if (!wpa_s->conf->disable_btm)
+ if (!wpa_s->disable_mbo_oce && !wpa_s->conf->disable_btm)
*pos |= 0x08; /* Bit 19 - BSS Transition */
#endif /* CONFIG_WNM */
break;
@@ -1740,6 +1928,12 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
#endif /* CONFIG_MBO */
break;
case 6: /* Bits 48-55 */
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->disable_scs_support)
+ scs = false;
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (scs)
+ *pos |= 0x40; /* Bit 54 - SCS */
break;
case 7: /* Bits 56-63 */
break;
@@ -1755,6 +1949,14 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
*pos |= 0x01;
#endif /* CONFIG_FILS */
break;
+ case 10: /* Bits 80-87 */
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->disable_mscs_support)
+ mscs = false;
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (mscs)
+ *pos |= 0x20; /* Bit 85 - Mirrored SCS */
+ break;
}
}
@@ -1762,7 +1964,7 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen)
{
u8 *pos = buf;
- u8 len = 10, i;
+ u8 len = 11, i;
if (len < wpa_s->extended_capa_len)
len = wpa_s->extended_capa_len;
@@ -1918,6 +2120,79 @@ int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s)
}
+static void wpa_s_setup_sae_pt(struct wpa_config *conf, struct wpa_ssid *ssid)
+{
+#ifdef CONFIG_SAE
+ int *groups = conf->sae_groups;
+ int default_groups[] = { 19, 20, 21, 0 };
+ const char *password;
+
+ if (!groups || groups[0] <= 0)
+ groups = default_groups;
+
+ password = ssid->sae_password;
+ if (!password)
+ password = ssid->passphrase;
+
+ if (!password ||
+ (conf->sae_pwe == 0 && !ssid->sae_password_id &&
+ !sae_pk_valid_password(password)) ||
+ conf->sae_pwe == 3) {
+ /* PT derivation not needed */
+ sae_deinit_pt(ssid->pt);
+ ssid->pt = NULL;
+ return;
+ }
+
+ if (ssid->pt)
+ return; /* PT already derived */
+ ssid->pt = sae_derive_pt(groups, ssid->ssid, ssid->ssid_len,
+ (const u8 *) password, os_strlen(password),
+ ssid->sae_password_id);
+#endif /* CONFIG_SAE */
+}
+
+
+static void wpa_s_clear_sae_rejected(struct wpa_supplicant *wpa_s)
+{
+#if defined(CONFIG_SAE) && defined(CONFIG_SME)
+ os_free(wpa_s->sme.sae_rejected_groups);
+ wpa_s->sme.sae_rejected_groups = NULL;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->extra_sae_rejected_groups) {
+ int i, *groups = wpa_s->extra_sae_rejected_groups;
+
+ for (i = 0; groups[i]; i++) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: Indicate rejection of an extra SAE group %d",
+ groups[i]);
+ int_array_add_unique(&wpa_s->sme.sae_rejected_groups,
+ groups[i]);
+ }
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_SAE && CONFIG_SME */
+}
+
+
+int wpas_restore_permanent_mac_addr(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_drv_set_mac_addr(wpa_s, NULL) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Could not restore permanent MAC address");
+ return -1;
+ }
+ wpa_s->mac_addr_changed = 0;
+ if (wpa_supplicant_update_mac_addr(wpa_s) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Could not update MAC address information");
+ return -1;
+ }
+ wpa_msg(wpa_s, MSG_DEBUG, "Using permanent MAC address");
+ return 0;
+}
+
+
static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit);
/**
@@ -1935,6 +2210,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
int rand_style;
wpa_s->own_disconnect_req = 0;
+ wpa_s->own_reconnect_req = 0;
/*
* If we are starting a new connection, any previously pending EAPOL
@@ -1948,6 +2224,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
else
rand_style = ssid->mac_addr;
+ wpa_s->multi_ap_ie = 0;
wmm_ac_clear_saved_tspecs(wpa_s);
wpa_s->reassoc_same_bss = 0;
wpa_s->reassoc_same_ess = 0;
@@ -1964,25 +2241,22 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
} else if (wpa_s->current_bss && wpa_s->current_bss != bss) {
os_get_reltime(&wpa_s->roam_start);
}
+ } else {
+#ifdef CONFIG_SAE
+ wpa_s_clear_sae_rejected(wpa_s);
+#endif /* CONFIG_SAE */
}
+#ifdef CONFIG_SAE
+ wpa_s_setup_sae_pt(wpa_s->conf, ssid);
+#endif /* CONFIG_SAE */
if (rand_style > 0 && !wpa_s->reassoc_same_ess) {
if (wpas_update_random_addr(wpa_s, rand_style) < 0)
return;
wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
} else if (rand_style == 0 && wpa_s->mac_addr_changed) {
- if (wpa_drv_set_mac_addr(wpa_s, NULL) < 0) {
- wpa_msg(wpa_s, MSG_INFO,
- "Could not restore permanent MAC address");
+ if (wpas_restore_permanent_mac_addr(wpa_s) < 0)
return;
- }
- wpa_s->mac_addr_changed = 0;
- if (wpa_supplicant_update_mac_addr(wpa_s) < 0) {
- wpa_msg(wpa_s, MSG_INFO,
- "Could not update MAC address information");
- return;
- }
- wpa_msg(wpa_s, MSG_DEBUG, "Using permanent MAC address");
}
wpa_s->last_ssid = ssid;
@@ -2034,10 +2308,6 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
return;
}
wpa_s->current_bss = bss;
- wpa_msg(wpa_s, MSG_INFO, MESH_GROUP_STARTED "ssid=\"%s\" id=%d",
- wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
- ssid->id);
- wpas_notify_mesh_group_started(wpa_s, ssid);
#else /* CONFIG_MESH */
wpa_msg(wpa_s, MSG_ERROR,
"mesh mode support not included in the build");
@@ -2061,10 +2331,13 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_TDLS
if (bss)
- wpa_tdls_ap_ies(wpa_s->wpa, (const u8 *) (bss + 1),
- bss->ie_len);
+ wpa_tdls_ap_ies(wpa_s->wpa, wpa_bss_ie_ptr(bss), bss->ie_len);
#endif /* CONFIG_TDLS */
+#ifdef CONFIG_MBO
+ wpas_mbo_check_pmf(wpa_s, bss, ssid);
+#endif /* CONFIG_MBO */
+
if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
ssid->mode == WPAS_MODE_INFRA) {
sme_authenticate(wpa_s, bss, ssid);
@@ -2136,6 +2409,23 @@ static int drv_supports_vht(struct wpa_supplicant *wpa_s,
}
+static bool ibss_mesh_is_80mhz_avail(int channel, struct hostapd_hw_modes *mode)
+{
+ int i;
+
+ for (i = channel; i < channel + 16; i += 4) {
+ struct hostapd_channel_data *chan;
+
+ chan = hw_get_channel_chan(mode, i, NULL);
+ if (!chan ||
+ chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
+ return false;
+ }
+
+ return true;
+}
+
+
void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
const struct wpa_ssid *ssid,
struct hostapd_freq_params *freq)
@@ -2145,7 +2435,10 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
struct hostapd_hw_modes *mode = NULL;
int ht40plus[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
184, 192 };
- int vht80[] = { 36, 52, 100, 116, 132, 149 };
+ int bw80[] = { 5180, 5260, 5500, 5580, 5660, 5745, 5955,
+ 6035, 6115, 6195, 6275, 6355, 6435, 6515,
+ 6595, 6675, 6755, 6835, 6915, 6995 };
+ int bw160[] = { 5955, 6115, 6275, 6435, 6595, 6755, 6915 };
struct hostapd_channel_data *pri_chan = NULL, *sec_chan = NULL;
u8 channel;
int i, chan_idx, ht40 = -1, res, obss_scan = 1;
@@ -2153,6 +2446,7 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
struct hostapd_freq_params vht_freq;
int chwidth, seg0, seg1;
u32 vht_caps = 0;
+ bool is_24ghz, is_6ghz;
freq->freq = ssid->frequency;
@@ -2204,8 +2498,17 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
if (!mode)
return;
- /* HE can work without HT + VHT */
- freq->he_enabled = mode->he_capab[ieee80211_mode].he_supported;
+ freq->channel = channel;
+
+ is_24ghz = hw_mode == HOSTAPD_MODE_IEEE80211G ||
+ hw_mode == HOSTAPD_MODE_IEEE80211B;
+
+ /* HT/VHT and corresponding overrides are not applicable to 6 GHz.
+ * However, HE is mandatory for 6 GHz.
+ */
+ is_6ghz = is_6ghz_freq(freq->freq);
+ if (is_6ghz)
+ goto skip_to_6ghz;
#ifdef CONFIG_HT_OVERRIDES
if (ssid->disable_ht) {
@@ -2218,6 +2521,14 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
if (!freq->ht_enabled)
return;
+ /* Allow HE on 2.4 GHz without VHT: see nl80211_put_freq_params() */
+ if (is_24ghz)
+ freq->he_enabled = mode->he_capab[ieee80211_mode].he_supported;
+#ifdef CONFIG_HE_OVERRIDES
+ if (is_24ghz && ssid->disable_he)
+ freq->he_enabled = 0;
+#endif /* CONFIG_HE_OVERRIDES */
+
/* Setup higher BW only for 5 GHz */
if (mode->mode != HOSTAPD_MODE_IEEE80211A)
return;
@@ -2239,8 +2550,10 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_HT_OVERRIDES
if (ssid->disable_ht40) {
+#ifdef CONFIG_VHT_OVERRIDES
if (ssid->disable_vht)
return;
+#endif /* CONFIG_VHT_OVERRIDES */
goto skip_ht40;
}
#endif /* CONFIG_HT_OVERRIDES */
@@ -2286,8 +2599,7 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
return;
}
- res = check_40mhz_5g(mode, scan_res, pri_chan->chan,
- sec_chan->chan);
+ res = check_40mhz_5g(scan_res, pri_chan, sec_chan);
switch (res) {
case 0:
/* Back to HT20 */
@@ -2325,8 +2637,6 @@ skip_ht40:
!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_VHT_IBSS))
return;
- vht_freq = *freq;
-
#ifdef CONFIG_VHT_OVERRIDES
if (ssid->disable_vht) {
freq->vht_enabled = 0;
@@ -2334,43 +2644,67 @@ skip_ht40:
}
#endif /* CONFIG_VHT_OVERRIDES */
+skip_to_6ghz:
+ vht_freq = *freq;
+
+ /* 6 GHz does not have VHT enabled, so allow that exception here. */
vht_freq.vht_enabled = vht_supported(mode);
- if (!vht_freq.vht_enabled)
+ if (!vht_freq.vht_enabled && !is_6ghz)
return;
+ /* Enable HE with VHT for 5 GHz */
+ freq->he_enabled = mode->he_capab[ieee80211_mode].he_supported;
+
/* setup center_freq1, bandwidth */
- for (j = 0; j < ARRAY_SIZE(vht80); j++) {
- if (freq->channel >= vht80[j] &&
- freq->channel < vht80[j] + 16)
+ for (j = 0; j < ARRAY_SIZE(bw80); j++) {
+ if (freq->freq >= bw80[j] &&
+ freq->freq < bw80[j] + 80)
break;
}
- if (j == ARRAY_SIZE(vht80))
+ if (j == ARRAY_SIZE(bw80) ||
+ ieee80211_freq_to_chan(bw80[j], &channel) == NUM_HOSTAPD_MODES)
return;
- for (i = vht80[j]; i < vht80[j] + 16; i += 4) {
- struct hostapd_channel_data *chan;
+ /* Back to HT configuration if channel not usable */
+ if (!ibss_mesh_is_80mhz_avail(channel, mode))
+ return;
- chan = hw_get_channel_chan(mode, i, NULL);
- if (!chan)
- return;
+ chwidth = CHANWIDTH_80MHZ;
+ seg0 = channel + 6;
+ seg1 = 0;
- /* Back to HT configuration if channel not usable */
- if (chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
+ if ((mode->he_capab[ieee80211_mode].phy_cap[
+ HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G) && is_6ghz) {
+ /* In 160 MHz, the initial four 20 MHz channels were validated
+ * above; check the remaining four 20 MHz channels for the total
+ * of 160 MHz bandwidth.
+ */
+ if (!ibss_mesh_is_80mhz_avail(channel + 16, mode))
return;
- }
- chwidth = CHANWIDTH_80MHZ;
- seg0 = vht80[j] + 6;
- seg1 = 0;
+ for (j = 0; j < ARRAY_SIZE(bw160); j++) {
+ if (freq->freq == bw160[j]) {
+ chwidth = CHANWIDTH_160MHZ;
+ seg0 = channel + 14;
+ break;
+ }
+ }
+ }
if (ssid->max_oper_chwidth == CHANWIDTH_80P80MHZ) {
/* setup center_freq2, bandwidth */
- for (k = 0; k < ARRAY_SIZE(vht80); k++) {
+ for (k = 0; k < ARRAY_SIZE(bw80); k++) {
/* Only accept 80 MHz segments separated by a gap */
- if (j == k || abs(vht80[j] - vht80[k]) == 16)
+ if (j == k || abs(bw80[j] - bw80[k]) == 80)
continue;
- for (i = vht80[k]; i < vht80[k] + 16; i += 4) {
+
+ if (ieee80211_freq_to_chan(bw80[k], &channel) ==
+ NUM_HOSTAPD_MODES)
+ return;
+
+ for (i = channel; i < channel + 16; i += 4) {
struct hostapd_channel_data *chan;
chan = hw_get_channel_chan(mode, i, NULL);
@@ -2384,9 +2718,10 @@ skip_ht40:
/* Found a suitable second segment for 80+80 */
chwidth = CHANWIDTH_80P80MHZ;
- vht_caps |=
- VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
- seg1 = vht80[k] + 6;
+ if (!is_6ghz)
+ vht_caps |=
+ VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
+ seg1 = channel + 6;
}
if (chwidth == CHANWIDTH_80P80MHZ)
@@ -2404,15 +2739,22 @@ skip_ht40:
}
} else if (ssid->max_oper_chwidth == CHANWIDTH_USE_HT) {
chwidth = CHANWIDTH_USE_HT;
- seg0 = vht80[j] + 2;
+ seg0 = channel + 2;
#ifdef CONFIG_HT_OVERRIDES
if (ssid->disable_ht40)
seg0 = 0;
#endif /* CONFIG_HT_OVERRIDES */
}
+#ifdef CONFIG_HE_OVERRIDES
+ if (ssid->disable_he) {
+ vht_freq.he_enabled = 0;
+ freq->he_enabled = 0;
+ }
+#endif /* CONFIG_HE_OVERRIDES */
if (hostapd_set_freq_params(&vht_freq, mode->mode, freq->freq,
- freq->channel, freq->ht_enabled,
+ freq->channel, ssid->enable_edmg,
+ ssid->edmg_channel, freq->ht_enabled,
vht_freq.vht_enabled, freq->he_enabled,
freq->sec_channel_offset,
chwidth, seg0, seg1, vht_caps,
@@ -2517,6 +2859,54 @@ int wpa_is_fils_sk_pfs_supported(struct wpa_supplicant *wpa_s)
#endif /* CONFIG_FILS */
+static int wpas_populate_wfa_capa(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss,
+ u8 *wpa_ie, size_t wpa_ie_len,
+ size_t max_wpa_ie_len)
+{
+ struct wpabuf *wfa_ie = NULL;
+ u8 wfa_capa[1];
+ size_t wfa_ie_len, buf_len;
+
+ os_memset(wfa_capa, 0, sizeof(wfa_capa));
+ if (wpa_s->enable_dscp_policy_capa)
+ wfa_capa[0] |= WFA_CAPA_QM_DSCP_POLICY;
+
+ if (!wfa_capa[0])
+ return wpa_ie_len;
+
+ /* Wi-Fi Alliance element */
+ buf_len = 1 + /* Element ID */
+ 1 + /* Length */
+ 3 + /* OUI */
+ 1 + /* OUI Type */
+ 1 + /* Capabilities Length */
+ sizeof(wfa_capa); /* Capabilities */
+ wfa_ie = wpabuf_alloc(buf_len);
+ if (!wfa_ie)
+ return wpa_ie_len;
+
+ wpabuf_put_u8(wfa_ie, WLAN_EID_VENDOR_SPECIFIC);
+ wpabuf_put_u8(wfa_ie, buf_len - 2);
+ wpabuf_put_be24(wfa_ie, OUI_WFA);
+ wpabuf_put_u8(wfa_ie, WFA_CAPA_OUI_TYPE);
+ wpabuf_put_u8(wfa_ie, sizeof(wfa_capa));
+ wpabuf_put_data(wfa_ie, wfa_capa, sizeof(wfa_capa));
+
+ wfa_ie_len = wpabuf_len(wfa_ie);
+ if (wpa_ie_len + wfa_ie_len <= max_wpa_ie_len) {
+ wpa_hexdump_buf(MSG_MSGDUMP, "WFA Capabilities element",
+ wfa_ie);
+ os_memcpy(wpa_ie + wpa_ie_len, wpabuf_head(wfa_ie),
+ wfa_ie_len);
+ wpa_ie_len += wfa_ie_len;
+ }
+
+ wpabuf_free(wfa_ie);
+ return wpa_ie_len;
+}
+
+
static u8 * wpas_populate_assoc_ies(
struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, struct wpa_ssid *ssid,
@@ -2530,9 +2920,9 @@ static u8 * wpas_populate_assoc_ies(
#ifdef CONFIG_MBO
const u8 *mbo_ie;
#endif
-#ifdef CONFIG_SAE
- int sae_pmksa_cached = 0;
-#endif /* CONFIG_SAE */
+#if defined(CONFIG_SAE) || defined(CONFIG_FILS)
+ int pmksa_cached = 0;
+#endif /* CONFIG_SAE || CONFIG_FILS */
#ifdef CONFIG_FILS
const u8 *realm, *username, *rrk;
size_t realm_len, username_len, rrk_len;
@@ -2572,9 +2962,9 @@ static u8 * wpas_populate_assoc_ies(
ssid, try_opportunistic,
cache_id, 0) == 0) {
eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
-#ifdef CONFIG_SAE
- sae_pmksa_cached = 1;
-#endif /* CONFIG_SAE */
+#if defined(CONFIG_SAE) || defined(CONFIG_FILS)
+ pmksa_cached = 1;
+#endif /* CONFIG_SAE || CONFIG_FILS */
}
wpa_ie_len = max_wpa_ie_len;
if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
@@ -2673,6 +3063,10 @@ static u8 * wpas_populate_assoc_ies(
if (mask)
*mask |= WPA_DRV_UPDATE_FILS_ERP_INFO;
+ } else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD) &&
+ ssid->eap.erp && wpa_key_mgmt_fils(wpa_s->key_mgmt) &&
+ pmksa_cached) {
+ algs = WPA_AUTH_ALG_FILS;
}
#endif /* CONFIG_FILS */
#endif /* IEEE8021X_EAPOL */
@@ -2689,7 +3083,7 @@ static u8 * wpas_populate_assoc_ies(
}
#ifdef CONFIG_SAE
- if (sae_pmksa_cached && algs == WPA_AUTH_ALG_SAE) {
+ if (pmksa_cached && algs == WPA_AUTH_ALG_SAE) {
wpa_dbg(wpa_s, MSG_DEBUG,
"SAE: Use WPA_AUTH_ALG_OPEN for PMKSA caching attempt");
algs = WPA_AUTH_ALG_OPEN;
@@ -2728,7 +3122,7 @@ static u8 * wpas_populate_assoc_ies(
#endif /* CONFIG_P2P */
if (bss) {
- wpa_ie_len += wpas_supp_op_class_ie(wpa_s, ssid, bss->freq,
+ wpa_ie_len += wpas_supp_op_class_ie(wpa_s, ssid, bss,
wpa_ie + wpa_ie_len,
max_wpa_ie_len -
wpa_ie_len);
@@ -2815,7 +3209,7 @@ static u8 * wpas_populate_assoc_ies(
#ifdef CONFIG_MBO
mbo_ie = bss ? wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE) : NULL;
- if (mbo_ie) {
+ if (!wpa_s->disable_mbo_oce && mbo_ie) {
int len;
len = wpas_mbo_ie(wpa_s, wpa_ie + wpa_ie_len,
@@ -2876,8 +3270,16 @@ static u8 * wpas_populate_assoc_ies(
#endif /* CONFIG_OWE */
#ifdef CONFIG_DPP2
- if (wpa_sm_get_key_mgmt(wpa_s->wpa) == WPA_KEY_MGMT_DPP &&
- ssid->dpp_netaccesskey) {
+ if (DPP_VERSION > 1 &&
+ wpa_sm_get_key_mgmt(wpa_s->wpa) == WPA_KEY_MGMT_DPP &&
+ ssid->dpp_netaccesskey &&
+ ssid->dpp_pfs != 2 && !ssid->dpp_pfs_fallback) {
+ struct rsn_pmksa_cache_entry *pmksa;
+
+ pmksa = pmksa_cache_get_current(wpa_s->wpa);
+ if (!pmksa || !pmksa->dpp_pfs)
+ goto pfs_fail;
+
dpp_pfs_free(wpa_s->dpp_pfs);
wpa_s->dpp_pfs = dpp_pfs_init(ssid->dpp_netaccesskey,
ssid->dpp_netaccesskey_len);
@@ -2930,6 +3332,61 @@ pfs_fail:
}
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->rsnxe_override_assoc &&
+ wpabuf_len(wpa_s->rsnxe_override_assoc) <=
+ max_wpa_ie_len - wpa_ie_len) {
+ wpa_printf(MSG_DEBUG, "TESTING: RSNXE AssocReq override");
+ os_memcpy(wpa_ie + wpa_ie_len,
+ wpabuf_head(wpa_s->rsnxe_override_assoc),
+ wpabuf_len(wpa_s->rsnxe_override_assoc));
+ wpa_ie_len += wpabuf_len(wpa_s->rsnxe_override_assoc);
+ } else
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (wpa_s->rsnxe_len > 0 &&
+ wpa_s->rsnxe_len <= max_wpa_ie_len - wpa_ie_len) {
+ os_memcpy(wpa_ie + wpa_ie_len, wpa_s->rsnxe, wpa_s->rsnxe_len);
+ wpa_ie_len += wpa_s->rsnxe_len;
+ }
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->disable_mscs_support)
+ goto mscs_end;
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_MSCS) &&
+ wpa_s->robust_av.valid_config) {
+ struct wpabuf *mscs_ie;
+ size_t mscs_ie_len, buf_len;
+
+ buf_len = 3 + /* MSCS descriptor IE header */
+ 1 + /* Request type */
+ 2 + /* User priority control */
+ 4 + /* Stream timeout */
+ 3 + /* TCLAS Mask IE header */
+ wpa_s->robust_av.frame_classifier_len;
+ mscs_ie = wpabuf_alloc(buf_len);
+ if (!mscs_ie) {
+ wpa_printf(MSG_INFO,
+ "MSCS: Failed to allocate MSCS IE");
+ goto mscs_end;
+ }
+
+ wpas_populate_mscs_descriptor_ie(&wpa_s->robust_av, mscs_ie);
+ if ((wpa_ie_len + wpabuf_len(mscs_ie)) <= max_wpa_ie_len) {
+ wpa_hexdump_buf(MSG_MSGDUMP, "MSCS IE", mscs_ie);
+ mscs_ie_len = wpabuf_len(mscs_ie);
+ os_memcpy(wpa_ie + wpa_ie_len, wpabuf_head(mscs_ie),
+ mscs_ie_len);
+ wpa_ie_len += mscs_ie_len;
+ }
+
+ wpabuf_free(mscs_ie);
+ }
+mscs_end:
+
+ wpa_ie_len = wpas_populate_wfa_capa(wpa_s, bss, wpa_ie, wpa_ie_len,
+ max_wpa_ie_len);
+
if (ssid->multi_ap_backhaul_sta) {
size_t multi_ap_ie_len;
@@ -2955,6 +3412,24 @@ pfs_fail:
}
+#ifdef CONFIG_OWE
+static void wpas_update_owe_connect_params(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_driver_associate_params params;
+ u8 *wpa_ie;
+
+ os_memset(&params, 0, sizeof(params));
+ wpa_ie = wpas_populate_assoc_ies(wpa_s, wpa_s->current_bss,
+ wpa_s->current_ssid, &params, NULL);
+ if (!wpa_ie)
+ return;
+
+ wpa_drv_update_connect_params(wpa_s, &params, WPA_DRV_UPDATE_ASSOC_IES);
+ os_free(wpa_ie);
+}
+#endif /* CONFIG_OWE */
+
+
#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s)
{
@@ -2971,18 +3446,127 @@ static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s)
if (!wpa_ie)
return;
- if (params.auth_alg != WPA_AUTH_ALG_FILS) {
- os_free(wpa_ie);
- return;
+ if (params.auth_alg == WPA_AUTH_ALG_FILS) {
+ wpa_s->auth_alg = params.auth_alg;
+ wpa_drv_update_connect_params(wpa_s, &params, mask);
}
- wpa_s->auth_alg = params.auth_alg;
- wpa_drv_update_connect_params(wpa_s, &params, mask);
os_free(wpa_ie);
}
#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
+static u8 wpa_ie_get_edmg_oper_chans(const u8 *edmg_ie)
+{
+ if (!edmg_ie || edmg_ie[1] < 6)
+ return 0;
+ return edmg_ie[EDMG_BSS_OPERATING_CHANNELS_OFFSET];
+}
+
+
+static u8 wpa_ie_get_edmg_oper_chan_width(const u8 *edmg_ie)
+{
+ if (!edmg_ie || edmg_ie[1] < 6)
+ return 0;
+ return edmg_ie[EDMG_OPERATING_CHANNEL_WIDTH_OFFSET];
+}
+
+
+/* Returns the intersection of two EDMG configurations.
+ * Note: The current implementation is limited to CB2 only (CB1 included),
+ * i.e., the implementation supports up to 2 contiguous channels.
+ * For supporting non-contiguous (aggregated) channels and for supporting
+ * CB3 and above, this function will need to be extended.
+ */
+static struct ieee80211_edmg_config
+get_edmg_intersection(struct ieee80211_edmg_config a,
+ struct ieee80211_edmg_config b,
+ u8 primary_channel)
+{
+ struct ieee80211_edmg_config result;
+ int i, contiguous = 0;
+ int max_contiguous = 0;
+
+ result.channels = b.channels & a.channels;
+ if (!result.channels) {
+ wpa_printf(MSG_DEBUG,
+ "EDMG not possible: cannot intersect channels 0x%x and 0x%x",
+ a.channels, b.channels);
+ goto fail;
+ }
+
+ if (!(result.channels & BIT(primary_channel - 1))) {
+ wpa_printf(MSG_DEBUG,
+ "EDMG not possible: the primary channel %d is not one of the intersected channels 0x%x",
+ primary_channel, result.channels);
+ goto fail;
+ }
+
+ /* Find max contiguous channels */
+ for (i = 0; i < 6; i++) {
+ if (result.channels & BIT(i))
+ contiguous++;
+ else
+ contiguous = 0;
+
+ if (contiguous > max_contiguous)
+ max_contiguous = contiguous;
+ }
+
+ /* Assuming AP and STA supports ONLY contiguous channels,
+ * bw configuration can have value between 4-7.
+ */
+ if ((b.bw_config < a.bw_config))
+ result.bw_config = b.bw_config;
+ else
+ result.bw_config = a.bw_config;
+
+ if ((max_contiguous >= 2 && result.bw_config < EDMG_BW_CONFIG_5) ||
+ (max_contiguous >= 1 && result.bw_config < EDMG_BW_CONFIG_4)) {
+ wpa_printf(MSG_DEBUG,
+ "EDMG not possible: not enough contiguous channels %d for supporting CB1 or CB2",
+ max_contiguous);
+ goto fail;
+ }
+
+ return result;
+
+fail:
+ result.channels = 0;
+ result.bw_config = 0;
+ return result;
+}
+
+
+static struct ieee80211_edmg_config
+get_supported_edmg(struct wpa_supplicant *wpa_s,
+ struct hostapd_freq_params *freq,
+ struct ieee80211_edmg_config request_edmg)
+{
+ enum hostapd_hw_mode hw_mode;
+ struct hostapd_hw_modes *mode = NULL;
+ u8 primary_channel;
+
+ if (!wpa_s->hw.modes)
+ goto fail;
+
+ hw_mode = ieee80211_freq_to_chan(freq->freq, &primary_channel);
+ if (hw_mode == NUM_HOSTAPD_MODES)
+ goto fail;
+
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, hw_mode, false);
+ if (!mode)
+ goto fail;
+
+ return get_edmg_intersection(mode->edmg, request_edmg, primary_channel);
+
+fail:
+ request_edmg.channels = 0;
+ request_edmg.bw_config = 0;
+ return request_edmg;
+}
+
+
#ifdef CONFIG_MBO
void wpas_update_mbo_connect_params(struct wpa_supplicant *wpa_s)
{
@@ -3018,10 +3602,13 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
struct wpa_ssid *ssid = cwork->ssid;
struct wpa_supplicant *wpa_s = work->wpa_s;
u8 *wpa_ie;
- int use_crypt, ret, i, bssid_changed;
+ const u8 *edmg_ie_oper;
+ int use_crypt, ret, bssid_changed;
unsigned int cipher_pairwise, cipher_group, cipher_group_mgmt;
struct wpa_driver_associate_params params;
+#if defined(CONFIG_WEP) || defined(IEEE8021X_EAPOL)
int wep_keys_set = 0;
+#endif /* CONFIG_WEP || IEEE8021X_EAPOL */
int assoc_failed = 0;
struct wpa_ssid *old_ssid;
u8 prev_bssid[ETH_ALEN];
@@ -3034,6 +3621,11 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
struct ieee80211_vht_capabilities vhtcaps_mask;
#endif /* CONFIG_VHT_OVERRIDES */
+ wpa_s->roam_in_progress = false;
+#ifdef CONFIG_WNM
+ wpa_s->bss_trans_mgmt_in_progress = false;
+#endif /* CONFIG_WNM */
+
if (deinit) {
if (work->started) {
wpa_s->connect_work = NULL;
@@ -3059,6 +3651,20 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
os_memset(&params, 0, sizeof(params));
wpa_s->reassociate = 0;
wpa_s->eap_expected_failure = 0;
+
+ /* Starting new association, so clear the possibly used WPA IE from the
+ * previous association. */
+ wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
+ wpa_s->rsnxe_len = 0;
+ wpa_s->mscs_setup_done = false;
+
+ wpa_ie = wpas_populate_assoc_ies(wpa_s, bss, ssid, &params, NULL);
+ if (!wpa_ie) {
+ wpas_connect_work_done(wpa_s);
+ return;
+ }
+
if (bss &&
(!wpas_driver_bss_selection(wpa_s) || wpas_wps_searching(wpa_s))) {
#ifdef CONFIG_IEEE80211R
@@ -3092,6 +3698,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
wpa_s->scan_req = MANUAL_SCAN_REQ;
wpa_s->reassociate = 1;
wpa_supplicant_req_scan(wpa_s, 0, 0);
+ os_free(wpa_ie);
return;
#endif /* CONFIG_WPS */
} else {
@@ -3107,16 +3714,6 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
wpa_supplicant_cancel_scan(wpa_s);
- /* Starting new association, so clear the possibly used WPA IE from the
- * previous association. */
- wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
-
- wpa_ie = wpas_populate_assoc_ies(wpa_s, bss, ssid, &params, NULL);
- if (!wpa_ie) {
- wpas_connect_work_done(wpa_s);
- return;
- }
-
wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
use_crypt = 1;
cipher_pairwise = wpa_s->pairwise_cipher;
@@ -3126,10 +3723,12 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE)
use_crypt = 0;
+#ifdef CONFIG_WEP
if (wpa_set_wep_keys(wpa_s, ssid)) {
use_crypt = 1;
wep_keys_set = 1;
}
+#endif /* CONFIG_WEP */
}
if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS)
use_crypt = 0;
@@ -3201,6 +3800,71 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
params.beacon_int = wpa_s->conf->beacon_int;
}
+ if (bss && ssid->enable_edmg)
+ edmg_ie_oper = wpa_bss_get_ie_ext(bss,
+ WLAN_EID_EXT_EDMG_OPERATION);
+ else
+ edmg_ie_oper = NULL;
+
+ if (edmg_ie_oper) {
+ params.freq.edmg.channels =
+ wpa_ie_get_edmg_oper_chans(edmg_ie_oper);
+ params.freq.edmg.bw_config =
+ wpa_ie_get_edmg_oper_chan_width(edmg_ie_oper);
+ wpa_printf(MSG_DEBUG,
+ "AP supports EDMG channels 0x%x, bw_config %d",
+ params.freq.edmg.channels,
+ params.freq.edmg.bw_config);
+
+ /* User may ask for specific EDMG channel for EDMG connection
+ * (must be supported by AP)
+ */
+ if (ssid->edmg_channel) {
+ struct ieee80211_edmg_config configured_edmg;
+ enum hostapd_hw_mode hw_mode;
+ u8 primary_channel;
+
+ hw_mode = ieee80211_freq_to_chan(bss->freq,
+ &primary_channel);
+ if (hw_mode == NUM_HOSTAPD_MODES)
+ goto edmg_fail;
+
+ hostapd_encode_edmg_chan(ssid->enable_edmg,
+ ssid->edmg_channel,
+ primary_channel,
+ &configured_edmg);
+
+ if (ieee802_edmg_is_allowed(params.freq.edmg,
+ configured_edmg)) {
+ params.freq.edmg = configured_edmg;
+ wpa_printf(MSG_DEBUG,
+ "Use EDMG channel %d for connection",
+ ssid->edmg_channel);
+ } else {
+ edmg_fail:
+ params.freq.edmg.channels = 0;
+ params.freq.edmg.bw_config = 0;
+ wpa_printf(MSG_WARNING,
+ "EDMG channel %d not supported by AP, fallback to DMG",
+ ssid->edmg_channel);
+ }
+ }
+
+ if (params.freq.edmg.channels) {
+ wpa_printf(MSG_DEBUG,
+ "EDMG before: channels 0x%x, bw_config %d",
+ params.freq.edmg.channels,
+ params.freq.edmg.bw_config);
+ params.freq.edmg = get_supported_edmg(wpa_s,
+ &params.freq,
+ params.freq.edmg);
+ wpa_printf(MSG_DEBUG,
+ "EDMG after: channels 0x%x, bw_config %d",
+ params.freq.edmg.channels,
+ params.freq.edmg.bw_config);
+ }
+ }
+
params.pairwise_suite = cipher_pairwise;
params.group_suite = cipher_group;
params.mgmt_group_suite = cipher_group_mgmt;
@@ -3209,12 +3873,18 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
wpa_s->auth_alg = params.auth_alg;
params.mode = ssid->mode;
params.bg_scan_period = ssid->bg_scan_period;
- for (i = 0; i < NUM_WEP_KEYS; i++) {
- if (ssid->wep_key_len[i])
- params.wep_key[i] = ssid->wep_key[i];
- params.wep_key_len[i] = ssid->wep_key_len[i];
+#ifdef CONFIG_WEP
+ {
+ int i;
+
+ for (i = 0; i < NUM_WEP_KEYS; i++) {
+ if (ssid->wep_key_len[i])
+ params.wep_key[i] = ssid->wep_key[i];
+ params.wep_key_len[i] = ssid->wep_key_len[i];
+ }
+ params.wep_tx_keyidx = ssid->wep_tx_keyidx;
}
- params.wep_tx_keyidx = ssid->wep_tx_keyidx;
+#endif /* CONFIG_WEP */
if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) &&
(params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
@@ -3251,7 +3921,6 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
params.drop_unencrypted = use_crypt;
-#ifdef CONFIG_IEEE80211W
params.mgmt_frame_protection = wpas_get_ssid_pmf(wpa_s, ssid);
if (params.mgmt_frame_protection != NO_MGMT_FRAME_PROTECTION && bss) {
const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
@@ -3270,7 +3939,6 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
#endif /* CONFIG_OWE */
}
}
-#endif /* CONFIG_IEEE80211W */
params.p2p = ssid->p2p_group;
@@ -3293,6 +3961,9 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
params.vhtcaps_mask = &vhtcaps_mask;
wpa_supplicant_apply_vht_overrides(wpa_s, ssid, &params);
#endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_HE_OVERRIDES
+ wpa_supplicant_apply_he_overrides(wpa_s, ssid, &params);
+#endif /* CONFIG_HE_OVERRIDES */
#ifdef CONFIG_P2P
/*
@@ -3321,12 +3992,16 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
wpa_s->current_ssid)
params.prev_bssid = prev_bssid;
+#ifdef CONFIG_SAE
+ params.sae_pwe = wpa_s->conf->sae_pwe;
+#endif /* CONFIG_SAE */
+
ret = wpa_drv_associate(wpa_s, &params);
os_free(wpa_ie);
if (ret < 0) {
wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
"failed");
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SANE_ERROR_CODES) {
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_VALID_ERROR_CODES) {
/*
* The driver is known to mean what is saying, so we
* can stop right here; the association will not
@@ -3374,11 +4049,13 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0);
}
+#ifdef CONFIG_WEP
if (wep_keys_set &&
(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC)) {
/* Set static WEP keys again */
wpa_set_wep_keys(wpa_s, ssid);
}
+#endif /* CONFIG_WEP */
if (wpa_s->current_ssid && wpa_s->current_ssid != ssid) {
/*
@@ -3417,6 +4094,9 @@ static void wpa_supplicant_clear_connection(struct wpa_supplicant *wpa_s,
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
if (old_ssid != wpa_s->current_ssid)
wpas_notify_network_changed(wpa_s);
+
+ wpas_scs_deinit(wpa_s);
+ wpas_dscp_deinit(wpa_s);
eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
}
@@ -3475,7 +4155,7 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
wpa_s->ifname);
wpas_notify_mesh_group_removed(wpa_s, mconf->meshid,
mconf->meshid_len, reason_code);
- wpa_supplicant_leave_mesh(wpa_s);
+ wpa_supplicant_leave_mesh(wpa_s, true);
}
#endif /* CONFIG_MESH */
@@ -3492,6 +4172,15 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
wpa_supplicant_clear_connection(wpa_s, addr);
}
+
+void wpa_supplicant_reconnect(struct wpa_supplicant *wpa_s)
+{
+ wpa_s->own_reconnect_req = 1;
+ wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_UNSPECIFIED);
+
+}
+
+
static void wpa_supplicant_enable_one_network(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
@@ -3602,6 +4291,52 @@ int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id)
/**
+ * wpa_supplicant_remove_all_networks - Remove all configured networks
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: 0 on success (errors are currently ignored)
+ *
+ * This function performs the following operations:
+ * 1. Remove all networks.
+ * 2. Send network removal notifications.
+ * 3. Update internal state machines.
+ * 4. Stop any running sched scans.
+ */
+int wpa_supplicant_remove_all_networks(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_ssid *ssid;
+
+ if (wpa_s->sched_scanning)
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+
+ eapol_sm_invalidate_cached_session(wpa_s->eapol);
+ if (wpa_s->current_ssid) {
+#ifdef CONFIG_SME
+ wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+ wpa_sm_set_config(wpa_s->wpa, NULL);
+ eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+ if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
+ wpa_s->own_disconnect_req = 1;
+ wpa_supplicant_deauthenticate(
+ wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ }
+ ssid = wpa_s->conf->ssid;
+ while (ssid) {
+ struct wpa_ssid *remove_ssid = ssid;
+ int id;
+
+ id = ssid->id;
+ ssid = ssid->next;
+ if (wpa_s->last_ssid == remove_ssid)
+ wpa_s->last_ssid = NULL;
+ wpas_notify_network_removed(wpa_s, remove_ssid);
+ wpa_config_remove_network(wpa_s->conf, id);
+ }
+ return 0;
+}
+
+
+/**
* wpa_supplicant_enable_network - Mark a configured network as enabled
* @wpa_s: wpa_supplicant structure for a network interface
* @ssid: wpa_ssid structure for a configured network or %NULL
@@ -3763,9 +4498,12 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
+ wpa_s_clear_sae_rejected(wpa_s);
wpa_s->last_owe_group = 0;
- if (ssid)
+ if (ssid) {
ssid->owe_transition_bss_select_count = 0;
+ wpa_s_setup_sae_pt(wpa_s->conf, ssid);
+ }
if (wpa_s->connect_without_scan ||
wpa_supplicant_fast_associate(wpa_s) != 1) {
@@ -3780,6 +4518,82 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
/**
+ * wpas_remove_cred - Remove the specified credential and all the network
+ * entries created based on the removed credential
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @cred: The credential to remove
+ * Returns: 0 on success, -1 on failure
+ */
+int wpas_remove_cred(struct wpa_supplicant *wpa_s, struct wpa_cred *cred)
+{
+ struct wpa_ssid *ssid, *next;
+ int id;
+
+ if (!cred) {
+ wpa_printf(MSG_DEBUG, "Could not find cred");
+ return -1;
+ }
+
+ id = cred->id;
+ if (wpa_config_remove_cred(wpa_s->conf, id) < 0) {
+ wpa_printf(MSG_DEBUG, "Could not find cred %d", id);
+ return -1;
+ }
+
+ wpa_msg(wpa_s, MSG_INFO, CRED_REMOVED "%d", id);
+
+ /* Remove any network entry created based on the removed credential */
+ ssid = wpa_s->conf->ssid;
+ while (ssid) {
+ next = ssid->next;
+
+ if (ssid->parent_cred == cred) {
+ wpa_printf(MSG_DEBUG,
+ "Remove network id %d since it used the removed credential",
+ ssid->id);
+ if (wpa_supplicant_remove_network(wpa_s, ssid->id) ==
+ -1) {
+ wpa_printf(MSG_DEBUG,
+ "Could not find network id=%d",
+ ssid->id);
+ }
+ }
+
+ ssid = next;
+ }
+
+ return 0;
+}
+
+
+/**
+ * wpas_remove_cred - Remove all the Interworking credentials
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: 0 on success, -1 on failure
+ */
+int wpas_remove_all_creds(struct wpa_supplicant *wpa_s)
+{
+ int res, ret = 0;
+ struct wpa_cred *cred, *prev;
+
+ cred = wpa_s->conf->cred;
+ while (cred) {
+ prev = cred;
+ cred = cred->next;
+ res = wpas_remove_cred(wpa_s, prev);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG,
+ "Removal of all credentials failed - failed to remove credential id=%d",
+ prev->id);
+ ret = -1;
+ }
+ }
+
+ return ret;
+}
+
+
+/**
* wpas_set_pkcs11_engine_and_module_path - Set PKCS #11 engine and module path
* @wpa_s: wpa_supplicant structure for a network interface
* @pkcs11_engine_path: PKCS #11 engine path or NULL
@@ -4126,8 +4940,13 @@ static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
}
if (name == NULL) {
- /* default to first driver in the list */
- return select_driver(wpa_s, 0);
+ /* Default to first successful driver in the list */
+ for (i = 0; wpa_drivers[i]; i++) {
+ if (select_driver(wpa_s, i) == 0)
+ return 0;
+ }
+ /* Drivers have each reported failure, so no wpa_msg() here. */
+ return -1;
}
do {
@@ -4177,7 +4996,15 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
+ if (wpa_s->own_disconnect_req) {
+ wpa_printf(MSG_DEBUG,
+ "Drop received EAPOL frame as we are disconnecting");
+ return;
+ }
+
#ifdef CONFIG_TESTING_OPTIONS
+ wpa_msg_ctrl(wpa_s, MSG_INFO, "EAPOL-RX " MACSTR " %zu",
+ MAC2STR(src_addr), len);
if (wpa_s->ignore_auth_resp) {
wpa_printf(MSG_INFO, "RX EAPOL - ignore_auth_resp active!");
return;
@@ -4303,16 +5130,23 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);
else if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
/*
- * Set portValid = TRUE here since we are going to skip 4-way
+ * Set portValid = true here since we are going to skip 4-way
* handshake processing which would normally set portValid. We
* need this to allow the EAPOL state machines to be completed
* without going through EAPOL-Key handshake.
*/
- eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
+ eapol_sm_notify_portValid(wpa_s->eapol, true);
}
}
+static int wpas_eapol_needs_l2_packet(struct wpa_supplicant *wpa_s)
+{
+ return !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_CONTROL_PORT) ||
+ !(wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX);
+}
+
+
int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
{
if ((!wpa_s->p2p_mgmt ||
@@ -4322,7 +5156,9 @@ int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
wpa_s->l2 = l2_packet_init(wpa_s->ifname,
wpa_drv_get_mac_addr(wpa_s),
ETH_P_EAPOL,
- wpa_supplicant_rx_eapol, wpa_s, 0);
+ wpas_eapol_needs_l2_packet(wpa_s) ?
+ wpa_supplicant_rx_eapol : NULL,
+ wpa_s, 0);
if (wpa_s->l2 == NULL)
return -1;
@@ -4330,18 +5166,25 @@ int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
L2_PACKET_FILTER_PKTTYPE))
wpa_dbg(wpa_s, MSG_DEBUG,
"Failed to attach pkt_type filter");
+
+ if (l2_packet_get_own_addr(wpa_s->l2, wpa_s->own_addr)) {
+ wpa_msg(wpa_s, MSG_ERROR,
+ "Failed to get own L2 address");
+ return -1;
+ }
} else {
const u8 *addr = wpa_drv_get_mac_addr(wpa_s);
if (addr)
os_memcpy(wpa_s->own_addr, addr, ETH_ALEN);
}
- if (wpa_s->l2 && l2_packet_get_own_addr(wpa_s->l2, wpa_s->own_addr)) {
- wpa_msg(wpa_s, MSG_ERROR, "Failed to get own L2 address");
- return -1;
- }
-
wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
+ wpas_wps_update_mac_addr(wpa_s);
+
+#ifdef CONFIG_FST
+ if (wpa_s->fst)
+ fst_update_mac_addr(wpa_s->fst, wpa_s->own_addr);
+#endif /* CONFIG_FST */
return 0;
}
@@ -4372,6 +5215,65 @@ static void wpa_supplicant_rx_eapol_bridge(void *ctx, const u8 *src_addr,
}
+int wpa_supplicant_update_bridge_ifname(struct wpa_supplicant *wpa_s,
+ const char *bridge_ifname)
+{
+ if (wpa_s->wpa_state > WPA_SCANNING)
+ return -EBUSY;
+
+ if (bridge_ifname &&
+ os_strlen(bridge_ifname) >= sizeof(wpa_s->bridge_ifname))
+ return -EINVAL;
+
+ if (!bridge_ifname)
+ bridge_ifname = "";
+
+ if (os_strcmp(wpa_s->bridge_ifname, bridge_ifname) == 0)
+ return 0;
+
+ if (wpa_s->l2_br) {
+ l2_packet_deinit(wpa_s->l2_br);
+ wpa_s->l2_br = NULL;
+ }
+
+ os_strlcpy(wpa_s->bridge_ifname, bridge_ifname,
+ sizeof(wpa_s->bridge_ifname));
+
+ if (wpa_s->bridge_ifname[0]) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Receiving packets from bridge interface '%s'",
+ wpa_s->bridge_ifname);
+ wpa_s->l2_br = l2_packet_init_bridge(
+ wpa_s->bridge_ifname, wpa_s->ifname, wpa_s->own_addr,
+ ETH_P_EAPOL, wpa_supplicant_rx_eapol_bridge, wpa_s, 1);
+ if (!wpa_s->l2_br) {
+ wpa_msg(wpa_s, MSG_ERROR,
+ "Failed to open l2_packet connection for the bridge interface '%s'",
+ wpa_s->bridge_ifname);
+ goto fail;
+ }
+ }
+
+#ifdef CONFIG_TDLS
+ if (!wpa_s->p2p_mgmt && wpa_tdls_init(wpa_s->wpa))
+ goto fail;
+#endif /* CONFIG_TDLS */
+
+ return 0;
+fail:
+ wpa_s->bridge_ifname[0] = 0;
+ if (wpa_s->l2_br) {
+ l2_packet_deinit(wpa_s->l2_br);
+ wpa_s->l2_br = NULL;
+ }
+#ifdef CONFIG_TDLS
+ if (!wpa_s->p2p_mgmt)
+ wpa_tdls_init(wpa_s->wpa);
+#endif /* CONFIG_TDLS */
+ return -EIO;
+}
+
+
/**
* wpa_supplicant_driver_init - Initialize driver interface parameters
* @wpa_s: Pointer to wpa_supplicant data
@@ -4393,7 +5295,7 @@ int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
os_memcpy(wpa_s->perm_addr, wpa_s->own_addr, ETH_ALEN);
wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
- if (wpa_s->bridge_ifname[0]) {
+ if (wpa_s->bridge_ifname[0] && wpas_eapol_needs_l2_packet(wpa_s)) {
wpa_dbg(wpa_s, MSG_DEBUG, "Receiving packets from bridge "
"interface '%s'", wpa_s->bridge_ifname);
wpa_s->l2_br = l2_packet_init_bridge(
@@ -4467,9 +5369,14 @@ wpa_supplicant_alloc(struct wpa_supplicant *parent)
wpa_s->parent = parent ? parent : wpa_s;
wpa_s->p2pdev = wpa_s->parent;
wpa_s->sched_scanning = 0;
+ wpa_s->setband_mask = WPA_SETBAND_AUTO;
dl_list_init(&wpa_s->bss_tmp_disallowed);
dl_list_init(&wpa_s->fils_hlp_req);
+#ifdef CONFIG_TESTING_OPTIONS
+ dl_list_init(&wpa_s->drv_signal_override);
+#endif /* CONFIG_TESTING_OPTIONS */
+ dl_list_init(&wpa_s->active_scs_ids);
return wpa_s;
}
@@ -4832,6 +5739,19 @@ void wpa_supplicant_apply_vht_overrides(
#endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_HE_OVERRIDES
+void wpa_supplicant_apply_he_overrides(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ struct wpa_driver_associate_params *params)
+{
+ if (!ssid)
+ return;
+
+ params->disable_he = ssid->disable_he;
+}
+#endif /* CONFIG_HE_OVERRIDES */
+
+
static int pcsc_reader_init(struct wpa_supplicant *wpa_s)
{
#ifdef PCSC_FUNCS
@@ -4995,7 +5915,7 @@ static void wpas_fst_update_mb_ie_cb(void *ctx, const u8 *addr,
static const u8 * wpas_fst_get_peer_first(void *ctx,
struct fst_get_peer_ctx **get_ctx,
- Boolean mb_only)
+ bool mb_only)
{
struct wpa_supplicant *wpa_s = ctx;
@@ -5009,7 +5929,7 @@ static const u8 * wpas_fst_get_peer_first(void *ctx,
static const u8 * wpas_fst_get_peer_next(void *ctx,
struct fst_get_peer_ctx **get_ctx,
- Boolean mb_only)
+ bool mb_only)
{
return NULL;
}
@@ -5195,7 +6115,7 @@ static struct wpa_radio_work * radio_work_get_next_work(struct wpa_radio *radio)
dl_list_for_each(tmp, &radio->work, struct wpa_radio_work,
list) {
if (os_strcmp(tmp->type, "scan") == 0 &&
- radio->external_scan_running &&
+ external_scan_running(radio) &&
(((struct wpa_driver_scan_params *)
tmp->ctx)->only_new_results ||
tmp->wpa_s->clear_driver_scan_cache))
@@ -5251,7 +6171,7 @@ static struct wpa_radio_work * radio_work_get_next_work(struct wpa_radio *radio)
* rejected by kernel.
*/
if (os_strcmp(tmp->type, "scan") == 0 &&
- radio->external_scan_running &&
+ external_scan_running(radio) &&
(((struct wpa_driver_scan_params *)
tmp->ctx)->only_new_results ||
tmp->wpa_s->clear_driver_scan_cache))
@@ -5290,7 +6210,7 @@ static void radio_start_next_work(void *eloop_ctx, void *timeout_ctx)
if (work->started)
return; /* already started and still in progress */
- if (wpa_s && wpa_s->radio->external_scan_running) {
+ if (wpa_s && external_scan_running(wpa_s->radio)) {
wpa_printf(MSG_DEBUG, "Delay radio work start until externally triggered scan completes");
return;
}
@@ -5386,6 +6306,10 @@ static void radio_remove_interface(struct wpa_supplicant *wpa_s)
wpa_s->ifname, radio->name);
dl_list_del(&wpa_s->radio_list);
radio_remove_works(wpa_s, NULL, 0);
+ /* If the interface that triggered the external scan was removed, the
+ * external scan is no longer running. */
+ if (wpa_s == radio->external_scan_req_interface)
+ radio->external_scan_req_interface = NULL;
wpa_s->radio = NULL;
if (!dl_list_empty(&radio->ifaces))
return; /* Interfaces remain for this radio */
@@ -5539,6 +6463,8 @@ next_driver:
wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname);
if (wpa_s->drv_priv == NULL) {
const char *pos;
+ int level = MSG_ERROR;
+
pos = driver ? os_strchr(driver, ',') : NULL;
if (pos) {
wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
@@ -5546,8 +6472,12 @@ next_driver:
driver = pos + 1;
goto next_driver;
}
- wpa_msg(wpa_s, MSG_ERROR, "Failed to initialize driver "
- "interface");
+
+#ifdef CONFIG_MATCH_IFACE
+ if (wpa_s->matched == WPA_IFACE_MATCHED_NULL)
+ level = MSG_DEBUG;
+#endif /* CONFIG_MATCH_IFACE */
+ wpa_msg(wpa_s, level, "Failed to initialize driver interface");
return -1;
}
if (wpa_drv_set_param(wpa_s, wpa_s->conf->driver_param) < 0) {
@@ -5692,6 +6622,9 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
return -1;
}
os_strlcpy(wpa_s->ifname, iface->ifname, sizeof(wpa_s->ifname));
+#ifdef CONFIG_MATCH_IFACE
+ wpa_s->matched = iface->matched;
+#endif /* CONFIG_MATCH_IFACE */
if (iface->bridge_ifname) {
if (os_strlen(iface->bridge_ifname) >=
@@ -5705,8 +6638,8 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
}
/* RSNA Supplicant Key Management - INITIALIZE */
- eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
- eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
+ eapol_sm_notify_portEnabled(wpa_s->eapol, false);
+ eapol_sm_notify_portValid(wpa_s->eapol, false);
/* Initialize driver interface and register driver event handler before
* L2 receive handler so that association events are processed before
@@ -5773,8 +6706,8 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
if (capa_res == 0) {
wpa_s->drv_capa_known = 1;
wpa_s->drv_flags = capa.flags;
+ wpa_s->drv_flags2 = capa.flags2;
wpa_s->drv_enc = capa.enc;
- wpa_s->drv_smps_modes = capa.smps_modes;
wpa_s->drv_rrm_flags = capa.rrm_flags;
wpa_s->probe_resp_offloads = capa.probe_resp_offloads;
wpa_s->max_scan_ssids = capa.max_scan_ssids;
@@ -5951,7 +6884,7 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
hs20_init(wpa_s);
#endif /* CONFIG_HS20 */
#ifdef CONFIG_MBO
- if (wpa_s->conf->oce) {
+ if (!wpa_s->disable_mbo_oce && 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;
@@ -5998,11 +6931,21 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
wpa_s->disconnected = 1;
if (wpa_s->drv_priv) {
- wpa_supplicant_deauthenticate(wpa_s,
- WLAN_REASON_DEAUTH_LEAVING);
+ /*
+ * Don't deauthenticate if WoWLAN is enable and not explicitly
+ * been configured to disconnect.
+ */
+ if (!wpa_drv_get_wowlan(wpa_s) ||
+ wpa_s->conf->wowlan_disconnect_on_deinit) {
+ wpa_supplicant_deauthenticate(
+ wpa_s, WLAN_REASON_DEAUTH_LEAVING);
- wpa_drv_set_countermeasures(wpa_s, 0);
- wpa_clear_keys(wpa_s, NULL);
+ wpa_drv_set_countermeasures(wpa_s, 0);
+ wpa_clear_keys(wpa_s, NULL);
+ } else {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Do not deauthenticate as part of interface deinit since WoWLAN is enabled");
+ }
}
wpa_supplicant_cleanup(wpa_s);
@@ -6031,14 +6974,12 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
if (terminate)
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TERMINATING);
- if (wpa_s->ctrl_iface) {
- wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
- wpa_s->ctrl_iface = NULL;
- }
+ wpa_supplicant_ctrl_iface_deinit(wpa_s, wpa_s->ctrl_iface);
+ wpa_s->ctrl_iface = NULL;
#ifdef CONFIG_MESH
if (wpa_s->ifmsh) {
- wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh);
+ wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh, true);
wpa_s->ifmsh = NULL;
}
#endif /* CONFIG_MESH */
@@ -6049,6 +6990,7 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
}
os_free(wpa_s->ssids_from_scan_req);
+ os_free(wpa_s->last_scan_freqs);
os_free(wpa_s);
}
@@ -6076,6 +7018,10 @@ struct wpa_interface * wpa_supplicant_match_iface(struct wpa_global *global,
if (!iface)
return NULL;
*iface = *miface;
+ if (!miface->ifname)
+ iface->matched = WPA_IFACE_MATCHED_NULL;
+ else
+ iface->matched = WPA_IFACE_MATCHED;
iface->ifname = ifname;
return iface;
}
@@ -6108,10 +7054,8 @@ static int wpa_supplicant_match_existing(struct wpa_global *global)
continue;
iface = wpa_supplicant_match_iface(global, ifi->if_name);
if (iface) {
- wpa_s = wpa_supplicant_add_iface(global, iface, NULL);
+ wpa_supplicant_add_iface(global, iface, NULL);
os_free(iface);
- if (wpa_s)
- wpa_s->matched = 1;
}
}
@@ -6373,7 +7317,7 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
if (params->wpa_debug_file_path)
wpa_debug_open_file(params->wpa_debug_file_path);
- else
+ if (!params->wpa_debug_file_path && !params->wpa_debug_syslog)
wpa_debug_setup_stdout();
if (params->wpa_debug_syslog)
wpa_debug_open_syslog();
@@ -6441,7 +7385,7 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
wpa_debug_timestamp = global->params.wpa_debug_timestamp =
params->wpa_debug_timestamp;
- wpa_printf(MSG_DEBUG, "wpa_supplicant v" VERSION_STR);
+ wpa_printf(MSG_DEBUG, "wpa_supplicant v%s", VERSION_STR);
if (eloop_init()) {
wpa_printf(MSG_ERROR, "Failed to initialize event loop");
@@ -6632,6 +7576,18 @@ void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s)
if (wpa_s->conf->changed_parameters & CFG_CHANGED_DISABLE_BTM)
wpa_supplicant_set_default_scan_ies(wpa_s);
+#ifdef CONFIG_BGSCAN
+ /*
+ * We default to global bgscan parameters only when per-network bgscan
+ * parameters aren't set. Only bother resetting bgscan parameters if
+ * this is the case.
+ */
+ if ((wpa_s->conf->changed_parameters & CFG_CHANGED_BGSCAN) &&
+ wpa_s->current_ssid && !wpa_s->current_ssid->bgscan &&
+ wpa_s->wpa_state == WPA_COMPLETED)
+ wpa_supplicant_reset_bgscan(wpa_s);
+#endif /* CONFIG_BGSCAN */
+
#ifdef CONFIG_WPS
wpas_wps_update_config(wpa_s);
#endif /* CONFIG_WPS */
@@ -6672,7 +7628,7 @@ static int * get_bss_freqs_in_ess(struct wpa_supplicant *wpa_s)
continue;
if (bss->ssid_len == cbss->ssid_len &&
os_memcmp(bss->ssid, cbss->ssid, bss->ssid_len) == 0 &&
- wpa_blacklist_get(wpa_s, bss->bssid) == NULL) {
+ !wpa_bssid_ignore_is_listed(wpa_s, bss->bssid)) {
add_freq(freqs, &num_freqs, bss->freq);
if (num_freqs == max_freqs)
break;
@@ -6702,10 +7658,10 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
/*
- * There is no point in blacklisting the AP if this event is
+ * There is no point in ignoring the AP temporarily if this event is
* generated based on local request to disconnect.
*/
- if (wpa_s->own_disconnect_req) {
+ if (wpa_s->own_disconnect_req || wpa_s->own_reconnect_req) {
wpa_s->own_disconnect_req = 0;
wpa_dbg(wpa_s, MSG_DEBUG,
"Ignore connection failure due to local request to disconnect");
@@ -6719,17 +7675,13 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
}
/*
- * Add the failed BSSID into the blacklist and speed up next scan
+ * Add the failed BSSID into the ignore list and speed up next scan
* attempt if there could be other APs that could accept association.
- * The current blacklist count indicates how many times we have tried
- * connecting to this AP and multiple attempts mean that other APs are
- * either not available or has already been tried, so that we can start
- * increasing the delay here to avoid constant scanning.
*/
- count = wpa_blacklist_add(wpa_s, bssid);
+ count = wpa_bssid_ignore_add(wpa_s, bssid);
if (count == 1 && wpa_s->current_bss) {
/*
- * This BSS was not in the blacklist before. If there is
+ * This BSS was not in the ignore list before. If there is
* another BSS available for the same ESS, we should try that
* next. Otherwise, we may as well try this one once more
* before allowing other, likely worse, ESSes to be considered.
@@ -6738,7 +7690,7 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
if (freqs) {
wpa_dbg(wpa_s, MSG_DEBUG, "Another BSS in this ESS "
"has been seen; try it next");
- wpa_blacklist_add(wpa_s, bssid);
+ wpa_bssid_ignore_add(wpa_s, bssid);
/*
* On the next scan, go through only the known channels
* used in this ESS based on previous scans to speed up
@@ -6749,19 +7701,19 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
}
}
- /*
- * Add previous failure count in case the temporary blacklist was
- * cleared due to no other BSSes being available.
- */
- count += wpa_s->extra_blacklist_count;
+ wpa_s->consecutive_conn_failures++;
- if (count > 3 && wpa_s->current_ssid) {
+ if (wpa_s->consecutive_conn_failures > 3 && wpa_s->current_ssid) {
wpa_printf(MSG_DEBUG, "Continuous association failures - "
"consider temporary network disabling");
wpas_auth_failed(wpa_s, "CONN_FAILED");
}
-
- switch (count) {
+ /*
+ * Multiple consecutive connection failures mean that other APs are
+ * either not available or have already been tried, so we can start
+ * increasing the delay here to avoid constant scanning.
+ */
+ switch (wpa_s->consecutive_conn_failures) {
case 1:
timeout = 100;
break;
@@ -6779,8 +7731,9 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
break;
}
- wpa_dbg(wpa_s, MSG_DEBUG, "Blacklist count %d --> request scan in %d "
- "ms", count, timeout);
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Consecutive connection failures: %d --> request scan in %d ms",
+ wpa_s->consecutive_conn_failures, timeout);
/*
* TODO: if more than one possible AP is available in scan results,
@@ -6795,6 +7748,46 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
#ifdef CONFIG_FILS
+
+void fils_pmksa_cache_flush(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ const u8 *realm, *username, *rrk;
+ size_t realm_len, username_len, rrk_len;
+ u16 next_seq_num;
+
+ /* Clear the PMKSA cache entry if FILS authentication was rejected.
+ * Check for ERP keys existing to limit when this can be done since
+ * the rejection response is not protected and such triggers should
+ * really not allow internal state to be modified unless required to
+ * avoid significant issues in functionality. In addition, drop
+ * externally configure PMKSA entries even without ERP keys since it
+ * is possible for an external component to add PMKSA entries for FILS
+ * authentication without restoring previously generated ERP keys.
+ *
+ * In this case, this is needed to allow recovery from cases where the
+ * AP or authentication server has dropped PMKSAs and ERP keys. */
+ if (!ssid || !ssid->eap.erp || !wpa_key_mgmt_fils(ssid->key_mgmt))
+ return;
+
+ if (eapol_sm_get_erp_info(wpa_s->eapol, &ssid->eap,
+ &username, &username_len,
+ &realm, &realm_len, &next_seq_num,
+ &rrk, &rrk_len) != 0 ||
+ !realm) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "FILS: Drop external PMKSA cache entry");
+ wpa_sm_aborted_external_cached(wpa_s->wpa);
+ wpa_sm_external_pmksa_cache_flush(wpa_s->wpa, ssid);
+ return;
+ }
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "FILS: Drop PMKSA cache entry");
+ wpa_sm_aborted_cached(wpa_s->wpa);
+ wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
+}
+
+
void fils_connection_failure(struct wpa_supplicant *wpa_s)
{
struct wpa_ssid *ssid = wpa_s->current_ssid;
@@ -6869,8 +7862,8 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
wpa_s->reassociate = 1;
break;
case WPA_CTRL_REQ_EAP_PIN:
- str_clear_free(eap->pin);
- eap->pin = os_strdup(value);
+ str_clear_free(eap->cert.pin);
+ eap->cert.pin = os_strdup(value);
eap->pending_req_pin = 0;
if (ssid == wpa_s->current_ssid)
wpa_s->reassociate = 1;
@@ -6884,8 +7877,8 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
eap->pending_req_otp_len = 0;
break;
case WPA_CTRL_REQ_EAP_PASSPHRASE:
- str_clear_free(eap->private_key_passwd);
- eap->private_key_passwd = os_strdup(value);
+ str_clear_free(eap->cert.private_key_passwd);
+ eap->cert.private_key_passwd = os_strdup(value);
eap->pending_req_passphrase = 0;
if (ssid == wpa_s->current_ssid)
wpa_s->reassociate = 1;
@@ -6930,8 +7923,10 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
{
+#ifdef CONFIG_WEP
int i;
unsigned int drv_enc;
+#endif /* CONFIG_WEP */
if (wpa_s->p2p_mgmt)
return 1; /* no normal network profiles on p2p_mgmt interface */
@@ -6942,6 +7937,7 @@ int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
if (ssid->disabled)
return 1;
+#ifdef CONFIG_WEP
if (wpa_s->drv_capa_known)
drv_enc = wpa_s->drv_enc;
else
@@ -6959,6 +7955,7 @@ int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
continue;
return 1; /* invalid WEP key */
}
+#endif /* CONFIG_WEP */
if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set &&
(!ssid->passphrase || ssid->ssid_len != 0) && !ssid->ext_psk &&
@@ -6972,7 +7969,6 @@ int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
{
-#ifdef CONFIG_IEEE80211W
if (ssid == NULL || ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT) {
if (wpa_s->conf->pmf == MGMT_FRAME_PROTECTION_OPTIONAL &&
!(wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_BIP)) {
@@ -7001,9 +7997,16 @@ int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
}
return ssid->ieee80211w;
-#else /* CONFIG_IEEE80211W */
- return NO_MGMT_FRAME_PROTECTION;
-#endif /* CONFIG_IEEE80211W */
+}
+
+
+int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr)
+{
+ if (wpa_s->current_ssid == NULL ||
+ wpa_s->wpa_state < WPA_4WAY_HANDSHAKE ||
+ os_memcmp(addr, wpa_s->bssid, ETH_ALEN) != 0)
+ return 0;
+ return wpa_sm_pmf_enabled(wpa_s->wpa);
}
@@ -7144,7 +8147,6 @@ void wpas_request_connection(struct wpa_supplicant *wpa_s)
wpa_s->normal_scans = 0;
wpa_s->scan_req = NORMAL_SCAN_REQ;
wpa_supplicant_reinit_autoscan(wpa_s);
- wpa_s->extra_blacklist_count = 0;
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
wpa_s->last_owe_group = 0;
@@ -7176,6 +8178,10 @@ void wpas_request_disconnection(struct wpa_supplicant *wpa_s)
eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
radio_remove_works(wpa_s, "connect", 0);
radio_remove_works(wpa_s, "sme-connect", 0);
+ wpa_s->roam_in_progress = false;
+#ifdef CONFIG_WNM
+ wpa_s->bss_trans_mgmt_in_progress = false;
+#endif /* CONFIG_WNM */
}
@@ -7360,12 +8366,20 @@ int wpas_vendor_elem_remove(struct wpa_supplicant *wpa_s, int frame,
struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
- u16 num_modes, enum hostapd_hw_mode mode)
+ u16 num_modes, enum hostapd_hw_mode mode,
+ bool is_6ghz)
{
u16 i;
+ if (!modes)
+ return NULL;
+
for (i = 0; i < num_modes; i++) {
- if (modes[i].mode == mode)
+ if (modes[i].mode != mode ||
+ !modes[i].num_channels || !modes[i].channels)
+ continue;
+ if ((!is_6ghz && !is_6ghz_freq(modes[i].channels[0].freq)) ||
+ (is_6ghz && is_6ghz_freq(modes[i].channels[0].freq)))
return &modes[i];
}
@@ -7373,6 +8387,22 @@ struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
}
+struct hostapd_hw_modes * get_mode_with_freq(struct hostapd_hw_modes *modes,
+ u16 num_modes, int freq)
+{
+ int i, j;
+
+ for (i = 0; i < num_modes; i++) {
+ for (j = 0; j < modes[i].num_channels; j++) {
+ if (freq == modes[i].channels[j].freq)
+ return &modes[i];
+ }
+ }
+
+ return NULL;
+}
+
+
static struct
wpa_bss_tmp_disallowed * wpas_get_disallowed_bss(struct wpa_supplicant *wpa_s,
const u8 *bssid)
@@ -7405,7 +8435,7 @@ static int wpa_set_driver_tmp_disallow_list(struct wpa_supplicant *wpa_s)
ETH_ALEN);
num_bssid++;
}
- ret = wpa_drv_set_bssid_blacklist(wpa_s, num_bssid, bssids);
+ ret = wpa_drv_set_bssid_tmp_disallow(wpa_s, num_bssid, bssids);
os_free(bssids);
return ret;
}
@@ -7420,8 +8450,7 @@ static void wpa_bss_tmp_disallow_timeout(void *eloop_ctx, void *timeout_ctx)
dl_list_for_each(tmp, &wpa_s->bss_tmp_disallowed,
struct wpa_bss_tmp_disallowed, list) {
if (bss == tmp) {
- dl_list_del(&tmp->list);
- os_free(tmp);
+ remove_bss_tmp_disallowed_entry(wpa_s, tmp);
wpa_set_driver_tmp_disallow_list(wpa_s);
break;
}
@@ -7474,8 +8503,11 @@ int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s,
return 0;
if (disallowed->rssi_threshold != 0 &&
- bss->level > disallowed->rssi_threshold)
+ bss->level > disallowed->rssi_threshold) {
+ remove_bss_tmp_disallowed_entry(wpa_s, disallowed);
+ wpa_set_driver_tmp_disallow_list(wpa_s);
return 0;
+ }
return 1;
}
@@ -7542,3 +8574,87 @@ int wpas_disable_mac_addr_randomization(struct wpa_supplicant *wpa_s,
return 0;
}
+
+
+int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s,
+ struct wpa_signal_info *si)
+{
+ int res;
+
+ if (!wpa_s->driver->signal_poll)
+ return -1;
+
+ res = wpa_s->driver->signal_poll(wpa_s->drv_priv, si);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (res == 0) {
+ struct driver_signal_override *dso;
+
+ dl_list_for_each(dso, &wpa_s->drv_signal_override,
+ struct driver_signal_override, list) {
+ if (os_memcmp(wpa_s->bssid, dso->bssid,
+ ETH_ALEN) != 0)
+ continue;
+ wpa_printf(MSG_DEBUG,
+ "Override driver signal_poll information: current_signal: %d->%d avg_signal: %d->%d avg_beacon_signal: %d->%d current_noise: %d->%d",
+ si->current_signal,
+ dso->si_current_signal,
+ si->avg_signal,
+ dso->si_avg_signal,
+ si->avg_beacon_signal,
+ dso->si_avg_beacon_signal,
+ si->current_noise,
+ dso->si_current_noise);
+ si->current_signal = dso->si_current_signal;
+ si->avg_signal = dso->si_avg_signal;
+ si->avg_beacon_signal = dso->si_avg_beacon_signal;
+ si->current_noise = dso->si_current_noise;
+ break;
+ }
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ return res;
+}
+
+
+struct wpa_scan_results *
+wpa_drv_get_scan_results2(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_scan_results *scan_res;
+#ifdef CONFIG_TESTING_OPTIONS
+ size_t idx;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (!wpa_s->driver->get_scan_results2)
+ return NULL;
+
+ scan_res = wpa_s->driver->get_scan_results2(wpa_s->drv_priv);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ for (idx = 0; scan_res && idx < scan_res->num; idx++) {
+ struct driver_signal_override *dso;
+ struct wpa_scan_res *res = scan_res->res[idx];
+
+ dl_list_for_each(dso, &wpa_s->drv_signal_override,
+ struct driver_signal_override, list) {
+ if (os_memcmp(res->bssid, dso->bssid, ETH_ALEN) != 0)
+ continue;
+ wpa_printf(MSG_DEBUG,
+ "Override driver scan signal level %d->%d for "
+ MACSTR,
+ res->level, dso->scan_level,
+ MAC2STR(res->bssid));
+ res->flags |= WPA_SCAN_QUAL_INVALID;
+ if (dso->scan_level < 0)
+ res->flags |= WPA_SCAN_LEVEL_DBM;
+ else
+ res->flags &= ~WPA_SCAN_LEVEL_DBM;
+ res->level = dso->scan_level;
+ break;
+ }
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ return scan_res;
+}