wifi: mac80211: add support for mld in ieee80211_chswitch_done

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>
This commit is contained in:
Emmanuel Grumbach 2023-08-28 13:04:10 +03:00 committed by Johannes Berg
parent 5ea82df1f5
commit a469a5938d
14 changed files with 73 additions and 49 deletions

View 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:

View 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);

View 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,

View 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 */

View 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;
}

View 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 */
/**

View 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 */

View 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);

View 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;

View 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

View 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:

View 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;
}

View 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);

View 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
)
);