forked from mirrors/linux
		
	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: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
		
							parent
							
								
									c71420db65
								
							
						
					
					
						commit
						ba6ddab94f
					
				
					 3 changed files with 92 additions and 7 deletions
				
			
		| 
						 | 
				
			
			@ -1366,6 +1366,7 @@ struct ieee80211_local {
 | 
			
		|||
	unsigned long num_sta;
 | 
			
		||||
	struct list_head sta_list;
 | 
			
		||||
	struct rhltable sta_hash;
 | 
			
		||||
	struct rhltable link_sta_hash;
 | 
			
		||||
	struct timer_list sta_cleanup;
 | 
			
		||||
	int sta_generation;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -79,6 +79,15 @@ static const struct rhashtable_params sta_rht_params = {
 | 
			
		|||
	.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 */
 | 
			
		||||
static int sta_info_hash_del(struct ieee80211_local *local,
 | 
			
		||||
			     struct sta_info *sta)
 | 
			
		||||
| 
						 | 
				
			
			@ -87,6 +96,14 @@ static int sta_info_hash_del(struct ieee80211_local *local,
 | 
			
		|||
			       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)
 | 
			
		||||
{
 | 
			
		||||
	int ac, i;
 | 
			
		||||
| 
						 | 
				
			
			@ -216,6 +233,37 @@ struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata,
 | 
			
		|||
	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,
 | 
			
		||||
				       const u8 *sta_addr, const u8 *vif_addr)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -256,7 +304,8 @@ static void sta_info_free_link(struct link_sta_info *link_sta)
 | 
			
		|||
	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 link_sta_info *link_sta;
 | 
			
		||||
| 
						 | 
				
			
			@ -267,6 +316,9 @@ static void sta_remove_link(struct sta_info *sta, unsigned int link_id)
 | 
			
		|||
	if (WARN_ON(!link_sta))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (unhash)
 | 
			
		||||
		link_sta_info_hash_del(sta->local, link_sta);
 | 
			
		||||
 | 
			
		||||
	if (link_sta != &sta->deflink)
 | 
			
		||||
		alloc = container_of(link_sta, typeof(*alloc), info);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -298,7 +350,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);
 | 
			
		||||
		sta_remove_link(sta, i, true);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
| 
						 | 
				
			
			@ -1262,6 +1314,12 @@ int sta_info_init(struct ieee80211_local *local)
 | 
			
		|||
	if (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);
 | 
			
		||||
	mutex_init(&local->sta_mtx);
 | 
			
		||||
	INIT_LIST_HEAD(&local->sta_list);
 | 
			
		||||
| 
						 | 
				
			
			@ -1274,6 +1332,7 @@ void sta_info_stop(struct ieee80211_local *local)
 | 
			
		|||
{
 | 
			
		||||
	del_timer_sync(&local->sta_cleanup);
 | 
			
		||||
	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)
 | 
			
		|||
	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)
 | 
			
		||||
{
 | 
			
		||||
	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)
 | 
			
		|||
 | 
			
		||||
	sta->sta.valid_links = new_links;
 | 
			
		||||
 | 
			
		||||
	if (!test_sta_flag(sta, WLAN_STA_INSERTED))
 | 
			
		||||
		return 0;
 | 
			
		||||
	if (!test_sta_flag(sta, WLAN_STA_INSERTED)) {
 | 
			
		||||
		ret = 0;
 | 
			
		||||
		goto hash;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = drv_change_sta_links(sdata->local, sdata, &sta->sta,
 | 
			
		||||
				   old_links, new_links);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -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 & ~BIT(link_id));
 | 
			
		||||
 | 
			
		||||
	sta_remove_link(sta, link_id);
 | 
			
		||||
	sta_remove_link(sta, link_id, true);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -491,6 +491,7 @@ struct ieee80211_fragment_cache {
 | 
			
		|||
 *	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
 | 
			
		||||
 *	and set to the corresponding vif LinkId for MLD STA
 | 
			
		||||
 * @link_hash_node: hash node for rhashtable
 | 
			
		||||
 * @sta: Points to the STA info
 | 
			
		||||
 * @gtk: group keys negotiated with this station, if any
 | 
			
		||||
 * @tx_stats: TX statistics
 | 
			
		||||
| 
						 | 
				
			
			@ -523,7 +524,7 @@ struct link_sta_info {
 | 
			
		|||
	u8 addr[ETH_ALEN];
 | 
			
		||||
	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 ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS +
 | 
			
		||||
| 
						 | 
				
			
			@ -824,6 +825,17 @@ struct sta_info *sta_info_get_by_addrs(struct ieee80211_local *local,
 | 
			
		|||
	rhl_for_each_entry_rcu(_sta, _tmp,				\
 | 
			
		||||
			       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!
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue