wifi: mac80211: handle color change per link
authorAditya Kumar Singh <quic_adisi@quicinc.com>
Mon, 22 Apr 2024 05:34:08 +0000 (11:04 +0530)
committerJohannes Berg <johannes.berg@intel.com>
Fri, 3 May 2024 08:18:19 +0000 (10:18 +0200)
In order to support color change with MLO, handle the link ID now
passed from cfg80211, adjust the code to do everything per link
and call the notifications to cfg80211 correctly.

Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
Link: https://msgid.link/20240422053412.2024075-4-quic_adisi@quicinc.com
Link: https://msgid.link/20240422053412.2024075-5-quic_adisi@quicinc.com
Link: https://msgid.link/20240422053412.2024075-6-quic_adisi@quicinc.com
Link: https://msgid.link/20240422053412.2024075-7-quic_adisi@quicinc.com
[squash, move API call updates to this patch]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/ath/ath11k/mac.c
drivers/net/wireless/ath/ath11k/wmi.c
drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
include/net/mac80211.h
net/mac80211/cfg.c
net/mac80211/rx.c

index 4fdd56cd30a12693e75e157b2b970d25774e5a9d..7fa760ef674ebadb2f15c9ea87ad43458348067d 100644 (file)
@@ -1659,7 +1659,7 @@ void ath11k_mac_bcn_tx_event(struct ath11k_vif *arvif)
        if (vif->bss_conf.color_change_active &&
            ieee80211_beacon_cntdwn_is_complete(vif, 0)) {
                arvif->bcca_zero_sent = true;
-               ieee80211_color_change_finish(vif);
+               ieee80211_color_change_finish(vif, 0);
                return;
        }
 
index c74aa3f95658dc54a423d3f08f1e1e63a9645ef3..3761dfce1f64fc72264fcf40668e46942d0a1611 100644 (file)
@@ -4064,7 +4064,8 @@ ath11k_wmi_obss_color_collision_event(struct ath11k_base *ab, struct sk_buff *sk
 
        switch (ev->evt_type) {
        case WMI_BSS_COLOR_COLLISION_DETECTION:
-               ieee80211_obss_color_collision_notify(arvif->vif, ev->obss_color_bitmap);
+               ieee80211_obss_color_collision_notify(arvif->vif, ev->obss_color_bitmap,
+                                                     0);
                ath11k_dbg(ab, ATH11K_DBG_WMI,
                           "OBSS color collision detected vdev:%d, event:%d, bitmap:%08llx\n",
                           ev->vdev_id, ev->evt_type, ev->obss_color_bitmap);
index d90f98c5003994735d2dcb201acbde9bb4bd6a95..6442e3e5d45bf7e7b1d79240c339acdc108a92d1 100644 (file)
@@ -331,7 +331,7 @@ mt7915_mcu_cca_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
        if (!vif->bss_conf.color_change_active || vif->type == NL80211_IFTYPE_STATION)
                return;
 
-       ieee80211_color_change_finish(vif);
+       ieee80211_color_change_finish(vif, 0);
 }
 
 static void
index b44abe2acc81b1ad808bc5c51918bd8b1ad3632e..163b822a477c048609f10c68fcc97f5ce2546e0c 100644 (file)
@@ -418,7 +418,7 @@ mt7996_mcu_cca_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
        if (!vif->bss_conf.color_change_active || vif->type == NL80211_IFTYPE_STATION)
                return;
 
-       ieee80211_color_change_finish(vif);
+       ieee80211_color_change_finish(vif, 0);
 }
 
 static void
