[RFC PATCH v1 03/13] FT: Include MLO link data in MIC calculation
Jeff Hansen
x at jeffhansen.com
Fri Sep 11 12:20:01 PDT 2026
Cover the non-AP MLD link addresses in FT request MICs. Reconstruct the
per-link RSNE and RSNXE sequence and cover the AP link BSSIDs when
validating FT reassociation response MICs.
Signed-off-by: Jeff Hansen <x at jeffhansen.com>
---
src/rsn_supp/wpa_ft.c | 96 ++++++++++++++++++++++++++++++++++++++++---
1 file changed, 90 insertions(+), 6 deletions(-)
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index fb46fa2f4..b9d151736 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -220,6 +220,13 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
int rsnxe_used;
int res;
u8 mic_control;
+ struct wpabuf *extra = NULL;
+ u16 mlo_links = 0;
+
+#ifdef CONFIG_IEEE80211BE
+ mlo_links = sm->mlo.req_links ? sm->mlo.req_links :
+ sm->mlo.valid_links;
+#endif /* CONFIG_IEEE80211BE */
sm->ft_completed = 0;
sm->ft_reassoc_completed = 0;
@@ -469,18 +476,36 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
*elem_count = 3 + ieee802_11_ie_count(ric_ies, ric_ies_len);
if (rsnxe_len)
*elem_count += 1;
+#ifdef CONFIG_IEEE80211BE
+ if (mlo_links) {
+ int link_id;
+
+ extra = wpabuf_alloc(MAX_NUM_MLD_LINKS * ETH_ALEN);
+ if (!extra) {
+ os_free(buf);
+ return NULL;
+ }
+
+ for_each_link(mlo_links, link_id)
+ wpabuf_put_data(extra,
+ sm->mlo.links[link_id].addr,
+ ETH_ALEN);
+ }
+#endif /* CONFIG_IEEE80211BE */
if (wpa_ft_mic(sm->key_mgmt, kck, kck_len,
sm->own_addr, target_ap, 5,
((u8 *) mdie) - 2, 2 + sizeof(*mdie),
ftie_pos, 2 + *ftie_len,
(u8 *) rsnie, 2 + rsnie->len, ric_ies,
ric_ies_len, rsnxe_len ? rsnxe : NULL, rsnxe_len,
- NULL,
+ extra,
fte_mic) < 0) {
wpa_printf(MSG_INFO, "FT: Failed to calculate MIC");
+ wpabuf_free(extra);
os_free(buf);
return NULL;
}
+ wpabuf_free(extra);
}
*len = pos - buf;
@@ -1036,6 +1061,13 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
int own_rsnxe_used;
size_t mic_len;
int ret = -1;
+ struct wpabuf *extra = NULL, *rsne = NULL, *rsnxe = NULL;
+ u16 mlo_links = 0;
+
+#ifdef CONFIG_IEEE80211BE
+ mlo_links = sm->mlo.req_links ? sm->mlo.req_links :
+ sm->mlo.valid_links;
+#endif /* CONFIG_IEEE80211BE */
os_memset(&parse, 0, sizeof(parse));
@@ -1138,9 +1170,54 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
}
count = 3;
+#ifdef CONFIG_IEEE80211BE
+ if (mlo_links) {
+ int link_id;
+
+ count = 2; /* MDE and FTE */
+ extra = wpabuf_alloc(MAX_NUM_MLD_LINKS * ETH_ALEN);
+ rsne = wpabuf_alloc(MAX_NUM_MLD_LINKS *
+ (2 + 255 + 2 + PMKID_LEN));
+ rsnxe = wpabuf_alloc(MAX_NUM_MLD_LINKS * 257);
+ if (!extra || !rsne || !rsnxe)
+ goto fail;
+
+ for_each_link(mlo_links, link_id) {
+ struct wpa_sm_link *link = &sm->mlo.links[link_id];
+ u8 rsne_buf[2 + 255 + 2 + PMKID_LEN];
+ size_t rsne_len = link->ap_rsne_len;
+
+ if (!link->ap_rsne || !rsne_len ||
+ rsne_len > 2 + 255) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Invalid AP RSNE for MLO link %d",
+ link_id);
+ goto fail;
+ }
+
+ os_memcpy(rsne_buf, link->ap_rsne, rsne_len);
+ if (wpa_insert_pmkid(rsne_buf, &rsne_len,
+ sm->pmk_r1_name, true) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Failed to add PMKR1Name for MLO link %d",
+ link_id);
+ goto fail;
+ }
+ wpabuf_put_data(rsne, rsne_buf, rsne_len);
+ count++;
+
+ if (link->ap_rsnxe && link->ap_rsnxe_len) {
+ wpabuf_put_data(rsnxe, link->ap_rsnxe,
+ link->ap_rsnxe_len);
+ count++;
+ }
+ wpabuf_put_data(extra, link->bssid, ETH_ALEN);
+ }
+ }
+#endif /* CONFIG_IEEE80211BE */
if (parse.ric)
count += ieee802_11_ie_count(parse.ric, parse.ric_len);
- if (parse.rsnxe)
+ if (parse.rsnxe && !mlo_links)
count++;
if (parse.fte_elem_count != count) {
wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
@@ -1160,11 +1237,15 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
if (wpa_ft_mic(sm->key_mgmt, kck, kck_len, sm->own_addr, src_addr, 6,
parse.mdie - 2, parse.mdie_len + 2,
parse.ftie - 2, parse.ftie_len + 2,
- parse.rsn - 2, parse.rsn_len + 2,
+ mlo_links ? wpabuf_head(rsne) : parse.rsn - 2,
+ mlo_links ? wpabuf_len(rsne) : parse.rsn_len + 2,
parse.ric, parse.ric_len,
- parse.rsnxe ? parse.rsnxe - 2 : NULL,
- parse.rsnxe ? parse.rsnxe_len + 2 : 0,
- NULL,
+ mlo_links ?
+ (wpabuf_len(rsnxe) ? wpabuf_head(rsnxe) : NULL) :
+ (parse.rsnxe ? parse.rsnxe - 2 : NULL),
+ mlo_links ? wpabuf_len(rsnxe) :
+ (parse.rsnxe ? parse.rsnxe_len + 2 : 0),
+ extra,
mic) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
goto fail;
@@ -1278,6 +1359,9 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
ret = 0;
fail:
+ wpabuf_free(extra);
+ wpabuf_free(rsne);
+ wpabuf_free(rsnxe);
wpa_ft_parse_ies_free(&parse);
return ret;
}
--
2.53.0
More information about the Hostap
mailing list