]>
Commit | Line | Data |
---|---|---|
c06f7f46 GKH |
1 | From 231c3a1f0630c07a584905507a1cb7b705a56ab7 Mon Sep 17 00:00:00 2001 |
2 | From: Felix Fietkau <nbd@openwrt.org> | |
3 | Date: Mon, 20 Sep 2010 19:35:28 +0200 | |
4 | Subject: ath9k: fix an aggregation start related race condition | |
5 | ||
6 | From: Felix Fietkau <nbd@openwrt.org> | |
7 | ||
8 | commit 231c3a1f0630c07a584905507a1cb7b705a56ab7 upstream. | |
9 | ||
10 | A new aggregation session start can be issued by mac80211, even when the | |
11 | cleanup of the previous session has not completed yet. Since the data structure | |
12 | for the session is not recreated, this could corrupt the block ack window | |
13 | and lock up the aggregation session. Fix this by delaying the new session | |
14 | until the old one has been cleaned up. | |
15 | ||
16 | Signed-off-by: Felix Fietkau <nbd@openwrt.org> | |
17 | Signed-off-by: John W. Linville <linville@tuxdriver.com> | |
18 | Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | |
19 | ||
20 | --- | |
21 | drivers/net/wireless/ath/ath9k/ath9k.h | 4 ++-- | |
22 | drivers/net/wireless/ath/ath9k/main.c | 5 +++-- | |
23 | drivers/net/wireless/ath/ath9k/xmit.c | 10 ++++++++-- | |
24 | 3 files changed, 13 insertions(+), 6 deletions(-) | |
25 | ||
26 | --- a/drivers/net/wireless/ath/ath9k/ath9k.h | |
27 | +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |
28 | @@ -346,8 +346,8 @@ void ath_tx_tasklet(struct ath_softc *sc | |
29 | void ath_tx_edma_tasklet(struct ath_softc *sc); | |
30 | void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb); | |
31 | bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno); | |
32 | -void ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, | |
33 | - u16 tid, u16 *ssn); | |
34 | +int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, | |
35 | + u16 tid, u16 *ssn); | |
36 | void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); | |
37 | void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); | |
38 | void ath9k_enable_ps(struct ath_softc *sc); | |
39 | --- a/drivers/net/wireless/ath/ath9k/main.c | |
40 | +++ b/drivers/net/wireless/ath/ath9k/main.c | |
41 | @@ -1973,8 +1973,9 @@ static int ath9k_ampdu_action(struct iee | |
42 | break; | |
43 | case IEEE80211_AMPDU_TX_START: | |
44 | ath9k_ps_wakeup(sc); | |
45 | - ath_tx_aggr_start(sc, sta, tid, ssn); | |
46 | - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); | |
47 | + ret = ath_tx_aggr_start(sc, sta, tid, ssn); | |
48 | + if (!ret) | |
49 | + ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); | |
50 | ath9k_ps_restore(sc); | |
51 | break; | |
52 | case IEEE80211_AMPDU_TX_STOP: | |
53 | --- a/drivers/net/wireless/ath/ath9k/xmit.c | |
54 | +++ b/drivers/net/wireless/ath/ath9k/xmit.c | |
55 | @@ -792,17 +792,23 @@ static void ath_tx_sched_aggr(struct ath | |
56 | status != ATH_AGGR_BAW_CLOSED); | |
57 | } | |
58 | ||
59 | -void ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, | |
60 | - u16 tid, u16 *ssn) | |
61 | +int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, | |
62 | + u16 tid, u16 *ssn) | |
63 | { | |
64 | struct ath_atx_tid *txtid; | |
65 | struct ath_node *an; | |
66 | ||
67 | an = (struct ath_node *)sta->drv_priv; | |
68 | txtid = ATH_AN_2_TID(an, tid); | |
69 | + | |
70 | + if (txtid->state & (AGGR_CLEANUP | AGGR_ADDBA_COMPLETE)) | |
71 | + return -EAGAIN; | |
72 | + | |
73 | txtid->state |= AGGR_ADDBA_PROGRESS; | |
74 | txtid->paused = true; | |
75 | *ssn = txtid->seq_start; | |
76 | + | |
77 | + return 0; | |
78 | } | |
79 | ||
80 | void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) |