feat(roaming): ignore WPA2-only APs on transition disable

This commit introduces a new feature to the roaming logic. If the
currently connected AP has the 'transition disable' bit set in its
RSN IE, the roaming logic will now ignore any scanned APs that only
support WPA2-PSK. This prevents a security downgrade when roaming in a
mixed WPA2/WPA3 environment.

A new Kconfig option, CONFIG_ESP_WIFI_IGNORE_WPA2_ONLY_ON_TRANSITION_DISABLE,
has been added to control this feature. It is disabled by default.
This commit is contained in:
Kapil Gupta
2025-07-25 14:06:51 +05:30
committed by BOT
parent 074b2d0f93
commit 7d18b82575
6 changed files with 58 additions and 1 deletions

View File

@@ -219,4 +219,13 @@ menu "Blacklist Configuration"
default 5
help
Maximum number of roaming candidates to consider. This also defines the size of the blacklist.
config ESP_WIFI_ROAMING_PREVENT_DOWNGRADE
bool "Prevent security downgrade when roaming"
default n
help
If the currently connected AP sends a "transition disable" bit,
this option will make the roaming logic ignore less secure APs.
This helps prevent security downgrades when roaming in a mixed
security environment (e.g., WPA2/WPA3).
endmenu # "Blacklist Configuration"

View File

@@ -605,8 +605,40 @@ static bool candidate_security_match(wifi_ap_record_t candidate)
return false;
}
#include "esp_wpas_glue.h"
static bool candidate_profile_match(wifi_ap_record_t candidate)
{
u8 transition_disable = wpa_supplicant_get_transition_disable();
#if CONFIG_ESP_WIFI_ROAMING_PREVENT_DOWNGRADE
if (transition_disable & TRANSITION_DISABLE_WPA3_PERSONAL) {
if (candidate.authmode == WIFI_AUTH_WPA2_PSK) {
return false;
}
}
if (transition_disable & TRANSITION_DISABLE_ENHANCED_OPEN) {
if (candidate.authmode == WIFI_AUTH_OPEN) {
return false;
}
}
if (transition_disable & TRANSITION_DISABLE_WPA3_ENTERPRISE) {
if (candidate.authmode == WIFI_AUTH_WPA2_ENTERPRISE) {
return false;
}
}
#if TODO // application doesn't have a way to know SAE-PK enabled AP atm
if (transition_disable & TRANSITION_DISABLE_SAE_PK) {
/* This is a simplification. A more accurate check would involve
* parsing the candidate's RSN IE to see if it supports SAE-PK.
* For now, we reject all SAE APs if SAE-PK is enforced. */
if (candidate.authmode == WIFI_AUTH_WPA3_PSK) {
return false;
}
}
#endif
#endif
return candidate_security_match(candidate);
}

View File

@@ -189,4 +189,9 @@ void wpa_sm_disassociate(struct wpa_sm *sm, int reason_code)
{
/*check if need clear internal state and data value*/
}
u8 wpa_supplicant_get_transition_disable(void)
{
return wpa_sm_get_transition_disable(&gWpaSm);
}
#endif

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -35,4 +35,6 @@ void wpa_supplicant_transition_disable(struct wpa_sm *sm, u8 bitmap);
int hostapd_send_eapol(const u8 *source, const u8 *sta_addr,
const u8 *data, size_t data_len);
u8 wpa_supplicant_get_transition_disable(void);
#endif /* WPAS_GLUE_H */

View File

@@ -1340,6 +1340,7 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
if (ie.transition_disable) {
wpa_supplicant_transition_disable(sm, ie.transition_disable[0]);
sm->transition_disable = ie.transition_disable[0];
}
if (sm->key_install && sm->key_info & WPA_KEY_INFO_INSTALL && sm->use_ext_key_id) {
@@ -1357,6 +1358,11 @@ failed:
wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
}
u8 wpa_sm_get_transition_disable(struct wpa_sm *sm)
{
return sm->transition_disable;
}
static int wpa_supplicant_activate_ptk(struct wpa_sm *sm)
{
int keylen;

View File

@@ -86,6 +86,7 @@ struct wpa_sm {
struct wpa_gtk_data gd; //used for calllback save param
u16 key_info; //used for txcallback param
u16 txcb_flags;
u8 transition_disable;
bool ap_notify_completed_rsne;
wifi_pmf_config_t pmf_cfg;
u8 eapol1_count;
@@ -208,6 +209,8 @@ int wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher,
int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len);
u8 wpa_sm_get_transition_disable(struct wpa_sm *sm);
int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
const struct wpa_eapol_key *key, struct wpa_ptk *ptk);
#endif /* WPA_I_H */