index 5be28b45049bcb9854554b51a73bcbb997c9945d..cafc664ee53185dd89104892ad66bbd962635651 100644 (file)
@@ -5615,12 +5615,13 @@ bool ieee80211_beacon_cntdwn_is_complete(struct ieee80211_vif *vif,
 /**
  * ieee80211_color_change_finish - notify mac80211 about color change
  * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ * @link_id: valid link_id during MLO or 0 for non-MLO
  *
  * After a color change announcement was scheduled and the counter in this
  * announcement hits 1, this function must be called by the driver to
  * notify mac80211 that the color can be changed
  */
-void ieee80211_color_change_finish(struct ieee80211_vif *vif);
+void ieee80211_color_change_finish(struct ieee80211_vif *vif, u8 link_id);
 
 /**
  * ieee80211_proberesp_get - retrieve a Probe Response template
@@ -7533,6 +7534,7 @@ ieee80211_get_unsol_bcast_probe_resp_tmpl(struct ieee80211_hw *hw,
 /**
  * ieee80211_obss_color_collision_notify - notify userland about a BSS color
  * collision.
+ * @link_id: valid link_id during MLO or 0 for non-MLO
  *
  * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  * @color_bitmap: a 64 bit bitmap representing the colors that the local BSS is
@@ -7540,7 +7542,7 @@ ieee80211_get_unsol_bcast_probe_resp_tmpl(struct ieee80211_hw *hw,
  */
 void
 ieee80211_obss_color_collision_notify(struct ieee80211_vif *vif,
-                                     u64 color_bitmap);
+                                     u64 color_bitmap, u8 link_id);
 
 /**
  * ieee80211_is_tx_data - check if frame is a data frame
index 4131ad6c1de3aa849527aebfd7eb343d7ecad73a..b08e5d7687e3fcfb855b3db7ea916491d5c10c1b 100644 (file)
@@ -3918,13 +3918,13 @@ static int ieee80211_set_csa_beacon(struct ieee80211_link_data *link_data,
        return 0;
 }
 
-static void ieee80211_color_change_abort(struct ieee80211_sub_if_data  *sdata)
+static void ieee80211_color_change_abort(struct ieee80211_link_data *link)
 {
-       sdata->vif.bss_conf.color_change_active = false;
+       link->conf->color_change_active = false;
 
-       ieee80211_free_next_beacon(&sdata->deflink);
+       ieee80211_free_next_beacon(link);
 
-       cfg80211_color_change_aborted_notify(sdata->dev, 0);
+       cfg80211_color_change_aborted_notify(link->sdata->dev, link->link_id);
 }
 
 static int
@@ -4008,7 +4008,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 
        /* if there is a color change in progress, abort it */
        if (link_conf->color_change_active)
