[PATCH] AP: Fix MLD STA re-authentication with changed per-link address

Jose Ignacio Tornos Martinez jtornosm at redhat.com
Mon Jul 27 09:43:19 PDT 2026


When an MLD STA reconnects after a firmware crash recovery, mac80211
generates new random per-link addresses for the new connection. If
the AP still has the STA entry from the previous connection, the
authentication response is sent to the old per-link address which
the STA does not ACK, preventing reconnection until the AP's
inactivity timer (~300s) removes the stale entry.

This happens because the driver cannot translate the new per-link
address (it is not in the STA table yet), so mgmt->sa in the auth
frame contains the raw new per-link address while sa (from the ML
element) contains the MLD address. The stale driver entry still maps
the MLD address to the old per-link address.

Fix this by detecting the per-link address change in handle_auth():
when mgmt->sa differs from sa for a known MLD STA, update the stored
per-link address and mld_assoc_link_id before the existing code path
clears mld_info and re-adds the STA to the driver with the correct
address.

Update mld_assoc_link_id to the current link so that when the
existing ap_sta_re_add() runs, the STA is added as the primary MLD
STA. Without this, if the STA authenticates on a different link than
the previous association, mld_link_sta would be set to true and the
kernel would not set up proper MLD-to-per-link address translation.

Clear added_unassoc so that the existing code paths can proceed:
the mld_info clearing block resets stale partner link addresses, and
the FULL_AP_CLIENT_STATE flow runs ap_sta_re_add() to remove the old
STA from the driver and re-add it with the correct per-link address.

For PMF-protected authorized stations, immediately deauthorize the
STA and stop any running SA Query rather than starting a new SA Query
procedure. SA Query is designed to verify whether the old STA is
still reachable, but in this scenario it can never succeed: the SA
Query is sent to the MLD address which the driver translates to the
old per-link address that the STA no longer uses after its firmware
restart. Waiting for the SA Query timeout (~5s) causes the STA to
give up on that link and fall back to a different link, resulting in
a single-link association instead of the expected multi-link setup.
Skipping SA Query is safe because the full 4-Way Handshake that
follows the authentication will verify the STA's credentials before
any protected frames are exchanged. This brings MLD (Wi-Fi 7) crash
recovery in line with non-MLD (Wi-Fi 6) stations, where
reconnection after firmware restart works without such delays.

Signed-off-by: Jose Ignacio Tornos Martinez <jtornosm at redhat.com>
---
Note: I will have limited availability from mid-August to
mid-September. I will address any review feedback before then
or promptly after returning.

 src/ap/ieee802_11.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 418582407..1625deda9 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -4549,6 +4549,24 @@ static void handle_auth(struct hostapd_data *hapd,
 #endif /* CONFIG_ENC_ASSOC || CONFIG_IEEE8021X_AUTH */
 
 #ifdef CONFIG_IEEE80211BE
+	if (auth_transaction == 1 && mld_sta &&
+	    !is_zero_ether_addr(sta->mld_info.links[hapd->mld_link_id].peer_addr) &&
+	    os_memcmp(mgmt->sa, sa, ETH_ALEN) != 0) {
+		wpa_printf(MSG_DEBUG,
+			   "MLD: " MACSTR " per-link address changed on link %u",
+			   MAC2STR(sa), hapd->mld_link_id);
+		os_memcpy(sta->mld_info.links[hapd->mld_link_id].peer_addr,
+			  mgmt->sa, ETH_ALEN);
+		sta->mld_assoc_link_id = hapd->mld_link_id;
+		if ((sta->flags & WLAN_STA_MFP) &&
+		    ap_sta_is_authorized(sta)) {
+			ap_sta_set_authorized(hapd, sta, 0);
+			ap_sta_stop_sa_query(hapd, sta);
+			sta->sa_query_timed_out = 0;
+		}
+		sta->added_unassoc = 0;
+	}
+
 	/* Set the non-AP MLD information based on the initial Authentication
 	 * frame. Once the STA entry has been added to the driver, the driver
 	 * will translate addresses in the frame and we need to avoid overriding
-- 
2.54.0




More information about the Hostap mailing list