diff options
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/agg-rx.c | 8 | ||||
-rw-r--r-- | net/mac80211/debugfs_sta.c | 29 | ||||
-rw-r--r-- | net/mac80211/rx.c | 17 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 29 |
4 files changed, 45 insertions, 38 deletions
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 720b7a84af59..f138b195d657 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c | |||
@@ -129,9 +129,7 @@ static void sta_rx_agg_reorder_timer_expired(unsigned long data) | |||
129 | timer_to_tid[0]); | 129 | timer_to_tid[0]); |
130 | 130 | ||
131 | rcu_read_lock(); | 131 | rcu_read_lock(); |
132 | spin_lock(&sta->lock); | ||
133 | ieee80211_release_reorder_timeout(sta, *ptid); | 132 | ieee80211_release_reorder_timeout(sta, *ptid); |
134 | spin_unlock(&sta->lock); | ||
135 | rcu_read_unlock(); | 133 | rcu_read_unlock(); |
136 | } | 134 | } |
137 | 135 | ||
@@ -256,7 +254,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | |||
256 | } | 254 | } |
257 | 255 | ||
258 | /* prepare A-MPDU MLME for Rx aggregation */ | 256 | /* prepare A-MPDU MLME for Rx aggregation */ |
259 | tid_agg_rx = kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC); | 257 | tid_agg_rx = kmalloc(sizeof(struct tid_ampdu_rx), GFP_KERNEL); |
260 | if (!tid_agg_rx) { | 258 | if (!tid_agg_rx) { |
261 | #ifdef CONFIG_MAC80211_HT_DEBUG | 259 | #ifdef CONFIG_MAC80211_HT_DEBUG |
262 | if (net_ratelimit()) | 260 | if (net_ratelimit()) |
@@ -280,9 +278,9 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | |||
280 | 278 | ||
281 | /* prepare reordering buffer */ | 279 | /* prepare reordering buffer */ |
282 | tid_agg_rx->reorder_buf = | 280 | tid_agg_rx->reorder_buf = |
283 | kcalloc(buf_size, sizeof(struct sk_buff *), GFP_ATOMIC); | 281 | kcalloc(buf_size, sizeof(struct sk_buff *), GFP_KERNEL); |
284 | tid_agg_rx->reorder_time = | 282 | tid_agg_rx->reorder_time = |
285 | kcalloc(buf_size, sizeof(unsigned long), GFP_ATOMIC); | 283 | kcalloc(buf_size, sizeof(unsigned long), GFP_KERNEL); |
286 | if (!tid_agg_rx->reorder_buf || !tid_agg_rx->reorder_time) { | 284 | if (!tid_agg_rx->reorder_buf || !tid_agg_rx->reorder_time) { |
287 | #ifdef CONFIG_MAC80211_HT_DEBUG | 285 | #ifdef CONFIG_MAC80211_HT_DEBUG |
288 | if (net_ratelimit()) | 286 | if (net_ratelimit()) |
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index f0fce37f4069..8bb5af85f469 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
@@ -112,34 +112,35 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, | |||
112 | char buf[71 + STA_TID_NUM * 40], *p = buf; | 112 | char buf[71 + STA_TID_NUM * 40], *p = buf; |
113 | int i; | 113 | int i; |
114 | struct sta_info *sta = file->private_data; | 114 | struct sta_info *sta = file->private_data; |
115 | struct tid_ampdu_rx *tid_rx; | ||
116 | struct tid_ampdu_tx *tid_tx; | ||
117 | |||
118 | rcu_read_lock(); | ||
115 | 119 | ||
116 | spin_lock_bh(&sta->lock); | ||
117 | p += scnprintf(p, sizeof(buf) + buf - p, "next dialog_token: %#02x\n", | 120 | p += scnprintf(p, sizeof(buf) + buf - p, "next dialog_token: %#02x\n", |
118 | sta->ampdu_mlme.dialog_token_allocator + 1); | 121 | sta->ampdu_mlme.dialog_token_allocator + 1); |
119 | p += scnprintf(p, sizeof(buf) + buf - p, | 122 | p += scnprintf(p, sizeof(buf) + buf - p, |
120 | "TID\t\tRX active\tDTKN\tSSN\t\tTX\tDTKN\tpending\n"); | 123 | "TID\t\tRX active\tDTKN\tSSN\t\tTX\tDTKN\tpending\n"); |
124 | |||
121 | for (i = 0; i < STA_TID_NUM; i++) { | 125 | for (i = 0; i < STA_TID_NUM; i++) { |
126 | tid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[i]); | ||
127 | tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[i]); | ||
128 | |||
122 | p += scnprintf(p, sizeof(buf) + buf - p, "%02d", i); | 129 | p += scnprintf(p, sizeof(buf) + buf - p, "%02d", i); |
123 | p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", | 130 | p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", !!tid_rx); |
124 | !!sta->ampdu_mlme.tid_rx[i]); | ||
125 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x", | 131 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x", |
126 | sta->ampdu_mlme.tid_rx[i] ? | 132 | tid_rx ? tid_rx->dialog_token : 0); |
127 | sta->ampdu_mlme.tid_rx[i]->dialog_token : 0); | ||
128 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x", | 133 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x", |
129 | sta->ampdu_mlme.tid_rx[i] ? | 134 | tid_rx ? tid_rx->ssn : 0); |
130 | sta->ampdu_mlme.tid_rx[i]->ssn : 0); | ||
131 | 135 | ||
132 | p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", | 136 | p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", !!tid_tx); |
133 | !!sta->ampdu_mlme.tid_tx[i]); | ||
134 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x", | 137 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x", |
135 | sta->ampdu_mlme.tid_tx[i] ? | 138 | tid_tx ? tid_tx->dialog_token : 0); |
136 | sta->ampdu_mlme.tid_tx[i]->dialog_token : 0); | ||
137 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%03d", | 139 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%03d", |
138 | sta->ampdu_mlme.tid_tx[i] ? | 140 | tid_tx ? skb_queue_len(&tid_tx->pending) : 0); |
139 | skb_queue_len(&sta->ampdu_mlme.tid_tx[i]->pending) : 0); | ||
140 | p += scnprintf(p, sizeof(buf) + buf - p, "\n"); | 141 | p += scnprintf(p, sizeof(buf) + buf - p, "\n"); |
141 | } | 142 | } |
142 | spin_unlock_bh(&sta->lock); | 143 | rcu_read_unlock(); |
143 | 144 | ||
144 | return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); | 145 | return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); |
145 | } | 146 | } |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index d2fcd22ab06d..fdeabb19943c 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -538,6 +538,8 @@ static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw, | |||
538 | { | 538 | { |
539 | struct sk_buff *skb = tid_agg_rx->reorder_buf[index]; | 539 | struct sk_buff *skb = tid_agg_rx->reorder_buf[index]; |
540 | 540 | ||
541 | lockdep_assert_held(&tid_agg_rx->reorder_lock); | ||
542 | |||
541 | if (!skb) | 543 | if (!skb) |
542 | goto no_frame; | 544 | goto no_frame; |
543 | 545 | ||
@@ -557,6 +559,8 @@ static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw, | |||
557 | { | 559 | { |
558 | int index; | 560 | int index; |
559 | 561 | ||
562 | lockdep_assert_held(&tid_agg_rx->reorder_lock); | ||
563 | |||
560 | while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) { | 564 | while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) { |
561 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % | 565 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % |
562 | tid_agg_rx->buf_size; | 566 | tid_agg_rx->buf_size; |
@@ -581,6 +585,8 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw, | |||
581 | { | 585 | { |
582 | int index, j; | 586 | int index, j; |
583 | 587 | ||
588 | lockdep_assert_held(&tid_agg_rx->reorder_lock); | ||
589 | |||
584 | /* release the buffer until next missing frame */ | 590 | /* release the buffer until next missing frame */ |
585 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % | 591 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % |
586 | tid_agg_rx->buf_size; | 592 | tid_agg_rx->buf_size; |
@@ -683,10 +689,11 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, | |||
683 | int index; | 689 | int index; |
684 | bool ret = true; | 690 | bool ret = true; |
685 | 691 | ||
692 | spin_lock(&tid_agg_rx->reorder_lock); | ||
693 | |||
686 | buf_size = tid_agg_rx->buf_size; | 694 | buf_size = tid_agg_rx->buf_size; |
687 | head_seq_num = tid_agg_rx->head_seq_num; | 695 | head_seq_num = tid_agg_rx->head_seq_num; |
688 | 696 | ||
689 | spin_lock(&tid_agg_rx->reorder_lock); | ||
690 | /* frame with out of date sequence number */ | 697 | /* frame with out of date sequence number */ |
691 | if (seq_less(mpdu_seq_num, head_seq_num)) { | 698 | if (seq_less(mpdu_seq_num, head_seq_num)) { |
692 | dev_kfree_skb(skb); | 699 | dev_kfree_skb(skb); |
@@ -1921,9 +1928,12 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames) | |||
1921 | mod_timer(&tid_agg_rx->session_timer, | 1928 | mod_timer(&tid_agg_rx->session_timer, |
1922 | TU_TO_EXP_TIME(tid_agg_rx->timeout)); | 1929 | TU_TO_EXP_TIME(tid_agg_rx->timeout)); |
1923 | 1930 | ||
1931 | spin_lock(&tid_agg_rx->reorder_lock); | ||
1924 | /* release stored frames up to start of BAR */ | 1932 | /* release stored frames up to start of BAR */ |
1925 | ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num, | 1933 | ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num, |
1926 | frames); | 1934 | frames); |
1935 | spin_unlock(&tid_agg_rx->reorder_lock); | ||
1936 | |||
1927 | kfree_skb(skb); | 1937 | kfree_skb(skb); |
1928 | return RX_QUEUED; | 1938 | return RX_QUEUED; |
1929 | } | 1939 | } |
@@ -2515,9 +2525,8 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx) | |||
2515 | } | 2525 | } |
2516 | 2526 | ||
2517 | /* | 2527 | /* |
2518 | * This function makes calls into the RX path. Therefore the | 2528 | * This function makes calls into the RX path, therefore |
2519 | * caller must hold the sta_info->lock and everything has to | 2529 | * it has to be invoked under RCU read lock. |
2520 | * be under rcu_read_lock protection as well. | ||
2521 | */ | 2530 | */ |
2522 | void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid) | 2531 | void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid) |
2523 | { | 2532 | { |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index b562d9b6a702..05f11302443b 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -81,13 +81,14 @@ enum ieee80211_sta_info_flags { | |||
81 | * @stop_initiator: initiator of a session stop | 81 | * @stop_initiator: initiator of a session stop |
82 | * @tx_stop: TX DelBA frame when stopping | 82 | * @tx_stop: TX DelBA frame when stopping |
83 | * | 83 | * |
84 | * This structure is protected by RCU and the per-station | 84 | * This structure's lifetime is managed by RCU, assignments to |
85 | * spinlock. Assignments to the array holding it must hold | 85 | * the array holding it must hold the aggregation mutex. |
86 | * the spinlock, only the TX path can access it under RCU | 86 | * |
87 | * lock-free if, and only if, the state has the flag | 87 | * The TX path can access it under RCU lock-free if, and |
88 | * %HT_AGG_STATE_OPERATIONAL set. Otherwise, the TX path | 88 | * only if, the state has the flag %HT_AGG_STATE_OPERATIONAL |
89 | * must also acquire the spinlock and re-check the state, | 89 | * set. Otherwise, the TX path must also acquire the spinlock |
90 | * see comments in the tx code touching it. | 90 | * and re-check the state, see comments in the tx code |
91 | * touching it. | ||
91 | */ | 92 | */ |
92 | struct tid_ampdu_tx { | 93 | struct tid_ampdu_tx { |
93 | struct rcu_head rcu_head; | 94 | struct rcu_head rcu_head; |
@@ -115,15 +116,13 @@ struct tid_ampdu_tx { | |||
115 | * @rcu_head: RCU head used for freeing this struct | 116 | * @rcu_head: RCU head used for freeing this struct |
116 | * @reorder_lock: serializes access to reorder buffer, see below. | 117 | * @reorder_lock: serializes access to reorder buffer, see below. |
117 | * | 118 | * |
118 | * This structure is protected by RCU and the per-station | 119 | * This structure's lifetime is managed by RCU, assignments to |
119 | * spinlock. Assignments to the array holding it must hold | 120 | * the array holding it must hold the aggregation mutex. |
120 | * the spinlock. | ||
121 | * | 121 | * |
122 | * The @reorder_lock is used to protect the variables and | 122 | * The @reorder_lock is used to protect the members of this |
123 | * arrays such as @reorder_buf, @reorder_time, @head_seq_num, | 123 | * struct, except for @timeout, @buf_size and @dialog_token, |
124 | * @stored_mpdu_num and @reorder_time from being corrupted by | 124 | * which are constant across the lifetime of the struct (the |
125 | * concurrent access of the RX path and the expired frame | 125 | * dialog token being used only for debugging). |
126 | * release timer. | ||
127 | */ | 126 | */ |
128 | struct tid_ampdu_rx { | 127 | struct tid_ampdu_rx { |
129 | struct rcu_head rcu_head; | 128 | struct rcu_head rcu_head; |