diff options
author | John W. Linville <linville@tuxdriver.com> | 2011-11-30 14:14:42 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-11-30 14:14:42 -0500 |
commit | 3b95e9c089d932c11f9ec03f7493f02cceff04ba (patch) | |
tree | b4b5fac6f2f1908aebf49f63805f07f4ec58abb9 /net | |
parent | 5dc5503f5a400be5a7dc611745a034f04b0679b8 (diff) | |
parent | 2a1e0fd175dcfd72096ba9291d31e3b1b5342e60 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless into for-davem
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/agg-tx.c | 42 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 4 |
2 files changed, 41 insertions, 5 deletions
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index b3f65520e7a7..b064e4df12c6 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -161,6 +161,12 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
161 | return -ENOENT; | 161 | return -ENOENT; |
162 | } | 162 | } |
163 | 163 | ||
164 | /* if we're already stopping ignore any new requests to stop */ | ||
165 | if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { | ||
166 | spin_unlock_bh(&sta->lock); | ||
167 | return -EALREADY; | ||
168 | } | ||
169 | |||
164 | if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { | 170 | if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { |
165 | /* not even started yet! */ | 171 | /* not even started yet! */ |
166 | ieee80211_assign_tid_tx(sta, tid, NULL); | 172 | ieee80211_assign_tid_tx(sta, tid, NULL); |
@@ -169,6 +175,8 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
169 | return 0; | 175 | return 0; |
170 | } | 176 | } |
171 | 177 | ||
178 | set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state); | ||
179 | |||
172 | spin_unlock_bh(&sta->lock); | 180 | spin_unlock_bh(&sta->lock); |
173 | 181 | ||
174 | #ifdef CONFIG_MAC80211_HT_DEBUG | 182 | #ifdef CONFIG_MAC80211_HT_DEBUG |
@@ -176,8 +184,6 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
176 | sta->sta.addr, tid); | 184 | sta->sta.addr, tid); |
177 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 185 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
178 | 186 | ||
179 | set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state); | ||
180 | |||
181 | del_timer_sync(&tid_tx->addba_resp_timer); | 187 | del_timer_sync(&tid_tx->addba_resp_timer); |
182 | 188 | ||
183 | /* | 189 | /* |
@@ -187,6 +193,20 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
187 | */ | 193 | */ |
188 | clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state); | 194 | clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state); |
189 | 195 | ||
196 | /* | ||
197 | * There might be a few packets being processed right now (on | ||
198 | * another CPU) that have already gotten past the aggregation | ||
199 | * check when it was still OPERATIONAL and consequently have | ||
200 | * IEEE80211_TX_CTL_AMPDU set. In that case, this code might | ||
201 | * call into the driver at the same time or even before the | ||
202 | * TX paths calls into it, which could confuse the driver. | ||
203 | * | ||
204 | * Wait for all currently running TX paths to finish before | ||
205 | * telling the driver. New packets will not go through since | ||
206 | * the aggregation session is no longer OPERATIONAL. | ||
207 | */ | ||
208 | synchronize_net(); | ||
209 | |||
190 | tid_tx->stop_initiator = initiator; | 210 | tid_tx->stop_initiator = initiator; |
191 | tid_tx->tx_stop = tx; | 211 | tid_tx->tx_stop = tx; |
192 | 212 | ||
@@ -757,11 +777,27 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, | |||
757 | goto out; | 777 | goto out; |
758 | } | 778 | } |
759 | 779 | ||
760 | del_timer(&tid_tx->addba_resp_timer); | 780 | del_timer_sync(&tid_tx->addba_resp_timer); |
761 | 781 | ||
762 | #ifdef CONFIG_MAC80211_HT_DEBUG | 782 | #ifdef CONFIG_MAC80211_HT_DEBUG |
763 | printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid); | 783 | printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid); |
764 | #endif | 784 | #endif |
785 | |||
786 | /* | ||
787 | * addba_resp_timer may have fired before we got here, and | ||
788 | * caused WANT_STOP to be set. If the stop then was already | ||
789 | * processed further, STOPPING might be set. | ||
790 | */ | ||
791 | if (test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state) || | ||
792 | test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { | ||
793 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
794 | printk(KERN_DEBUG | ||
795 | "got addBA resp for tid %d but we already gave up\n", | ||
796 | tid); | ||
797 | #endif | ||
798 | goto out; | ||
799 | } | ||
800 | |||
765 | /* | 801 | /* |
766 | * IEEE 802.11-2007 7.3.1.14: | 802 | * IEEE 802.11-2007 7.3.1.14: |
767 | * In an ADDBA Response frame, when the Status Code field | 803 | * In an ADDBA Response frame, when the Status Code field |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b3a476fe8272..ffafda5022c2 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -89,8 +89,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
89 | [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, | 89 | [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, |
90 | [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 }, | 90 | [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 }, |
91 | 91 | ||
92 | [NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN }, | 92 | [NL80211_ATTR_MAC] = { .len = ETH_ALEN }, |
93 | [NL80211_ATTR_PREV_BSSID] = { .type = NLA_BINARY, .len = ETH_ALEN }, | 93 | [NL80211_ATTR_PREV_BSSID] = { .len = ETH_ALEN }, |
94 | 94 | ||
95 | [NL80211_ATTR_KEY] = { .type = NLA_NESTED, }, | 95 | [NL80211_ATTR_KEY] = { .type = NLA_NESTED, }, |
96 | [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY, | 96 | [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY, |