wifi: mac80211: add support for mld in ieee80211_chswitch_done
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Mon, 28 Aug 2023 10:04:10 +0000 (13:04 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 11 Sep 2023 10:31:31 +0000 (12:31 +0200)
This allows to finalize the CSA per link.
In case the switch didn't work, tear down the MLD connection.
Also pass the ieee80211_bss_conf to post_channel_switch to let the
driver know which link completed the switch.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20230828130311.3d3eacc88436.Ic2d14e2285aa1646216a56806cfd4a8d0054437c@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
14 files changed:
drivers/net/wireless/intel/iwlegacy/4965-mac.c
drivers/net/wireless/intel/iwlegacy/common.c
drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
drivers/net/wireless/ti/wlcore/event.c
drivers/net/wireless/ti/wlcore/main.c
include/net/mac80211.h
net/mac80211/cfg.c
net/mac80211/driver-ops.h
net/mac80211/mlme.c
net/mac80211/trace.h

index 0a4aa3c678c1017c40addc2b94d20c1d0f0d4d5e..69276266ce6f40c8b206160e000e8caaaa6add23 100644 (file)
@@ -6122,7 +6122,7 @@ il4965_mac_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        if (il->ops->set_channel_switch(il, ch_switch)) {
                clear_bit(S_CHANNEL_SWITCH_PENDING, &il->status);
                il->switch_channel = 0;
-               ieee80211_chswitch_done(il->vif, false);
+               ieee80211_chswitch_done(il->vif, false, 0);
        }
 
 out:
index 96002121bb8b27b2cafd961b24491251a26e04ce..054fef680aba0e2498b48873184d5238bea1f6a1 100644 (file)
@@ -4090,7 +4090,7 @@ il_chswitch_done(struct il_priv *il, bool is_success)
                return;
 
        if (test_and_clear_bit(S_CHANNEL_SWITCH_PENDING, &il->status))
-               ieee80211_chswitch_done(il->vif, is_success);
+               ieee80211_chswitch_done(il->vif, is_success, 0);
 }
 EXPORT_SYMBOL(il_chswitch_done);
 
index b1939ff275b51f8bcf5d0dec9af9aba644843589..5f3d5b15f727eaba4b55096a9488251232ce2a33 100644 (file)
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
- * Copyright (C) 2018 - 2019, 2022 Intel Corporation
+ * Copyright(C) 2018 - 2019, 2022 - 2023 Intel Corporation
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
@@ -1001,7 +1001,7 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
        if (priv->lib->set_channel_switch(priv, ch_switch)) {
                clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status);
                priv->switch_channel = 0;
-               ieee80211_chswitch_done(ctx->vif, false);
+               ieee80211_chswitch_done(ctx->vif, false, 0);
        }
 
 out:
@@ -1024,7 +1024,7 @@ void iwl_chswitch_done(struct iwl_priv *priv, bool is_success)
                return;
 
        if (ctx->vif)
-               ieee80211_chswitch_done(ctx->vif, is_success);
+               ieee80211_chswitch_done(ctx->vif, is_success, 0);
 }
 
 static void iwlagn_configure_filter(struct ieee80211_hw *hw,
index 7369a45f7f2bd7a4b23ff7f8ba07486f78b5993e..b28d998c65c5b3686dff33131398c9b8d8f82dea 100644 (file)
@@ -1839,7 +1839,7 @@ void iwl_mvm_channel_switch_start_notif(struct iwl_mvm *mvm,
 
                iwl_mvm_csa_client_absent(mvm, vif);
                cancel_delayed_work(&mvmvif->csa_work);
-               ieee80211_chswitch_done(vif, true);
+               ieee80211_chswitch_done(vif, true, 0);
                break;
        default:
                /* should never happen */
index 5918c1f2b10c38d84335a407b37efb68c90c1d7a..921f72dcddac9bafa84c991c459ee8cb80768504 100644 (file)
@@ -1370,7 +1370,8 @@ int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 }
 
 int iwl_mvm_post_channel_switch(struct ieee80211_hw *hw,
-                               struct ieee80211_vif *vif)
+                               struct ieee80211_vif *vif,
+                               struct ieee80211_bss_conf *link_conf)
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
@@ -1452,7 +1453,8 @@ void iwl_mvm_abort_channel_switch(struct ieee80211_hw *hw,
        mvmvif->csa_failed = true;
        mutex_unlock(&mvm->mutex);
 
-       iwl_mvm_post_channel_switch(hw, vif);
+       /* If we're here, we can't support MLD */
+       iwl_mvm_post_channel_switch(hw, vif, &vif->bss_conf);
 }
 
 void iwl_mvm_channel_switch_disconnect_wk(struct work_struct *wk)
