Compare commits

...

1 Commits

Author SHA1 Message Date
John Crispin
55691669ea hostapd: fix VLAN assignment lost on MPSK roaming between bands
When a client roams between bands (2.4/5/6 GHz) using RADIUS-based
Multi-PSK (MPSK), the VLAN assignment is lost and the client gets
placed on the default VLAN 1.

Root cause: On initial authentication, RADIUS provides both the PSK
and VLAN assignment. On subsequent roaming events, when using cached
credentials (PMK caching), RADIUS only validates the PSK without
re-sending the VLAN assignment, causing the client to fall back to
VLAN 1.

Solution: Store the VLAN ID in the cached PSK structure when first
assigned by RADIUS. On roaming, if RADIUS doesn't provide a VLAN,
restore it from the cached PSK entry.

The VLAN cache lifetime matches the PSK cache, automatically expiring
when the station disconnects.

Fixes: WIFI-14179
Signed-off-by: John Crispin <john@phrozen.org>
2025-10-02 07:33:11 +02:00

View File

@@ -0,0 +1,55 @@
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -153,6 +153,7 @@ struct hostapd_sta_wpa_psk_short {
unsigned int is_passphrase:1;
u8 psk[PMK_LEN];
char passphrase[MAX_PASSPHRASE_LEN + 1];
+ int vlan_id;
int ref; /* (number of references held) - 1 */
};
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -2404,6 +2404,42 @@ int ieee802_11_set_radius_info(struct ho
vlan_id->tagged[0] ? "+" : "");
return -1;
}
+
+ /* Store VLAN ID with cached PSK for MPSK roaming support */
+ if (hapd->conf->ssid.dynamic_vlan && psk && vlan_id->notempty &&
+ vlan_id->untagged > 0) {
+ struct hostapd_sta_wpa_psk_short *psk_entry;
+
+ for (psk_entry = psk; psk_entry; psk_entry = psk_entry->next) {
+ psk_entry->vlan_id = vlan_id->untagged;
+ wpa_printf(MSG_DEBUG,
+ "RADIUS MPSK: Stored VLAN %d with PSK for "
+ MACSTR, vlan_id->untagged,
+ MAC2STR(sta->addr));
+ }
+ }
+
+ /* Restore VLAN from cached PSK if not provided by RADIUS */
+ if (hapd->conf->ssid.dynamic_vlan && !vlan_id->notempty && sta->psk) {
+ struct hostapd_sta_wpa_psk_short *psk_entry;
+ int cached_vlan = 0;
+
+ for (psk_entry = sta->psk; psk_entry; psk_entry = psk_entry->next) {
+ if (psk_entry->vlan_id > 0) {
+ cached_vlan = psk_entry->vlan_id;
+ break;
+ }
+ }
+
+ if (cached_vlan > 0) {
+ vlan_id->notempty = 1;
+ vlan_id->untagged = cached_vlan;
+ wpa_printf(MSG_DEBUG,
+ "RADIUS MPSK: Restored VLAN %d from cached PSK for " MACSTR,
+ cached_vlan, MAC2STR(sta->addr));
+ }
+ }
+
if (ap_sta_set_vlan(hapd, sta, vlan_id) < 0)
return -1;
if (sta->vlan_id)