summaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2022-07-18 22:54:27 +0200
committerJohannes Berg <johannes.berg@intel.com>2022-07-22 14:28:10 +0200
commit0ad49045f28474b3cbc1f27ec7a4238970734764 (patch)
treec027d03e9311afc65c4e0de2f773c9c5533b51bc /net/mac80211
parent9aebce6c97bfd7dafd364be2e5b3af7a78af2662 (diff)
downloadlinux-0ad49045f28474b3cbc1f27ec7a4238970734764.tar.bz2
wifi: mac80211: fix link sta hash table handling
There are two issues here: we unhash the link stations only directly before freeing the station they belong to, and we also don't unhash all the links correctly in all cases. Fix these issues. Fixes: ba6ddab94fc6 ("wifi: mac80211: maintain link-sta hash table") Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/sta_info.c18
1 files changed, 16 insertions, 2 deletions
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 75122eced104..44e21dee6077 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -358,7 +358,7 @@ void sta_info_free(struct ieee80211_local *local, struct sta_info *sta)
if (!(sta->sta.valid_links & BIT(i)))
continue;
- sta_remove_link(sta, i, true);
+ sta_remove_link(sta, i, false);
}
/*
@@ -846,6 +846,8 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
return 0;
out_remove:
+ if (sta->sta.valid_links)
+ link_sta_info_hash_del(local, &sta->deflink);
sta_info_hash_del(local, sta);
list_del_rcu(&sta->list);
out_drop_sta:
@@ -1140,7 +1142,7 @@ static int __must_check __sta_info_destroy_part1(struct sta_info *sta)
{
struct ieee80211_local *local;
struct ieee80211_sub_if_data *sdata;
- int ret;
+ int ret, i;
might_sleep();
@@ -1168,6 +1170,18 @@ static int __must_check __sta_info_destroy_part1(struct sta_info *sta)
*/
drv_sync_rx_queues(local, sta);
+ for (i = 0; i < ARRAY_SIZE(sta->link); i++) {
+ struct link_sta_info *link_sta;
+
+ if (!(sta->sta.valid_links & BIT(i)))
+ continue;
+
+ link_sta = rcu_dereference_protected(sta->link[i],
+ lockdep_is_held(&local->sta_mtx));
+
+ link_sta_info_hash_del(local, link_sta);
+ }
+
ret = sta_info_hash_del(local, sta);
if (WARN_ON(ret))
return ret;