Commit ba6ddab9 authored by Johannes Berg's avatar Johannes Berg

wifi: mac80211: maintain link-sta hash table

Maintain a hash table of link-sta addresses so we can find
them for management frames etc. where addresses haven't
been replaced by the drivers to the MLD address yet.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent c71420db
...@@ -1366,6 +1366,7 @@ struct ieee80211_local { ...@@ -1366,6 +1366,7 @@ struct ieee80211_local {
unsigned long num_sta; unsigned long num_sta;
struct list_head sta_list; struct list_head sta_list;
struct rhltable sta_hash; struct rhltable sta_hash;
struct rhltable link_sta_hash;
struct timer_list sta_cleanup; struct timer_list sta_cleanup;
int sta_generation; int sta_generation;
......
...@@ -79,6 +79,15 @@ static const struct rhashtable_params sta_rht_params = { ...@@ -79,6 +79,15 @@ static const struct rhashtable_params sta_rht_params = {
.max_size = CONFIG_MAC80211_STA_HASH_MAX_SIZE, .max_size = CONFIG_MAC80211_STA_HASH_MAX_SIZE,
}; };
static const struct rhashtable_params link_sta_rht_params = {
.nelem_hint = 3, /* start small */
.automatic_shrinking = true,
.head_offset = offsetof(struct link_sta_info, link_hash_node),
.key_offset = offsetof(struct link_sta_info, addr),
.key_len = ETH_ALEN,
.max_size = CONFIG_MAC80211_STA_HASH_MAX_SIZE,
};
/* Caller must hold local->sta_mtx */ /* Caller must hold local->sta_mtx */
static int sta_info_hash_del(struct ieee80211_local *local, static int sta_info_hash_del(struct ieee80211_local *local,
struct sta_info *sta) struct sta_info *sta)
...@@ -87,6 +96,14 @@ static int sta_info_hash_del(struct ieee80211_local *local, ...@@ -87,6 +96,14 @@ static int sta_info_hash_del(struct ieee80211_local *local,
sta_rht_params); sta_rht_params);
} }
static int link_sta_info_hash_del(struct ieee80211_local *local,
struct link_sta_info *link_sta)
{
return rhltable_remove(&local->link_sta_hash,
&link_sta->link_hash_node,
link_sta_rht_params);
}
static void __cleanup_single_sta(struct sta_info *sta) static void __cleanup_single_sta(struct sta_info *sta)
{ {
int ac, i; int ac, i;
...@@ -216,6 +233,37 @@ struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata, ...@@ -216,6 +233,37 @@ struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata,
return NULL; return NULL;
} }
struct rhlist_head *link_sta_info_hash_lookup(struct ieee80211_local *local,
const u8 *addr)
{
return rhltable_lookup(&local->link_sta_hash, addr,
link_sta_rht_params);
}
struct link_sta_info *
link_sta_info_get_bss(struct ieee80211_sub_if_data *sdata, const u8 *addr)
{
struct ieee80211_local *local = sdata->local;
struct rhlist_head *tmp;
struct link_sta_info *link_sta;
rcu_read_lock();
for_each_link_sta_info(local, addr, link_sta, tmp) {
struct sta_info *sta = link_sta->sta;
if (sta->sdata == sdata ||
(sta->sdata->bss && sta->sdata->bss == sdata->bss)) {
rcu_read_unlock();
/* this is safe as the caller must already hold
* another rcu read section or the mutex
*/
return link_sta;
}
}
rcu_read_unlock();
return NULL;
}
struct sta_info *sta_info_get_by_addrs(struct ieee80211_local *local, struct sta_info *sta_info_get_by_addrs(struct ieee80211_local *local,
const u8 *sta_addr, const u8 *vif_addr) const u8 *sta_addr, const u8 *vif_addr)
{ {
...@@ -256,7 +304,8 @@ static void sta_info_free_link(struct link_sta_info *link_sta) ...@@ -256,7 +304,8 @@ static void sta_info_free_link(struct link_sta_info *link_sta)
free_percpu(link_sta->pcpu_rx_stats); free_percpu(link_sta->pcpu_rx_stats);
} }
static void sta_remove_link(struct sta_info *sta, unsigned int link_id) static void sta_remove_link(struct sta_info *sta, unsigned int link_id,
bool unhash)
{ {
struct sta_link_alloc *alloc = NULL; struct sta_link_alloc *alloc = NULL;
struct link_sta_info *link_sta; struct link_sta_info *link_sta;
...@@ -267,6 +316,9 @@ static void sta_remove_link(struct sta_info *sta, unsigned int link_id) ...@@ -267,6 +316,9 @@ static void sta_remove_link(struct sta_info *sta, unsigned int link_id)
if (WARN_ON(!link_sta)) if (WARN_ON(!link_sta))
return; return;
if (unhash)
link_sta_info_hash_del(sta->local, link_sta);
if (link_sta != &sta->deflink) if (link_sta != &sta->deflink)
alloc = container_of(link_sta, typeof(*alloc), info); alloc = container_of(link_sta, typeof(*alloc), info);
...@@ -298,7 +350,7 @@ void sta_info_free(struct ieee80211_local *local, struct sta_info *sta) ...@@ -298,7 +350,7 @@ void sta_info_free(struct ieee80211_local *local, struct sta_info *sta)
if (!(sta->sta.valid_links & BIT(i))) if (!(sta->sta.valid_links & BIT(i)))
continue; continue;
sta_remove_link(sta, i); sta_remove_link(sta, i, true);
} }
/* /*
...@@ -1262,6 +1314,12 @@ int sta_info_init(struct ieee80211_local *local) ...@@ -1262,6 +1314,12 @@ int sta_info_init(struct ieee80211_local *local)
if (err) if (err)
return err; return err;
err = rhltable_init(&local->link_sta_hash, &link_sta_rht_params);
if (err) {
rhltable_destroy(&local->sta_hash);
return err;
}
spin_lock_init(&local->tim_lock); spin_lock_init(&local->tim_lock);
mutex_init(&local->sta_mtx); mutex_init(&local->sta_mtx);
INIT_LIST_HEAD(&local->sta_list); INIT_LIST_HEAD(&local->sta_list);
...@@ -1274,6 +1332,7 @@ void sta_info_stop(struct ieee80211_local *local) ...@@ -1274,6 +1332,7 @@ void sta_info_stop(struct ieee80211_local *local)
{ {
del_timer_sync(&local->sta_cleanup); del_timer_sync(&local->sta_cleanup);
rhltable_destroy(&local->sta_hash); rhltable_destroy(&local->sta_hash);
rhltable_destroy(&local->link_sta_hash);
} }
...@@ -2685,6 +2744,14 @@ int ieee80211_sta_allocate_link(struct sta_info *sta, unsigned int link_id) ...@@ -2685,6 +2744,14 @@ int ieee80211_sta_allocate_link(struct sta_info *sta, unsigned int link_id)
return 0; return 0;
} }
static int link_sta_info_hash_add(struct ieee80211_local *local,
struct link_sta_info *link_sta)
{
return rhltable_insert(&local->link_sta_hash,
&link_sta->link_hash_node,
link_sta_rht_params);
}
int ieee80211_sta_activate_link(struct sta_info *sta, unsigned int link_id) int ieee80211_sta_activate_link(struct sta_info *sta, unsigned int link_id)
{ {
struct ieee80211_sub_if_data *sdata = sta->sdata; struct ieee80211_sub_if_data *sdata = sta->sdata;
...@@ -2701,16 +2768,21 @@ int ieee80211_sta_activate_link(struct sta_info *sta, unsigned int link_id) ...@@ -2701,16 +2768,21 @@ int ieee80211_sta_activate_link(struct sta_info *sta, unsigned int link_id)
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)) {
return 0; ret = 0;
goto hash;
}
ret = drv_change_sta_links(sdata->local, sdata, &sta->sta, ret = drv_change_sta_links(sdata->local, sdata, &sta->sta,
old_links, new_links); old_links, new_links);
if (ret) { if (ret) {
sta->sta.valid_links = old_links; sta->sta.valid_links = old_links;
sta_remove_link(sta, link_id); sta_remove_link(sta, link_id, false);
} }
hash:
link_sta_info_hash_add(sdata->local, link_sta);
return ret; return ret;
} }
...@@ -2727,5 +2799,5 @@ void ieee80211_sta_remove_link(struct sta_info *sta, unsigned int link_id) ...@@ -2727,5 +2799,5 @@ void ieee80211_sta_remove_link(struct sta_info *sta, unsigned int link_id)
sta->sta.valid_links, sta->sta.valid_links,
sta->sta.valid_links & ~BIT(link_id)); sta->sta.valid_links & ~BIT(link_id));
sta_remove_link(sta, link_id); sta_remove_link(sta, link_id, true);
} }
...@@ -491,6 +491,7 @@ struct ieee80211_fragment_cache { ...@@ -491,6 +491,7 @@ struct ieee80211_fragment_cache {
* same for non-MLD STA. This is used as key for searching link STA * same for non-MLD STA. This is used as key for searching link STA
* @link_id: Link ID uniquely identifying the link STA. This is 0 for non-MLD * @link_id: Link ID uniquely identifying the link STA. This is 0 for non-MLD
* and set to the corresponding vif LinkId for MLD STA * and set to the corresponding vif LinkId for MLD STA
* @link_hash_node: hash node for rhashtable
* @sta: Points to the STA info * @sta: Points to the STA info
* @gtk: group keys negotiated with this station, if any * @gtk: group keys negotiated with this station, if any
* @tx_stats: TX statistics * @tx_stats: TX statistics
...@@ -523,7 +524,7 @@ struct link_sta_info { ...@@ -523,7 +524,7 @@ struct link_sta_info {
u8 addr[ETH_ALEN]; u8 addr[ETH_ALEN];
u8 link_id; u8 link_id;
/* TODO rhash head/node for finding link_sta based on addr */ struct rhlist_head link_hash_node;
struct sta_info *sta; struct sta_info *sta;
struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS + struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS +
...@@ -824,6 +825,17 @@ struct sta_info *sta_info_get_by_addrs(struct ieee80211_local *local, ...@@ -824,6 +825,17 @@ struct sta_info *sta_info_get_by_addrs(struct ieee80211_local *local,
rhl_for_each_entry_rcu(_sta, _tmp, \ rhl_for_each_entry_rcu(_sta, _tmp, \
sta_info_hash_lookup(local, _addr), hash_node) sta_info_hash_lookup(local, _addr), hash_node)
struct rhlist_head *link_sta_info_hash_lookup(struct ieee80211_local *local,
const u8 *addr);
#define for_each_link_sta_info(local, _addr, _sta, _tmp) \
rhl_for_each_entry_rcu(_sta, _tmp, \
link_sta_info_hash_lookup(local, _addr), \
link_hash_node)
struct link_sta_info *
link_sta_info_get_bss(struct ieee80211_sub_if_data *sdata, const u8 *addr);
/* /*
* Get STA info by index, BROKEN! * Get STA info by index, BROKEN!
*/ */
......
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