diff options
Diffstat (limited to 'net/mac80211/sta_info.c')
-rw-r--r-- | net/mac80211/sta_info.c | 75 |
1 files changed, 21 insertions, 54 deletions
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index fb12cec4d333..ff0eb948917b 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -250,9 +250,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
250 | * enable session_timer's data differentiation. refer to | 250 | * enable session_timer's data differentiation. refer to |
251 | * sta_rx_agg_session_timer_expired for useage */ | 251 | * sta_rx_agg_session_timer_expired for useage */ |
252 | sta->timer_to_tid[i] = i; | 252 | sta->timer_to_tid[i] = i; |
253 | /* rx */ | ||
254 | sta->ampdu_mlme.tid_state_rx[i] = HT_AGG_STATE_IDLE; | ||
255 | sta->ampdu_mlme.tid_rx[i] = NULL; | ||
256 | /* tx */ | 253 | /* tx */ |
257 | sta->ampdu_mlme.tid_state_tx[i] = HT_AGG_STATE_IDLE; | 254 | sta->ampdu_mlme.tid_state_tx[i] = HT_AGG_STATE_IDLE; |
258 | sta->ampdu_mlme.tid_tx[i] = NULL; | 255 | sta->ampdu_mlme.tid_tx[i] = NULL; |
@@ -619,7 +616,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) | |||
619 | struct ieee80211_sub_if_data *sdata; | 616 | struct ieee80211_sub_if_data *sdata; |
620 | struct sk_buff *skb; | 617 | struct sk_buff *skb; |
621 | unsigned long flags; | 618 | unsigned long flags; |
622 | int ret, i; | 619 | int ret; |
623 | 620 | ||
624 | might_sleep(); | 621 | might_sleep(); |
625 | 622 | ||
@@ -629,6 +626,15 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) | |||
629 | local = sta->local; | 626 | local = sta->local; |
630 | sdata = sta->sdata; | 627 | sdata = sta->sdata; |
631 | 628 | ||
629 | /* | ||
630 | * Before removing the station from the driver and | ||
631 | * rate control, it might still start new aggregation | ||
632 | * sessions -- block that to make sure the tear-down | ||
633 | * will be sufficient. | ||
634 | */ | ||
635 | set_sta_flags(sta, WLAN_STA_BLOCK_BA); | ||
636 | ieee80211_sta_tear_down_BA_sessions(sta); | ||
637 | |||
632 | spin_lock_irqsave(&local->sta_lock, flags); | 638 | spin_lock_irqsave(&local->sta_lock, flags); |
633 | ret = sta_info_hash_del(local, sta); | 639 | ret = sta_info_hash_del(local, sta); |
634 | /* this might still be the pending list ... which is fine */ | 640 | /* this might still be the pending list ... which is fine */ |
@@ -645,9 +651,6 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) | |||
645 | * may mean it is removed from hardware which requires that | 651 | * may mean it is removed from hardware which requires that |
646 | * the key->sta pointer is still valid, so flush the key todo | 652 | * the key->sta pointer is still valid, so flush the key todo |
647 | * list here. | 653 | * list here. |
648 | * | ||
649 | * ieee80211_key_todo() will synchronize_rcu() so after this | ||
650 | * nothing can reference this sta struct any more. | ||
651 | */ | 654 | */ |
652 | ieee80211_key_todo(); | 655 | ieee80211_key_todo(); |
653 | 656 | ||
@@ -679,11 +682,17 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) | |||
679 | sdata = sta->sdata; | 682 | sdata = sta->sdata; |
680 | } | 683 | } |
681 | 684 | ||
685 | /* | ||
686 | * At this point, after we wait for an RCU grace period, | ||
687 | * neither mac80211 nor the driver can reference this | ||
688 | * sta struct any more except by still existing timers | ||
689 | * associated with this station that we clean up below. | ||
690 | */ | ||
691 | synchronize_rcu(); | ||
692 | |||
682 | #ifdef CONFIG_MAC80211_MESH | 693 | #ifdef CONFIG_MAC80211_MESH |
683 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 694 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
684 | mesh_accept_plinks_update(sdata); | 695 | mesh_accept_plinks_update(sdata); |
685 | del_timer(&sta->plink_timer); | ||
686 | } | ||
687 | #endif | 696 | #endif |
688 | 697 | ||
689 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 698 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
@@ -710,50 +719,6 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) | |||
710 | while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) | 719 | while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) |
711 | dev_kfree_skb_any(skb); | 720 | dev_kfree_skb_any(skb); |
712 | 721 | ||
713 | for (i = 0; i < STA_TID_NUM; i++) { | ||
714 | struct tid_ampdu_rx *tid_rx; | ||
715 | struct tid_ampdu_tx *tid_tx; | ||
716 | |||
717 | spin_lock_bh(&sta->lock); | ||
718 | tid_rx = sta->ampdu_mlme.tid_rx[i]; | ||
719 | /* Make sure timer won't free the tid_rx struct, see below */ | ||
720 | if (tid_rx) | ||
721 | tid_rx->shutdown = true; | ||
722 | |||
723 | spin_unlock_bh(&sta->lock); | ||
724 | |||
725 | /* | ||
726 | * Outside spinlock - shutdown is true now so that the timer | ||
727 | * won't free tid_rx, we have to do that now. Can't let the | ||
728 | * timer do it because we have to sync the timer outside the | ||
729 | * lock that it takes itself. | ||
730 | */ | ||
731 | if (tid_rx) { | ||
732 | del_timer_sync(&tid_rx->session_timer); | ||
733 | kfree(tid_rx); | ||
734 | } | ||
735 | |||
736 | /* | ||
737 | * No need to do such complications for TX agg sessions, the | ||
738 | * path leading to freeing the tid_tx struct goes via a call | ||
739 | * from the driver, and thus needs to look up the sta struct | ||
740 | * again, which cannot be found when we get here. Hence, we | ||
741 | * just need to delete the timer and free the aggregation | ||
742 | * info; we won't be telling the peer about it then but that | ||
743 | * doesn't matter if we're not talking to it again anyway. | ||
744 | */ | ||
745 | tid_tx = sta->ampdu_mlme.tid_tx[i]; | ||
746 | if (tid_tx) { | ||
747 | del_timer_sync(&tid_tx->addba_resp_timer); | ||
748 | /* | ||
749 | * STA removed while aggregation session being | ||
750 | * started? Bit odd, but purge frames anyway. | ||
751 | */ | ||
752 | skb_queue_purge(&tid_tx->pending); | ||
753 | kfree(tid_tx); | ||
754 | } | ||
755 | } | ||
756 | |||
757 | __sta_info_free(local, sta); | 722 | __sta_info_free(local, sta); |
758 | 723 | ||
759 | return 0; | 724 | return 0; |
@@ -992,6 +957,8 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw, | |||
992 | { | 957 | { |
993 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); | 958 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); |
994 | 959 | ||
960 | trace_api_sta_block_awake(sta->local, pubsta, block); | ||
961 | |||
995 | if (block) | 962 | if (block) |
996 | set_sta_flags(sta, WLAN_STA_PS_DRIVER); | 963 | set_sta_flags(sta, WLAN_STA_PS_DRIVER); |
997 | else | 964 | else |