aboutsummaryrefslogtreecommitdiff
path: root/wpa_supplicant/wpa_supplicant.c
diff options
context:
space:
mode:
Diffstat (limited to 'wpa_supplicant/wpa_supplicant.c')
-rw-r--r--wpa_supplicant/wpa_supplicant.c1271
1 files changed, 899 insertions, 372 deletions
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 99af85e0..287bc9e6 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -17,6 +17,7 @@
#endif /* CONFIG_MATCH_IFACE */
#include "common.h"
+#include "crypto/crypto.h"
#include "crypto/random.h"
#include "crypto/sha1.h"
#include "eapol_supp/eapol_supp_sm.h"
@@ -68,6 +69,7 @@
#include "ap/ap_config.h"
#include "ap/hostapd.h"
#endif /* CONFIG_MESH */
+#include "aidl/aidl.h"
const char *const wpa_supplicant_version =
"wpa_supplicant v" VERSION_STR "\n"
@@ -142,7 +144,7 @@ int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
continue;
set = 1;
- wpa_drv_set_key(wpa_s, WPA_ALG_WEP, NULL,
+ wpa_drv_set_key(wpa_s, -1, WPA_ALG_WEP, NULL,
i, i == ssid->wep_tx_keyidx, NULL, 0,
ssid->wep_key[i], ssid->wep_key_len[i],
i == ssid->wep_tx_keyidx ?
@@ -206,7 +208,7 @@ 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, -1, alg, NULL, 0, 1, seq, 6, key, keylen,
KEY_FLAG_GROUP_RX_TX_DEFAULT);
os_memset(key, 0, sizeof(key));
return ret;
@@ -403,6 +405,7 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_WEP
int i;
#endif /* CONFIG_WEP */
+ struct wpa_sm_mlo mlo;
if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
wpa_s->key_mgmt = WPA_KEY_MGMT_WPS;
@@ -443,6 +446,8 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
wpa_s->mgmt_group_cipher);
pmksa_cache_clear_current(wpa_s->wpa);
+ os_memset(&mlo, 0, sizeof(mlo));
+ wpa_sm_set_mlo_params(wpa_s->wpa, &mlo);
}
@@ -765,18 +770,18 @@ void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
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,
+ wpa_drv_set_key(wpa_s, -1, WPA_ALG_NONE, NULL, i, 0, NULL, 0,
NULL, 0, KEY_FLAG_GROUP);
}
/* 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)) {
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);
+ wpa_drv_set_key(wpa_s, -1, 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);
+ wpa_drv_set_key(wpa_s, -1, WPA_ALG_NONE, addr, 1, 0,
+ NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE);
/* MLME-SETPROTECTION.request(None) */
wpa_drv_mlme_setprotection(
wpa_s, addr,
@@ -985,6 +990,13 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
if (state == WPA_COMPLETED && wpa_s->new_connection) {
struct wpa_ssid *ssid = wpa_s->current_ssid;
int fils_hlp_sent = 0;
+ char mld_addr[50];
+
+ mld_addr[0] = '\0';
+ if (wpa_s->valid_links)
+ os_snprintf(mld_addr, sizeof(mld_addr),
+ " ap_mld_addr=" MACSTR,
+ MAC2STR(wpa_s->ap_mld_addr));
#ifdef CONFIG_SME
if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
@@ -997,11 +1009,11 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED "- Connection to "
- MACSTR " completed [id=%d id_str=%s%s]",
+ MACSTR " completed [id=%d id_str=%s%s]%s",
MAC2STR(wpa_s->bssid),
ssid ? ssid->id : -1,
ssid && ssid->id_str ? ssid->id_str : "",
- fils_hlp_sent ? " FILS_HLP_SENT" : "");
+ fils_hlp_sent ? " FILS_HLP_SENT" : "", mld_addr);
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
wpas_clear_temp_disabled(wpa_s, ssid, 1);
wpa_s->consecutive_conn_failures = 0;
@@ -1122,6 +1134,7 @@ void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s)
wpa_s->group_cipher = 0;
wpa_s->mgmt_group_cipher = 0;
wpa_s->key_mgmt = 0;
+ wpa_s->allowed_key_mgmts = 0;
if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED)
wpa_supplicant_set_state(wpa_s, new_state);
@@ -1149,14 +1162,14 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
if (wpa_s->confname == NULL)
return -1;
- conf = wpa_config_read(wpa_s->confname, NULL);
+ conf = wpa_config_read(wpa_s->confname, NULL, false);
if (conf == NULL) {
wpa_msg(wpa_s, MSG_ERROR, "Failed to parse the configuration "
"file '%s' - exiting", wpa_s->confname);
return -1;
}
if (wpa_s->confanother &&
- !wpa_config_read(wpa_s->confanother, conf)) {
+ !wpa_config_read(wpa_s->confanother, conf, true)) {
wpa_msg(wpa_s, MSG_ERROR,
"Failed to parse the configuration file '%s' - exiting",
wpa_s->confanother);
@@ -1341,6 +1354,214 @@ void wpas_set_mgmt_group_cipher(struct wpa_supplicant *wpa_s,
wpas_get_ssid_pmf(wpa_s, ssid));
}
+/**
+ * wpa_supplicant_get_psk - Get PSK from config or external database
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bss: Scan results for the selected BSS, or %NULL if not available
+ * @ssid: Configuration data for the selected network
+ * @psk: Buffer for the PSK
+ * Returns: 0 on success or -1 if configuration parsing failed
+ *
+ * This function obtains the PSK for a network, either included inline in the
+ * config or retrieved from an external database.
+ */
+static int wpa_supplicant_get_psk(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss, struct wpa_ssid *ssid,
+ u8 *psk)
+{
+ if (ssid->psk_set) {
+ wpa_hexdump_key(MSG_MSGDUMP, "PSK (set in config)",
+ ssid->psk, PMK_LEN);
+ os_memcpy(psk, ssid->psk, PMK_LEN);
+ return 0;
+ }
+
+#ifndef CONFIG_NO_PBKDF2
+ if (bss && ssid->bssid_set && ssid->ssid_len == 0 && ssid->passphrase) {
+ if (pbkdf2_sha1(ssid->passphrase, bss->ssid, bss->ssid_len,
+ 4096, psk, PMK_LEN) != 0) {
+ wpa_msg(wpa_s, MSG_WARNING, "Error in pbkdf2_sha1()");
+ return -1;
+ }
+ wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
+ psk, PMK_LEN);
+ return 0;
+ }
+#endif /* CONFIG_NO_PBKDF2 */
+
+#ifdef CONFIG_EXT_PASSWORD
+ if (ssid->ext_psk) {
+ struct wpabuf *pw = ext_password_get(wpa_s->ext_pw,
+ ssid->ext_psk);
+ char pw_str[64 + 1];
+
+ if (!pw) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "EXT PW: No PSK found from external storage");
+ return -1;
+ }
+
+ if (wpabuf_len(pw) < 8 || wpabuf_len(pw) > 64) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "EXT PW: Unexpected PSK length %d in external storage",
+ (int) wpabuf_len(pw));
+ ext_password_free(pw);
+ return -1;
+ }
+
+ os_memcpy(pw_str, wpabuf_head(pw), wpabuf_len(pw));
+ pw_str[wpabuf_len(pw)] = '\0';
+
+#ifndef CONFIG_NO_PBKDF2
+ if (wpabuf_len(pw) >= 8 && wpabuf_len(pw) < 64 && bss)
+ {
+ if (pbkdf2_sha1(pw_str, bss->ssid, bss->ssid_len,
+ 4096, psk, PMK_LEN) != 0) {
+ wpa_msg(wpa_s, MSG_WARNING,
+ "Error in pbkdf2_sha1()");
+ forced_memzero(pw_str, sizeof(pw_str));
+ ext_password_free(pw);
+ return -1;
+ }
+ wpa_hexdump_key(MSG_MSGDUMP,
+ "PSK (from external passphrase)",
+ psk, PMK_LEN);
+ } else
+#endif /* CONFIG_NO_PBKDF2 */
+ if (wpabuf_len(pw) == 2 * PMK_LEN) {
+ if (hexstr2bin(pw_str, psk, PMK_LEN) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "EXT PW: Invalid PSK hex string");
+ forced_memzero(pw_str, sizeof(pw_str));
+ ext_password_free(pw);
+ return -1;
+ }
+ wpa_hexdump_key(MSG_MSGDUMP, "PSK (from external PSK)",
+ psk, PMK_LEN);
+ } else {
+ wpa_msg(wpa_s, MSG_INFO,
+ "EXT PW: No suitable PSK available");
+ forced_memzero(pw_str, sizeof(pw_str));
+ ext_password_free(pw);
+ return -1;
+ }
+
+ forced_memzero(pw_str, sizeof(pw_str));
+ ext_password_free(pw);
+
+ return 0;
+ }
+#endif /* CONFIG_EXT_PASSWORD */
+
+ return -1;
+}
+
+
+static void wpas_update_allowed_key_mgmt(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ int akm_count = wpa_s->max_num_akms;
+ u8 capab = 0;
+
+ if (akm_count < 2)
+ return;
+
+ akm_count--;
+ wpa_s->allowed_key_mgmts = 0;
+ switch (wpa_s->key_mgmt) {
+ case WPA_KEY_MGMT_PSK:
+ if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
+ akm_count--;
+ wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE;
+ }
+ if (!akm_count)
+ break;
+ if (ssid->key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) {
+ akm_count--;
+ wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE_EXT_KEY;
+ }
+ if (!akm_count)
+ break;
+ if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
+ wpa_s->allowed_key_mgmts |=
+ WPA_KEY_MGMT_PSK_SHA256;
+ break;
+ case WPA_KEY_MGMT_PSK_SHA256:
+ if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
+ akm_count--;
+ wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE;
+ }
+ if (!akm_count)
+ break;
+ if (ssid->key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) {
+ akm_count--;
+ wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE_EXT_KEY;
+ }
+ if (!akm_count)
+ break;
+ if (ssid->key_mgmt & WPA_KEY_MGMT_PSK)
+ wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_PSK;
+ break;
+ case WPA_KEY_MGMT_SAE:
+ if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
+ akm_count--;
+ wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_PSK;
+ }
+ if (!akm_count)
+ break;
+ if (ssid->key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) {
+ akm_count--;
+ wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE_EXT_KEY;
+ }
+ if (!akm_count)
+ break;
+ if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
+ wpa_s->allowed_key_mgmts |=
+ WPA_KEY_MGMT_PSK_SHA256;
+ break;
+ case WPA_KEY_MGMT_SAE_EXT_KEY:
+ if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
+ akm_count--;
+ wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE;
+ }
+ if (!akm_count)
+ break;
+ if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
+ akm_count--;
+ wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_PSK;
+ }
+ if (!akm_count)
+ break;
+ if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
+ wpa_s->allowed_key_mgmts |=
+ WPA_KEY_MGMT_PSK_SHA256;
+ break;
+ default:
+ return;
+ }
+
+ if (wpa_s->conf->sae_pwe != SAE_PWE_HUNT_AND_PECK &&
+ wpa_s->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
+ capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+#ifdef CONFIG_SAE_PK
+ if (ssid->sae_pk)
+ capab |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
+#endif /* CONFIG_SAE_PK */
+
+ if (!((wpa_s->allowed_key_mgmts &
+ (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_SAE_EXT_KEY)) && capab))
+ return;
+
+ if (!wpa_s->rsnxe_len) {
+ wpa_s->rsnxe_len = 3;
+ wpa_s->rsnxe[0] = WLAN_EID_RSNX;
+ wpa_s->rsnxe[1] = 1;
+ wpa_s->rsnxe[2] = 0;
+ }
+
+ wpa_s->rsnxe[2] |= capab;
+}
+
/**
* wpa_supplicant_set_suites - Set authentication and encryption parameters
@@ -1350,6 +1571,7 @@ void wpas_set_mgmt_group_cipher(struct wpa_supplicant *wpa_s,
* @wpa_ie: Buffer for the WPA/RSN IE
* @wpa_ie_len: Maximum wpa_ie buffer size on input. This is changed to be the
* used buffer length in case the functions returns success.
+ * @skip_default_rsne: Whether to skip setting of the default RSNE/RSNXE
* Returns: 0 on success or -1 on failure
*
* This function is used to configure authentication and encryption parameters
@@ -1358,10 +1580,12 @@ void wpas_set_mgmt_group_cipher(struct wpa_supplicant *wpa_s,
*/
int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, struct wpa_ssid *ssid,
- u8 *wpa_ie, size_t *wpa_ie_len)
+ u8 *wpa_ie, size_t *wpa_ie_len,
+ bool skip_default_rsne)
{
struct wpa_ie_data ie;
- int sel, proto, sae_pwe;
+ int sel, proto;
+ enum sae_pwe sae_pwe;
const u8 *bss_wpa, *bss_rsn, *bss_rsnx, *bss_osen;
if (bss) {
@@ -1541,8 +1765,10 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
sel = ie.key_mgmt & ssid->key_mgmt;
#ifdef CONFIG_SAE
- if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE))
- sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE);
+ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE) ||
+ wpas_is_sae_avoided(wpa_s, ssid, &ie))
+ sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_SAE_EXT_KEY |
+ WPA_KEY_MGMT_FT_SAE | WPA_KEY_MGMT_FT_SAE_EXT_KEY);
#endif /* CONFIG_SAE */
#ifdef CONFIG_IEEE80211R
if (!(wpa_s->drv_flags & (WPA_DRIVER_FLAGS_SME |
@@ -1587,13 +1813,15 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
} else if (sel & WPA_KEY_MGMT_FT_FILS_SHA384) {
wpa_s->key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA384;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT-FILS-SHA384");
- } else if (sel & WPA_KEY_MGMT_FT_FILS_SHA256) {
- wpa_s->key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA256;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT-FILS-SHA256");
#endif /* CONFIG_IEEE80211R */
} else if (sel & WPA_KEY_MGMT_FILS_SHA384) {
wpa_s->key_mgmt = WPA_KEY_MGMT_FILS_SHA384;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FILS-SHA384");
+#ifdef CONFIG_IEEE80211R
+ } else if (sel & WPA_KEY_MGMT_FT_FILS_SHA256) {
+ wpa_s->key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA256;
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT-FILS-SHA256");
+#endif /* CONFIG_IEEE80211R */
} else if (sel & WPA_KEY_MGMT_FILS_SHA256) {
wpa_s->key_mgmt = WPA_KEY_MGMT_FILS_SHA256;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FILS-SHA256");
@@ -1618,6 +1846,13 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT DPP");
#endif /* CONFIG_DPP */
#ifdef CONFIG_SAE
+ } else if (sel & WPA_KEY_MGMT_FT_SAE_EXT_KEY) {
+ wpa_s->key_mgmt = WPA_KEY_MGMT_FT_SAE_EXT_KEY;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "RSN: using KEY_MGMT FT/SAE (ext key)");
+ } else if (sel & WPA_KEY_MGMT_SAE_EXT_KEY) {
+ wpa_s->key_mgmt = WPA_KEY_MGMT_SAE_EXT_KEY;
+ wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT SAE (ext key)");
} else if (sel & WPA_KEY_MGMT_FT_SAE) {
wpa_s->key_mgmt = WPA_KEY_MGMT_FT_SAE;
wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT FT/SAE");
@@ -1669,7 +1904,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
- wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) {
+ (wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED ||
+ (bss && is_6ghz_freq(bss->freq)))) {
wpa_msg(wpa_s, MSG_INFO,
"RSN: Management frame protection required but the selected AP does not enable it");
return -1;
@@ -1682,18 +1918,16 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
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;
- if (bss && is_6ghz_freq(bss->freq)) {
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: force hash-to-element mode for 6GHz BSS.");
- sae_pwe = 1;
- }
-#ifdef CONFIG_TESTING_OPTIONS
- if (wpa_s->force_hunting_and_pecking_pwe) {
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: force hunting and pecking mode.");
- sae_pwe = 0;
+ if ((ssid->sae_password_id ||
+ wpa_key_mgmt_sae_ext_key(wpa_s->key_mgmt)) &&
+ sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
+ sae_pwe = SAE_PWE_HASH_TO_ELEMENT;
+ if (bss && is_6ghz_freq(bss->freq) &&
+ sae_pwe == SAE_PWE_HUNT_AND_PECK) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "RSN: Enable SAE hash-to-element mode for 6 GHz BSS");
+ sae_pwe = SAE_PWE_BOTH;
}
-#endif
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,
@@ -1704,6 +1938,12 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
(!ssid->sae_password && ssid->passphrase &&
sae_pk_valid_password(ssid->passphrase))));
#endif /* CONFIG_SAE_PK */
+ if (bss && is_6ghz_freq(bss->freq) &&
+ wpas_get_ssid_pmf(wpa_s, ssid) != MGMT_FRAME_PROTECTION_REQUIRED) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "RSN: Force MFPR=1 on 6 GHz");
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP,
+ MGMT_FRAME_PROTECTION_REQUIRED);
+ }
#ifdef CONFIG_TESTING_OPTIONS
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_FT_RSNXE_USED,
wpa_s->ft_rsnxe_used);
@@ -1715,6 +1955,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
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);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DISABLE_EAPOL_G2_TX,
+ wpa_s->disable_eapol_g2_tx);
#endif /* CONFIG_TESTING_OPTIONS */
/* Extended Key ID is only supported in infrastructure BSS so far */
@@ -1741,16 +1983,21 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
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;
- }
+ if (!skip_default_rsne) {
+ if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie,
+ wpa_ie_len)) {
+ wpa_msg(wpa_s, MSG_WARNING,
+ "RSN: Failed to generate RSNE/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;
+ 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) {
@@ -1764,108 +2011,27 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_DPP */
} else if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
int psk_set = 0;
- int sae_only;
-
- sae_only = (ssid->key_mgmt & (WPA_KEY_MGMT_PSK |
- WPA_KEY_MGMT_FT_PSK |
- WPA_KEY_MGMT_PSK_SHA256)) == 0;
-
- if (ssid->psk_set && !sae_only) {
- wpa_hexdump_key(MSG_MSGDUMP, "PSK (set in config)",
- ssid->psk, PMK_LEN);
- wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL,
- NULL);
- psk_set = 1;
- }
- if (wpa_key_mgmt_sae(ssid->key_mgmt) &&
- (ssid->sae_password || ssid->passphrase))
- psk_set = 1;
-
-#ifndef CONFIG_NO_PBKDF2
- if (bss && ssid->bssid_set && ssid->ssid_len == 0 &&
- ssid->passphrase && !sae_only) {
+ if (wpa_key_mgmt_wpa_psk_no_sae(ssid->key_mgmt)) {
u8 psk[PMK_LEN];
- pbkdf2_sha1(ssid->passphrase, bss->ssid, bss->ssid_len,
- 4096, psk, PMK_LEN);
- wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
- psk, PMK_LEN);
- wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL, NULL);
- psk_set = 1;
- os_memset(psk, 0, sizeof(psk));
- }
-#endif /* CONFIG_NO_PBKDF2 */
-#ifdef CONFIG_EXT_PASSWORD
- if (ssid->ext_psk && !sae_only) {
- struct wpabuf *pw = ext_password_get(wpa_s->ext_pw,
- ssid->ext_psk);
- char pw_str[64 + 1];
- u8 psk[PMK_LEN];
-
- if (pw == NULL) {
- wpa_msg(wpa_s, MSG_INFO, "EXT PW: No PSK "
- "found from external storage");
- return -1;
- }
-
- if (wpabuf_len(pw) < 8 || wpabuf_len(pw) > 64) {
- wpa_msg(wpa_s, MSG_INFO, "EXT PW: Unexpected "
- "PSK length %d in external storage",
- (int) wpabuf_len(pw));
- ext_password_free(pw);
- return -1;
- }
-
- os_memcpy(pw_str, wpabuf_head(pw), wpabuf_len(pw));
- pw_str[wpabuf_len(pw)] = '\0';
-#ifndef CONFIG_NO_PBKDF2
- if (wpabuf_len(pw) >= 8 && wpabuf_len(pw) < 64 && bss)
- {
- pbkdf2_sha1(pw_str, bss->ssid, bss->ssid_len,
- 4096, psk, PMK_LEN);
- os_memset(pw_str, 0, sizeof(pw_str));
- wpa_hexdump_key(MSG_MSGDUMP, "PSK (from "
- "external passphrase)",
- psk, PMK_LEN);
- wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL,
- NULL);
- psk_set = 1;
- os_memset(psk, 0, sizeof(psk));
- } else
-#endif /* CONFIG_NO_PBKDF2 */
- if (wpabuf_len(pw) == 2 * PMK_LEN) {
- if (hexstr2bin(pw_str, psk, PMK_LEN) < 0) {
- wpa_msg(wpa_s, MSG_INFO, "EXT PW: "
- "Invalid PSK hex string");
- os_memset(pw_str, 0, sizeof(pw_str));
- ext_password_free(pw);
- return -1;
- }
- wpa_hexdump_key(MSG_MSGDUMP,
- "PSK (from external PSK)",
- psk, PMK_LEN);
+ if (wpa_supplicant_get_psk(wpa_s, bss, ssid,
+ psk) == 0) {
wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL,
NULL);
psk_set = 1;
- os_memset(psk, 0, sizeof(psk));
- } else {
- wpa_msg(wpa_s, MSG_INFO, "EXT PW: No suitable "
- "PSK available");
- os_memset(pw_str, 0, sizeof(pw_str));
- ext_password_free(pw);
- return -1;
}
-
- os_memset(pw_str, 0, sizeof(pw_str));
- ext_password_free(pw);
+ forced_memzero(psk, sizeof(psk));
}
-#endif /* CONFIG_EXT_PASSWORD */
+
+ if (wpa_key_mgmt_sae(ssid->key_mgmt) &&
+ (ssid->sae_password || ssid->passphrase || ssid->ext_psk))
+ psk_set = 1;
if (!psk_set) {
wpa_msg(wpa_s, MSG_INFO,
"No PSK available for association");
- wpas_auth_failed(wpa_s, "NO_PSK_AVAILABLE");
+ wpas_auth_failed(wpa_s, "NO_PSK_AVAILABLE", NULL);
return -1;
}
#ifdef CONFIG_OWE
@@ -1891,14 +2057,21 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DENY_PTK0_REKEY, 0);
}
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
if ((wpa_s->key_mgmt & WPA_KEY_MGMT_CROSS_AKM_ROAM) &&
- IS_CROSS_AKM_ROAM_KEY_MGMT(ssid->key_mgmt)) {
+ IS_CROSS_AKM_ROAM_KEY_MGMT(ssid->key_mgmt) &&
+ (wpa_s->group_cipher == WPA_CIPHER_CCMP) &&
+ (wpa_s->pairwise_cipher == WPA_CIPHER_CCMP) &&
+ (wpa_s->wpa_proto == WPA_PROTO_RSN)) {
wpa_s->key_mgmt = WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_PSK;
wpa_dbg(wpa_s, MSG_INFO,
"WPA: Updating to KEY_MGMT SAE+PSK for seamless roaming");
}
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#else
+ if (wpa_key_mgmt_cross_akm(wpa_s->key_mgmt) &&
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME))
+ wpas_update_allowed_key_mgmt(wpa_s, ssid);
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
return 0;
}
@@ -2081,31 +2254,53 @@ void wpas_connect_work_done(struct wpa_supplicant *wpa_s)
}
-int wpas_update_random_addr(struct wpa_supplicant *wpa_s, int style)
+int wpas_update_random_addr(struct wpa_supplicant *wpa_s,
+ enum wpas_mac_addr_style style,
+ struct wpa_ssid *ssid)
{
struct os_reltime now;
u8 addr[ETH_ALEN];
os_get_reltime(&now);
- if (wpa_s->last_mac_addr_style == style &&
- wpa_s->last_mac_addr_change.sec != 0 &&
- !os_reltime_expired(&now, &wpa_s->last_mac_addr_change,
- wpa_s->conf->rand_addr_lifetime)) {
- wpa_msg(wpa_s, MSG_DEBUG,
- "Previously selected random MAC address has not yet expired");
- return 0;
+ /* Random addresses are valid within a given ESS so check
+ * expiration/value only when continuing to use the same ESS. */
+ if (wpa_s->last_mac_addr_style == style && wpa_s->reassoc_same_ess) {
+ if (style == WPAS_MAC_ADDR_STYLE_DEDICATED_PER_ESS) {
+ /* Pregenerated addresses do not expire but their value
+ * might have changed, so let's check that. */
+ if (os_memcmp(wpa_s->own_addr, ssid->mac_value,
+ ETH_ALEN) == 0)
+ return 0;
+ } else if ((wpa_s->last_mac_addr_change.sec != 0 ||
+ wpa_s->last_mac_addr_change.usec != 0) &&
+ !os_reltime_expired(
+ &now,
+ &wpa_s->last_mac_addr_change,
+ wpa_s->conf->rand_addr_lifetime)) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Previously selected random MAC address has not yet expired");
+ return 0;
+ }
}
switch (style) {
- case 1:
+ case WPAS_MAC_ADDR_STYLE_RANDOM:
if (random_mac_addr(addr) < 0)
return -1;
break;
- case 2:
+ case WPAS_MAC_ADDR_STYLE_RANDOM_SAME_OUI:
os_memcpy(addr, wpa_s->perm_addr, ETH_ALEN);
if (random_mac_addr_keep_oui(addr) < 0)
return -1;
break;
+ case WPAS_MAC_ADDR_STYLE_DEDICATED_PER_ESS:
+ if (!ssid) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Invalid 'ssid' for address policy 3");
+ return -1;
+ }
+ os_memcpy(addr, ssid->mac_value, ETH_ALEN);
+ break;
default:
return -1;
}
@@ -2129,7 +2324,7 @@ int wpas_update_random_addr(struct wpa_supplicant *wpa_s, int style)
wpa_msg(wpa_s, MSG_DEBUG, "Using random MAC address " MACSTR,
MAC2STR(addr));
- return 0;
+ return 1;
}
@@ -2139,11 +2334,13 @@ int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s)
!wpa_s->conf->preassoc_mac_addr)
return 0;
- return wpas_update_random_addr(wpa_s, wpa_s->conf->preassoc_mac_addr);
+ return wpas_update_random_addr(wpa_s, wpa_s->conf->preassoc_mac_addr,
+ NULL);
}
-static void wpa_s_setup_sae_pt(struct wpa_config *conf, struct wpa_ssid *ssid)
+void wpa_s_setup_sae_pt(struct wpa_config *conf, struct wpa_ssid *ssid,
+ bool force)
{
#ifdef CONFIG_SAE
int *groups = conf->sae_groups;
@@ -2158,9 +2355,11 @@ static void wpa_s_setup_sae_pt(struct wpa_config *conf, struct wpa_ssid *ssid)
password = ssid->passphrase;
if (!password ||
- (conf->sae_pwe == 0 && !ssid->sae_password_id &&
+ (conf->sae_pwe == SAE_PWE_HUNT_AND_PECK && !ssid->sae_password_id &&
+ !wpa_key_mgmt_sae_ext_key(ssid->key_mgmt) &&
+ !force &&
!sae_pk_valid_password(password)) ||
- conf->sae_pwe == 3) {
+ conf->sae_pwe == SAE_PWE_FORCE_HUNT_AND_PECK) {
/* PT derivation not needed */
sae_deinit_pt(ssid->pt);
ssid->pt = NULL;
@@ -2230,7 +2429,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, struct wpa_ssid *ssid)
{
struct wpa_connect_work *cwork;
- int rand_style;
+ enum wpas_mac_addr_style rand_style;
wpa_s->own_disconnect_req = 0;
wpa_s->own_reconnect_req = 0;
@@ -2242,11 +2441,12 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
wpabuf_free(wpa_s->pending_eapol_rx);
wpa_s->pending_eapol_rx = NULL;
- if (ssid->mac_addr == -1)
+ if (ssid->mac_addr == WPAS_MAC_ADDR_STYLE_NOT_SET)
rand_style = wpa_s->conf->mac_addr;
else
rand_style = ssid->mac_addr;
+ wpa_s->eapol_failed = 0;
wpa_s->multi_ap_ie = 0;
wmm_ac_clear_saved_tspecs(wpa_s);
wpa_s->reassoc_same_bss = 0;
@@ -2270,14 +2470,19 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_SAE */
}
#ifdef CONFIG_SAE
- wpa_s_setup_sae_pt(wpa_s->conf, ssid);
+ wpa_s_setup_sae_pt(wpa_s->conf, ssid, false);
#endif /* CONFIG_SAE */
- if (rand_style > 0 && !wpa_s->reassoc_same_ess) {
- if (wpas_update_random_addr(wpa_s, rand_style) < 0)
+ if (rand_style > WPAS_MAC_ADDR_STYLE_PERMANENT) {
+ int status = wpas_update_random_addr(wpa_s, rand_style, ssid);
+
+ if (status < 0)
return;
- wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
- } else if (rand_style == 0 && wpa_s->mac_addr_changed) {
+ if (rand_style != WPAS_MAC_ADDR_STYLE_DEDICATED_PER_ESS &&
+ status > 0) /* MAC changed */
+ wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
+ } else if (rand_style == WPAS_MAC_ADDR_STYLE_PERMANENT &&
+ wpa_s->mac_addr_changed) {
if (wpas_restore_permanent_mac_addr(wpa_s) < 0)
return;
}
@@ -2327,6 +2532,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
if (bss)
ssid->frequency = bss->freq;
if (wpa_supplicant_join_mesh(wpa_s, ssid) < 0) {
+ wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
wpa_msg(wpa_s, MSG_ERROR, "Could not join mesh");
return;
}
@@ -2449,116 +2655,142 @@ static bool ibss_mesh_is_80mhz_avail(int channel, struct hostapd_hw_modes *mode)
}
-void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
- const struct wpa_ssid *ssid,
- struct hostapd_freq_params *freq)
+static struct wpa_bss * ibss_find_existing_bss(struct wpa_supplicant *wpa_s,
+ const struct wpa_ssid *ssid)
{
- int ieee80211_mode = wpas_mode_to_ieee80211_mode(ssid->mode);
- enum hostapd_hw_mode hw_mode;
- struct hostapd_hw_modes *mode = NULL;
- int ht40plus[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
- 184, 192 };
- 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;
- unsigned int j, k;
- struct hostapd_freq_params vht_freq;
- int chwidth, seg0, seg1;
- u32 vht_caps = 0;
- bool is_24ghz, is_6ghz;
-
- freq->freq = ssid->frequency;
+ unsigned int j;
for (j = 0; j < wpa_s->last_scan_res_used; j++) {
struct wpa_bss *bss = wpa_s->last_scan_res[j];
- if (ssid->mode != WPAS_MODE_IBSS)
- break;
-
- /* Don't adjust control freq in case of fixed_freq */
- if (ssid->fixed_freq)
- break;
-
if (!bss_is_ibss(bss))
continue;
if (ssid->ssid_len == bss->ssid_len &&
- os_memcmp(ssid->ssid, bss->ssid, bss->ssid_len) == 0) {
- wpa_printf(MSG_DEBUG,
- "IBSS already found in scan results, adjust control freq: %d",
- bss->freq);
- freq->freq = bss->freq;
- obss_scan = 0;
- break;
- }
+ os_memcmp(ssid->ssid, bss->ssid, bss->ssid_len) == 0)
+ return bss;
}
+ return NULL;
+}
+
+static bool ibss_mesh_can_use_ht(struct wpa_supplicant *wpa_s,
+ const struct wpa_ssid *ssid,
+ struct hostapd_hw_modes *mode)
+{
/* For IBSS check HT_IBSS flag */
if (ssid->mode == WPAS_MODE_IBSS &&
!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_HT_IBSS))
- return;
+ return false;
if (wpa_s->group_cipher == WPA_CIPHER_WEP40 ||
wpa_s->group_cipher == WPA_CIPHER_WEP104 ||
wpa_s->pairwise_cipher == WPA_CIPHER_TKIP) {
wpa_printf(MSG_DEBUG,
"IBSS: WEP/TKIP detected, do not try to enable HT");
- return;
+ return false;
}
- hw_mode = ieee80211_freq_to_chan(freq->freq, &channel);
- for (i = 0; wpa_s->hw.modes && i < wpa_s->hw.num_modes; i++) {
- if (wpa_s->hw.modes[i].mode == hw_mode) {
- mode = &wpa_s->hw.modes[i];
- break;
- }
- }
+ if (!ht_supported(mode))
+ return false;
- if (!mode)
- return;
+#ifdef CONFIG_HT_OVERRIDES
+ if (ssid->disable_ht)
+ return false;
+#endif /* CONFIG_HT_OVERRIDES */
- freq->channel = channel;
+ return true;
+}
- 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;
+static bool ibss_mesh_can_use_vht(struct wpa_supplicant *wpa_s,
+ const struct wpa_ssid *ssid,
+ struct hostapd_hw_modes *mode)
+{
+ if (mode->mode != HOSTAPD_MODE_IEEE80211A)
+ return false;
-#ifdef CONFIG_HT_OVERRIDES
- if (ssid->disable_ht) {
- freq->ht_enabled = 0;
- return;
- }
-#endif /* CONFIG_HT_OVERRIDES */
+ if (!drv_supports_vht(wpa_s, ssid))
+ return false;
- freq->ht_enabled = ht_supported(mode);
- if (!freq->ht_enabled)
- return;
+ /* For IBSS check VHT_IBSS flag */
+ if (ssid->mode == WPAS_MODE_IBSS &&
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_VHT_IBSS))
+ return false;
- /* 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;
+ if (!vht_supported(mode))
+ return false;
+
+#ifdef CONFIG_VHT_OVERRIDES
+ if (ssid->disable_vht)
+ return false;
+#endif /* CONFIG_VHT_OVERRIDES */
+
+ return true;
+}
+
+
+static bool ibss_mesh_can_use_he(struct wpa_supplicant *wpa_s,
+ const struct wpa_ssid *ssid,
+ const struct hostapd_hw_modes *mode,
+ int ieee80211_mode)
+{
#ifdef CONFIG_HE_OVERRIDES
- if (is_24ghz && ssid->disable_he)
- freq->he_enabled = 0;
+ if (ssid->disable_he)
+ return false;
#endif /* CONFIG_HE_OVERRIDES */
- /* Setup higher BW only for 5 GHz */
- if (mode->mode != HOSTAPD_MODE_IEEE80211A)
+ switch (mode->mode) {
+ case HOSTAPD_MODE_IEEE80211G:
+ case HOSTAPD_MODE_IEEE80211B:
+ case HOSTAPD_MODE_IEEE80211A:
+ return mode->he_capab[ieee80211_mode].he_supported;
+ default:
+ return false;
+ }
+}
+
+
+static bool ibss_mesh_can_use_eht(struct wpa_supplicant *wpa_s,
+ const struct wpa_ssid *ssid,
+ const struct hostapd_hw_modes *mode,
+ int ieee80211_mode)
+{
+ if (ssid->disable_eht)
+ return false;
+
+ switch(mode->mode) {
+ case HOSTAPD_MODE_IEEE80211G:
+ case HOSTAPD_MODE_IEEE80211B:
+ case HOSTAPD_MODE_IEEE80211A:
+ return mode->eht_capab[ieee80211_mode].eht_supported;
+ default:
+ return false;
+ }
+}
+
+
+static void ibss_mesh_select_40mhz(struct wpa_supplicant *wpa_s,
+ const struct wpa_ssid *ssid,
+ struct hostapd_hw_modes *mode,
+ struct hostapd_freq_params *freq,
+ int obss_scan) {
+ int chan_idx;
+ struct hostapd_channel_data *pri_chan = NULL, *sec_chan = NULL;
+ int i, res;
+ unsigned int j;
+ static const int ht40plus[] = {
+ 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157, 165, 173,
+ 184, 192
+ };
+ int ht40 = -1;
+
+ if (!freq->ht_enabled)
return;
for (chan_idx = 0; chan_idx < mode->num_channels; chan_idx++) {
pri_chan = &mode->channels[chan_idx];
- if (pri_chan->chan == channel)
+ if (pri_chan->chan == freq->channel)
break;
pri_chan = NULL;
}
@@ -2569,21 +2801,14 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
if (pri_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
return;
- freq->channel = pri_chan->chan;
-
#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 */
+ if (ssid->disable_ht40)
+ return;
+#endif
/* Check/setup HT40+/HT40- */
for (j = 0; j < ARRAY_SIZE(ht40plus); j++) {
- if (ht40plus[j] == channel) {
+ if (ht40plus[j] == freq->channel) {
ht40 = 1;
break;
}
@@ -2592,7 +2817,7 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
/* Find secondary channel */
for (i = 0; i < mode->num_channels; i++) {
sec_chan = &mode->channels[i];
- if (sec_chan->chan == channel + ht40 * 4)
+ if (sec_chan->chan == freq->channel + ht40 * 4)
break;
sec_chan = NULL;
}
@@ -2645,38 +2870,48 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
wpa_scan_results_free(scan_res);
}
-#ifdef CONFIG_HT_OVERRIDES
-skip_ht40:
-#endif /* CONFIG_HT_OVERRIDES */
wpa_printf(MSG_DEBUG,
"IBSS/mesh: setup freq channel %d, sec_channel_offset %d",
freq->channel, freq->sec_channel_offset);
+}
- if (!drv_supports_vht(wpa_s, ssid))
- return;
- /* For IBSS check VHT_IBSS flag */
- if (ssid->mode == WPAS_MODE_IBSS &&
- !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_VHT_IBSS))
- return;
+static bool ibss_mesh_select_80_160mhz(struct wpa_supplicant *wpa_s,
+ const struct wpa_ssid *ssid,
+ struct hostapd_hw_modes *mode,
+ struct hostapd_freq_params *freq,
+ int ieee80211_mode, bool is_6ghz) {
+ static const int bw80[] = {
+ 5180, 5260, 5500, 5580, 5660, 5745, 5825,
+ 5955, 6035, 6115, 6195, 6275, 6355, 6435,
+ 6515, 6595, 6675, 6755, 6835, 6915, 6995
+ };
+ static const int bw160[] = {
+ 5955, 6115, 6275, 6435, 6595, 6755, 6915
+ };
+ struct hostapd_freq_params vht_freq;
+ int i;
+ unsigned int j, k;
+ int chwidth, seg0, seg1;
+ u32 vht_caps = 0;
+ u8 channel = freq->channel;
-#ifdef CONFIG_VHT_OVERRIDES
- if (ssid->disable_vht) {
- freq->vht_enabled = 0;
- return;
- }
-#endif /* CONFIG_VHT_OVERRIDES */
+ if (!freq->vht_enabled && !freq->he_enabled)
+ return true;
-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 && !is_6ghz)
- return;
-
- /* Enable HE with VHT for 5 GHz */
- freq->he_enabled = mode->he_capab[ieee80211_mode].he_supported;
+ chwidth = CONF_OPER_CHWIDTH_USE_HT;
+ seg0 = freq->channel + 2 * freq->sec_channel_offset;
+ seg1 = 0;
+ if (freq->sec_channel_offset == 0) {
+ seg0 = 0;
+ /* Don't try 80 MHz if 40 MHz failed, except in 6 GHz */
+ if (freq->ht_enabled && !is_6ghz)
+ goto skip_80mhz;
+ }
+ if (ssid->max_oper_chwidth == CONF_OPER_CHWIDTH_USE_HT)
+ goto skip_80mhz;
/* setup center_freq1, bandwidth */
for (j = 0; j < ARRAY_SIZE(bw80); j++) {
@@ -2687,36 +2922,34 @@ skip_to_6ghz:
if (j == ARRAY_SIZE(bw80) ||
ieee80211_freq_to_chan(bw80[j], &channel) == NUM_HOSTAPD_MODES)
- return;
+ goto skip_80mhz;
- /* Back to HT configuration if channel not usable */
+ /* Use 40 MHz if channel not usable */
if (!ibss_mesh_is_80mhz_avail(channel, mode))
- return;
+ goto skip_80mhz;
- chwidth = CHANWIDTH_80MHZ;
+ chwidth = CONF_OPER_CHWIDTH_80MHZ;
seg0 = channel + 6;
seg1 = 0;
+ /* In 160 MHz, the initial four 20 MHz channels were validated
+ * above. If 160 MHz is supported, check the remaining four 20 MHz
+ * channels for the total of 160 MHz bandwidth for 6 GHz.
+ */
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;
-
+ HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G) && is_6ghz &&
+ ibss_mesh_is_80mhz_avail(channel + 16, mode)) {
for (j = 0; j < ARRAY_SIZE(bw160); j++) {
if (freq->freq == bw160[j]) {
- chwidth = CHANWIDTH_160MHZ;
+ chwidth = CONF_OPER_CHWIDTH_160MHZ;
seg0 = channel + 14;
break;
}
}
}
- if (ssid->max_oper_chwidth == CHANWIDTH_80P80MHZ) {
+ if (ssid->max_oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ) {
/* setup center_freq2, bandwidth */
for (k = 0; k < ARRAY_SIZE(bw80); k++) {
/* Only accept 80 MHz segments separated by a gap */
@@ -2725,7 +2958,7 @@ skip_to_6ghz:
if (ieee80211_freq_to_chan(bw80[k], &channel) ==
NUM_HOSTAPD_MODES)
- return;
+ break;
for (i = channel; i < channel + 16; i += 4) {
struct hostapd_channel_data *chan;
@@ -2740,54 +2973,112 @@ skip_to_6ghz:
continue;
/* Found a suitable second segment for 80+80 */
- chwidth = CHANWIDTH_80P80MHZ;
+ chwidth = CONF_OPER_CHWIDTH_80P80MHZ;
if (!is_6ghz)
vht_caps |=
VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
seg1 = channel + 6;
}
- if (chwidth == CHANWIDTH_80P80MHZ)
+ if (chwidth == CONF_OPER_CHWIDTH_80P80MHZ)
break;
}
- } else if (ssid->max_oper_chwidth == CHANWIDTH_160MHZ) {
+ } else if (ssid->max_oper_chwidth == CONF_OPER_CHWIDTH_160MHZ) {
if (freq->freq == 5180) {
- chwidth = CHANWIDTH_160MHZ;
+ chwidth = CONF_OPER_CHWIDTH_160MHZ;
vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
seg0 = 50;
} else if (freq->freq == 5520) {
- chwidth = CHANWIDTH_160MHZ;
+ chwidth = CONF_OPER_CHWIDTH_160MHZ;
vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
seg0 = 114;
}
- } else if (ssid->max_oper_chwidth == CHANWIDTH_USE_HT) {
- chwidth = CHANWIDTH_USE_HT;
- 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 */
+skip_80mhz:
if (hostapd_set_freq_params(&vht_freq, mode->mode, freq->freq,
freq->channel, ssid->enable_edmg,
ssid->edmg_channel, freq->ht_enabled,
- vht_freq.vht_enabled, freq->he_enabled,
+ freq->vht_enabled, freq->he_enabled,
+ freq->eht_enabled,
freq->sec_channel_offset,
chwidth, seg0, seg1, vht_caps,
- &mode->he_capab[ieee80211_mode]) != 0)
- return;
+ &mode->he_capab[ieee80211_mode],
+ &mode->eht_capab[ieee80211_mode]) != 0)
+ return false;
*freq = vht_freq;
wpa_printf(MSG_DEBUG, "IBSS: VHT setup freq cf1 %d, cf2 %d, bw %d",
freq->center_freq1, freq->center_freq2, freq->bandwidth);
+ return true;
+}
+
+
+void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
+ const struct wpa_ssid *ssid,
+ struct hostapd_freq_params *freq)
+{
+ int ieee80211_mode = wpas_mode_to_ieee80211_mode(ssid->mode);
+ enum hostapd_hw_mode hw_mode;
+ struct hostapd_hw_modes *mode = NULL;
+ int i, obss_scan = 1;
+ u8 channel;
+ bool is_6ghz;
+
+ freq->freq = ssid->frequency;
+
+ if (ssid->mode == WPAS_MODE_IBSS && !ssid->fixed_freq) {
+ struct wpa_bss *bss = ibss_find_existing_bss(wpa_s, ssid);
+
+ if (bss) {
+ wpa_printf(MSG_DEBUG,
+ "IBSS already found in scan results, adjust control freq: %d",
+ bss->freq);
+ freq->freq = bss->freq;
+ obss_scan = 0;
+ }
+ }
+
+ hw_mode = ieee80211_freq_to_chan(freq->freq, &channel);
+ for (i = 0; wpa_s->hw.modes && i < wpa_s->hw.num_modes; i++) {
+ if (wpa_s->hw.modes[i].mode == hw_mode &&
+ hw_mode_get_channel(&wpa_s->hw.modes[i], freq->freq,
+ NULL) != NULL) {
+ mode = &wpa_s->hw.modes[i];
+ break;
+ }
+ }
+
+ if (!mode)
+ return;
+
+ is_6ghz = is_6ghz_freq(freq->freq);
+
+ freq->ht_enabled = 0;
+ freq->vht_enabled = 0;
+ freq->he_enabled = 0;
+ freq->eht_enabled = 0;
+
+ if (!is_6ghz)
+ freq->ht_enabled = ibss_mesh_can_use_ht(wpa_s, ssid, mode);
+ if (freq->ht_enabled)
+ freq->vht_enabled = ibss_mesh_can_use_vht(wpa_s, ssid, mode);
+ if (freq->vht_enabled || is_6ghz)
+ freq->he_enabled = ibss_mesh_can_use_he(wpa_s, ssid, mode,
+ ieee80211_mode);
+ freq->channel = channel;
+ /* Setup higher BW only for 5 GHz */
+ if (mode->mode == HOSTAPD_MODE_IEEE80211A) {
+ ibss_mesh_select_40mhz(wpa_s, ssid, mode, freq, obss_scan);
+ if (!ibss_mesh_select_80_160mhz(wpa_s, ssid, mode, freq,
+ ieee80211_mode, is_6ghz))
+ freq->he_enabled = freq->vht_enabled = false;
+ }
+
+ if (freq->he_enabled)
+ freq->eht_enabled = ibss_mesh_can_use_eht(wpa_s, ssid, mode,
+ ieee80211_mode);
}
@@ -2972,6 +3263,16 @@ static u8 * wpas_populate_assoc_ies(
wpa_key_mgmt_wpa(ssid->key_mgmt)) {
int try_opportunistic;
const u8 *cache_id = NULL;
+ const u8 *addr = bss->bssid;
+
+ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
+ (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_MLO) &&
+ !is_zero_ether_addr(bss->mld_addr))
+ addr = bss->mld_addr;
+
+ if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
+ wpa_s->valid_links)
+ addr = wpa_s->ap_mld_addr;
try_opportunistic = (ssid->proactive_key_caching < 0 ?
wpa_s->conf->okc :
@@ -2981,7 +3282,7 @@ static u8 * wpas_populate_assoc_ies(
if (wpa_key_mgmt_fils(ssid->key_mgmt))
cache_id = wpa_bss_get_fils_cache_id(bss);
#endif /* CONFIG_FILS */
- if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
+ if (pmksa_cache_set_current(wpa_s->wpa, NULL, addr,
ssid, try_opportunistic,
cache_id, 0) == 0) {
eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
@@ -2991,7 +3292,7 @@ static u8 * wpas_populate_assoc_ies(
}
wpa_ie_len = max_wpa_ie_len;
if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
- wpa_ie, &wpa_ie_len)) {
+ wpa_ie, &wpa_ie_len, false)) {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
"key management and encryption suites");
os_free(wpa_ie);
@@ -3003,7 +3304,7 @@ static u8 * wpas_populate_assoc_ies(
/* No PMKSA caching, but otherwise similar to RSN/WPA */
wpa_ie_len = max_wpa_ie_len;
if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
- wpa_ie, &wpa_ie_len)) {
+ wpa_ie, &wpa_ie_len, false)) {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
"key management and encryption suites");
os_free(wpa_ie);
@@ -3023,7 +3324,7 @@ static u8 * wpas_populate_assoc_ies(
} else if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
wpa_ie_len = max_wpa_ie_len;
if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
- wpa_ie, &wpa_ie_len)) {
+ wpa_ie, &wpa_ie_len, false)) {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
"key management and encryption suites (no "
"scan results)");
@@ -3094,7 +3395,7 @@ static u8 * wpas_populate_assoc_ies(
#endif /* CONFIG_FILS */
#endif /* IEEE8021X_EAPOL */
#ifdef CONFIG_SAE
- if (wpa_s->key_mgmt & (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE))
+ if (wpa_key_mgmt_sae(wpa_s->key_mgmt))
algs = WPA_AUTH_ALG_SAE;
#endif /* CONFIG_SAE */
@@ -3348,7 +3649,7 @@ pfs_fail:
}
#ifdef CONFIG_SME
if (len > 0 && wpa_s->sme.ft_used &&
- wpa_sm_has_ptk(wpa_s->wpa)) {
+ wpa_sm_has_ft_keys(wpa_s->wpa, md)) {
wpa_dbg(wpa_s, MSG_DEBUG,
"SME: Trying to use FT over-the-air");
algs |= WPA_AUTH_ALG_FT;
@@ -3632,6 +3933,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
int use_crypt, ret, bssid_changed;
unsigned int cipher_pairwise, cipher_group, cipher_group_mgmt;
struct wpa_driver_associate_params params;
+ u8 psk[PMK_LEN];
#if defined(CONFIG_WEP) || defined(IEEE8021X_EAPOL)
int wep_keys_set = 0;
#endif /* CONFIG_WEP || IEEE8021X_EAPOL */
@@ -3780,6 +4082,11 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
wpa_supplicant_set_wpa_none_key(wpa_s, ssid);
}
+ /* Set current_ssid before changing state to ASSOCIATING, so that the
+ * selected SSID is available to wpas_notify_state_changed(). */
+ old_ssid = wpa_s->current_ssid;
+ wpa_s->current_ssid = ssid;
+
wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);
if (bss) {
params.ssid = bss->ssid;
@@ -3895,6 +4202,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
params.group_suite = cipher_group;
params.mgmt_group_suite = cipher_group_mgmt;
params.key_mgmt_suite = wpa_s->key_mgmt;
+ params.allowed_key_mgmts = wpa_s->allowed_key_mgmts;
params.wpa_proto = wpa_s->wpa_proto;
wpa_s->auth_alg = params.auth_alg;
params.mode = ssid->mode;
@@ -3913,16 +4221,18 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
#endif /* CONFIG_WEP */
if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) &&
- (
-#ifdef CONFIG_DRIVER_NL80211_BRCM
- (params.key_mgmt_suite & WPA_KEY_MGMT_PSK) ||
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
+ ((params.key_mgmt_suite & WPA_KEY_MGMT_PSK) ||
+ (params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK))) {
#else
- params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
- params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK)) {
+ (params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
+ params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK ||
+ (params.allowed_key_mgmts &
+ (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK)))) {
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
params.passphrase = ssid->passphrase;
- if (ssid->psk_set)
- params.psk = ssid->psk;
+ if (wpa_supplicant_get_psk(wpa_s, bss, ssid, psk) == 0)
+ params.psk = psk;
}
if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X) &&
@@ -3943,16 +4253,16 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
else
params.req_key_mgmt_offload = 1;
- if ((
-#ifdef CONFIG_DRIVER_NL80211_BRCM
- (params.key_mgmt_suite & WPA_KEY_MGMT_PSK) ||
-#else
- params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
+ if (((params.key_mgmt_suite & WPA_KEY_MGMT_PSK) ||
params.key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK) &&
- ssid->psk_set)
- params.psk = ssid->psk;
+#else
+ if ((wpa_key_mgmt_wpa_psk_no_sae(params.key_mgmt_suite) ||
+ wpa_key_mgmt_wpa_psk_no_sae(params.allowed_key_mgmts)) &&
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
+ wpa_supplicant_get_psk(wpa_s, bss, ssid, psk) == 0)
+ params.psk = psk;
}
params.drop_unencrypted = use_crypt;
@@ -4000,6 +4310,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
#ifdef CONFIG_HE_OVERRIDES
wpa_supplicant_apply_he_overrides(wpa_s, ssid, &params);
#endif /* CONFIG_HE_OVERRIDES */
+ wpa_supplicant_apply_eht_overrides(wpa_s, ssid, &params);
#ifdef CONFIG_P2P
/*
@@ -4009,7 +4320,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
*/
if (wpa_s->num_multichan_concurrent < 2) {
int freq, num;
- num = get_shared_radio_freqs(wpa_s, &freq, 1);
+ num = get_shared_radio_freqs(wpa_s, &freq, 1, false);
if (num > 0 && freq > 0 && freq != params.freq.freq) {
wpa_printf(MSG_DEBUG,
"Assoc conflicting freq found (%d != %d)",
@@ -4025,7 +4336,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
#endif /* CONFIG_P2P */
if (wpa_s->reassoc_same_ess && !is_zero_ether_addr(prev_bssid) &&
- wpa_s->current_ssid)
+ old_ssid)
params.prev_bssid = prev_bssid;
#ifdef CONFIG_SAE
@@ -4033,6 +4344,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
#endif /* CONFIG_SAE */
ret = wpa_drv_associate(wpa_s, &params);
+ forced_memzero(psk, sizeof(psk));
os_free(wpa_ie);
if (ret < 0) {
wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
@@ -4095,15 +4407,13 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
}
#endif /* CONFIG_WEP */
- if (wpa_s->current_ssid && wpa_s->current_ssid != ssid) {
+ if (old_ssid && old_ssid != ssid) {
/*
* Do not allow EAP session resumption between different
* network configurations.
*/
eapol_sm_invalidate_cached_session(wpa_s->eapol);
}
- old_ssid = wpa_s->current_ssid;
- wpa_s->current_ssid = ssid;
if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set) {
wpa_s->current_bss = bss;
@@ -4116,6 +4426,8 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
wpa_supplicant_initiate_eapol(wpa_s);
if (old_ssid != wpa_s->current_ssid)
wpas_notify_network_changed(wpa_s);
+ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME))
+ wpas_notify_auth_changed(wpa_s);
}
@@ -4280,7 +4592,7 @@ struct wpa_ssid * wpa_supplicant_add_network(struct wpa_supplicant *wpa_s)
*/
int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id)
{
- struct wpa_ssid *ssid;
+ struct wpa_ssid *ssid, *prev = wpa_s->current_ssid;
int was_disabled;
ssid = wpa_config_get_network(wpa_s->conf, id);
@@ -4288,10 +4600,7 @@ int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id)
return -1;
wpas_notify_network_removed(wpa_s, ssid);
- if (wpa_s->last_ssid == ssid)
- wpa_s->last_ssid = NULL;
-
- if (ssid == wpa_s->current_ssid || !wpa_s->current_ssid) {
+ if (ssid == prev || !prev) {
#ifdef CONFIG_SME
wpa_s->sme.prev_bssid_set = 0;
#endif /* CONFIG_SME */
@@ -4302,7 +4611,7 @@ int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id)
eapol_sm_invalidate_cached_session(wpa_s->eapol);
}
- if (ssid == wpa_s->current_ssid) {
+ if (ssid == prev) {
wpa_sm_set_config(wpa_s->wpa, NULL);
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
@@ -4365,8 +4674,6 @@ int wpa_supplicant_remove_all_networks(struct wpa_supplicant *wpa_s)
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);
}
@@ -4540,7 +4847,7 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
wpa_s->last_owe_group = 0;
if (ssid) {
ssid->owe_transition_bss_select_count = 0;
- wpa_s_setup_sae_pt(wpa_s->conf, ssid);
+ wpa_s_setup_sae_pt(wpa_s->conf, ssid, false);
}
if (wpa_s->connect_without_scan ||
@@ -5019,6 +5326,7 @@ static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
* @src_addr: Source address of the EAPOL frame
* @buf: EAPOL data starting from the EAPOL header (i.e., no Ethernet header)
* @len: Length of the EAPOL data
+ * @encrypted: Whether the frame was encrypted
*
* This function is called for each received EAPOL frame. Most driver
* interfaces rely on more generic OS mechanism for receiving frames through
@@ -5027,11 +5335,15 @@ static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
* code by calling this function.
*/
void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
- const u8 *buf, size_t len)
+ const u8 *buf, size_t len,
+ enum frame_encryption encrypted)
{
struct wpa_supplicant *wpa_s = ctx;
+ const u8 *connected_addr = wpa_s->valid_links ?
+ wpa_s->ap_mld_addr : wpa_s->bssid;
- wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
+ wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " (encrypted=%d)",
+ MAC2STR(src_addr), encrypted);
wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
if (wpa_s->own_disconnect_req) {
@@ -5054,7 +5366,7 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
#ifdef CONFIG_AP
!wpa_s->ap_iface &&
#endif /* CONFIG_AP */
- os_memcmp(src_addr, wpa_s->bssid, ETH_ALEN) != 0)) {
+ os_memcmp(src_addr, connected_addr, ETH_ALEN) != 0)) {
/*
* There is possible race condition between receiving the
* association event and the EAPOL frame since they are coming
@@ -5067,26 +5379,29 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
* Authenticator uses BSSID as the src_addr (which is not the
* case with wired IEEE 802.1X).
*/
- wpa_dbg(wpa_s, MSG_DEBUG, "Not associated - Delay processing "
- "of received EAPOL frame (state=%s bssid=" MACSTR ")",
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Not associated - Delay processing of received EAPOL frame (state=%s connected_addr="
+ MACSTR ")",
wpa_supplicant_state_txt(wpa_s->wpa_state),
- MAC2STR(wpa_s->bssid));
+ MAC2STR(connected_addr));
wpabuf_free(wpa_s->pending_eapol_rx);
wpa_s->pending_eapol_rx = wpabuf_alloc_copy(buf, len);
if (wpa_s->pending_eapol_rx) {
os_get_reltime(&wpa_s->pending_eapol_rx_time);
os_memcpy(wpa_s->pending_eapol_rx_src, src_addr,
ETH_ALEN);
+ wpa_s->pending_eapol_encrypted = encrypted;
}
return;
}
wpa_s->last_eapol_matches_bssid =
- os_memcmp(src_addr, wpa_s->bssid, ETH_ALEN) == 0;
+ os_memcmp(src_addr, connected_addr, ETH_ALEN) == 0;
#ifdef CONFIG_AP
if (wpa_s->ap_iface) {
- wpa_supplicant_ap_rx_eapol(wpa_s, src_addr, buf, len);
+ wpa_supplicant_ap_rx_eapol(wpa_s, src_addr, buf, len,
+ encrypted);
return;
}
#endif /* CONFIG_AP */
@@ -5146,7 +5461,8 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
#ifdef CONFIG_IBSS_RSN
if (wpa_s->current_ssid &&
wpa_s->current_ssid->mode == WPAS_MODE_IBSS) {
- ibss_rsn_rx_eapol(wpa_s->ibss_rsn, src_addr, buf, len);
+ ibss_rsn_rx_eapol(wpa_s->ibss_rsn, src_addr, buf, len,
+ encrypted);
return;
}
#endif /* CONFIG_IBSS_RSN */
@@ -5161,11 +5477,12 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
if (!wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) &&
wpa_s->key_mgmt != WPA_KEY_MGMT_OWE &&
wpa_s->key_mgmt != WPA_KEY_MGMT_DPP &&
- eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len) > 0)
+ eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len,
+ encrypted) > 0)
return;
wpa_drv_poll(wpa_s);
if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK))
- wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);
+ wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len, encrypted);
else if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
/*
* Set portValid = true here since we are going to skip 4-way
@@ -5178,6 +5495,14 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
}
+static void wpa_supplicant_rx_eapol_cb(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len)
+{
+ wpa_supplicant_rx_eapol(ctx, src_addr, buf, len,
+ FRAME_ENCRYPTION_UNKNOWN);
+}
+
+
static int wpas_eapol_needs_l2_packet(struct wpa_supplicant *wpa_s)
{
return !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_CONTROL_PORT) ||
@@ -5187,6 +5512,10 @@ static int wpas_eapol_needs_l2_packet(struct wpa_supplicant *wpa_s)
int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
{
+ u8 prev_mac_addr[ETH_ALEN];
+
+ os_memcpy(prev_mac_addr, wpa_s->own_addr, ETH_ALEN);
+
if ((!wpa_s->p2p_mgmt ||
!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)) &&
!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE)) {
@@ -5195,7 +5524,7 @@ int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
wpa_drv_get_mac_addr(wpa_s),
ETH_P_EAPOL,
wpas_eapol_needs_l2_packet(wpa_s) ?
- wpa_supplicant_rx_eapol : NULL,
+ wpa_supplicant_rx_eapol_cb : NULL,
wpa_s, 0);
if (wpa_s->l2 == NULL)
return -1;
@@ -5224,6 +5553,9 @@ int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
fst_update_mac_addr(wpa_s->fst, wpa_s->own_addr);
#endif /* CONFIG_FST */
+ if (os_memcmp(prev_mac_addr, wpa_s->own_addr, ETH_ALEN) != 0)
+ wpas_notify_mac_address_changed(wpa_s);
+
return 0;
}
@@ -5249,7 +5581,7 @@ static void wpa_supplicant_rx_eapol_bridge(void *ctx, const u8 *src_addr,
wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " to " MACSTR
" (bridge)", MAC2STR(src_addr), MAC2STR(eth->h_dest));
wpa_supplicant_rx_eapol(wpa_s, src_addr, buf + sizeof(*eth),
- len - sizeof(*eth));
+ len - sizeof(*eth), FRAME_ENCRYPTION_UNKNOWN);
}
@@ -5790,6 +6122,17 @@ void wpa_supplicant_apply_he_overrides(
#endif /* CONFIG_HE_OVERRIDES */
+void wpa_supplicant_apply_eht_overrides(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ struct wpa_driver_associate_params *params)
+{
+ if (!ssid)
+ return;
+
+ params->disable_eht = ssid->disable_eht;
+}
+
+
static int pcsc_reader_init(struct wpa_supplicant *wpa_s)
{
#ifdef PCSC_FUNCS
@@ -5975,6 +6318,7 @@ static const u8 * wpas_fst_get_peer_next(void *ctx,
void fst_wpa_supplicant_fill_iface_obj(struct wpa_supplicant *wpa_s,
struct fst_wpa_obj *iface_obj)
{
+ os_memset(iface_obj, 0, sizeof(*iface_obj));
iface_obj->ctx = wpa_s;
iface_obj->get_bssid = wpas_fst_get_bssid_cb;
iface_obj->get_channel_info = wpas_fst_get_channel_info_cb;
@@ -6606,7 +6950,7 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
#else /* CONFIG_BACKEND_FILE */
wpa_s->confname = os_strdup(iface->confname);
#endif /* CONFIG_BACKEND_FILE */
- wpa_s->conf = wpa_config_read(wpa_s->confname, NULL);
+ wpa_s->conf = wpa_config_read(wpa_s->confname, NULL, false);
if (wpa_s->conf == NULL) {
wpa_printf(MSG_ERROR, "Failed to read or parse "
"configuration '%s'.", wpa_s->confname);
@@ -6614,7 +6958,7 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
}
wpa_s->confanother = os_rel2abs_path(iface->confanother);
if (wpa_s->confanother &&
- !wpa_config_read(wpa_s->confanother, wpa_s->conf)) {
+ !wpa_config_read(wpa_s->confanother, wpa_s->conf, true)) {
wpa_printf(MSG_ERROR,
"Failed to read or parse configuration '%s'.",
wpa_s->confanother);
@@ -6629,12 +6973,24 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
os_free(wpa_s->conf->ctrl_interface);
wpa_s->conf->ctrl_interface =
os_strdup(iface->ctrl_interface);
+ if (!wpa_s->conf->ctrl_interface) {
+ wpa_printf(MSG_ERROR,
+ "Failed to duplicate control interface '%s'.",
+ iface->ctrl_interface);
+ return -1;
+ }
}
if (iface->driver_param) {
os_free(wpa_s->conf->driver_param);
wpa_s->conf->driver_param =
os_strdup(iface->driver_param);
+ if (!wpa_s->conf->driver_param) {
+ wpa_printf(MSG_ERROR,
+ "Failed to duplicate driver param '%s'.",
+ iface->driver_param);
+ return -1;
+ }
}
if (iface->p2p_mgmt && !iface->ctrl_interface) {
@@ -6747,6 +7103,7 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
wpa_s->drv_flags2 = capa.flags2;
wpa_s->drv_enc = capa.enc;
wpa_s->drv_rrm_flags = capa.rrm_flags;
+ wpa_s->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs;
wpa_s->probe_resp_offloads = capa.probe_resp_offloads;
wpa_s->max_scan_ssids = capa.max_scan_ssids;
wpa_s->max_sched_scan_ssids = capa.max_sched_scan_ssids;
@@ -6765,6 +7122,7 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
wpa_s->num_multichan_concurrent =
capa.num_multichan_concurrent;
wpa_s->wmm_ac_supported = capa.wmm_ac_supported;
+ wpa_s->max_num_akms = capa.max_num_akms;
if (capa.mac_addr_rand_scan_supported)
wpa_s->mac_addr_rand_supported |= MAC_ADDR_RAND_SCAN;
@@ -6779,6 +7137,9 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
wpa_s->extended_capa[2] & 0x40)
wpa_s->multi_bss_support = 1;
}
+#ifdef CONFIG_PASN
+ wpa_pasn_sm_set_caps(wpa_s->wpa, wpa_s->drv_flags2);
+#endif /* CONFIG_PASN */
if (wpa_s->max_remain_on_chan == 0)
wpa_s->max_remain_on_chan = 1000;
@@ -7162,11 +7523,15 @@ struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
return NULL;
}
- /* Notify the control interfaces about new networks for non p2p mgmt
- * ifaces. */
- if (iface->p2p_mgmt == 0) {
- for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
+ /* Notify the control interfaces about new networks */
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (iface->p2p_mgmt == 0) {
wpas_notify_network_added(wpa_s, ssid);
+ } else if (ssid->ssid_len > P2P_WILDCARD_SSID_LEN
+ && os_strncmp((const char *) ssid->ssid,
+ P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 0) {
+ wpas_notify_persistent_group_added(wpa_s, ssid);
+ }
}
wpa_s->next = global->ifaces;
@@ -7394,26 +7759,63 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
global->params.daemonize = params->daemonize;
global->params.wait_for_monitor = params->wait_for_monitor;
global->params.dbus_ctrl_interface = params->dbus_ctrl_interface;
- if (params->pid_file)
+
+ if (params->pid_file) {
global->params.pid_file = os_strdup(params->pid_file);
- if (params->ctrl_interface)
+ if (!global->params.pid_file) {
+ wpa_supplicant_deinit(global);
+ return NULL;
+ }
+ }
+
+ if (params->ctrl_interface) {
global->params.ctrl_interface =
os_strdup(params->ctrl_interface);
- if (params->ctrl_interface_group)
+ if (!global->params.ctrl_interface) {
+ wpa_supplicant_deinit(global);
+ return NULL;
+ }
+ }
+
+ if (params->ctrl_interface_group) {
global->params.ctrl_interface_group =
os_strdup(params->ctrl_interface_group);
- if (params->override_driver)
+ if (!global->params.ctrl_interface_group) {
+ wpa_supplicant_deinit(global);
+ return NULL;
+ }
+ }
+
+ if (params->override_driver) {
global->params.override_driver =
os_strdup(params->override_driver);
- if (params->override_ctrl_interface)
+ if (!global->params.override_driver) {
+ wpa_supplicant_deinit(global);
+ return NULL;
+ }
+ }
+
+ if (params->override_ctrl_interface) {
global->params.override_ctrl_interface =
os_strdup(params->override_ctrl_interface);
+ if (!global->params.override_ctrl_interface) {
+ wpa_supplicant_deinit(global);
+ return NULL;
+ }
+ }
+
#ifdef CONFIG_MATCH_IFACE
global->params.match_iface_count = params->match_iface_count;
if (params->match_iface_count) {
global->params.match_ifaces =
os_calloc(params->match_iface_count,
sizeof(struct wpa_interface));
+ if (!global->params.match_ifaces) {
+ wpa_printf(MSG_ERROR,
+ "Failed to allocate match interfaces");
+ wpa_supplicant_deinit(global);
+ return NULL;
+ }
os_memcpy(global->params.match_ifaces,
params->match_ifaces,
params->match_iface_count *
@@ -7421,9 +7823,15 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
}
#endif /* CONFIG_MATCH_IFACE */
#ifdef CONFIG_P2P
- if (params->conf_p2p_dev)
+ if (params->conf_p2p_dev) {
global->params.conf_p2p_dev =
os_strdup(params->conf_p2p_dev);
+ if (!global->params.conf_p2p_dev) {
+ wpa_printf(MSG_ERROR, "Failed to allocate conf p2p");
+ wpa_supplicant_deinit(global);
+ return NULL;
+ }
+ }
#endif /* CONFIG_P2P */
wpa_debug_level = global->params.wpa_debug_level =
params->wpa_debug_level;
@@ -7511,6 +7919,15 @@ int wpa_supplicant_run(struct wpa_global *global)
wpa_s->ctrl_iface);
}
+#ifdef CONFIG_AIDL
+ // If daemonize is enabled, initialize AIDL here.
+ if (global->params.daemonize) {
+ global->aidl = wpas_aidl_init(global);
+ if (!global->aidl)
+ return -1;
+ }
+#endif /* CONFIG_AIDL */
+
eloop_register_signal_terminate(wpa_supplicant_terminate, global);
eloop_register_signal_reconfig(wpa_supplicant_reconfig, global);
@@ -7758,7 +8175,7 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
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");
+ wpas_auth_failed(wpa_s, "CONN_FAILED", bssid);
}
/*
* Multiple consecutive connection failures mean that other APs are
@@ -7935,6 +8352,8 @@ int wpa_supplicant_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
case WPA_CTRL_REQ_EAP_PASSWORD:
bin_clear_free(eap->password, eap->password_len);
eap->password = (u8 *) os_strdup(value);
+ if (!eap->password)
+ return -1;
eap->password_len = value_len;
eap->pending_req_password = 0;
if (ssid == wpa_s->current_ssid)
@@ -7943,6 +8362,8 @@ int wpa_supplicant_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
case WPA_CTRL_REQ_EAP_NEW_PASSWORD:
bin_clear_free(eap->new_password, eap->new_password_len);
eap->new_password = (u8 *) os_strdup(value);
+ if (!eap->new_password)
+ return -1;
eap->new_password_len = value_len;
eap->pending_req_new_password = 0;
if (ssid == wpa_s->current_ssid)
@@ -7951,6 +8372,8 @@ int wpa_supplicant_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
case WPA_CTRL_REQ_EAP_PIN:
str_clear_free(eap->cert.pin);
eap->cert.pin = os_strdup(value);
+ if (!eap->cert.pin)
+ return -1;
eap->pending_req_pin = 0;
if (ssid == wpa_s->current_ssid)
wpa_s->reassociate = 1;
@@ -7958,6 +8381,8 @@ int wpa_supplicant_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
case WPA_CTRL_REQ_EAP_OTP:
bin_clear_free(eap->otp, eap->otp_len);
eap->otp = (u8 *) os_strdup(value);
+ if (!eap->otp)
+ return -1;
eap->otp_len = value_len;
os_free(eap->pending_req_otp);
eap->pending_req_otp = NULL;
@@ -7966,6 +8391,8 @@ int wpa_supplicant_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
case WPA_CTRL_REQ_EAP_PASSPHRASE:
str_clear_free(eap->cert.private_key_passwd);
eap->cert.private_key_passwd = os_strdup(value);
+ if (!eap->cert.private_key_passwd)
+ return -1;
eap->pending_req_passphrase = 0;
if (ssid == wpa_s->current_ssid)
wpa_s->reassociate = 1;
@@ -7973,6 +8400,8 @@ int wpa_supplicant_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
case WPA_CTRL_REQ_SIM:
str_clear_free(eap->external_sim_resp);
eap->external_sim_resp = os_strdup(value);
+ if (!eap->external_sim_resp)
+ return -1;
eap->pending_req_sim = 0;
break;
case WPA_CTRL_REQ_PSK_PASSPHRASE:
@@ -8050,6 +8479,26 @@ int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
!ssid->mem_only_psk)
return 1;
+#ifdef IEEE8021X_EAPOL
+#ifdef CRYPTO_RSA_OAEP_SHA256
+ if (ssid->eap.imsi_privacy_cert) {
+ struct crypto_rsa_key *key;
+ bool failed = false;
+
+ key = crypto_rsa_key_read(ssid->eap.imsi_privacy_cert, false);
+ if (!key)
+ failed = true;
+ crypto_rsa_key_free(key);
+ if (failed) {
+ wpa_printf(MSG_DEBUG,
+ "Invalid imsi_privacy_cert (%s) - disable network",
+ ssid->eap.imsi_privacy_cert);
+ return 1;
+ }
+ }
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
+#endif /* IEEE8021X_EAPOL */
+
return 0;
}
@@ -8080,6 +8529,13 @@ int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
return NO_MGMT_FRAME_PROTECTION;
}
+#ifdef CONFIG_OCV
+ /* Enable PMF if OCV is being enabled */
+ if (wpa_s->conf->pmf == NO_MGMT_FRAME_PROTECTION &&
+ ssid && ssid->ocv)
+ return MGMT_FRAME_PROTECTION_OPTIONAL;
+#endif /* CONFIG_OCV */
+
return wpa_s->conf->pmf;
}
@@ -8087,6 +8543,19 @@ int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
}
+#ifdef CONFIG_SAE
+bool wpas_is_sae_avoided(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ const struct wpa_ie_data *ie)
+{
+ return wpa_s->conf->sae_check_mfp &&
+ (!(ie->capabilities &
+ (WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR)) ||
+ wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION);
+}
+#endif /* CONFIG_SAE */
+
+
int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr)
{
if (wpa_s->current_ssid == NULL ||
@@ -8107,7 +8576,8 @@ int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s)
}
-void wpas_auth_failed(struct wpa_supplicant *wpa_s, char *reason)
+void wpas_auth_failed(struct wpa_supplicant *wpa_s, const char *reason,
+ const u8 *bssid)
{
struct wpa_ssid *ssid = wpa_s->current_ssid;
int dur;
@@ -8170,11 +8640,16 @@ void wpas_auth_failed(struct wpa_supplicant *wpa_s, char *reason)
ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
ssid->auth_failures, dur, reason) + 1;
char *msg = os_malloc(msg_len);
+ if (!msg)
+ return;
snprintf(msg, msg_len, format_str,
ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
ssid->auth_failures, dur, reason);
wpas_notify_ssid_temp_disabled(wpa_s, msg);
os_free(msg);
+
+ if (bssid)
+ os_memcpy(ssid->disabled_due_to, bssid, ETH_ALEN);
}
@@ -8191,8 +8666,15 @@ void wpas_clear_temp_disabled(struct wpa_supplicant *wpa_s,
}
ssid->disabled_until.sec = 0;
ssid->disabled_until.usec = 0;
- if (clear_failures)
+ if (clear_failures) {
ssid->auth_failures = 0;
+ } else if (!is_zero_ether_addr(ssid->disabled_due_to)) {
+ wpa_printf(MSG_DEBUG, "Mark BSSID " MACSTR
+ " ignored to allow a lower priority BSS, if any, to be tried next",
+ MAC2STR(ssid->disabled_due_to));
+ wpa_bssid_ignore_add(wpa_s, ssid->disabled_due_to);
+ os_memset(ssid->disabled_due_to, 0, ETH_ALEN);
+ }
}
@@ -8306,7 +8788,7 @@ void dump_freq_data(struct wpa_supplicant *wpa_s, const char *title,
*/
int get_shared_radio_freqs_data(struct wpa_supplicant *wpa_s,
struct wpa_used_freq_data *freqs_data,
- unsigned int len)
+ unsigned int len, bool exclude_current)
{
struct wpa_supplicant *ifs;
u8 bssid[ETH_ALEN];
@@ -8322,6 +8804,9 @@ int get_shared_radio_freqs_data(struct wpa_supplicant *wpa_s,
if (idx == len)
break;
+ if (exclude_current && ifs == wpa_s)
+ continue;
+
if (ifs->current_ssid == NULL || ifs->assoc_freq == 0)
continue;
@@ -8359,7 +8844,8 @@ int get_shared_radio_freqs_data(struct wpa_supplicant *wpa_s,
* are using the same radio as the current interface.
*/
int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
- int *freq_array, unsigned int len)
+ int *freq_array, unsigned int len,
+ bool exclude_current)
{
struct wpa_used_freq_data *freqs_data;
int num, i;
@@ -8370,7 +8856,8 @@ int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
if (!freqs_data)
return -1;
- num = get_shared_radio_freqs_data(wpa_s, freqs_data, len);
+ num = get_shared_radio_freqs_data(wpa_s, freqs_data, len,
+ exclude_current);
for (i = 0; i < num; i++)
freq_array[i] = freqs_data[i].freq;
@@ -8695,17 +9182,17 @@ int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s,
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,
+ si->data.signal,
dso->si_current_signal,
- si->avg_signal,
+ si->data.avg_signal,
dso->si_avg_signal,
- si->avg_beacon_signal,
+ si->data.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->data.signal = dso->si_current_signal;
+ si->data.avg_signal = dso->si_avg_signal;
+ si->data.avg_beacon_signal = dso->si_avg_beacon_signal;
si->current_noise = dso->si_current_noise;
break;
}
@@ -8756,3 +9243,43 @@ wpa_drv_get_scan_results2(struct wpa_supplicant *wpa_s)
return scan_res;
}
+
+
+static bool wpas_ap_link_address(struct wpa_supplicant *wpa_s, const u8 *addr)
+{
+ int i;
+
+ if (!wpa_s->valid_links)
+ return false;
+
+ for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+ if (!(wpa_s->valid_links & BIT(i)))
+ continue;
+
+ if (os_memcmp(wpa_s->links[i].bssid, addr, ETH_ALEN) == 0)
+ return true;
+ }
+
+ return false;
+}
+
+
+int wpa_drv_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
+ unsigned int wait, const u8 *dst, const u8 *src,
+ const u8 *bssid, const u8 *data, size_t data_len,
+ int no_cck)
+{
+ if (!wpa_s->driver->send_action)
+ return -1;
+
+ if (data_len > 0 && data[0] != WLAN_ACTION_PUBLIC) {
+ if (wpas_ap_link_address(wpa_s, dst))
+ dst = wpa_s->ap_mld_addr;
+
+ if (wpas_ap_link_address(wpa_s, bssid))
+ bssid = wpa_s->ap_mld_addr;
+ }
+
+ return wpa_s->driver->send_action(wpa_s->drv_priv, freq, wait, dst, src,
+ bssid, data, data_len, no_cck);
+}