Skip to content

Commit 11ac0d7

Browse files
egrumbachjmberg-intel
authored andcommitted
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: 414e090 ("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>
1 parent 220bf00 commit 11ac0d7

File tree

7 files changed

+50
-45
lines changed

7 files changed

+50
-45
lines changed

drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1972,7 +1972,7 @@ void iwl_mvm_channel_switch_error_notif(struct iwl_mvm *mvm,
19721972
if (csa_err_mask & (CS_ERR_COUNT_ERROR |
19731973
CS_ERR_LONG_DELAY_AFTER_CS |
19741974
CS_ERR_TX_BLOCK_TIMER_EXPIRED))
1975-
ieee80211_channel_switch_disconnect(vif, true);
1975+
ieee80211_channel_switch_disconnect(vif);
19761976
rcu_read_unlock();
19771977
}
19781978

include/net/mac80211.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6795,14 +6795,12 @@ void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success,
67956795
/**
67966796
* ieee80211_channel_switch_disconnect - disconnect due to channel switch error
67976797
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
6798-
* @block_tx: if %true, do not send deauth frame.
67996798
*
68006799
* Instruct mac80211 to disconnect due to a channel switch error. The channel
68016800
* switch can request to block the tx and so, we need to make sure we do not send
68026801
* a deauth frame in this case.
68036802
*/
6804-
void ieee80211_channel_switch_disconnect(struct ieee80211_vif *vif,
6805-
bool block_tx);
6803+
void ieee80211_channel_switch_disconnect(struct ieee80211_vif *vif);
68066804

68076805
/**
68086806
* ieee80211_request_smps - request SM PS transition

net/mac80211/cfg.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3726,13 +3726,12 @@ void ieee80211_csa_finish(struct ieee80211_vif *vif, unsigned int link_id)
37263726
}
37273727
EXPORT_SYMBOL(ieee80211_csa_finish);
37283728

3729-
void ieee80211_channel_switch_disconnect(struct ieee80211_vif *vif, bool block_tx)
3729+
void ieee80211_channel_switch_disconnect(struct ieee80211_vif *vif)
37303730
{
37313731
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
37323732
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
37333733
struct ieee80211_local *local = sdata->local;
37343734

3735-
sdata->csa_blocked_queues = block_tx;
37363735
sdata_info(sdata, "channel switch failed, disconnecting\n");
37373736
wiphy_work_queue(local->hw.wiphy, &ifmgd->csa_connection_drop_work);
37383737
}

net/mac80211/ieee80211_i.h

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,8 +1104,6 @@ struct ieee80211_sub_if_data {
11041104

11051105
unsigned long state;
11061106

1107-
bool csa_blocked_queues;
1108-
11091107
char name[IFNAMSIZ];
11101108

11111109
struct ieee80211_fragment_cache frags;
@@ -2412,17 +2410,13 @@ void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local,
24122410
struct ieee80211_sub_if_data *sdata);
24132411
void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
24142412
struct ieee80211_hdr *hdr, bool ack, u16 tx_time);
2415-
2413+
unsigned int
2414+
ieee80211_get_vif_queues(struct ieee80211_local *local,
2415+
struct ieee80211_sub_if_data *sdata);
24162416
void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
24172417
unsigned long queues,
24182418
enum queue_stop_reason reason,
24192419
bool refcounted);
2420-
void ieee80211_stop_vif_queues(struct ieee80211_local *local,
2421-
struct ieee80211_sub_if_data *sdata,
2422-
enum queue_stop_reason reason);
2423-
void ieee80211_wake_vif_queues(struct ieee80211_local *local,
2424-
struct ieee80211_sub_if_data *sdata,
2425-
enum queue_stop_reason reason);
24262420
void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
24272421
unsigned long queues,
24282422
enum queue_stop_reason reason,
@@ -2433,6 +2427,43 @@ void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
24332427
void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
24342428
enum queue_stop_reason reason,
24352429
bool refcounted);
2430+
static inline void
2431+
ieee80211_stop_vif_queues(struct ieee80211_local *local,
2432+
struct ieee80211_sub_if_data *sdata,
2433+
enum queue_stop_reason reason)
2434+
{
2435+
ieee80211_stop_queues_by_reason(&local->hw,
2436+
ieee80211_get_vif_queues(local, sdata),
2437+
reason, true);
2438+
}
2439+
2440+
static inline void
2441+
ieee80211_wake_vif_queues(struct ieee80211_local *local,
2442+
struct ieee80211_sub_if_data *sdata,
2443+
enum queue_stop_reason reason)
2444+
{
2445+
ieee80211_wake_queues_by_reason(&local->hw,
2446+
ieee80211_get_vif_queues(local, sdata),
2447+
reason, true);
2448+
}
2449+
static inline void
2450+
ieee80211_stop_vif_queues_norefcount(struct ieee80211_local *local,
2451+
struct ieee80211_sub_if_data *sdata,
2452+
enum queue_stop_reason reason)
2453+
{
2454+
ieee80211_stop_queues_by_reason(&local->hw,
2455+
ieee80211_get_vif_queues(local, sdata),
2456+
reason, false);
2457+
}
2458+
static inline void
2459+
ieee80211_wake_vif_queues_norefcount(struct ieee80211_local *local,
2460+
struct ieee80211_sub_if_data *sdata,
2461+
enum queue_stop_reason reason)
2462+
{
2463+
ieee80211_wake_queues_by_reason(&local->hw,
2464+
ieee80211_get_vif_queues(local, sdata),
2465+
reason, false);
2466+
}
24362467
void ieee80211_add_pending_skb(struct ieee80211_local *local,
24372468
struct sk_buff *skb);
24382469
void ieee80211_add_pending_skbs(struct ieee80211_local *local,

net/mac80211/iface.c

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2374,18 +2374,14 @@ void ieee80211_vif_block_queues_csa(struct ieee80211_sub_if_data *sdata)
23742374
if (ieee80211_hw_check(&local->hw, HANDLES_QUIET_CSA))
23752375
return;
23762376

2377-
ieee80211_stop_vif_queues(local, sdata,
2378-
IEEE80211_QUEUE_STOP_REASON_CSA);
2379-
sdata->csa_blocked_queues = true;
2377+
ieee80211_stop_vif_queues_norefcount(local, sdata,
2378+
IEEE80211_QUEUE_STOP_REASON_CSA);
23802379
}
23812380

23822381
void ieee80211_vif_unblock_queues_csa(struct ieee80211_sub_if_data *sdata)
23832382
{
23842383
struct ieee80211_local *local = sdata->local;
23852384

2386-
if (sdata->csa_blocked_queues) {
2387-
ieee80211_wake_vif_queues(local, sdata,
2388-
IEEE80211_QUEUE_STOP_REASON_CSA);
2389-
sdata->csa_blocked_queues = false;
2390-
}
2385+
ieee80211_wake_vif_queues_norefcount(local, sdata,
2386+
IEEE80211_QUEUE_STOP_REASON_CSA);
23912387
}

net/mac80211/mlme.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2638,8 +2638,6 @@ ieee80211_sta_process_chanswitch(struct ieee80211_link_data *link,
26382638
*/
26392639
link->conf->csa_active = true;
26402640
link->u.mgd.csa.blocked_tx = csa_ie.mode;
2641-
sdata->csa_blocked_queues =
2642-
csa_ie.mode && !ieee80211_hw_check(&local->hw, HANDLES_QUIET_CSA);
26432641

26442642
wiphy_work_queue(sdata->local->hw.wiphy,
26452643
&ifmgd->csa_connection_drop_work);

net/mac80211/util.c

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -657,7 +657,7 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw)
657657
}
658658
EXPORT_SYMBOL(ieee80211_wake_queues);
659659

