Commit 177577db authored by Johannes Berg's avatar Johannes Berg

wifi: mac80211: sta_info: fix link_sta insertion

When inserting a link STA, make sure it doesn't exist first
and add lockdep assertions that we cannot modify the hash
table without holding the sta_mtx, so this check is really
correct.

Also return without hashing if the driver failed, and warn
if the hashing fails, which shouldn't happen due to the
check described above.

Fixes: cb71f1d1 ("wifi: mac80211: add sta link addition/removal")
Fixes: ba6ddab9 ("wifi: mac80211: maintain link-sta hash table")
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent b18d87f5
...@@ -99,6 +99,7 @@ static int sta_info_hash_del(struct ieee80211_local *local, ...@@ -99,6 +99,7 @@ static int sta_info_hash_del(struct ieee80211_local *local,
static int link_sta_info_hash_add(struct ieee80211_local *local, static int link_sta_info_hash_add(struct ieee80211_local *local,
struct link_sta_info *link_sta) struct link_sta_info *link_sta)
{ {
lockdep_assert_held(&local->sta_mtx);
return rhltable_insert(&local->link_sta_hash, return rhltable_insert(&local->link_sta_hash,
&link_sta->link_hash_node, &link_sta->link_hash_node,
link_sta_rht_params); link_sta_rht_params);
...@@ -107,6 +108,7 @@ static int link_sta_info_hash_add(struct ieee80211_local *local, ...@@ -107,6 +108,7 @@ static int link_sta_info_hash_add(struct ieee80211_local *local,
static int link_sta_info_hash_del(struct ieee80211_local *local, static int link_sta_info_hash_del(struct ieee80211_local *local,
struct link_sta_info *link_sta) struct link_sta_info *link_sta)
{ {
lockdep_assert_held(&local->sta_mtx);
return rhltable_remove(&local->link_sta_hash, return rhltable_remove(&local->link_sta_hash,
&link_sta->link_hash_node, &link_sta->link_hash_node,
link_sta_rht_params); link_sta_rht_params);
...@@ -2765,6 +2767,14 @@ int ieee80211_sta_activate_link(struct sta_info *sta, unsigned int link_id) ...@@ -2765,6 +2767,14 @@ int ieee80211_sta_activate_link(struct sta_info *sta, unsigned int link_id)
if (WARN_ON(old_links == new_links || !link_sta)) if (WARN_ON(old_links == new_links || !link_sta))
return -EINVAL; return -EINVAL;
rcu_read_lock();
if (link_sta_info_hash_lookup(sdata->local, link_sta->addr)) {
rcu_read_unlock();
return -EALREADY;
}
/* we only modify under the mutex so this is fine */
rcu_read_unlock();
sta->sta.valid_links = new_links; sta->sta.valid_links = new_links;
if (!test_sta_flag(sta, WLAN_STA_INSERTED)) { if (!test_sta_flag(sta, WLAN_STA_INSERTED)) {
...@@ -2777,12 +2787,13 @@ int ieee80211_sta_activate_link(struct sta_info *sta, unsigned int link_id) ...@@ -2777,12 +2787,13 @@ int ieee80211_sta_activate_link(struct sta_info *sta, unsigned int link_id)
if (ret) { if (ret) {
sta->sta.valid_links = old_links; sta->sta.valid_links = old_links;
sta_remove_link(sta, link_id, false); sta_remove_link(sta, link_id, false);
return ret;
} }
hash: hash:
link_sta_info_hash_add(sdata->local, link_sta); ret = link_sta_info_hash_add(sdata->local, link_sta);
WARN_ON(ret);
return ret; return 0;
} }
void ieee80211_sta_remove_link(struct sta_info *sta, unsigned int link_id) void ieee80211_sta_remove_link(struct sta_info *sta, unsigned int link_id)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment