Message ID | 20230827135854.9f3d846ec9ad.Ic2d14e2285aa1646216a56806cfd4a8d0054437c@changeid (mailing list archive) |
---|---|
State | Superseded |
Delegated to: | Johannes Berg |
Headers | show |
Series | cfg80211/mac80211 patches from our internal tree 2023-08-27 | expand |
On 8/27/2023 4:05 AM, gregory.greenman@intel.com wrote: > From: Emmanuel Grumbach <emmanuel.grumbach@intel.com> > > 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> > --- > .../net/wireless/intel/iwlegacy/4965-mac.c | 2 +- > drivers/net/wireless/intel/iwlegacy/common.c | 2 +- > .../net/wireless/intel/iwlwifi/dvm/mac80211.c | 6 ++-- > .../net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 2 +- > .../net/wireless/intel/iwlwifi/mvm/mac80211.c | 10 +++--- > drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 3 +- > .../wireless/intel/iwlwifi/mvm/time-event.c | 2 +- > drivers/net/wireless/ti/wlcore/event.c | 2 +- > drivers/net/wireless/ti/wlcore/main.c | 6 ++-- > include/net/mac80211.h | 8 +++-- > net/mac80211/cfg.c | 35 ++++++++++--------- > net/mac80211/driver-ops.h | 6 ++-- > net/mac80211/mlme.c | 29 ++++++++++----- ... > diff --git a/include/net/mac80211.h b/include/net/mac80211.h > index 7c707358d15c..67f54825110f 100644 > --- a/include/net/mac80211.h > +++ b/include/net/mac80211.h > @@ -4544,7 +4544,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, > @@ -6542,11 +6543,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. I would not call this being ignored: + link = rcu_dereference(sdata->link[link_id]); + if (WARN_ON(!link)) { + rcu_read_unlock(); + return; + } > * > * 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 ... > diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c > index f93eb38ae0b8..ca6045f56b4b 100644 > --- a/net/mac80211/mlme.c > +++ b/net/mac80211/mlme.c > @@ -1773,7 +1773,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"); > @@ -1785,25 +1785,36 @@ 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_link_data *link; > 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; > + struct ieee80211_link_data_managed *ifmgd; > > trace_api_chswitch_done(sdata, success); no value in tracing the link_id? > + > + rcu_read_lock(); > + > + link = rcu_dereference(sdata->link[link_id]); > + if (WARN_ON(!link)) { > + rcu_read_unlock(); > + return; > + } > + > + ifmgd = &link->u.mgd; > + > 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 { > wiphy_delayed_work_queue(sdata->local->hw.wiphy, > - &sdata->deflink.u.mgd.chswitch_work, > - 0); > + &ifmgd->chswitch_work, 0); > } > + > + rcu_read_unlock(); > } > EXPORT_SYMBOL(ieee80211_chswitch_done); >
On Sun, 2023-08-27 at 09:43 -0700, Jeff Johnson wrote: > On 8/27/2023 4:05 AM, gregory.greenman@intel.com wrote: > > From: Emmanuel Grumbach <emmanuel.grumbach@intel.com> > > > > 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> > > --- > > .../net/wireless/intel/iwlegacy/4965-mac.c | 2 +- > > drivers/net/wireless/intel/iwlegacy/common.c | 2 +- > > .../net/wireless/intel/iwlwifi/dvm/mac80211.c | 6 ++-- > > .../net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 2 +- > > .../net/wireless/intel/iwlwifi/mvm/mac80211.c | 10 +++--- > > drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 3 +- > > .../wireless/intel/iwlwifi/mvm/time-event.c | 2 +- > > drivers/net/wireless/ti/wlcore/event.c | 2 +- > > drivers/net/wireless/ti/wlcore/main.c | 6 ++-- > > include/net/mac80211.h | 8 +++-- > > net/mac80211/cfg.c | 35 ++++++++++--------- > > net/mac80211/driver-ops.h | 6 ++-- > > net/mac80211/mlme.c | 29 ++++++++++----- > ... > > diff --git a/include/net/mac80211.h b/include/net/mac80211.h > > index 7c707358d15c..67f54825110f 100644 > > --- a/include/net/mac80211.h > > +++ b/include/net/mac80211.h > > @@ -4544,7 +4544,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, > > @@ -6542,11 +6543,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. > > I would not call this being ignored: > + link = rcu_dereference(sdata->link[link_id]); > + if (WARN_ON(!link)) { > + rcu_read_unlock(); > + return; > + } > Yeah - you're right. We don't need the link pointer in case success is false and yet we return here, I'll fix. > > * > > * 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 > ... > > diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c > > index f93eb38ae0b8..ca6045f56b4b 100644 > > --- a/net/mac80211/mlme.c > > +++ b/net/mac80211/mlme.c > > @@ -1773,7 +1773,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"); > > @@ -1785,25 +1785,36 @@ 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_link_data *link; > > 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; > > + struct ieee80211_link_data_managed *ifmgd; > > > > trace_api_chswitch_done(sdata, success); > > no value in tracing the link_id? I can add it. > > > + > > + rcu_read_lock(); > > + > > + link = rcu_dereference(sdata->link[link_id]); > > + if (WARN_ON(!link)) { > > + rcu_read_unlock(); > > + return; > > + } > > + > > + ifmgd = &link->u.mgd; > > + > > 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 { > > wiphy_delayed_work_queue(sdata->local->hw.wiphy, > > - &sdata->deflink.u.mgd.chswitch_work, > > - 0); > > + &ifmgd->chswitch_work, 0); > > } > > + > > + rcu_read_unlock(); > > } > > EXPORT_SYMBOL(ieee80211_chswitch_done); > > > Gregory / Johannes, I'll send a patch internally to fix the issues raised here and you'll squash before resending?
diff --git a/drivers/net/wireless/intel/iwlegacy/4965-mac.c b/drivers/net/wireless/intel/iwlegacy/4965-mac.c index 0a4aa3c678c1..69276266ce6f 100644 --- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c @@ -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: diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c index 96002121bb8b..054fef680aba 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.c +++ b/drivers/net/wireless/intel/iwlegacy/common.c @@ -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); diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c index b1939ff275b5..5f3d5b15f727 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c @@ -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, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 7369a45f7f2b..b28d998c65c5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -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 */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 5918c1f2b10c..921f72dcddac 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -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; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index b18c91c5dd5d..dda13f4351c3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -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 */ /** diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 5f0e7144a951..e1f6cea649c3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -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 */ diff --git a/drivers/net/wireless/ti/wlcore/event.c b/drivers/net/wireless/ti/wlcore/event.c index 46ab69eab26a..1e082d039b82 100644 --- a/drivers/net/wireless/ti/wlcore/event.c +++ b/drivers/net/wireless/ti/wlcore/event.c @@ -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); diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index bf21611872a3..b7e68d2721c1 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -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; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 7c707358d15c..67f54825110f 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -4544,7 +4544,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, @@ -6542,11 +6543,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 diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 45e7a5d9c7d9..ae5017edd09f 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -3638,8 +3638,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; @@ -3655,20 +3656,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; @@ -3685,25 +3686,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); @@ -3712,9 +3715,9 @@ static void ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) void ieee80211_csa_finalize_work(struct work_struct *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; sdata_lock(sdata); @@ -3722,13 +3725,13 @@ void ieee80211_csa_finalize_work(struct work_struct *work) mutex_lock(&local->chanctx_mtx); /* AP might have been stopped while waiting for the lock. */ - if (!sdata->vif.bss_conf.csa_active) + if (!link->conf->csa_active) goto unlock; if (!ieee80211_sdata_running(sdata)) goto unlock; - ieee80211_csa_finalize(sdata); + ieee80211_csa_finalize(link); unlock: mutex_unlock(&local->chanctx_mtx); @@ -3978,7 +3981,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, 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: diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index c4505593ba7a..a41dd60ae4b4 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -1072,8 +1072,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; @@ -1082,7 +1083,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; } diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index f93eb38ae0b8..ca6045f56b4b 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1773,7 +1773,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"); @@ -1785,25 +1785,36 @@ 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_link_data *link; 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; + struct ieee80211_link_data_managed *ifmgd; trace_api_chswitch_done(sdata, success); + + rcu_read_lock(); + + link = rcu_dereference(sdata->link[link_id]); + if (WARN_ON(!link)) { + rcu_read_unlock(); + return; + } + + ifmgd = &link->u.mgd; + 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 { wiphy_delayed_work_queue(sdata->local->hw.wiphy, - &sdata->deflink.u.mgd.chswitch_work, - 0); + &ifmgd->chswitch_work, 0); } + + rcu_read_unlock(); } EXPORT_SYMBOL(ieee80211_chswitch_done);