aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-01-18 17:47:05 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-01-24 09:43:51 -0500
commit8147dc7f54f0f2e13c3b65fd9628994ad576610b (patch)
treeb093d0d991d91077ddc622c3a8d811c4fdd37209
parent887da9176e011a044b12ec0deff62df5faadd67c (diff)
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 <johannes.berg@intel.com>
-rw-r--r--net/mac80211/agg-tx.c17
-rw-r--r--net/mac80211/mlme.c9
2 files changed, 10 insertions, 16 deletions
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index e90911819ed4..13b7683de5a4 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -296,7 +296,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
296 IEEE80211_AMPDU_TX_STOP_FLUSH_CONT, 296 IEEE80211_AMPDU_TX_STOP_FLUSH_CONT,
297 &sta->sta, tid, NULL, 0); 297 &sta->sta, tid, NULL, 0);
298 WARN_ON_ONCE(ret); 298 WARN_ON_ONCE(ret);
299 goto remove_tid_tx; 299 return 0;
300 } 300 }
301 301
302 if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { 302 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,
354 */ 354 */
355 } 355 }
356 356
357 if (reason == AGG_STOP_DESTROY_STA) { 357 /*
358 remove_tid_tx: 358 * In the case of AGG_STOP_DESTROY_STA, the driver won't
359 spin_lock_bh(&sta->lock); 359 * necessarily call ieee80211_stop_tx_ba_cb(), so this may
360 ieee80211_remove_tid_tx(sta, tid); 360 * seem like we can leave the tid_tx data pending forever.
361 spin_unlock_bh(&sta->lock); 361 * This is true, in a way, but "forever" is only until the
362 } 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 */
363 366
364 return 0; 367 return 0;
365} 368}
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 344ef7d47c1a..62e8f890fed6 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1487,7 +1487,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
1487{ 1487{
1488 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 1488 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
1489 struct ieee80211_local *local = sdata->local; 1489 struct ieee80211_local *local = sdata->local;
1490 struct sta_info *sta;
1491 u32 changed = 0; 1490 u32 changed = 0;
1492 1491
1493 ASSERT_MGD_MTX(ifmgd); 1492 ASSERT_MGD_MTX(ifmgd);
@@ -1519,14 +1518,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
1519 netif_tx_stop_all_queues(sdata->dev); 1518 netif_tx_stop_all_queues(sdata->dev);
1520 netif_carrier_off(sdata->dev); 1519 netif_carrier_off(sdata->dev);
1521 1520
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
1530 /* 1521 /*
1531 * if we want to get out of ps before disassoc (why?) we have 1522 * if we want to get out of ps before disassoc (why?) we have
1532 * to do it before sending disassoc, as otherwise the null-packet 1523 * to do it before sending disassoc, as otherwise the null-packet