From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Jeff Hansen Date: Sat, 5 Sep 2026 15:00:00 -0600 Subject: [PATCH] wifi: mac80211: preserve MLO link addresses during FT An MLO FT reassociation MIC covers the non-AP MLD link addresses. Keep the addresses from the current association while authenticating with the target AP and use the same addresses when constructing the reassociation request. Without this, ieee80211_mgd_auth() tears down the current links before it creates the target authentication link, and ieee80211_mgd_assoc() generates new random addresses for the remaining links. Userspace has already calculated the FT MIC by then, so the target AP rejects the reassociation with WLAN_STATUS_INVALID_FTIE. Limit the address preservation to FT. Other authentication methods retain the existing behavior of selecting fresh local link addresses. Signed-off-by: Jeff Hansen --- net/mac80211/ieee80211_i.h | 2 ++ net/mac80211/mlme.c | 29 ++++++++++++++++++++++++++--- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 111111111111..222222222222 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -430,6 +430,8 @@ struct ieee80211_mgd_auth_data { int link_id; u8 ap_addr[ETH_ALEN] __aligned(2); + u8 link_addr[IEEE80211_MLD_MAX_NUM_LINKS][ETH_ALEN]; + u16 valid_link_addrs; u16 trans, status; size_t data_len; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 111111111111..222222222222 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -9020,6 +9020,10 @@ void ieee80211_mgd_setup_link(struct ieee80211_link_data *link) if (sdata->u.mgd.assoc_data) ether_addr_copy(link->conf->addr, sdata->u.mgd.assoc_data->link[link_id].addr); + else if (sdata->u.mgd.auth_data && + sdata->u.mgd.auth_data->valid_link_addrs & BIT(link_id)) + ether_addr_copy(link->conf->addr, + sdata->u.mgd.auth_data->link_addr[link_id]); else if (sdata->u.mgd.reconf.add_links_data) ether_addr_copy(link->conf->addr, sdata->u.mgd.reconf.add_links_data->link[link_id].addr); @@ -9453,6 +9457,23 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, /* prep auth_data so we don't go into idle on disassoc */ ifmgd->auth_data = auth_data; + if (req->auth_type == NL80211_AUTHTYPE_FT && req->ap_mld_addr && + ifmgd->associated) { + int link_id; + + for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; + link_id++) { + struct ieee80211_link_data *link; + + link = sdata_dereference(sdata->link[link_id], sdata); + if (link && is_valid_ether_addr(link->conf->addr)) { + ether_addr_copy(auth_data->link_addr[link_id], + link->conf->addr); + auth_data->valid_link_addrs |= BIT(link_id); + } + } + } + /* If this is continuation of an ongoing SAE authentication exchange * (i.e., request to send SAE Confirm) and the peer has already * confirmed, mark authentication completed since we are about to send @@ -9886,11 +9907,16 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, goto err_free; } - link = sdata_dereference(sdata->link[i], sdata); - if (link) + link = sdata_dereference(sdata->link[i], sdata); + if (ifmgd->auth_data && + ifmgd->auth_data->valid_link_addrs & BIT(i)) { + ether_addr_copy(assoc_data->link[i].addr, + ifmgd->auth_data->link_addr[i]); + } else if (link) { ether_addr_copy(assoc_data->link[i].addr, link->conf->addr); - else + } else { eth_random_addr(assoc_data->link[i].addr); + } sband = local->hw.wiphy->bands[link_cbss->channel->band]; if (match_auth && i == assoc_link_id && link) -- 2.50.1