summaryrefslogtreecommitdiff
path: root/net/mac80211/agg-tx.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2023-06-18 21:49:58 +0300
committerJohannes Berg <johannes.berg@intel.com>2023-06-19 14:12:43 +0300
commit92bf4dd35801b4e3e73d3cc4beb5c929f75e0da6 (patch)
tree26a5a26c5b666ab680a78c58e1f11208112ea661 /net/mac80211/agg-tx.c
parent6f2db6588b8189caeeb8249727b8344eba991250 (diff)
downloadlinux-92bf4dd35801b4e3e73d3cc4beb5c929f75e0da6.tar.xz
wifi: mac80211: agg-tx: prevent start/stop race
There were crashes reported in this code, and the timer_shutdown() warning in one of the previous patches indicates that the timeout timer for the AP response (addba_resp_timer) is still armed while we're stopping the aggregation session. After a very long deliberation of the code, so far the only way I could find that might cause this would be the following sequence: - session start requested - session start indicated to driver, but driver returns IEEE80211_AMPDU_TX_START_DELAY_ADDBA - session stop requested, sets HT_AGG_STATE_WANT_STOP - session stop worker runs ___ieee80211_stop_tx_ba_session(), sets HT_AGG_STATE_STOPPING From here on, the order doesn't matter exactly, but: 1. driver calls ieee80211_start_tx_ba_cb_irqsafe(), setting HT_AGG_STATE_START_CB 2. driver calls ieee80211_stop_tx_ba_cb_irqsafe(), setting HT_AGG_STATE_STOP_CB 3. the worker will run ieee80211_start_tx_ba_cb() for HT_AGG_STATE_START_CB 4. the worker will run ieee80211_stop_tx_ba_cb() for HT_AGG_STATE_STOP_CB (the order could also be 1./3./2./4.) This will cause ieee80211_start_tx_ba_cb() to send out the AddBA request frame to the AP and arm the timer, but we're already in the middle of stopping and so the ieee80211_stop_tx_ba_cb() will no longer assume it needs to stop anything. Prevent this by checking for WANT_STOP/STOPPING in the start CB, and warn if we're sending a frame on a stopping session. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Gregory Greenman <gregory.greenman@intel.com> Link: https://lore.kernel.org/r/20230618214436.e5b52777462a.I0b2ed6658e81804279f5d7c9c1918cb1f6626bf2@changeid Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/agg-tx.c')
-rw-r--r--net/mac80211/agg-tx.c8
1 files changed, 8 insertions, 0 deletions
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 118ad2e24dbb..b6b772685881 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -457,6 +457,10 @@ static void ieee80211_send_addba_with_timeout(struct sta_info *sta,
u8 tid = tid_tx->tid;
u16 buf_size;
+ if (WARN_ON_ONCE(test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state) ||
+ test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state)))
+ return;
+
lockdep_assert_held(&sta->ampdu_mlme.mtx);
/* activate the timer for the recipient's addBA response */
@@ -802,6 +806,10 @@ void ieee80211_start_tx_ba_cb(struct sta_info *sta, int tid,
if (WARN_ON(test_and_set_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state)))
return;
+ if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state) ||
+ test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state))
+ return;
+
if (!test_bit(HT_AGG_STATE_SENT_ADDBA, &tid_tx->state)) {
ieee80211_send_addba_with_timeout(sta, tid_tx);
/* RESPONSE_RECEIVED state whould trigger the flow again */