@@ -1464,7 +1466,7 @@ void iwl_mvm_channel_switch_disconnect_wk(struct work_struct *wk)
        vif = container_of((void *)mvmvif, struct ieee80211_vif, drv_priv);
 
        /* Trigger disconnect (should clear the CSA state) */
-       ieee80211_chswitch_done(vif, false);
+       ieee80211_chswitch_done(vif, false, 0);
 }
 
 static u8
@@ -5535,7 +5537,7 @@ void iwl_mvm_channel_switch_rx_beacon(struct ieee80211_hw *hw,
                if (mvmvif->csa_misbehave) {
                        /* Second time, give up on this AP*/
                        iwl_mvm_abort_channel_switch(hw, vif);
-                       ieee80211_chswitch_done(vif, false);
+                       ieee80211_chswitch_done(vif, false, 0);
                        mvmvif->csa_misbehave = false;
                        return;
                }
index b18c91c5dd5d1c0691ab910c38184344776a5566..dda13f4351c3c6975108f26a9cc97784fe483f3f 100644 (file)
@@ -2427,7 +2427,8 @@ static inline u8 iwl_mvm_phy_band_from_nl80211(enum nl80211_band band)
 /* Channel Switch */
 void iwl_mvm_channel_switch_disconnect_wk(struct work_struct *wk);
 int iwl_mvm_post_channel_switch(struct ieee80211_hw *hw,
-                               struct ieee80211_vif *vif);
+                               struct ieee80211_vif *vif,
+                               struct ieee80211_bss_conf *link);
 
 /* Channel Context */
 /**
index 5f0e7144a951ce9f1eaeb0e781acdfbe13ea01b3..e1f6cea649c3738af9c29f0c8bc51482b710a4f1 100644 (file)
@@ -223,7 +223,7 @@ iwl_mvm_te_handle_notify_csa(struct iwl_mvm *mvm,
                }
                iwl_mvm_csa_client_absent(mvm, te_data->vif);
                cancel_delayed_work(&mvmvif->csa_work);
-               ieee80211_chswitch_done(te_data->vif, true);
+               ieee80211_chswitch_done(te_data->vif, true, 0);
                break;
        default:
                /* should never happen */
index 46ab69eab26a9a20df1da68522be0e97c1a3a6a2..1e082d039b8224e694396adb0db71567bf711627 100644 (file)
@@ -229,7 +229,7 @@ void wlcore_event_channel_switch(struct wl1271 *wl,
                vif = wl12xx_wlvif_to_vif(wlvif);
 
                if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
-                       ieee80211_chswitch_done(vif, success);
+                       ieee80211_chswitch_done(vif, success, 0);
                        cancel_delayed_work(&wlvif->channel_switch_work);
                } else {
                        set_bit(WLVIF_FLAG_BEACON_DISABLED, &wlvif->flags);
index bf21611872a3c1ac81438a72439d694933083ef7..b7e68d2721c145fe55efabd1ab961a7f456d2aea 100644 (file)
@@ -2043,7 +2043,7 @@ static void wlcore_channel_switch_work(struct work_struct *work)
                goto out;
 
        vif = wl12xx_wlvif_to_vif(wlvif);
-       ieee80211_chswitch_done(vif, false);
+       ieee80211_chswitch_done(vif, false, 0);
 
        ret = pm_runtime_resume_and_get(wl->dev);
        if (ret < 0)
@@ -3030,7 +3030,7 @@ static int wlcore_unset_assoc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
                struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
 
                wl12xx_cmd_stop_channel_switch(wl, wlvif);
-               ieee80211_chswitch_done(vif, false);
+               ieee80211_chswitch_done(vif, false, 0);
                cancel_delayed_work(&wlvif->channel_switch_work);
        }
 
