]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: mac80211: restructure tx profile retrieval for MLO MBSSID
authorRameshkumar Sundaram <rameshkumar.sundaram@oss.qualcomm.com>
Tue, 8 Apr 2025 18:45:00 +0000 (11:45 -0700)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 23 Apr 2025 16:03:53 +0000 (18:03 +0200)
For MBSSID, each vif (struct ieee80211_vif) stores another vif
pointer for the transmitting profile of MBSSID set. This won't
suffice for MLO as there may be multiple links, each of which can
be part of different MBSSID sets. Hence the information needs to
be stored per-link. Additionally, the transmitted profile itself
may be part of an MLD hence storing vif will not suffice either.
Fix MLO by storing an instance of struct ieee80211_bss_conf
for each link.

Modify following operations to reflect the above structure updates:
- channel switch completion
- BSS color change completion
- Removing nontransmitted links in ieee80211_stop_mbssid()
- drivers retrieving the transmitted link for beacon templates.

Signed-off-by: Rameshkumar Sundaram <rameshkumar.sundaram@oss.qualcomm.com>
Co-developed-by: Muna Sinada <muna.sinada@oss.qualcomm.com>
Signed-off-by: Muna Sinada <muna.sinada@oss.qualcomm.com>
Co-developed-by: Aloka Dixit <aloka.dixit@oss.qualcomm.com>
Signed-off-by: Aloka Dixit <aloka.dixit@oss.qualcomm.com>
Link: https://patch.msgid.link/20250408184501.3715887-3-aloka.dixit@oss.qualcomm.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/ath/ath11k/mac.c
drivers/net/wireless/ath/ath12k/mac.c
drivers/net/wireless/virtual/mac80211_hwsim.c
include/net/mac80211.h
net/mac80211/cfg.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c

