aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/sta_info.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/sta_info.c')
-rw-r--r--net/mac80211/sta_info.c58
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;