wifi: mac80211: Create separate links for VLAN interfaces
authorMuna Sinada <muna.sinada@oss.qualcomm.com>
Tue, 25 Mar 2025 21:31:24 +0000 (14:31 -0700)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 23 Apr 2025 14:56:15 +0000 (16:56 +0200)
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>
net/mac80211/chan.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/link.c

index c3bfac58151f639bfcd04e4b326fddd158d118fb..3aaf5abf1acc13008a0472672c826d495c80407c 100644 (file)
@@ -2131,6 +2131,9 @@ void ieee80211_link_release_channel(struct ieee80211_link_data *link)
 {
        struct ieee80211_sub_if_data *sdata = link->sdata;
 
+       if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+               return;
+
        lockdep_assert_wiphy(sdata->local->hw.wiphy);
 
        if (rcu_access_pointer(link->conf->chanctx_conf))
index c797513f58e03a7511a2f7459d8ca25c2926f602..99a31017fa59d04566f6f0e7962c392f3cc992ad 100644 (file)
@@ -2087,6 +2087,9 @@ static inline void ieee80211_vif_clear_links(struct ieee80211_sub_if_data *sdata
        ieee80211_vif_set_links(sdata, 0, 0);
 }
 
+void ieee80211_apvlan_link_setup(struct ieee80211_sub_if_data *sdata);
+void ieee80211_apvlan_link_clear(struct ieee80211_sub_if_data *sdata);
+
 /* tx handling */
 void ieee80211_clear_tx_pending(struct ieee80211_local *local);
 void ieee80211_tx_pending(struct tasklet_struct *t);
index 969b3e2c496af51291b9bede8ee7affa7d68f868..7d93e5aa595b286901d303db9b5705762bb63b77 100644 (file)
@@ -485,6 +485,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
        case NL80211_IFTYPE_MONITOR:
                list_del_rcu(&sdata->u.mntr.list);
                break;
+       case NL80211_IFTYPE_AP_VLAN:
+               ieee80211_apvlan_link_clear(sdata);
+               break;
        default:
                break;
        }
@@ -1268,6 +1271,8 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
                sdata->crypto_tx_tailroom_needed_cnt +=
                        master->crypto_tx_tailroom_needed_cnt;
 
+               ieee80211_apvlan_link_setup(sdata);
+
                break;
                }
        case NL80211_IFTYPE_AP:
@@ -1324,7 +1329,12 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
        case NL80211_IFTYPE_AP_VLAN:
                /* no need to tell driver, but set carrier and chanctx */
                if (sdata->bss->active) {
-                       ieee80211_link_vlan_copy_chanctx(&sdata->deflink);
+                       struct ieee80211_link_data *link;
+
+                       for_each_link_data(sdata, link) {
+                               ieee80211_link_vlan_copy_chanctx(link);
+                       }
+
                        netif_carrier_on(dev);
                        ieee80211_set_vif_encap_ops(sdata);
                } else {
index 58a76bcd6ae68670fbbe7fa7d07540c04ff996f8..d40c2bd3b50b086e2ef3646b448c77b1172a150b 100644 (file)
 #include "key.h"
 #include "debugfs_netdev.h"
 
+static void ieee80211_update_apvlan_links(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_sub_if_data *vlan;
+       struct ieee80211_link_data *link;
+       u16 ap_bss_links = sdata->vif.valid_links;
+       u16 new_links, vlan_links;
+       unsigned long add;
+
+       list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
+               int link_id;
+
+               if (!vlan)
+                       continue;
+
+               /* No support for 4addr with MLO yet */
+               if (vlan->wdev.use_4addr)
+                       return;
+
+               vlan_links = vlan->vif.valid_links;
+
+               new_links = ap_bss_links;
+
+               add = new_links & ~vlan_links;
+               if (!add)
+                       continue;
+
+               ieee80211_vif_set_links(vlan, add, 0);
+
+               for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
+                       link = sdata_dereference(vlan->link[link_id], vlan);
+                       ieee80211_link_vlan_copy_chanctx(link);
+               }
+       }
+}
+
+void ieee80211_apvlan_link_setup(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_sub_if_data *ap_bss = container_of(sdata->bss,
+                                           struct ieee80211_sub_if_data, u.ap);
+       u16 new_links = ap_bss->vif.valid_links;
+       unsigned long add;
+       int link_id;
+
+       if (!ap_bss->vif.valid_links)
+               return;
+
+       add = new_links;
+       for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
+               sdata->wdev.valid_links |= BIT(link_id);
+               ether_addr_copy(sdata->wdev.links[link_id].addr,
+                               ap_bss->wdev.links[link_id].addr);
+       }
+
+       ieee80211_vif_set_links(sdata, new_links, 0);
+}
+
+void ieee80211_apvlan_link_clear(struct ieee80211_sub_if_data *sdata)
+{
+       if (!sdata->wdev.valid_links)
+               return;
+
+       sdata->wdev.valid_links = 0;
+       ieee80211_vif_clear_links(sdata);
+}
+
 void ieee80211_link_setup(struct ieee80211_link_data *link)
 {
        if (link->sdata->vif.type == NL80211_IFTYPE_STATION)
@@ -31,6 +96,17 @@ void ieee80211_link_init(struct ieee80211_sub_if_data *sdata,
        rcu_assign_pointer(sdata->vif.link_conf[link_id], link_conf);
        rcu_assign_pointer(sdata->link[link_id], link);
 
+       if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
+               struct ieee80211_sub_if_data *ap_bss;
+               struct ieee80211_bss_conf *ap_bss_conf;
+
+               ap_bss = container_of(sdata->bss,
+                                     struct ieee80211_sub_if_data, u.ap);
+               ap_bss_conf = sdata_dereference(ap_bss->vif.link_conf[link_id],
+                                               ap_bss);
+               memcpy(link_conf, ap_bss_conf, sizeof(*link_conf));
+       }
+
        link->sdata = sdata;
        link->link_id = link_id;
        link->conf = link_conf;
@@ -54,6 +130,7 @@ void ieee80211_link_init(struct ieee80211_sub_if_data *sdata,
        if (!deflink) {
                switch (sdata->vif.type) {
                case NL80211_IFTYPE_AP:
+               case NL80211_IFTYPE_AP_VLAN:
                        ether_addr_copy(link_conf->addr,
                                        sdata->wdev.links[link_id].addr);
                        link_conf->bssid = link_conf->addr;
@@ -177,6 +254,7 @@ static void ieee80211_set_vif_links_bitmaps(struct ieee80211_sub_if_data *sdata,
 
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_AP_VLAN:
                /* in an AP all links are always active */
                sdata->vif.active_links = valid_links;
 
@@ -278,12 +356,16 @@ static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata,
                ieee80211_set_vif_links_bitmaps(sdata, new_links, dormant_links);
 
                /* tell the driver */
-               ret = drv_change_vif_links(sdata->local, sdata,
-                                          old_links & old_active,
-                                          new_links & sdata->vif.active_links,
-                                          old);
+               if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN)
+                       ret = drv_change_vif_links(sdata->local, sdata,
+                                                  old_links & old_active,
+                                                  new_links & sdata->vif.active_links,
+                                                  old);
                if (!new_links)
                        ieee80211_debugfs_recreate_netdev(sdata, false);
+
+               if (sdata->vif.type == NL80211_IFTYPE_AP)
+                       ieee80211_update_apvlan_links(sdata);
        }
 
        if (ret) {