diff options
-rw-r--r-- | include/net/mac80211.h | 4 | ||||
-rw-r--r-- | net/mac80211/agg-tx.c | 136 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 8 | ||||
-rw-r--r-- | net/mac80211/main.c | 2 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 5 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 2 | ||||
-rw-r--r-- | net/mac80211/tx.c | 142 |
7 files changed, 221 insertions, 78 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 07fe9875506e..841f7f804bb6 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -248,6 +248,9 @@ struct ieee80211_bss_conf { | |||
248 | * @IEEE80211_TX_INTFL_RCALGO: mac80211 internal flag, do not test or | 248 | * @IEEE80211_TX_INTFL_RCALGO: mac80211 internal flag, do not test or |
249 | * set this flag in the driver; indicates that the rate control | 249 | * set this flag in the driver; indicates that the rate control |
250 | * algorithm was used and should be notified of TX status | 250 | * algorithm was used and should be notified of TX status |
251 | * @IEEE80211_TX_INTFL_NEED_TXPROCESSING: completely internal to mac80211, | ||
252 | * used to indicate that a pending frame requires TX processing before | ||
253 | * it can be sent out. | ||
251 | */ | 254 | */ |
252 | enum mac80211_tx_control_flags { | 255 | enum mac80211_tx_control_flags { |
253 | IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0), | 256 | IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0), |
@@ -264,6 +267,7 @@ enum mac80211_tx_control_flags { | |||
264 | IEEE80211_TX_STAT_AMPDU_NO_BACK = BIT(11), | 267 | IEEE80211_TX_STAT_AMPDU_NO_BACK = BIT(11), |
265 | IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(12), | 268 | IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(12), |
266 | IEEE80211_TX_INTFL_RCALGO = BIT(13), | 269 | IEEE80211_TX_INTFL_RCALGO = BIT(13), |
270 | IEEE80211_TX_INTFL_NEED_TXPROCESSING = BIT(14), | ||
267 | }; | 271 | }; |
268 | 272 | ||
269 | /** | 273 | /** |
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index fd718e2b29f7..64b839bfbf17 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -132,16 +132,6 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
132 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | 132 | state = &sta->ampdu_mlme.tid_state_tx[tid]; |
133 | 133 | ||
134 | if (local->hw.ampdu_queues) { | 134 | if (local->hw.ampdu_queues) { |
135 | if (initiator) { | ||
136 | /* | ||
137 | * Stop the AC queue to avoid issues where we send | ||
138 | * unaggregated frames already before the delba. | ||
139 | */ | ||
140 | ieee80211_stop_queue_by_reason(&local->hw, | ||
141 | local->hw.queues + sta->tid_to_tx_q[tid], | ||
142 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | ||
143 | } | ||
144 | |||
145 | /* | 135 | /* |
146 | * Pretend the driver woke the queue, just in case | 136 | * Pretend the driver woke the queue, just in case |
147 | * it disabled it before the session was stopped. | 137 | * it disabled it before the session was stopped. |
@@ -158,6 +148,10 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
158 | /* HW shall not deny going back to legacy */ | 148 | /* HW shall not deny going back to legacy */ |
159 | if (WARN_ON(ret)) { | 149 | if (WARN_ON(ret)) { |
160 | *state = HT_AGG_STATE_OPERATIONAL; | 150 | *state = HT_AGG_STATE_OPERATIONAL; |
151 | /* | ||
152 | * We may have pending packets get stuck in this case... | ||
153 | * Not bothering with a workaround for now. | ||
154 | */ | ||
161 | } | 155 | } |
162 | 156 | ||
163 | return ret; | 157 | return ret; |
@@ -226,13 +220,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
226 | ra, tid); | 220 | ra, tid); |
227 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 221 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
228 | 222 | ||
229 | if (hw->ampdu_queues && ieee80211_ac_from_tid(tid) == 0) { | ||
230 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
231 | printk(KERN_DEBUG "rejecting on voice AC\n"); | ||
232 | #endif | ||
233 | return -EINVAL; | ||
234 | } | ||
235 | |||
236 | rcu_read_lock(); | 223 | rcu_read_lock(); |
237 | 224 | ||
238 | sta = sta_info_get(local, ra); | 225 | sta = sta_info_get(local, ra); |
@@ -267,6 +254,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
267 | } | 254 | } |
268 | 255 | ||
269 | spin_lock_bh(&sta->lock); | 256 | spin_lock_bh(&sta->lock); |
257 | spin_lock(&local->ampdu_lock); | ||
270 | 258 | ||
271 | sdata = sta->sdata; | 259 | sdata = sta->sdata; |
272 | 260 | ||
@@ -308,21 +296,19 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
308 | ret = -ENOSPC; | 296 | ret = -ENOSPC; |
309 | goto err_unlock_sta; | 297 | goto err_unlock_sta; |
310 | } | 298 | } |
311 | |||
312 | /* | ||
313 | * If we successfully allocate the session, we can't have | ||
314 | * anything going on on the queue this TID maps into, so | ||
315 | * stop it for now. This is a "virtual" stop using the same | ||
316 | * mechanism that drivers will use. | ||
317 | * | ||
318 | * XXX: queue up frames for this session in the sta_info | ||
319 | * struct instead to avoid hitting all other STAs. | ||
320 | */ | ||
321 | ieee80211_stop_queue_by_reason( | ||
322 | &local->hw, hw->queues + qn, | ||
323 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | ||
324 | } | 299 | } |
325 | 300 | ||
301 | /* | ||
302 | * While we're asking the driver about the aggregation, | ||
303 | * stop the AC queue so that we don't have to worry | ||
304 | * about frames that came in while we were doing that, | ||
305 | * which would require us to put them to the AC pending | ||
306 | * afterwards which just makes the code more complex. | ||
307 | */ | ||
308 | ieee80211_stop_queue_by_reason( | ||
309 | &local->hw, ieee80211_ac_from_tid(tid), | ||
310 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | ||
311 | |||
326 | /* prepare A-MPDU MLME for Tx aggregation */ | 312 | /* prepare A-MPDU MLME for Tx aggregation */ |
327 | sta->ampdu_mlme.tid_tx[tid] = | 313 | sta->ampdu_mlme.tid_tx[tid] = |
328 | kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC); | 314 | kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC); |
@@ -336,6 +322,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
336 | goto err_return_queue; | 322 | goto err_return_queue; |
337 | } | 323 | } |
338 | 324 | ||
325 | skb_queue_head_init(&sta->ampdu_mlme.tid_tx[tid]->pending); | ||
326 | |||
339 | /* Tx timer */ | 327 | /* Tx timer */ |
340 | sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function = | 328 | sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function = |
341 | sta_addba_resp_timer_expired; | 329 | sta_addba_resp_timer_expired; |
@@ -362,6 +350,12 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
362 | } | 350 | } |
363 | sta->tid_to_tx_q[tid] = qn; | 351 | sta->tid_to_tx_q[tid] = qn; |
364 | 352 | ||
353 | /* Driver vetoed or OKed, but we can take packets again now */ | ||
354 | ieee80211_wake_queue_by_reason( | ||
355 | &local->hw, ieee80211_ac_from_tid(tid), | ||
356 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | ||
357 | |||
358 | spin_unlock(&local->ampdu_lock); | ||
365 | spin_unlock_bh(&sta->lock); | 359 | spin_unlock_bh(&sta->lock); |
366 | 360 | ||
367 | /* send an addBA request */ | 361 | /* send an addBA request */ |
@@ -388,15 +382,16 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
388 | sta->ampdu_mlme.tid_tx[tid] = NULL; | 382 | sta->ampdu_mlme.tid_tx[tid] = NULL; |
389 | err_return_queue: | 383 | err_return_queue: |
390 | if (qn >= 0) { | 384 | if (qn >= 0) { |
391 | /* We failed, so start queue again right away. */ | ||
392 | ieee80211_wake_queue_by_reason(hw, hw->queues + qn, | ||
393 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | ||
394 | /* give queue back to pool */ | 385 | /* give queue back to pool */ |
395 | spin_lock(&local->queue_stop_reason_lock); | 386 | spin_lock(&local->queue_stop_reason_lock); |
396 | local->ampdu_ac_queue[qn] = -1; | 387 | local->ampdu_ac_queue[qn] = -1; |
397 | spin_unlock(&local->queue_stop_reason_lock); | 388 | spin_unlock(&local->queue_stop_reason_lock); |
398 | } | 389 | } |
390 | ieee80211_wake_queue_by_reason( | ||
391 | &local->hw, ieee80211_ac_from_tid(tid), | ||
392 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | ||
399 | err_unlock_sta: | 393 | err_unlock_sta: |
394 | spin_unlock(&local->ampdu_lock); | ||
400 | spin_unlock_bh(&sta->lock); | 395 | spin_unlock_bh(&sta->lock); |
401 | unlock: | 396 | unlock: |
402 | rcu_read_unlock(); | 397 | rcu_read_unlock(); |
@@ -404,6 +399,45 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
404 | } | 399 | } |
405 | EXPORT_SYMBOL(ieee80211_start_tx_ba_session); | 400 | EXPORT_SYMBOL(ieee80211_start_tx_ba_session); |
406 | 401 | ||
402 | /* | ||
403 | * splice packets from the STA's pending to the local pending, | ||
404 | * requires a call to ieee80211_agg_splice_finish and holding | ||
405 | * local->ampdu_lock across both calls. | ||
406 | */ | ||
407 | static void ieee80211_agg_splice_packets(struct ieee80211_local *local, | ||
408 | struct sta_info *sta, u16 tid) | ||
409 | { | ||
410 | unsigned long flags; | ||
411 | u16 queue = ieee80211_ac_from_tid(tid); | ||
412 | |||
413 | ieee80211_stop_queue_by_reason( | ||
414 | &local->hw, queue, | ||
415 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | ||
416 | |||
417 | if (!skb_queue_empty(&sta->ampdu_mlme.tid_tx[tid]->pending)) { | ||
418 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | ||
419 | /* mark queue as pending, it is stopped already */ | ||
420 | __set_bit(IEEE80211_QUEUE_STOP_REASON_PENDING, | ||
421 | &local->queue_stop_reasons[queue]); | ||
422 | /* copy over remaining packets */ | ||
423 | skb_queue_splice_tail_init( | ||
424 | &sta->ampdu_mlme.tid_tx[tid]->pending, | ||
425 | &local->pending[queue]); | ||
426 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | ||
427 | } | ||
428 | } | ||
429 | |||
430 | static void ieee80211_agg_splice_finish(struct ieee80211_local *local, | ||
431 | struct sta_info *sta, u16 tid) | ||
432 | { | ||
433 | u16 queue = ieee80211_ac_from_tid(tid); | ||
434 | |||
435 | ieee80211_wake_queue_by_reason( | ||
436 | &local->hw, queue, | ||
437 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | ||
438 | } | ||
439 | |||
440 | /* caller must hold sta->lock */ | ||
407 | static void ieee80211_agg_tx_operational(struct ieee80211_local *local, | 441 | static void ieee80211_agg_tx_operational(struct ieee80211_local *local, |
408 | struct sta_info *sta, u16 tid) | 442 | struct sta_info *sta, u16 tid) |
409 | { | 443 | { |
@@ -411,15 +445,16 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local, | |||
411 | printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid); | 445 | printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid); |
412 | #endif | 446 | #endif |
413 | 447 | ||
414 | if (local->hw.ampdu_queues) { | 448 | spin_lock(&local->ampdu_lock); |
415 | /* | 449 | ieee80211_agg_splice_packets(local, sta, tid); |
416 | * Wake up the A-MPDU queue, we stopped it earlier, | 450 | /* |
417 | * this will in turn wake the entire AC. | 451 | * NB: we rely on sta->lock being taken in the TX |
418 | */ | 452 | * processing here when adding to the pending queue, |
419 | ieee80211_wake_queue_by_reason(&local->hw, | 453 | * otherwise we could only change the state of the |
420 | local->hw.queues + sta->tid_to_tx_q[tid], | 454 | * session to OPERATIONAL _here_. |
421 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | 455 | */ |
422 | } | 456 | ieee80211_agg_splice_finish(local, sta, tid); |
457 | spin_unlock(&local->ampdu_lock); | ||
423 | 458 | ||
424 | local->ops->ampdu_action(&local->hw, IEEE80211_AMPDU_TX_OPERATIONAL, | 459 | local->ops->ampdu_action(&local->hw, IEEE80211_AMPDU_TX_OPERATIONAL, |
425 | &sta->sta, tid, NULL); | 460 | &sta->sta, tid, NULL); |
@@ -602,22 +637,19 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) | |||
602 | WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); | 637 | WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); |
603 | 638 | ||
604 | spin_lock_bh(&sta->lock); | 639 | spin_lock_bh(&sta->lock); |
640 | spin_lock(&local->ampdu_lock); | ||
605 | 641 | ||
606 | if (*state & HT_AGG_STATE_INITIATOR_MSK && | 642 | ieee80211_agg_splice_packets(local, sta, tid); |
607 | hw->ampdu_queues) { | ||
608 | /* | ||
609 | * Wake up this queue, we stopped it earlier, | ||
610 | * this will in turn wake the entire AC. | ||
611 | */ | ||
612 | ieee80211_wake_queue_by_reason(hw, | ||
613 | hw->queues + sta->tid_to_tx_q[tid], | ||
614 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | ||
615 | } | ||
616 | 643 | ||
617 | *state = HT_AGG_STATE_IDLE; | 644 | *state = HT_AGG_STATE_IDLE; |
645 | /* from now on packets are no longer put onto sta->pending */ | ||
618 | sta->ampdu_mlme.addba_req_num[tid] = 0; | 646 | sta->ampdu_mlme.addba_req_num[tid] = 0; |
619 | kfree(sta->ampdu_mlme.tid_tx[tid]); | 647 | kfree(sta->ampdu_mlme.tid_tx[tid]); |
620 | sta->ampdu_mlme.tid_tx[tid] = NULL; | 648 | sta->ampdu_mlme.tid_tx[tid] = NULL; |
649 | |||
650 | ieee80211_agg_splice_finish(local, sta, tid); | ||
651 | |||
652 | spin_unlock(&local->ampdu_lock); | ||
621 | spin_unlock_bh(&sta->lock); | 653 | spin_unlock_bh(&sta->lock); |
622 | 654 | ||
623 | rcu_read_unlock(); | 655 | rcu_read_unlock(); |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 6ce62e553dc2..32345b479adb 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -639,6 +639,14 @@ struct ieee80211_local { | |||
639 | struct sk_buff_head pending[IEEE80211_MAX_QUEUES]; | 639 | struct sk_buff_head pending[IEEE80211_MAX_QUEUES]; |
640 | struct tasklet_struct tx_pending_tasklet; | 640 | struct tasklet_struct tx_pending_tasklet; |
641 | 641 | ||
642 | /* | ||
643 | * This lock is used to prevent concurrent A-MPDU | ||
644 | * session start/stop processing, this thus also | ||
645 | * synchronises the ->ampdu_action() callback to | ||
646 | * drivers and limits it to one at a time. | ||
647 | */ | ||
648 | spinlock_t ampdu_lock; | ||
649 | |||
642 | /* number of interfaces with corresponding IFF_ flags */ | 650 | /* number of interfaces with corresponding IFF_ flags */ |
643 | atomic_t iff_allmultis, iff_promiscs; | 651 | atomic_t iff_allmultis, iff_promiscs; |
644 | 652 | ||
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index a7430e98c531..756284e0bbd3 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -795,6 +795,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
795 | skb_queue_head_init(&local->skb_queue); | 795 | skb_queue_head_init(&local->skb_queue); |
796 | skb_queue_head_init(&local->skb_queue_unreliable); | 796 | skb_queue_head_init(&local->skb_queue_unreliable); |
797 | 797 | ||
798 | spin_lock_init(&local->ampdu_lock); | ||
799 | |||
798 | return local_to_hw(local); | 800 | return local_to_hw(local); |
799 | } | 801 | } |
800 | EXPORT_SYMBOL(ieee80211_alloc_hw); | 802 | EXPORT_SYMBOL(ieee80211_alloc_hw); |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 4ba3c540fcf3..dd3593c1fd23 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -239,6 +239,11 @@ void sta_info_destroy(struct sta_info *sta) | |||
239 | tid_tx = sta->ampdu_mlme.tid_tx[i]; | 239 | tid_tx = sta->ampdu_mlme.tid_tx[i]; |
240 | if (tid_tx) { | 240 | if (tid_tx) { |
241 | del_timer_sync(&tid_tx->addba_resp_timer); | 241 | del_timer_sync(&tid_tx->addba_resp_timer); |
242 | /* | ||
243 | * STA removed while aggregation session being | ||
244 | * started? Bit odd, but purge frames anyway. | ||
245 | */ | ||
246 | skb_queue_purge(&tid_tx->pending); | ||
242 | kfree(tid_tx); | 247 | kfree(tid_tx); |
243 | } | 248 | } |
244 | } | 249 | } |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 5b223b216e5a..18fd5d1a4422 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -73,11 +73,13 @@ enum ieee80211_sta_info_flags { | |||
73 | * struct tid_ampdu_tx - TID aggregation information (Tx). | 73 | * struct tid_ampdu_tx - TID aggregation information (Tx). |
74 | * | 74 | * |
75 | * @addba_resp_timer: timer for peer's response to addba request | 75 | * @addba_resp_timer: timer for peer's response to addba request |
76 | * @pending: pending frames queue -- use sta's spinlock to protect | ||
76 | * @ssn: Starting Sequence Number expected to be aggregated. | 77 | * @ssn: Starting Sequence Number expected to be aggregated. |
77 | * @dialog_token: dialog token for aggregation session | 78 | * @dialog_token: dialog token for aggregation session |
78 | */ | 79 | */ |
79 | struct tid_ampdu_tx { | 80 | struct tid_ampdu_tx { |
80 | struct timer_list addba_resp_timer; | 81 | struct timer_list addba_resp_timer; |
82 | struct sk_buff_head pending; | ||
81 | u16 ssn; | 83 | u16 ssn; |
82 | u8 dialog_token; | 84 | u8 dialog_token; |
83 | }; | 85 | }; |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index a0e00c6339ca..906ab785db40 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -984,9 +984,9 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, | |||
984 | struct ieee80211_hdr *hdr; | 984 | struct ieee80211_hdr *hdr; |
985 | struct ieee80211_sub_if_data *sdata; | 985 | struct ieee80211_sub_if_data *sdata; |
986 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 986 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
987 | |||
988 | int hdrlen, tid; | 987 | int hdrlen, tid; |
989 | u8 *qc, *state; | 988 | u8 *qc, *state; |
989 | bool queued = false; | ||
990 | 990 | ||
991 | memset(tx, 0, sizeof(*tx)); | 991 | memset(tx, 0, sizeof(*tx)); |
992 | tx->skb = skb; | 992 | tx->skb = skb; |
@@ -1013,20 +1013,53 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, | |||
1013 | */ | 1013 | */ |
1014 | } | 1014 | } |
1015 | 1015 | ||
1016 | /* | ||
1017 | * If this flag is set to true anywhere, and we get here, | ||
1018 | * we are doing the needed processing, so remove the flag | ||
1019 | * now. | ||
1020 | */ | ||
1021 | info->flags &= ~IEEE80211_TX_INTFL_NEED_TXPROCESSING; | ||
1022 | |||
1016 | hdr = (struct ieee80211_hdr *) skb->data; | 1023 | hdr = (struct ieee80211_hdr *) skb->data; |
1017 | 1024 | ||
1018 | tx->sta = sta_info_get(local, hdr->addr1); | 1025 | tx->sta = sta_info_get(local, hdr->addr1); |
1019 | 1026 | ||
1020 | if (tx->sta && ieee80211_is_data_qos(hdr->frame_control)) { | 1027 | if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) && |
1028 | (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)) { | ||
1021 | unsigned long flags; | 1029 | unsigned long flags; |
1030 | struct tid_ampdu_tx *tid_tx; | ||
1031 | |||
1022 | qc = ieee80211_get_qos_ctl(hdr); | 1032 | qc = ieee80211_get_qos_ctl(hdr); |
1023 | tid = *qc & IEEE80211_QOS_CTL_TID_MASK; | 1033 | tid = *qc & IEEE80211_QOS_CTL_TID_MASK; |
1024 | 1034 | ||
1025 | spin_lock_irqsave(&tx->sta->lock, flags); | 1035 | spin_lock_irqsave(&tx->sta->lock, flags); |
1036 | /* | ||
1037 | * XXX: This spinlock could be fairly expensive, but see the | ||
1038 | * comment in agg-tx.c:ieee80211_agg_tx_operational(). | ||
1039 | * One way to solve this would be to do something RCU-like | ||
1040 | * for managing the tid_tx struct and using atomic bitops | ||
1041 | * for the actual state -- by introducing an actual | ||
1042 | * 'operational' bit that would be possible. It would | ||
1043 | * require changing ieee80211_agg_tx_operational() to | ||
1044 | * set that bit, and changing the way tid_tx is managed | ||
1045 | * everywhere, including races between that bit and | ||
1046 | * tid_tx going away (tid_tx being added can be easily | ||
1047 | * committed to memory before the 'operational' bit). | ||
1048 | */ | ||
1049 | tid_tx = tx->sta->ampdu_mlme.tid_tx[tid]; | ||
1026 | state = &tx->sta->ampdu_mlme.tid_state_tx[tid]; | 1050 | state = &tx->sta->ampdu_mlme.tid_state_tx[tid]; |
1027 | if (*state == HT_AGG_STATE_OPERATIONAL) | 1051 | if (*state == HT_AGG_STATE_OPERATIONAL) { |
1028 | info->flags |= IEEE80211_TX_CTL_AMPDU; | 1052 | info->flags |= IEEE80211_TX_CTL_AMPDU; |
1053 | } else if (*state != HT_AGG_STATE_IDLE) { | ||
1054 | /* in progress */ | ||
1055 | queued = true; | ||
1056 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; | ||
1057 | __skb_queue_tail(&tid_tx->pending, skb); | ||
1058 | } | ||
1029 | spin_unlock_irqrestore(&tx->sta->lock, flags); | 1059 | spin_unlock_irqrestore(&tx->sta->lock, flags); |
1060 | |||
1061 | if (unlikely(queued)) | ||
1062 | return TX_QUEUED; | ||
1030 | } | 1063 | } |
1031 | 1064 | ||
1032 | if (is_multicast_ether_addr(hdr->addr1)) { | 1065 | if (is_multicast_ether_addr(hdr->addr1)) { |
@@ -1077,7 +1110,14 @@ static int ieee80211_tx_prepare(struct ieee80211_local *local, | |||
1077 | } | 1110 | } |
1078 | if (unlikely(!dev)) | 1111 | if (unlikely(!dev)) |
1079 | return -ENODEV; | 1112 | return -ENODEV; |
1080 | /* initialises tx with control */ | 1113 | /* |
1114 | * initialises tx with control | ||
1115 | * | ||
1116 | * return value is safe to ignore here because this function | ||
1117 | * can only be invoked for multicast frames | ||
1118 | * | ||
1119 | * XXX: clean up | ||
1120 | */ | ||
1081 | __ieee80211_tx_prepare(tx, skb, dev); | 1121 | __ieee80211_tx_prepare(tx, skb, dev); |
1082 | dev_put(dev); | 1122 | dev_put(dev); |
1083 | return 0; | 1123 | return 0; |
@@ -1188,7 +1228,8 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) | |||
1188 | return 0; | 1228 | return 0; |
1189 | } | 1229 | } |
1190 | 1230 | ||
1191 | static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb) | 1231 | static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb, |
1232 | bool txpending) | ||
1192 | { | 1233 | { |
1193 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 1234 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
1194 | struct sta_info *sta; | 1235 | struct sta_info *sta; |
@@ -1202,11 +1243,11 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb) | |||
1202 | 1243 | ||
1203 | queue = skb_get_queue_mapping(skb); | 1244 | queue = skb_get_queue_mapping(skb); |
1204 | 1245 | ||
1205 | WARN_ON(!skb_queue_empty(&local->pending[queue])); | 1246 | WARN_ON(!txpending && !skb_queue_empty(&local->pending[queue])); |
1206 | 1247 | ||
1207 | if (unlikely(skb->len < 10)) { | 1248 | if (unlikely(skb->len < 10)) { |
1208 | dev_kfree_skb(skb); | 1249 | dev_kfree_skb(skb); |
1209 | return 0; | 1250 | return; |
1210 | } | 1251 | } |
1211 | 1252 | ||
1212 | rcu_read_lock(); | 1253 | rcu_read_lock(); |
@@ -1214,10 +1255,13 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb) | |||
1214 | /* initialises tx */ | 1255 | /* initialises tx */ |
1215 | res_prepare = __ieee80211_tx_prepare(&tx, skb, dev); | 1256 | res_prepare = __ieee80211_tx_prepare(&tx, skb, dev); |
1216 | 1257 | ||
1217 | if (res_prepare == TX_DROP) { | 1258 | if (unlikely(res_prepare == TX_DROP)) { |
1218 | dev_kfree_skb(skb); | 1259 | dev_kfree_skb(skb); |
1219 | rcu_read_unlock(); | 1260 | rcu_read_unlock(); |
1220 | return 0; | 1261 | return; |
1262 | } else if (unlikely(res_prepare == TX_QUEUED)) { | ||
1263 | rcu_read_unlock(); | ||
1264 | return; | ||
1221 | } | 1265 | } |
1222 | 1266 | ||
1223 | sta = tx.sta; | 1267 | sta = tx.sta; |
@@ -1251,7 +1295,12 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb) | |||
1251 | do { | 1295 | do { |
1252 | next = skb->next; | 1296 | next = skb->next; |
1253 | skb->next = NULL; | 1297 | skb->next = NULL; |
1254 | skb_queue_tail(&local->pending[queue], skb); | 1298 | if (unlikely(txpending)) |
1299 | skb_queue_head(&local->pending[queue], | ||
1300 | skb); | ||
1301 | else | ||
1302 | skb_queue_tail(&local->pending[queue], | ||
1303 | skb); | ||
1255 | } while ((skb = next)); | 1304 | } while ((skb = next)); |
1256 | 1305 | ||
1257 | /* | 1306 | /* |
@@ -1276,7 +1325,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb) | |||
1276 | } | 1325 | } |
1277 | out: | 1326 | out: |
1278 | rcu_read_unlock(); | 1327 | rcu_read_unlock(); |
1279 | return 0; | 1328 | return; |
1280 | 1329 | ||
1281 | drop: | 1330 | drop: |
1282 | rcu_read_unlock(); | 1331 | rcu_read_unlock(); |
@@ -1287,7 +1336,6 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb) | |||
1287 | dev_kfree_skb(skb); | 1336 | dev_kfree_skb(skb); |
1288 | skb = next; | 1337 | skb = next; |
1289 | } | 1338 | } |
1290 | return 0; | ||
1291 | } | 1339 | } |
1292 | 1340 | ||
1293 | /* device xmit handlers */ | 1341 | /* device xmit handlers */ |
@@ -1346,7 +1394,6 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1346 | FOUND_SDATA, | 1394 | FOUND_SDATA, |
1347 | UNKNOWN_ADDRESS, | 1395 | UNKNOWN_ADDRESS, |
1348 | } monitor_iface = NOT_MONITOR; | 1396 | } monitor_iface = NOT_MONITOR; |
1349 | int ret; | ||
1350 | 1397 | ||
1351 | if (skb->iif) | 1398 | if (skb->iif) |
1352 | odev = dev_get_by_index(&init_net, skb->iif); | 1399 | odev = dev_get_by_index(&init_net, skb->iif); |
@@ -1360,7 +1407,7 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1360 | "originating device\n", dev->name); | 1407 | "originating device\n", dev->name); |
1361 | #endif | 1408 | #endif |
1362 | dev_kfree_skb(skb); | 1409 | dev_kfree_skb(skb); |
1363 | return 0; | 1410 | return NETDEV_TX_OK; |
1364 | } | 1411 | } |
1365 | 1412 | ||
1366 | if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && | 1413 | if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && |
@@ -1389,7 +1436,7 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1389 | else | 1436 | else |
1390 | if (mesh_nexthop_lookup(skb, osdata)) { | 1437 | if (mesh_nexthop_lookup(skb, osdata)) { |
1391 | dev_put(odev); | 1438 | dev_put(odev); |
1392 | return 0; | 1439 | return NETDEV_TX_OK; |
1393 | } | 1440 | } |
1394 | if (memcmp(odev->dev_addr, hdr->addr4, ETH_ALEN) != 0) | 1441 | if (memcmp(odev->dev_addr, hdr->addr4, ETH_ALEN) != 0) |
1395 | IEEE80211_IFSTA_MESH_CTR_INC(&osdata->u.mesh, | 1442 | IEEE80211_IFSTA_MESH_CTR_INC(&osdata->u.mesh, |
@@ -1451,7 +1498,7 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1451 | if (ieee80211_skb_resize(osdata->local, skb, headroom, may_encrypt)) { | 1498 | if (ieee80211_skb_resize(osdata->local, skb, headroom, may_encrypt)) { |
1452 | dev_kfree_skb(skb); | 1499 | dev_kfree_skb(skb); |
1453 | dev_put(odev); | 1500 | dev_put(odev); |
1454 | return 0; | 1501 | return NETDEV_TX_OK; |
1455 | } | 1502 | } |
1456 | 1503 | ||
1457 | if (osdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 1504 | if (osdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
@@ -1460,10 +1507,11 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1460 | u.ap); | 1507 | u.ap); |
1461 | if (likely(monitor_iface != UNKNOWN_ADDRESS)) | 1508 | if (likely(monitor_iface != UNKNOWN_ADDRESS)) |
1462 | info->control.vif = &osdata->vif; | 1509 | info->control.vif = &osdata->vif; |
1463 | ret = ieee80211_tx(odev, skb); | 1510 | |
1511 | ieee80211_tx(odev, skb, false); | ||
1464 | dev_put(odev); | 1512 | dev_put(odev); |
1465 | 1513 | ||
1466 | return ret; | 1514 | return NETDEV_TX_OK; |
1467 | } | 1515 | } |
1468 | 1516 | ||
1469 | int ieee80211_monitor_start_xmit(struct sk_buff *skb, | 1517 | int ieee80211_monitor_start_xmit(struct sk_buff *skb, |
@@ -1827,6 +1875,54 @@ void ieee80211_clear_tx_pending(struct ieee80211_local *local) | |||
1827 | skb_queue_purge(&local->pending[i]); | 1875 | skb_queue_purge(&local->pending[i]); |
1828 | } | 1876 | } |
1829 | 1877 | ||
1878 | static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, | ||
1879 | struct sk_buff *skb) | ||
1880 | { | ||
1881 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
1882 | struct ieee80211_sub_if_data *sdata; | ||
1883 | struct sta_info *sta; | ||
1884 | struct ieee80211_hdr *hdr; | ||
1885 | struct net_device *dev; | ||
1886 | int ret; | ||
1887 | bool result = true; | ||
1888 | |||
1889 | /* does interface still exist? */ | ||
1890 | dev = dev_get_by_index(&init_net, skb->iif); | ||
1891 | if (!dev) { | ||
1892 | dev_kfree_skb(skb); | ||
1893 | return true; | ||
1894 | } | ||
1895 | |||
1896 | /* validate info->control.vif against skb->iif */ | ||
1897 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1898 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
1899 | sdata = container_of(sdata->bss, | ||
1900 | struct ieee80211_sub_if_data, | ||
1901 | u.ap); | ||
1902 | |||
1903 | if (unlikely(info->control.vif && info->control.vif != &sdata->vif)) { | ||
1904 | dev_kfree_skb(skb); | ||
1905 | result = true; | ||
1906 | goto out; | ||
1907 | } | ||
1908 | |||
1909 | if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) { | ||
1910 | ieee80211_tx(dev, skb, true); | ||
1911 | } else { | ||
1912 | hdr = (struct ieee80211_hdr *)skb->data; | ||
1913 | sta = sta_info_get(local, hdr->addr1); | ||
1914 | |||
1915 | ret = __ieee80211_tx(local, &skb, sta); | ||
1916 | if (ret != IEEE80211_TX_OK) | ||
1917 | result = false; | ||
1918 | } | ||
1919 | |||
1920 | out: | ||
1921 | dev_put(dev); | ||
1922 | |||
1923 | return result; | ||
1924 | } | ||
1925 | |||
1830 | /* | 1926 | /* |
1831 | * Transmit all pending packets. Called from tasklet, locks master device | 1927 | * Transmit all pending packets. Called from tasklet, locks master device |
1832 | * TX lock so that no new packets can come in. | 1928 | * TX lock so that no new packets can come in. |
@@ -1835,9 +1931,8 @@ void ieee80211_tx_pending(unsigned long data) | |||
1835 | { | 1931 | { |
1836 | struct ieee80211_local *local = (struct ieee80211_local *)data; | 1932 | struct ieee80211_local *local = (struct ieee80211_local *)data; |
1837 | struct net_device *dev = local->mdev; | 1933 | struct net_device *dev = local->mdev; |
1838 | struct ieee80211_hdr *hdr; | ||
1839 | unsigned long flags; | 1934 | unsigned long flags; |
1840 | int i, ret; | 1935 | int i; |
1841 | bool next; | 1936 | bool next; |
1842 | 1937 | ||
1843 | rcu_read_lock(); | 1938 | rcu_read_lock(); |
@@ -1868,13 +1963,8 @@ void ieee80211_tx_pending(unsigned long data) | |||
1868 | 1963 | ||
1869 | while (!skb_queue_empty(&local->pending[i])) { | 1964 | while (!skb_queue_empty(&local->pending[i])) { |
1870 | struct sk_buff *skb = skb_dequeue(&local->pending[i]); | 1965 | struct sk_buff *skb = skb_dequeue(&local->pending[i]); |
1871 | struct sta_info *sta; | ||
1872 | |||
1873 | hdr = (struct ieee80211_hdr *)skb->data; | ||
1874 | sta = sta_info_get(local, hdr->addr1); | ||
1875 | 1966 | ||
1876 | ret = __ieee80211_tx(local, &skb, sta); | 1967 | if (!ieee80211_tx_pending_skb(local, skb)) { |
1877 | if (ret != IEEE80211_TX_OK) { | ||
1878 | skb_queue_head(&local->pending[i], skb); | 1968 | skb_queue_head(&local->pending[i], skb); |
1879 | break; | 1969 | break; |
1880 | } | 1970 | } |