aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2015-01-09 05:40:39 -0500
committerJohannes Berg <johannes.berg@intel.com>2015-01-09 05:48:37 -0500
commit9b7a86f3514dd5cb4a6787292781daae65a29a10 (patch)
treeb98a66a8cd74795a6435405299b44572aa2bbc39 /net/mac80211
parenta809ca5e03c6dd3b324d148564715ca5ea2b8103 (diff)
mac80211: fix handling TIM IE when stations disconnect
When a station disconnects with frames still pending, we clear the TIM bit, but too late - it's only cleared when the station is already removed from the driver, and thus the driver can get confused (and hwsim will loudly complain.) Fix this by clearing the TIM bit earlier, when the station has been unlinked but not removed from the driver yet. To do this, refactor the TIM recalculation to in that case ignore traffic and simply assume no pending traffic - this is correct for the disconnected station even though the frames haven't been freed yet at that point. This patch isn't needed for current drivers though as they don't check the station argument to the set_tim() operation and thus don't really run into the possible confusion. Reported-by: Jouni Malinen <j@w1.fi> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/sta_info.c16
1 files changed, 13 insertions, 3 deletions
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index dc352fcdd469..79383ef0c264 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -116,7 +116,6 @@ static void __cleanup_single_sta(struct sta_info *sta)
116 clear_sta_flag(sta, WLAN_STA_PS_DELIVER); 116 clear_sta_flag(sta, WLAN_STA_PS_DELIVER);
117 117
118 atomic_dec(&ps->num_sta_ps); 118 atomic_dec(&ps->num_sta_ps);
119 sta_info_recalc_tim(sta);
120 } 119 }
121 120
122 for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { 121 for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
@@ -625,7 +624,7 @@ static unsigned long ieee80211_tids_for_ac(int ac)
625 } 624 }
626} 625}
627 626
628void sta_info_recalc_tim(struct sta_info *sta) 627static void __sta_info_recalc_tim(struct sta_info *sta, bool ignore_pending)
629{ 628{
630 struct ieee80211_local *local = sta->local; 629 struct ieee80211_local *local = sta->local;
631 struct ps_data *ps; 630 struct ps_data *ps;
@@ -667,6 +666,9 @@ void sta_info_recalc_tim(struct sta_info *sta)
667 if (ignore_for_tim == BIT(IEEE80211_NUM_ACS) - 1) 666 if (ignore_for_tim == BIT(IEEE80211_NUM_ACS) - 1)
668 ignore_for_tim = 0; 667 ignore_for_tim = 0;
669 668
669 if (ignore_pending)
670 ignore_for_tim = BIT(IEEE80211_NUM_ACS) - 1;
671
670 for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { 672 for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
671 unsigned long tids; 673 unsigned long tids;
672 674
@@ -695,7 +697,7 @@ void sta_info_recalc_tim(struct sta_info *sta)
695 else 697 else
696 __bss_tim_clear(ps->tim, id); 698 __bss_tim_clear(ps->tim, id);
697 699
698 if (local->ops->set_tim) { 700 if (local->ops->set_tim && !WARN_ON(sta->dead)) {
699 local->tim_in_locked_section = true; 701 local->tim_in_locked_section = true;
700 drv_set_tim(local, &sta->sta, indicate_tim); 702 drv_set_tim(local, &sta->sta, indicate_tim);
701 local->tim_in_locked_section = false; 703 local->tim_in_locked_section = false;
@@ -705,6 +707,11 @@ out_unlock:
705 spin_unlock_bh(&local->tim_lock); 707 spin_unlock_bh(&local->tim_lock);
706} 708}
707 709
710void sta_info_recalc_tim(struct sta_info *sta)
711{
712 __sta_info_recalc_tim(sta, false);
713}
714
708static bool sta_info_buffer_expired(struct sta_info *sta, struct sk_buff *skb) 715static bool sta_info_buffer_expired(struct sta_info *sta, struct sk_buff *skb)
709{ 716{
710 struct ieee80211_tx_info *info; 717 struct ieee80211_tx_info *info;
@@ -888,6 +895,9 @@ static void __sta_info_destroy_part2(struct sta_info *sta)
888 /* now keys can no longer be reached */ 895 /* now keys can no longer be reached */
889 ieee80211_free_sta_keys(local, sta); 896 ieee80211_free_sta_keys(local, sta);
890 897
898 /* disable TIM bit - last chance to tell driver */
899 __sta_info_recalc_tim(sta, true);
900
891 sta->dead = true; 901 sta->dead = true;
892 902
893 local->num_sta--; 903 local->num_sta--;