diff options
-rw-r--r-- | include/linux/ieee80211.h | 1 | ||||
-rw-r--r-- | net/mac80211/agg-rx.c | 48 | ||||
-rw-r--r-- | net/mac80211/debugfs_sta.c | 10 | ||||
-rw-r--r-- | net/mac80211/rx.c | 5 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 58 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 6 |
6 files changed, 40 insertions, 88 deletions
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 19984958ab7b..e9e03b02cb08 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h | |||
@@ -1324,7 +1324,6 @@ enum ieee80211_back_actioncode { | |||
1324 | enum ieee80211_back_parties { | 1324 | enum ieee80211_back_parties { |
1325 | WLAN_BACK_RECIPIENT = 0, | 1325 | WLAN_BACK_RECIPIENT = 0, |
1326 | WLAN_BACK_INITIATOR = 1, | 1326 | WLAN_BACK_INITIATOR = 1, |
1327 | WLAN_BACK_TIMER = 2, | ||
1328 | }; | 1327 | }; |
1329 | 1328 | ||
1330 | /* SA Query action */ | 1329 | /* SA Query action */ |
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 7d87f446f030..53233ab50f65 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c | |||
@@ -22,19 +22,20 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, | |||
22 | u16 initiator, u16 reason) | 22 | u16 initiator, u16 reason) |
23 | { | 23 | { |
24 | struct ieee80211_local *local = sta->local; | 24 | struct ieee80211_local *local = sta->local; |
25 | struct tid_ampdu_rx *tid_rx; | ||
25 | int i; | 26 | int i; |
26 | 27 | ||
27 | /* check if TID is in operational state */ | ||
28 | spin_lock_bh(&sta->lock); | 28 | spin_lock_bh(&sta->lock); |
29 | if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL) { | 29 | |
30 | /* check if TID is in operational state */ | ||
31 | if (!sta->ampdu_mlme.tid_active_rx[tid]) { | ||
30 | spin_unlock_bh(&sta->lock); | 32 | spin_unlock_bh(&sta->lock); |
31 | return; | 33 | return; |
32 | } | 34 | } |
33 | 35 | ||
34 | sta->ampdu_mlme.tid_state_rx[tid] = | 36 | sta->ampdu_mlme.tid_active_rx[tid] = false; |
35 | HT_AGG_STATE_REQ_STOP_BA_MSK | | 37 | |
36 | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); | 38 | tid_rx = sta->ampdu_mlme.tid_rx[tid]; |
37 | spin_unlock_bh(&sta->lock); | ||
38 | 39 | ||
39 | #ifdef CONFIG_MAC80211_HT_DEBUG | 40 | #ifdef CONFIG_MAC80211_HT_DEBUG |
40 | printk(KERN_DEBUG "Rx BA session stop requested for %pM tid %u\n", | 41 | printk(KERN_DEBUG "Rx BA session stop requested for %pM tid %u\n", |
@@ -46,37 +47,30 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, | |||
46 | printk(KERN_DEBUG "HW problem - can not stop rx " | 47 | printk(KERN_DEBUG "HW problem - can not stop rx " |
47 | "aggregation for tid %d\n", tid); | 48 | "aggregation for tid %d\n", tid); |
48 | 49 | ||
49 | /* shutdown timer has not expired */ | ||
50 | if (initiator != WLAN_BACK_TIMER) | ||
51 | del_timer_sync(&sta->ampdu_mlme.tid_rx[tid]->session_timer); | ||
52 | |||
53 | /* check if this is a self generated aggregation halt */ | 50 | /* check if this is a self generated aggregation halt */ |
54 | if (initiator == WLAN_BACK_RECIPIENT || initiator == WLAN_BACK_TIMER) | 51 | if (initiator == WLAN_BACK_RECIPIENT) |
55 | ieee80211_send_delba(sta->sdata, sta->sta.addr, | 52 | ieee80211_send_delba(sta->sdata, sta->sta.addr, |
56 | tid, 0, reason); | 53 | tid, 0, reason); |
57 | 54 | ||
58 | /* free the reordering buffer */ | 55 | /* free the reordering buffer */ |
59 | for (i = 0; i < sta->ampdu_mlme.tid_rx[tid]->buf_size; i++) { | 56 | for (i = 0; i < tid_rx->buf_size; i++) { |
60 | if (sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]) { | 57 | if (tid_rx->reorder_buf[i]) { |
61 | /* release the reordered frames */ | 58 | /* release the reordered frames */ |
62 | dev_kfree_skb(sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]); | 59 | dev_kfree_skb(tid_rx->reorder_buf[i]); |
63 | sta->ampdu_mlme.tid_rx[tid]->stored_mpdu_num--; | 60 | tid_rx->stored_mpdu_num--; |
64 | sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i] = NULL; | 61 | tid_rx->reorder_buf[i] = NULL; |
65 | } | 62 | } |
66 | } | 63 | } |
67 | 64 | ||
68 | spin_lock_bh(&sta->lock); | ||
69 | /* free resources */ | 65 | /* free resources */ |
70 | kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_buf); | 66 | kfree(tid_rx->reorder_buf); |
71 | kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_time); | 67 | kfree(tid_rx->reorder_time); |
72 | 68 | sta->ampdu_mlme.tid_rx[tid] = NULL; | |
73 | if (!sta->ampdu_mlme.tid_rx[tid]->shutdown) { | ||
74 | kfree(sta->ampdu_mlme.tid_rx[tid]); | ||
75 | sta->ampdu_mlme.tid_rx[tid] = NULL; | ||
76 | } | ||
77 | 69 | ||
78 | sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_IDLE; | ||
79 | spin_unlock_bh(&sta->lock); | 70 | spin_unlock_bh(&sta->lock); |
71 | |||
72 | del_timer_sync(&tid_rx->session_timer); | ||
73 | kfree(tid_rx); | ||
80 | } | 74 | } |
81 | 75 | ||
82 | /* | 76 | /* |
@@ -211,7 +205,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | |||
211 | /* examine state machine */ | 205 | /* examine state machine */ |
212 | spin_lock_bh(&sta->lock); | 206 | spin_lock_bh(&sta->lock); |
213 | 207 | ||
214 | if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) { | 208 | if (sta->ampdu_mlme.tid_active_rx[tid]) { |
215 | #ifdef CONFIG_MAC80211_HT_DEBUG | 209 | #ifdef CONFIG_MAC80211_HT_DEBUG |
216 | if (net_ratelimit()) | 210 | if (net_ratelimit()) |
217 | printk(KERN_DEBUG "unexpected AddBA Req from " | 211 | printk(KERN_DEBUG "unexpected AddBA Req from " |
@@ -273,7 +267,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | |||
273 | } | 267 | } |
274 | 268 | ||
275 | /* change state and send addba resp */ | 269 | /* change state and send addba resp */ |
276 | sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_OPERATIONAL; | 270 | sta->ampdu_mlme.tid_active_rx[tid] = true; |
277 | tid_agg_rx->dialog_token = dialog_token; | 271 | tid_agg_rx->dialog_token = dialog_token; |
278 | tid_agg_rx->ssn = start_seq_num; | 272 | tid_agg_rx->ssn = start_seq_num; |
279 | tid_agg_rx->head_seq_num = start_seq_num; | 273 | tid_agg_rx->head_seq_num = start_seq_num; |
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 23e720034577..740ff6c5b92c 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
@@ -119,7 +119,7 @@ STA_OPS(last_seq_ctrl); | |||
119 | static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, | 119 | static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, |
120 | size_t count, loff_t *ppos) | 120 | size_t count, loff_t *ppos) |
121 | { | 121 | { |
122 | char buf[64 + STA_TID_NUM * 40], *p = buf; | 122 | char buf[71 + STA_TID_NUM * 40], *p = buf; |
123 | int i; | 123 | int i; |
124 | struct sta_info *sta = file->private_data; | 124 | struct sta_info *sta = file->private_data; |
125 | 125 | ||
@@ -127,16 +127,16 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, | |||
127 | p += scnprintf(p, sizeof(buf) + buf - p, "next dialog_token: %#02x\n", | 127 | p += scnprintf(p, sizeof(buf) + buf - p, "next dialog_token: %#02x\n", |
128 | sta->ampdu_mlme.dialog_token_allocator + 1); | 128 | sta->ampdu_mlme.dialog_token_allocator + 1); |
129 | p += scnprintf(p, sizeof(buf) + buf - p, | 129 | p += scnprintf(p, sizeof(buf) + buf - p, |
130 | "TID\t\tRX\tDTKN\tSSN\t\tTX\tDTKN\tSSN\tpending\n"); | 130 | "TID\t\tRX active\tDTKN\tSSN\t\tTX\tDTKN\tSSN\tpending\n"); |
131 | for (i = 0; i < STA_TID_NUM; i++) { | 131 | for (i = 0; i < STA_TID_NUM; i++) { |
132 | p += scnprintf(p, sizeof(buf) + buf - p, "%02d", i); | 132 | p += scnprintf(p, sizeof(buf) + buf - p, "%02d", i); |
133 | p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", | 133 | p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", |
134 | sta->ampdu_mlme.tid_state_rx[i]); | 134 | sta->ampdu_mlme.tid_active_rx[i]); |
135 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x", | 135 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x", |
136 | sta->ampdu_mlme.tid_state_rx[i] ? | 136 | sta->ampdu_mlme.tid_active_rx[i] ? |
137 | sta->ampdu_mlme.tid_rx[i]->dialog_token : 0); | 137 | sta->ampdu_mlme.tid_rx[i]->dialog_token : 0); |
138 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x", | 138 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x", |
139 | sta->ampdu_mlme.tid_state_rx[i] ? | 139 | sta->ampdu_mlme.tid_active_rx[i] ? |
140 | sta->ampdu_mlme.tid_rx[i]->ssn : 0); | 140 | sta->ampdu_mlme.tid_rx[i]->ssn : 0); |
141 | 141 | ||
142 | p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", | 142 | p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index c02e43b50ac3..62053fa711f3 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -720,7 +720,7 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx, | |||
720 | 720 | ||
721 | tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; | 721 | tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; |
722 | 722 | ||
723 | if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL) | 723 | if (!sta->ampdu_mlme.tid_active_rx[tid]) |
724 | goto dont_reorder; | 724 | goto dont_reorder; |
725 | 725 | ||
726 | tid_agg_rx = sta->ampdu_mlme.tid_rx[tid]; | 726 | tid_agg_rx = sta->ampdu_mlme.tid_rx[tid]; |
@@ -1805,8 +1805,7 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames) | |||
1805 | if (!rx->sta) | 1805 | if (!rx->sta) |
1806 | return RX_DROP_MONITOR; | 1806 | return RX_DROP_MONITOR; |
1807 | tid = le16_to_cpu(bar->control) >> 12; | 1807 | tid = le16_to_cpu(bar->control) >> 12; |
1808 | if (rx->sta->ampdu_mlme.tid_state_rx[tid] | 1808 | if (!rx->sta->ampdu_mlme.tid_active_rx[tid]) |
1809 | != HT_AGG_STATE_OPERATIONAL) | ||
1810 | return RX_DROP_MONITOR; | 1809 | return RX_DROP_MONITOR; |
1811 | tid_agg_rx = rx->sta->ampdu_mlme.tid_rx[tid]; | 1810 | tid_agg_rx = rx->sta->ampdu_mlme.tid_rx[tid]; |
1812 | 1811 | ||
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index bd11753c1525..5bf044b92dca 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -238,9 +238,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
238 | * enable session_timer's data differentiation. refer to | 238 | * enable session_timer's data differentiation. refer to |
239 | * sta_rx_agg_session_timer_expired for useage */ | 239 | * sta_rx_agg_session_timer_expired for useage */ |
240 | sta->timer_to_tid[i] = i; | 240 | sta->timer_to_tid[i] = i; |
241 | /* rx */ | ||
242 | sta->ampdu_mlme.tid_state_rx[i] = HT_AGG_STATE_IDLE; | ||
243 | sta->ampdu_mlme.tid_rx[i] = NULL; | ||
244 | /* tx */ | 241 | /* tx */ |
245 | sta->ampdu_mlme.tid_state_tx[i] = HT_AGG_STATE_IDLE; | 242 | sta->ampdu_mlme.tid_state_tx[i] = HT_AGG_STATE_IDLE; |
246 | sta->ampdu_mlme.tid_tx[i] = NULL; | 243 | sta->ampdu_mlme.tid_tx[i] = NULL; |
@@ -606,7 +603,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) | |||
606 | struct ieee80211_sub_if_data *sdata; | 603 | struct ieee80211_sub_if_data *sdata; |
607 | struct sk_buff *skb; | 604 | struct sk_buff *skb; |
608 | unsigned long flags; | 605 | unsigned long flags; |
609 | int ret, i; | 606 | int ret; |
610 | 607 | ||
611 | might_sleep(); | 608 | might_sleep(); |
612 | 609 | ||
@@ -616,6 +613,15 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) | |||
616 | local = sta->local; | 613 | local = sta->local; |
617 | sdata = sta->sdata; | 614 | sdata = sta->sdata; |
618 | 615 | ||
616 | /* | ||
617 | * Before removing the station from the driver and | ||
618 | * rate control, it might still start new aggregation | ||
619 | * sessions -- block that to make sure the tear-down | ||
620 | * will be sufficient. | ||
621 | */ | ||
622 | set_sta_flags(sta, WLAN_STA_BLOCK_BA); | ||
623 | ieee80211_sta_tear_down_BA_sessions(sta); | ||
624 | |||
619 | spin_lock_irqsave(&local->sta_lock, flags); | 625 | spin_lock_irqsave(&local->sta_lock, flags); |
620 | ret = sta_info_hash_del(local, sta); | 626 | ret = sta_info_hash_del(local, sta); |
621 | /* this might still be the pending list ... which is fine */ | 627 | /* this might still be the pending list ... which is fine */ |
@@ -700,50 +706,6 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) | |||
700 | while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) | 706 | while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) |
701 | dev_kfree_skb_any(skb); | 707 | dev_kfree_skb_any(skb); |
702 | 708 | ||
703 | for (i = 0; i < STA_TID_NUM; i++) { | ||
704 | struct tid_ampdu_rx *tid_rx; | ||
705 | struct tid_ampdu_tx *tid_tx; | ||
706 | |||
707 | spin_lock_bh(&sta->lock); | ||
708 | tid_rx = sta->ampdu_mlme.tid_rx[i]; | ||
709 | /* Make sure timer won't free the tid_rx struct, see below */ | ||
710 | if (tid_rx) | ||
711 | tid_rx->shutdown = true; | ||
712 | |||
713 | spin_unlock_bh(&sta->lock); | ||
714 | |||
715 | /* | ||
716 | * Outside spinlock - shutdown is true now so that the timer | ||
717 | * won't free tid_rx, we have to do that now. Can't let the | ||
718 | * timer do it because we have to sync the timer outside the | ||
719 | * lock that it takes itself. | ||
720 | */ | ||
721 | if (tid_rx) { | ||
722 | del_timer_sync(&tid_rx->session_timer); | ||
723 | kfree(tid_rx); | ||
724 | } | ||
725 | |||
726 | /* | ||
727 | * No need to do such complications for TX agg sessions, the | ||
728 | * path leading to freeing the tid_tx struct goes via a call | ||
729 | * from the driver, and thus needs to look up the sta struct | ||
730 | * again, which cannot be found when we get here. Hence, we | ||
731 | * just need to delete the timer and free the aggregation | ||
732 | * info; we won't be telling the peer about it then but that | ||
733 | * doesn't matter if we're not talking to it again anyway. | ||
734 | */ | ||
735 | tid_tx = sta->ampdu_mlme.tid_tx[i]; | ||
736 | if (tid_tx) { | ||
737 | del_timer_sync(&tid_tx->addba_resp_timer); | ||
738 | /* | ||
739 | * STA removed while aggregation session being | ||
740 | * started? Bit odd, but purge frames anyway. | ||
741 | */ | ||
742 | skb_queue_purge(&tid_tx->pending); | ||
743 | kfree(tid_tx); | ||
744 | } | ||
745 | } | ||
746 | |||
747 | __sta_info_free(local, sta); | 709 | __sta_info_free(local, sta); |
748 | 710 | ||
749 | return 0; | 711 | return 0; |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 57e81758d6f7..48a5e80957f0 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -36,7 +36,7 @@ | |||
36 | * frame to this station is transmitted. | 36 | * frame to this station is transmitted. |
37 | * @WLAN_STA_MFP: Management frame protection is used with this STA. | 37 | * @WLAN_STA_MFP: Management frame protection is used with this STA. |
38 | * @WLAN_STA_BLOCK_BA: Used to deny ADDBA requests (both TX and RX) | 38 | * @WLAN_STA_BLOCK_BA: Used to deny ADDBA requests (both TX and RX) |
39 | * during suspend/resume. | 39 | * during suspend/resume and station removal. |
40 | * @WLAN_STA_PS_DRIVER: driver requires keeping this station in | 40 | * @WLAN_STA_PS_DRIVER: driver requires keeping this station in |
41 | * power-save mode logically to flush frames that might still | 41 | * power-save mode logically to flush frames that might still |
42 | * be in the queues | 42 | * be in the queues |
@@ -106,7 +106,6 @@ struct tid_ampdu_tx { | |||
106 | * @buf_size: buffer size for incoming A-MPDUs | 106 | * @buf_size: buffer size for incoming A-MPDUs |
107 | * @timeout: reset timer value (in TUs). | 107 | * @timeout: reset timer value (in TUs). |
108 | * @dialog_token: dialog token for aggregation session | 108 | * @dialog_token: dialog token for aggregation session |
109 | * @shutdown: this session is being shut down due to STA removal | ||
110 | */ | 109 | */ |
111 | struct tid_ampdu_rx { | 110 | struct tid_ampdu_rx { |
112 | struct sk_buff **reorder_buf; | 111 | struct sk_buff **reorder_buf; |
@@ -118,7 +117,6 @@ struct tid_ampdu_rx { | |||
118 | u16 buf_size; | 117 | u16 buf_size; |
119 | u16 timeout; | 118 | u16 timeout; |
120 | u8 dialog_token; | 119 | u8 dialog_token; |
121 | bool shutdown; | ||
122 | }; | 120 | }; |
123 | 121 | ||
124 | /** | 122 | /** |
@@ -156,7 +154,7 @@ enum plink_state { | |||
156 | */ | 154 | */ |
157 | struct sta_ampdu_mlme { | 155 | struct sta_ampdu_mlme { |
158 | /* rx */ | 156 | /* rx */ |
159 | u8 tid_state_rx[STA_TID_NUM]; | 157 | bool tid_active_rx[STA_TID_NUM]; |
160 | struct tid_ampdu_rx *tid_rx[STA_TID_NUM]; | 158 | struct tid_ampdu_rx *tid_rx[STA_TID_NUM]; |
161 | /* tx */ | 159 | /* tx */ |
162 | u8 tid_state_tx[STA_TID_NUM]; | 160 | u8 tid_state_tx[STA_TID_NUM]; |