ath9k: fix a potential buffer leak in the STA teardown path
authorFelix Fietkau <nbd@openwrt.org>
Wed, 7 Jul 2010 17:42:08 +0000 (19:42 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 7 Jul 2010 19:48:18 +0000 (15:48 -0400)
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>
drivers/net/wireless/ath/ath9k/xmit.c

index c3681a1dc94116c32aa5e7bbc575f0cdc8bad0de..408d1c596a038aa239c4894867afaff00bff2134 100644 (file)
@@ -2430,37 +2430,37 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
 
 void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
 {
-       int i;
-       struct ath_atx_ac *ac, *ac_tmp;
-       struct ath_atx_tid *tid, *tid_tmp;
+       struct ath_atx_ac *ac;
+       struct ath_atx_tid *tid;
        struct ath_txq *txq;
+       int i, tidno;
 
-       for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
-               if (ATH_TXQ_SETUP(sc, i)) {
-                       txq = &sc->tx.txq[i];
+       for (tidno = 0, tid = &an->tid[tidno];
+            tidno < WME_NUM_TID; tidno++, tid++) {
+               i = tid->ac->qnum;
 
-                       spin_lock_bh(&txq->axq_lock);
+               if (!ATH_TXQ_SETUP(sc, i))
+                       continue;
 
-                       list_for_each_entry_safe(ac,
-                                       ac_tmp, &txq->axq_acq, list) {
-                               tid = list_first_entry(&ac->tid_q,
-                                               struct ath_atx_tid, list);
-                               if (tid && tid->an != an)
-                                       continue;
-                               list_del(&ac->list);
-                               ac->sched = false;
-
-                               list_for_each_entry_safe(tid,
-                                               tid_tmp, &ac->tid_q, list) {
-                                       list_del(&tid->list);
-                                       tid->sched = false;
-                                       ath_tid_drain(sc, txq, tid);
-                                       tid->state &= ~AGGR_ADDBA_COMPLETE;
-                                       tid->state &= ~AGGR_CLEANUP;
-                               }
-                       }
+               txq = &sc->tx.txq[i];
+               ac = tid->ac;
 
-                       spin_unlock_bh(&txq->axq_lock);
+               spin_lock_bh(&txq->axq_lock);
+
+               if (tid->sched) {
+                       list_del(&tid->list);
+                       tid->sched = false;
+               }
+
+               if (ac->sched) {
+                       list_del(&ac->list);
+                       tid->ac->sched = false;
                }
+
+               ath_tid_drain(sc, txq, tid);
+               tid->state &= ~AGGR_ADDBA_COMPLETE;
+               tid->state &= ~AGGR_CLEANUP;
+
+               spin_unlock_bh(&txq->axq_lock);
        }
 }