diff options
Diffstat (limited to 'net/mac80211/agg-tx.c')
-rw-r--r-- | net/mac80211/agg-tx.c | 59 |
1 files changed, 38 insertions, 21 deletions
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 63d852cb4ca2..cd5125f77cc5 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -136,6 +136,14 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1 | |||
136 | ieee80211_tx_skb(sdata, skb); | 136 | ieee80211_tx_skb(sdata, skb); |
137 | } | 137 | } |
138 | 138 | ||
139 | void ieee80211_assign_tid_tx(struct sta_info *sta, int tid, | ||
140 | struct tid_ampdu_tx *tid_tx) | ||
141 | { | ||
142 | lockdep_assert_held(&sta->ampdu_mlme.mtx); | ||
143 | lockdep_assert_held(&sta->lock); | ||
144 | rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx); | ||
145 | } | ||
146 | |||
139 | static void kfree_tid_tx(struct rcu_head *rcu_head) | 147 | static void kfree_tid_tx(struct rcu_head *rcu_head) |
140 | { | 148 | { |
141 | struct tid_ampdu_tx *tid_tx = | 149 | struct tid_ampdu_tx *tid_tx = |
@@ -149,19 +157,22 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
149 | bool tx) | 157 | bool tx) |
150 | { | 158 | { |
151 | struct ieee80211_local *local = sta->local; | 159 | struct ieee80211_local *local = sta->local; |
152 | struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 160 | struct tid_ampdu_tx *tid_tx; |
153 | int ret; | 161 | int ret; |
154 | 162 | ||
155 | lockdep_assert_held(&sta->ampdu_mlme.mtx); | 163 | lockdep_assert_held(&sta->ampdu_mlme.mtx); |
156 | 164 | ||
157 | if (!tid_tx) | ||
158 | return -ENOENT; | ||
159 | |||
160 | spin_lock_bh(&sta->lock); | 165 | spin_lock_bh(&sta->lock); |
161 | 166 | ||
167 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); | ||
168 | if (!tid_tx) { | ||
169 | spin_unlock_bh(&sta->lock); | ||
170 | return -ENOENT; | ||
171 | } | ||
172 | |||
162 | if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { | 173 | if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { |
163 | /* not even started yet! */ | 174 | /* not even started yet! */ |
164 | rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL); | 175 | ieee80211_assign_tid_tx(sta, tid, NULL); |
165 | spin_unlock_bh(&sta->lock); | 176 | spin_unlock_bh(&sta->lock); |
166 | call_rcu(&tid_tx->rcu_head, kfree_tid_tx); | 177 | call_rcu(&tid_tx->rcu_head, kfree_tid_tx); |
167 | return 0; | 178 | return 0; |
@@ -283,13 +294,13 @@ ieee80211_wake_queue_agg(struct ieee80211_local *local, int tid) | |||
283 | 294 | ||
284 | void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) | 295 | void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) |
285 | { | 296 | { |
286 | struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 297 | struct tid_ampdu_tx *tid_tx; |
287 | struct ieee80211_local *local = sta->local; | 298 | struct ieee80211_local *local = sta->local; |
288 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 299 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
289 | u16 start_seq_num; | 300 | u16 start_seq_num; |
290 | int ret; | 301 | int ret; |
291 | 302 | ||
292 | lockdep_assert_held(&sta->ampdu_mlme.mtx); | 303 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
293 | 304 | ||
294 | /* | 305 | /* |
295 | * While we're asking the driver about the aggregation, | 306 | * While we're asking the driver about the aggregation, |
@@ -318,7 +329,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) | |||
318 | " tid %d\n", tid); | 329 | " tid %d\n", tid); |
319 | #endif | 330 | #endif |
320 | spin_lock_bh(&sta->lock); | 331 | spin_lock_bh(&sta->lock); |
321 | rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL); | 332 | ieee80211_assign_tid_tx(sta, tid, NULL); |
322 | spin_unlock_bh(&sta->lock); | 333 | spin_unlock_bh(&sta->lock); |
323 | 334 | ||
324 | ieee80211_wake_queue_agg(local, tid); | 335 | ieee80211_wake_queue_agg(local, tid); |
@@ -396,9 +407,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, | |||
396 | goto err_unlock_sta; | 407 | goto err_unlock_sta; |
397 | } | 408 | } |
398 | 409 | ||
399 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 410 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
400 | /* check if the TID is not in aggregation flow already */ | 411 | /* check if the TID is not in aggregation flow already */ |
401 | if (tid_tx) { | 412 | if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) { |
402 | #ifdef CONFIG_MAC80211_HT_DEBUG | 413 | #ifdef CONFIG_MAC80211_HT_DEBUG |
403 | printk(KERN_DEBUG "BA request denied - session is not " | 414 | printk(KERN_DEBUG "BA request denied - session is not " |
404 | "idle on tid %u\n", tid); | 415 | "idle on tid %u\n", tid); |
@@ -433,8 +444,11 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, | |||
433 | sta->ampdu_mlme.dialog_token_allocator++; | 444 | sta->ampdu_mlme.dialog_token_allocator++; |
434 | tid_tx->dialog_token = sta->ampdu_mlme.dialog_token_allocator; | 445 | tid_tx->dialog_token = sta->ampdu_mlme.dialog_token_allocator; |
435 | 446 | ||
436 | /* finally, assign it to the array */ | 447 | /* |
437 | rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx); | 448 | * Finally, assign it to the start array; the work item will |
449 | * collect it and move it to the normal array. | ||
450 | */ | ||
451 | sta->ampdu_mlme.tid_start_tx[tid] = tid_tx; | ||
438 | 452 | ||
439 | ieee80211_queue_work(&local->hw, &sta->ampdu_mlme.work); | 453 | ieee80211_queue_work(&local->hw, &sta->ampdu_mlme.work); |
440 | 454 | ||
@@ -480,16 +494,19 @@ ieee80211_agg_splice_finish(struct ieee80211_local *local, u16 tid) | |||
480 | static void ieee80211_agg_tx_operational(struct ieee80211_local *local, | 494 | static void ieee80211_agg_tx_operational(struct ieee80211_local *local, |
481 | struct sta_info *sta, u16 tid) | 495 | struct sta_info *sta, u16 tid) |
482 | { | 496 | { |
497 | struct tid_ampdu_tx *tid_tx; | ||
498 | |||
483 | lockdep_assert_held(&sta->ampdu_mlme.mtx); | 499 | lockdep_assert_held(&sta->ampdu_mlme.mtx); |
484 | 500 | ||
501 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); | ||
502 | |||
485 | #ifdef CONFIG_MAC80211_HT_DEBUG | 503 | #ifdef CONFIG_MAC80211_HT_DEBUG |
486 | printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid); | 504 | printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid); |
487 | #endif | 505 | #endif |
488 | 506 | ||
489 | drv_ampdu_action(local, sta->sdata, | 507 | drv_ampdu_action(local, sta->sdata, |
490 | IEEE80211_AMPDU_TX_OPERATIONAL, | 508 | IEEE80211_AMPDU_TX_OPERATIONAL, |
491 | &sta->sta, tid, NULL, | 509 | &sta->sta, tid, NULL, tid_tx->buf_size); |
492 | sta->ampdu_mlme.tid_tx[tid]->buf_size); | ||
493 | 510 | ||
494 | /* | 511 | /* |
495 | * synchronize with TX path, while splicing the TX path | 512 | * synchronize with TX path, while splicing the TX path |
@@ -497,13 +514,13 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local, | |||
497 | */ | 514 | */ |
498 | spin_lock_bh(&sta->lock); | 515 | spin_lock_bh(&sta->lock); |
499 | 516 | ||
500 | ieee80211_agg_splice_packets(local, sta->ampdu_mlme.tid_tx[tid], tid); | 517 | ieee80211_agg_splice_packets(local, tid_tx, tid); |
501 | /* | 518 | /* |
502 | * Now mark as operational. This will be visible | 519 | * Now mark as operational. This will be visible |
503 | * in the TX path, and lets it go lock-free in | 520 | * in the TX path, and lets it go lock-free in |
504 | * the common case. | 521 | * the common case. |
505 | */ | 522 | */ |
506 | set_bit(HT_AGG_STATE_OPERATIONAL, &sta->ampdu_mlme.tid_tx[tid]->state); | 523 | set_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state); |
507 | ieee80211_agg_splice_finish(local, tid); | 524 | ieee80211_agg_splice_finish(local, tid); |
508 | 525 | ||
509 | spin_unlock_bh(&sta->lock); | 526 | spin_unlock_bh(&sta->lock); |
@@ -537,7 +554,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid) | |||
537 | } | 554 | } |
538 | 555 | ||
539 | mutex_lock(&sta->ampdu_mlme.mtx); | 556 | mutex_lock(&sta->ampdu_mlme.mtx); |
540 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 557 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
541 | 558 | ||
542 | if (WARN_ON(!tid_tx)) { | 559 | if (WARN_ON(!tid_tx)) { |
543 | #ifdef CONFIG_MAC80211_HT_DEBUG | 560 | #ifdef CONFIG_MAC80211_HT_DEBUG |
@@ -615,7 +632,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) | |||
615 | return -EINVAL; | 632 | return -EINVAL; |
616 | 633 | ||
617 | spin_lock_bh(&sta->lock); | 634 | spin_lock_bh(&sta->lock); |
618 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 635 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
619 | 636 | ||
620 | if (!tid_tx) { | 637 | if (!tid_tx) { |
621 | ret = -ENOENT; | 638 | ret = -ENOENT; |
@@ -671,7 +688,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) | |||
671 | 688 | ||
672 | mutex_lock(&sta->ampdu_mlme.mtx); | 689 | mutex_lock(&sta->ampdu_mlme.mtx); |
673 | spin_lock_bh(&sta->lock); | 690 | spin_lock_bh(&sta->lock); |
674 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 691 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
675 | 692 | ||
676 | if (!tid_tx || !test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { | 693 | if (!tid_tx || !test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { |
677 | #ifdef CONFIG_MAC80211_HT_DEBUG | 694 | #ifdef CONFIG_MAC80211_HT_DEBUG |
@@ -697,7 +714,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) | |||
697 | ieee80211_agg_splice_packets(local, tid_tx, tid); | 714 | ieee80211_agg_splice_packets(local, tid_tx, tid); |
698 | 715 | ||
699 | /* future packets must not find the tid_tx struct any more */ | 716 | /* future packets must not find the tid_tx struct any more */ |
700 | rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL); | 717 | ieee80211_assign_tid_tx(sta, tid, NULL); |
701 | 718 | ||
702 | ieee80211_agg_splice_finish(local, tid); | 719 | ieee80211_agg_splice_finish(local, tid); |
703 | 720 | ||
@@ -752,7 +769,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, | |||
752 | 769 | ||
753 | mutex_lock(&sta->ampdu_mlme.mtx); | 770 | mutex_lock(&sta->ampdu_mlme.mtx); |
754 | 771 | ||
755 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 772 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
756 | if (!tid_tx) | 773 | if (!tid_tx) |
757 | goto out; | 774 | goto out; |
758 | 775 | ||