aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/agg-rx.c22
-rw-r--r--net/mac80211/ieee80211_i.h1
-rw-r--r--net/mac80211/rx.c70
-rw-r--r--net/mac80211/sta_info.h16
4 files changed, 97 insertions, 12 deletions
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c
index 965b272499fd..58eab9e8e4ee 100644
--- a/net/mac80211/agg-rx.c
+++ b/net/mac80211/agg-rx.c
@@ -86,6 +86,7 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
86 tid, 0, reason); 86 tid, 0, reason);
87 87
88 del_timer_sync(&tid_rx->session_timer); 88 del_timer_sync(&tid_rx->session_timer);
89 del_timer_sync(&tid_rx->reorder_timer);
89 90
90 call_rcu(&tid_rx->rcu_head, ieee80211_free_tid_rx); 91 call_rcu(&tid_rx->rcu_head, ieee80211_free_tid_rx);
91} 92}
@@ -120,6 +121,20 @@ static void sta_rx_agg_session_timer_expired(unsigned long data)
120 ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work); 121 ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work);
121} 122}
122 123
124static void sta_rx_agg_reorder_timer_expired(unsigned long data)
125{
126 u8 *ptid = (u8 *)data;
127 u8 *timer_to_id = ptid - *ptid;
128 struct sta_info *sta = container_of(timer_to_id, struct sta_info,
129 timer_to_tid[0]);
130
131 rcu_read_lock();
132 spin_lock(&sta->lock);
133 ieee80211_release_reorder_timeout(sta, *ptid);
134 spin_unlock(&sta->lock);
135 rcu_read_unlock();
136}
137
123static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid, 138static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid,
124 u8 dialog_token, u16 status, u16 policy, 139 u8 dialog_token, u16 status, u16 policy,
125 u16 buf_size, u16 timeout) 140 u16 buf_size, u16 timeout)
@@ -251,11 +266,18 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
251 goto end; 266 goto end;
252 } 267 }
253 268
269 spin_lock_init(&tid_agg_rx->reorder_lock);
270
254 /* rx timer */ 271 /* rx timer */
255 tid_agg_rx->session_timer.function = sta_rx_agg_session_timer_expired; 272 tid_agg_rx->session_timer.function = sta_rx_agg_session_timer_expired;
256 tid_agg_rx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid]; 273 tid_agg_rx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid];
257 init_timer(&tid_agg_rx->session_timer); 274 init_timer(&tid_agg_rx->session_timer);
258 275
276 /* rx reorder timer */
277 tid_agg_rx->reorder_timer.function = sta_rx_agg_reorder_timer_expired;
278 tid_agg_rx->reorder_timer.data = (unsigned long)&sta->timer_to_tid[tid];
279 init_timer(&tid_agg_rx->reorder_timer);
280
259 /* prepare reordering buffer */ 281 /* prepare reordering buffer */
260 tid_agg_rx->reorder_buf = 282 tid_agg_rx->reorder_buf =
261 kcalloc(buf_size, sizeof(struct sk_buff *), GFP_ATOMIC); 283 kcalloc(buf_size, sizeof(struct sk_buff *), GFP_ATOMIC);
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index fb4363e148f2..b44e03a02da9 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1136,6 +1136,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid);
1136void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid); 1136void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid);
1137void ieee80211_ba_session_work(struct work_struct *work); 1137void ieee80211_ba_session_work(struct work_struct *work);
1138void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid); 1138void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid);
1139void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid);
1139 1140
1140/* Spectrum management */ 1141/* Spectrum management */
1141void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, 1142void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index d5b91b6eb120..f24a0a1cff1a 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -572,6 +572,8 @@ static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw,
572 * frames that have not yet been received are assumed to be lost and the skb 572 * frames that have not yet been received are assumed to be lost and the skb
573 * can be released for processing. This may also release other skb's from the 573 * can be released for processing. This may also release other skb's from the
574 * reorder buffer if there are no additional gaps between the frames. 574 * reorder buffer if there are no additional gaps between the frames.
575 *
576 * Callers must hold tid_agg_rx->reorder_lock.
575 */ 577 */
576#define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10) 578#define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10)
577 579
@@ -579,7 +581,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw,
579 struct tid_ampdu_rx *tid_agg_rx, 581 struct tid_ampdu_rx *tid_agg_rx,
580 struct sk_buff_head *frames) 582 struct sk_buff_head *frames)
581{ 583{
582 int index; 584 int index, j;
583 585
584 /* release the buffer until next missing frame */ 586 /* release the buffer until next missing frame */
585 index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % 587 index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
@@ -590,7 +592,6 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw,
590 * No buffers ready to be released, but check whether any 592 * No buffers ready to be released, but check whether any
591 * frames in the reorder buffer have timed out. 593 * frames in the reorder buffer have timed out.
592 */ 594 */
593 int j;
594 int skipped = 1; 595 int skipped = 1;
595 for (j = (index + 1) % tid_agg_rx->buf_size; j != index; 596 for (j = (index + 1) % tid_agg_rx->buf_size; j != index;
596 j = (j + 1) % tid_agg_rx->buf_size) { 597 j = (j + 1) % tid_agg_rx->buf_size) {
@@ -600,7 +601,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw,
600 } 601 }
601 if (!time_after(jiffies, tid_agg_rx->reorder_time[j] + 602 if (!time_after(jiffies, tid_agg_rx->reorder_time[j] +
602 HT_RX_REORDER_BUF_TIMEOUT)) 603 HT_RX_REORDER_BUF_TIMEOUT))
603 break; 604 goto set_release_timer;
604 605
605#ifdef CONFIG_MAC80211_HT_DEBUG 606#ifdef CONFIG_MAC80211_HT_DEBUG
606 if (net_ratelimit()) 607 if (net_ratelimit())
@@ -624,6 +625,25 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw,
624 index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % 625 index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
625 tid_agg_rx->buf_size; 626 tid_agg_rx->buf_size;
626 } 627 }
628
629 if (tid_agg_rx->stored_mpdu_num) {
630 j = index = seq_sub(tid_agg_rx->head_seq_num,
631 tid_agg_rx->ssn) % tid_agg_rx->buf_size;
632
633 for (; j != (index - 1) % tid_agg_rx->buf_size;
634 j = (j + 1) % tid_agg_rx->buf_size) {
635 if (tid_agg_rx->reorder_buf[j])
636 break;
637 }
638
639 set_release_timer:
640
641 mod_timer(&tid_agg_rx->reorder_timer,
642 tid_agg_rx->reorder_time[j] +
643 HT_RX_REORDER_BUF_TIMEOUT);
644 } else {
645 del_timer(&tid_agg_rx->reorder_timer);
646 }
627} 647}
628 648
629/* 649/*
@@ -641,14 +661,16 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
641 u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4; 661 u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;
642 u16 head_seq_num, buf_size; 662 u16 head_seq_num, buf_size;
643 int index; 663 int index;
664 bool ret = true;
644 665
645 buf_size = tid_agg_rx->buf_size; 666 buf_size = tid_agg_rx->buf_size;
646 head_seq_num = tid_agg_rx->head_seq_num; 667 head_seq_num = tid_agg_rx->head_seq_num;
647 668
669 spin_lock(&tid_agg_rx->reorder_lock);
648 /* frame with out of date sequence number */ 670 /* frame with out of date sequence number */
649 if (seq_less(mpdu_seq_num, head_seq_num)) { 671 if (seq_less(mpdu_seq_num, head_seq_num)) {
650 dev_kfree_skb(skb); 672 dev_kfree_skb(skb);
651 return true; 673 goto out;
652 } 674 }
653 675
654 /* 676 /*
@@ -669,7 +691,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
669 /* check if we already stored this frame */ 691 /* check if we already stored this frame */
670 if (tid_agg_rx->reorder_buf[index]) { 692 if (tid_agg_rx->reorder_buf[index]) {
671 dev_kfree_skb(skb); 693 dev_kfree_skb(skb);
672 return true; 694 goto out;
673 } 695 }
674 696
675 /* 697 /*
@@ -679,7 +701,8 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
679 if (mpdu_seq_num == tid_agg_rx->head_seq_num && 701 if (mpdu_seq_num == tid_agg_rx->head_seq_num &&
680 tid_agg_rx->stored_mpdu_num == 0) { 702 tid_agg_rx->stored_mpdu_num == 0) {
681 tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); 703 tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
682 return false; 704 ret = false;
705 goto out;
683 } 706 }
684 707
685 /* put the frame in the reordering buffer */ 708 /* put the frame in the reordering buffer */
@@ -688,7 +711,9 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
688 tid_agg_rx->stored_mpdu_num++; 711 tid_agg_rx->stored_mpdu_num++;
689 ieee80211_sta_reorder_release(hw, tid_agg_rx, frames); 712 ieee80211_sta_reorder_release(hw, tid_agg_rx, frames);
690 713
691 return true; 714 out:
715 spin_unlock(&tid_agg_rx->reorder_lock);
716 return ret;
692} 717}
693 718
694/* 719/*
@@ -2387,6 +2412,37 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
2387#undef CALL_RXH 2412#undef CALL_RXH
2388} 2413}
2389 2414
2415/*
2416 * This function makes calls into the RX path. Therefore the
2417 * caller must hold the sta_info->lock and everything has to
2418 * be under rcu_read_lock protection as well.
2419 */
2420void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
2421{
2422 struct sk_buff_head frames;
2423 struct ieee80211_rx_data rx = { };
2424
2425 __skb_queue_head_init(&frames);
2426
2427 /* construct rx struct */
2428 rx.sta = sta;
2429 rx.sdata = sta->sdata;
2430 rx.local = sta->local;
2431 rx.queue = tid;
2432 rx.flags |= IEEE80211_RX_RA_MATCH;
2433
2434 if (unlikely(test_bit(SCAN_HW_SCANNING, &sta->local->scanning) ||
2435 test_bit(SCAN_OFF_CHANNEL, &sta->local->scanning)))
2436 rx.flags |= IEEE80211_RX_IN_SCAN;
2437
2438 spin_lock(&sta->ampdu_mlme.tid_rx[tid]->reorder_lock);
2439 ieee80211_sta_reorder_release(&sta->local->hw,
2440 sta->ampdu_mlme.tid_rx[tid], &frames);
2441 spin_unlock(&sta->ampdu_mlme.tid_rx[tid]->reorder_lock);
2442
2443 ieee80211_rx_handlers(&rx, &frames);
2444}
2445
2390/* main receive path */ 2446/* main receive path */
2391 2447
2392static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, 2448static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 54262e72376d..810c5ce98316 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -103,6 +103,7 @@ struct tid_ampdu_tx {
103 * @reorder_buf: buffer to reorder incoming aggregated MPDUs 103 * @reorder_buf: buffer to reorder incoming aggregated MPDUs
104 * @reorder_time: jiffies when skb was added 104 * @reorder_time: jiffies when skb was added
105 * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value) 105 * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value)
106 * @reorder_timer: releases expired frames from the reorder buffer.
106 * @head_seq_num: head sequence number in reordering buffer. 107 * @head_seq_num: head sequence number in reordering buffer.
107 * @stored_mpdu_num: number of MPDUs in reordering buffer 108 * @stored_mpdu_num: number of MPDUs in reordering buffer
108 * @ssn: Starting Sequence Number expected to be aggregated. 109 * @ssn: Starting Sequence Number expected to be aggregated.
@@ -110,20 +111,25 @@ struct tid_ampdu_tx {
110 * @timeout: reset timer value (in TUs). 111 * @timeout: reset timer value (in TUs).
111 * @dialog_token: dialog token for aggregation session 112 * @dialog_token: dialog token for aggregation session
112 * @rcu_head: RCU head used for freeing this struct 113 * @rcu_head: RCU head used for freeing this struct
114 * @reorder_lock: serializes access to reorder buffer, see below.
113 * 115 *
114 * This structure is protected by RCU and the per-station 116 * This structure is protected by RCU and the per-station
115 * spinlock. Assignments to the array holding it must hold 117 * spinlock. Assignments to the array holding it must hold
116 * the spinlock, only the RX path can access it under RCU 118 * the spinlock.
117 * lock-free. The RX path, since it is single-threaded, 119 *
118 * can even modify the structure without locking since the 120 * The @reorder_lock is used to protect the variables and
119 * only other modifications to it are done when the struct 121 * arrays such as @reorder_buf, @reorder_time, @head_seq_num,
120 * can not yet or no longer be found by the RX path. 122 * @stored_mpdu_num and @reorder_time from being corrupted by
123 * concurrent access of the RX path and the expired frame
124 * release timer.
121 */ 125 */
122struct tid_ampdu_rx { 126struct tid_ampdu_rx {
123 struct rcu_head rcu_head; 127 struct rcu_head rcu_head;
128 spinlock_t reorder_lock;
124 struct sk_buff **reorder_buf; 129 struct sk_buff **reorder_buf;
125 unsigned long *reorder_time; 130 unsigned long *reorder_time;
126 struct timer_list session_timer; 131 struct timer_list session_timer;
132 struct timer_list reorder_timer;
127 u16 head_seq_num; 133 u16 head_seq_num;
128 u16 stored_mpdu_num; 134 u16 stored_mpdu_num;
129 u16 ssn; 135 u16 ssn;