mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2024-12-28 16:53:49 +00:00
wifi: mac80211: fix a queue stall in certain cases of CSA
If we got an unprotected action frame with CSA and then we heard the
beacon with the CSA IE, we'll block the queues with the CSA reason
twice. Since this reason is refcounted, we won't wake up the queues
since we wake them up only once and the ref count will never reach 0.
This led to blocked queues that prevented any activity (even
disconnection wouldn't reset the queue state and the only way to recover
would be to reload the kernel module.
Fix this by not refcounting the CSA reason.
It becomes now pointless to maintain the csa_blocked_queues state.
Remove it.
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Fixes: 414e090bc4
("wifi: mac80211: restrict public action ECSA frame handling")
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=219447
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20241119173108.5ea90828c2cc.I4f89e58572fb71ae48e47a81e74595cac410fbac@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
220bf00053
commit
11ac0d7c3b
@ -1972,7 +1972,7 @@ void iwl_mvm_channel_switch_error_notif(struct iwl_mvm *mvm,
|
||||
if (csa_err_mask & (CS_ERR_COUNT_ERROR |
|
||||
CS_ERR_LONG_DELAY_AFTER_CS |
|
||||
CS_ERR_TX_BLOCK_TIMER_EXPIRED))
|
||||
ieee80211_channel_switch_disconnect(vif, true);
|
||||
ieee80211_channel_switch_disconnect(vif);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
|
@ -6795,14 +6795,12 @@ void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success,
|
||||
/**
|
||||
* ieee80211_channel_switch_disconnect - disconnect due to channel switch error
|
||||
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
|
||||
* @block_tx: if %true, do not send deauth frame.
|
||||
*
|
||||
* Instruct mac80211 to disconnect due to a channel switch error. The channel
|
||||
* switch can request to block the tx and so, we need to make sure we do not send
|
||||
* a deauth frame in this case.
|
||||
*/
|
||||
void ieee80211_channel_switch_disconnect(struct ieee80211_vif *vif,
|
||||
bool block_tx);
|
||||
void ieee80211_channel_switch_disconnect(struct ieee80211_vif *vif);
|
||||
|
||||
/**
|
||||
* ieee80211_request_smps - request SM PS transition
|
||||
|
@ -3726,13 +3726,12 @@ void ieee80211_csa_finish(struct ieee80211_vif *vif, unsigned int link_id)
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_csa_finish);
|
||||
|
||||
void ieee80211_channel_switch_disconnect(struct ieee80211_vif *vif, bool block_tx)
|
||||
void ieee80211_channel_switch_disconnect(struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
|
||||
sdata->csa_blocked_queues = block_tx;
|
||||
sdata_info(sdata, "channel switch failed, disconnecting\n");
|
||||
wiphy_work_queue(local->hw.wiphy, &ifmgd->csa_connection_drop_work);
|
||||
}
|
||||
|
@ -1104,8 +1104,6 @@ struct ieee80211_sub_if_data {
|
||||
|
||||
unsigned long state;
|
||||
|
||||
bool csa_blocked_queues;
|
||||
|
||||
char name[IFNAMSIZ];
|
||||
|
||||
struct ieee80211_fragment_cache frags;
|
||||
@ -2412,17 +2410,13 @@ void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_hdr *hdr, bool ack, u16 tx_time);
|
||||
|
||||
unsigned int
|
||||
ieee80211_get_vif_queues(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
|
||||
unsigned long queues,
|
||||
enum queue_stop_reason reason,
|
||||
bool refcounted);
|
||||
void ieee80211_stop_vif_queues(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
enum queue_stop_reason reason);
|
||||
void ieee80211_wake_vif_queues(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
enum queue_stop_reason reason);
|
||||
void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
|
||||
unsigned long queues,
|
||||
enum queue_stop_reason reason,
|
||||
@ -2433,6 +2427,43 @@ void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
|
||||
void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
|
||||
enum queue_stop_reason reason,
|
||||
bool refcounted);
|
||||
static inline void
|
||||
ieee80211_stop_vif_queues(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
enum queue_stop_reason reason)
|
||||
{
|
||||
ieee80211_stop_queues_by_reason(&local->hw,
|
||||
ieee80211_get_vif_queues(local, sdata),
|
||||
reason, true);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ieee80211_wake_vif_queues(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
enum queue_stop_reason reason)
|
||||
{
|
||||
ieee80211_wake_queues_by_reason(&local->hw,
|
||||
ieee80211_get_vif_queues(local, sdata),
|
||||
reason, true);
|
||||
}
|
||||
static inline void
|
||||
ieee80211_stop_vif_queues_norefcount(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
enum queue_stop_reason reason)
|
||||
{
|
||||
ieee80211_stop_queues_by_reason(&local->hw,
|
||||
ieee80211_get_vif_queues(local, sdata),
|
||||
reason, false);
|
||||
}
|
||||
static inline void
|
||||
ieee80211_wake_vif_queues_norefcount(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
enum queue_stop_reason reason)
|
||||
{
|
||||
ieee80211_wake_queues_by_reason(&local->hw,
|
||||
ieee80211_get_vif_queues(local, sdata),
|
||||
reason, false);
|
||||
}
|
||||
void ieee80211_add_pending_skb(struct ieee80211_local *local,
|
||||
struct sk_buff *skb);
|
||||
void ieee80211_add_pending_skbs(struct ieee80211_local *local,
|
||||
|
@ -2374,18 +2374,14 @@ void ieee80211_vif_block_queues_csa(struct ieee80211_sub_if_data *sdata)
|
||||
if (ieee80211_hw_check(&local->hw, HANDLES_QUIET_CSA))
|
||||
return;
|
||||
|
||||
ieee80211_stop_vif_queues(local, sdata,
|
||||
IEEE80211_QUEUE_STOP_REASON_CSA);
|
||||
sdata->csa_blocked_queues = true;
|
||||
ieee80211_stop_vif_queues_norefcount(local, sdata,
|
||||
IEEE80211_QUEUE_STOP_REASON_CSA);
|
||||
}
|
||||
|
||||
void ieee80211_vif_unblock_queues_csa(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
|
||||
if (sdata->csa_blocked_queues) {
|
||||
ieee80211_wake_vif_queues(local, sdata,
|
||||
IEEE80211_QUEUE_STOP_REASON_CSA);
|
||||
sdata->csa_blocked_queues = false;
|
||||
}
|
||||
ieee80211_wake_vif_queues_norefcount(local, sdata,
|
||||
IEEE80211_QUEUE_STOP_REASON_CSA);
|
||||
}
|
||||
|
@ -2638,8 +2638,6 @@ ieee80211_sta_process_chanswitch(struct ieee80211_link_data *link,
|
||||
*/
|
||||
link->conf->csa_active = true;
|
||||
link->u.mgd.csa.blocked_tx = csa_ie.mode;
|
||||
sdata->csa_blocked_queues =
|
||||
csa_ie.mode && !ieee80211_hw_check(&local->hw, HANDLES_QUIET_CSA);
|
||||
|
||||
wiphy_work_queue(sdata->local->hw.wiphy,
|
||||
&ifmgd->csa_connection_drop_work);
|
||||
|
@ -657,7 +657,7 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw)
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_wake_queues);
|
||||
|
||||
static unsigned int
|
||||
unsigned int
|
||||
ieee80211_get_vif_queues(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
@ -669,7 +669,8 @@ ieee80211_get_vif_queues(struct ieee80211_local *local,
|
||||
queues = 0;
|
||||
|
||||
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
|
||||
queues |= BIT(sdata->vif.hw_queue[ac]);
|
||||
if (sdata->vif.hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE)
|
||||
queues |= BIT(sdata->vif.hw_queue[ac]);
|
||||
if (sdata->vif.cab_queue != IEEE80211_INVAL_HW_QUEUE)
|
||||
queues |= BIT(sdata->vif.cab_queue);
|
||||
} else {
|
||||
@ -724,24 +725,6 @@ void ieee80211_flush_queues(struct ieee80211_local *local,
|
||||
__ieee80211_flush_queues(local, sdata, 0, drop);
|
||||
}
|
||||
|
||||
void ieee80211_stop_vif_queues(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
enum queue_stop_reason reason)
|
||||
{
|
||||
ieee80211_stop_queues_by_reason(&local->hw,
|
||||
ieee80211_get_vif_queues(local, sdata),
|
||||
reason, true);
|
||||
}
|
||||
|
||||
void ieee80211_wake_vif_queues(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
enum queue_stop_reason reason)
|
||||
{
|
||||
ieee80211_wake_queues_by_reason(&local->hw,
|
||||
ieee80211_get_vif_queues(local, sdata),
|
||||
reason, true);
|
||||
}
|
||||
|
||||
static void __iterate_interfaces(struct ieee80211_local *local,
|
||||
u32 iter_flags,
|
||||
void (*iterator)(void *data, u8 *mac,
|
||||
|
Loading…
Reference in New Issue
Block a user