Skip to content

Commit 8147dc7

Browse files
committed
mac80211: fix aggregation state with current drivers
For drivers that don't actually flush their queues when aggregation stop with the IEEE80211_AMPDU_TX_STOP_FLUSH or IEEE80211_AMPDU_TX_STOP_FLUSH_CONT reasons is done, like iwlwifi or iwlegacy, mac80211 can then transmit on a TID that the driver still considers busy. This happens in the following way: - IEEE80211_AMPDU_TX_STOP_FLUSH requested - driver marks TID as emptying - mac80211 removes tid_tx data, this can copy packets to the TX pending queues and also let new packets through to the driver - driver gets unexpected TX as it wasn't completely converted to the new API In iwlwifi, this lead to the following warning: WARNING: at drivers/net/wireless/iwlwifi/dvm/tx.c:442 iwlagn_tx_skb+0xc47/0xce0 Tx while agg.state = 4 Modules linked in: [...] Pid: 0, comm: kworker/0:0 Tainted: G W 3.1.0 #1 Call Trace: [<c1046e42>] warn_slowpath_common+0x72/0xa0 [<c1046f13>] warn_slowpath_fmt+0x33/0x40 [<fddffa17>] iwlagn_tx_skb+0xc47/0xce0 [iwldvm] [<fddfcaa3>] iwlagn_mac_tx+0x23/0x40 [iwldvm] [<fd8c98b6>] __ieee80211_tx+0xf6/0x3c0 [mac80211] [<fd8cbe00>] ieee80211_tx+0xd0/0x100 [mac80211] [<fd8cc176>] ieee80211_xmit+0x96/0xe0 [mac80211] [<fd8cc578>] ieee80211_subif_start_xmit+0x348/0xc80 [mac80211] [<c1445207>] dev_hard_start_xmit+0x337/0x6d0 [<c145eee9>] sch_direct_xmit+0xa9/0x210 [<c14462c0>] dev_queue_xmit+0x1b0/0x8e0 Fortunately, solving this problem is easy as the station is being destroyed, so such transmit packets can only happen due to races. Instead of trying to close the race just let the race not reach the drivers by making two changes: 1) remove the explicit aggregation session teardown in the managed mode code, the same thing will be done when the station is removed, in __sta_info_destroy. 2) When aggregation stop with AGG_STOP_DESTROY_STA is requested, leave the tid_tx data around as stopped. It will be cleared and freed in cleanup_single_sta later, but until then any racy packets will be put onto the tid_tx pending queue instead of transmitted which is fine since the station is being removed. Signed-off-by: Johannes Berg <[email protected]>
1 parent 887da91 commit 8147dc7

2 files changed

Lines changed: 10 additions & 16 deletions

File tree

net/mac80211/agg-tx.c

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
296296
IEEE80211_AMPDU_TX_STOP_FLUSH_CONT,
297297
&sta->sta, tid, NULL, 0);
298298
WARN_ON_ONCE(ret);
299-
goto remove_tid_tx;
299+
return 0;
300300
}
301301

302302
if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) {
@@ -354,12 +354,15 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
354354
*/
355355
}
356356

357-
if (reason == AGG_STOP_DESTROY_STA) {
358-
remove_tid_tx:
359-
spin_lock_bh(&sta->lock);
360-
ieee80211_remove_tid_tx(sta, tid);
361-
spin_unlock_bh(&sta->lock);
362-
}
357+
/*
358+
* In the case of AGG_STOP_DESTROY_STA, the driver won't
359+
* necessarily call ieee80211_stop_tx_ba_cb(), so this may
360+
* seem like we can leave the tid_tx data pending forever.
361+
* This is true, in a way, but "forever" is only until the
362+
* station struct is actually destroyed. In the meantime,
363+
* leaving it around ensures that we don't transmit packets
364+
* to the driver on this TID which might confuse it.
365+
*/
363366

364367
return 0;
365368
}

net/mac80211/mlme.c

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1487,7 +1487,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
14871487
{
14881488
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
14891489
struct ieee80211_local *local = sdata->local;
1490-
struct sta_info *sta;
14911490
u32 changed = 0;
14921491

14931492
ASSERT_MGD_MTX(ifmgd);
@@ -1519,14 +1518,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
15191518
netif_tx_stop_all_queues(sdata->dev);
15201519
netif_carrier_off(sdata->dev);
15211520

1522-
mutex_lock(&local->sta_mtx);
1523-
sta = sta_info_get(sdata, ifmgd->bssid);
1524-
if (sta) {
1525-
set_sta_flag(sta, WLAN_STA_BLOCK_BA);
1526-
ieee80211_sta_tear_down_BA_sessions(sta, AGG_STOP_DESTROY_STA);
1527-
}
1528-
mutex_unlock(&local->sta_mtx);
1529-
15301521
/*
15311522
* if we want to get out of ps before disassoc (why?) we have
15321523
* to do it before sending disassoc, as otherwise the null-packet

0 commit comments

Comments
 (0)