diff options
-rw-r--r-- | net/mac80211/agg-rx.c | 11 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 37 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 1 |
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 | /** |