Skip to content

Commit bde59c4

Browse files
committed
mac80211: fix deadlock in driver-managed RX BA session start
When an RX BA session is started by the driver, and it has to tell mac80211 about it, the corresponding bit in tid_rx_manage_offl gets set and the BA session work is scheduled. Upon testing this bit, it will call __ieee80211_start_rx_ba_session(), thus deadlocking as it already holds the ampdu_mlme.mtx, which that acquires again. Fix this by adding ___ieee80211_start_rx_ba_session(), a version of the function that requires the mutex already held. Cc: stable@vger.kernel.org Fixes: 699cb58 ("mac80211: manage RX BA session offload without SKB queue") Reported-by: Matteo Croce <mcroce@redhat.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
1 parent 98e93e9 commit bde59c4

File tree

3 files changed

+28
-14
lines changed

3 files changed

+28
-14
lines changed

net/mac80211/agg-rx.c

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -245,10 +245,10 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d
245245
ieee80211_tx_skb(sdata, skb);
246246
}
247247

248-
void __ieee80211_start_rx_ba_session(struct sta_info *sta,
249-
u8 dialog_token, u16 timeout,
250-
u16 start_seq_num, u16 ba_policy, u16 tid,
251-
u16 buf_size, bool tx, bool auto_seq)
248+
void ___ieee80211_start_rx_ba_session(struct sta_info *sta,
249+
u8 dialog_token, u16 timeout,
250+
u16 start_seq_num, u16 ba_policy, u16 tid,
251+
u16 buf_size, bool tx, bool auto_seq)
252252
{
253253
struct ieee80211_local *local = sta->sdata->local;
254254
struct tid_ampdu_rx *tid_agg_rx;
@@ -267,22 +267,22 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
267267
ht_dbg(sta->sdata,
268268
"STA %pM requests BA session on unsupported tid %d\n",
269269
sta->sta.addr, tid);
270-
goto end_no_lock;
270+
goto end;
271271
}
272272

273273
if (!sta->sta.ht_cap.ht_supported) {
274274
ht_dbg(sta->sdata,
275275
"STA %pM erroneously requests BA session on tid %d w/o QoS\n",
276276
sta->sta.addr, tid);
277277
/* send a response anyway, it's an error case if we get here */
278-
goto end_no_lock;
278+
goto end;
279279
}
280280

281281
if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
282282
ht_dbg(sta->sdata,
283283
"Suspend in progress - Denying ADDBA request (%pM tid %d)\n",
284284
sta->sta.addr, tid);
285-
goto end_no_lock;
285+
goto end;
286286
}
287287

288288
/* sanity check for incoming parameters:
@@ -296,7 +296,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
296296
ht_dbg_ratelimited(sta->sdata,
297297
"AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n",
298298
sta->sta.addr, tid, ba_policy, buf_size);
299-
goto end_no_lock;
299+
goto end;
300300
}
301301
/* determine default buffer size */
302302
if (buf_size == 0)
@@ -311,7 +311,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
311311
buf_size, sta->sta.addr);
312312

313313
/* examine state machine */
314-
mutex_lock(&sta->ampdu_mlme.mtx);
314+
lockdep_assert_held(&sta->ampdu_mlme.mtx);
315315

316316
if (test_bit(tid, sta->ampdu_mlme.agg_session_valid)) {
317317
if (sta->ampdu_mlme.tid_rx_token[tid] == dialog_token) {
@@ -415,15 +415,25 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
415415
__clear_bit(tid, sta->ampdu_mlme.unexpected_agg);
416416
sta->ampdu_mlme.tid_rx_token[tid] = dialog_token;
417417
}
418-
mutex_unlock(&sta->ampdu_mlme.mtx);
419418

420-
end_no_lock:
421419
if (tx)
422420
ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid,
423421
dialog_token, status, 1, buf_size,
424422
timeout);
425423
}
426424

425+
void __ieee80211_start_rx_ba_session(struct sta_info *sta,
426+
u8 dialog_token, u16 timeout,
427+
u16 start_seq_num, u16 ba_policy, u16 tid,
428+
u16 buf_size, bool tx, bool auto_seq)
429+
{
430+
mutex_lock(&sta->ampdu_mlme.mtx);
431+
___ieee80211_start_rx_ba_session(sta, dialog_token, timeout,
432+
start_seq_num, ba_policy, tid,
433+
buf_size, tx, auto_seq);
434+
mutex_unlock(&sta->ampdu_mlme.mtx);
435+
}
436+
427437
void ieee80211_process_addba_request(struct ieee80211_local *local,
428438
struct sta_info *sta,
429439
struct ieee80211_mgmt *mgmt,

net/mac80211/ht.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -351,9 +351,9 @@ void ieee80211_ba_session_work(struct work_struct *work)
351351

352352
if (test_and_clear_bit(tid,
353353
sta->ampdu_mlme.tid_rx_manage_offl))
354-
__ieee80211_start_rx_ba_session(sta, 0, 0, 0, 1, tid,
355-
IEEE80211_MAX_AMPDU_BUF,
356-
false, true);
354+
___ieee80211_start_rx_ba_session(sta, 0, 0, 0, 1, tid,
355+
IEEE80211_MAX_AMPDU_BUF,
356+
false, true);
357357

358358
if (test_and_clear_bit(tid + IEEE80211_NUM_TIDS,
359359
sta->ampdu_mlme.tid_rx_manage_offl))

net/mac80211/ieee80211_i.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1760,6 +1760,10 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
17601760
u8 dialog_token, u16 timeout,
17611761
u16 start_seq_num, u16 ba_policy, u16 tid,
17621762
u16 buf_size, bool tx, bool auto_seq);
1763+
void ___ieee80211_start_rx_ba_session(struct sta_info *sta,
1764+
u8 dialog_token, u16 timeout,
1765+
u16 start_seq_num, u16 ba_policy, u16 tid,
1766+
u16 buf_size, bool tx, bool auto_seq);
17631767
void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta,
17641768
enum ieee80211_agg_stop_reason reason);
17651769
void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,

0 commit comments

Comments
 (0)