aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/mac80211/agg-rx.c11
-rw-r--r--net/mac80211/sta_info.c37
-rw-r--r--net/mac80211/sta_info.h1
3 files changed, 43 insertions, 6 deletions
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c
index d7afd0956970..4b571b211625 100644
--- a/net/mac80211/agg-rx.c
+++ b/net/mac80211/agg-rx.c
@@ -78,11 +78,18 @@ void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *r
78 sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i] = NULL; 78 sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i] = NULL;
79 } 79 }
80 } 80 }
81
82 spin_lock_bh(&sta->lock);
81 /* free resources */ 83 /* free resources */
82 kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_buf); 84 kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_buf);
83 kfree(sta->ampdu_mlme.tid_rx[tid]); 85
84 sta->ampdu_mlme.tid_rx[tid] = NULL; 86 if (!sta->ampdu_mlme.tid_rx[tid]->shutdown) {
87 kfree(sta->ampdu_mlme.tid_rx[tid]);
88 sta->ampdu_mlme.tid_rx[tid] = NULL;
89 }
90
85 sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_IDLE; 91 sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_IDLE;
92 spin_unlock_bh(&sta->lock);
86 93
87 rcu_read_unlock(); 94 rcu_read_unlock();
88} 95}
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 10c5539c20ab..634f65c0130e 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -194,12 +194,41 @@ void sta_info_destroy(struct sta_info *sta)
194 dev_kfree_skb_any(skb); 194 dev_kfree_skb_any(skb);
195 195
196 for (i = 0; i < STA_TID_NUM; i++) { 196 for (i = 0; i < STA_TID_NUM; i++) {
197 struct tid_ampdu_rx *tid_rx;
198 struct tid_ampdu_tx *tid_tx;
199
197 spin_lock_bh(&sta->lock); 200 spin_lock_bh(&sta->lock);
198 if (sta->ampdu_mlme.tid_rx[i]) 201 tid_rx = sta->ampdu_mlme.tid_rx[i];
199 del_timer_sync(&sta->ampdu_mlme.tid_rx[i]->session_timer); 202 /* Make sure timer won't free the tid_rx struct, see below */
200 if (sta->ampdu_mlme.tid_tx[i]) 203 if (tid_rx)
201 del_timer_sync(&sta->ampdu_mlme.tid_tx[i]->addba_resp_timer); 204 tid_rx->shutdown = true;
202 spin_unlock_bh(&sta->lock); 205 spin_unlock_bh(&sta->lock);
206
207 /*
208 * Outside spinlock - shutdown is true now so that the timer
209 * won't free tid_rx, we have to do that now. Can't let the
210 * timer do it because we have to sync the timer outside the
211 * lock that it takes itself.
212 */
213 if (tid_rx) {
214 del_timer_sync(&tid_rx->session_timer);
215 kfree(tid_rx);
216 }
217
218 /*
219 * No need to do such complications for TX agg sessions, the
220 * path leading to freeing the tid_tx struct goes via a call
221 * from the driver, and thus needs to look up the sta struct
222 * again, which cannot be found when we get here. Hence, we
223 * just need to delete the timer and free the aggregation
224 * info; we won't be telling the peer about it then but that
225 * doesn't matter if we're not talking to it again anyway.
226 */
227 tid_tx = sta->ampdu_mlme.tid_tx[i];
228 if (tid_tx) {
229 del_timer_sync(&tid_tx->addba_resp_timer);
230 kfree(tid_tx);
231 }
203 } 232 }
204 233
205 __sta_info_free(local, sta); 234 __sta_info_free(local, sta);
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index a070bd929e00..d9653231992f 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -100,6 +100,7 @@ struct tid_ampdu_rx {
100 u16 buf_size; 100 u16 buf_size;
101 u16 timeout; 101 u16 timeout;
102 u8 dialog_token; 102 u8 dialog_token;
103 bool shutdown;
103}; 104};
104 105
105/** 106/**