diff options
Diffstat (limited to 'net/mac80211/agg-tx.c')
-rw-r--r-- | net/mac80211/agg-tx.c | 42 |
1 files changed, 39 insertions, 3 deletions
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 266cc871c72d..2c2e9519a2e7 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -162,6 +162,12 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
162 | return -ENOENT; | 162 | return -ENOENT; |
163 | } | 163 | } |
164 | 164 | ||
165 | /* if we're already stopping ignore any new requests to stop */ | ||
166 | if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { | ||
167 | spin_unlock_bh(&sta->lock); | ||
168 | return -EALREADY; | ||
169 | } | ||
170 | |||
165 | if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { | 171 | if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { |
166 | /* not even started yet! */ | 172 | /* not even started yet! */ |
167 | ieee80211_assign_tid_tx(sta, tid, NULL); | 173 | ieee80211_assign_tid_tx(sta, tid, NULL); |
@@ -170,6 +176,8 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
170 | return 0; | 176 | return 0; |
171 | } | 177 | } |
172 | 178 | ||
179 | set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state); | ||
180 | |||
173 | spin_unlock_bh(&sta->lock); | 181 | spin_unlock_bh(&sta->lock); |
174 | 182 | ||
175 | #ifdef CONFIG_MAC80211_HT_DEBUG | 183 | #ifdef CONFIG_MAC80211_HT_DEBUG |
@@ -177,8 +185,6 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
177 | sta->sta.addr, tid); | 185 | sta->sta.addr, tid); |
178 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 186 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
179 | 187 | ||
180 | set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state); | ||
181 | |||
182 | del_timer_sync(&tid_tx->addba_resp_timer); | 188 | del_timer_sync(&tid_tx->addba_resp_timer); |
183 | del_timer_sync(&tid_tx->session_timer); | 189 | del_timer_sync(&tid_tx->session_timer); |
184 | 190 | ||
@@ -189,6 +195,20 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
189 | */ | 195 | */ |
190 | clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state); | 196 | clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state); |
191 | 197 | ||
198 | /* | ||
199 | * There might be a few packets being processed right now (on | ||
200 | * another CPU) that have already gotten past the aggregation | ||
201 | * check when it was still OPERATIONAL and consequently have | ||
202 | * IEEE80211_TX_CTL_AMPDU set. In that case, this code might | ||
203 | * call into the driver at the same time or even before the | ||
204 | * TX paths calls into it, which could confuse the driver. | ||
205 | * | ||
206 | * Wait for all currently running TX paths to finish before | ||
207 | * telling the driver. New packets will not go through since | ||
208 | * the aggregation session is no longer OPERATIONAL. | ||
209 | */ | ||
210 | synchronize_net(); | ||
211 | |||
192 | tid_tx->stop_initiator = initiator; | 212 | tid_tx->stop_initiator = initiator; |
193 | tid_tx->tx_stop = tx; | 213 | tid_tx->tx_stop = tx; |
194 | 214 | ||
@@ -781,11 +801,27 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, | |||
781 | goto out; | 801 | goto out; |
782 | } | 802 | } |
783 | 803 | ||
784 | del_timer(&tid_tx->addba_resp_timer); | 804 | del_timer_sync(&tid_tx->addba_resp_timer); |
785 | 805 | ||
786 | #ifdef CONFIG_MAC80211_HT_DEBUG | 806 | #ifdef CONFIG_MAC80211_HT_DEBUG |
787 | printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid); | 807 | printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid); |
788 | #endif | 808 | #endif |
809 | |||
810 | /* | ||
811 | * addba_resp_timer may have fired before we got here, and | ||
812 | * caused WANT_STOP to be set. If the stop then was already | ||
813 | * processed further, STOPPING might be set. | ||
814 | */ | ||
815 | if (test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state) || | ||
816 | test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { | ||
817 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
818 | printk(KERN_DEBUG | ||
819 | "got addBA resp for tid %d but we already gave up\n", | ||
820 | tid); | ||
821 | #endif | ||
822 | goto out; | ||
823 | } | ||
824 | |||
789 | /* | 825 | /* |
790 | * IEEE 802.11-2007 7.3.1.14: | 826 | * IEEE 802.11-2007 7.3.1.14: |
791 | * In an ADDBA Response frame, when the Status Code field | 827 | * In an ADDBA Response frame, when the Status Code field |