660-
static unsigned int
660+
unsigned int
661661
ieee80211_get_vif_queues(struct ieee80211_local *local,
662662
struct ieee80211_sub_if_data *sdata)
663663
{
@@ -669,7 +669,8 @@ ieee80211_get_vif_queues(struct ieee80211_local *local,
669669
queues = 0;
670670

671671
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
672-
queues |= BIT(sdata->vif.hw_queue[ac]);
672+
if (sdata->vif.hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE)
673+
queues |= BIT(sdata->vif.hw_queue[ac]);
673674
if (sdata->vif.cab_queue != IEEE80211_INVAL_HW_QUEUE)
674675
queues |= BIT(sdata->vif.cab_queue);
675676
} else {
@@ -724,24 +725,6 @@ void ieee80211_flush_queues(struct ieee80211_local *local,
724725
__ieee80211_flush_queues(local, sdata, 0, drop);
725726
}
726727

727-
void ieee80211_stop_vif_queues(struct ieee80211_local *local,
728-
struct ieee80211_sub_if_data *sdata,
729-
enum queue_stop_reason reason)
730-
{
731-
ieee80211_stop_queues_by_reason(&local->hw,
732-
ieee80211_get_vif_queues(local, sdata),
733-
reason, true);
734-
}
735-
736-
void ieee80211_wake_vif_queues(struct ieee80211_local *local,
737-
struct ieee80211_sub_if_data *sdata,
738-
enum queue_stop_reason reason)
739-
{
740-
ieee80211_wake_queues_by_reason(&local->hw,
741-
ieee80211_get_vif_queues(local, sdata),
742-
reason, true);
743-
}
744-
745728
static void __iterate_interfaces(struct ieee80211_local *local,
746729
u32 iter_flags,
747730
void (*iterator)(void *data, u8 *mac,

0 commit comments

Comments
 (0)