aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/ieee80211.h1
-rw-r--r--net/mac80211/agg-rx.c48
-rw-r--r--net/mac80211/debugfs_sta.c10
-rw-r--r--net/mac80211/rx.c5
-rw-r--r--net/mac80211/sta_info.c58
-rw-r--r--net/mac80211/sta_info.h6
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 {
1324enum ieee80211_back_parties { 1324enum 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);
119static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, 119static 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 */
111struct tid_ampdu_rx { 110struct 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 */
157struct sta_ampdu_mlme { 155struct 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];