]> rtime.felk.cvut.cz Git - lisovros/linux_canprio.git/commitdiff
ath9k: fix an aggregation start related race condition
authorFelix Fietkau <nbd@openwrt.org>
Mon, 20 Sep 2010 17:35:28 +0000 (19:35 +0200)
committerGreg Kroah-Hartman <gregkh@suse.de>
Thu, 9 Dec 2010 21:31:59 +0000 (13:31 -0800)
commit 231c3a1f0630c07a584905507a1cb7b705a56ab7 upstream.

A new aggregation session start can be issued by mac80211, even when the
cleanup of the previous session has not completed yet. Since the data structure
for the session is not recreated, this could corrupt the block ack window
and lock up the aggregation session. Fix this by delaying the new session
until the old one has been cleaned up.

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/xmit.c

index 07f26ee7a7235ac0f3c48c7966630ce849217cfc..010bb9607b3ec226a243d4c174244f845eafc4cf 100644 (file)
@@ -346,8 +346,8 @@ void ath_tx_tasklet(struct ath_softc *sc);
 void ath_tx_edma_tasklet(struct ath_softc *sc);
 void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb);
 bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno);
-void ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
-                      u16 tid, u16 *ssn);
+int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
+                     u16 tid, u16 *ssn);
 void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
 void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
 void ath9k_enable_ps(struct ath_softc *sc);
index 43def661ca1ca0c23ce928fe9528b2006a43c3f5..feea5fe1da95f0c22578075e3d0f5dd6bc223089 100644 (file)
@@ -1973,8 +1973,9 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
                break;
        case IEEE80211_AMPDU_TX_START:
                ath9k_ps_wakeup(sc);
-               ath_tx_aggr_start(sc, sta, tid, ssn);
-               ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+               ret = ath_tx_aggr_start(sc, sta, tid, ssn);
+               if (!ret)
+                       ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
                ath9k_ps_restore(sc);
                break;
        case IEEE80211_AMPDU_TX_STOP:
index 6dbad36e6870792044812bf027d420ac31c5b49a..5e9963a7d6893f8677697188c02a5e02fadba497 100644 (file)
@@ -792,17 +792,23 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
                 status != ATH_AGGR_BAW_CLOSED);
 }
 
-void ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
-                      u16 tid, u16 *ssn)
+int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
+                     u16 tid, u16 *ssn)
 {
        struct ath_atx_tid *txtid;
        struct ath_node *an;
 
        an = (struct ath_node *)sta->drv_priv;
        txtid = ATH_AN_2_TID(an, tid);
+
+       if (txtid->state & (AGGR_CLEANUP | AGGR_ADDBA_COMPLETE))
+               return -EAGAIN;
+
        txtid->state |= AGGR_ADDBA_PROGRESS;
        txtid->paused = true;
        *ssn = txtid->seq_start;
+
+       return 0;
 }
 
 void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)