summaryrefslogtreecommitdiffstats
path: root/net/mac80211/sta_info.c
diff options
context:
space:
mode:
authorJohannes Berg2013-12-04 20:11:06 +0100
committerJohannes Berg2013-12-16 11:29:45 +0100
commita710c8160dd93e981163759aad754f758850273a (patch)
tree1b125791f1a332af6a219bca9072bd7085d28f92 /net/mac80211/sta_info.c
parentiwlwifi: mvm: use pre-RCU-sync sta removal operation (diff)
downloadkernel-qcow2-linux-a710c8160dd93e981163759aad754f758850273a.tar.gz
kernel-qcow2-linux-a710c8160dd93e981163759aad754f758850273a.tar.xz
kernel-qcow2-linux-a710c8160dd93e981163759aad754f758850273a.zip
mac80211: move 4-addr sta pointer clearing before synchronize_rcu()
The pointer should be cleared before synchronize_rcu() so that the consequently dead station won't be found by any lookups in the TX or RX paths. Also check that the station is actually the one being removed, the check is not needed because each 4-addr VLAN can only have a single station and non-4-addr VLANs always have a NULL pointer there, but the code is clearer this way (and we avoid the memory write.) Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/sta_info.c')
-rw-r--r--net/mac80211/sta_info.c7
1 files changed, 4 insertions, 3 deletions
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 1e147742eccf..557ac250ac10 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -875,6 +875,10 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
drv_sta_pre_rcu_remove(local, sta->sdata, sta);
+ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
+ rcu_access_pointer(sdata->u.vlan.sta) == sta)
+ RCU_INIT_POINTER(sdata->u.vlan.sta, NULL);
+
/* this always calls synchronize_net() */
ieee80211_free_sta_keys(local, sta);
@@ -883,9 +887,6 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
local->num_sta--;
local->sta_generation++;
- if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
- RCU_INIT_POINTER(sdata->u.vlan.sta, NULL);
-
while (sta->sta_state > IEEE80211_STA_NONE) {
ret = sta_info_move_state(sta, sta->sta_state - 1);
if (ret) {