diff options
Diffstat (limited to 'net/mac80211/sta_info.c')
-rw-r--r-- | net/mac80211/sta_info.c | 37 |
1 files changed, 33 insertions, 4 deletions
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); |