[PATCH 4/6] hostapd: Allow STA association after SA Query timeout

Ramasamy Kaliappan ramasamy.kaliappan at oss.qualcomm.com
Thu Aug 6 09:31:45 PDT 2026


When a PMF-protected non-AP MLD STA is already associated using M1 as
its MLD address and L1/L2 as link addresses, it may later send an
association request using the same M1 address but different link
addresses.

In this case, the kernel does not perform MLD address translation and
sets the no_sta flag. The AP MLD responds to the source address with a
temporary rejection (with no_sta set) and starts an SA Query
procedure.

When a subsequent association request is received after the SA Query
comeback time with no_sta set, hostapd removes the existing STA entry
from the driver and re-adds the STA based on the new capabilities and
MLD information from the association request.

The AP MLD then sends an association response with status SUCCESS to the
STA address with no_sta cleared, allowing the reassociation with the
new link addresses to complete.

Co-developed-by: Rameshkumar Sundaram <rameshkumar.sundaram at oss.qualcomm.com>
Signed-off-by: Rameshkumar Sundaram <rameshkumar.sundaram at oss.qualcomm.com>
Signed-off-by: Ramasamy Kaliappan <ramasamy.kaliappan at oss.qualcomm.com>
---
 src/ap/ieee802_11.c | 70 ++++++++++++++++++++++++++++++++++++++++++++-
 src/ap/sta_info.c   |  4 +--
 src/ap/sta_info.h   |  2 ++
 3 files changed, 73 insertions(+), 3 deletions(-)

diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 45e1386d7a11..3b71b5edc311 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -6644,7 +6644,7 @@ static int add_associated_sta(struct hostapd_data *hapd,
 		   wpa_auth_sta_ft_tk_already_set(sta->wpa_sm),
 		   wpa_auth_sta_fils_tk_already_set(sta->wpa_sm));
 
-	if (!mld_link_sta && !sta->added_unassoc &&
+	if (!ap_sta_is_mld(hapd, sta) && !sta->added_unassoc &&
 	    (!(sta->flags & WLAN_STA_AUTHORIZED) ||
 	     (reassoc && sta->ft_over_ds && sta->auth_alg == WLAN_AUTH_FT) ||
 	     (!wpa_auth_sta_ft_tk_already_set(sta->wpa_sm) &&
@@ -7601,6 +7601,74 @@ static void handle_assoc(struct hostapd_data *hapd,
 	}
 #endif /* CONFIG_FILS */
 
+	if ((sta->flags & WLAN_STA_MFP) &&
+	     sta->sa_query_timed_out &&
+	     sta->mld_info.mld_sta) {
+		struct ieee802_11_elems elems;
+		u8 mld_addr[ETH_ALEN] = {0};
+		/*
+		 * Clean up the existing STA info
+		 * allowing association with new sta info based on
+		 * the association request after the SA Query timeout.
+		 */
+		wpa_auth_sta_deinit(sta->wpa_sm);
+		sta->wpa_sm = NULL;
+		clear_wpa_sm_for_each_partner_link(hapd, sta);
+		ap_sta_remove_link_sta(hapd, sta);
+		hostapd_drv_sta_remove(hapd, sta->addr);
+		sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_AUTHORIZED);
+		ap_sta_set_sa_query_timeout(hapd, sta, 0);
+
+		if (ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed) {
+			wpa_printf(MSG_DEBUG, "Failed to parse elements");
+			goto fail;
+		}
+
+		os_memset(&sta->mld_info, 0x00, sizeof(sta->mld_info));
+
+		if (!hostapd_process_ml_assoc_req_addr(hapd,
+						elems.basic_mle,
+						elems.basic_mle_len,
+						mld_addr)) {
+			u8 link_id = hapd->mld_link_id;
+
+			sta->mld_info.mld_sta = true;
+			sta->mld_assoc_link_id = link_id;
+
+			os_memcpy(sta->mld_info.common_info.mld_addr, mld_addr,
+					ETH_ALEN);
+			os_memcpy(sta->mld_info.links[link_id].peer_addr,
+					mgmt->sa, ETH_ALEN);
+			os_memcpy(sta->mld_info.links[link_id].local_addr,
+					hapd->own_addr, ETH_ALEN);
+		}
+
+		wpa_printf(MSG_DEBUG, "Allowing association of STA "
+				MACSTR " after timed out SA Query procedure",
+				MAC2STR(sta->addr));
+		if (hostapd_sta_add(hapd, sta->addr, 0, 0,
+				    sta->supported_rates,
+				    sta->supported_rates_len,
+				    0, NULL, NULL, NULL, 0, NULL, 0,
+				    NULL, 0, NULL,
+				    sta->flags, 0, 0, 0, 0,
+				    mgmt->sa, 0,
+				    0, 0)) {
+			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+				       HOSTAPD_LEVEL_NOTICE,
+				       "Could not add STA to kernel driver");
+			goto fail;
+		}
+		/*
+		 * The station has been added to the driver.
+		 * When sending the (Re)Association response frame,
+		 * reset the no_sta flag and send the response to sta->addr
+		 * instead of the source address.
+		 */
+		no_sta = false;
+		dst = sta->addr;
+	}
+
 	/* followed by SSID and Supported rates; and HT capabilities if 802.11n
 	 * is used */
 	resp = check_assoc_ies(hapd, sta, pos, left,
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index feb1282078ff..e9e33f040c76 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -2070,8 +2070,8 @@ int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
 
 
 #ifdef CONFIG_IEEE80211BE
-static void ap_sta_remove_link_sta(struct hostapd_data *hapd,
-				   struct sta_info *sta)
+void ap_sta_remove_link_sta(struct hostapd_data *hapd,
+			    struct sta_info *sta)
 {
 	struct hostapd_data *tmp_hapd;
 
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index baac3865b553..42e4f7f16bce 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -469,6 +469,8 @@ void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
 					    unsigned timeout);
 int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
 						   struct sta_info *sta);
+void ap_sta_remove_link_sta(struct hostapd_data *hapd,
+			    struct sta_info *sta);
 int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta);
 
 void ap_free_sta_pasn(struct hostapd_data *hapd, struct sta_info *sta);
-- 
2.34.1




More information about the Hostap mailing list