wifi: mac80211: start and finalize channel switch on link basis
authorAditya Kumar Singh <quic_adisi@quicinc.com>
Tue, 30 Jan 2024 14:09:17 +0000 (19:39 +0530)
committerJohannes Berg <johannes.berg@intel.com>
Thu, 8 Feb 2024 14:00:45 +0000 (15:00 +0100)
Add changes to start a channel switch as well as finalize it on link basis
in order to support CSA with MLO as well.

Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
Link: https://msgid.link/20240130140918.1172387-5-quic_adisi@quicinc.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/cfg.c
net/mac80211/link.c

index 0c0f418c365228c47d36e3973cd7e726335484a3..d30a64cf95cd48388483e8573509876a2388ff37 100644 (file)
@@ -3633,6 +3633,7 @@ static int __ieee80211_csa_finalize(struct ieee80211_link_data *link_data)
 {
        struct ieee80211_sub_if_data *sdata = link_data->sdata;
        struct ieee80211_local *local = sdata->local;
+       struct ieee80211_bss_conf *link_conf = link_data->conf;
        u64 changed = 0;
        int err;
 
@@ -3654,16 +3655,16 @@ static int __ieee80211_csa_finalize(struct ieee80211_link_data *link_data)
                if (link_data->reserved_ready)
                        return 0;
 
-               return ieee80211_link_use_reserved_context(&sdata->deflink);
+               return ieee80211_link_use_reserved_context(link_data);
        }
 
-       if (!cfg80211_chandef_identical(&link_data->conf->chanreq.oper,
+       if (!cfg80211_chandef_identical(&link_conf->chanreq.oper,
                                        &link_data->csa_chanreq.oper))
                return -EINVAL;
 
-       sdata->vif.bss_conf.csa_active = false;
+       link_conf->csa_active = false;
 
-       err = ieee80211_set_after_csa_beacon(&sdata->deflink, &changed);
+       err = ieee80211_set_after_csa_beacon(link_data, &changed);
        if (err)
                return err;
 
@@ -3690,7 +3691,8 @@ static void ieee80211_csa_finalize(struct ieee80211_link_data *link_data)
        struct ieee80211_sub_if_data *sdata = link_data->sdata;
 
        if (__ieee80211_csa_finalize(link_data)) {
-               sdata_info(sdata, "failed to finalize CSA, disconnecting\n");
+               sdata_info(sdata, "failed to finalize CSA on link %d, disconnecting\n",
+                          link_data->link_id);
                cfg80211_stop_iface(sdata->local->hw.wiphy, &sdata->wdev,
                                    GFP_KERNEL);
        }
@@ -3867,7 +3869,10 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
        struct ieee80211_channel_switch ch_switch;
        struct ieee80211_chanctx_conf *conf;
        struct ieee80211_chanctx *chanctx;
+       struct ieee80211_bss_conf *link_conf;
+       struct ieee80211_link_data *link_data;
        u64 changed = 0;
+       u8 link_id = params->link_id;
        int err;
 
        lockdep_assert_wiphy(local->hw.wiphy);
@@ -3878,15 +3883,23 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
        if (sdata->wdev.cac_started)
                return -EBUSY;
 
-       if (chanreq.oper.punctured && !sdata->vif.bss_conf.eht_support)
+       if (WARN_ON(link_id >= IEEE80211_MLD_MAX_NUM_LINKS))
+               return -EINVAL;
+
+       link_data = wiphy_dereference(wiphy, sdata->link[link_id]);
+       if (!link_data)
+               return -ENOLINK;
+
+       link_conf = link_data->conf;
+
+       if (chanreq.oper.punctured && !link_conf->eht_support)
                return -EINVAL;
 
        /* don't allow another channel switch if one is already active. */
-       if (sdata->vif.bss_conf.csa_active)
+       if (link_conf->csa_active)
                return -EBUSY;
 
-       conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf,
-                                        lockdep_is_held(&local->hw.wiphy->mtx));
+       conf = wiphy_dereference(wiphy, link_conf->chanctx_conf);
        if (!conf) {
                err = -EBUSY;
                goto out;
@@ -3910,7 +3923,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
        if (err)
                goto out;
 
-       err = ieee80211_link_reserve_chanctx(&sdata->deflink, &chanreq,
+       err = ieee80211_link_reserve_chanctx(link_data, &chanreq,
                                             chanctx->mode,
                                             params->radar_required);
        if (err)
@@ -3919,40 +3932,38 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
        /* if reservation is invalid then this will fail */
        err = ieee80211_check_combinations(sdata, NULL, chanctx->mode, 0);
        if (err) {
-               ieee80211_link_unreserve_chanctx(&sdata->deflink);
+               ieee80211_link_unreserve_chanctx(link_data);
                goto out;
        }
 
        /* if there is a color change in progress, abort it */
-       if (sdata->vif.bss_conf.color_change_active)
+       if (link_conf->color_change_active)
                ieee80211_color_change_abort(sdata);
 
-       err = ieee80211_set_csa_beacon(&sdata->deflink, params, &changed);
+       err = ieee80211_set_csa_beacon(link_data, params, &changed);
        if (err) {
-               ieee80211_link_unreserve_chanctx(&sdata->deflink);
+               ieee80211_link_unreserve_chanctx(link_data);
                goto out;
        }
 
-       sdata->deflink.csa_chanreq = chanreq; 
-       sdata->deflink.csa_block_tx = params->block_tx;
-       sdata->vif.bss_conf.csa_active = true;
+       link_data->csa_chanreq = chanreq; 
+       link_data->csa_block_tx = params->block_tx;
+       link_conf->csa_active = true;
 
-       if (sdata->deflink.csa_block_tx)
+       if (link_data->csa_block_tx)
                ieee80211_stop_vif_queues(local, sdata,
                                          IEEE80211_QUEUE_STOP_REASON_CSA);
 
        cfg80211_ch_switch_started_notify(sdata->dev,
-                                         &sdata->deflink.csa_chanreq.oper, 0,
+                                         &link_data->csa_chanreq.oper, 0,
                                          params->count, params->block_tx);
 
        if (changed) {
-               ieee80211_link_info_change_notify(sdata, &sdata->deflink,
-                                                 changed);
-               drv_channel_switch_beacon(sdata,
-                                         &sdata->deflink.csa_chanreq.oper);
+               ieee80211_link_info_change_notify(sdata, link_data, changed);
+               drv_channel_switch_beacon(sdata, &link_data->csa_chanreq.oper);
        } else {
                /* if the beacon didn't change, we can finalize immediately */
-               ieee80211_csa_finalize(&sdata->deflink);
+               ieee80211_csa_finalize(link_data);
        }
 
 out:
index 4f19d6479befda7293a73ee47589ce7c58711ec4..87a413374eceefebbd1c70fd511b99f777da9204 100644 (file)
@@ -73,6 +73,8 @@ void ieee80211_link_stop(struct ieee80211_link_data *link)
                ieee80211_mgd_stop_link(link);
 
        cancel_delayed_work_sync(&link->color_collision_detect_work);
+       wiphy_work_cancel(link->sdata->local->hw.wiphy,
+                         &link->csa_finalize_work);
        ieee80211_link_release_channel(link);
 }