diff options
author | Felix Fietkau <nbd@openwrt.org> | 2010-07-07 13:42:08 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-07-07 15:48:18 -0400 |
commit | 2b40994cabd2f545d5c11d3a65dcee6f6f9155f8 (patch) | |
tree | 5298b5441abc363c40352e64ef784ae8d085445e /drivers | |
parent | 60ea385ff279a18790a432d57a8302562aaa0f8d (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')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/xmit.c | 52 |
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 | ||
2431 | void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) | 2431 | void 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 | } |