diff options
author | Johannes Berg <johannes.berg@intel.com> | 2022-07-18 23:54:27 +0300 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2022-07-22 15:28:10 +0300 |
commit | 0ad49045f28474b3cbc1f27ec7a4238970734764 (patch) | |
tree | c027d03e9311afc65c4e0de2f773c9c5533b51bc /net/mac80211/sta_info.c | |
parent | 9aebce6c97bfd7dafd364be2e5b3af7a78af2662 (diff) | |
download | linux-0ad49045f28474b3cbc1f27ec7a4238970734764.tar.xz |
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/sta_info.c')
-rw-r--r-- | net/mac80211/sta_info.c | 18 |
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; |