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

wifi: mac80211: Create separate links for VLAN interfaces

Currently, MLD links for an AP_VLAN interface type is not fully
supported.

Add allocation of separate links for each VLAN interface and copy
chanctx and chandef of AP bss to VLAN where necessary. Separate
links are created because for Dynamic VLAN each link will have its own
default_multicast_key.

Signed-off-by: Muna Sinada <muna.sinada@oss.qualcomm.com>
Link: https://patch.msgid.link/20250325213125.1509362-3-muna.sinada@oss.qualcomm.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>

authored by

Muna Sinada and committed by
Johannes Berg
90233b0a f61c7b3d

+103 -5
+3
net/mac80211/chan.c
··· 2131 2131 { 2132 2132 struct ieee80211_sub_if_data *sdata = link->sdata; 2133 2133 2134 + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 2135 + return; 2136 + 2134 2137 lockdep_assert_wiphy(sdata->local->hw.wiphy); 2135 2138 2136 2139 if (rcu_access_pointer(link->conf->chanctx_conf))
+3
net/mac80211/ieee80211_i.h
··· 2087 2087 ieee80211_vif_set_links(sdata, 0, 0); 2088 2088 } 2089 2089 2090 + void ieee80211_apvlan_link_setup(struct ieee80211_sub_if_data *sdata); 2091 + void ieee80211_apvlan_link_clear(struct ieee80211_sub_if_data *sdata); 2092 + 2090 2093 /* tx handling */ 2091 2094 void ieee80211_clear_tx_pending(struct ieee80211_local *local); 2092 2095 void ieee80211_tx_pending(struct tasklet_struct *t);
+11 -1
net/mac80211/iface.c
··· 485 485 case NL80211_IFTYPE_MONITOR: 486 486 list_del_rcu(&sdata->u.mntr.list); 487 487 break; 488 + case NL80211_IFTYPE_AP_VLAN: 489 + ieee80211_apvlan_link_clear(sdata); 490 + break; 488 491 default: 489 492 break; 490 493 } ··· 1271 1268 sdata->crypto_tx_tailroom_needed_cnt += 1272 1269 master->crypto_tx_tailroom_needed_cnt; 1273 1270 1271 + ieee80211_apvlan_link_setup(sdata); 1272 + 1274 1273 break; 1275 1274 } 1276 1275 case NL80211_IFTYPE_AP: ··· 1329 1324 case NL80211_IFTYPE_AP_VLAN: 1330 1325 /* no need to tell driver, but set carrier and chanctx */ 1331 1326 if (sdata->bss->active) { 1332 - ieee80211_link_vlan_copy_chanctx(&sdata->deflink); 1327 + struct ieee80211_link_data *link; 1328 + 1329 + for_each_link_data(sdata, link) { 1330 + ieee80211_link_vlan_copy_chanctx(link); 1331 + } 1332 + 1333 1333 netif_carrier_on(dev); 1334 1334 ieee80211_set_vif_encap_ops(sdata); 1335 1335 } else {
+86 -4
net/mac80211/link.c
··· 12 12 #include "key.h" 13 13 #include "debugfs_netdev.h" 14 14 15 + static void ieee80211_update_apvlan_links(struct ieee80211_sub_if_data *sdata) 16 + { 17 + struct ieee80211_sub_if_data *vlan; 18 + struct ieee80211_link_data *link; 19 + u16 ap_bss_links = sdata->vif.valid_links; 20 + u16 new_links, vlan_links; 21 + unsigned long add; 22 + 23 + list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) { 24 + int link_id; 25 + 26 + if (!vlan) 27 + continue; 28 + 29 + /* No support for 4addr with MLO yet */ 30 + if (vlan->wdev.use_4addr) 31 + return; 32 + 33 + vlan_links = vlan->vif.valid_links; 34 + 35 + new_links = ap_bss_links; 36 + 37 + add = new_links & ~vlan_links; 38 + if (!add) 39 + continue; 40 + 41 + ieee80211_vif_set_links(vlan, add, 0); 42 + 43 + for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) { 44 + link = sdata_dereference(vlan->link[link_id], vlan); 45 + ieee80211_link_vlan_copy_chanctx(link); 46 + } 47 + } 48 + } 49 + 50 + void ieee80211_apvlan_link_setup(struct ieee80211_sub_if_data *sdata) 51 + { 52 + struct ieee80211_sub_if_data *ap_bss = container_of(sdata->bss, 53 + struct ieee80211_sub_if_data, u.ap); 54 + u16 new_links = ap_bss->vif.valid_links; 55 + unsigned long add; 56 + int link_id; 57 + 58 + if (!ap_bss->vif.valid_links) 59 + return; 60 + 61 + add = new_links; 62 + for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) { 63 + sdata->wdev.valid_links |= BIT(link_id); 64 + ether_addr_copy(sdata->wdev.links[link_id].addr, 65 + ap_bss->wdev.links[link_id].addr); 66 + } 67 + 68 + ieee80211_vif_set_links(sdata, new_links, 0); 69 + } 70 + 71 + void ieee80211_apvlan_link_clear(struct ieee80211_sub_if_data *sdata) 72 + { 73 + if (!sdata->wdev.valid_links) 74 + return; 75 + 76 + sdata->wdev.valid_links = 0; 77 + ieee80211_vif_clear_links(sdata); 78 + } 79 + 15 80 void ieee80211_link_setup(struct ieee80211_link_data *link) 16 81 { 17 82 if (link->sdata->vif.type == NL80211_IFTYPE_STATION) ··· 95 30 96 31 rcu_assign_pointer(sdata->vif.link_conf[link_id], link_conf); 97 32 rcu_assign_pointer(sdata->link[link_id], link); 33 + 34 + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { 35 + struct ieee80211_sub_if_data *ap_bss; 36 + struct ieee80211_bss_conf *ap_bss_conf; 37 + 38 + ap_bss = container_of(sdata->bss, 39 + struct ieee80211_sub_if_data, u.ap); 40 + ap_bss_conf = sdata_dereference(ap_bss->vif.link_conf[link_id], 41 + ap_bss); 42 + memcpy(link_conf, ap_bss_conf, sizeof(*link_conf)); 43 + } 98 44 99 45 link->sdata = sdata; 100 46 link->link_id = link_id; ··· 130 54 if (!deflink) { 131 55 switch (sdata->vif.type) { 132 56 case NL80211_IFTYPE_AP: 57 + case NL80211_IFTYPE_AP_VLAN: 133 58 ether_addr_copy(link_conf->addr, 134 59 sdata->wdev.links[link_id].addr); 135 60 link_conf->bssid = link_conf->addr; ··· 254 177 255 178 switch (sdata->vif.type) { 256 179 case NL80211_IFTYPE_AP: 180 + case NL80211_IFTYPE_AP_VLAN: 257 181 /* in an AP all links are always active */ 258 182 sdata->vif.active_links = valid_links; 259 183 ··· 356 278 ieee80211_set_vif_links_bitmaps(sdata, new_links, dormant_links); 357 279 358 280 /* tell the driver */ 359 - ret = drv_change_vif_links(sdata->local, sdata, 360 - old_links & old_active, 361 - new_links & sdata->vif.active_links, 362 - old); 281 + if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN) 282 + ret = drv_change_vif_links(sdata->local, sdata, 283 + old_links & old_active, 284 + new_links & sdata->vif.active_links, 285 + old); 363 286 if (!new_links) 364 287 ieee80211_debugfs_recreate_netdev(sdata, false); 288 + 289 + if (sdata->vif.type == NL80211_IFTYPE_AP) 290 + ieee80211_update_apvlan_links(sdata); 365 291 } 366 292 367 293 if (ret) {