162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright 2002-2005, Instant802 Networks, Inc. 462306a36Sopenharmony_ci * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> 562306a36Sopenharmony_ci * Copyright 2013-2014 Intel Mobile Communications GmbH 662306a36Sopenharmony_ci * Copyright (C) 2015 - 2017 Intel Deutschland GmbH 762306a36Sopenharmony_ci * Copyright (C) 2018-2023 Intel Corporation 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/init.h> 1262306a36Sopenharmony_ci#include <linux/etherdevice.h> 1362306a36Sopenharmony_ci#include <linux/netdevice.h> 1462306a36Sopenharmony_ci#include <linux/types.h> 1562306a36Sopenharmony_ci#include <linux/slab.h> 1662306a36Sopenharmony_ci#include <linux/skbuff.h> 1762306a36Sopenharmony_ci#include <linux/if_arp.h> 1862306a36Sopenharmony_ci#include <linux/timer.h> 1962306a36Sopenharmony_ci#include <linux/rtnetlink.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <net/codel.h> 2262306a36Sopenharmony_ci#include <net/mac80211.h> 2362306a36Sopenharmony_ci#include "ieee80211_i.h" 2462306a36Sopenharmony_ci#include "driver-ops.h" 2562306a36Sopenharmony_ci#include "rate.h" 2662306a36Sopenharmony_ci#include "sta_info.h" 2762306a36Sopenharmony_ci#include "debugfs_sta.h" 2862306a36Sopenharmony_ci#include "mesh.h" 2962306a36Sopenharmony_ci#include "wme.h" 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/** 3262306a36Sopenharmony_ci * DOC: STA information lifetime rules 3362306a36Sopenharmony_ci * 3462306a36Sopenharmony_ci * STA info structures (&struct sta_info) are managed in a hash table 3562306a36Sopenharmony_ci * for faster lookup and a list for iteration. They are managed using 3662306a36Sopenharmony_ci * RCU, i.e. access to the list and hash table is protected by RCU. 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci * Upon allocating a STA info structure with sta_info_alloc(), the caller 3962306a36Sopenharmony_ci * owns that structure. It must then insert it into the hash table using 4062306a36Sopenharmony_ci * either sta_info_insert() or sta_info_insert_rcu(); only in the latter 4162306a36Sopenharmony_ci * case (which acquires an rcu read section but must not be called from 4262306a36Sopenharmony_ci * within one) will the pointer still be valid after the call. Note that 4362306a36Sopenharmony_ci * the caller may not do much with the STA info before inserting it, in 4462306a36Sopenharmony_ci * particular, it may not start any mesh peer link management or add 4562306a36Sopenharmony_ci * encryption keys. 4662306a36Sopenharmony_ci * 4762306a36Sopenharmony_ci * When the insertion fails (sta_info_insert()) returns non-zero), the 4862306a36Sopenharmony_ci * structure will have been freed by sta_info_insert()! 4962306a36Sopenharmony_ci * 5062306a36Sopenharmony_ci * Station entries are added by mac80211 when you establish a link with a 5162306a36Sopenharmony_ci * peer. This means different things for the different type of interfaces 5262306a36Sopenharmony_ci * we support. For a regular station this mean we add the AP sta when we 5362306a36Sopenharmony_ci * receive an association response from the AP. For IBSS this occurs when 5462306a36Sopenharmony_ci * get to know about a peer on the same IBSS. For WDS we add the sta for 5562306a36Sopenharmony_ci * the peer immediately upon device open. When using AP mode we add stations 5662306a36Sopenharmony_ci * for each respective station upon request from userspace through nl80211. 5762306a36Sopenharmony_ci * 5862306a36Sopenharmony_ci * In order to remove a STA info structure, various sta_info_destroy_*() 5962306a36Sopenharmony_ci * calls are available. 6062306a36Sopenharmony_ci * 6162306a36Sopenharmony_ci * There is no concept of ownership on a STA entry, each structure is 6262306a36Sopenharmony_ci * owned by the global hash table/list until it is removed. All users of 6362306a36Sopenharmony_ci * the structure need to be RCU protected so that the structure won't be 6462306a36Sopenharmony_ci * freed before they are done using it. 6562306a36Sopenharmony_ci */ 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistruct sta_link_alloc { 6862306a36Sopenharmony_ci struct link_sta_info info; 6962306a36Sopenharmony_ci struct ieee80211_link_sta sta; 7062306a36Sopenharmony_ci struct rcu_head rcu_head; 7162306a36Sopenharmony_ci}; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic const struct rhashtable_params sta_rht_params = { 7462306a36Sopenharmony_ci .nelem_hint = 3, /* start small */ 7562306a36Sopenharmony_ci .automatic_shrinking = true, 7662306a36Sopenharmony_ci .head_offset = offsetof(struct sta_info, hash_node), 7762306a36Sopenharmony_ci .key_offset = offsetof(struct sta_info, addr), 7862306a36Sopenharmony_ci .key_len = ETH_ALEN, 7962306a36Sopenharmony_ci .max_size = CONFIG_MAC80211_STA_HASH_MAX_SIZE, 8062306a36Sopenharmony_ci}; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic const struct rhashtable_params link_sta_rht_params = { 8362306a36Sopenharmony_ci .nelem_hint = 3, /* start small */ 8462306a36Sopenharmony_ci .automatic_shrinking = true, 8562306a36Sopenharmony_ci .head_offset = offsetof(struct link_sta_info, link_hash_node), 8662306a36Sopenharmony_ci .key_offset = offsetof(struct link_sta_info, addr), 8762306a36Sopenharmony_ci .key_len = ETH_ALEN, 8862306a36Sopenharmony_ci .max_size = CONFIG_MAC80211_STA_HASH_MAX_SIZE, 8962306a36Sopenharmony_ci}; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/* Caller must hold local->sta_mtx */ 9262306a36Sopenharmony_cistatic int sta_info_hash_del(struct ieee80211_local *local, 9362306a36Sopenharmony_ci struct sta_info *sta) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci return rhltable_remove(&local->sta_hash, &sta->hash_node, 9662306a36Sopenharmony_ci sta_rht_params); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic int link_sta_info_hash_add(struct ieee80211_local *local, 10062306a36Sopenharmony_ci struct link_sta_info *link_sta) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci lockdep_assert_held(&local->sta_mtx); 10362306a36Sopenharmony_ci return rhltable_insert(&local->link_sta_hash, 10462306a36Sopenharmony_ci &link_sta->link_hash_node, 10562306a36Sopenharmony_ci link_sta_rht_params); 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic int link_sta_info_hash_del(struct ieee80211_local *local, 10962306a36Sopenharmony_ci struct link_sta_info *link_sta) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci lockdep_assert_held(&local->sta_mtx); 11262306a36Sopenharmony_ci return rhltable_remove(&local->link_sta_hash, 11362306a36Sopenharmony_ci &link_sta->link_hash_node, 11462306a36Sopenharmony_ci link_sta_rht_params); 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic void __cleanup_single_sta(struct sta_info *sta) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci int ac, i; 12062306a36Sopenharmony_ci struct tid_ampdu_tx *tid_tx; 12162306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata = sta->sdata; 12262306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 12362306a36Sopenharmony_ci struct ps_data *ps; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (test_sta_flag(sta, WLAN_STA_PS_STA) || 12662306a36Sopenharmony_ci test_sta_flag(sta, WLAN_STA_PS_DRIVER) || 12762306a36Sopenharmony_ci test_sta_flag(sta, WLAN_STA_PS_DELIVER)) { 12862306a36Sopenharmony_ci if (sta->sdata->vif.type == NL80211_IFTYPE_AP || 12962306a36Sopenharmony_ci sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 13062306a36Sopenharmony_ci ps = &sdata->bss->ps; 13162306a36Sopenharmony_ci else if (ieee80211_vif_is_mesh(&sdata->vif)) 13262306a36Sopenharmony_ci ps = &sdata->u.mesh.ps; 13362306a36Sopenharmony_ci else 13462306a36Sopenharmony_ci return; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci clear_sta_flag(sta, WLAN_STA_PS_STA); 13762306a36Sopenharmony_ci clear_sta_flag(sta, WLAN_STA_PS_DRIVER); 13862306a36Sopenharmony_ci clear_sta_flag(sta, WLAN_STA_PS_DELIVER); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci atomic_dec(&ps->num_sta_ps); 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) { 14462306a36Sopenharmony_ci struct txq_info *txqi; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if (!sta->sta.txq[i]) 14762306a36Sopenharmony_ci continue; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci txqi = to_txq_info(sta->sta.txq[i]); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci ieee80211_txq_purge(local, txqi); 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { 15562306a36Sopenharmony_ci local->total_ps_buffered -= skb_queue_len(&sta->ps_tx_buf[ac]); 15662306a36Sopenharmony_ci ieee80211_purge_tx_queue(&local->hw, &sta->ps_tx_buf[ac]); 15762306a36Sopenharmony_ci ieee80211_purge_tx_queue(&local->hw, &sta->tx_filtered[ac]); 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci if (ieee80211_vif_is_mesh(&sdata->vif)) 16162306a36Sopenharmony_ci mesh_sta_cleanup(sta); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci cancel_work_sync(&sta->drv_deliver_wk); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci /* 16662306a36Sopenharmony_ci * Destroy aggregation state here. It would be nice to wait for the 16762306a36Sopenharmony_ci * driver to finish aggregation stop and then clean up, but for now 16862306a36Sopenharmony_ci * drivers have to handle aggregation stop being requested, followed 16962306a36Sopenharmony_ci * directly by station destruction. 17062306a36Sopenharmony_ci */ 17162306a36Sopenharmony_ci for (i = 0; i < IEEE80211_NUM_TIDS; i++) { 17262306a36Sopenharmony_ci kfree(sta->ampdu_mlme.tid_start_tx[i]); 17362306a36Sopenharmony_ci tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]); 17462306a36Sopenharmony_ci if (!tid_tx) 17562306a36Sopenharmony_ci continue; 17662306a36Sopenharmony_ci ieee80211_purge_tx_queue(&local->hw, &tid_tx->pending); 17762306a36Sopenharmony_ci kfree(tid_tx); 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic void cleanup_single_sta(struct sta_info *sta) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata = sta->sdata; 18462306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci __cleanup_single_sta(sta); 18762306a36Sopenharmony_ci sta_info_free(local, sta); 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistruct rhlist_head *sta_info_hash_lookup(struct ieee80211_local *local, 19162306a36Sopenharmony_ci const u8 *addr) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci return rhltable_lookup(&local->sta_hash, addr, sta_rht_params); 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci/* protected by RCU */ 19762306a36Sopenharmony_cistruct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, 19862306a36Sopenharmony_ci const u8 *addr) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 20162306a36Sopenharmony_ci struct rhlist_head *tmp; 20262306a36Sopenharmony_ci struct sta_info *sta; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci rcu_read_lock(); 20562306a36Sopenharmony_ci for_each_sta_info(local, addr, sta, tmp) { 20662306a36Sopenharmony_ci if (sta->sdata == sdata) { 20762306a36Sopenharmony_ci rcu_read_unlock(); 20862306a36Sopenharmony_ci /* this is safe as the caller must already hold 20962306a36Sopenharmony_ci * another rcu read section or the mutex 21062306a36Sopenharmony_ci */ 21162306a36Sopenharmony_ci return sta; 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci rcu_read_unlock(); 21562306a36Sopenharmony_ci return NULL; 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci/* 21962306a36Sopenharmony_ci * Get sta info either from the specified interface 22062306a36Sopenharmony_ci * or from one of its vlans 22162306a36Sopenharmony_ci */ 22262306a36Sopenharmony_cistruct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata, 22362306a36Sopenharmony_ci const u8 *addr) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 22662306a36Sopenharmony_ci struct rhlist_head *tmp; 22762306a36Sopenharmony_ci struct sta_info *sta; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci rcu_read_lock(); 23062306a36Sopenharmony_ci for_each_sta_info(local, addr, sta, tmp) { 23162306a36Sopenharmony_ci if (sta->sdata == sdata || 23262306a36Sopenharmony_ci (sta->sdata->bss && sta->sdata->bss == sdata->bss)) { 23362306a36Sopenharmony_ci rcu_read_unlock(); 23462306a36Sopenharmony_ci /* this is safe as the caller must already hold 23562306a36Sopenharmony_ci * another rcu read section or the mutex 23662306a36Sopenharmony_ci */ 23762306a36Sopenharmony_ci return sta; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci rcu_read_unlock(); 24162306a36Sopenharmony_ci return NULL; 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistruct rhlist_head *link_sta_info_hash_lookup(struct ieee80211_local *local, 24562306a36Sopenharmony_ci const u8 *addr) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci return rhltable_lookup(&local->link_sta_hash, addr, 24862306a36Sopenharmony_ci link_sta_rht_params); 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistruct link_sta_info * 25262306a36Sopenharmony_cilink_sta_info_get_bss(struct ieee80211_sub_if_data *sdata, const u8 *addr) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 25562306a36Sopenharmony_ci struct rhlist_head *tmp; 25662306a36Sopenharmony_ci struct link_sta_info *link_sta; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci rcu_read_lock(); 25962306a36Sopenharmony_ci for_each_link_sta_info(local, addr, link_sta, tmp) { 26062306a36Sopenharmony_ci struct sta_info *sta = link_sta->sta; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci if (sta->sdata == sdata || 26362306a36Sopenharmony_ci (sta->sdata->bss && sta->sdata->bss == sdata->bss)) { 26462306a36Sopenharmony_ci rcu_read_unlock(); 26562306a36Sopenharmony_ci /* this is safe as the caller must already hold 26662306a36Sopenharmony_ci * another rcu read section or the mutex 26762306a36Sopenharmony_ci */ 26862306a36Sopenharmony_ci return link_sta; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci rcu_read_unlock(); 27262306a36Sopenharmony_ci return NULL; 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistruct ieee80211_sta * 27662306a36Sopenharmony_ciieee80211_find_sta_by_link_addrs(struct ieee80211_hw *hw, 27762306a36Sopenharmony_ci const u8 *addr, 27862306a36Sopenharmony_ci const u8 *localaddr, 27962306a36Sopenharmony_ci unsigned int *link_id) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci struct ieee80211_local *local = hw_to_local(hw); 28262306a36Sopenharmony_ci struct link_sta_info *link_sta; 28362306a36Sopenharmony_ci struct rhlist_head *tmp; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci for_each_link_sta_info(local, addr, link_sta, tmp) { 28662306a36Sopenharmony_ci struct sta_info *sta = link_sta->sta; 28762306a36Sopenharmony_ci struct ieee80211_link_data *link; 28862306a36Sopenharmony_ci u8 _link_id = link_sta->link_id; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci if (!localaddr) { 29162306a36Sopenharmony_ci if (link_id) 29262306a36Sopenharmony_ci *link_id = _link_id; 29362306a36Sopenharmony_ci return &sta->sta; 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci link = rcu_dereference(sta->sdata->link[_link_id]); 29762306a36Sopenharmony_ci if (!link) 29862306a36Sopenharmony_ci continue; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci if (memcmp(link->conf->addr, localaddr, ETH_ALEN)) 30162306a36Sopenharmony_ci continue; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci if (link_id) 30462306a36Sopenharmony_ci *link_id = _link_id; 30562306a36Sopenharmony_ci return &sta->sta; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci return NULL; 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ieee80211_find_sta_by_link_addrs); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cistruct sta_info *sta_info_get_by_addrs(struct ieee80211_local *local, 31362306a36Sopenharmony_ci const u8 *sta_addr, const u8 *vif_addr) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci struct rhlist_head *tmp; 31662306a36Sopenharmony_ci struct sta_info *sta; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci for_each_sta_info(local, sta_addr, sta, tmp) { 31962306a36Sopenharmony_ci if (ether_addr_equal(vif_addr, sta->sdata->vif.addr)) 32062306a36Sopenharmony_ci return sta; 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci return NULL; 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cistruct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata, 32762306a36Sopenharmony_ci int idx) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 33062306a36Sopenharmony_ci struct sta_info *sta; 33162306a36Sopenharmony_ci int i = 0; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci list_for_each_entry_rcu(sta, &local->sta_list, list, 33462306a36Sopenharmony_ci lockdep_is_held(&local->sta_mtx)) { 33562306a36Sopenharmony_ci if (sdata != sta->sdata) 33662306a36Sopenharmony_ci continue; 33762306a36Sopenharmony_ci if (i < idx) { 33862306a36Sopenharmony_ci ++i; 33962306a36Sopenharmony_ci continue; 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci return sta; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci return NULL; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic void sta_info_free_link(struct link_sta_info *link_sta) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci free_percpu(link_sta->pcpu_rx_stats); 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_cistatic void sta_remove_link(struct sta_info *sta, unsigned int link_id, 35362306a36Sopenharmony_ci bool unhash) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci struct sta_link_alloc *alloc = NULL; 35662306a36Sopenharmony_ci struct link_sta_info *link_sta; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci link_sta = rcu_access_pointer(sta->link[link_id]); 35962306a36Sopenharmony_ci if (link_sta != &sta->deflink) 36062306a36Sopenharmony_ci lockdep_assert_held(&sta->local->sta_mtx); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci if (WARN_ON(!link_sta)) 36362306a36Sopenharmony_ci return; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci if (unhash) 36662306a36Sopenharmony_ci link_sta_info_hash_del(sta->local, link_sta); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci if (test_sta_flag(sta, WLAN_STA_INSERTED)) 36962306a36Sopenharmony_ci ieee80211_link_sta_debugfs_remove(link_sta); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci if (link_sta != &sta->deflink) 37262306a36Sopenharmony_ci alloc = container_of(link_sta, typeof(*alloc), info); 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci sta->sta.valid_links &= ~BIT(link_id); 37562306a36Sopenharmony_ci RCU_INIT_POINTER(sta->link[link_id], NULL); 37662306a36Sopenharmony_ci RCU_INIT_POINTER(sta->sta.link[link_id], NULL); 37762306a36Sopenharmony_ci if (alloc) { 37862306a36Sopenharmony_ci sta_info_free_link(&alloc->info); 37962306a36Sopenharmony_ci kfree_rcu(alloc, rcu_head); 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci ieee80211_sta_recalc_aggregates(&sta->sta); 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci/** 38662306a36Sopenharmony_ci * sta_info_free - free STA 38762306a36Sopenharmony_ci * 38862306a36Sopenharmony_ci * @local: pointer to the global information 38962306a36Sopenharmony_ci * @sta: STA info to free 39062306a36Sopenharmony_ci * 39162306a36Sopenharmony_ci * This function must undo everything done by sta_info_alloc() 39262306a36Sopenharmony_ci * that may happen before sta_info_insert(). It may only be 39362306a36Sopenharmony_ci * called when sta_info_insert() has not been attempted (and 39462306a36Sopenharmony_ci * if that fails, the station is freed anyway.) 39562306a36Sopenharmony_ci */ 39662306a36Sopenharmony_civoid sta_info_free(struct ieee80211_local *local, struct sta_info *sta) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci int i; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sta->link); i++) { 40162306a36Sopenharmony_ci struct link_sta_info *link_sta; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci link_sta = rcu_access_pointer(sta->link[i]); 40462306a36Sopenharmony_ci if (!link_sta) 40562306a36Sopenharmony_ci continue; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci sta_remove_link(sta, i, false); 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci /* 41162306a36Sopenharmony_ci * If we had used sta_info_pre_move_state() then we might not 41262306a36Sopenharmony_ci * have gone through the state transitions down again, so do 41362306a36Sopenharmony_ci * it here now (and warn if it's inserted). 41462306a36Sopenharmony_ci * 41562306a36Sopenharmony_ci * This will clear state such as fast TX/RX that may have been 41662306a36Sopenharmony_ci * allocated during state transitions. 41762306a36Sopenharmony_ci */ 41862306a36Sopenharmony_ci while (sta->sta_state > IEEE80211_STA_NONE) { 41962306a36Sopenharmony_ci int ret; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci WARN_ON_ONCE(test_sta_flag(sta, WLAN_STA_INSERTED)); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci ret = sta_info_move_state(sta, sta->sta_state - 1); 42462306a36Sopenharmony_ci if (WARN_ONCE(ret, "sta_info_move_state() returned %d\n", ret)) 42562306a36Sopenharmony_ci break; 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci if (sta->rate_ctrl) 42962306a36Sopenharmony_ci rate_control_free_sta(sta); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci kfree(to_txq_info(sta->sta.txq[0])); 43462306a36Sopenharmony_ci kfree(rcu_dereference_raw(sta->sta.rates)); 43562306a36Sopenharmony_ci#ifdef CONFIG_MAC80211_MESH 43662306a36Sopenharmony_ci kfree(sta->mesh); 43762306a36Sopenharmony_ci#endif 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci sta_info_free_link(&sta->deflink); 44062306a36Sopenharmony_ci kfree(sta); 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci/* Caller must hold local->sta_mtx */ 44462306a36Sopenharmony_cistatic int sta_info_hash_add(struct ieee80211_local *local, 44562306a36Sopenharmony_ci struct sta_info *sta) 44662306a36Sopenharmony_ci{ 44762306a36Sopenharmony_ci return rhltable_insert(&local->sta_hash, &sta->hash_node, 44862306a36Sopenharmony_ci sta_rht_params); 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic void sta_deliver_ps_frames(struct work_struct *wk) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci struct sta_info *sta; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci sta = container_of(wk, struct sta_info, drv_deliver_wk); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci if (sta->dead) 45862306a36Sopenharmony_ci return; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci local_bh_disable(); 46162306a36Sopenharmony_ci if (!test_sta_flag(sta, WLAN_STA_PS_STA)) 46262306a36Sopenharmony_ci ieee80211_sta_ps_deliver_wakeup(sta); 46362306a36Sopenharmony_ci else if (test_and_clear_sta_flag(sta, WLAN_STA_PSPOLL)) 46462306a36Sopenharmony_ci ieee80211_sta_ps_deliver_poll_response(sta); 46562306a36Sopenharmony_ci else if (test_and_clear_sta_flag(sta, WLAN_STA_UAPSD)) 46662306a36Sopenharmony_ci ieee80211_sta_ps_deliver_uapsd(sta); 46762306a36Sopenharmony_ci local_bh_enable(); 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_cistatic int sta_prepare_rate_control(struct ieee80211_local *local, 47162306a36Sopenharmony_ci struct sta_info *sta, gfp_t gfp) 47262306a36Sopenharmony_ci{ 47362306a36Sopenharmony_ci if (ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL)) 47462306a36Sopenharmony_ci return 0; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci sta->rate_ctrl = local->rate_ctrl; 47762306a36Sopenharmony_ci sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl, 47862306a36Sopenharmony_ci sta, gfp); 47962306a36Sopenharmony_ci if (!sta->rate_ctrl_priv) 48062306a36Sopenharmony_ci return -ENOMEM; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci return 0; 48362306a36Sopenharmony_ci} 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_cistatic int sta_info_alloc_link(struct ieee80211_local *local, 48662306a36Sopenharmony_ci struct link_sta_info *link_info, 48762306a36Sopenharmony_ci gfp_t gfp) 48862306a36Sopenharmony_ci{ 48962306a36Sopenharmony_ci struct ieee80211_hw *hw = &local->hw; 49062306a36Sopenharmony_ci int i; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci if (ieee80211_hw_check(hw, USES_RSS)) { 49362306a36Sopenharmony_ci link_info->pcpu_rx_stats = 49462306a36Sopenharmony_ci alloc_percpu_gfp(struct ieee80211_sta_rx_stats, gfp); 49562306a36Sopenharmony_ci if (!link_info->pcpu_rx_stats) 49662306a36Sopenharmony_ci return -ENOMEM; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci link_info->rx_stats.last_rx = jiffies; 50062306a36Sopenharmony_ci u64_stats_init(&link_info->rx_stats.syncp); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci ewma_signal_init(&link_info->rx_stats_avg.signal); 50362306a36Sopenharmony_ci ewma_avg_signal_init(&link_info->status_stats.avg_ack_signal); 50462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(link_info->rx_stats_avg.chain_signal); i++) 50562306a36Sopenharmony_ci ewma_signal_init(&link_info->rx_stats_avg.chain_signal[i]); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci return 0; 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_cistatic void sta_info_add_link(struct sta_info *sta, 51162306a36Sopenharmony_ci unsigned int link_id, 51262306a36Sopenharmony_ci struct link_sta_info *link_info, 51362306a36Sopenharmony_ci struct ieee80211_link_sta *link_sta) 51462306a36Sopenharmony_ci{ 51562306a36Sopenharmony_ci link_info->sta = sta; 51662306a36Sopenharmony_ci link_info->link_id = link_id; 51762306a36Sopenharmony_ci link_info->pub = link_sta; 51862306a36Sopenharmony_ci link_info->pub->sta = &sta->sta; 51962306a36Sopenharmony_ci link_sta->link_id = link_id; 52062306a36Sopenharmony_ci rcu_assign_pointer(sta->link[link_id], link_info); 52162306a36Sopenharmony_ci rcu_assign_pointer(sta->sta.link[link_id], link_sta); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci link_sta->smps_mode = IEEE80211_SMPS_OFF; 52462306a36Sopenharmony_ci link_sta->agg.max_rc_amsdu_len = IEEE80211_MAX_MPDU_LEN_HT_BA; 52562306a36Sopenharmony_ci} 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_cistatic struct sta_info * 52862306a36Sopenharmony_ci__sta_info_alloc(struct ieee80211_sub_if_data *sdata, 52962306a36Sopenharmony_ci const u8 *addr, int link_id, const u8 *link_addr, 53062306a36Sopenharmony_ci gfp_t gfp) 53162306a36Sopenharmony_ci{ 53262306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 53362306a36Sopenharmony_ci struct ieee80211_hw *hw = &local->hw; 53462306a36Sopenharmony_ci struct sta_info *sta; 53562306a36Sopenharmony_ci void *txq_data; 53662306a36Sopenharmony_ci int size; 53762306a36Sopenharmony_ci int i; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci sta = kzalloc(sizeof(*sta) + hw->sta_data_size, gfp); 54062306a36Sopenharmony_ci if (!sta) 54162306a36Sopenharmony_ci return NULL; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci sta->local = local; 54462306a36Sopenharmony_ci sta->sdata = sdata; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci if (sta_info_alloc_link(local, &sta->deflink, gfp)) 54762306a36Sopenharmony_ci goto free; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci if (link_id >= 0) { 55062306a36Sopenharmony_ci sta_info_add_link(sta, link_id, &sta->deflink, 55162306a36Sopenharmony_ci &sta->sta.deflink); 55262306a36Sopenharmony_ci sta->sta.valid_links = BIT(link_id); 55362306a36Sopenharmony_ci } else { 55462306a36Sopenharmony_ci sta_info_add_link(sta, 0, &sta->deflink, &sta->sta.deflink); 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci sta->sta.cur = &sta->sta.deflink.agg; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci spin_lock_init(&sta->lock); 56062306a36Sopenharmony_ci spin_lock_init(&sta->ps_lock); 56162306a36Sopenharmony_ci INIT_WORK(&sta->drv_deliver_wk, sta_deliver_ps_frames); 56262306a36Sopenharmony_ci INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); 56362306a36Sopenharmony_ci mutex_init(&sta->ampdu_mlme.mtx); 56462306a36Sopenharmony_ci#ifdef CONFIG_MAC80211_MESH 56562306a36Sopenharmony_ci if (ieee80211_vif_is_mesh(&sdata->vif)) { 56662306a36Sopenharmony_ci sta->mesh = kzalloc(sizeof(*sta->mesh), gfp); 56762306a36Sopenharmony_ci if (!sta->mesh) 56862306a36Sopenharmony_ci goto free; 56962306a36Sopenharmony_ci sta->mesh->plink_sta = sta; 57062306a36Sopenharmony_ci spin_lock_init(&sta->mesh->plink_lock); 57162306a36Sopenharmony_ci if (!sdata->u.mesh.user_mpm) 57262306a36Sopenharmony_ci timer_setup(&sta->mesh->plink_timer, mesh_plink_timer, 57362306a36Sopenharmony_ci 0); 57462306a36Sopenharmony_ci sta->mesh->nonpeer_pm = NL80211_MESH_POWER_ACTIVE; 57562306a36Sopenharmony_ci } 57662306a36Sopenharmony_ci#endif 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci memcpy(sta->addr, addr, ETH_ALEN); 57962306a36Sopenharmony_ci memcpy(sta->sta.addr, addr, ETH_ALEN); 58062306a36Sopenharmony_ci memcpy(sta->deflink.addr, link_addr, ETH_ALEN); 58162306a36Sopenharmony_ci memcpy(sta->sta.deflink.addr, link_addr, ETH_ALEN); 58262306a36Sopenharmony_ci sta->sta.max_rx_aggregation_subframes = 58362306a36Sopenharmony_ci local->hw.max_rx_aggregation_subframes; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci /* TODO link specific alloc and assignments for MLO Link STA */ 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci /* Extended Key ID needs to install keys for keyid 0 and 1 Rx-only. 58862306a36Sopenharmony_ci * The Tx path starts to use a key as soon as the key slot ptk_idx 58962306a36Sopenharmony_ci * references to is not NULL. To not use the initial Rx-only key 59062306a36Sopenharmony_ci * prematurely for Tx initialize ptk_idx to an impossible PTK keyid 59162306a36Sopenharmony_ci * which always will refer to a NULL key. 59262306a36Sopenharmony_ci */ 59362306a36Sopenharmony_ci BUILD_BUG_ON(ARRAY_SIZE(sta->ptk) <= INVALID_PTK_KEYIDX); 59462306a36Sopenharmony_ci sta->ptk_idx = INVALID_PTK_KEYIDX; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci ieee80211_init_frag_cache(&sta->frags); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci sta->sta_state = IEEE80211_STA_NONE; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT) 60262306a36Sopenharmony_ci sta->amsdu_mesh_control = -1; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci /* Mark TID as unreserved */ 60562306a36Sopenharmony_ci sta->reserved_tid = IEEE80211_TID_UNRESERVED; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci sta->last_connected = ktime_get_seconds(); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci size = sizeof(struct txq_info) + 61062306a36Sopenharmony_ci ALIGN(hw->txq_data_size, sizeof(void *)); 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci txq_data = kcalloc(ARRAY_SIZE(sta->sta.txq), size, gfp); 61362306a36Sopenharmony_ci if (!txq_data) 61462306a36Sopenharmony_ci goto free; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) { 61762306a36Sopenharmony_ci struct txq_info *txq = txq_data + i * size; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci /* might not do anything for the (bufferable) MMPDU TXQ */ 62062306a36Sopenharmony_ci ieee80211_txq_init(sdata, sta, txq, i); 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci if (sta_prepare_rate_control(local, sta, gfp)) 62462306a36Sopenharmony_ci goto free_txq; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci sta->airtime_weight = IEEE80211_DEFAULT_AIRTIME_WEIGHT; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci for (i = 0; i < IEEE80211_NUM_ACS; i++) { 62962306a36Sopenharmony_ci skb_queue_head_init(&sta->ps_tx_buf[i]); 63062306a36Sopenharmony_ci skb_queue_head_init(&sta->tx_filtered[i]); 63162306a36Sopenharmony_ci sta->airtime[i].deficit = sta->airtime_weight; 63262306a36Sopenharmony_ci atomic_set(&sta->airtime[i].aql_tx_pending, 0); 63362306a36Sopenharmony_ci sta->airtime[i].aql_limit_low = local->aql_txq_limit_low[i]; 63462306a36Sopenharmony_ci sta->airtime[i].aql_limit_high = local->aql_txq_limit_high[i]; 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci for (i = 0; i < IEEE80211_NUM_TIDS; i++) 63862306a36Sopenharmony_ci sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX); 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci for (i = 0; i < NUM_NL80211_BANDS; i++) { 64162306a36Sopenharmony_ci u32 mandatory = 0; 64262306a36Sopenharmony_ci int r; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci if (!hw->wiphy->bands[i]) 64562306a36Sopenharmony_ci continue; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci switch (i) { 64862306a36Sopenharmony_ci case NL80211_BAND_2GHZ: 64962306a36Sopenharmony_ci case NL80211_BAND_LC: 65062306a36Sopenharmony_ci /* 65162306a36Sopenharmony_ci * We use both here, even if we cannot really know for 65262306a36Sopenharmony_ci * sure the station will support both, but the only use 65362306a36Sopenharmony_ci * for this is when we don't know anything yet and send 65462306a36Sopenharmony_ci * management frames, and then we'll pick the lowest 65562306a36Sopenharmony_ci * possible rate anyway. 65662306a36Sopenharmony_ci * If we don't include _G here, we cannot find a rate 65762306a36Sopenharmony_ci * in P2P, and thus trigger the WARN_ONCE() in rate.c 65862306a36Sopenharmony_ci */ 65962306a36Sopenharmony_ci mandatory = IEEE80211_RATE_MANDATORY_B | 66062306a36Sopenharmony_ci IEEE80211_RATE_MANDATORY_G; 66162306a36Sopenharmony_ci break; 66262306a36Sopenharmony_ci case NL80211_BAND_5GHZ: 66362306a36Sopenharmony_ci mandatory = IEEE80211_RATE_MANDATORY_A; 66462306a36Sopenharmony_ci break; 66562306a36Sopenharmony_ci case NL80211_BAND_60GHZ: 66662306a36Sopenharmony_ci WARN_ON(1); 66762306a36Sopenharmony_ci mandatory = 0; 66862306a36Sopenharmony_ci break; 66962306a36Sopenharmony_ci } 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci for (r = 0; r < hw->wiphy->bands[i]->n_bitrates; r++) { 67262306a36Sopenharmony_ci struct ieee80211_rate *rate; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci rate = &hw->wiphy->bands[i]->bitrates[r]; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci if (!(rate->flags & mandatory)) 67762306a36Sopenharmony_ci continue; 67862306a36Sopenharmony_ci sta->sta.deflink.supp_rates[i] |= BIT(r); 67962306a36Sopenharmony_ci } 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci sta->cparams.ce_threshold = CODEL_DISABLED_THRESHOLD; 68362306a36Sopenharmony_ci sta->cparams.target = MS2TIME(20); 68462306a36Sopenharmony_ci sta->cparams.interval = MS2TIME(100); 68562306a36Sopenharmony_ci sta->cparams.ecn = true; 68662306a36Sopenharmony_ci sta->cparams.ce_threshold_selector = 0; 68762306a36Sopenharmony_ci sta->cparams.ce_threshold_mask = 0; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci return sta; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_cifree_txq: 69462306a36Sopenharmony_ci kfree(to_txq_info(sta->sta.txq[0])); 69562306a36Sopenharmony_cifree: 69662306a36Sopenharmony_ci sta_info_free_link(&sta->deflink); 69762306a36Sopenharmony_ci#ifdef CONFIG_MAC80211_MESH 69862306a36Sopenharmony_ci kfree(sta->mesh); 69962306a36Sopenharmony_ci#endif 70062306a36Sopenharmony_ci kfree(sta); 70162306a36Sopenharmony_ci return NULL; 70262306a36Sopenharmony_ci} 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_cistruct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, 70562306a36Sopenharmony_ci const u8 *addr, gfp_t gfp) 70662306a36Sopenharmony_ci{ 70762306a36Sopenharmony_ci return __sta_info_alloc(sdata, addr, -1, addr, gfp); 70862306a36Sopenharmony_ci} 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_cistruct sta_info *sta_info_alloc_with_link(struct ieee80211_sub_if_data *sdata, 71162306a36Sopenharmony_ci const u8 *mld_addr, 71262306a36Sopenharmony_ci unsigned int link_id, 71362306a36Sopenharmony_ci const u8 *link_addr, 71462306a36Sopenharmony_ci gfp_t gfp) 71562306a36Sopenharmony_ci{ 71662306a36Sopenharmony_ci return __sta_info_alloc(sdata, mld_addr, link_id, link_addr, gfp); 71762306a36Sopenharmony_ci} 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_cistatic int sta_info_insert_check(struct sta_info *sta) 72062306a36Sopenharmony_ci{ 72162306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata = sta->sdata; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci /* 72462306a36Sopenharmony_ci * Can't be a WARN_ON because it can be triggered through a race: 72562306a36Sopenharmony_ci * something inserts a STA (on one CPU) without holding the RTNL 72662306a36Sopenharmony_ci * and another CPU turns off the net device. 72762306a36Sopenharmony_ci */ 72862306a36Sopenharmony_ci if (unlikely(!ieee80211_sdata_running(sdata))) 72962306a36Sopenharmony_ci return -ENETDOWN; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci if (WARN_ON(ether_addr_equal(sta->sta.addr, sdata->vif.addr) || 73262306a36Sopenharmony_ci !is_valid_ether_addr(sta->sta.addr))) 73362306a36Sopenharmony_ci return -EINVAL; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci /* The RCU read lock is required by rhashtable due to 73662306a36Sopenharmony_ci * asynchronous resize/rehash. We also require the mutex 73762306a36Sopenharmony_ci * for correctness. 73862306a36Sopenharmony_ci */ 73962306a36Sopenharmony_ci rcu_read_lock(); 74062306a36Sopenharmony_ci lockdep_assert_held(&sdata->local->sta_mtx); 74162306a36Sopenharmony_ci if (ieee80211_hw_check(&sdata->local->hw, NEEDS_UNIQUE_STA_ADDR) && 74262306a36Sopenharmony_ci ieee80211_find_sta_by_ifaddr(&sdata->local->hw, sta->addr, NULL)) { 74362306a36Sopenharmony_ci rcu_read_unlock(); 74462306a36Sopenharmony_ci return -ENOTUNIQ; 74562306a36Sopenharmony_ci } 74662306a36Sopenharmony_ci rcu_read_unlock(); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci return 0; 74962306a36Sopenharmony_ci} 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_cistatic int sta_info_insert_drv_state(struct ieee80211_local *local, 75262306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata, 75362306a36Sopenharmony_ci struct sta_info *sta) 75462306a36Sopenharmony_ci{ 75562306a36Sopenharmony_ci enum ieee80211_sta_state state; 75662306a36Sopenharmony_ci int err = 0; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci for (state = IEEE80211_STA_NOTEXIST; state < sta->sta_state; state++) { 75962306a36Sopenharmony_ci err = drv_sta_state(local, sdata, sta, state, state + 1); 76062306a36Sopenharmony_ci if (err) 76162306a36Sopenharmony_ci break; 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci if (!err) { 76562306a36Sopenharmony_ci /* 76662306a36Sopenharmony_ci * Drivers using legacy sta_add/sta_remove callbacks only 76762306a36Sopenharmony_ci * get uploaded set to true after sta_add is called. 76862306a36Sopenharmony_ci */ 76962306a36Sopenharmony_ci if (!local->ops->sta_add) 77062306a36Sopenharmony_ci sta->uploaded = true; 77162306a36Sopenharmony_ci return 0; 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { 77562306a36Sopenharmony_ci sdata_info(sdata, 77662306a36Sopenharmony_ci "failed to move IBSS STA %pM to state %d (%d) - keeping it anyway\n", 77762306a36Sopenharmony_ci sta->sta.addr, state + 1, err); 77862306a36Sopenharmony_ci err = 0; 77962306a36Sopenharmony_ci } 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci /* unwind on error */ 78262306a36Sopenharmony_ci for (; state > IEEE80211_STA_NOTEXIST; state--) 78362306a36Sopenharmony_ci WARN_ON(drv_sta_state(local, sdata, sta, state, state - 1)); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci return err; 78662306a36Sopenharmony_ci} 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_cistatic void 78962306a36Sopenharmony_ciieee80211_recalc_p2p_go_ps_allowed(struct ieee80211_sub_if_data *sdata) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 79262306a36Sopenharmony_ci bool allow_p2p_go_ps = sdata->vif.p2p; 79362306a36Sopenharmony_ci struct sta_info *sta; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci rcu_read_lock(); 79662306a36Sopenharmony_ci list_for_each_entry_rcu(sta, &local->sta_list, list) { 79762306a36Sopenharmony_ci if (sdata != sta->sdata || 79862306a36Sopenharmony_ci !test_sta_flag(sta, WLAN_STA_ASSOC)) 79962306a36Sopenharmony_ci continue; 80062306a36Sopenharmony_ci if (!sta->sta.support_p2p_ps) { 80162306a36Sopenharmony_ci allow_p2p_go_ps = false; 80262306a36Sopenharmony_ci break; 80362306a36Sopenharmony_ci } 80462306a36Sopenharmony_ci } 80562306a36Sopenharmony_ci rcu_read_unlock(); 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci if (allow_p2p_go_ps != sdata->vif.bss_conf.allow_p2p_go_ps) { 80862306a36Sopenharmony_ci sdata->vif.bss_conf.allow_p2p_go_ps = allow_p2p_go_ps; 80962306a36Sopenharmony_ci ieee80211_link_info_change_notify(sdata, &sdata->deflink, 81062306a36Sopenharmony_ci BSS_CHANGED_P2P_PS); 81162306a36Sopenharmony_ci } 81262306a36Sopenharmony_ci} 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci/* 81562306a36Sopenharmony_ci * should be called with sta_mtx locked 81662306a36Sopenharmony_ci * this function replaces the mutex lock 81762306a36Sopenharmony_ci * with a RCU lock 81862306a36Sopenharmony_ci */ 81962306a36Sopenharmony_cistatic int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) 82062306a36Sopenharmony_ci{ 82162306a36Sopenharmony_ci struct ieee80211_local *local = sta->local; 82262306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata = sta->sdata; 82362306a36Sopenharmony_ci struct station_info *sinfo = NULL; 82462306a36Sopenharmony_ci int err = 0; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci lockdep_assert_held(&local->sta_mtx); 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci /* check if STA exists already */ 82962306a36Sopenharmony_ci if (sta_info_get_bss(sdata, sta->sta.addr)) { 83062306a36Sopenharmony_ci err = -EEXIST; 83162306a36Sopenharmony_ci goto out_cleanup; 83262306a36Sopenharmony_ci } 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci sinfo = kzalloc(sizeof(struct station_info), GFP_KERNEL); 83562306a36Sopenharmony_ci if (!sinfo) { 83662306a36Sopenharmony_ci err = -ENOMEM; 83762306a36Sopenharmony_ci goto out_cleanup; 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci local->num_sta++; 84162306a36Sopenharmony_ci local->sta_generation++; 84262306a36Sopenharmony_ci smp_mb(); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci /* simplify things and don't accept BA sessions yet */ 84562306a36Sopenharmony_ci set_sta_flag(sta, WLAN_STA_BLOCK_BA); 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci /* make the station visible */ 84862306a36Sopenharmony_ci err = sta_info_hash_add(local, sta); 84962306a36Sopenharmony_ci if (err) 85062306a36Sopenharmony_ci goto out_drop_sta; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci if (sta->sta.valid_links) { 85362306a36Sopenharmony_ci err = link_sta_info_hash_add(local, &sta->deflink); 85462306a36Sopenharmony_ci if (err) { 85562306a36Sopenharmony_ci sta_info_hash_del(local, sta); 85662306a36Sopenharmony_ci goto out_drop_sta; 85762306a36Sopenharmony_ci } 85862306a36Sopenharmony_ci } 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci list_add_tail_rcu(&sta->list, &local->sta_list); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci /* update channel context before notifying the driver about state 86362306a36Sopenharmony_ci * change, this enables driver using the updated channel context right away. 86462306a36Sopenharmony_ci */ 86562306a36Sopenharmony_ci if (sta->sta_state >= IEEE80211_STA_ASSOC) { 86662306a36Sopenharmony_ci ieee80211_recalc_min_chandef(sta->sdata, -1); 86762306a36Sopenharmony_ci if (!sta->sta.support_p2p_ps) 86862306a36Sopenharmony_ci ieee80211_recalc_p2p_go_ps_allowed(sta->sdata); 86962306a36Sopenharmony_ci } 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci /* notify driver */ 87262306a36Sopenharmony_ci err = sta_info_insert_drv_state(local, sdata, sta); 87362306a36Sopenharmony_ci if (err) 87462306a36Sopenharmony_ci goto out_remove; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci set_sta_flag(sta, WLAN_STA_INSERTED); 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci /* accept BA sessions now */ 87962306a36Sopenharmony_ci clear_sta_flag(sta, WLAN_STA_BLOCK_BA); 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci ieee80211_sta_debugfs_add(sta); 88262306a36Sopenharmony_ci rate_control_add_sta_debugfs(sta); 88362306a36Sopenharmony_ci if (sta->sta.valid_links) { 88462306a36Sopenharmony_ci int i; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sta->link); i++) { 88762306a36Sopenharmony_ci struct link_sta_info *link_sta; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci link_sta = rcu_dereference_protected(sta->link[i], 89062306a36Sopenharmony_ci lockdep_is_held(&local->sta_mtx)); 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci if (!link_sta) 89362306a36Sopenharmony_ci continue; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci ieee80211_link_sta_debugfs_add(link_sta); 89662306a36Sopenharmony_ci if (sdata->vif.active_links & BIT(i)) 89762306a36Sopenharmony_ci ieee80211_link_sta_debugfs_drv_add(link_sta); 89862306a36Sopenharmony_ci } 89962306a36Sopenharmony_ci } else { 90062306a36Sopenharmony_ci ieee80211_link_sta_debugfs_add(&sta->deflink); 90162306a36Sopenharmony_ci ieee80211_link_sta_debugfs_drv_add(&sta->deflink); 90262306a36Sopenharmony_ci } 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci sinfo->generation = local->sta_generation; 90562306a36Sopenharmony_ci cfg80211_new_sta(sdata->dev, sta->sta.addr, sinfo, GFP_KERNEL); 90662306a36Sopenharmony_ci kfree(sinfo); 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci sta_dbg(sdata, "Inserted STA %pM\n", sta->sta.addr); 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci /* move reference to rcu-protected */ 91162306a36Sopenharmony_ci rcu_read_lock(); 91262306a36Sopenharmony_ci mutex_unlock(&local->sta_mtx); 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci if (ieee80211_vif_is_mesh(&sdata->vif)) 91562306a36Sopenharmony_ci mesh_accept_plinks_update(sdata); 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci ieee80211_check_fast_xmit(sta); 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci return 0; 92062306a36Sopenharmony_ci out_remove: 92162306a36Sopenharmony_ci if (sta->sta.valid_links) 92262306a36Sopenharmony_ci link_sta_info_hash_del(local, &sta->deflink); 92362306a36Sopenharmony_ci sta_info_hash_del(local, sta); 92462306a36Sopenharmony_ci list_del_rcu(&sta->list); 92562306a36Sopenharmony_ci out_drop_sta: 92662306a36Sopenharmony_ci local->num_sta--; 92762306a36Sopenharmony_ci synchronize_net(); 92862306a36Sopenharmony_ci out_cleanup: 92962306a36Sopenharmony_ci cleanup_single_sta(sta); 93062306a36Sopenharmony_ci mutex_unlock(&local->sta_mtx); 93162306a36Sopenharmony_ci kfree(sinfo); 93262306a36Sopenharmony_ci rcu_read_lock(); 93362306a36Sopenharmony_ci return err; 93462306a36Sopenharmony_ci} 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ciint sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU) 93762306a36Sopenharmony_ci{ 93862306a36Sopenharmony_ci struct ieee80211_local *local = sta->local; 93962306a36Sopenharmony_ci int err; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci might_sleep(); 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci mutex_lock(&local->sta_mtx); 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci err = sta_info_insert_check(sta); 94662306a36Sopenharmony_ci if (err) { 94762306a36Sopenharmony_ci sta_info_free(local, sta); 94862306a36Sopenharmony_ci mutex_unlock(&local->sta_mtx); 94962306a36Sopenharmony_ci rcu_read_lock(); 95062306a36Sopenharmony_ci return err; 95162306a36Sopenharmony_ci } 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci return sta_info_insert_finish(sta); 95462306a36Sopenharmony_ci} 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ciint sta_info_insert(struct sta_info *sta) 95762306a36Sopenharmony_ci{ 95862306a36Sopenharmony_ci int err = sta_info_insert_rcu(sta); 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci rcu_read_unlock(); 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci return err; 96362306a36Sopenharmony_ci} 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_cistatic inline void __bss_tim_set(u8 *tim, u16 id) 96662306a36Sopenharmony_ci{ 96762306a36Sopenharmony_ci /* 96862306a36Sopenharmony_ci * This format has been mandated by the IEEE specifications, 96962306a36Sopenharmony_ci * so this line may not be changed to use the __set_bit() format. 97062306a36Sopenharmony_ci */ 97162306a36Sopenharmony_ci tim[id / 8] |= (1 << (id % 8)); 97262306a36Sopenharmony_ci} 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_cistatic inline void __bss_tim_clear(u8 *tim, u16 id) 97562306a36Sopenharmony_ci{ 97662306a36Sopenharmony_ci /* 97762306a36Sopenharmony_ci * This format has been mandated by the IEEE specifications, 97862306a36Sopenharmony_ci * so this line may not be changed to use the __clear_bit() format. 97962306a36Sopenharmony_ci */ 98062306a36Sopenharmony_ci tim[id / 8] &= ~(1 << (id % 8)); 98162306a36Sopenharmony_ci} 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_cistatic inline bool __bss_tim_get(u8 *tim, u16 id) 98462306a36Sopenharmony_ci{ 98562306a36Sopenharmony_ci /* 98662306a36Sopenharmony_ci * This format has been mandated by the IEEE specifications, 98762306a36Sopenharmony_ci * so this line may not be changed to use the test_bit() format. 98862306a36Sopenharmony_ci */ 98962306a36Sopenharmony_ci return tim[id / 8] & (1 << (id % 8)); 99062306a36Sopenharmony_ci} 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_cistatic unsigned long ieee80211_tids_for_ac(int ac) 99362306a36Sopenharmony_ci{ 99462306a36Sopenharmony_ci /* If we ever support TIDs > 7, this obviously needs to be adjusted */ 99562306a36Sopenharmony_ci switch (ac) { 99662306a36Sopenharmony_ci case IEEE80211_AC_VO: 99762306a36Sopenharmony_ci return BIT(6) | BIT(7); 99862306a36Sopenharmony_ci case IEEE80211_AC_VI: 99962306a36Sopenharmony_ci return BIT(4) | BIT(5); 100062306a36Sopenharmony_ci case IEEE80211_AC_BE: 100162306a36Sopenharmony_ci return BIT(0) | BIT(3); 100262306a36Sopenharmony_ci case IEEE80211_AC_BK: 100362306a36Sopenharmony_ci return BIT(1) | BIT(2); 100462306a36Sopenharmony_ci default: 100562306a36Sopenharmony_ci WARN_ON(1); 100662306a36Sopenharmony_ci return 0; 100762306a36Sopenharmony_ci } 100862306a36Sopenharmony_ci} 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_cistatic void __sta_info_recalc_tim(struct sta_info *sta, bool ignore_pending) 101162306a36Sopenharmony_ci{ 101262306a36Sopenharmony_ci struct ieee80211_local *local = sta->local; 101362306a36Sopenharmony_ci struct ps_data *ps; 101462306a36Sopenharmony_ci bool indicate_tim = false; 101562306a36Sopenharmony_ci u8 ignore_for_tim = sta->sta.uapsd_queues; 101662306a36Sopenharmony_ci int ac; 101762306a36Sopenharmony_ci u16 id = sta->sta.aid; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci if (sta->sdata->vif.type == NL80211_IFTYPE_AP || 102062306a36Sopenharmony_ci sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { 102162306a36Sopenharmony_ci if (WARN_ON_ONCE(!sta->sdata->bss)) 102262306a36Sopenharmony_ci return; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci ps = &sta->sdata->bss->ps; 102562306a36Sopenharmony_ci#ifdef CONFIG_MAC80211_MESH 102662306a36Sopenharmony_ci } else if (ieee80211_vif_is_mesh(&sta->sdata->vif)) { 102762306a36Sopenharmony_ci ps = &sta->sdata->u.mesh.ps; 102862306a36Sopenharmony_ci#endif 102962306a36Sopenharmony_ci } else { 103062306a36Sopenharmony_ci return; 103162306a36Sopenharmony_ci } 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci /* No need to do anything if the driver does all */ 103462306a36Sopenharmony_ci if (ieee80211_hw_check(&local->hw, AP_LINK_PS) && !local->ops->set_tim) 103562306a36Sopenharmony_ci return; 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci if (sta->dead) 103862306a36Sopenharmony_ci goto done; 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci /* 104162306a36Sopenharmony_ci * If all ACs are delivery-enabled then we should build 104262306a36Sopenharmony_ci * the TIM bit for all ACs anyway; if only some are then 104362306a36Sopenharmony_ci * we ignore those and build the TIM bit using only the 104462306a36Sopenharmony_ci * non-enabled ones. 104562306a36Sopenharmony_ci */ 104662306a36Sopenharmony_ci if (ignore_for_tim == BIT(IEEE80211_NUM_ACS) - 1) 104762306a36Sopenharmony_ci ignore_for_tim = 0; 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci if (ignore_pending) 105062306a36Sopenharmony_ci ignore_for_tim = BIT(IEEE80211_NUM_ACS) - 1; 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { 105362306a36Sopenharmony_ci unsigned long tids; 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci if (ignore_for_tim & ieee80211_ac_to_qos_mask[ac]) 105662306a36Sopenharmony_ci continue; 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci indicate_tim |= !skb_queue_empty(&sta->tx_filtered[ac]) || 105962306a36Sopenharmony_ci !skb_queue_empty(&sta->ps_tx_buf[ac]); 106062306a36Sopenharmony_ci if (indicate_tim) 106162306a36Sopenharmony_ci break; 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci tids = ieee80211_tids_for_ac(ac); 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci indicate_tim |= 106662306a36Sopenharmony_ci sta->driver_buffered_tids & tids; 106762306a36Sopenharmony_ci indicate_tim |= 106862306a36Sopenharmony_ci sta->txq_buffered_tids & tids; 106962306a36Sopenharmony_ci } 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci done: 107262306a36Sopenharmony_ci spin_lock_bh(&local->tim_lock); 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci if (indicate_tim == __bss_tim_get(ps->tim, id)) 107562306a36Sopenharmony_ci goto out_unlock; 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci if (indicate_tim) 107862306a36Sopenharmony_ci __bss_tim_set(ps->tim, id); 107962306a36Sopenharmony_ci else 108062306a36Sopenharmony_ci __bss_tim_clear(ps->tim, id); 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci if (local->ops->set_tim && !WARN_ON(sta->dead)) { 108362306a36Sopenharmony_ci local->tim_in_locked_section = true; 108462306a36Sopenharmony_ci drv_set_tim(local, &sta->sta, indicate_tim); 108562306a36Sopenharmony_ci local->tim_in_locked_section = false; 108662306a36Sopenharmony_ci } 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ciout_unlock: 108962306a36Sopenharmony_ci spin_unlock_bh(&local->tim_lock); 109062306a36Sopenharmony_ci} 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_civoid sta_info_recalc_tim(struct sta_info *sta) 109362306a36Sopenharmony_ci{ 109462306a36Sopenharmony_ci __sta_info_recalc_tim(sta, false); 109562306a36Sopenharmony_ci} 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_cistatic bool sta_info_buffer_expired(struct sta_info *sta, struct sk_buff *skb) 109862306a36Sopenharmony_ci{ 109962306a36Sopenharmony_ci struct ieee80211_tx_info *info; 110062306a36Sopenharmony_ci int timeout; 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci if (!skb) 110362306a36Sopenharmony_ci return false; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci info = IEEE80211_SKB_CB(skb); 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci /* Timeout: (2 * listen_interval * beacon_int * 1024 / 1000000) sec */ 110862306a36Sopenharmony_ci timeout = (sta->listen_interval * 110962306a36Sopenharmony_ci sta->sdata->vif.bss_conf.beacon_int * 111062306a36Sopenharmony_ci 32 / 15625) * HZ; 111162306a36Sopenharmony_ci if (timeout < STA_TX_BUFFER_EXPIRE) 111262306a36Sopenharmony_ci timeout = STA_TX_BUFFER_EXPIRE; 111362306a36Sopenharmony_ci return time_after(jiffies, info->control.jiffies + timeout); 111462306a36Sopenharmony_ci} 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_cistatic bool sta_info_cleanup_expire_buffered_ac(struct ieee80211_local *local, 111862306a36Sopenharmony_ci struct sta_info *sta, int ac) 111962306a36Sopenharmony_ci{ 112062306a36Sopenharmony_ci unsigned long flags; 112162306a36Sopenharmony_ci struct sk_buff *skb; 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci /* 112462306a36Sopenharmony_ci * First check for frames that should expire on the filtered 112562306a36Sopenharmony_ci * queue. Frames here were rejected by the driver and are on 112662306a36Sopenharmony_ci * a separate queue to avoid reordering with normal PS-buffered 112762306a36Sopenharmony_ci * frames. They also aren't accounted for right now in the 112862306a36Sopenharmony_ci * total_ps_buffered counter. 112962306a36Sopenharmony_ci */ 113062306a36Sopenharmony_ci for (;;) { 113162306a36Sopenharmony_ci spin_lock_irqsave(&sta->tx_filtered[ac].lock, flags); 113262306a36Sopenharmony_ci skb = skb_peek(&sta->tx_filtered[ac]); 113362306a36Sopenharmony_ci if (sta_info_buffer_expired(sta, skb)) 113462306a36Sopenharmony_ci skb = __skb_dequeue(&sta->tx_filtered[ac]); 113562306a36Sopenharmony_ci else 113662306a36Sopenharmony_ci skb = NULL; 113762306a36Sopenharmony_ci spin_unlock_irqrestore(&sta->tx_filtered[ac].lock, flags); 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci /* 114062306a36Sopenharmony_ci * Frames are queued in order, so if this one 114162306a36Sopenharmony_ci * hasn't expired yet we can stop testing. If 114262306a36Sopenharmony_ci * we actually reached the end of the queue we 114362306a36Sopenharmony_ci * also need to stop, of course. 114462306a36Sopenharmony_ci */ 114562306a36Sopenharmony_ci if (!skb) 114662306a36Sopenharmony_ci break; 114762306a36Sopenharmony_ci ieee80211_free_txskb(&local->hw, skb); 114862306a36Sopenharmony_ci } 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci /* 115162306a36Sopenharmony_ci * Now also check the normal PS-buffered queue, this will 115262306a36Sopenharmony_ci * only find something if the filtered queue was emptied 115362306a36Sopenharmony_ci * since the filtered frames are all before the normal PS 115462306a36Sopenharmony_ci * buffered frames. 115562306a36Sopenharmony_ci */ 115662306a36Sopenharmony_ci for (;;) { 115762306a36Sopenharmony_ci spin_lock_irqsave(&sta->ps_tx_buf[ac].lock, flags); 115862306a36Sopenharmony_ci skb = skb_peek(&sta->ps_tx_buf[ac]); 115962306a36Sopenharmony_ci if (sta_info_buffer_expired(sta, skb)) 116062306a36Sopenharmony_ci skb = __skb_dequeue(&sta->ps_tx_buf[ac]); 116162306a36Sopenharmony_ci else 116262306a36Sopenharmony_ci skb = NULL; 116362306a36Sopenharmony_ci spin_unlock_irqrestore(&sta->ps_tx_buf[ac].lock, flags); 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci /* 116662306a36Sopenharmony_ci * frames are queued in order, so if this one 116762306a36Sopenharmony_ci * hasn't expired yet (or we reached the end of 116862306a36Sopenharmony_ci * the queue) we can stop testing 116962306a36Sopenharmony_ci */ 117062306a36Sopenharmony_ci if (!skb) 117162306a36Sopenharmony_ci break; 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci local->total_ps_buffered--; 117462306a36Sopenharmony_ci ps_dbg(sta->sdata, "Buffered frame expired (STA %pM)\n", 117562306a36Sopenharmony_ci sta->sta.addr); 117662306a36Sopenharmony_ci ieee80211_free_txskb(&local->hw, skb); 117762306a36Sopenharmony_ci } 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci /* 118062306a36Sopenharmony_ci * Finally, recalculate the TIM bit for this station -- it might 118162306a36Sopenharmony_ci * now be clear because the station was too slow to retrieve its 118262306a36Sopenharmony_ci * frames. 118362306a36Sopenharmony_ci */ 118462306a36Sopenharmony_ci sta_info_recalc_tim(sta); 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci /* 118762306a36Sopenharmony_ci * Return whether there are any frames still buffered, this is 118862306a36Sopenharmony_ci * used to check whether the cleanup timer still needs to run, 118962306a36Sopenharmony_ci * if there are no frames we don't need to rearm the timer. 119062306a36Sopenharmony_ci */ 119162306a36Sopenharmony_ci return !(skb_queue_empty(&sta->ps_tx_buf[ac]) && 119262306a36Sopenharmony_ci skb_queue_empty(&sta->tx_filtered[ac])); 119362306a36Sopenharmony_ci} 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_cistatic bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local, 119662306a36Sopenharmony_ci struct sta_info *sta) 119762306a36Sopenharmony_ci{ 119862306a36Sopenharmony_ci bool have_buffered = false; 119962306a36Sopenharmony_ci int ac; 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci /* This is only necessary for stations on BSS/MBSS interfaces */ 120262306a36Sopenharmony_ci if (!sta->sdata->bss && 120362306a36Sopenharmony_ci !ieee80211_vif_is_mesh(&sta->sdata->vif)) 120462306a36Sopenharmony_ci return false; 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) 120762306a36Sopenharmony_ci have_buffered |= 120862306a36Sopenharmony_ci sta_info_cleanup_expire_buffered_ac(local, sta, ac); 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci return have_buffered; 121162306a36Sopenharmony_ci} 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_cistatic int __must_check __sta_info_destroy_part1(struct sta_info *sta) 121462306a36Sopenharmony_ci{ 121562306a36Sopenharmony_ci struct ieee80211_local *local; 121662306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata; 121762306a36Sopenharmony_ci int ret, i; 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci might_sleep(); 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci if (!sta) 122262306a36Sopenharmony_ci return -ENOENT; 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci local = sta->local; 122562306a36Sopenharmony_ci sdata = sta->sdata; 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci lockdep_assert_held(&local->sta_mtx); 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci /* 123062306a36Sopenharmony_ci * Before removing the station from the driver and 123162306a36Sopenharmony_ci * rate control, it might still start new aggregation 123262306a36Sopenharmony_ci * sessions -- block that to make sure the tear-down 123362306a36Sopenharmony_ci * will be sufficient. 123462306a36Sopenharmony_ci */ 123562306a36Sopenharmony_ci set_sta_flag(sta, WLAN_STA_BLOCK_BA); 123662306a36Sopenharmony_ci ieee80211_sta_tear_down_BA_sessions(sta, AGG_STOP_DESTROY_STA); 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci /* 123962306a36Sopenharmony_ci * Before removing the station from the driver there might be pending 124062306a36Sopenharmony_ci * rx frames on RSS queues sent prior to the disassociation - wait for 124162306a36Sopenharmony_ci * all such frames to be processed. 124262306a36Sopenharmony_ci */ 124362306a36Sopenharmony_ci drv_sync_rx_queues(local, sta); 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sta->link); i++) { 124662306a36Sopenharmony_ci struct link_sta_info *link_sta; 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci if (!(sta->sta.valid_links & BIT(i))) 124962306a36Sopenharmony_ci continue; 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci link_sta = rcu_dereference_protected(sta->link[i], 125262306a36Sopenharmony_ci lockdep_is_held(&local->sta_mtx)); 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci link_sta_info_hash_del(local, link_sta); 125562306a36Sopenharmony_ci } 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci ret = sta_info_hash_del(local, sta); 125862306a36Sopenharmony_ci if (WARN_ON(ret)) 125962306a36Sopenharmony_ci return ret; 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci /* 126262306a36Sopenharmony_ci * for TDLS peers, make sure to return to the base channel before 126362306a36Sopenharmony_ci * removal. 126462306a36Sopenharmony_ci */ 126562306a36Sopenharmony_ci if (test_sta_flag(sta, WLAN_STA_TDLS_OFF_CHANNEL)) { 126662306a36Sopenharmony_ci drv_tdls_cancel_channel_switch(local, sdata, &sta->sta); 126762306a36Sopenharmony_ci clear_sta_flag(sta, WLAN_STA_TDLS_OFF_CHANNEL); 126862306a36Sopenharmony_ci } 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci list_del_rcu(&sta->list); 127162306a36Sopenharmony_ci sta->removed = true; 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci if (sta->uploaded) 127462306a36Sopenharmony_ci drv_sta_pre_rcu_remove(local, sta->sdata, sta); 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN && 127762306a36Sopenharmony_ci rcu_access_pointer(sdata->u.vlan.sta) == sta) 127862306a36Sopenharmony_ci RCU_INIT_POINTER(sdata->u.vlan.sta, NULL); 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci return 0; 128162306a36Sopenharmony_ci} 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_cistatic int _sta_info_move_state(struct sta_info *sta, 128462306a36Sopenharmony_ci enum ieee80211_sta_state new_state, 128562306a36Sopenharmony_ci bool recalc) 128662306a36Sopenharmony_ci{ 128762306a36Sopenharmony_ci might_sleep(); 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci if (sta->sta_state == new_state) 129062306a36Sopenharmony_ci return 0; 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci /* check allowed transitions first */ 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci switch (new_state) { 129562306a36Sopenharmony_ci case IEEE80211_STA_NONE: 129662306a36Sopenharmony_ci if (sta->sta_state != IEEE80211_STA_AUTH) 129762306a36Sopenharmony_ci return -EINVAL; 129862306a36Sopenharmony_ci break; 129962306a36Sopenharmony_ci case IEEE80211_STA_AUTH: 130062306a36Sopenharmony_ci if (sta->sta_state != IEEE80211_STA_NONE && 130162306a36Sopenharmony_ci sta->sta_state != IEEE80211_STA_ASSOC) 130262306a36Sopenharmony_ci return -EINVAL; 130362306a36Sopenharmony_ci break; 130462306a36Sopenharmony_ci case IEEE80211_STA_ASSOC: 130562306a36Sopenharmony_ci if (sta->sta_state != IEEE80211_STA_AUTH && 130662306a36Sopenharmony_ci sta->sta_state != IEEE80211_STA_AUTHORIZED) 130762306a36Sopenharmony_ci return -EINVAL; 130862306a36Sopenharmony_ci break; 130962306a36Sopenharmony_ci case IEEE80211_STA_AUTHORIZED: 131062306a36Sopenharmony_ci if (sta->sta_state != IEEE80211_STA_ASSOC) 131162306a36Sopenharmony_ci return -EINVAL; 131262306a36Sopenharmony_ci break; 131362306a36Sopenharmony_ci default: 131462306a36Sopenharmony_ci WARN(1, "invalid state %d", new_state); 131562306a36Sopenharmony_ci return -EINVAL; 131662306a36Sopenharmony_ci } 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci sta_dbg(sta->sdata, "moving STA %pM to state %d\n", 131962306a36Sopenharmony_ci sta->sta.addr, new_state); 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci /* notify the driver before the actual changes so it can 132262306a36Sopenharmony_ci * fail the transition 132362306a36Sopenharmony_ci */ 132462306a36Sopenharmony_ci if (test_sta_flag(sta, WLAN_STA_INSERTED)) { 132562306a36Sopenharmony_ci int err = drv_sta_state(sta->local, sta->sdata, sta, 132662306a36Sopenharmony_ci sta->sta_state, new_state); 132762306a36Sopenharmony_ci if (err) 132862306a36Sopenharmony_ci return err; 132962306a36Sopenharmony_ci } 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci /* reflect the change in all state variables */ 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci switch (new_state) { 133462306a36Sopenharmony_ci case IEEE80211_STA_NONE: 133562306a36Sopenharmony_ci if (sta->sta_state == IEEE80211_STA_AUTH) 133662306a36Sopenharmony_ci clear_bit(WLAN_STA_AUTH, &sta->_flags); 133762306a36Sopenharmony_ci break; 133862306a36Sopenharmony_ci case IEEE80211_STA_AUTH: 133962306a36Sopenharmony_ci if (sta->sta_state == IEEE80211_STA_NONE) { 134062306a36Sopenharmony_ci set_bit(WLAN_STA_AUTH, &sta->_flags); 134162306a36Sopenharmony_ci } else if (sta->sta_state == IEEE80211_STA_ASSOC) { 134262306a36Sopenharmony_ci clear_bit(WLAN_STA_ASSOC, &sta->_flags); 134362306a36Sopenharmony_ci if (recalc) { 134462306a36Sopenharmony_ci ieee80211_recalc_min_chandef(sta->sdata, -1); 134562306a36Sopenharmony_ci if (!sta->sta.support_p2p_ps) 134662306a36Sopenharmony_ci ieee80211_recalc_p2p_go_ps_allowed(sta->sdata); 134762306a36Sopenharmony_ci } 134862306a36Sopenharmony_ci } 134962306a36Sopenharmony_ci break; 135062306a36Sopenharmony_ci case IEEE80211_STA_ASSOC: 135162306a36Sopenharmony_ci if (sta->sta_state == IEEE80211_STA_AUTH) { 135262306a36Sopenharmony_ci set_bit(WLAN_STA_ASSOC, &sta->_flags); 135362306a36Sopenharmony_ci sta->assoc_at = ktime_get_boottime_ns(); 135462306a36Sopenharmony_ci if (recalc) { 135562306a36Sopenharmony_ci ieee80211_recalc_min_chandef(sta->sdata, -1); 135662306a36Sopenharmony_ci if (!sta->sta.support_p2p_ps) 135762306a36Sopenharmony_ci ieee80211_recalc_p2p_go_ps_allowed(sta->sdata); 135862306a36Sopenharmony_ci } 135962306a36Sopenharmony_ci } else if (sta->sta_state == IEEE80211_STA_AUTHORIZED) { 136062306a36Sopenharmony_ci ieee80211_vif_dec_num_mcast(sta->sdata); 136162306a36Sopenharmony_ci clear_bit(WLAN_STA_AUTHORIZED, &sta->_flags); 136262306a36Sopenharmony_ci ieee80211_clear_fast_xmit(sta); 136362306a36Sopenharmony_ci ieee80211_clear_fast_rx(sta); 136462306a36Sopenharmony_ci } 136562306a36Sopenharmony_ci break; 136662306a36Sopenharmony_ci case IEEE80211_STA_AUTHORIZED: 136762306a36Sopenharmony_ci if (sta->sta_state == IEEE80211_STA_ASSOC) { 136862306a36Sopenharmony_ci ieee80211_vif_inc_num_mcast(sta->sdata); 136962306a36Sopenharmony_ci set_bit(WLAN_STA_AUTHORIZED, &sta->_flags); 137062306a36Sopenharmony_ci ieee80211_check_fast_xmit(sta); 137162306a36Sopenharmony_ci ieee80211_check_fast_rx(sta); 137262306a36Sopenharmony_ci } 137362306a36Sopenharmony_ci if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN || 137462306a36Sopenharmony_ci sta->sdata->vif.type == NL80211_IFTYPE_AP) 137562306a36Sopenharmony_ci cfg80211_send_layer2_update(sta->sdata->dev, 137662306a36Sopenharmony_ci sta->sta.addr); 137762306a36Sopenharmony_ci break; 137862306a36Sopenharmony_ci default: 137962306a36Sopenharmony_ci break; 138062306a36Sopenharmony_ci } 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci sta->sta_state = new_state; 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci return 0; 138562306a36Sopenharmony_ci} 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ciint sta_info_move_state(struct sta_info *sta, 138862306a36Sopenharmony_ci enum ieee80211_sta_state new_state) 138962306a36Sopenharmony_ci{ 139062306a36Sopenharmony_ci return _sta_info_move_state(sta, new_state, true); 139162306a36Sopenharmony_ci} 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_cistatic void __sta_info_destroy_part2(struct sta_info *sta, bool recalc) 139462306a36Sopenharmony_ci{ 139562306a36Sopenharmony_ci struct ieee80211_local *local = sta->local; 139662306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata = sta->sdata; 139762306a36Sopenharmony_ci struct station_info *sinfo; 139862306a36Sopenharmony_ci int ret; 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci /* 140162306a36Sopenharmony_ci * NOTE: This assumes at least synchronize_net() was done 140262306a36Sopenharmony_ci * after _part1 and before _part2! 140362306a36Sopenharmony_ci */ 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci might_sleep(); 140662306a36Sopenharmony_ci lockdep_assert_held(&local->sta_mtx); 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci if (sta->sta_state == IEEE80211_STA_AUTHORIZED) { 140962306a36Sopenharmony_ci ret = _sta_info_move_state(sta, IEEE80211_STA_ASSOC, recalc); 141062306a36Sopenharmony_ci WARN_ON_ONCE(ret); 141162306a36Sopenharmony_ci } 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci /* Flush queues before removing keys, as that might remove them 141462306a36Sopenharmony_ci * from hardware, and then depending on the offload method, any 141562306a36Sopenharmony_ci * frames sitting on hardware queues might be sent out without 141662306a36Sopenharmony_ci * any encryption at all. 141762306a36Sopenharmony_ci */ 141862306a36Sopenharmony_ci if (local->ops->set_key) { 141962306a36Sopenharmony_ci if (local->ops->flush_sta) 142062306a36Sopenharmony_ci drv_flush_sta(local, sta->sdata, sta); 142162306a36Sopenharmony_ci else 142262306a36Sopenharmony_ci ieee80211_flush_queues(local, sta->sdata, false); 142362306a36Sopenharmony_ci } 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci /* now keys can no longer be reached */ 142662306a36Sopenharmony_ci ieee80211_free_sta_keys(local, sta); 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci /* disable TIM bit - last chance to tell driver */ 142962306a36Sopenharmony_ci __sta_info_recalc_tim(sta, true); 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci sta->dead = true; 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci local->num_sta--; 143462306a36Sopenharmony_ci local->sta_generation++; 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci while (sta->sta_state > IEEE80211_STA_NONE) { 143762306a36Sopenharmony_ci ret = _sta_info_move_state(sta, sta->sta_state - 1, recalc); 143862306a36Sopenharmony_ci if (ret) { 143962306a36Sopenharmony_ci WARN_ON_ONCE(1); 144062306a36Sopenharmony_ci break; 144162306a36Sopenharmony_ci } 144262306a36Sopenharmony_ci } 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci if (sta->uploaded) { 144562306a36Sopenharmony_ci ret = drv_sta_state(local, sdata, sta, IEEE80211_STA_NONE, 144662306a36Sopenharmony_ci IEEE80211_STA_NOTEXIST); 144762306a36Sopenharmony_ci WARN_ON_ONCE(ret != 0); 144862306a36Sopenharmony_ci } 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci sta_dbg(sdata, "Removed STA %pM\n", sta->sta.addr); 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL); 145362306a36Sopenharmony_ci if (sinfo) 145462306a36Sopenharmony_ci sta_set_sinfo(sta, sinfo, true); 145562306a36Sopenharmony_ci cfg80211_del_sta_sinfo(sdata->dev, sta->sta.addr, sinfo, GFP_KERNEL); 145662306a36Sopenharmony_ci kfree(sinfo); 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci ieee80211_sta_debugfs_remove(sta); 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci ieee80211_destroy_frag_cache(&sta->frags); 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci cleanup_single_sta(sta); 146362306a36Sopenharmony_ci} 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ciint __must_check __sta_info_destroy(struct sta_info *sta) 146662306a36Sopenharmony_ci{ 146762306a36Sopenharmony_ci int err = __sta_info_destroy_part1(sta); 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci if (err) 147062306a36Sopenharmony_ci return err; 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci synchronize_net(); 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci __sta_info_destroy_part2(sta, true); 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci return 0; 147762306a36Sopenharmony_ci} 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ciint sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata, const u8 *addr) 148062306a36Sopenharmony_ci{ 148162306a36Sopenharmony_ci struct sta_info *sta; 148262306a36Sopenharmony_ci int ret; 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci mutex_lock(&sdata->local->sta_mtx); 148562306a36Sopenharmony_ci sta = sta_info_get(sdata, addr); 148662306a36Sopenharmony_ci ret = __sta_info_destroy(sta); 148762306a36Sopenharmony_ci mutex_unlock(&sdata->local->sta_mtx); 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci return ret; 149062306a36Sopenharmony_ci} 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ciint sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata, 149362306a36Sopenharmony_ci const u8 *addr) 149462306a36Sopenharmony_ci{ 149562306a36Sopenharmony_ci struct sta_info *sta; 149662306a36Sopenharmony_ci int ret; 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci mutex_lock(&sdata->local->sta_mtx); 149962306a36Sopenharmony_ci sta = sta_info_get_bss(sdata, addr); 150062306a36Sopenharmony_ci ret = __sta_info_destroy(sta); 150162306a36Sopenharmony_ci mutex_unlock(&sdata->local->sta_mtx); 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci return ret; 150462306a36Sopenharmony_ci} 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_cistatic void sta_info_cleanup(struct timer_list *t) 150762306a36Sopenharmony_ci{ 150862306a36Sopenharmony_ci struct ieee80211_local *local = from_timer(local, t, sta_cleanup); 150962306a36Sopenharmony_ci struct sta_info *sta; 151062306a36Sopenharmony_ci bool timer_needed = false; 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci rcu_read_lock(); 151362306a36Sopenharmony_ci list_for_each_entry_rcu(sta, &local->sta_list, list) 151462306a36Sopenharmony_ci if (sta_info_cleanup_expire_buffered(local, sta)) 151562306a36Sopenharmony_ci timer_needed = true; 151662306a36Sopenharmony_ci rcu_read_unlock(); 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci if (local->quiescing) 151962306a36Sopenharmony_ci return; 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci if (!timer_needed) 152262306a36Sopenharmony_ci return; 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci mod_timer(&local->sta_cleanup, 152562306a36Sopenharmony_ci round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL)); 152662306a36Sopenharmony_ci} 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ciint sta_info_init(struct ieee80211_local *local) 152962306a36Sopenharmony_ci{ 153062306a36Sopenharmony_ci int err; 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci err = rhltable_init(&local->sta_hash, &sta_rht_params); 153362306a36Sopenharmony_ci if (err) 153462306a36Sopenharmony_ci return err; 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci err = rhltable_init(&local->link_sta_hash, &link_sta_rht_params); 153762306a36Sopenharmony_ci if (err) { 153862306a36Sopenharmony_ci rhltable_destroy(&local->sta_hash); 153962306a36Sopenharmony_ci return err; 154062306a36Sopenharmony_ci } 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci spin_lock_init(&local->tim_lock); 154362306a36Sopenharmony_ci mutex_init(&local->sta_mtx); 154462306a36Sopenharmony_ci INIT_LIST_HEAD(&local->sta_list); 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci timer_setup(&local->sta_cleanup, sta_info_cleanup, 0); 154762306a36Sopenharmony_ci return 0; 154862306a36Sopenharmony_ci} 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_civoid sta_info_stop(struct ieee80211_local *local) 155162306a36Sopenharmony_ci{ 155262306a36Sopenharmony_ci del_timer_sync(&local->sta_cleanup); 155362306a36Sopenharmony_ci rhltable_destroy(&local->sta_hash); 155462306a36Sopenharmony_ci rhltable_destroy(&local->link_sta_hash); 155562306a36Sopenharmony_ci} 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ciint __sta_info_flush(struct ieee80211_sub_if_data *sdata, bool vlans) 155962306a36Sopenharmony_ci{ 156062306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 156162306a36Sopenharmony_ci struct sta_info *sta, *tmp; 156262306a36Sopenharmony_ci LIST_HEAD(free_list); 156362306a36Sopenharmony_ci int ret = 0; 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci might_sleep(); 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci WARN_ON(vlans && sdata->vif.type != NL80211_IFTYPE_AP); 156862306a36Sopenharmony_ci WARN_ON(vlans && !sdata->bss); 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci mutex_lock(&local->sta_mtx); 157162306a36Sopenharmony_ci list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { 157262306a36Sopenharmony_ci if (sdata == sta->sdata || 157362306a36Sopenharmony_ci (vlans && sdata->bss == sta->sdata->bss)) { 157462306a36Sopenharmony_ci if (!WARN_ON(__sta_info_destroy_part1(sta))) 157562306a36Sopenharmony_ci list_add(&sta->free_list, &free_list); 157662306a36Sopenharmony_ci ret++; 157762306a36Sopenharmony_ci } 157862306a36Sopenharmony_ci } 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci if (!list_empty(&free_list)) { 158162306a36Sopenharmony_ci bool support_p2p_ps = true; 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci synchronize_net(); 158462306a36Sopenharmony_ci list_for_each_entry_safe(sta, tmp, &free_list, free_list) { 158562306a36Sopenharmony_ci if (!sta->sta.support_p2p_ps) 158662306a36Sopenharmony_ci support_p2p_ps = false; 158762306a36Sopenharmony_ci __sta_info_destroy_part2(sta, false); 158862306a36Sopenharmony_ci } 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_ci ieee80211_recalc_min_chandef(sdata, -1); 159162306a36Sopenharmony_ci if (!support_p2p_ps) 159262306a36Sopenharmony_ci ieee80211_recalc_p2p_go_ps_allowed(sdata); 159362306a36Sopenharmony_ci } 159462306a36Sopenharmony_ci mutex_unlock(&local->sta_mtx); 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci return ret; 159762306a36Sopenharmony_ci} 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_civoid ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, 160062306a36Sopenharmony_ci unsigned long exp_time) 160162306a36Sopenharmony_ci{ 160262306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 160362306a36Sopenharmony_ci struct sta_info *sta, *tmp; 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci mutex_lock(&local->sta_mtx); 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { 160862306a36Sopenharmony_ci unsigned long last_active = ieee80211_sta_last_active(sta); 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci if (sdata != sta->sdata) 161162306a36Sopenharmony_ci continue; 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci if (time_is_before_jiffies(last_active + exp_time)) { 161462306a36Sopenharmony_ci sta_dbg(sta->sdata, "expiring inactive STA %pM\n", 161562306a36Sopenharmony_ci sta->sta.addr); 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_ci if (ieee80211_vif_is_mesh(&sdata->vif) && 161862306a36Sopenharmony_ci test_sta_flag(sta, WLAN_STA_PS_STA)) 161962306a36Sopenharmony_ci atomic_dec(&sdata->u.mesh.ps.num_sta_ps); 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci WARN_ON(__sta_info_destroy(sta)); 162262306a36Sopenharmony_ci } 162362306a36Sopenharmony_ci } 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci mutex_unlock(&local->sta_mtx); 162662306a36Sopenharmony_ci} 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_cistruct ieee80211_sta *ieee80211_find_sta_by_ifaddr(struct ieee80211_hw *hw, 162962306a36Sopenharmony_ci const u8 *addr, 163062306a36Sopenharmony_ci const u8 *localaddr) 163162306a36Sopenharmony_ci{ 163262306a36Sopenharmony_ci struct ieee80211_local *local = hw_to_local(hw); 163362306a36Sopenharmony_ci struct rhlist_head *tmp; 163462306a36Sopenharmony_ci struct sta_info *sta; 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci /* 163762306a36Sopenharmony_ci * Just return a random station if localaddr is NULL 163862306a36Sopenharmony_ci * ... first in list. 163962306a36Sopenharmony_ci */ 164062306a36Sopenharmony_ci for_each_sta_info(local, addr, sta, tmp) { 164162306a36Sopenharmony_ci if (localaddr && 164262306a36Sopenharmony_ci !ether_addr_equal(sta->sdata->vif.addr, localaddr)) 164362306a36Sopenharmony_ci continue; 164462306a36Sopenharmony_ci if (!sta->uploaded) 164562306a36Sopenharmony_ci return NULL; 164662306a36Sopenharmony_ci return &sta->sta; 164762306a36Sopenharmony_ci } 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_ci return NULL; 165062306a36Sopenharmony_ci} 165162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ieee80211_find_sta_by_ifaddr); 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_cistruct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif, 165462306a36Sopenharmony_ci const u8 *addr) 165562306a36Sopenharmony_ci{ 165662306a36Sopenharmony_ci struct sta_info *sta; 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci if (!vif) 165962306a36Sopenharmony_ci return NULL; 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci sta = sta_info_get_bss(vif_to_sdata(vif), addr); 166262306a36Sopenharmony_ci if (!sta) 166362306a36Sopenharmony_ci return NULL; 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci if (!sta->uploaded) 166662306a36Sopenharmony_ci return NULL; 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_ci return &sta->sta; 166962306a36Sopenharmony_ci} 167062306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_find_sta); 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_ci/* powersave support code */ 167362306a36Sopenharmony_civoid ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) 167462306a36Sopenharmony_ci{ 167562306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata = sta->sdata; 167662306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 167762306a36Sopenharmony_ci struct sk_buff_head pending; 167862306a36Sopenharmony_ci int filtered = 0, buffered = 0, ac, i; 167962306a36Sopenharmony_ci unsigned long flags; 168062306a36Sopenharmony_ci struct ps_data *ps; 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 168362306a36Sopenharmony_ci sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, 168462306a36Sopenharmony_ci u.ap); 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_ci if (sdata->vif.type == NL80211_IFTYPE_AP) 168762306a36Sopenharmony_ci ps = &sdata->bss->ps; 168862306a36Sopenharmony_ci else if (ieee80211_vif_is_mesh(&sdata->vif)) 168962306a36Sopenharmony_ci ps = &sdata->u.mesh.ps; 169062306a36Sopenharmony_ci else 169162306a36Sopenharmony_ci return; 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci clear_sta_flag(sta, WLAN_STA_SP); 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_ci BUILD_BUG_ON(BITS_TO_LONGS(IEEE80211_NUM_TIDS) > 1); 169662306a36Sopenharmony_ci sta->driver_buffered_tids = 0; 169762306a36Sopenharmony_ci sta->txq_buffered_tids = 0; 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_ci if (!ieee80211_hw_check(&local->hw, AP_LINK_PS)) 170062306a36Sopenharmony_ci drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta); 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) { 170362306a36Sopenharmony_ci if (!sta->sta.txq[i] || !txq_has_queue(sta->sta.txq[i])) 170462306a36Sopenharmony_ci continue; 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_ci schedule_and_wake_txq(local, to_txq_info(sta->sta.txq[i])); 170762306a36Sopenharmony_ci } 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci skb_queue_head_init(&pending); 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_ci /* sync with ieee80211_tx_h_unicast_ps_buf */ 171262306a36Sopenharmony_ci spin_lock(&sta->ps_lock); 171362306a36Sopenharmony_ci /* Send all buffered frames to the station */ 171462306a36Sopenharmony_ci for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { 171562306a36Sopenharmony_ci int count = skb_queue_len(&pending), tmp; 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_ci spin_lock_irqsave(&sta->tx_filtered[ac].lock, flags); 171862306a36Sopenharmony_ci skb_queue_splice_tail_init(&sta->tx_filtered[ac], &pending); 171962306a36Sopenharmony_ci spin_unlock_irqrestore(&sta->tx_filtered[ac].lock, flags); 172062306a36Sopenharmony_ci tmp = skb_queue_len(&pending); 172162306a36Sopenharmony_ci filtered += tmp - count; 172262306a36Sopenharmony_ci count = tmp; 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci spin_lock_irqsave(&sta->ps_tx_buf[ac].lock, flags); 172562306a36Sopenharmony_ci skb_queue_splice_tail_init(&sta->ps_tx_buf[ac], &pending); 172662306a36Sopenharmony_ci spin_unlock_irqrestore(&sta->ps_tx_buf[ac].lock, flags); 172762306a36Sopenharmony_ci tmp = skb_queue_len(&pending); 172862306a36Sopenharmony_ci buffered += tmp - count; 172962306a36Sopenharmony_ci } 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci ieee80211_add_pending_skbs(local, &pending); 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_ci /* now we're no longer in the deliver code */ 173462306a36Sopenharmony_ci clear_sta_flag(sta, WLAN_STA_PS_DELIVER); 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ci /* The station might have polled and then woken up before we responded, 173762306a36Sopenharmony_ci * so clear these flags now to avoid them sticking around. 173862306a36Sopenharmony_ci */ 173962306a36Sopenharmony_ci clear_sta_flag(sta, WLAN_STA_PSPOLL); 174062306a36Sopenharmony_ci clear_sta_flag(sta, WLAN_STA_UAPSD); 174162306a36Sopenharmony_ci spin_unlock(&sta->ps_lock); 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci atomic_dec(&ps->num_sta_ps); 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ci local->total_ps_buffered -= buffered; 174662306a36Sopenharmony_ci 174762306a36Sopenharmony_ci sta_info_recalc_tim(sta); 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_ci ps_dbg(sdata, 175062306a36Sopenharmony_ci "STA %pM aid %d sending %d filtered/%d PS frames since STA woke up\n", 175162306a36Sopenharmony_ci sta->sta.addr, sta->sta.aid, filtered, buffered); 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_ci ieee80211_check_fast_xmit(sta); 175462306a36Sopenharmony_ci} 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_cistatic void ieee80211_send_null_response(struct sta_info *sta, int tid, 175762306a36Sopenharmony_ci enum ieee80211_frame_release_type reason, 175862306a36Sopenharmony_ci bool call_driver, bool more_data) 175962306a36Sopenharmony_ci{ 176062306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata = sta->sdata; 176162306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 176262306a36Sopenharmony_ci struct ieee80211_qos_hdr *nullfunc; 176362306a36Sopenharmony_ci struct sk_buff *skb; 176462306a36Sopenharmony_ci int size = sizeof(*nullfunc); 176562306a36Sopenharmony_ci __le16 fc; 176662306a36Sopenharmony_ci bool qos = sta->sta.wme; 176762306a36Sopenharmony_ci struct ieee80211_tx_info *info; 176862306a36Sopenharmony_ci struct ieee80211_chanctx_conf *chanctx_conf; 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci if (qos) { 177162306a36Sopenharmony_ci fc = cpu_to_le16(IEEE80211_FTYPE_DATA | 177262306a36Sopenharmony_ci IEEE80211_STYPE_QOS_NULLFUNC | 177362306a36Sopenharmony_ci IEEE80211_FCTL_FROMDS); 177462306a36Sopenharmony_ci } else { 177562306a36Sopenharmony_ci size -= 2; 177662306a36Sopenharmony_ci fc = cpu_to_le16(IEEE80211_FTYPE_DATA | 177762306a36Sopenharmony_ci IEEE80211_STYPE_NULLFUNC | 177862306a36Sopenharmony_ci IEEE80211_FCTL_FROMDS); 177962306a36Sopenharmony_ci } 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_ci skb = dev_alloc_skb(local->hw.extra_tx_headroom + size); 178262306a36Sopenharmony_ci if (!skb) 178362306a36Sopenharmony_ci return; 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci skb_reserve(skb, local->hw.extra_tx_headroom); 178662306a36Sopenharmony_ci 178762306a36Sopenharmony_ci nullfunc = skb_put(skb, size); 178862306a36Sopenharmony_ci nullfunc->frame_control = fc; 178962306a36Sopenharmony_ci nullfunc->duration_id = 0; 179062306a36Sopenharmony_ci memcpy(nullfunc->addr1, sta->sta.addr, ETH_ALEN); 179162306a36Sopenharmony_ci memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN); 179262306a36Sopenharmony_ci memcpy(nullfunc->addr3, sdata->vif.addr, ETH_ALEN); 179362306a36Sopenharmony_ci nullfunc->seq_ctrl = 0; 179462306a36Sopenharmony_ci 179562306a36Sopenharmony_ci skb->priority = tid; 179662306a36Sopenharmony_ci skb_set_queue_mapping(skb, ieee802_1d_to_ac[tid]); 179762306a36Sopenharmony_ci if (qos) { 179862306a36Sopenharmony_ci nullfunc->qos_ctrl = cpu_to_le16(tid); 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ci if (reason == IEEE80211_FRAME_RELEASE_UAPSD) { 180162306a36Sopenharmony_ci nullfunc->qos_ctrl |= 180262306a36Sopenharmony_ci cpu_to_le16(IEEE80211_QOS_CTL_EOSP); 180362306a36Sopenharmony_ci if (more_data) 180462306a36Sopenharmony_ci nullfunc->frame_control |= 180562306a36Sopenharmony_ci cpu_to_le16(IEEE80211_FCTL_MOREDATA); 180662306a36Sopenharmony_ci } 180762306a36Sopenharmony_ci } 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci info = IEEE80211_SKB_CB(skb); 181062306a36Sopenharmony_ci 181162306a36Sopenharmony_ci /* 181262306a36Sopenharmony_ci * Tell TX path to send this frame even though the 181362306a36Sopenharmony_ci * STA may still remain is PS mode after this frame 181462306a36Sopenharmony_ci * exchange. Also set EOSP to indicate this packet 181562306a36Sopenharmony_ci * ends the poll/service period. 181662306a36Sopenharmony_ci */ 181762306a36Sopenharmony_ci info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER | 181862306a36Sopenharmony_ci IEEE80211_TX_STATUS_EOSP | 181962306a36Sopenharmony_ci IEEE80211_TX_CTL_REQ_TX_STATUS; 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_ci info->control.flags |= IEEE80211_TX_CTRL_PS_RESPONSE; 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_ci if (call_driver) 182462306a36Sopenharmony_ci drv_allow_buffered_frames(local, sta, BIT(tid), 1, 182562306a36Sopenharmony_ci reason, false); 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci skb->dev = sdata->dev; 182862306a36Sopenharmony_ci 182962306a36Sopenharmony_ci rcu_read_lock(); 183062306a36Sopenharmony_ci chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); 183162306a36Sopenharmony_ci if (WARN_ON(!chanctx_conf)) { 183262306a36Sopenharmony_ci rcu_read_unlock(); 183362306a36Sopenharmony_ci kfree_skb(skb); 183462306a36Sopenharmony_ci return; 183562306a36Sopenharmony_ci } 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci info->band = chanctx_conf->def.chan->band; 183862306a36Sopenharmony_ci ieee80211_xmit(sdata, sta, skb); 183962306a36Sopenharmony_ci rcu_read_unlock(); 184062306a36Sopenharmony_ci} 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_cistatic int find_highest_prio_tid(unsigned long tids) 184362306a36Sopenharmony_ci{ 184462306a36Sopenharmony_ci /* lower 3 TIDs aren't ordered perfectly */ 184562306a36Sopenharmony_ci if (tids & 0xF8) 184662306a36Sopenharmony_ci return fls(tids) - 1; 184762306a36Sopenharmony_ci /* TID 0 is BE just like TID 3 */ 184862306a36Sopenharmony_ci if (tids & BIT(0)) 184962306a36Sopenharmony_ci return 0; 185062306a36Sopenharmony_ci return fls(tids) - 1; 185162306a36Sopenharmony_ci} 185262306a36Sopenharmony_ci 185362306a36Sopenharmony_ci/* Indicates if the MORE_DATA bit should be set in the last 185462306a36Sopenharmony_ci * frame obtained by ieee80211_sta_ps_get_frames. 185562306a36Sopenharmony_ci * Note that driver_release_tids is relevant only if 185662306a36Sopenharmony_ci * reason = IEEE80211_FRAME_RELEASE_PSPOLL 185762306a36Sopenharmony_ci */ 185862306a36Sopenharmony_cistatic bool 185962306a36Sopenharmony_ciieee80211_sta_ps_more_data(struct sta_info *sta, u8 ignored_acs, 186062306a36Sopenharmony_ci enum ieee80211_frame_release_type reason, 186162306a36Sopenharmony_ci unsigned long driver_release_tids) 186262306a36Sopenharmony_ci{ 186362306a36Sopenharmony_ci int ac; 186462306a36Sopenharmony_ci 186562306a36Sopenharmony_ci /* If the driver has data on more than one TID then 186662306a36Sopenharmony_ci * certainly there's more data if we release just a 186762306a36Sopenharmony_ci * single frame now (from a single TID). This will 186862306a36Sopenharmony_ci * only happen for PS-Poll. 186962306a36Sopenharmony_ci */ 187062306a36Sopenharmony_ci if (reason == IEEE80211_FRAME_RELEASE_PSPOLL && 187162306a36Sopenharmony_ci hweight16(driver_release_tids) > 1) 187262306a36Sopenharmony_ci return true; 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_ci for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { 187562306a36Sopenharmony_ci if (ignored_acs & ieee80211_ac_to_qos_mask[ac]) 187662306a36Sopenharmony_ci continue; 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci if (!skb_queue_empty(&sta->tx_filtered[ac]) || 187962306a36Sopenharmony_ci !skb_queue_empty(&sta->ps_tx_buf[ac])) 188062306a36Sopenharmony_ci return true; 188162306a36Sopenharmony_ci } 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_ci return false; 188462306a36Sopenharmony_ci} 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_cistatic void 188762306a36Sopenharmony_ciieee80211_sta_ps_get_frames(struct sta_info *sta, int n_frames, u8 ignored_acs, 188862306a36Sopenharmony_ci enum ieee80211_frame_release_type reason, 188962306a36Sopenharmony_ci struct sk_buff_head *frames, 189062306a36Sopenharmony_ci unsigned long *driver_release_tids) 189162306a36Sopenharmony_ci{ 189262306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata = sta->sdata; 189362306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 189462306a36Sopenharmony_ci int ac; 189562306a36Sopenharmony_ci 189662306a36Sopenharmony_ci /* Get response frame(s) and more data bit for the last one. */ 189762306a36Sopenharmony_ci for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { 189862306a36Sopenharmony_ci unsigned long tids; 189962306a36Sopenharmony_ci 190062306a36Sopenharmony_ci if (ignored_acs & ieee80211_ac_to_qos_mask[ac]) 190162306a36Sopenharmony_ci continue; 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_ci tids = ieee80211_tids_for_ac(ac); 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_ci /* if we already have frames from software, then we can't also 190662306a36Sopenharmony_ci * release from hardware queues 190762306a36Sopenharmony_ci */ 190862306a36Sopenharmony_ci if (skb_queue_empty(frames)) { 190962306a36Sopenharmony_ci *driver_release_tids |= 191062306a36Sopenharmony_ci sta->driver_buffered_tids & tids; 191162306a36Sopenharmony_ci *driver_release_tids |= sta->txq_buffered_tids & tids; 191262306a36Sopenharmony_ci } 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_ci if (!*driver_release_tids) { 191562306a36Sopenharmony_ci struct sk_buff *skb; 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_ci while (n_frames > 0) { 191862306a36Sopenharmony_ci skb = skb_dequeue(&sta->tx_filtered[ac]); 191962306a36Sopenharmony_ci if (!skb) { 192062306a36Sopenharmony_ci skb = skb_dequeue( 192162306a36Sopenharmony_ci &sta->ps_tx_buf[ac]); 192262306a36Sopenharmony_ci if (skb) 192362306a36Sopenharmony_ci local->total_ps_buffered--; 192462306a36Sopenharmony_ci } 192562306a36Sopenharmony_ci if (!skb) 192662306a36Sopenharmony_ci break; 192762306a36Sopenharmony_ci n_frames--; 192862306a36Sopenharmony_ci __skb_queue_tail(frames, skb); 192962306a36Sopenharmony_ci } 193062306a36Sopenharmony_ci } 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_ci /* If we have more frames buffered on this AC, then abort the 193362306a36Sopenharmony_ci * loop since we can't send more data from other ACs before 193462306a36Sopenharmony_ci * the buffered frames from this. 193562306a36Sopenharmony_ci */ 193662306a36Sopenharmony_ci if (!skb_queue_empty(&sta->tx_filtered[ac]) || 193762306a36Sopenharmony_ci !skb_queue_empty(&sta->ps_tx_buf[ac])) 193862306a36Sopenharmony_ci break; 193962306a36Sopenharmony_ci } 194062306a36Sopenharmony_ci} 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_cistatic void 194362306a36Sopenharmony_ciieee80211_sta_ps_deliver_response(struct sta_info *sta, 194462306a36Sopenharmony_ci int n_frames, u8 ignored_acs, 194562306a36Sopenharmony_ci enum ieee80211_frame_release_type reason) 194662306a36Sopenharmony_ci{ 194762306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata = sta->sdata; 194862306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 194962306a36Sopenharmony_ci unsigned long driver_release_tids = 0; 195062306a36Sopenharmony_ci struct sk_buff_head frames; 195162306a36Sopenharmony_ci bool more_data; 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_ci /* Service or PS-Poll period starts */ 195462306a36Sopenharmony_ci set_sta_flag(sta, WLAN_STA_SP); 195562306a36Sopenharmony_ci 195662306a36Sopenharmony_ci __skb_queue_head_init(&frames); 195762306a36Sopenharmony_ci 195862306a36Sopenharmony_ci ieee80211_sta_ps_get_frames(sta, n_frames, ignored_acs, reason, 195962306a36Sopenharmony_ci &frames, &driver_release_tids); 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_ci more_data = ieee80211_sta_ps_more_data(sta, ignored_acs, reason, driver_release_tids); 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_ci if (driver_release_tids && reason == IEEE80211_FRAME_RELEASE_PSPOLL) 196462306a36Sopenharmony_ci driver_release_tids = 196562306a36Sopenharmony_ci BIT(find_highest_prio_tid(driver_release_tids)); 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_ci if (skb_queue_empty(&frames) && !driver_release_tids) { 196862306a36Sopenharmony_ci int tid, ac; 196962306a36Sopenharmony_ci 197062306a36Sopenharmony_ci /* 197162306a36Sopenharmony_ci * For PS-Poll, this can only happen due to a race condition 197262306a36Sopenharmony_ci * when we set the TIM bit and the station notices it, but 197362306a36Sopenharmony_ci * before it can poll for the frame we expire it. 197462306a36Sopenharmony_ci * 197562306a36Sopenharmony_ci * For uAPSD, this is said in the standard (11.2.1.5 h): 197662306a36Sopenharmony_ci * At each unscheduled SP for a non-AP STA, the AP shall 197762306a36Sopenharmony_ci * attempt to transmit at least one MSDU or MMPDU, but no 197862306a36Sopenharmony_ci * more than the value specified in the Max SP Length field 197962306a36Sopenharmony_ci * in the QoS Capability element from delivery-enabled ACs, 198062306a36Sopenharmony_ci * that are destined for the non-AP STA. 198162306a36Sopenharmony_ci * 198262306a36Sopenharmony_ci * Since we have no other MSDU/MMPDU, transmit a QoS null frame. 198362306a36Sopenharmony_ci */ 198462306a36Sopenharmony_ci 198562306a36Sopenharmony_ci /* This will evaluate to 1, 3, 5 or 7. */ 198662306a36Sopenharmony_ci for (ac = IEEE80211_AC_VO; ac < IEEE80211_NUM_ACS; ac++) 198762306a36Sopenharmony_ci if (!(ignored_acs & ieee80211_ac_to_qos_mask[ac])) 198862306a36Sopenharmony_ci break; 198962306a36Sopenharmony_ci tid = 7 - 2 * ac; 199062306a36Sopenharmony_ci 199162306a36Sopenharmony_ci ieee80211_send_null_response(sta, tid, reason, true, false); 199262306a36Sopenharmony_ci } else if (!driver_release_tids) { 199362306a36Sopenharmony_ci struct sk_buff_head pending; 199462306a36Sopenharmony_ci struct sk_buff *skb; 199562306a36Sopenharmony_ci int num = 0; 199662306a36Sopenharmony_ci u16 tids = 0; 199762306a36Sopenharmony_ci bool need_null = false; 199862306a36Sopenharmony_ci 199962306a36Sopenharmony_ci skb_queue_head_init(&pending); 200062306a36Sopenharmony_ci 200162306a36Sopenharmony_ci while ((skb = __skb_dequeue(&frames))) { 200262306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 200362306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (void *) skb->data; 200462306a36Sopenharmony_ci u8 *qoshdr = NULL; 200562306a36Sopenharmony_ci 200662306a36Sopenharmony_ci num++; 200762306a36Sopenharmony_ci 200862306a36Sopenharmony_ci /* 200962306a36Sopenharmony_ci * Tell TX path to send this frame even though the 201062306a36Sopenharmony_ci * STA may still remain is PS mode after this frame 201162306a36Sopenharmony_ci * exchange. 201262306a36Sopenharmony_ci */ 201362306a36Sopenharmony_ci info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER; 201462306a36Sopenharmony_ci info->control.flags |= IEEE80211_TX_CTRL_PS_RESPONSE; 201562306a36Sopenharmony_ci 201662306a36Sopenharmony_ci /* 201762306a36Sopenharmony_ci * Use MoreData flag to indicate whether there are 201862306a36Sopenharmony_ci * more buffered frames for this STA 201962306a36Sopenharmony_ci */ 202062306a36Sopenharmony_ci if (more_data || !skb_queue_empty(&frames)) 202162306a36Sopenharmony_ci hdr->frame_control |= 202262306a36Sopenharmony_ci cpu_to_le16(IEEE80211_FCTL_MOREDATA); 202362306a36Sopenharmony_ci else 202462306a36Sopenharmony_ci hdr->frame_control &= 202562306a36Sopenharmony_ci cpu_to_le16(~IEEE80211_FCTL_MOREDATA); 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_ci if (ieee80211_is_data_qos(hdr->frame_control) || 202862306a36Sopenharmony_ci ieee80211_is_qos_nullfunc(hdr->frame_control)) 202962306a36Sopenharmony_ci qoshdr = ieee80211_get_qos_ctl(hdr); 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_ci tids |= BIT(skb->priority); 203262306a36Sopenharmony_ci 203362306a36Sopenharmony_ci __skb_queue_tail(&pending, skb); 203462306a36Sopenharmony_ci 203562306a36Sopenharmony_ci /* end service period after last frame or add one */ 203662306a36Sopenharmony_ci if (!skb_queue_empty(&frames)) 203762306a36Sopenharmony_ci continue; 203862306a36Sopenharmony_ci 203962306a36Sopenharmony_ci if (reason != IEEE80211_FRAME_RELEASE_UAPSD) { 204062306a36Sopenharmony_ci /* for PS-Poll, there's only one frame */ 204162306a36Sopenharmony_ci info->flags |= IEEE80211_TX_STATUS_EOSP | 204262306a36Sopenharmony_ci IEEE80211_TX_CTL_REQ_TX_STATUS; 204362306a36Sopenharmony_ci break; 204462306a36Sopenharmony_ci } 204562306a36Sopenharmony_ci 204662306a36Sopenharmony_ci /* For uAPSD, things are a bit more complicated. If the 204762306a36Sopenharmony_ci * last frame has a QoS header (i.e. is a QoS-data or 204862306a36Sopenharmony_ci * QoS-nulldata frame) then just set the EOSP bit there 204962306a36Sopenharmony_ci * and be done. 205062306a36Sopenharmony_ci * If the frame doesn't have a QoS header (which means 205162306a36Sopenharmony_ci * it should be a bufferable MMPDU) then we can't set 205262306a36Sopenharmony_ci * the EOSP bit in the QoS header; add a QoS-nulldata 205362306a36Sopenharmony_ci * frame to the list to send it after the MMPDU. 205462306a36Sopenharmony_ci * 205562306a36Sopenharmony_ci * Note that this code is only in the mac80211-release 205662306a36Sopenharmony_ci * code path, we assume that the driver will not buffer 205762306a36Sopenharmony_ci * anything but QoS-data frames, or if it does, will 205862306a36Sopenharmony_ci * create the QoS-nulldata frame by itself if needed. 205962306a36Sopenharmony_ci * 206062306a36Sopenharmony_ci * Cf. 802.11-2012 10.2.1.10 (c). 206162306a36Sopenharmony_ci */ 206262306a36Sopenharmony_ci if (qoshdr) { 206362306a36Sopenharmony_ci *qoshdr |= IEEE80211_QOS_CTL_EOSP; 206462306a36Sopenharmony_ci 206562306a36Sopenharmony_ci info->flags |= IEEE80211_TX_STATUS_EOSP | 206662306a36Sopenharmony_ci IEEE80211_TX_CTL_REQ_TX_STATUS; 206762306a36Sopenharmony_ci } else { 206862306a36Sopenharmony_ci /* The standard isn't completely clear on this 206962306a36Sopenharmony_ci * as it says the more-data bit should be set 207062306a36Sopenharmony_ci * if there are more BUs. The QoS-Null frame 207162306a36Sopenharmony_ci * we're about to send isn't buffered yet, we 207262306a36Sopenharmony_ci * only create it below, but let's pretend it 207362306a36Sopenharmony_ci * was buffered just in case some clients only 207462306a36Sopenharmony_ci * expect more-data=0 when eosp=1. 207562306a36Sopenharmony_ci */ 207662306a36Sopenharmony_ci hdr->frame_control |= 207762306a36Sopenharmony_ci cpu_to_le16(IEEE80211_FCTL_MOREDATA); 207862306a36Sopenharmony_ci need_null = true; 207962306a36Sopenharmony_ci num++; 208062306a36Sopenharmony_ci } 208162306a36Sopenharmony_ci break; 208262306a36Sopenharmony_ci } 208362306a36Sopenharmony_ci 208462306a36Sopenharmony_ci drv_allow_buffered_frames(local, sta, tids, num, 208562306a36Sopenharmony_ci reason, more_data); 208662306a36Sopenharmony_ci 208762306a36Sopenharmony_ci ieee80211_add_pending_skbs(local, &pending); 208862306a36Sopenharmony_ci 208962306a36Sopenharmony_ci if (need_null) 209062306a36Sopenharmony_ci ieee80211_send_null_response( 209162306a36Sopenharmony_ci sta, find_highest_prio_tid(tids), 209262306a36Sopenharmony_ci reason, false, false); 209362306a36Sopenharmony_ci 209462306a36Sopenharmony_ci sta_info_recalc_tim(sta); 209562306a36Sopenharmony_ci } else { 209662306a36Sopenharmony_ci int tid; 209762306a36Sopenharmony_ci 209862306a36Sopenharmony_ci /* 209962306a36Sopenharmony_ci * We need to release a frame that is buffered somewhere in the 210062306a36Sopenharmony_ci * driver ... it'll have to handle that. 210162306a36Sopenharmony_ci * Note that the driver also has to check the number of frames 210262306a36Sopenharmony_ci * on the TIDs we're releasing from - if there are more than 210362306a36Sopenharmony_ci * n_frames it has to set the more-data bit (if we didn't ask 210462306a36Sopenharmony_ci * it to set it anyway due to other buffered frames); if there 210562306a36Sopenharmony_ci * are fewer than n_frames it has to make sure to adjust that 210662306a36Sopenharmony_ci * to allow the service period to end properly. 210762306a36Sopenharmony_ci */ 210862306a36Sopenharmony_ci drv_release_buffered_frames(local, sta, driver_release_tids, 210962306a36Sopenharmony_ci n_frames, reason, more_data); 211062306a36Sopenharmony_ci 211162306a36Sopenharmony_ci /* 211262306a36Sopenharmony_ci * Note that we don't recalculate the TIM bit here as it would 211362306a36Sopenharmony_ci * most likely have no effect at all unless the driver told us 211462306a36Sopenharmony_ci * that the TID(s) became empty before returning here from the 211562306a36Sopenharmony_ci * release function. 211662306a36Sopenharmony_ci * Either way, however, when the driver tells us that the TID(s) 211762306a36Sopenharmony_ci * became empty or we find that a txq became empty, we'll do the 211862306a36Sopenharmony_ci * TIM recalculation. 211962306a36Sopenharmony_ci */ 212062306a36Sopenharmony_ci 212162306a36Sopenharmony_ci for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) { 212262306a36Sopenharmony_ci if (!sta->sta.txq[tid] || 212362306a36Sopenharmony_ci !(driver_release_tids & BIT(tid)) || 212462306a36Sopenharmony_ci txq_has_queue(sta->sta.txq[tid])) 212562306a36Sopenharmony_ci continue; 212662306a36Sopenharmony_ci 212762306a36Sopenharmony_ci sta_info_recalc_tim(sta); 212862306a36Sopenharmony_ci break; 212962306a36Sopenharmony_ci } 213062306a36Sopenharmony_ci } 213162306a36Sopenharmony_ci} 213262306a36Sopenharmony_ci 213362306a36Sopenharmony_civoid ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta) 213462306a36Sopenharmony_ci{ 213562306a36Sopenharmony_ci u8 ignore_for_response = sta->sta.uapsd_queues; 213662306a36Sopenharmony_ci 213762306a36Sopenharmony_ci /* 213862306a36Sopenharmony_ci * If all ACs are delivery-enabled then we should reply 213962306a36Sopenharmony_ci * from any of them, if only some are enabled we reply 214062306a36Sopenharmony_ci * only from the non-enabled ones. 214162306a36Sopenharmony_ci */ 214262306a36Sopenharmony_ci if (ignore_for_response == BIT(IEEE80211_NUM_ACS) - 1) 214362306a36Sopenharmony_ci ignore_for_response = 0; 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci ieee80211_sta_ps_deliver_response(sta, 1, ignore_for_response, 214662306a36Sopenharmony_ci IEEE80211_FRAME_RELEASE_PSPOLL); 214762306a36Sopenharmony_ci} 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_civoid ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta) 215062306a36Sopenharmony_ci{ 215162306a36Sopenharmony_ci int n_frames = sta->sta.max_sp; 215262306a36Sopenharmony_ci u8 delivery_enabled = sta->sta.uapsd_queues; 215362306a36Sopenharmony_ci 215462306a36Sopenharmony_ci /* 215562306a36Sopenharmony_ci * If we ever grow support for TSPEC this might happen if 215662306a36Sopenharmony_ci * the TSPEC update from hostapd comes in between a trigger 215762306a36Sopenharmony_ci * frame setting WLAN_STA_UAPSD in the RX path and this 215862306a36Sopenharmony_ci * actually getting called. 215962306a36Sopenharmony_ci */ 216062306a36Sopenharmony_ci if (!delivery_enabled) 216162306a36Sopenharmony_ci return; 216262306a36Sopenharmony_ci 216362306a36Sopenharmony_ci switch (sta->sta.max_sp) { 216462306a36Sopenharmony_ci case 1: 216562306a36Sopenharmony_ci n_frames = 2; 216662306a36Sopenharmony_ci break; 216762306a36Sopenharmony_ci case 2: 216862306a36Sopenharmony_ci n_frames = 4; 216962306a36Sopenharmony_ci break; 217062306a36Sopenharmony_ci case 3: 217162306a36Sopenharmony_ci n_frames = 6; 217262306a36Sopenharmony_ci break; 217362306a36Sopenharmony_ci case 0: 217462306a36Sopenharmony_ci /* XXX: what is a good value? */ 217562306a36Sopenharmony_ci n_frames = 128; 217662306a36Sopenharmony_ci break; 217762306a36Sopenharmony_ci } 217862306a36Sopenharmony_ci 217962306a36Sopenharmony_ci ieee80211_sta_ps_deliver_response(sta, n_frames, ~delivery_enabled, 218062306a36Sopenharmony_ci IEEE80211_FRAME_RELEASE_UAPSD); 218162306a36Sopenharmony_ci} 218262306a36Sopenharmony_ci 218362306a36Sopenharmony_civoid ieee80211_sta_block_awake(struct ieee80211_hw *hw, 218462306a36Sopenharmony_ci struct ieee80211_sta *pubsta, bool block) 218562306a36Sopenharmony_ci{ 218662306a36Sopenharmony_ci struct sta_info *sta = container_of(pubsta, struct sta_info, sta); 218762306a36Sopenharmony_ci 218862306a36Sopenharmony_ci trace_api_sta_block_awake(sta->local, pubsta, block); 218962306a36Sopenharmony_ci 219062306a36Sopenharmony_ci if (block) { 219162306a36Sopenharmony_ci set_sta_flag(sta, WLAN_STA_PS_DRIVER); 219262306a36Sopenharmony_ci ieee80211_clear_fast_xmit(sta); 219362306a36Sopenharmony_ci return; 219462306a36Sopenharmony_ci } 219562306a36Sopenharmony_ci 219662306a36Sopenharmony_ci if (!test_sta_flag(sta, WLAN_STA_PS_DRIVER)) 219762306a36Sopenharmony_ci return; 219862306a36Sopenharmony_ci 219962306a36Sopenharmony_ci if (!test_sta_flag(sta, WLAN_STA_PS_STA)) { 220062306a36Sopenharmony_ci set_sta_flag(sta, WLAN_STA_PS_DELIVER); 220162306a36Sopenharmony_ci clear_sta_flag(sta, WLAN_STA_PS_DRIVER); 220262306a36Sopenharmony_ci ieee80211_queue_work(hw, &sta->drv_deliver_wk); 220362306a36Sopenharmony_ci } else if (test_sta_flag(sta, WLAN_STA_PSPOLL) || 220462306a36Sopenharmony_ci test_sta_flag(sta, WLAN_STA_UAPSD)) { 220562306a36Sopenharmony_ci /* must be asleep in this case */ 220662306a36Sopenharmony_ci clear_sta_flag(sta, WLAN_STA_PS_DRIVER); 220762306a36Sopenharmony_ci ieee80211_queue_work(hw, &sta->drv_deliver_wk); 220862306a36Sopenharmony_ci } else { 220962306a36Sopenharmony_ci clear_sta_flag(sta, WLAN_STA_PS_DRIVER); 221062306a36Sopenharmony_ci ieee80211_check_fast_xmit(sta); 221162306a36Sopenharmony_ci } 221262306a36Sopenharmony_ci} 221362306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_sta_block_awake); 221462306a36Sopenharmony_ci 221562306a36Sopenharmony_civoid ieee80211_sta_eosp(struct ieee80211_sta *pubsta) 221662306a36Sopenharmony_ci{ 221762306a36Sopenharmony_ci struct sta_info *sta = container_of(pubsta, struct sta_info, sta); 221862306a36Sopenharmony_ci struct ieee80211_local *local = sta->local; 221962306a36Sopenharmony_ci 222062306a36Sopenharmony_ci trace_api_eosp(local, pubsta); 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_ci clear_sta_flag(sta, WLAN_STA_SP); 222362306a36Sopenharmony_ci} 222462306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_sta_eosp); 222562306a36Sopenharmony_ci 222662306a36Sopenharmony_civoid ieee80211_send_eosp_nullfunc(struct ieee80211_sta *pubsta, int tid) 222762306a36Sopenharmony_ci{ 222862306a36Sopenharmony_ci struct sta_info *sta = container_of(pubsta, struct sta_info, sta); 222962306a36Sopenharmony_ci enum ieee80211_frame_release_type reason; 223062306a36Sopenharmony_ci bool more_data; 223162306a36Sopenharmony_ci 223262306a36Sopenharmony_ci trace_api_send_eosp_nullfunc(sta->local, pubsta, tid); 223362306a36Sopenharmony_ci 223462306a36Sopenharmony_ci reason = IEEE80211_FRAME_RELEASE_UAPSD; 223562306a36Sopenharmony_ci more_data = ieee80211_sta_ps_more_data(sta, ~sta->sta.uapsd_queues, 223662306a36Sopenharmony_ci reason, 0); 223762306a36Sopenharmony_ci 223862306a36Sopenharmony_ci ieee80211_send_null_response(sta, tid, reason, false, more_data); 223962306a36Sopenharmony_ci} 224062306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_send_eosp_nullfunc); 224162306a36Sopenharmony_ci 224262306a36Sopenharmony_civoid ieee80211_sta_set_buffered(struct ieee80211_sta *pubsta, 224362306a36Sopenharmony_ci u8 tid, bool buffered) 224462306a36Sopenharmony_ci{ 224562306a36Sopenharmony_ci struct sta_info *sta = container_of(pubsta, struct sta_info, sta); 224662306a36Sopenharmony_ci 224762306a36Sopenharmony_ci if (WARN_ON(tid >= IEEE80211_NUM_TIDS)) 224862306a36Sopenharmony_ci return; 224962306a36Sopenharmony_ci 225062306a36Sopenharmony_ci trace_api_sta_set_buffered(sta->local, pubsta, tid, buffered); 225162306a36Sopenharmony_ci 225262306a36Sopenharmony_ci if (buffered) 225362306a36Sopenharmony_ci set_bit(tid, &sta->driver_buffered_tids); 225462306a36Sopenharmony_ci else 225562306a36Sopenharmony_ci clear_bit(tid, &sta->driver_buffered_tids); 225662306a36Sopenharmony_ci 225762306a36Sopenharmony_ci sta_info_recalc_tim(sta); 225862306a36Sopenharmony_ci} 225962306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_sta_set_buffered); 226062306a36Sopenharmony_ci 226162306a36Sopenharmony_civoid ieee80211_sta_register_airtime(struct ieee80211_sta *pubsta, u8 tid, 226262306a36Sopenharmony_ci u32 tx_airtime, u32 rx_airtime) 226362306a36Sopenharmony_ci{ 226462306a36Sopenharmony_ci struct sta_info *sta = container_of(pubsta, struct sta_info, sta); 226562306a36Sopenharmony_ci struct ieee80211_local *local = sta->sdata->local; 226662306a36Sopenharmony_ci u8 ac = ieee80211_ac_from_tid(tid); 226762306a36Sopenharmony_ci u32 airtime = 0; 226862306a36Sopenharmony_ci u32 diff; 226962306a36Sopenharmony_ci 227062306a36Sopenharmony_ci if (sta->local->airtime_flags & AIRTIME_USE_TX) 227162306a36Sopenharmony_ci airtime += tx_airtime; 227262306a36Sopenharmony_ci if (sta->local->airtime_flags & AIRTIME_USE_RX) 227362306a36Sopenharmony_ci airtime += rx_airtime; 227462306a36Sopenharmony_ci 227562306a36Sopenharmony_ci spin_lock_bh(&local->active_txq_lock[ac]); 227662306a36Sopenharmony_ci sta->airtime[ac].tx_airtime += tx_airtime; 227762306a36Sopenharmony_ci sta->airtime[ac].rx_airtime += rx_airtime; 227862306a36Sopenharmony_ci 227962306a36Sopenharmony_ci diff = (u32)jiffies - sta->airtime[ac].last_active; 228062306a36Sopenharmony_ci if (diff <= AIRTIME_ACTIVE_DURATION) 228162306a36Sopenharmony_ci sta->airtime[ac].deficit -= airtime; 228262306a36Sopenharmony_ci 228362306a36Sopenharmony_ci spin_unlock_bh(&local->active_txq_lock[ac]); 228462306a36Sopenharmony_ci} 228562306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_sta_register_airtime); 228662306a36Sopenharmony_ci 228762306a36Sopenharmony_civoid __ieee80211_sta_recalc_aggregates(struct sta_info *sta, u16 active_links) 228862306a36Sopenharmony_ci{ 228962306a36Sopenharmony_ci bool first = true; 229062306a36Sopenharmony_ci int link_id; 229162306a36Sopenharmony_ci 229262306a36Sopenharmony_ci if (!sta->sta.valid_links || !sta->sta.mlo) { 229362306a36Sopenharmony_ci sta->sta.cur = &sta->sta.deflink.agg; 229462306a36Sopenharmony_ci return; 229562306a36Sopenharmony_ci } 229662306a36Sopenharmony_ci 229762306a36Sopenharmony_ci rcu_read_lock(); 229862306a36Sopenharmony_ci for (link_id = 0; link_id < ARRAY_SIZE((sta)->link); link_id++) { 229962306a36Sopenharmony_ci struct ieee80211_link_sta *link_sta; 230062306a36Sopenharmony_ci int i; 230162306a36Sopenharmony_ci 230262306a36Sopenharmony_ci if (!(active_links & BIT(link_id))) 230362306a36Sopenharmony_ci continue; 230462306a36Sopenharmony_ci 230562306a36Sopenharmony_ci link_sta = rcu_dereference(sta->sta.link[link_id]); 230662306a36Sopenharmony_ci if (!link_sta) 230762306a36Sopenharmony_ci continue; 230862306a36Sopenharmony_ci 230962306a36Sopenharmony_ci if (first) { 231062306a36Sopenharmony_ci sta->cur = sta->sta.deflink.agg; 231162306a36Sopenharmony_ci first = false; 231262306a36Sopenharmony_ci continue; 231362306a36Sopenharmony_ci } 231462306a36Sopenharmony_ci 231562306a36Sopenharmony_ci sta->cur.max_amsdu_len = 231662306a36Sopenharmony_ci min(sta->cur.max_amsdu_len, 231762306a36Sopenharmony_ci link_sta->agg.max_amsdu_len); 231862306a36Sopenharmony_ci sta->cur.max_rc_amsdu_len = 231962306a36Sopenharmony_ci min(sta->cur.max_rc_amsdu_len, 232062306a36Sopenharmony_ci link_sta->agg.max_rc_amsdu_len); 232162306a36Sopenharmony_ci 232262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sta->cur.max_tid_amsdu_len); i++) 232362306a36Sopenharmony_ci sta->cur.max_tid_amsdu_len[i] = 232462306a36Sopenharmony_ci min(sta->cur.max_tid_amsdu_len[i], 232562306a36Sopenharmony_ci link_sta->agg.max_tid_amsdu_len[i]); 232662306a36Sopenharmony_ci } 232762306a36Sopenharmony_ci rcu_read_unlock(); 232862306a36Sopenharmony_ci 232962306a36Sopenharmony_ci sta->sta.cur = &sta->cur; 233062306a36Sopenharmony_ci} 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_civoid ieee80211_sta_recalc_aggregates(struct ieee80211_sta *pubsta) 233362306a36Sopenharmony_ci{ 233462306a36Sopenharmony_ci struct sta_info *sta = container_of(pubsta, struct sta_info, sta); 233562306a36Sopenharmony_ci 233662306a36Sopenharmony_ci __ieee80211_sta_recalc_aggregates(sta, sta->sdata->vif.active_links); 233762306a36Sopenharmony_ci} 233862306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_sta_recalc_aggregates); 233962306a36Sopenharmony_ci 234062306a36Sopenharmony_civoid ieee80211_sta_update_pending_airtime(struct ieee80211_local *local, 234162306a36Sopenharmony_ci struct sta_info *sta, u8 ac, 234262306a36Sopenharmony_ci u16 tx_airtime, bool tx_completed) 234362306a36Sopenharmony_ci{ 234462306a36Sopenharmony_ci int tx_pending; 234562306a36Sopenharmony_ci 234662306a36Sopenharmony_ci if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) 234762306a36Sopenharmony_ci return; 234862306a36Sopenharmony_ci 234962306a36Sopenharmony_ci if (!tx_completed) { 235062306a36Sopenharmony_ci if (sta) 235162306a36Sopenharmony_ci atomic_add(tx_airtime, 235262306a36Sopenharmony_ci &sta->airtime[ac].aql_tx_pending); 235362306a36Sopenharmony_ci 235462306a36Sopenharmony_ci atomic_add(tx_airtime, &local->aql_total_pending_airtime); 235562306a36Sopenharmony_ci atomic_add(tx_airtime, &local->aql_ac_pending_airtime[ac]); 235662306a36Sopenharmony_ci return; 235762306a36Sopenharmony_ci } 235862306a36Sopenharmony_ci 235962306a36Sopenharmony_ci if (sta) { 236062306a36Sopenharmony_ci tx_pending = atomic_sub_return(tx_airtime, 236162306a36Sopenharmony_ci &sta->airtime[ac].aql_tx_pending); 236262306a36Sopenharmony_ci if (tx_pending < 0) 236362306a36Sopenharmony_ci atomic_cmpxchg(&sta->airtime[ac].aql_tx_pending, 236462306a36Sopenharmony_ci tx_pending, 0); 236562306a36Sopenharmony_ci } 236662306a36Sopenharmony_ci 236762306a36Sopenharmony_ci atomic_sub(tx_airtime, &local->aql_total_pending_airtime); 236862306a36Sopenharmony_ci tx_pending = atomic_sub_return(tx_airtime, 236962306a36Sopenharmony_ci &local->aql_ac_pending_airtime[ac]); 237062306a36Sopenharmony_ci if (WARN_ONCE(tx_pending < 0, 237162306a36Sopenharmony_ci "Device %s AC %d pending airtime underflow: %u, %u", 237262306a36Sopenharmony_ci wiphy_name(local->hw.wiphy), ac, tx_pending, 237362306a36Sopenharmony_ci tx_airtime)) { 237462306a36Sopenharmony_ci atomic_cmpxchg(&local->aql_ac_pending_airtime[ac], 237562306a36Sopenharmony_ci tx_pending, 0); 237662306a36Sopenharmony_ci atomic_sub(tx_pending, &local->aql_total_pending_airtime); 237762306a36Sopenharmony_ci } 237862306a36Sopenharmony_ci} 237962306a36Sopenharmony_ci 238062306a36Sopenharmony_cistatic struct ieee80211_sta_rx_stats * 238162306a36Sopenharmony_cista_get_last_rx_stats(struct sta_info *sta) 238262306a36Sopenharmony_ci{ 238362306a36Sopenharmony_ci struct ieee80211_sta_rx_stats *stats = &sta->deflink.rx_stats; 238462306a36Sopenharmony_ci int cpu; 238562306a36Sopenharmony_ci 238662306a36Sopenharmony_ci if (!sta->deflink.pcpu_rx_stats) 238762306a36Sopenharmony_ci return stats; 238862306a36Sopenharmony_ci 238962306a36Sopenharmony_ci for_each_possible_cpu(cpu) { 239062306a36Sopenharmony_ci struct ieee80211_sta_rx_stats *cpustats; 239162306a36Sopenharmony_ci 239262306a36Sopenharmony_ci cpustats = per_cpu_ptr(sta->deflink.pcpu_rx_stats, cpu); 239362306a36Sopenharmony_ci 239462306a36Sopenharmony_ci if (time_after(cpustats->last_rx, stats->last_rx)) 239562306a36Sopenharmony_ci stats = cpustats; 239662306a36Sopenharmony_ci } 239762306a36Sopenharmony_ci 239862306a36Sopenharmony_ci return stats; 239962306a36Sopenharmony_ci} 240062306a36Sopenharmony_ci 240162306a36Sopenharmony_cistatic void sta_stats_decode_rate(struct ieee80211_local *local, u32 rate, 240262306a36Sopenharmony_ci struct rate_info *rinfo) 240362306a36Sopenharmony_ci{ 240462306a36Sopenharmony_ci rinfo->bw = STA_STATS_GET(BW, rate); 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_ci switch (STA_STATS_GET(TYPE, rate)) { 240762306a36Sopenharmony_ci case STA_STATS_RATE_TYPE_VHT: 240862306a36Sopenharmony_ci rinfo->flags = RATE_INFO_FLAGS_VHT_MCS; 240962306a36Sopenharmony_ci rinfo->mcs = STA_STATS_GET(VHT_MCS, rate); 241062306a36Sopenharmony_ci rinfo->nss = STA_STATS_GET(VHT_NSS, rate); 241162306a36Sopenharmony_ci if (STA_STATS_GET(SGI, rate)) 241262306a36Sopenharmony_ci rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI; 241362306a36Sopenharmony_ci break; 241462306a36Sopenharmony_ci case STA_STATS_RATE_TYPE_HT: 241562306a36Sopenharmony_ci rinfo->flags = RATE_INFO_FLAGS_MCS; 241662306a36Sopenharmony_ci rinfo->mcs = STA_STATS_GET(HT_MCS, rate); 241762306a36Sopenharmony_ci if (STA_STATS_GET(SGI, rate)) 241862306a36Sopenharmony_ci rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI; 241962306a36Sopenharmony_ci break; 242062306a36Sopenharmony_ci case STA_STATS_RATE_TYPE_LEGACY: { 242162306a36Sopenharmony_ci struct ieee80211_supported_band *sband; 242262306a36Sopenharmony_ci u16 brate; 242362306a36Sopenharmony_ci unsigned int shift; 242462306a36Sopenharmony_ci int band = STA_STATS_GET(LEGACY_BAND, rate); 242562306a36Sopenharmony_ci int rate_idx = STA_STATS_GET(LEGACY_IDX, rate); 242662306a36Sopenharmony_ci 242762306a36Sopenharmony_ci sband = local->hw.wiphy->bands[band]; 242862306a36Sopenharmony_ci 242962306a36Sopenharmony_ci if (WARN_ON_ONCE(!sband->bitrates)) 243062306a36Sopenharmony_ci break; 243162306a36Sopenharmony_ci 243262306a36Sopenharmony_ci brate = sband->bitrates[rate_idx].bitrate; 243362306a36Sopenharmony_ci if (rinfo->bw == RATE_INFO_BW_5) 243462306a36Sopenharmony_ci shift = 2; 243562306a36Sopenharmony_ci else if (rinfo->bw == RATE_INFO_BW_10) 243662306a36Sopenharmony_ci shift = 1; 243762306a36Sopenharmony_ci else 243862306a36Sopenharmony_ci shift = 0; 243962306a36Sopenharmony_ci rinfo->legacy = DIV_ROUND_UP(brate, 1 << shift); 244062306a36Sopenharmony_ci break; 244162306a36Sopenharmony_ci } 244262306a36Sopenharmony_ci case STA_STATS_RATE_TYPE_HE: 244362306a36Sopenharmony_ci rinfo->flags = RATE_INFO_FLAGS_HE_MCS; 244462306a36Sopenharmony_ci rinfo->mcs = STA_STATS_GET(HE_MCS, rate); 244562306a36Sopenharmony_ci rinfo->nss = STA_STATS_GET(HE_NSS, rate); 244662306a36Sopenharmony_ci rinfo->he_gi = STA_STATS_GET(HE_GI, rate); 244762306a36Sopenharmony_ci rinfo->he_ru_alloc = STA_STATS_GET(HE_RU, rate); 244862306a36Sopenharmony_ci rinfo->he_dcm = STA_STATS_GET(HE_DCM, rate); 244962306a36Sopenharmony_ci break; 245062306a36Sopenharmony_ci case STA_STATS_RATE_TYPE_EHT: 245162306a36Sopenharmony_ci rinfo->flags = RATE_INFO_FLAGS_EHT_MCS; 245262306a36Sopenharmony_ci rinfo->mcs = STA_STATS_GET(EHT_MCS, rate); 245362306a36Sopenharmony_ci rinfo->nss = STA_STATS_GET(EHT_NSS, rate); 245462306a36Sopenharmony_ci rinfo->eht_gi = STA_STATS_GET(EHT_GI, rate); 245562306a36Sopenharmony_ci rinfo->eht_ru_alloc = STA_STATS_GET(EHT_RU, rate); 245662306a36Sopenharmony_ci break; 245762306a36Sopenharmony_ci } 245862306a36Sopenharmony_ci} 245962306a36Sopenharmony_ci 246062306a36Sopenharmony_cistatic int sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo) 246162306a36Sopenharmony_ci{ 246262306a36Sopenharmony_ci u32 rate = READ_ONCE(sta_get_last_rx_stats(sta)->last_rate); 246362306a36Sopenharmony_ci 246462306a36Sopenharmony_ci if (rate == STA_STATS_RATE_INVALID) 246562306a36Sopenharmony_ci return -EINVAL; 246662306a36Sopenharmony_ci 246762306a36Sopenharmony_ci sta_stats_decode_rate(sta->local, rate, rinfo); 246862306a36Sopenharmony_ci return 0; 246962306a36Sopenharmony_ci} 247062306a36Sopenharmony_ci 247162306a36Sopenharmony_cistatic inline u64 sta_get_tidstats_msdu(struct ieee80211_sta_rx_stats *rxstats, 247262306a36Sopenharmony_ci int tid) 247362306a36Sopenharmony_ci{ 247462306a36Sopenharmony_ci unsigned int start; 247562306a36Sopenharmony_ci u64 value; 247662306a36Sopenharmony_ci 247762306a36Sopenharmony_ci do { 247862306a36Sopenharmony_ci start = u64_stats_fetch_begin(&rxstats->syncp); 247962306a36Sopenharmony_ci value = rxstats->msdu[tid]; 248062306a36Sopenharmony_ci } while (u64_stats_fetch_retry(&rxstats->syncp, start)); 248162306a36Sopenharmony_ci 248262306a36Sopenharmony_ci return value; 248362306a36Sopenharmony_ci} 248462306a36Sopenharmony_ci 248562306a36Sopenharmony_cistatic void sta_set_tidstats(struct sta_info *sta, 248662306a36Sopenharmony_ci struct cfg80211_tid_stats *tidstats, 248762306a36Sopenharmony_ci int tid) 248862306a36Sopenharmony_ci{ 248962306a36Sopenharmony_ci struct ieee80211_local *local = sta->local; 249062306a36Sopenharmony_ci int cpu; 249162306a36Sopenharmony_ci 249262306a36Sopenharmony_ci if (!(tidstats->filled & BIT(NL80211_TID_STATS_RX_MSDU))) { 249362306a36Sopenharmony_ci tidstats->rx_msdu += sta_get_tidstats_msdu(&sta->deflink.rx_stats, 249462306a36Sopenharmony_ci tid); 249562306a36Sopenharmony_ci 249662306a36Sopenharmony_ci if (sta->deflink.pcpu_rx_stats) { 249762306a36Sopenharmony_ci for_each_possible_cpu(cpu) { 249862306a36Sopenharmony_ci struct ieee80211_sta_rx_stats *cpurxs; 249962306a36Sopenharmony_ci 250062306a36Sopenharmony_ci cpurxs = per_cpu_ptr(sta->deflink.pcpu_rx_stats, 250162306a36Sopenharmony_ci cpu); 250262306a36Sopenharmony_ci tidstats->rx_msdu += 250362306a36Sopenharmony_ci sta_get_tidstats_msdu(cpurxs, tid); 250462306a36Sopenharmony_ci } 250562306a36Sopenharmony_ci } 250662306a36Sopenharmony_ci 250762306a36Sopenharmony_ci tidstats->filled |= BIT(NL80211_TID_STATS_RX_MSDU); 250862306a36Sopenharmony_ci } 250962306a36Sopenharmony_ci 251062306a36Sopenharmony_ci if (!(tidstats->filled & BIT(NL80211_TID_STATS_TX_MSDU))) { 251162306a36Sopenharmony_ci tidstats->filled |= BIT(NL80211_TID_STATS_TX_MSDU); 251262306a36Sopenharmony_ci tidstats->tx_msdu = sta->deflink.tx_stats.msdu[tid]; 251362306a36Sopenharmony_ci } 251462306a36Sopenharmony_ci 251562306a36Sopenharmony_ci if (!(tidstats->filled & BIT(NL80211_TID_STATS_TX_MSDU_RETRIES)) && 251662306a36Sopenharmony_ci ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) { 251762306a36Sopenharmony_ci tidstats->filled |= BIT(NL80211_TID_STATS_TX_MSDU_RETRIES); 251862306a36Sopenharmony_ci tidstats->tx_msdu_retries = sta->deflink.status_stats.msdu_retries[tid]; 251962306a36Sopenharmony_ci } 252062306a36Sopenharmony_ci 252162306a36Sopenharmony_ci if (!(tidstats->filled & BIT(NL80211_TID_STATS_TX_MSDU_FAILED)) && 252262306a36Sopenharmony_ci ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) { 252362306a36Sopenharmony_ci tidstats->filled |= BIT(NL80211_TID_STATS_TX_MSDU_FAILED); 252462306a36Sopenharmony_ci tidstats->tx_msdu_failed = sta->deflink.status_stats.msdu_failed[tid]; 252562306a36Sopenharmony_ci } 252662306a36Sopenharmony_ci 252762306a36Sopenharmony_ci if (tid < IEEE80211_NUM_TIDS) { 252862306a36Sopenharmony_ci spin_lock_bh(&local->fq.lock); 252962306a36Sopenharmony_ci rcu_read_lock(); 253062306a36Sopenharmony_ci 253162306a36Sopenharmony_ci tidstats->filled |= BIT(NL80211_TID_STATS_TXQ_STATS); 253262306a36Sopenharmony_ci ieee80211_fill_txq_stats(&tidstats->txq_stats, 253362306a36Sopenharmony_ci to_txq_info(sta->sta.txq[tid])); 253462306a36Sopenharmony_ci 253562306a36Sopenharmony_ci rcu_read_unlock(); 253662306a36Sopenharmony_ci spin_unlock_bh(&local->fq.lock); 253762306a36Sopenharmony_ci } 253862306a36Sopenharmony_ci} 253962306a36Sopenharmony_ci 254062306a36Sopenharmony_cistatic inline u64 sta_get_stats_bytes(struct ieee80211_sta_rx_stats *rxstats) 254162306a36Sopenharmony_ci{ 254262306a36Sopenharmony_ci unsigned int start; 254362306a36Sopenharmony_ci u64 value; 254462306a36Sopenharmony_ci 254562306a36Sopenharmony_ci do { 254662306a36Sopenharmony_ci start = u64_stats_fetch_begin(&rxstats->syncp); 254762306a36Sopenharmony_ci value = rxstats->bytes; 254862306a36Sopenharmony_ci } while (u64_stats_fetch_retry(&rxstats->syncp, start)); 254962306a36Sopenharmony_ci 255062306a36Sopenharmony_ci return value; 255162306a36Sopenharmony_ci} 255262306a36Sopenharmony_ci 255362306a36Sopenharmony_civoid sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo, 255462306a36Sopenharmony_ci bool tidstats) 255562306a36Sopenharmony_ci{ 255662306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata = sta->sdata; 255762306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 255862306a36Sopenharmony_ci u32 thr = 0; 255962306a36Sopenharmony_ci int i, ac, cpu; 256062306a36Sopenharmony_ci struct ieee80211_sta_rx_stats *last_rxstats; 256162306a36Sopenharmony_ci 256262306a36Sopenharmony_ci last_rxstats = sta_get_last_rx_stats(sta); 256362306a36Sopenharmony_ci 256462306a36Sopenharmony_ci sinfo->generation = sdata->local->sta_generation; 256562306a36Sopenharmony_ci 256662306a36Sopenharmony_ci /* do before driver, so beacon filtering drivers have a 256762306a36Sopenharmony_ci * chance to e.g. just add the number of filtered beacons 256862306a36Sopenharmony_ci * (or just modify the value entirely, of course) 256962306a36Sopenharmony_ci */ 257062306a36Sopenharmony_ci if (sdata->vif.type == NL80211_IFTYPE_STATION) 257162306a36Sopenharmony_ci sinfo->rx_beacon = sdata->deflink.u.mgd.count_beacon_signal; 257262306a36Sopenharmony_ci 257362306a36Sopenharmony_ci drv_sta_statistics(local, sdata, &sta->sta, sinfo); 257462306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_INACTIVE_TIME) | 257562306a36Sopenharmony_ci BIT_ULL(NL80211_STA_INFO_STA_FLAGS) | 257662306a36Sopenharmony_ci BIT_ULL(NL80211_STA_INFO_BSS_PARAM) | 257762306a36Sopenharmony_ci BIT_ULL(NL80211_STA_INFO_CONNECTED_TIME) | 257862306a36Sopenharmony_ci BIT_ULL(NL80211_STA_INFO_ASSOC_AT_BOOTTIME) | 257962306a36Sopenharmony_ci BIT_ULL(NL80211_STA_INFO_RX_DROP_MISC); 258062306a36Sopenharmony_ci 258162306a36Sopenharmony_ci if (sdata->vif.type == NL80211_IFTYPE_STATION) { 258262306a36Sopenharmony_ci sinfo->beacon_loss_count = 258362306a36Sopenharmony_ci sdata->deflink.u.mgd.beacon_loss_count; 258462306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_BEACON_LOSS); 258562306a36Sopenharmony_ci } 258662306a36Sopenharmony_ci 258762306a36Sopenharmony_ci sinfo->connected_time = ktime_get_seconds() - sta->last_connected; 258862306a36Sopenharmony_ci sinfo->assoc_at = sta->assoc_at; 258962306a36Sopenharmony_ci sinfo->inactive_time = 259062306a36Sopenharmony_ci jiffies_to_msecs(jiffies - ieee80211_sta_last_active(sta)); 259162306a36Sopenharmony_ci 259262306a36Sopenharmony_ci if (!(sinfo->filled & (BIT_ULL(NL80211_STA_INFO_TX_BYTES64) | 259362306a36Sopenharmony_ci BIT_ULL(NL80211_STA_INFO_TX_BYTES)))) { 259462306a36Sopenharmony_ci sinfo->tx_bytes = 0; 259562306a36Sopenharmony_ci for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) 259662306a36Sopenharmony_ci sinfo->tx_bytes += sta->deflink.tx_stats.bytes[ac]; 259762306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BYTES64); 259862306a36Sopenharmony_ci } 259962306a36Sopenharmony_ci 260062306a36Sopenharmony_ci if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_PACKETS))) { 260162306a36Sopenharmony_ci sinfo->tx_packets = 0; 260262306a36Sopenharmony_ci for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) 260362306a36Sopenharmony_ci sinfo->tx_packets += sta->deflink.tx_stats.packets[ac]; 260462306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_PACKETS); 260562306a36Sopenharmony_ci } 260662306a36Sopenharmony_ci 260762306a36Sopenharmony_ci if (!(sinfo->filled & (BIT_ULL(NL80211_STA_INFO_RX_BYTES64) | 260862306a36Sopenharmony_ci BIT_ULL(NL80211_STA_INFO_RX_BYTES)))) { 260962306a36Sopenharmony_ci sinfo->rx_bytes += sta_get_stats_bytes(&sta->deflink.rx_stats); 261062306a36Sopenharmony_ci 261162306a36Sopenharmony_ci if (sta->deflink.pcpu_rx_stats) { 261262306a36Sopenharmony_ci for_each_possible_cpu(cpu) { 261362306a36Sopenharmony_ci struct ieee80211_sta_rx_stats *cpurxs; 261462306a36Sopenharmony_ci 261562306a36Sopenharmony_ci cpurxs = per_cpu_ptr(sta->deflink.pcpu_rx_stats, 261662306a36Sopenharmony_ci cpu); 261762306a36Sopenharmony_ci sinfo->rx_bytes += sta_get_stats_bytes(cpurxs); 261862306a36Sopenharmony_ci } 261962306a36Sopenharmony_ci } 262062306a36Sopenharmony_ci 262162306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BYTES64); 262262306a36Sopenharmony_ci } 262362306a36Sopenharmony_ci 262462306a36Sopenharmony_ci if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_RX_PACKETS))) { 262562306a36Sopenharmony_ci sinfo->rx_packets = sta->deflink.rx_stats.packets; 262662306a36Sopenharmony_ci if (sta->deflink.pcpu_rx_stats) { 262762306a36Sopenharmony_ci for_each_possible_cpu(cpu) { 262862306a36Sopenharmony_ci struct ieee80211_sta_rx_stats *cpurxs; 262962306a36Sopenharmony_ci 263062306a36Sopenharmony_ci cpurxs = per_cpu_ptr(sta->deflink.pcpu_rx_stats, 263162306a36Sopenharmony_ci cpu); 263262306a36Sopenharmony_ci sinfo->rx_packets += cpurxs->packets; 263362306a36Sopenharmony_ci } 263462306a36Sopenharmony_ci } 263562306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_PACKETS); 263662306a36Sopenharmony_ci } 263762306a36Sopenharmony_ci 263862306a36Sopenharmony_ci if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_RETRIES))) { 263962306a36Sopenharmony_ci sinfo->tx_retries = sta->deflink.status_stats.retry_count; 264062306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES); 264162306a36Sopenharmony_ci } 264262306a36Sopenharmony_ci 264362306a36Sopenharmony_ci if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_FAILED))) { 264462306a36Sopenharmony_ci sinfo->tx_failed = sta->deflink.status_stats.retry_failed; 264562306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED); 264662306a36Sopenharmony_ci } 264762306a36Sopenharmony_ci 264862306a36Sopenharmony_ci if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_RX_DURATION))) { 264962306a36Sopenharmony_ci for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) 265062306a36Sopenharmony_ci sinfo->rx_duration += sta->airtime[ac].rx_airtime; 265162306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DURATION); 265262306a36Sopenharmony_ci } 265362306a36Sopenharmony_ci 265462306a36Sopenharmony_ci if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_DURATION))) { 265562306a36Sopenharmony_ci for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) 265662306a36Sopenharmony_ci sinfo->tx_duration += sta->airtime[ac].tx_airtime; 265762306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_DURATION); 265862306a36Sopenharmony_ci } 265962306a36Sopenharmony_ci 266062306a36Sopenharmony_ci if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT))) { 266162306a36Sopenharmony_ci sinfo->airtime_weight = sta->airtime_weight; 266262306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT); 266362306a36Sopenharmony_ci } 266462306a36Sopenharmony_ci 266562306a36Sopenharmony_ci sinfo->rx_dropped_misc = sta->deflink.rx_stats.dropped; 266662306a36Sopenharmony_ci if (sta->deflink.pcpu_rx_stats) { 266762306a36Sopenharmony_ci for_each_possible_cpu(cpu) { 266862306a36Sopenharmony_ci struct ieee80211_sta_rx_stats *cpurxs; 266962306a36Sopenharmony_ci 267062306a36Sopenharmony_ci cpurxs = per_cpu_ptr(sta->deflink.pcpu_rx_stats, cpu); 267162306a36Sopenharmony_ci sinfo->rx_dropped_misc += cpurxs->dropped; 267262306a36Sopenharmony_ci } 267362306a36Sopenharmony_ci } 267462306a36Sopenharmony_ci 267562306a36Sopenharmony_ci if (sdata->vif.type == NL80211_IFTYPE_STATION && 267662306a36Sopenharmony_ci !(sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER)) { 267762306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_BEACON_RX) | 267862306a36Sopenharmony_ci BIT_ULL(NL80211_STA_INFO_BEACON_SIGNAL_AVG); 267962306a36Sopenharmony_ci sinfo->rx_beacon_signal_avg = ieee80211_ave_rssi(&sdata->vif); 268062306a36Sopenharmony_ci } 268162306a36Sopenharmony_ci 268262306a36Sopenharmony_ci if (ieee80211_hw_check(&sta->local->hw, SIGNAL_DBM) || 268362306a36Sopenharmony_ci ieee80211_hw_check(&sta->local->hw, SIGNAL_UNSPEC)) { 268462306a36Sopenharmony_ci if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_SIGNAL))) { 268562306a36Sopenharmony_ci sinfo->signal = (s8)last_rxstats->last_signal; 268662306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); 268762306a36Sopenharmony_ci } 268862306a36Sopenharmony_ci 268962306a36Sopenharmony_ci if (!sta->deflink.pcpu_rx_stats && 269062306a36Sopenharmony_ci !(sinfo->filled & BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG))) { 269162306a36Sopenharmony_ci sinfo->signal_avg = 269262306a36Sopenharmony_ci -ewma_signal_read(&sta->deflink.rx_stats_avg.signal); 269362306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG); 269462306a36Sopenharmony_ci } 269562306a36Sopenharmony_ci } 269662306a36Sopenharmony_ci 269762306a36Sopenharmony_ci /* for the average - if pcpu_rx_stats isn't set - rxstats must point to 269862306a36Sopenharmony_ci * the sta->rx_stats struct, so the check here is fine with and without 269962306a36Sopenharmony_ci * pcpu statistics 270062306a36Sopenharmony_ci */ 270162306a36Sopenharmony_ci if (last_rxstats->chains && 270262306a36Sopenharmony_ci !(sinfo->filled & (BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL) | 270362306a36Sopenharmony_ci BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)))) { 270462306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL); 270562306a36Sopenharmony_ci if (!sta->deflink.pcpu_rx_stats) 270662306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL_AVG); 270762306a36Sopenharmony_ci 270862306a36Sopenharmony_ci sinfo->chains = last_rxstats->chains; 270962306a36Sopenharmony_ci 271062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) { 271162306a36Sopenharmony_ci sinfo->chain_signal[i] = 271262306a36Sopenharmony_ci last_rxstats->chain_signal_last[i]; 271362306a36Sopenharmony_ci sinfo->chain_signal_avg[i] = 271462306a36Sopenharmony_ci -ewma_signal_read(&sta->deflink.rx_stats_avg.chain_signal[i]); 271562306a36Sopenharmony_ci } 271662306a36Sopenharmony_ci } 271762306a36Sopenharmony_ci 271862306a36Sopenharmony_ci if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_BITRATE)) && 271962306a36Sopenharmony_ci !sta->sta.valid_links) { 272062306a36Sopenharmony_ci sta_set_rate_info_tx(sta, &sta->deflink.tx_stats.last_rate, 272162306a36Sopenharmony_ci &sinfo->txrate); 272262306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); 272362306a36Sopenharmony_ci } 272462306a36Sopenharmony_ci 272562306a36Sopenharmony_ci if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_RX_BITRATE)) && 272662306a36Sopenharmony_ci !sta->sta.valid_links) { 272762306a36Sopenharmony_ci if (sta_set_rate_info_rx(sta, &sinfo->rxrate) == 0) 272862306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BITRATE); 272962306a36Sopenharmony_ci } 273062306a36Sopenharmony_ci 273162306a36Sopenharmony_ci if (tidstats && !cfg80211_sinfo_alloc_tid_stats(sinfo, GFP_KERNEL)) { 273262306a36Sopenharmony_ci for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) 273362306a36Sopenharmony_ci sta_set_tidstats(sta, &sinfo->pertid[i], i); 273462306a36Sopenharmony_ci } 273562306a36Sopenharmony_ci 273662306a36Sopenharmony_ci if (ieee80211_vif_is_mesh(&sdata->vif)) { 273762306a36Sopenharmony_ci#ifdef CONFIG_MAC80211_MESH 273862306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_LLID) | 273962306a36Sopenharmony_ci BIT_ULL(NL80211_STA_INFO_PLID) | 274062306a36Sopenharmony_ci BIT_ULL(NL80211_STA_INFO_PLINK_STATE) | 274162306a36Sopenharmony_ci BIT_ULL(NL80211_STA_INFO_LOCAL_PM) | 274262306a36Sopenharmony_ci BIT_ULL(NL80211_STA_INFO_PEER_PM) | 274362306a36Sopenharmony_ci BIT_ULL(NL80211_STA_INFO_NONPEER_PM) | 274462306a36Sopenharmony_ci BIT_ULL(NL80211_STA_INFO_CONNECTED_TO_GATE) | 274562306a36Sopenharmony_ci BIT_ULL(NL80211_STA_INFO_CONNECTED_TO_AS); 274662306a36Sopenharmony_ci 274762306a36Sopenharmony_ci sinfo->llid = sta->mesh->llid; 274862306a36Sopenharmony_ci sinfo->plid = sta->mesh->plid; 274962306a36Sopenharmony_ci sinfo->plink_state = sta->mesh->plink_state; 275062306a36Sopenharmony_ci if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) { 275162306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_T_OFFSET); 275262306a36Sopenharmony_ci sinfo->t_offset = sta->mesh->t_offset; 275362306a36Sopenharmony_ci } 275462306a36Sopenharmony_ci sinfo->local_pm = sta->mesh->local_pm; 275562306a36Sopenharmony_ci sinfo->peer_pm = sta->mesh->peer_pm; 275662306a36Sopenharmony_ci sinfo->nonpeer_pm = sta->mesh->nonpeer_pm; 275762306a36Sopenharmony_ci sinfo->connected_to_gate = sta->mesh->connected_to_gate; 275862306a36Sopenharmony_ci sinfo->connected_to_as = sta->mesh->connected_to_as; 275962306a36Sopenharmony_ci#endif 276062306a36Sopenharmony_ci } 276162306a36Sopenharmony_ci 276262306a36Sopenharmony_ci sinfo->bss_param.flags = 0; 276362306a36Sopenharmony_ci if (sdata->vif.bss_conf.use_cts_prot) 276462306a36Sopenharmony_ci sinfo->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT; 276562306a36Sopenharmony_ci if (sdata->vif.bss_conf.use_short_preamble) 276662306a36Sopenharmony_ci sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE; 276762306a36Sopenharmony_ci if (sdata->vif.bss_conf.use_short_slot) 276862306a36Sopenharmony_ci sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME; 276962306a36Sopenharmony_ci sinfo->bss_param.dtim_period = sdata->vif.bss_conf.dtim_period; 277062306a36Sopenharmony_ci sinfo->bss_param.beacon_interval = sdata->vif.bss_conf.beacon_int; 277162306a36Sopenharmony_ci 277262306a36Sopenharmony_ci sinfo->sta_flags.set = 0; 277362306a36Sopenharmony_ci sinfo->sta_flags.mask = BIT(NL80211_STA_FLAG_AUTHORIZED) | 277462306a36Sopenharmony_ci BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) | 277562306a36Sopenharmony_ci BIT(NL80211_STA_FLAG_WME) | 277662306a36Sopenharmony_ci BIT(NL80211_STA_FLAG_MFP) | 277762306a36Sopenharmony_ci BIT(NL80211_STA_FLAG_AUTHENTICATED) | 277862306a36Sopenharmony_ci BIT(NL80211_STA_FLAG_ASSOCIATED) | 277962306a36Sopenharmony_ci BIT(NL80211_STA_FLAG_TDLS_PEER); 278062306a36Sopenharmony_ci if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) 278162306a36Sopenharmony_ci sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHORIZED); 278262306a36Sopenharmony_ci if (test_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE)) 278362306a36Sopenharmony_ci sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE); 278462306a36Sopenharmony_ci if (sta->sta.wme) 278562306a36Sopenharmony_ci sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_WME); 278662306a36Sopenharmony_ci if (test_sta_flag(sta, WLAN_STA_MFP)) 278762306a36Sopenharmony_ci sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_MFP); 278862306a36Sopenharmony_ci if (test_sta_flag(sta, WLAN_STA_AUTH)) 278962306a36Sopenharmony_ci sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHENTICATED); 279062306a36Sopenharmony_ci if (test_sta_flag(sta, WLAN_STA_ASSOC)) 279162306a36Sopenharmony_ci sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_ASSOCIATED); 279262306a36Sopenharmony_ci if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) 279362306a36Sopenharmony_ci sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER); 279462306a36Sopenharmony_ci 279562306a36Sopenharmony_ci thr = sta_get_expected_throughput(sta); 279662306a36Sopenharmony_ci 279762306a36Sopenharmony_ci if (thr != 0) { 279862306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_EXPECTED_THROUGHPUT); 279962306a36Sopenharmony_ci sinfo->expected_throughput = thr; 280062306a36Sopenharmony_ci } 280162306a36Sopenharmony_ci 280262306a36Sopenharmony_ci if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL)) && 280362306a36Sopenharmony_ci sta->deflink.status_stats.ack_signal_filled) { 280462306a36Sopenharmony_ci sinfo->ack_signal = sta->deflink.status_stats.last_ack_signal; 280562306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL); 280662306a36Sopenharmony_ci } 280762306a36Sopenharmony_ci 280862306a36Sopenharmony_ci if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG)) && 280962306a36Sopenharmony_ci sta->deflink.status_stats.ack_signal_filled) { 281062306a36Sopenharmony_ci sinfo->avg_ack_signal = 281162306a36Sopenharmony_ci -(s8)ewma_avg_signal_read( 281262306a36Sopenharmony_ci &sta->deflink.status_stats.avg_ack_signal); 281362306a36Sopenharmony_ci sinfo->filled |= 281462306a36Sopenharmony_ci BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG); 281562306a36Sopenharmony_ci } 281662306a36Sopenharmony_ci 281762306a36Sopenharmony_ci if (ieee80211_vif_is_mesh(&sdata->vif)) { 281862306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_AIRTIME_LINK_METRIC); 281962306a36Sopenharmony_ci sinfo->airtime_link_metric = 282062306a36Sopenharmony_ci airtime_link_metric_get(local, sta); 282162306a36Sopenharmony_ci } 282262306a36Sopenharmony_ci} 282362306a36Sopenharmony_ci 282462306a36Sopenharmony_ciu32 sta_get_expected_throughput(struct sta_info *sta) 282562306a36Sopenharmony_ci{ 282662306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata = sta->sdata; 282762306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 282862306a36Sopenharmony_ci struct rate_control_ref *ref = NULL; 282962306a36Sopenharmony_ci u32 thr = 0; 283062306a36Sopenharmony_ci 283162306a36Sopenharmony_ci if (test_sta_flag(sta, WLAN_STA_RATE_CONTROL)) 283262306a36Sopenharmony_ci ref = local->rate_ctrl; 283362306a36Sopenharmony_ci 283462306a36Sopenharmony_ci /* check if the driver has a SW RC implementation */ 283562306a36Sopenharmony_ci if (ref && ref->ops->get_expected_throughput) 283662306a36Sopenharmony_ci thr = ref->ops->get_expected_throughput(sta->rate_ctrl_priv); 283762306a36Sopenharmony_ci else 283862306a36Sopenharmony_ci thr = drv_get_expected_throughput(local, sta); 283962306a36Sopenharmony_ci 284062306a36Sopenharmony_ci return thr; 284162306a36Sopenharmony_ci} 284262306a36Sopenharmony_ci 284362306a36Sopenharmony_ciunsigned long ieee80211_sta_last_active(struct sta_info *sta) 284462306a36Sopenharmony_ci{ 284562306a36Sopenharmony_ci struct ieee80211_sta_rx_stats *stats = sta_get_last_rx_stats(sta); 284662306a36Sopenharmony_ci 284762306a36Sopenharmony_ci if (!sta->deflink.status_stats.last_ack || 284862306a36Sopenharmony_ci time_after(stats->last_rx, sta->deflink.status_stats.last_ack)) 284962306a36Sopenharmony_ci return stats->last_rx; 285062306a36Sopenharmony_ci return sta->deflink.status_stats.last_ack; 285162306a36Sopenharmony_ci} 285262306a36Sopenharmony_ci 285362306a36Sopenharmony_cistatic void sta_update_codel_params(struct sta_info *sta, u32 thr) 285462306a36Sopenharmony_ci{ 285562306a36Sopenharmony_ci if (thr && thr < STA_SLOW_THRESHOLD * sta->local->num_sta) { 285662306a36Sopenharmony_ci sta->cparams.target = MS2TIME(50); 285762306a36Sopenharmony_ci sta->cparams.interval = MS2TIME(300); 285862306a36Sopenharmony_ci sta->cparams.ecn = false; 285962306a36Sopenharmony_ci } else { 286062306a36Sopenharmony_ci sta->cparams.target = MS2TIME(20); 286162306a36Sopenharmony_ci sta->cparams.interval = MS2TIME(100); 286262306a36Sopenharmony_ci sta->cparams.ecn = true; 286362306a36Sopenharmony_ci } 286462306a36Sopenharmony_ci} 286562306a36Sopenharmony_ci 286662306a36Sopenharmony_civoid ieee80211_sta_set_expected_throughput(struct ieee80211_sta *pubsta, 286762306a36Sopenharmony_ci u32 thr) 286862306a36Sopenharmony_ci{ 286962306a36Sopenharmony_ci struct sta_info *sta = container_of(pubsta, struct sta_info, sta); 287062306a36Sopenharmony_ci 287162306a36Sopenharmony_ci sta_update_codel_params(sta, thr); 287262306a36Sopenharmony_ci} 287362306a36Sopenharmony_ci 287462306a36Sopenharmony_ciint ieee80211_sta_allocate_link(struct sta_info *sta, unsigned int link_id) 287562306a36Sopenharmony_ci{ 287662306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata = sta->sdata; 287762306a36Sopenharmony_ci struct sta_link_alloc *alloc; 287862306a36Sopenharmony_ci int ret; 287962306a36Sopenharmony_ci 288062306a36Sopenharmony_ci lockdep_assert_held(&sdata->local->sta_mtx); 288162306a36Sopenharmony_ci 288262306a36Sopenharmony_ci /* must represent an MLD from the start */ 288362306a36Sopenharmony_ci if (WARN_ON(!sta->sta.valid_links)) 288462306a36Sopenharmony_ci return -EINVAL; 288562306a36Sopenharmony_ci 288662306a36Sopenharmony_ci if (WARN_ON(sta->sta.valid_links & BIT(link_id) || 288762306a36Sopenharmony_ci sta->link[link_id])) 288862306a36Sopenharmony_ci return -EBUSY; 288962306a36Sopenharmony_ci 289062306a36Sopenharmony_ci alloc = kzalloc(sizeof(*alloc), GFP_KERNEL); 289162306a36Sopenharmony_ci if (!alloc) 289262306a36Sopenharmony_ci return -ENOMEM; 289362306a36Sopenharmony_ci 289462306a36Sopenharmony_ci ret = sta_info_alloc_link(sdata->local, &alloc->info, GFP_KERNEL); 289562306a36Sopenharmony_ci if (ret) { 289662306a36Sopenharmony_ci kfree(alloc); 289762306a36Sopenharmony_ci return ret; 289862306a36Sopenharmony_ci } 289962306a36Sopenharmony_ci 290062306a36Sopenharmony_ci sta_info_add_link(sta, link_id, &alloc->info, &alloc->sta); 290162306a36Sopenharmony_ci 290262306a36Sopenharmony_ci ieee80211_link_sta_debugfs_add(&alloc->info); 290362306a36Sopenharmony_ci 290462306a36Sopenharmony_ci return 0; 290562306a36Sopenharmony_ci} 290662306a36Sopenharmony_ci 290762306a36Sopenharmony_civoid ieee80211_sta_free_link(struct sta_info *sta, unsigned int link_id) 290862306a36Sopenharmony_ci{ 290962306a36Sopenharmony_ci lockdep_assert_held(&sta->sdata->local->sta_mtx); 291062306a36Sopenharmony_ci 291162306a36Sopenharmony_ci sta_remove_link(sta, link_id, false); 291262306a36Sopenharmony_ci} 291362306a36Sopenharmony_ci 291462306a36Sopenharmony_ciint ieee80211_sta_activate_link(struct sta_info *sta, unsigned int link_id) 291562306a36Sopenharmony_ci{ 291662306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata = sta->sdata; 291762306a36Sopenharmony_ci struct link_sta_info *link_sta; 291862306a36Sopenharmony_ci u16 old_links = sta->sta.valid_links; 291962306a36Sopenharmony_ci u16 new_links = old_links | BIT(link_id); 292062306a36Sopenharmony_ci int ret; 292162306a36Sopenharmony_ci 292262306a36Sopenharmony_ci link_sta = rcu_dereference_protected(sta->link[link_id], 292362306a36Sopenharmony_ci lockdep_is_held(&sdata->local->sta_mtx)); 292462306a36Sopenharmony_ci 292562306a36Sopenharmony_ci if (WARN_ON(old_links == new_links || !link_sta)) 292662306a36Sopenharmony_ci return -EINVAL; 292762306a36Sopenharmony_ci 292862306a36Sopenharmony_ci rcu_read_lock(); 292962306a36Sopenharmony_ci if (link_sta_info_hash_lookup(sdata->local, link_sta->addr)) { 293062306a36Sopenharmony_ci rcu_read_unlock(); 293162306a36Sopenharmony_ci return -EALREADY; 293262306a36Sopenharmony_ci } 293362306a36Sopenharmony_ci /* we only modify under the mutex so this is fine */ 293462306a36Sopenharmony_ci rcu_read_unlock(); 293562306a36Sopenharmony_ci 293662306a36Sopenharmony_ci sta->sta.valid_links = new_links; 293762306a36Sopenharmony_ci 293862306a36Sopenharmony_ci if (!test_sta_flag(sta, WLAN_STA_INSERTED)) 293962306a36Sopenharmony_ci goto hash; 294062306a36Sopenharmony_ci 294162306a36Sopenharmony_ci ieee80211_recalc_min_chandef(sdata, link_id); 294262306a36Sopenharmony_ci 294362306a36Sopenharmony_ci /* Ensure the values are updated for the driver, 294462306a36Sopenharmony_ci * redone by sta_remove_link on failure. 294562306a36Sopenharmony_ci */ 294662306a36Sopenharmony_ci ieee80211_sta_recalc_aggregates(&sta->sta); 294762306a36Sopenharmony_ci 294862306a36Sopenharmony_ci ret = drv_change_sta_links(sdata->local, sdata, &sta->sta, 294962306a36Sopenharmony_ci old_links, new_links); 295062306a36Sopenharmony_ci if (ret) { 295162306a36Sopenharmony_ci sta->sta.valid_links = old_links; 295262306a36Sopenharmony_ci sta_remove_link(sta, link_id, false); 295362306a36Sopenharmony_ci return ret; 295462306a36Sopenharmony_ci } 295562306a36Sopenharmony_ci 295662306a36Sopenharmony_cihash: 295762306a36Sopenharmony_ci ret = link_sta_info_hash_add(sdata->local, link_sta); 295862306a36Sopenharmony_ci WARN_ON(ret); 295962306a36Sopenharmony_ci return 0; 296062306a36Sopenharmony_ci} 296162306a36Sopenharmony_ci 296262306a36Sopenharmony_civoid ieee80211_sta_remove_link(struct sta_info *sta, unsigned int link_id) 296362306a36Sopenharmony_ci{ 296462306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata = sta->sdata; 296562306a36Sopenharmony_ci u16 old_links = sta->sta.valid_links; 296662306a36Sopenharmony_ci 296762306a36Sopenharmony_ci lockdep_assert_held(&sdata->local->sta_mtx); 296862306a36Sopenharmony_ci 296962306a36Sopenharmony_ci sta->sta.valid_links &= ~BIT(link_id); 297062306a36Sopenharmony_ci 297162306a36Sopenharmony_ci if (test_sta_flag(sta, WLAN_STA_INSERTED)) 297262306a36Sopenharmony_ci drv_change_sta_links(sdata->local, sdata, &sta->sta, 297362306a36Sopenharmony_ci old_links, sta->sta.valid_links); 297462306a36Sopenharmony_ci 297562306a36Sopenharmony_ci sta_remove_link(sta, link_id, true); 297662306a36Sopenharmony_ci} 297762306a36Sopenharmony_ci 297862306a36Sopenharmony_civoid ieee80211_sta_set_max_amsdu_subframes(struct sta_info *sta, 297962306a36Sopenharmony_ci const u8 *ext_capab, 298062306a36Sopenharmony_ci unsigned int ext_capab_len) 298162306a36Sopenharmony_ci{ 298262306a36Sopenharmony_ci u8 val; 298362306a36Sopenharmony_ci 298462306a36Sopenharmony_ci sta->sta.max_amsdu_subframes = 0; 298562306a36Sopenharmony_ci 298662306a36Sopenharmony_ci if (ext_capab_len < 8) 298762306a36Sopenharmony_ci return; 298862306a36Sopenharmony_ci 298962306a36Sopenharmony_ci /* The sender might not have sent the last bit, consider it to be 0 */ 299062306a36Sopenharmony_ci val = u8_get_bits(ext_capab[7], WLAN_EXT_CAPA8_MAX_MSDU_IN_AMSDU_LSB); 299162306a36Sopenharmony_ci 299262306a36Sopenharmony_ci /* we did get all the bits, take the MSB as well */ 299362306a36Sopenharmony_ci if (ext_capab_len >= 9) 299462306a36Sopenharmony_ci val |= u8_get_bits(ext_capab[8], 299562306a36Sopenharmony_ci WLAN_EXT_CAPA9_MAX_MSDU_IN_AMSDU_MSB) << 1; 299662306a36Sopenharmony_ci 299762306a36Sopenharmony_ci if (val) 299862306a36Sopenharmony_ci sta->sta.max_amsdu_subframes = 4 << (4 - val); 299962306a36Sopenharmony_ci} 300062306a36Sopenharmony_ci 300162306a36Sopenharmony_ci#ifdef CONFIG_LOCKDEP 300262306a36Sopenharmony_cibool lockdep_sta_mutex_held(struct ieee80211_sta *pubsta) 300362306a36Sopenharmony_ci{ 300462306a36Sopenharmony_ci struct sta_info *sta = container_of(pubsta, struct sta_info, sta); 300562306a36Sopenharmony_ci 300662306a36Sopenharmony_ci return lockdep_is_held(&sta->local->sta_mtx); 300762306a36Sopenharmony_ci} 300862306a36Sopenharmony_ciEXPORT_SYMBOL(lockdep_sta_mutex_held); 300962306a36Sopenharmony_ci#endif 3010