aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath9k/xmit.c
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2010-07-07 13:42:08 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-07-07 15:48:18 -0400
commit2b40994cabd2f545d5c11d3a65dcee6f6f9155f8 (patch)
tree5298b5441abc363c40352e64ef784ae8d085445e /drivers/net/wireless/ath/ath9k/xmit.c
parent60ea385ff279a18790a432d57a8302562aaa0f8d (diff)
ath9k: fix a potential buffer leak in the STA teardown path
It looks like it might be possible for a TID to be paused, while still holding some queued buffers, however ath_tx_node_cleanup currently only iterates over active TIDs. Fix this by always checking every allocated TID for the STA that is being cleaned up. Signed-off-by: Felix Fietkau <nbd@openwrt.org> Cc: stable@kernel.org Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/xmit.c')
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c52
1 files changed, 26 insertions, 26 deletions
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index c3681a1dc94..408d1c596a0 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -2430,37 +2430,37 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
2430 2430
2431void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) 2431void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
2432{ 2432{
2433 int i; 2433 struct ath_atx_ac *ac;
2434 struct ath_atx_ac *ac, *ac_tmp; 2434 struct ath_atx_tid *tid;
2435 struct ath_atx_tid *tid, *tid_tmp;
2436 struct ath_txq *txq; 2435 struct ath_txq *txq;
2436 int i, tidno;
2437 2437
2438 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { 2438 for (tidno = 0, tid = &an->tid[tidno];
2439 if (ATH_TXQ_SETUP(sc, i)) { 2439 tidno < WME_NUM_TID; tidno++, tid++) {
2440 txq = &sc->tx.txq[i]; 2440 i = tid->ac->qnum;
2441 2441
2442 spin_lock_bh(&txq->axq_lock); 2442 if (!ATH_TXQ_SETUP(sc, i))
2443 continue;
2443 2444
2444 list_for_each_entry_safe(ac, 2445 txq = &sc->tx.txq[i];
2445 ac_tmp, &txq->axq_acq, list) { 2446 ac = tid->ac;
2446 tid = list_first_entry(&ac->tid_q,
2447 struct ath_atx_tid, list);
2448 if (tid && tid->an != an)
2449 continue;
2450 list_del(&ac->list);
2451 ac->sched = false;
2452
2453 list_for_each_entry_safe(tid,
2454 tid_tmp, &ac->tid_q, list) {
2455 list_del(&tid->list);
2456 tid->sched = false;
2457 ath_tid_drain(sc, txq, tid);
2458 tid->state &= ~AGGR_ADDBA_COMPLETE;
2459 tid->state &= ~AGGR_CLEANUP;
2460 }
2461 }
2462 2447
2463 spin_unlock_bh(&txq->axq_lock); 2448 spin_lock_bh(&txq->axq_lock);
2449
2450 if (tid->sched) {
2451 list_del(&tid->list);
2452 tid->sched = false;
2453 }
2454
2455 if (ac->sched) {
2456 list_del(&ac->list);
2457 tid->ac->sched = false;
2464 } 2458 }
2459
2460 ath_tid_drain(sc, txq, tid);
2461 tid->state &= ~AGGR_ADDBA_COMPLETE;
2462 tid->state &= ~AGGR_CLEANUP;
2463
2464 spin_unlock_bh(&txq->axq_lock);
2465 } 2465 }
2466} 2466}