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:
 
                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);
 
 
 /******************************************************************************
  *
  * 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.
        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:
                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,
 
 
                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 */
 
 }
 
 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);
        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)
        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
                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;
                }
 
 /* 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 */
 /**
 
                }
                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 */
 
                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);
 
                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)
                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);
        }
 
 
        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;
 
                                  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,
  * 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
 
        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;
         * 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;
 
        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);
 
 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,
                drv_channel_switch_beacon(sdata, ¶ms->chandef);
        } else {
                /* if the beacon didn't change, we can finalize immediately */
-               ieee80211_csa_finalize(sdata);
+               ieee80211_csa_finalize(&sdata->deflink);
        }
 
 out:
 
 }
 
 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;
 
 
        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;
 }
 
         */
        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");
        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);
 
 
 );
 
 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
        )
 );