-               ieee80211_color_change_abort(sdata);
+               ieee80211_color_change_abort(link_data);
 
        err = ieee80211_set_csa_beacon(link_data, params, &changed);
        if (err) {
@@ -4666,20 +4666,22 @@ static int ieee80211_set_sar_specs(struct wiphy *wiphy,
 }
 
 static int
-ieee80211_set_after_color_change_beacon(struct ieee80211_sub_if_data *sdata,
+ieee80211_set_after_color_change_beacon(struct ieee80211_link_data *link,
                                        u64 *changed)
 {
+       struct ieee80211_sub_if_data *sdata = link->sdata;
+
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_AP: {
                int ret;
 
-               if (!sdata->deflink.u.ap.next_beacon)
+               if (!link->u.ap.next_beacon)
                        return -EINVAL;
 
-               ret = ieee80211_assign_beacon(sdata, &sdata->deflink,
-                                             sdata->deflink.u.ap.next_beacon,
+               ret = ieee80211_assign_beacon(sdata, link,
+                                             link->u.ap.next_beacon,
                                              NULL, NULL, changed);
-               ieee80211_free_next_beacon(&sdata->deflink);
+               ieee80211_free_next_beacon(link);
 
                if (ret < 0)
                        return ret;
@@ -4695,18 +4697,19 @@ ieee80211_set_after_color_change_beacon(struct ieee80211_sub_if_data *sdata,
 }
 
 static int
-ieee80211_set_color_change_beacon(struct ieee80211_sub_if_data *sdata,
+ieee80211_set_color_change_beacon(struct ieee80211_link_data *link,
                                  struct cfg80211_color_change_settings *params,
                                  u64 *changed)
 {
+       struct ieee80211_sub_if_data *sdata = link->sdata;
        struct ieee80211_color_change_settings color_change = {};
        int err;
 
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_AP:
-               sdata->deflink.u.ap.next_beacon =
+               link->u.ap.next_beacon =
                        cfg80211_beacon_dup(&params->beacon_next);
-               if (!sdata->deflink.u.ap.next_beacon)
+               if (!link->u.ap.next_beacon)
                        return -ENOMEM;
 
                if (params->count <= 1)
@@ -4718,11 +4721,11 @@ ieee80211_set_color_change_beacon(struct ieee80211_sub_if_data *sdata,
                        params->counter_offset_presp;
                color_change.count = params->count;
 
-               err = ieee80211_assign_beacon(sdata, &sdata->deflink,
+               err = ieee80211_assign_beacon(sdata, link,
                                              &params->beacon_color_change,
                                              NULL, &color_change, changed);
                if (err < 0) {
-                       ieee80211_free_next_beacon(&sdata->deflink);
+                       ieee80211_free_next_beacon(link);
                        return err;
                }
                break;
@@ -4734,16 +4737,18 @@ ieee80211_set_color_change_beacon(struct ieee80211_sub_if_data *sdata,
 }
 
 static void
-ieee80211_color_change_bss_config_notify(struct ieee80211_sub_if_data *sdata,
+ieee80211_color_change_bss_config_notify(struct ieee80211_link_data *link,
                                         u8 color, int enable, u64 changed)
 {
+       struct ieee80211_sub_if_data *sdata = link->sdata;
+
        lockdep_assert_wiphy(sdata->local->hw.wiphy);
 
-       sdata->vif.bss_conf.he_bss_color.color = color;
-       sdata->vif.bss_conf.he_bss_color.enabled = enable;
+       link->conf->he_bss_color.color = color;
+       link->conf->he_bss_color.enabled = enable;
        changed |= BSS_CHANGED_HE_BSS_COLOR;
 
-       ieee80211_link_info_change_notify(sdata, &sdata->deflink, changed);
+       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;
@@ -4760,26 +4765,27 @@ ieee80211_color_change_bss_config_notify(struct ieee80211_sub_if_data *sdata,
        }
 }
 
-static int ieee80211_color_change_finalize(struct ieee80211_sub_if_data *sdata)
+static int ieee80211_color_change_finalize(struct ieee80211_link_data *link)
 {
+       struct ieee80211_sub_if_data *sdata = link->sdata;
        struct ieee80211_local *local = sdata->local;
        u64 changed = 0;
        int err;
 
        lockdep_assert_wiphy(local->hw.wiphy);
 
-       sdata->vif.bss_conf.color_change_active = false;
+       link->conf->color_change_active = false;
 
-       err = ieee80211_set_after_color_change_beacon(sdata, &changed);
+       err = ieee80211_set_after_color_change_beacon(link, &changed);
        if (err) {
-               cfg80211_color_change_aborted_notify(sdata->dev, 0);
+               cfg80211_color_change_aborted_notify(sdata->dev, link->link_id);
                return err;
        }
 
-       ieee80211_color_change_bss_config_notify(sdata,
-                                                sdata->vif.bss_conf.color_change_color,
+       ieee80211_color_change_bss_config_notify(link,
+                                                link->conf->color_change_color,
                                                 1, changed);
-       cfg80211_color_change_notify(sdata->dev, 0);
+       cfg80211_color_change_notify(sdata->dev, link->link_id);
 
        return 0;
 }
@@ -4787,21 +4793,23 @@ static int ieee80211_color_change_finalize(struct ieee80211_sub_if_data *sdata)
 void ieee80211_color_change_finalize_work(struct wiphy *wiphy,
                                          struct wiphy_work *work)
 {
-       struct ieee80211_sub_if_data *sdata =
-               container_of(work, struct ieee80211_sub_if_data,
-                            deflink.color_change_finalize_work);
+       struct ieee80211_link_data *link =
+               container_of(work, struct ieee80211_link_data,
+                            color_change_finalize_work);
+       struct ieee80211_sub_if_data *sdata = link->sdata;
+       struct ieee80211_bss_conf *link_conf = link->conf;
        struct ieee80211_local *local = sdata->local;
 
        lockdep_assert_wiphy(local->hw.wiphy);
 
        /* AP might have been stopped while waiting for the lock. */
-       if (!sdata->vif.bss_conf.color_change_active)
+       if (!link_conf->color_change_active)
                return;
 
        if (!ieee80211_sdata_running(sdata))
                return;
 
-       ieee80211_color_change_finalize(sdata);
+       ieee80211_color_change_finalize(link);
 }
 
 void ieee80211_color_collision_detection_work(struct work_struct *work)
@@ -4812,30 +4820,60 @@ void ieee80211_color_collision_detection_work(struct work_struct *work)
                             color_collision_detect_work);
        struct ieee80211_sub_if_data *sdata = link->sdata;
 
-       cfg80211_obss_color_collision_notify(sdata->dev, link->color_bitmap, 0);
+       cfg80211_obss_color_collision_notify(sdata->dev, link->color_bitmap,
+                                            link->link_id);
 }
 
-void ieee80211_color_change_finish(struct ieee80211_vif *vif)
+void ieee80211_color_change_finish(struct ieee80211_vif *vif, u8 link_id)
 {
        struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+       struct ieee80211_link_data *link;
+
+       if (WARN_ON(link_id >= IEEE80211_MLD_MAX_NUM_LINKS))
+               return;
+
+       rcu_read_lock();
+
+       link = rcu_dereference(sdata->link[link_id]);
+       if (WARN_ON(!link)) {
+               rcu_read_unlock();
+               return;
+       }
 
        wiphy_work_queue(sdata->local->hw.wiphy,
-                        &sdata->deflink.color_change_finalize_work);
+                        &link->color_change_finalize_work);
+
+       rcu_read_unlock();
 }
 EXPORT_SYMBOL_GPL(ieee80211_color_change_finish);
 
 void
 ieee80211_obss_color_collision_notify(struct ieee80211_vif *vif,
-                                     u64 color_bitmap)
+                                     u64 color_bitmap, u8 link_id)
 {
        struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
-       struct ieee80211_link_data *link = &sdata->deflink;
+       struct ieee80211_link_data *link;
 
-       if (sdata->vif.bss_conf.color_change_active || sdata->vif.bss_conf.csa_active)
+       if (WARN_ON(link_id >= IEEE80211_MLD_MAX_NUM_LINKS))
                return;
 
-       if (delayed_work_pending(&link->color_collision_detect_work))
+       rcu_read_lock();
+
+       link = rcu_dereference(sdata->link[link_id]);
+       if (WARN_ON(!link)) {
+               rcu_read_unlock();
                return;
+       }
+
+       if (link->conf->color_change_active || link->conf->csa_active) {
+               rcu_read_unlock();
+               return;
+       }
+
+       if (delayed_work_pending(&link->color_collision_detect_work)) {
+               rcu_read_unlock();
+               return;
+       }
 
        link->color_bitmap = color_bitmap;
        /* queue the color collision detection event every 500 ms in order to
@@ -4844,6 +4882,8 @@ ieee80211_obss_color_collision_notify(struct ieee80211_vif *vif,
        ieee80211_queue_delayed_work(&sdata->local->hw,
                                     &link->color_collision_detect_work,
                                     msecs_to_jiffies(500));
+
+       rcu_read_unlock();
 }
 EXPORT_SYMBOL_GPL(ieee80211_obss_color_collision_notify);
 
@@ -4853,36 +4893,48 @@ ieee80211_color_change(struct wiphy *wiphy, struct net_device *dev,
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
+       struct ieee80211_bss_conf *link_conf;
+       struct ieee80211_link_data *link;
+       u8 link_id = params->link_id;
        u64 changed = 0;
        int err;
 
        lockdep_assert_wiphy(local->hw.wiphy);
 
-       if (sdata->vif.bss_conf.nontransmitted)
+       if (WARN_ON(link_id >= IEEE80211_MLD_MAX_NUM_LINKS))
+               return -EINVAL;
+
+       link = wiphy_dereference(wiphy, sdata->link[link_id]);
+       if (!link)
+               return -ENOLINK;
+
+       link_conf = link->conf;
+
+       if (link_conf->nontransmitted)
                return -EINVAL;
 
        /* don't allow another color change if one is already active or if csa
         * is active
         */
-       if (sdata->vif.bss_conf.color_change_active || sdata->vif.bss_conf.csa_active) {
+       if (link_conf->color_change_active || link_conf->csa_active) {
                err = -EBUSY;
                goto out;
        }
 
-       err = ieee80211_set_color_change_beacon(sdata, params, &changed);
+       err = ieee80211_set_color_change_beacon(link, params, &changed);
        if (err)
                goto out;
 
-       sdata->vif.bss_conf.color_change_active = true;
-       sdata->vif.bss_conf.color_change_color = params->color;
+       link_conf->color_change_active = true;
+       link_conf->color_change_color = params->color;
 
-       cfg80211_color_change_started_notify(sdata->dev, params->count, 0);
+       cfg80211_color_change_started_notify(sdata->dev, params->count, link_id);
 
        if (changed)
-               ieee80211_color_change_bss_config_notify(sdata, 0, 0, changed);
+               ieee80211_color_change_bss_config_notify(link, 0, 0, changed);
        else
                /* if the beacon didn't change, we can finalize immediately */
-               ieee80211_color_change_finalize(sdata);
+               ieee80211_color_change_finalize(link);
 
 out:
 
index 8274dba76206a2f72cac22f57a728cea24268954..4914692750e5e8b5f891cebfed64c6c6e0fec247 100644 (file)
@@ -3368,7 +3368,7 @@ ieee80211_rx_check_bss_color_collision(struct ieee80211_rx_data *rx)
        if (ieee80211_hw_check(&rx->local->hw, DETECTS_COLOR_COLLISION))
                return;
 
-       if (rx->sdata->vif.bss_conf.csa_active)
+       if (rx->link->conf->csa_active)
                return;
 
        baselen = mgmt->u.beacon.variable - rx->skb->data;
@@ -3380,7 +3380,7 @@ ieee80211_rx_check_bss_color_collision(struct ieee80211_rx_data *rx)
                                    rx->skb->len - baselen);
        if (ie && ie->datalen >= sizeof(struct ieee80211_he_operation) &&
            ie->datalen >= ieee80211_he_oper_size(ie->data + 1)) {
-               struct ieee80211_bss_conf *bss_conf = &rx->sdata->vif.bss_conf;
+               struct ieee80211_bss_conf *bss_conf = rx->link->conf;
                const struct ieee80211_he_operation *he_oper;
                u8 color;
 
@@ -3393,7 +3393,8 @@ ieee80211_rx_check_bss_color_collision(struct ieee80211_rx_data *rx)
                                      IEEE80211_HE_OPERATION_BSS_COLOR_MASK);
                if (color == bss_conf->he_bss_color.color)
                        ieee80211_obss_color_collision_notify(&rx->sdata->vif,
-                                                             BIT_ULL(color));
+                                                             BIT_ULL(color),
+                                                             bss_conf->link_id);
        }
 }