index 97816916abac967481b8e008e8afe5bfefb06355..8191ee14a1fd18f6f1d67b0f5a8bbef3606f212b 100644 (file)
@@ -1531,8 +1531,14 @@ static int ath11k_mac_set_vif_params(struct ath11k_vif *arvif,
 
 static struct ath11k_vif *ath11k_mac_get_tx_arvif(struct ath11k_vif *arvif)
 {
-       if (arvif->vif->mbssid_tx_vif)
-               return ath11k_vif_to_arvif(arvif->vif->mbssid_tx_vif);
+       struct ieee80211_bss_conf *link_conf, *tx_bss_conf;
+
+       lockdep_assert_wiphy(arvif->ar->hw->wiphy);
+
+       link_conf = &arvif->vif->bss_conf;
+       tx_bss_conf = wiphy_dereference(arvif->ar->hw->wiphy, link_conf->tx_bss_conf);
+       if (tx_bss_conf)
+               return ath11k_vif_to_arvif(tx_bss_conf->vif);
 
        return NULL;
 }
index dfa05f0ee6c9f7356634ab55a6d9c0b4064645a9..84da77bf245be298f80827db4b9c9a607c7ebd11 100644 (file)
@@ -582,12 +582,26 @@ static int ath12k_mac_vif_link_chan(struct ieee80211_vif *vif, u8 link_id,
 
 static struct ath12k_link_vif *ath12k_mac_get_tx_arvif(struct ath12k_link_vif *arvif)
 {
+       struct ieee80211_bss_conf *link_conf, *tx_bss_conf;
+       struct ath12k *ar = arvif->ar;
        struct ath12k_vif *tx_ahvif;
 
-       if (arvif->ahvif->vif->mbssid_tx_vif) {
-               tx_ahvif = ath12k_vif_to_ahvif(arvif->ahvif->vif->mbssid_tx_vif);
-               if (tx_ahvif)
-                       return &tx_ahvif->deflink;
+       lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
+
+       link_conf = ath12k_mac_get_link_bss_conf(arvif);
+       if (!link_conf) {
+               ath12k_warn(ar->ab,
+                           "unable to access bss link conf for link %u required to retrieve transmitting link conf\n",
+                           arvif->link_id);
+               return NULL;
+       }
+
+       tx_bss_conf = wiphy_dereference(ath12k_ar_to_hw(ar)->wiphy,
+                                       link_conf->tx_bss_conf);
+       if (tx_bss_conf) {
+               tx_ahvif = ath12k_vif_to_ahvif(tx_bss_conf->vif);
+               return wiphy_dereference(tx_ahvif->ah->hw->wiphy,
+                                        tx_ahvif->link[tx_bss_conf->link_id]);
        }
 
        return NULL;
index cf3e976471c6141b95b9089ebc3498b2ab233d64..74d037cfccca06efd4de22dbdd87f18f1c6a744d 100644 (file)
@@ -2273,7 +2273,7 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
 {
        struct mac80211_hwsim_link_data *link_data = arg;
        u32 link_id = link_data->link_id;
-       struct ieee80211_bss_conf *link_conf;
+       struct ieee80211_bss_conf *link_conf, *tx_bss_conf;
        struct mac80211_hwsim_data *data =
                container_of(link_data, struct mac80211_hwsim_data,
                             link_data[link_id]);
@@ -2292,10 +2292,11 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
            vif->type != NL80211_IFTYPE_OCB)
                return;
 
-       if (vif->mbssid_tx_vif && vif->mbssid_tx_vif != vif)
+       tx_bss_conf = rcu_access_pointer(link_conf->tx_bss_conf);
+       if (tx_bss_conf && tx_bss_conf != link_conf)
                return;
 
-       if (vif->bss_conf.ema_ap) {
+       if (link_conf->ema_ap) {
                struct ieee80211_ema_beacons *ema;
                u8 i = 0;
 
index c305ebfa6e45dcca5357acba826880040127bebd..fdafc37d17cc3edf2ffbdfd6fac8fc19ff14ed1b 100644 (file)
@@ -682,6 +682,9 @@ struct ieee80211_parsed_tpe {
  *     responder functionality.
  * @ftmr_params: configurable lci/civic parameter when enabling FTM responder.
  * @nontransmitted: this BSS is a nontransmitted BSS profile
+ * @tx_bss_conf: Pointer to the BSS configuration of transmitting interface
+ *     if MBSSID is enabled. This pointer is RCU-protected due to CSA finish
+ *     and BSS color change flows accessing it.
  * @transmitter_bssid: the address of transmitter AP
  * @bssid_index: index inside the multiple BSSID set
  * @bssid_indicator: 2^bssid_indicator is the maximum number of APs in set
@@ -804,6 +807,7 @@ struct ieee80211_bss_conf {
        struct ieee80211_ftm_responder_params *ftmr_params;
        /* Multiple BSSID data */
        bool nontransmitted;
+       struct ieee80211_bss_conf __rcu *tx_bss_conf;
        u8 transmitter_bssid[ETH_ALEN];
        u8 bssid_index;
        u8 bssid_indicator;
@@ -2023,7 +2027,6 @@ enum ieee80211_neg_ttlm_res {
  * @txq: the multicast data TX queue
  * @offload_flags: 802.3 -> 802.11 enapsulation offload flags, see
  *     &enum ieee80211_offload_flags.
- * @mbssid_tx_vif: Pointer to the transmitting interface if MBSSID is enabled.
  */
 struct ieee80211_vif {
        enum nl80211_iftype type;
@@ -2052,8 +2055,6 @@ struct ieee80211_vif {
        bool probe_req_reg;
        bool rx_mcast_action_reg;
 
-       struct ieee80211_vif *mbssid_tx_vif;
-
        /* must be last */
        u8 drv_priv[] __aligned(sizeof(void *));
 };
index 2676b368e5a61e1aecb766046a54f13fafe82f1d..9017b98fea0482146870de27cb3858557cfa3792 100644 (file)
@@ -146,8 +146,8 @@ static int ieee80211_set_ap_mbssid_options(struct ieee80211_sub_if_data *sdata,
                                           struct ieee80211_bss_conf *link_conf)
 {
        struct ieee80211_sub_if_data *tx_sdata;
+       struct ieee80211_bss_conf *old;
 
-       sdata->vif.mbssid_tx_vif = NULL;
        link_conf->bssid_index = 0;
        link_conf->nontransmitted = false;
        link_conf->ema_ap = false;
@@ -156,14 +156,26 @@ static int ieee80211_set_ap_mbssid_options(struct ieee80211_sub_if_data *sdata,
        if (sdata->vif.type != NL80211_IFTYPE_AP || !params->tx_wdev)
                return -EINVAL;
 
+       old = sdata_dereference(link_conf->tx_bss_conf, sdata);
+       if (old)
+               return -EALREADY;
+
        tx_sdata = IEEE80211_WDEV_TO_SUB_IF(params->tx_wdev);
        if (!tx_sdata)
                return -EINVAL;
 
        if (tx_sdata == sdata) {
-               sdata->vif.mbssid_tx_vif = &sdata->vif;
+               rcu_assign_pointer(link_conf->tx_bss_conf, link_conf);
        } else {
-               sdata->vif.mbssid_tx_vif = &tx_sdata->vif;
+               struct ieee80211_bss_conf *tx_bss_conf;
+
+               tx_bss_conf = sdata_dereference(tx_sdata->vif.link_conf[params->tx_link_id],
+                                               sdata);
+               if (rcu_access_pointer(tx_bss_conf->tx_bss_conf) != tx_bss_conf)
+                       return -EINVAL;
+
+               rcu_assign_pointer(link_conf->tx_bss_conf, tx_bss_conf);
+
                link_conf->nontransmitted = true;
                link_conf->bssid_index = params->index;
        }
@@ -1669,7 +1681,6 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev,
        kfree(link_conf->ftmr_params);
        link_conf->ftmr_params = NULL;
 
-       sdata->vif.mbssid_tx_vif = NULL;
        link_conf->bssid_index = 0;
        link_conf->nontransmitted = false;
        link_conf->ema_ap = false;
@@ -1683,6 +1694,9 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev,
                ieee80211_free_key_list(local, &keys);
        }
 
+       ieee80211_stop_mbssid(sdata);
+       RCU_INIT_POINTER(link_conf->tx_bss_conf, NULL);
+
        link_conf->enable_beacon = false;
        sdata->beacon_rate_set = false;
        sdata->vif.cfg.ssid_len = 0;
@@ -3703,6 +3717,7 @@ void ieee80211_csa_finish(struct ieee80211_vif *vif, unsigned int link_id)
 {
        struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
        struct ieee80211_local *local = sdata->local;
+       struct ieee80211_bss_conf *tx_bss_conf;
        struct ieee80211_link_data *link_data;
 
        if (WARN_ON(link_id >= IEEE80211_MLD_MAX_NUM_LINKS))
@@ -3716,25 +3731,24 @@ void ieee80211_csa_finish(struct ieee80211_vif *vif, unsigned int link_id)
                return;
        }
 
-       /* TODO: MBSSID with MLO changes */
-       if (vif->mbssid_tx_vif == vif) {
+       tx_bss_conf = rcu_dereference(link_data->conf->tx_bss_conf);
+       if (tx_bss_conf == link_data->conf) {
                /* Trigger ieee80211_csa_finish() on the non-transmitting
                 * interfaces when channel switch is received on
                 * transmitting interface
                 */
-               struct ieee80211_sub_if_data *iter;
-
-               list_for_each_entry_rcu(iter, &local->interfaces, list) {
-                       if (!ieee80211_sdata_running(iter))
-                               continue;
+               struct ieee80211_link_data *iter;
 
-                       if (iter == sdata || iter->vif.mbssid_tx_vif != vif)
+               for_each_sdata_link(local, iter) {
+                       if (iter->sdata == sdata ||
+                           rcu_access_pointer(iter->conf->tx_bss_conf) != tx_bss_conf)
                                continue;
 
-                       wiphy_work_queue(iter->local->hw.wiphy,
-                                        &iter->deflink.csa.finalize_work);
+                       wiphy_work_queue(iter->sdata->local->hw.wiphy,
+                                        &iter->csa.finalize_work);
                }
        }
+
        wiphy_work_queue(local->hw.wiphy, &link_data->csa.finalize_work);
 
        rcu_read_unlock();
@@ -4836,17 +4850,19 @@ ieee80211_color_change_bss_config_notify(struct ieee80211_link_data *link,
 
        ieee80211_link_info_change_notify(sdata, link, changed);
 
-       if (!sdata->vif.bss_conf.nontransmitted && sdata->vif.mbssid_tx_vif) {
-               struct ieee80211_sub_if_data *child;
+       if (!link->conf->nontransmitted &&
+           rcu_access_pointer(link->conf->tx_bss_conf)) {
+               struct ieee80211_link_data *tmp;
 
-               list_for_each_entry(child, &sdata->local->interfaces, list) {
-                       if (child != sdata && child->vif.mbssid_tx_vif == &sdata->vif) {
-                               child->vif.bss_conf.he_bss_color.color = color;
-                               child->vif.bss_conf.he_bss_color.enabled = enable;
-                               ieee80211_link_info_change_notify(child,
-                                                                 &child->deflink,
-                                                                 BSS_CHANGED_HE_BSS_COLOR);
-                       }
+               for_each_sdata_link(sdata->local, tmp) {
+                       if (tmp->sdata == sdata ||
+                           rcu_access_pointer(tmp->conf->tx_bss_conf) != link->conf)
+                               continue;
+
+                       tmp->conf->he_bss_color.color = color;
+                       tmp->conf->he_bss_color.enabled = enable;
+                       ieee80211_link_info_change_notify(tmp->sdata, tmp,
+                                                         BSS_CHANGED_HE_BSS_COLOR);
                }
        }
 }
index 99a31017fa59d04566f6f0e7962c392f3cc992ad..30809f0b35f73e77b05a6f802011a64900e1532f 100644 (file)
@@ -2807,6 +2807,8 @@ int ieee80211_mgd_assoc_ml_reconf(struct ieee80211_sub_if_data *sdata,
 
 void ieee80211_process_ml_reconf_resp(struct ieee80211_sub_if_data *sdata,
                                      struct ieee80211_mgmt *mgmt, size_t len);
+void ieee80211_stop_mbssid(struct ieee80211_sub_if_data *sdata);
+
 #if IS_ENABLED(CONFIG_MAC80211_KUNIT_TEST)
 #define EXPORT_SYMBOL_IF_MAC80211_KUNIT(sym) EXPORT_SYMBOL_IF_KUNIT(sym)
 #define VISIBLE_IF_MAC80211_KUNIT
index 7d93e5aa595b286901d303db9b5705762bb63b77..7c27f3cd841c3cad37e91f62c04d2a75048ae7cf 100644 (file)
@@ -732,30 +732,59 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
                ieee80211_add_virtual_monitor(local);
 }
 
-static void ieee80211_stop_mbssid(struct ieee80211_sub_if_data *sdata)
+void ieee80211_stop_mbssid(struct ieee80211_sub_if_data *sdata)
 {
-       struct ieee80211_sub_if_data *tx_sdata, *non_tx_sdata, *tmp_sdata;
-       struct ieee80211_vif *tx_vif = sdata->vif.mbssid_tx_vif;
+       struct ieee80211_sub_if_data *tx_sdata;
+       struct ieee80211_bss_conf *link_conf, *tx_bss_conf;
+       struct ieee80211_link_data *tx_link, *link;
+       unsigned int link_id;
 
-       if (!tx_vif)
-               return;
+       lockdep_assert_wiphy(sdata->local->hw.wiphy);
+
+       /* Check if any of the links of current sdata is an MBSSID. */
+       for_each_vif_active_link(&sdata->vif, link_conf, link_id) {
+               tx_bss_conf = sdata_dereference(link_conf->tx_bss_conf, sdata);
+               if (!tx_bss_conf)
+                       continue;
 
-       tx_sdata = vif_to_sdata(tx_vif);
-       sdata->vif.mbssid_tx_vif = NULL;
+               tx_sdata = vif_to_sdata(tx_bss_conf->vif);
+               RCU_INIT_POINTER(link_conf->tx_bss_conf, NULL);
 
-       list_for_each_entry_safe(non_tx_sdata, tmp_sdata,
-                                &tx_sdata->local->interfaces, list) {
-               if (non_tx_sdata != sdata && non_tx_sdata != tx_sdata &&
-                   non_tx_sdata->vif.mbssid_tx_vif == tx_vif &&
-                   ieee80211_sdata_running(non_tx_sdata)) {
-                       non_tx_sdata->vif.mbssid_tx_vif = NULL;
-                       dev_close(non_tx_sdata->wdev.netdev);
+               /* If we are not tx sdata reset tx sdata's tx_bss_conf to avoid recusrion
+                * while closing tx sdata at the end of outer loop below.
+                */
+               if (sdata != tx_sdata) {
+                       tx_link = sdata_dereference(tx_sdata->link[tx_bss_conf->link_id],
+                                                   tx_sdata);
+                       if (!tx_link)
+                               continue;
+
+                       RCU_INIT_POINTER(tx_link->conf->tx_bss_conf, NULL);
+               }
+
+               /* loop through sdatas to find if any of their links
+                * belong to same MBSSID set as the one getting deleted.
+                */
+               for_each_sdata_link(tx_sdata->local, link) {
+                       struct ieee80211_sub_if_data *link_sdata = link->sdata;
+
+                       if (link_sdata == sdata || link_sdata == tx_sdata ||
+                           rcu_access_pointer(link->conf->tx_bss_conf) != tx_bss_conf)
+                               continue;
+
+                       RCU_INIT_POINTER(link->conf->tx_bss_conf, NULL);
+
+                       /* Remove all links of matching MLD until dynamic link
+                        * removal can be supported.
+                        */
+                       cfg80211_stop_iface(link_sdata->wdev.wiphy, &link_sdata->wdev,
+                                           GFP_KERNEL);
                }
-       }
 
-       if (sdata != tx_sdata && ieee80211_sdata_running(tx_sdata)) {
-               tx_sdata->vif.mbssid_tx_vif = NULL;
-               dev_close(tx_sdata->wdev.netdev);
+               /* If we are not tx sdata, remove links of tx sdata and proceed */
+               if (sdata != tx_sdata && ieee80211_sdata_running(tx_sdata))
+                       cfg80211_stop_iface(tx_sdata->wdev.wiphy,
+                                           &tx_sdata->wdev, GFP_KERNEL);
        }
 }
 
@@ -763,21 +792,25 @@ static int ieee80211_stop(struct net_device *dev)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       /* close dependent VLAN and MBSSID interfaces before locking wiphy */
+       /* close dependent VLAN interfaces before locking wiphy */
        if (sdata->vif.type == NL80211_IFTYPE_AP) {
                struct ieee80211_sub_if_data *vlan, *tmpsdata;
 
                list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
                                         u.vlan.list)
                        dev_close(vlan->dev);
-
-               ieee80211_stop_mbssid(sdata);
        }
 
        guard(wiphy)(sdata->local->hw.wiphy);
 
        wiphy_work_cancel(sdata->local->hw.wiphy, &sdata->activate_links_work);
 
+       /* Close the dependent MBSSID interfaces with wiphy lock as we may be
+        * terminating its partner links too in case of MLD.
+        */
+       if (sdata->vif.type == NL80211_IFTYPE_AP)
+               ieee80211_stop_mbssid(sdata);
+
        ieee80211_do_stop(sdata, true);
 
        return 0;