@@ -5451,7 +5451,7 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
 
        if (unlikely(wl->state == WLCORE_STATE_OFF)) {
                if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
-                       ieee80211_chswitch_done(vif, false);
+                       ieee80211_chswitch_done(vif, false, 0);
                goto out;
        } else if (unlikely(wl->state != WLCORE_STATE_ON)) {
                goto out;
index 154592ce48e5fb9252a10422704025ec8d2a66f6..09fe4601bf592333be5659bc65a174f02d1eb7b2 100644 (file)
@@ -4539,7 +4539,8 @@ struct ieee80211_ops {
                                  struct ieee80211_channel_switch *ch_switch);
 
        int (*post_channel_switch)(struct ieee80211_hw *hw,
-                                  struct ieee80211_vif *vif);
+                                  struct ieee80211_vif *vif,
+                                  struct ieee80211_bss_conf *link_conf);
        void (*abort_channel_switch)(struct ieee80211_hw *hw,
                                     struct ieee80211_vif *vif);
        void (*channel_switch_rx_beacon)(struct ieee80211_hw *hw,
@@ -6537,11 +6538,14 @@ void ieee80211_radar_detected(struct ieee80211_hw *hw);
  * ieee80211_chswitch_done - Complete channel switch process
  * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  * @success: make the channel switch successful or not
+ * @link_id: the link_id on which the switch was done. Ignored if success is
+ *     false.
  *
  * Complete the channel switch post-process: set the new operational channel
  * and wake up the suspended queues.
  */
-void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success);
+void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success,
+                            unsigned int link_id);
 
 /**
  * ieee80211_channel_switch_disconnect - disconnect due to channel switch error
index 851d6ed68367abb8aff71fd5ddb4cb57891e6d1c..490ee6f52d6e8d33f71ab5445f2eceec17772c28 100644 (file)
@@ -3590,8 +3590,9 @@ static int ieee80211_set_after_csa_beacon(struct ieee80211_sub_if_data *sdata,
        return 0;
 }
 
-static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
+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;
        u64 changed = 0;
        int err;
@@ -3605,20 +3606,20 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
         * completed successfully
         */
 
-       if (sdata->deflink.reserved_chanctx) {
+       if (link_data->reserved_chanctx) {
                /*
                 * with multi-vif csa driver may call ieee80211_csa_finish()
                 * many times while waiting for other interfaces to use their
                 * reservations
                 */
-               if (sdata->deflink.reserved_ready)
+               if (link_data->reserved_ready)
                        return 0;
 
                return ieee80211_link_use_reserved_context(&sdata->deflink);
        }
 
        if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef,
-                                       &sdata->deflink.csa_chandef))
+                                       &link_data->csa_chandef))
                return -EINVAL;
 
        sdata->vif.bss_conf.csa_active = false;
@@ -3635,25 +3636,27 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
 
        ieee80211_link_info_change_notify(sdata, &sdata->deflink, changed);
 
