aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/sta_info.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2010-04-06 05:18:47 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-04-07 14:38:05 -0400
commit098a607091426e79178b9a6c318d993fea131791 (patch)
treed62c9993e49f90ca962cd763b096911d22d7e051 /net/mac80211/sta_info.c
parent618f356b95e37ca0c30b3b513898fda54abd52a6 (diff)
mac80211: clean up/fix aggregation code
The aggregation code has a number of quirks, like inventing an unneeded WLAN_BACK_TIMER value and leaking memory under certain circumstances during station destruction. Fix these issues by using the regular aggregation session teardown code and blocking new aggregation sessions, all before the station is really destructed. As a side effect, this gets rid of the long code block to destroy aggregation safely. Additionally, rename tid_state_rx which can only have the values IDLE and OPERATIONAL to tid_active_rx to make it easier to understand that there is no bitwise stuff going on on the RX side -- the TX side remains because it needs to keep track of the driver and peer states. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
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;