[RFC PATCH v1 02/13] FT: Update target AP MLO state before response processing

Jeff Hansen x at jeffhansen.com
Fri Sep 11 12:20:01 PDT 2026


Populate the WPA state machine with the target AP MLD and per-link
security elements before processing an over-the-air FT response.
Preserve the non-AP MLD link addresses assigned by the driver while
replacing AP-specific state.

Signed-off-by: Jeff Hansen <x at jeffhansen.com>
---
 src/rsn_supp/wpa.c   | 23 ++++++++++++++++++
 src/rsn_supp/wpa.h   | 12 ++++++++++
 wpa_supplicant/sme.c | 56 +++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 90 insertions(+), 1 deletion(-)

diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 155bcba11..6aff72b91 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -5077,6 +5077,29 @@ int wpa_sm_set_mlo_params(struct wpa_sm *sm, const struct wpa_sm_mlo *mlo)
 }
 
 
+#ifdef CONFIG_IEEE80211BE
+int wpa_sm_set_ft_mlo_params(struct wpa_sm *sm,
+			     const struct wpa_sm_mlo *mlo)
+{
+	u8 addr[MAX_NUM_MLD_LINKS][ETH_ALEN];
+	int i, ret;
+
+	if (!sm)
+		return -1;
+
+	for (i = 0; i < MAX_NUM_MLD_LINKS; i++)
+		os_memcpy(addr[i], sm->mlo.links[i].addr, ETH_ALEN);
+
+	ret = wpa_sm_set_mlo_params(sm, mlo);
+
+	for (i = 0; i < MAX_NUM_MLD_LINKS; i++)
+		os_memcpy(sm->mlo.links[i].addr, addr[i], ETH_ALEN);
+
+	return ret;
+}
+#endif /* CONFIG_IEEE80211BE */
+
+
 /**
  * wpa_sm_set_own_addr - Set own MAC address
  * @sm: Pointer to WPA state machine data from wpa_sm_init()
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 4983903da..0cc5a8007 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -294,6 +294,10 @@ bool wpa_eppke_is_completed(struct wpa_sm *sm);
 bool wpa_eap_over_auth_frame_is_completed(struct wpa_sm *sm);
 void wpa_sm_pmksa_cache_reconfig(struct wpa_sm *sm);
 int wpa_sm_set_mlo_params(struct wpa_sm *sm, const struct wpa_sm_mlo *mlo);
+#ifdef CONFIG_IEEE80211BE
+int wpa_sm_set_ft_mlo_params(struct wpa_sm *sm,
+			     const struct wpa_sm_mlo *mlo);
+#endif /* CONFIG_IEEE80211BE */
 void wpa_sm_set_driver_bss_selection(struct wpa_sm *sm,
 				     bool driver_bss_selection);
 bool wpa_sm_uses_spp_amsdu(struct wpa_sm *sm);
@@ -567,6 +571,14 @@ static inline int wpa_sm_set_mlo_params(struct wpa_sm *sm,
 	return 0;
 }
 
+#ifdef CONFIG_IEEE80211BE
+static inline int wpa_sm_set_ft_mlo_params(
+	struct wpa_sm *sm, const struct wpa_sm_mlo *mlo)
+{
+	return 0;
+}
+#endif /* CONFIG_IEEE80211BE */
+
 static inline void wpa_sm_set_driver_bss_selection(struct wpa_sm *sm,
 						   bool driver_bss_selection)
 {
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index f4c649eed..0c226aa31 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -1137,6 +1137,55 @@ static void wpas_sme_set_mlo_links(struct wpa_supplicant *wpa_s,
 }
 
 
+#if defined(CONFIG_IEEE80211R) && defined(CONFIG_IEEE80211BE)
+static int wpas_sme_set_ft_mlo_params(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_sm_mlo mlo;
+	int i;
+
+	if (!wpa_s->valid_links)
+		return 0;
+
+	os_memset(&mlo, 0, sizeof(mlo));
+	os_memcpy(mlo.ap_mld_addr, wpa_s->ap_mld_addr, ETH_ALEN);
+	mlo.assoc_link_id = wpa_s->mlo_assoc_link_id;
+	mlo.valid_links = wpa_s->valid_links;
+	mlo.req_links = wpa_s->valid_links;
+
+	for_each_link(mlo.req_links, i) {
+		struct wpa_bss *bss = wpa_s->links[i].bss;
+		const u8 *ie;
+
+		if (!bss)
+			return -1;
+
+		os_memcpy(mlo.links[i].bssid, wpa_s->links[i].bssid,
+			  ETH_ALEN);
+		ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+		mlo.links[i].ap_rsne = (u8 *) ie;
+		mlo.links[i].ap_rsne_len = ie ? 2 + ie[1] : 0;
+		ie = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
+		mlo.links[i].ap_rsnxe = (u8 *) ie;
+		mlo.links[i].ap_rsnxe_len = ie ? 2 + ie[1] : 0;
+		ie = wpa_bss_get_vendor_ie(
+			bss, RSNE_OVERRIDE_IE_VENDOR_TYPE);
+		mlo.links[i].ap_rsnoe = (u8 *) ie;
+		mlo.links[i].ap_rsnoe_len = ie ? 2 + ie[1] : 0;
+		ie = wpa_bss_get_vendor_ie(
+			bss, RSNE_OVERRIDE_2_IE_VENDOR_TYPE);
+		mlo.links[i].ap_rsno2e = (u8 *) ie;
+		mlo.links[i].ap_rsno2e_len = ie ? 2 + ie[1] : 0;
+		ie = wpa_bss_get_vendor_ie(
+			bss, RSNXE_OVERRIDE_IE_VENDOR_TYPE);
+		mlo.links[i].ap_rsnxoe = (u8 *) ie;
+		mlo.links[i].ap_rsnxoe_len = ie ? 2 + ie[1] : 0;
+	}
+
+	return wpa_sm_set_ft_mlo_params(wpa_s->wpa, &mlo);
+}
+#endif /* CONFIG_IEEE80211R && CONFIG_IEEE80211BE */
+
+
 static void sme_add_assoc_req_ie(struct wpa_supplicant *wpa_s,
 				 const struct wpabuf *buf)
 {
@@ -4393,12 +4442,17 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
 	if (data->auth.auth_type == WLAN_AUTH_FT) {
 		const u8 *ric_ies = NULL;
 		size_t ric_ies_len = 0;
+		int ret = 0;
 
 		if (wpa_s->ric_ies) {
 			ric_ies = wpabuf_head(wpa_s->ric_ies);
 			ric_ies_len = wpabuf_len(wpa_s->ric_ies);
 		}
-		if (wpa_ft_process_response(wpa_s->wpa, data->auth.ies,
+#ifdef CONFIG_IEEE80211BE
+		ret = wpas_sme_set_ft_mlo_params(wpa_s);
+#endif /* CONFIG_IEEE80211BE */
+		if (ret < 0 ||
+		    wpa_ft_process_response(wpa_s->wpa, data->auth.ies,
 					    data->auth.ies_len, 0,
 					    data->auth.peer,
 					    ric_ies, ric_ies_len) < 0) {
-- 
2.53.0




More information about the Hostap mailing list