Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

wifi: mac80211: synchronize valid links for WDS AP_VLAN interfaces

The current code does not provide any link-configuration support
for 4-address mode WDS AP_VLAN interfaces in MLO setups, preventing
MLD stations from being added correctly. Add the required handling
to enable proper integration of 4-address WDS stations into
an MLO environment.

When a 4-address station associates with an MLO AP, compute the
intersection of valid links between the master AP interface and
the station's advertised capabilities. Configure the AP_VLAN interface
with only these common links to ensure correct data-path operation.

This update ensures AP_VLAN interfaces correctly track link-state
transitions and maintain consistent addressing across all active MLO links.

Co-developed-by: Muna Sinada <muna.sinada@oss.qualcomm.com>
Signed-off-by: Muna Sinada <muna.sinada@oss.qualcomm.com>
Signed-off-by: Tamizh Chelvam Raja <tamizh.raja@oss.qualcomm.com>
Link: https://patch.msgid.link/20260326164723.553927-2-tamizh.raja@oss.qualcomm.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>

authored by

Tamizh Chelvam Raja and committed by
Johannes Berg
469d5d5a b5b8e295

+101 -19
+62 -5
net/mac80211/cfg.c
··· 2527 2527 return 0; 2528 2528 } 2529 2529 2530 + static int ieee80211_set_sta_4addr(struct ieee80211_local *local, 2531 + struct ieee80211_sub_if_data *sdata, 2532 + struct sta_info *sta) 2533 + { 2534 + struct ieee80211_vif *vif = &sdata->vif; 2535 + struct wiphy *wiphy = local->hw.wiphy; 2536 + struct ieee80211_sub_if_data *master; 2537 + struct ieee80211_bss_conf *link_conf; 2538 + struct wireless_dev *wdev; 2539 + unsigned long master_iter; 2540 + int link_id; 2541 + int err; 2542 + 2543 + lockdep_assert_wiphy(local->hw.wiphy); 2544 + 2545 + if (sdata->u.vlan.sta) 2546 + return -EBUSY; 2547 + 2548 + wdev = &sdata->wdev; 2549 + master = container_of(sdata->bss, 2550 + struct ieee80211_sub_if_data, 2551 + u.ap); 2552 + 2553 + if (sta->sta.valid_links) { 2554 + u16 sta_links = sta->sta.valid_links; 2555 + u16 new_links = master->vif.valid_links & sta_links; 2556 + u16 orig_links = wdev->valid_links; 2557 + 2558 + wdev->valid_links = new_links; 2559 + 2560 + err = ieee80211_vif_set_links(sdata, new_links, 0); 2561 + if (err) { 2562 + wdev->valid_links = orig_links; 2563 + return err; 2564 + } 2565 + 2566 + master_iter = master->vif.valid_links; 2567 + 2568 + for_each_set_bit(link_id, &master_iter, 2569 + IEEE80211_MLD_MAX_NUM_LINKS) { 2570 + if (!(sta_links & BIT(link_id))) { 2571 + eth_zero_addr(wdev->links[link_id].addr); 2572 + } else { 2573 + link_conf = wiphy_dereference(wiphy, 2574 + vif->link_conf[link_id]); 2575 + 2576 + ether_addr_copy(wdev->links[link_id].addr, 2577 + link_conf->bssid); 2578 + } 2579 + } 2580 + } 2581 + 2582 + rcu_assign_pointer(sdata->u.vlan.sta, sta); 2583 + __ieee80211_check_fast_rx_iface(sdata); 2584 + drv_sta_set_4addr(local, sta->sdata, &sta->sta, true); 2585 + 2586 + return 0; 2587 + } 2588 + 2530 2589 static int ieee80211_change_station(struct wiphy *wiphy, 2531 2590 struct wireless_dev *wdev, const u8 *mac, 2532 2591 struct station_parameters *params) ··· 2648 2589 vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); 2649 2590 2650 2591 if (params->vlan->ieee80211_ptr->use_4addr) { 2651 - if (vlansdata->u.vlan.sta) 2652 - return -EBUSY; 2592 + err = ieee80211_set_sta_4addr(local, vlansdata, sta); 2593 + if (err) 2594 + return err; 2653 2595 2654 - rcu_assign_pointer(vlansdata->u.vlan.sta, sta); 2655 - __ieee80211_check_fast_rx_iface(vlansdata); 2656 - drv_sta_set_4addr(local, sta->sdata, &sta->sta, true); 2657 2596 } 2658 2597 2659 2598 if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
+8
net/mac80211/chan.c
··· 1321 1321 list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) { 1322 1322 struct ieee80211_bss_conf *vlan_conf; 1323 1323 1324 + if (vlan->vif.valid_links && 1325 + !(vlan->vif.valid_links & BIT(link_id))) 1326 + continue; 1327 + 1324 1328 vlan_conf = wiphy_dereference(local->hw.wiphy, 1325 1329 vlan->vif.link_conf[link_id]); 1326 1330 if (WARN_ON(!vlan_conf)) ··· 1567 1563 1568 1564 list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) { 1569 1565 struct ieee80211_bss_conf *vlan_conf; 1566 + 1567 + if (vlan->vif.valid_links && 1568 + !(vlan->vif.valid_links & BIT(link_id))) 1569 + continue; 1570 1570 1571 1571 vlan_conf = wiphy_dereference(sdata->local->hw.wiphy, 1572 1572 vlan->vif.link_conf[link_id]);
+31 -14
net/mac80211/link.c
··· 14 14 15 15 static void ieee80211_update_apvlan_links(struct ieee80211_sub_if_data *sdata) 16 16 { 17 + unsigned long rem = ~sdata->vif.valid_links & 18 + GENMASK(IEEE80211_MLD_MAX_NUM_LINKS - 1, 0); 19 + struct ieee80211_local *local = sdata->local; 20 + unsigned long add = sdata->vif.valid_links; 21 + struct wiphy *wiphy = local->hw.wiphy; 17 22 struct ieee80211_sub_if_data *vlan; 18 23 struct ieee80211_link_data *link; 19 - u16 ap_bss_links = sdata->vif.valid_links; 20 - u16 new_links, vlan_links; 21 - unsigned long add; 24 + struct sta_info *sta; 22 25 23 26 list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) { 24 27 int link_id; 25 28 26 - /* No support for 4addr with MLO yet */ 27 - if (vlan->wdev.use_4addr) 28 - return; 29 + if (vlan->wdev.use_4addr) { 30 + sta = wiphy_dereference(wiphy, 31 + vlan->u.vlan.sta); 32 + if (sta) 33 + add = add & sta->sta.valid_links; 34 + } 29 35 30 - vlan_links = vlan->vif.valid_links; 31 - 32 - new_links = ap_bss_links; 33 - 34 - add = new_links & ~vlan_links; 35 - if (!add) 36 + if (add == vlan->vif.valid_links) 36 37 continue; 38 + 39 + for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) { 40 + vlan->wdev.valid_links |= BIT(link_id); 41 + ether_addr_copy(vlan->wdev.links[link_id].addr, 42 + sdata->wdev.links[link_id].addr); 43 + } 44 + 45 + for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) { 46 + vlan->wdev.valid_links &= ~BIT(link_id); 47 + eth_zero_addr(vlan->wdev.links[link_id].addr); 48 + } 37 49 38 50 ieee80211_vif_set_links(vlan, add, 0); 39 51 ··· 108 96 109 97 ap_bss = container_of(sdata->bss, 110 98 struct ieee80211_sub_if_data, u.ap); 111 - ap_bss_conf = sdata_dereference(ap_bss->vif.link_conf[link_id], 112 - ap_bss); 99 + 100 + if (deflink) 101 + ap_bss_conf = &ap_bss->vif.bss_conf; 102 + else 103 + ap_bss_conf = sdata_dereference(ap_bss->vif.link_conf[link_id], 104 + ap_bss); 105 + 113 106 memcpy(link_conf, ap_bss_conf, sizeof(*link_conf)); 114 107 } 115 108