diff options
-rw-r--r-- | net/mac80211/agg-rx.c | 70 | ||||
-rw-r--r-- | net/mac80211/debugfs_sta.c | 6 | ||||
-rw-r--r-- | net/mac80211/rx.c | 34 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 14 |
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 | ||
22 | static 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 | |||
22 | static void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, | 35 | static 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 | ||
79 | void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, | 76 | void __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); | ||
287 | end: | 281 | end: |
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 | */ |
106 | struct tid_ampdu_rx { | 115 | struct 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 | */ |
128 | struct sta_ampdu_mlme { | 137 | struct 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]; |