[PATCH wireless 2/2] wifi: mac80211: set the link addresses of a 4-address AP_VLAN before its links

From: Piotr Kubik

Date: Tue Oct 20 2026 - 08:47:11 EST


ieee80211_set_sta_4addr() gives the AP_VLAN of a 4-address MLD station
the links of that station. It added the links first and set
wdev->links[].addr afterwards, from the link_conf of the AP_VLAN
itself. ieee80211_link_init() takes the address of a new link from
wdev->links[].addr, so a link that the station gained later came up
with the zero address that an earlier call had set, and the copy from
its own link_conf kept it at zero. With two such links,
ieee80211_check_dup_link_addrs() refuses the change with -EALREADY,
and the station stays on the AP interface instead of its AP_VLAN.

Set the addresses from the link_conf of the AP before the links are
added, as the AP_VLAN link update in link.c does.

Fixes: 469d5d5a3b7a ("wifi: mac80211: synchronize valid links for WDS AP_VLAN interfaces")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Piotr Kubik <piotr@xxxxxxxx>
---
net/mac80211/cfg.c | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2823,26 +2823,29 @@ static int ieee80211_set_sta_4addr(struc

wdev->valid_links = new_links;

- err = ieee80211_vif_set_links(sdata, new_links, 0);
- if (err) {
- wdev->valid_links = orig_links;
- return err;
- }
-
master_iter = master->vif.valid_links;

+ /* ieee80211_link_init() takes the address of a new link from
+ * wdev->links, so set it before the links are added.
+ */
for_each_set_bit(link_id, &master_iter,
IEEE80211_MLD_MAX_NUM_LINKS) {
if (!(sta_links & BIT(link_id))) {
eth_zero_addr(wdev->links[link_id].addr);
} else {
link_conf = wiphy_dereference(wiphy,
- vif->link_conf[link_id]);
+ master->vif.link_conf[link_id]);

ether_addr_copy(wdev->links[link_id].addr,
link_conf->bssid);
}
}
+
+ err = ieee80211_vif_set_links(sdata, new_links, 0);
+ if (err) {
+ wdev->valid_links = orig_links;
+ return err;
+ }
}

rcu_assign_pointer(sdata->u.vlan.sta, sta);