aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/mac80211/agg-rx.c70
-rw-r--r--net/mac80211/debugfs_sta.c6
-rw-r--r--net/mac80211/rx.c34
-rw-r--r--net/mac80211/sta_info.h14
4 files changed, 61 insertions, 63 deletions
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c
index 6bb9a9a94960..bbf36d980232 100644
--- a/net/mac80211/agg-rx.c
+++ b/net/mac80211/agg-rx.c
@@ -19,25 +19,36 @@
19#include "ieee80211_i.h" 19#include "ieee80211_i.h"
20#include "driver-ops.h" 20#include "driver-ops.h"
21 21
22static void ieee80211_free_tid_rx(struct rcu_head *h)
23{
24 struct tid_ampdu_rx *tid_rx =
25 container_of(h, struct tid_ampdu_rx, rcu_head);
26 int i;
27
28 for (i = 0; i < tid_rx->buf_size; i++)
29 dev_kfree_skb(tid_rx->reorder_buf[i]);
30 kfree(tid_rx->reorder_buf);
31 kfree(tid_rx->reorder_time);
32 kfree(tid_rx);
33}
34
22static void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, 35static void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
23 u16 initiator, u16 reason, 36 u16 initiator, u16 reason,
24 bool from_timer) 37 bool from_timer)
25{ 38{
26 struct ieee80211_local *local = sta->local; 39 struct ieee80211_local *local = sta->local;
27 struct tid_ampdu_rx *tid_rx; 40 struct tid_ampdu_rx *tid_rx;
28 int i;
29 41
30 spin_lock_bh(&sta->lock); 42 spin_lock_bh(&sta->lock);
31 43
32 /* check if TID is in operational state */ 44 tid_rx = sta->ampdu_mlme.tid_rx[tid];
33 if (!sta->ampdu_mlme.tid_active_rx[tid]) { 45
46 if (!tid_rx) {
34 spin_unlock_bh(&sta->lock); 47 spin_unlock_bh(&sta->lock);
35 return; 48 return;
36 } 49 }
37 50
38 sta->ampdu_mlme.tid_active_rx[tid] = false; 51 rcu_assign_pointer(sta->ampdu_mlme.tid_rx[tid], NULL);
39
40 tid_rx = sta->ampdu_mlme.tid_rx[tid];
41 52
42#ifdef CONFIG_MAC80211_HT_DEBUG 53#ifdef CONFIG_MAC80211_HT_DEBUG
43 printk(KERN_DEBUG "Rx BA session stop requested for %pM tid %u\n", 54 printk(KERN_DEBUG "Rx BA session stop requested for %pM tid %u\n",
@@ -54,26 +65,12 @@ static void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
54 ieee80211_send_delba(sta->sdata, sta->sta.addr, 65 ieee80211_send_delba(sta->sdata, sta->sta.addr,
55 tid, 0, reason); 66 tid, 0, reason);
56 67
57 /* free the reordering buffer */
58 for (i = 0; i < tid_rx->buf_size; i++) {
59 if (tid_rx->reorder_buf[i]) {
60 /* release the reordered frames */
61 dev_kfree_skb(tid_rx->reorder_buf[i]);
62 tid_rx->stored_mpdu_num--;
63 tid_rx->reorder_buf[i] = NULL;
64 }
65 }
66
67 /* free resources */
68 kfree(tid_rx->reorder_buf);
69 kfree(tid_rx->reorder_time);
70 sta->ampdu_mlme.tid_rx[tid] = NULL;
71
72 spin_unlock_bh(&sta->lock); 68 spin_unlock_bh(&sta->lock);
73 69
74 if (!from_timer) 70 if (!from_timer)
75 del_timer_sync(&tid_rx->session_timer); 71 del_timer_sync(&tid_rx->session_timer);
76 kfree(tid_rx); 72
73 call_rcu(&tid_rx->rcu_head, ieee80211_free_tid_rx);
77} 74}
78 75
79void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, 76void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
@@ -214,7 +211,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
214 /* examine state machine */ 211 /* examine state machine */
215 spin_lock_bh(&sta->lock); 212 spin_lock_bh(&sta->lock);
216 213
217 if (sta->ampdu_mlme.tid_active_rx[tid]) { 214 if (sta->ampdu_mlme.tid_rx[tid]) {
218#ifdef CONFIG_MAC80211_HT_DEBUG 215#ifdef CONFIG_MAC80211_HT_DEBUG
219 if (net_ratelimit()) 216 if (net_ratelimit())
220 printk(KERN_DEBUG "unexpected AddBA Req from " 217 printk(KERN_DEBUG "unexpected AddBA Req from "
@@ -225,9 +222,8 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
225 } 222 }
226 223
227 /* prepare A-MPDU MLME for Rx aggregation */ 224 /* prepare A-MPDU MLME for Rx aggregation */
228 sta->ampdu_mlme.tid_rx[tid] = 225 tid_agg_rx = kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC);
229 kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC); 226 if (!tid_agg_rx) {
230 if (!sta->ampdu_mlme.tid_rx[tid]) {
231#ifdef CONFIG_MAC80211_HT_DEBUG 227#ifdef CONFIG_MAC80211_HT_DEBUG
232 if (net_ratelimit()) 228 if (net_ratelimit())
233 printk(KERN_ERR "allocate rx mlme to tid %d failed\n", 229 printk(KERN_ERR "allocate rx mlme to tid %d failed\n",
@@ -235,14 +231,11 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
235#endif 231#endif
236 goto end; 232 goto end;
237 } 233 }
238 /* rx timer */
239 sta->ampdu_mlme.tid_rx[tid]->session_timer.function =
240 sta_rx_agg_session_timer_expired;
241 sta->ampdu_mlme.tid_rx[tid]->session_timer.data =
242 (unsigned long)&sta->timer_to_tid[tid];
243 init_timer(&sta->ampdu_mlme.tid_rx[tid]->session_timer);
244 234
245 tid_agg_rx = sta->ampdu_mlme.tid_rx[tid]; 235 /* rx timer */
236 tid_agg_rx->session_timer.function = sta_rx_agg_session_timer_expired;
237 tid_agg_rx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid];
238 init_timer(&tid_agg_rx->session_timer);
246 239
247 /* prepare reordering buffer */ 240 /* prepare reordering buffer */
248 tid_agg_rx->reorder_buf = 241 tid_agg_rx->reorder_buf =
@@ -257,8 +250,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
257#endif 250#endif
258 kfree(tid_agg_rx->reorder_buf); 251 kfree(tid_agg_rx->reorder_buf);
259 kfree(tid_agg_rx->reorder_time); 252 kfree(tid_agg_rx->reorder_time);
260 kfree(sta->ampdu_mlme.tid_rx[tid]); 253 kfree(tid_agg_rx);
261 sta->ampdu_mlme.tid_rx[tid] = NULL;
262 goto end; 254 goto end;
263 } 255 }
264 256
@@ -270,13 +262,12 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
270 262
271 if (ret) { 263 if (ret) {
272 kfree(tid_agg_rx->reorder_buf); 264 kfree(tid_agg_rx->reorder_buf);
265 kfree(tid_agg_rx->reorder_time);
273 kfree(tid_agg_rx); 266 kfree(tid_agg_rx);
274 sta->ampdu_mlme.tid_rx[tid] = NULL;
275 goto end; 267 goto end;
276 } 268 }
277 269
278 /* change state and send addba resp */ 270 /* update data */
279 sta->ampdu_mlme.tid_active_rx[tid] = true;
280 tid_agg_rx->dialog_token = dialog_token; 271 tid_agg_rx->dialog_token = dialog_token;
281 tid_agg_rx->ssn = start_seq_num; 272 tid_agg_rx->ssn = start_seq_num;
282 tid_agg_rx->head_seq_num = start_seq_num; 273 tid_agg_rx->head_seq_num = start_seq_num;
@@ -284,6 +275,9 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
284 tid_agg_rx->timeout = timeout; 275 tid_agg_rx->timeout = timeout;
285 tid_agg_rx->stored_mpdu_num = 0; 276 tid_agg_rx->stored_mpdu_num = 0;
286 status = WLAN_STATUS_SUCCESS; 277 status = WLAN_STATUS_SUCCESS;
278
279 /* activate it for RX */
280 rcu_assign_pointer(sta->ampdu_mlme.tid_rx[tid], tid_agg_rx);
287end: 281end:
288 spin_unlock_bh(&sta->lock); 282 spin_unlock_bh(&sta->lock);
289 283
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index 576e024715e3..95c1ea47ad35 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -125,12 +125,12 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
125 for (i = 0; i < STA_TID_NUM; i++) { 125 for (i = 0; i < STA_TID_NUM; i++) {
126 p += scnprintf(p, sizeof(buf) + buf - p, "%02d", i); 126 p += scnprintf(p, sizeof(buf) + buf - p, "%02d", i);
127 p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", 127 p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x",
128 sta->ampdu_mlme.tid_active_rx[i]); 128 !!sta->ampdu_mlme.tid_rx[i]);
129 p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x", 129 p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x",
130 sta->ampdu_mlme.tid_active_rx[i] ? 130 sta->ampdu_mlme.tid_rx[i] ?
131 sta->ampdu_mlme.tid_rx[i]->dialog_token : 0); 131 sta->ampdu_mlme.tid_rx[i]->dialog_token : 0);
132 p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x", 132 p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x",
133 sta->ampdu_mlme.tid_active_rx[i] ? 133 sta->ampdu_mlme.tid_rx[i] ?
134 sta->ampdu_mlme.tid_rx[i]->ssn : 0); 134 sta->ampdu_mlme.tid_rx[i]->ssn : 0);
135 135
136 p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", 136 p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x",
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 84f11733b9fe..ee01daccacbb 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -719,16 +719,13 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx,
719 719
720 tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; 720 tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
721 721
722 spin_lock(&sta->lock); 722 tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
723 723 if (!tid_agg_rx)
724 if (!sta->ampdu_mlme.tid_active_rx[tid]) 724 goto dont_reorder;
725 goto dont_reorder_unlock;
726
727 tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
728 725
729 /* qos null data frames are excluded */ 726 /* qos null data frames are excluded */
730 if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC))) 727 if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
731 goto dont_reorder_unlock; 728 goto dont_reorder;
732 729
733 /* new, potentially un-ordered, ampdu frame - process it */ 730 /* new, potentially un-ordered, ampdu frame - process it */
734 731
@@ -740,20 +737,22 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx,
740 /* if this mpdu is fragmented - terminate rx aggregation session */ 737 /* if this mpdu is fragmented - terminate rx aggregation session */
741 sc = le16_to_cpu(hdr->seq_ctrl); 738 sc = le16_to_cpu(hdr->seq_ctrl);
742 if (sc & IEEE80211_SCTL_FRAG) { 739 if (sc & IEEE80211_SCTL_FRAG) {
743 spin_unlock(&sta->lock);
744 skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME; 740 skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME;
745 skb_queue_tail(&rx->sdata->skb_queue, skb); 741 skb_queue_tail(&rx->sdata->skb_queue, skb);
746 ieee80211_queue_work(&local->hw, &rx->sdata->work); 742 ieee80211_queue_work(&local->hw, &rx->sdata->work);
747 return; 743 return;
748 } 744 }
749 745
750 if (ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, frames)) { 746 /*
751 spin_unlock(&sta->lock); 747 * No locking needed -- we will only ever process one
748 * RX packet at a time, and thus own tid_agg_rx. All
749 * other code manipulating it needs to (and does) make
750 * sure that we cannot get to it any more before doing
751 * anything with it.
752 */
753 if (ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, frames))
752 return; 754 return;
753 }
754 755
755 dont_reorder_unlock:
756 spin_unlock(&sta->lock);
757 dont_reorder: 756 dont_reorder:
758 __skb_queue_tail(frames, skb); 757 __skb_queue_tail(frames, skb);
759} 758}
@@ -1830,13 +1829,11 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
1830 &bar_data, sizeof(bar_data))) 1829 &bar_data, sizeof(bar_data)))
1831 return RX_DROP_MONITOR; 1830 return RX_DROP_MONITOR;
1832 1831
1833 spin_lock(&rx->sta->lock);
1834 tid = le16_to_cpu(bar_data.control) >> 12; 1832 tid = le16_to_cpu(bar_data.control) >> 12;
1835 if (!rx->sta->ampdu_mlme.tid_active_rx[tid]) { 1833
1836 spin_unlock(&rx->sta->lock); 1834 tid_agg_rx = rcu_dereference(rx->sta->ampdu_mlme.tid_rx[tid]);
1835 if (!tid_agg_rx)
1837 return RX_DROP_MONITOR; 1836 return RX_DROP_MONITOR;
1838 }
1839 tid_agg_rx = rx->sta->ampdu_mlme.tid_rx[tid];
1840 1837
1841 start_seq_num = le16_to_cpu(bar_data.start_seq_num) >> 4; 1838 start_seq_num = le16_to_cpu(bar_data.start_seq_num) >> 4;
1842 1839
@@ -1849,7 +1846,6 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
1849 ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num, 1846 ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num,
1850 frames); 1847 frames);
1851 kfree_skb(skb); 1848 kfree_skb(skb);
1852 spin_unlock(&rx->sta->lock);
1853 return RX_QUEUED; 1849 return RX_QUEUED;
1854 } 1850 }
1855 1851
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 786bbd3103b1..16864a6045b4 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -102,8 +102,18 @@ struct tid_ampdu_tx {
102 * @buf_size: buffer size for incoming A-MPDUs 102 * @buf_size: buffer size for incoming A-MPDUs
103 * @timeout: reset timer value (in TUs). 103 * @timeout: reset timer value (in TUs).
104 * @dialog_token: dialog token for aggregation session 104 * @dialog_token: dialog token for aggregation session
105 * @rcu_head: RCU head used for freeing this struct
106 *
107 * This structure is protected by RCU and the per-station
108 * spinlock. Assignments to the array holding it must hold
109 * the spinlock, only the RX path can access it under RCU
110 * lock-free. The RX path, since it is single-threaded,
111 * can even modify the structure without locking since the
112 * only other modifications to it are done when the struct
113 * can not yet or no longer be found by the RX path.
105 */ 114 */
106struct tid_ampdu_rx { 115struct tid_ampdu_rx {
116 struct rcu_head rcu_head;
107 struct sk_buff **reorder_buf; 117 struct sk_buff **reorder_buf;
108 unsigned long *reorder_time; 118 unsigned long *reorder_time;
109 struct timer_list session_timer; 119 struct timer_list session_timer;
@@ -118,8 +128,7 @@ struct tid_ampdu_rx {
118/** 128/**
119 * struct sta_ampdu_mlme - STA aggregation information. 129 * struct sta_ampdu_mlme - STA aggregation information.
120 * 130 *
121 * @tid_active_rx: TID's state in Rx session state machine. 131 * @tid_rx: aggregation info for Rx per TID -- RCU protected
122 * @tid_rx: aggregation info for Rx per TID
123 * @tid_state_tx: TID's state in Tx session state machine. 132 * @tid_state_tx: TID's state in Tx session state machine.
124 * @tid_tx: aggregation info for Tx per TID 133 * @tid_tx: aggregation info for Tx per TID
125 * @addba_req_num: number of times addBA request has been sent. 134 * @addba_req_num: number of times addBA request has been sent.
@@ -127,7 +136,6 @@ struct tid_ampdu_rx {
127 */ 136 */
128struct sta_ampdu_mlme { 137struct sta_ampdu_mlme {
129 /* rx */ 138 /* rx */
130 bool tid_active_rx[STA_TID_NUM];
131 struct tid_ampdu_rx *tid_rx[STA_TID_NUM]; 139 struct tid_ampdu_rx *tid_rx[STA_TID_NUM];
132 /* tx */ 140 /* tx */
133 u8 tid_state_tx[STA_TID_NUM]; 141 u8 tid_state_tx[STA_TID_NUM];