mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-06 05:06:29 +00:00
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:
parent
5ea82df1f5
commit
a469a5938d
@ -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:
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
/**
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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, ¶ms->chandef);
|
||||
} else {
|
||||
/* if the beacon didn't change, we can finalize immediately */
|
||||
ieee80211_csa_finalize(sdata);
|
||||
ieee80211_csa_finalize(&sdata->deflink);
|
||||
}
|
||||
|
||||
out:
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
)
|
||||
);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user