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