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 39d72ccaffb3..556765749b9c 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 | 189 | ||
184 | /* | 190 | /* |
@@ -188,6 +194,20 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
188 | */ | 194 | */ |
189 | clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state); | 195 | clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state); |
190 | 196 | ||
197 | /* | ||
198 | * There might be a few packets being processed right now (on | ||
199 | * another CPU) that have already gotten past the aggregation | ||
200 | * check when it was still OPERATIONAL and consequently have | ||
201 | * IEEE80211_TX_CTL_AMPDU set. In that case, this code might | ||
202 | * call into the driver at the same time or even before the | ||
203 | * TX paths calls into it, which could confuse the driver. | ||
204 | * | ||
205 | * Wait for all currently running TX paths to finish before | ||
206 | * telling the driver. New packets will not go through since | ||
207 | * the aggregation session is no longer OPERATIONAL. | ||
208 | */ | ||
209 | synchronize_net(); | ||
210 | |||
191 | tid_tx->stop_initiator = initiator; | 211 | tid_tx->stop_initiator = initiator; |
192 | tid_tx->tx_stop = tx; | 212 | tid_tx->tx_stop = tx; |
193 | 213 | ||
@@ -753,11 +773,27 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, | |||
753 | goto out; | 773 | goto out; |
754 | } | 774 | } |
755 | 775 | ||
756 | del_timer(&tid_tx->addba_resp_timer); | 776 | del_timer_sync(&tid_tx->addba_resp_timer); |
757 | 777 | ||
758 | #ifdef CONFIG_MAC80211_HT_DEBUG | 778 | #ifdef CONFIG_MAC80211_HT_DEBUG |
759 | printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid); | 779 | printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid); |
760 | #endif | 780 | #endif |
781 | |||
782 | /* | ||
783 | * addba_resp_timer may have fired before we got here, and | ||
784 | * caused WANT_STOP to be set. If the stop then was already | ||
785 | * processed further, STOPPING might be set. | ||
786 | */ | ||
787 | if (test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state) || | ||
788 | test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { | ||
789 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
790 | printk(KERN_DEBUG | ||
791 | "got addBA resp for tid %d but we already gave up\n", | ||
792 | tid); | ||
793 | #endif | ||
794 | goto out; | ||
795 | } | ||
796 | |||
761 | /* | 797 | /* |
762 | * IEEE 802.11-2007 7.3.1.14: | 798 | * IEEE 802.11-2007 7.3.1.14: |
763 | * In an ADDBA Response frame, when the Status Code field | 799 | * In an ADDBA Response frame, when the Status Code field |