-       if (sdata->deflink.csa_block_tx) {
+       if (link_data->csa_block_tx) {
                ieee80211_wake_vif_queues(local, sdata,
                                          IEEE80211_QUEUE_STOP_REASON_CSA);
-               sdata->deflink.csa_block_tx = false;
+               link_data->csa_block_tx = false;
        }
 
-       err = drv_post_channel_switch(sdata);
+       err = drv_post_channel_switch(link_data);
        if (err)
                return err;
 
-       cfg80211_ch_switch_notify(sdata->dev, &sdata->deflink.csa_chandef, 0,
+       cfg80211_ch_switch_notify(sdata->dev, &link_data->csa_chandef, 0,
                                  sdata->vif.bss_conf.eht_puncturing);
 
        return 0;
 }
 
-static void ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
+static void ieee80211_csa_finalize(struct ieee80211_link_data *link_data)
 {
-       if (__ieee80211_csa_finalize(sdata)) {
+       struct ieee80211_sub_if_data *sdata = link_data->sdata;
+
+       if (__ieee80211_csa_finalize(link_data)) {
                sdata_info(sdata, "failed to finalize CSA, disconnecting\n");
                cfg80211_stop_iface(sdata->local->hw.wiphy, &sdata->wdev,
                                    GFP_KERNEL);
@@ -3662,21 +3665,21 @@ static void ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
 
 void ieee80211_csa_finalize_work(struct wiphy *wiphy, struct wiphy_work *work)
 {
-       struct ieee80211_sub_if_data *sdata =
-               container_of(work, struct ieee80211_sub_if_data,
-                            deflink.csa_finalize_work);
+       struct ieee80211_link_data *link =
+               container_of(work, struct ieee80211_link_data, csa_finalize_work);
+       struct ieee80211_sub_if_data *sdata = link->sdata;
        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.csa_active)
+       if (!link->conf->csa_active)
                return;
 
        if (!ieee80211_sdata_running(sdata))
                return;
 
-       ieee80211_csa_finalize(sdata);
+       ieee80211_csa_finalize(link);
 }
 
 static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata,
@@ -3919,7 +3922,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
                drv_channel_switch_beacon(sdata, &params->chandef);
        } else {
                /* if the beacon didn't change, we can finalize immediately */
-               ieee80211_csa_finalize(sdata);
+               ieee80211_csa_finalize(&sdata->deflink);
        }
 
 out:
index 554c7aa10cc2b32aba24319e801ab2551646c0b1..77048b9065e696101f20eaad232a9403e871ed65 100644 (file)
@@ -1126,8 +1126,9 @@ drv_pre_channel_switch(struct ieee80211_sub_if_data *sdata,
 }
 
 static inline int
-drv_post_channel_switch(struct ieee80211_sub_if_data *sdata)
+drv_post_channel_switch(struct ieee80211_link_data *link)
 {
+       struct ieee80211_sub_if_data *sdata = link->sdata;
        struct ieee80211_local *local = sdata->local;
        int ret = 0;
 
@@ -1139,7 +1140,8 @@ drv_post_channel_switch(struct ieee80211_sub_if_data *sdata)
 
        trace_drv_post_channel_switch(local, sdata);
        if (local->ops->post_channel_switch)
-               ret = local->ops->post_channel_switch(&local->hw, &sdata->vif);
+               ret = local->ops->post_channel_switch(&local->hw, &sdata->vif,
+                                                     link->conf);
        trace_drv_return_int(local, ret);
        return ret;
 }
index 6d0a29749e8c3aae98ba2da481bf3bb98be009c2..0f295c5403b36f16836bdce510b074d900bf063e 100644 (file)
@@ -1763,7 +1763,7 @@ static void ieee80211_chswitch_post_beacon(struct ieee80211_link_data *link)
         */
        link->u.mgd.beacon_crc_valid = false;
 
-       ret = drv_post_channel_switch(sdata);
+       ret = drv_post_channel_switch(link);
        if (ret) {
                sdata_info(sdata,
                           "driver post channel switch failed, disconnecting\n");
@@ -1775,25 +1775,34 @@ static void ieee80211_chswitch_post_beacon(struct ieee80211_link_data *link)
        cfg80211_ch_switch_notify(sdata->dev, &link->reserved_chandef, 0, 0);
 }
 
-void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success)
+void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success,
+                            unsigned int link_id)
 {
        struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
-       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 
-       if (WARN_ON(ieee80211_vif_is_mld(&sdata->vif)))
-               success = false;
+       trace_api_chswitch_done(sdata, success, link_id);
+
+       rcu_read_lock();
 
-       trace_api_chswitch_done(sdata, success);
        if (!success) {
                sdata_info(sdata,
                           "driver channel switch failed, disconnecting\n");
                wiphy_work_queue(sdata->local->hw.wiphy,
-                                &ifmgd->csa_connection_drop_work);
+                                &sdata->u.mgd.csa_connection_drop_work);
        } else {
+               struct ieee80211_link_data *link =
+                       rcu_dereference(sdata->link[link_id]);
+
+               if (WARN_ON(!link)) {
+                       rcu_read_unlock();
+                       return;
+               }
+
                wiphy_delayed_work_queue(sdata->local->hw.wiphy,
-                                        &sdata->deflink.u.mgd.chswitch_work,
-                                        0);
+                                        &link->u.mgd.chswitch_work, 0);
        }
+
+       rcu_read_unlock();
 }
 EXPORT_SYMBOL(ieee80211_chswitch_done);
 
index b8c53b4a710bddcfa6a267284e68dbfe315372a4..032718d5b298c3467ab0f2420a1f1d6ad980d6a2 100644 (file)
@@ -2839,23 +2839,26 @@ TRACE_EVENT(api_sta_block_awake,
 );
 
 TRACE_EVENT(api_chswitch_done,
-       TP_PROTO(struct ieee80211_sub_if_data *sdata, bool success),
+       TP_PROTO(struct ieee80211_sub_if_data *sdata, bool success,
+                unsigned int link_id),
 
-       TP_ARGS(sdata, success),
+       TP_ARGS(sdata, success, link_id),
 
        TP_STRUCT__entry(
                VIF_ENTRY
                __field(bool, success)
+               __field(unsigned int, link_id)
        ),
 
        TP_fast_assign(
                VIF_ASSIGN;
                __entry->success = success;
+               __entry->link_id = link_id;
        ),
 
        TP_printk(
-               VIF_PR_FMT " success=%d",
-               VIF_PR_ARG, __entry->success
+               VIF_PR_FMT " success=%d link_id=%d",
+               VIF_PR_ARG, __entry->success, __entry->link_id
        )
 );