linux/net/mac80211/sta_info.c

3028 lines
80 KiB
C
Raw Normal View History

// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2002-2005, Instant802 Networks, Inc.
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
* Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright (C) 2015 - 2017 Intel Deutschland GmbH
* Copyright (C) 2018-2023 Intel Corporation
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/etherdevice.h>
#include <linux/netdevice.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/skbuff.h>
#include <linux/if_arp.h>
#include <linux/timer.h>
#include <linux/rtnetlink.h>
#include <net/codel.h>
#include <net/mac80211.h>
#include "ieee80211_i.h"
#include "driver-ops.h"
#include "rate.h"
#include "sta_info.h"
#include "debugfs_sta.h"
#include "mesh.h"
#include "wme.h"
/**
* DOC: STA information lifetime rules
*
* STA info structures (&struct sta_info) are managed in a hash table
* for faster lookup and a list for iteration. They are managed using
* RCU, i.e. access to the list and hash table is protected by RCU.
*
* Upon allocating a STA info structure with sta_info_alloc(), the caller
* owns that structure. It must then insert it into the hash table using
* either sta_info_insert() or sta_info_insert_rcu(); only in the latter
* case (which acquires an rcu read section but must not be called from
* within one) will the pointer still be valid after the call. Note that
* the caller may not do much with the STA info before inserting it; in
* particular, it may not start any mesh peer link management or add
* encryption keys.
*
* When the insertion fails (sta_info_insert()) returns non-zero), the
* structure will have been freed by sta_info_insert()!
*
* Station entries are added by mac80211 when you establish a link with a
* peer. This means different things for the different type of interfaces
* we support. For a regular station this mean we add the AP sta when we
* receive an association response from the AP. For IBSS this occurs when
* get to know about a peer on the same IBSS. For WDS we add the sta for
* the peer immediately upon device open. When using AP mode we add stations
* for each respective station upon request from userspace through nl80211.
*
* In order to remove a STA info structure, various sta_info_destroy_*()
* calls are available.
*
* There is no concept of ownership on a STA entry; each structure is
* owned by the global hash table/list until it is removed. All users of
* the structure need to be RCU protected so that the structure won't be
* freed before they are done using it.
*/
struct sta_link_alloc {
struct link_sta_info info;
struct ieee80211_link_sta sta;
struct rcu_head rcu_head;
};
static const struct rhashtable_params sta_rht_params = {
.nelem_hint = 3, /* start small */
.automatic_shrinking = true,
.head_offset = offsetof(struct sta_info, hash_node),
.key_offset = offsetof(struct sta_info, addr),
.key_len = ETH_ALEN,
.max_size = CONFIG_MAC80211_STA_HASH_MAX_SIZE,
};
static const struct rhashtable_params link_sta_rht_params = {
.nelem_hint = 3, /* start small */
.automatic_shrinking = true,
.head_offset = offsetof(struct link_sta_info, link_hash_node),
.key_offset = offsetof(struct link_sta_info, addr),
.key_len = ETH_ALEN,
.max_size = CONFIG_MAC80211_STA_HASH_MAX_SIZE,
};
static int sta_info_hash_del(struct ieee80211_local *local,
struct sta_info *sta)
{
return rhltable_remove(&local->sta_hash, &sta->hash_node,
sta_rht_params);
}
static int link_sta_info_hash_add(struct ieee80211_local *local,
struct link_sta_info *link_sta)
{
lockdep_assert_wiphy(local->hw.wiphy);
return rhltable_insert(&local->link_sta_hash,
&link_sta->link_hash_node, link_sta_rht_params);
}
static int link_sta_info_hash_del(struct ieee80211_local *local,
struct link_sta_info *link_sta)
{
lockdep_assert_wiphy(local->hw.wiphy);
return rhltable_remove(&local->link_sta_hash,
&link_sta->link_hash_node, link_sta_rht_params);
}
void ieee80211_purge_sta_txqs(struct sta_info *sta)
{
struct ieee80211_local *local = sta->sdata->local;
int i;
for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
struct txq_info *txqi;
if (!sta->sta.txq[i])
continue;
txqi = to_txq_info(sta->sta.txq[i]);
ieee80211_txq_purge(local, txqi);
}
}
static void __cleanup_single_sta(struct sta_info *sta)
{
int ac, i;
struct tid_ampdu_tx *tid_tx;
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
struct ps_data *ps;
if (test_sta_flag(sta, WLAN_STA_PS_STA) ||
test_sta_flag(sta, WLAN_STA_PS_DRIVER) ||
test_sta_flag(sta, WLAN_STA_PS_DELIVER)) {
if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
ps = &sdata->bss->ps;
mac80211: mesh power save basics Add routines to - maintain a PS mode for each peer and a non-peer PS mode - indicate own PS mode in transmitted frames - track neighbor STAs power modes - buffer frames when neighbors are in PS mode - add TIM and Awake Window IE to beacons - release frames in Mesh Peer Service Periods Add local_pm to sta_info to represent the link-specific power mode at this station towards the remote station. When a peer link is established, use the default power mode stored in mesh config. Update the PS status if the peering status of a neighbor changes. Maintain a mesh power mode for non-peer mesh STAs. Set the non-peer power mode to active mode during peering. Authenticated mesh peering is currently not working when either node is configured to be in power save mode. Indicate the current power mode in transmitted frames. Use QoS Nulls to indicate mesh power mode transitions. For performance reasons, calls to the function setting the frame flags are placed in HWMP routing routines, as there the STA pointer is already available. Add peer_pm to sta_info to represent the peer's link-specific power mode towards the local station. Add nonpeer_pm to represent the peer's power mode towards all non-peer stations. Track power modes based on received frames. Add the ps_data structure to ieee80211_if_mesh (for TIM map, PS neighbor counter and group-addressed frame buffer). Set WLAN_STA_PS flag for STA in PS mode to use the unicast frame buffering routines in the tx path. Update num_sta_ps to buffer and release group-addressed frames after DTIM beacons. Announce the awake window duration in beacons if in light or deep sleep mode towards any peer or non-peer. Create a TIM IE similarly to AP mode and add it to mesh beacons. Parse received Awake Window IEs and check TIM IEs for buffered frames. Release frames towards peers in mesh Peer Service Periods. Use the corresponding trigger frames and monitor the MPSP status. Append a QoS Null as trigger frame if neccessary to properly end the MPSP. Currently, in HT channels MPSPs behave imperfectly and show large delay spikes and frame losses. Signed-off-by: Marco Porsch <marco@cozybit.com> Signed-off-by: Ivan Bezyazychnyy <ivan.bezyazychnyy@gmail.com> Signed-off-by: Mike Krinkin <krinkin.m.u@gmail.com> Signed-off-by: Max Filippov <jcmvbkbc@gmail.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2013-01-30 17:14:08 +00:00
else if (ieee80211_vif_is_mesh(&sdata->vif))
ps = &sdata->u.mesh.ps;
else
return;
clear_sta_flag(sta, WLAN_STA_PS_STA);
clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
clear_sta_flag(sta, WLAN_STA_PS_DELIVER);
atomic_dec(&ps->num_sta_ps);
}
ieee80211_purge_sta_txqs(sta);
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
local->total_ps_buffered -= skb_queue_len(&sta->ps_tx_buf[ac]);
ieee80211_purge_tx_queue(&local->hw, &sta->ps_tx_buf[ac]);
ieee80211_purge_tx_queue(&local->hw, &sta->tx_filtered[ac]);
}
if (ieee80211_vif_is_mesh(&sdata->vif))
mesh_sta_cleanup(sta);
cancel_work_sync(&sta->drv_deliver_wk);
/*
* Destroy aggregation state here. It would be nice to wait for the
* driver to finish aggregation stop and then clean up, but for now
* drivers have to handle aggregation stop being requested, followed
* directly by station destruction.
*/
for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
kfree(sta->ampdu_mlme.tid_start_tx[i]);
tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]);
if (!tid_tx)
continue;
ieee80211_purge_tx_queue(&local->hw, &tid_tx->pending);
kfree(tid_tx);
}
}
static void cleanup_single_sta(struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
__cleanup_single_sta(sta);
sta_info_free(local, sta);
}
struct rhlist_head *sta_info_hash_lookup(struct ieee80211_local *local,
const u8 *addr)
{
return rhltable_lookup(&local->sta_hash, addr, sta_rht_params);
}
/* protected by RCU */
struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata,
const u8 *addr)
{
struct ieee80211_local *local = sdata->local;
struct rhlist_head *tmp;
struct sta_info *sta;
rcu_read_lock();
for_each_sta_info(local, addr, sta, tmp) {
if (sta->sdata == sdata) {
rcu_read_unlock();
/* this is safe as the caller must already hold
* another rcu read section or the mutex
*/
return sta;
}
}
rcu_read_unlock();
return NULL;
}
/*
* Get sta info either from the specified interface
* or from one of its vlans
*/
struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata,
const u8 *addr)
{
struct ieee80211_local *local = sdata->local;
struct rhlist_head *tmp;
struct sta_info *sta;
rcu_read_lock();
for_each_sta_info(local, addr, sta, tmp) {
if (sta->sdata == sdata ||
(sta->sdata->bss && sta->sdata->bss == sdata->bss)) {
rcu_read_unlock();
/* this is safe as the caller must already hold
* another rcu read section or the mutex
*/
return sta;
}
}
rcu_read_unlock();
return NULL;
}
struct rhlist_head *link_sta_info_hash_lookup(struct ieee80211_local *local,
const u8 *addr)
{
return rhltable_lookup(&local->link_sta_hash, addr,
link_sta_rht_params);
}
struct link_sta_info *
link_sta_info_get_bss(struct ieee80211_sub_if_data *sdata, const u8 *addr)
{
struct ieee80211_local *local = sdata->local;
struct rhlist_head *tmp;
struct link_sta_info *link_sta;
rcu_read_lock();
for_each_link_sta_info(local, addr, link_sta, tmp) {
struct sta_info *sta = link_sta->sta;
if (sta->sdata == sdata ||
(sta->sdata->bss && sta->sdata->bss == sdata->bss)) {
rcu_read_unlock();
/* this is safe as the caller must already hold
* another rcu read section or the mutex
*/
return link_sta;
}
}
rcu_read_unlock();
return NULL;
}
struct ieee80211_sta *
ieee80211_find_sta_by_link_addrs(struct ieee80211_hw *hw,
const u8 *addr,
const u8 *localaddr,
unsigned int *link_id)
{
struct ieee80211_local *local = hw_to_local(hw);
struct link_sta_info *link_sta;
struct rhlist_head *tmp;
for_each_link_sta_info(local, addr, link_sta, tmp) {
struct sta_info *sta = link_sta->sta;
struct ieee80211_link_data *link;
u8 _link_id = link_sta->link_id;
if (!localaddr) {
if (link_id)
*link_id = _link_id;
return &sta->sta;
}
link = rcu_dereference(sta->sdata->link[_link_id]);
if (!link)
continue;
if (memcmp(link->conf->addr, localaddr, ETH_ALEN))
continue;
if (link_id)
*link_id = _link_id;
return &sta->sta;
}
return NULL;
}
EXPORT_SYMBOL_GPL(ieee80211_find_sta_by_link_addrs);
struct sta_info *sta_info_get_by_addrs(struct ieee80211_local *local,
const u8 *sta_addr, const u8 *vif_addr)
{
struct rhlist_head *tmp;
struct sta_info *sta;
for_each_sta_info(local, sta_addr, sta, tmp) {
if (ether_addr_equal(vif_addr, sta->sdata->vif.addr))
return sta;
}
return NULL;
}
struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata,
int idx)
{
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
int i = 0;
list_for_each_entry_rcu(sta, &local->sta_list, list,
lockdep_is_held(&local->hw.wiphy->mtx)) {
if (sdata != sta->sdata)
continue;
if (i < idx) {
++i;
continue;
}
return sta;
}
return NULL;
}
static void sta_info_free_link(struct link_sta_info *link_sta)
{
free_percpu(link_sta->pcpu_rx_stats);
}
static void sta_remove_link(struct sta_info *sta, unsigned int link_id,
bool unhash)
{
struct sta_link_alloc *alloc = NULL;
struct link_sta_info *link_sta;
lockdep_assert_wiphy(sta->local->hw.wiphy);
link_sta = rcu_access_pointer(sta->link[link_id]);
if (WARN_ON(!link_sta))
return;
if (unhash)
link_sta_info_hash_del(sta->local, link_sta);
if (test_sta_flag(sta, WLAN_STA_INSERTED))
ieee80211_link_sta_debugfs_remove(link_sta);
if (link_sta != &sta->deflink)
alloc = container_of(link_sta, typeof(*alloc), info);
sta->sta.valid_links &= ~BIT(link_id);
RCU_INIT_POINTER(sta->link[link_id], NULL);
RCU_INIT_POINTER(sta->sta.link[link_id], NULL);
if (alloc) {
sta_info_free_link(&alloc->info);
kfree_rcu(alloc, rcu_head);
}
ieee80211_sta_recalc_aggregates(&sta->sta);
}
/**
* sta_info_free - free STA
*
* @local: pointer to the global information
* @sta: STA info to free
*
* This function must undo everything done by sta_info_alloc()
* that may happen before sta_info_insert(). It may only be
* called when sta_info_insert() has not been attempted (and
* if that fails, the station is freed anyway.)
*/
void sta_info_free(struct ieee80211_local *local, struct sta_info *sta)
{
int i;
for (i = 0; i < ARRAY_SIZE(sta->link); i++) {
struct link_sta_info *link_sta;
link_sta = rcu_access_pointer(sta->link[i]);
if (!link_sta)
continue;
sta_remove_link(sta, i, false);
}
/*
* If we had used sta_info_pre_move_state() then we might not
* have gone through the state transitions down again, so do
* it here now (and warn if it's inserted).
*
* This will clear state such as fast TX/RX that may have been
* allocated during state transitions.
*/
while (sta->sta_state > IEEE80211_STA_NONE) {
int ret;
WARN_ON_ONCE(test_sta_flag(sta, WLAN_STA_INSERTED));
ret = sta_info_move_state(sta, sta->sta_state - 1);
if (WARN_ONCE(ret, "sta_info_move_state() returned %d\n", ret))
break;
}
if (sta->rate_ctrl)
rate_control_free_sta(sta);
sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr);
kfree(to_txq_info(sta->sta.txq[0]));
kfree(rcu_dereference_raw(sta->sta.rates));
#ifdef CONFIG_MAC80211_MESH
kfree(sta->mesh);
#endif
sta_info_free_link(&sta->deflink);
kfree(sta);
}
static int sta_info_hash_add(struct ieee80211_local *local,
struct sta_info *sta)
{
return rhltable_insert(&local->sta_hash, &sta->hash_node,
sta_rht_params);
}
static void sta_deliver_ps_frames(struct work_struct *wk)
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
{
struct sta_info *sta;
sta = container_of(wk, struct sta_info, drv_deliver_wk);
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
if (sta->dead)
return;
local_bh_disable();
if (!test_sta_flag(sta, WLAN_STA_PS_STA))
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
ieee80211_sta_ps_deliver_wakeup(sta);
else if (test_and_clear_sta_flag(sta, WLAN_STA_PSPOLL))
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
ieee80211_sta_ps_deliver_poll_response(sta);
else if (test_and_clear_sta_flag(sta, WLAN_STA_UAPSD))
ieee80211_sta_ps_deliver_uapsd(sta);
local_bh_enable();
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
}
static int sta_prepare_rate_control(struct ieee80211_local *local,
struct sta_info *sta, gfp_t gfp)
{
if (ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL))
return 0;
sta->rate_ctrl = local->rate_ctrl;
sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl,
sta, gfp);
if (!sta->rate_ctrl_priv)
return -ENOMEM;
return 0;
}
static int sta_info_alloc_link(struct ieee80211_local *local,
struct link_sta_info *link_info,
gfp_t gfp)
{
struct ieee80211_hw *hw = &local->hw;
int i;
if (ieee80211_hw_check(hw, USES_RSS)) {
link_info->pcpu_rx_stats =
alloc_percpu_gfp(struct ieee80211_sta_rx_stats, gfp);
if (!link_info->pcpu_rx_stats)
return -ENOMEM;
}
link_info->rx_stats.last_rx = jiffies;
u64_stats_init(&link_info->rx_stats.syncp);
ewma_signal_init(&link_info->rx_stats_avg.signal);
ewma_avg_signal_init(&link_info->status_stats.avg_ack_signal);
for (i = 0; i < ARRAY_SIZE(link_info->rx_stats_avg.chain_signal); i++)
ewma_signal_init(&link_info->rx_stats_avg.chain_signal[i]);
return 0;
}
static void sta_info_add_link(struct sta_info *sta,
unsigned int link_id,
struct link_sta_info *link_info,
struct ieee80211_link_sta *link_sta)
{
link_info->sta = sta;
link_info->link_id = link_id;
link_info->pub = link_sta;
link_info->pub->sta = &sta->sta;
link_sta->link_id = link_id;
rcu_assign_pointer(sta->link[link_id], link_info);
rcu_assign_pointer(sta->sta.link[link_id], link_sta);
link_sta->smps_mode = IEEE80211_SMPS_OFF;
link_sta->agg.max_rc_amsdu_len = IEEE80211_MAX_MPDU_LEN_HT_BA;
}
static struct sta_info *
__sta_info_alloc(struct ieee80211_sub_if_data *sdata,
const u8 *addr, int link_id, const u8 *link_addr,
gfp_t gfp)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_hw *hw = &local->hw;
struct sta_info *sta;
void *txq_data;
int size;
int i;
sta = kzalloc(sizeof(*sta) + hw->sta_data_size, gfp);
if (!sta)
return NULL;
sta->local = local;
sta->sdata = sdata;
if (sta_info_alloc_link(local, &sta->deflink, gfp))
goto free;
if (link_id >= 0) {
sta_info_add_link(sta, link_id, &sta->deflink,
&sta->sta.deflink);
sta->sta.valid_links = BIT(link_id);
} else {
sta_info_add_link(sta, 0, &sta->deflink, &sta->sta.deflink);
}
sta->sta.cur = &sta->sta.deflink.agg;
spin_lock_init(&sta->lock);
mac80211: fix AP powersave TX vs. wakeup race There is a race between the TX path and the STA wakeup: while a station is sleeping, mac80211 buffers frames until it wakes up, then the frames are transmitted. However, the RX and TX path are concurrent, so the packet indicating wakeup can be processed while a packet is being transmitted. This can lead to a situation where the buffered frames list is emptied on the one side, while a frame is being added on the other side, as the station is still seen as sleeping in the TX path. As a result, the newly added frame will not be send anytime soon. It might be sent much later (and out of order) when the station goes to sleep and wakes up the next time. Additionally, it can lead to the crash below. Fix all this by synchronising both paths with a new lock. Both path are not fastpath since they handle PS situations. In a later patch we'll remove the extra skb queue locks to reduce locking overhead. BUG: unable to handle kernel NULL pointer dereference at 000000b0 IP: [<ff6f1791>] ieee80211_report_used_skb+0x11/0x3e0 [mac80211] *pde = 00000000 Oops: 0000 [#1] SMP DEBUG_PAGEALLOC EIP: 0060:[<ff6f1791>] EFLAGS: 00210282 CPU: 1 EIP is at ieee80211_report_used_skb+0x11/0x3e0 [mac80211] EAX: e5900da0 EBX: 00000000 ECX: 00000001 EDX: 00000000 ESI: e41d00c0 EDI: e5900da0 EBP: ebe458e4 ESP: ebe458b0 DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 CR0: 8005003b CR2: 000000b0 CR3: 25a78000 CR4: 000407d0 DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000 DR6: ffff0ff0 DR7: 00000400 Process iperf (pid: 3934, ti=ebe44000 task=e757c0b0 task.ti=ebe44000) iwlwifi 0000:02:00.0: I iwl_pcie_enqueue_hcmd Sending command LQ_CMD (#4e), seq: 0x0903, 92 bytes at 3[3]:9 Stack: e403b32c ebe458c4 00200002 00200286 e403b338 ebe458cc c10960bb e5900da0 ff76a6ec ebe458d8 00000000 e41d00c0 e5900da0 ebe458f0 ff6f1b75 e403b210 ebe4598c ff723dc1 00000000 ff76a6ec e597c978 e403b758 00000002 00000002 Call Trace: [<ff6f1b75>] ieee80211_free_txskb+0x15/0x20 [mac80211] [<ff723dc1>] invoke_tx_handlers+0x1661/0x1780 [mac80211] [<ff7248a5>] ieee80211_tx+0x75/0x100 [mac80211] [<ff7249bf>] ieee80211_xmit+0x8f/0xc0 [mac80211] [<ff72550e>] ieee80211_subif_start_xmit+0x4fe/0xe20 [mac80211] [<c149ef70>] dev_hard_start_xmit+0x450/0x950 [<c14b9aa9>] sch_direct_xmit+0xa9/0x250 [<c14b9c9b>] __qdisc_run+0x4b/0x150 [<c149f732>] dev_queue_xmit+0x2c2/0xca0 Cc: stable@vger.kernel.org Reported-by: Yaara Rozenblum <yaara.rozenblum@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Reviewed-by: Stanislaw Gruszka <sgruszka@redhat.com> [reword commit log, use a separate lock] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2014-02-20 07:22:11 +00:00
spin_lock_init(&sta->ps_lock);
INIT_WORK(&sta->drv_deliver_wk, sta_deliver_ps_frames);
wiphy_work_init(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
#ifdef CONFIG_MAC80211_MESH
if (ieee80211_vif_is_mesh(&sdata->vif)) {
sta->mesh = kzalloc(sizeof(*sta->mesh), gfp);
if (!sta->mesh)
goto free;
sta->mesh->plink_sta = sta;
spin_lock_init(&sta->mesh->plink_lock);
if (!sdata->u.mesh.user_mpm)
timer_setup(&sta->mesh->plink_timer, mesh_plink_timer,
0);
sta->mesh->nonpeer_pm = NL80211_MESH_POWER_ACTIVE;
}
#endif
memcpy(sta->addr, addr, ETH_ALEN);
memcpy(sta->sta.addr, addr, ETH_ALEN);
memcpy(sta->deflink.addr, link_addr, ETH_ALEN);
memcpy(sta->sta.deflink.addr, link_addr, ETH_ALEN);
sta->sta.max_rx_aggregation_subframes =
local->hw.max_rx_aggregation_subframes;
mac80211: prepare sta handling for MLO support Currently in mac80211 each STA object is represented using sta_info datastructure with the associated STA specific information and drivers access ieee80211_sta part of it. With MLO (Multi Link Operation) support being added in 802.11be standard, though the association is logically with a single Multi Link capable STA, at the physical level communication can happen via different advertised links (uniquely identified by Channel, operating class, BSSID) and hence the need to handle multiple link STA parameters within a composite sta_info object called the MLD STA. The different link STA part of MLD STA are identified using the link address which can be same or different as the MLD STA address and unique link id based on the link vif. To support extension of such a model, the sta_info datastructure is modified to hold multiple link STA objects with link specific params currently within sta_info moved to this new structure. Similarly this is done for ieee80211_sta as well which will be accessed within mac80211 as well as by drivers, hence trivial driver changes are expected to support this. For current non MLO supported drivers, only one link STA is present and link information is accessed via 'deflink' member. For MLO drivers, we still need to define the APIs etc. to get the correct link ID and access the correct part of the station info. Currently in mac80211, all link STA info are accessed directly via deflink. These will be updated to access via link pointers indexed by link id with MLO support patches, with link id being 0 for non MLO supported cases. Except for couple of macro related changes, below spatch takes care of updating mac80211 and driver code to access to the link STA info via deflink. @ieee80211_sta@ struct ieee80211_sta *s; struct sta_info *si; identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr}; @@ ( s-> - var + deflink.var | si->sta. - var + deflink.var ) @sta_info@ struct sta_info *si; identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth}; @@ ( si-> - var + deflink.var ) Signed-off-by: Sriram R <quic_srirrama@quicinc.com> Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com [remove MLO-drivers notes from commit message, not clear yet; run spatch] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 15:41:23 +00:00
/* TODO link specific alloc and assignments for MLO Link STA */
/* Extended Key ID needs to install keys for keyid 0 and 1 Rx-only.
* The Tx path starts to use a key as soon as the key slot ptk_idx
* references to is not NULL. To not use the initial Rx-only key
* prematurely for Tx initialize ptk_idx to an impossible PTK keyid
* which always will refer to a NULL key.
*/
BUILD_BUG_ON(ARRAY_SIZE(sta->ptk) <= INVALID_PTK_KEYIDX);
sta->ptk_idx = INVALID_PTK_KEYIDX;
ieee80211_init_frag_cache(&sta->frags);
sta->sta_state = IEEE80211_STA_NONE;
if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
sta->amsdu_mesh_control = -1;
/* Mark TID as unreserved */
sta->reserved_tid = IEEE80211_TID_UNRESERVED;
sta->last_connected = ktime_get_seconds();
size = sizeof(struct txq_info) +
ALIGN(hw->txq_data_size, sizeof(void *));
txq_data = kcalloc(ARRAY_SIZE(sta->sta.txq), size, gfp);
if (!txq_data)
goto free;
for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
struct txq_info *txq = txq_data + i * size;
/* might not do anything for the (bufferable) MMPDU TXQ */
ieee80211_txq_init(sdata, sta, txq, i);
}
if (sta_prepare_rate_control(local, sta, gfp))
goto free_txq;
sta->airtime_weight = IEEE80211_DEFAULT_AIRTIME_WEIGHT;
mac80211: Add airtime accounting and scheduling to TXQs This adds airtime accounting and scheduling to the mac80211 TXQ scheduler. A new callback, ieee80211_sta_register_airtime(), is added that drivers can call to report airtime usage for stations. When airtime information is present, mac80211 will schedule TXQs (through ieee80211_next_txq()) in a way that enforces airtime fairness between active stations. This scheduling works the same way as the ath9k in-driver airtime fairness scheduling. If no airtime usage is reported by the driver, the scheduler will default to round-robin scheduling. For drivers that don't control TXQ scheduling in software, a new API function, ieee80211_txq_may_transmit(), is added which the driver can use to check if the TXQ is eligible for transmission, or should be throttled to enforce fairness. Calls to this function must also be enclosed in ieee80211_txq_schedule_{start,end}() calls to ensure proper locking. The API ieee80211_txq_may_transmit() also ensures that TXQ list will be aligned aginst driver's own round-robin scheduler list. i.e it rotates the TXQ list till it makes the requested node becomes the first entry in TXQ list. Thus both the TXQ list and driver's list are in sync. Co-developed-by: Rajkumar Manoharan <rmanohar@codeaurora.org> Signed-off-by: Louie Lu <git@louie.lu> [added debugfs write op to reset airtime counter] Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk> Signed-off-by: Rajkumar Manoharan <rmanohar@codeaurora.org> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2018-12-19 01:02:08 +00:00
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
skb_queue_head_init(&sta->ps_tx_buf[i]);
skb_queue_head_init(&sta->tx_filtered[i]);
sta->airtime[i].deficit = sta->airtime_weight;
atomic_set(&sta->airtime[i].aql_tx_pending, 0);
sta->airtime[i].aql_limit_low = local->aql_txq_limit_low[i];
sta->airtime[i].aql_limit_high = local->aql_txq_limit_high[i];
}
for (i = 0; i < IEEE80211_NUM_TIDS; i++)
sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX);
for (i = 0; i < NUM_NL80211_BANDS; i++) {
u32 mandatory = 0;
int r;
if (!hw->wiphy->bands[i])
continue;
switch (i) {
case NL80211_BAND_2GHZ:
case NL80211_BAND_LC:
/*
* We use both here, even if we cannot really know for
* sure the station will support both, but the only use
* for this is when we don't know anything yet and send
* management frames, and then we'll pick the lowest
* possible rate anyway.
* If we don't include _G here, we cannot find a rate
* in P2P, and thus trigger the WARN_ONCE() in rate.c
*/
mandatory = IEEE80211_RATE_MANDATORY_B |
IEEE80211_RATE_MANDATORY_G;
break;
case NL80211_BAND_5GHZ:
mandatory = IEEE80211_RATE_MANDATORY_A;
break;
case NL80211_BAND_60GHZ:
WARN_ON(1);
mandatory = 0;
break;
}
for (r = 0; r < hw->wiphy->bands[i]->n_bitrates; r++) {
struct ieee80211_rate *rate;
rate = &hw->wiphy->bands[i]->bitrates[r];
if (!(rate->flags & mandatory))
continue;
mac80211: prepare sta handling for MLO support Currently in mac80211 each STA object is represented using sta_info datastructure with the associated STA specific information and drivers access ieee80211_sta part of it. With MLO (Multi Link Operation) support being added in 802.11be standard, though the association is logically with a single Multi Link capable STA, at the physical level communication can happen via different advertised links (uniquely identified by Channel, operating class, BSSID) and hence the need to handle multiple link STA parameters within a composite sta_info object called the MLD STA. The different link STA part of MLD STA are identified using the link address which can be same or different as the MLD STA address and unique link id based on the link vif. To support extension of such a model, the sta_info datastructure is modified to hold multiple link STA objects with link specific params currently within sta_info moved to this new structure. Similarly this is done for ieee80211_sta as well which will be accessed within mac80211 as well as by drivers, hence trivial driver changes are expected to support this. For current non MLO supported drivers, only one link STA is present and link information is accessed via 'deflink' member. For MLO drivers, we still need to define the APIs etc. to get the correct link ID and access the correct part of the station info. Currently in mac80211, all link STA info are accessed directly via deflink. These will be updated to access via link pointers indexed by link id with MLO support patches, with link id being 0 for non MLO supported cases. Except for couple of macro related changes, below spatch takes care of updating mac80211 and driver code to access to the link STA info via deflink. @ieee80211_sta@ struct ieee80211_sta *s; struct sta_info *si; identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr}; @@ ( s-> - var + deflink.var | si->sta. - var + deflink.var ) @sta_info@ struct sta_info *si; identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth}; @@ ( si-> - var + deflink.var ) Signed-off-by: Sriram R <quic_srirrama@quicinc.com> Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com [remove MLO-drivers notes from commit message, not clear yet; run spatch] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 15:41:23 +00:00
sta->sta.deflink.supp_rates[i] |= BIT(r);
}
}
sta->cparams.ce_threshold = CODEL_DISABLED_THRESHOLD;
sta->cparams.target = MS2TIME(20);
sta->cparams.interval = MS2TIME(100);
sta->cparams.ecn = true;
fq_codel: generalise ce_threshold marking for subset of traffic Commit e72aeb9ee0e3 ("fq_codel: implement L4S style ce_threshold_ect1 marking") expanded the ce_threshold feature of FQ-CoDel so it can be applied to a subset of the traffic, using the ECT(1) bit of the ECN field as the classifier. However, hard-coding ECT(1) as the only classifier for this feature seems limiting, so let's expand it to be more general. To this end, change the parameter from a ce_threshold_ect1 boolean, to a one-byte selector/mask pair (ce_threshold_{selector,mask}) which is applied to the whole diffserv/ECN field in the IP header. This makes it possible to classify packets by any value in either the ECN field or the diffserv field. In particular, setting a selector of INET_ECN_ECT_1 and a mask of INET_ECN_MASK corresponds to the functionality before this patch, and a mask of ~INET_ECN_MASK allows using the selector as a straight-forward match against a diffserv code point: # apply ce_threshold to ECT(1) traffic tc qdisc replace dev eth0 root fq_codel ce_threshold 1ms ce_threshold_selector 0x1/0x3 # apply ce_threshold to ECN-capable traffic marked as diffserv AF22 tc qdisc replace dev eth0 root fq_codel ce_threshold 1ms ce_threshold_selector 0x50/0xfc Regardless of the selector chosen, the normal rules for ECN-marking of packets still apply, i.e., the flow must still declare itself ECN-capable by setting one of the bits in the ECN field to get marked at all. v2: - Add tc usage examples to patch description Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com> Reviewed-by: Eric Dumazet <edumazet@google.com> Link: https://lore.kernel.org/r/20211019174709.69081-1-toke@redhat.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2021-10-19 17:47:09 +00:00
sta->cparams.ce_threshold_selector = 0;
sta->cparams.ce_threshold_mask = 0;
sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr);
return sta;
free_txq:
kfree(to_txq_info(sta->sta.txq[0]));
free:
sta_info_free_link(&sta->deflink);
#ifdef CONFIG_MAC80211_MESH
kfree(sta->mesh);
#endif
kfree(sta);
return NULL;
}
struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
const u8 *addr, gfp_t gfp)
{
return __sta_info_alloc(sdata, addr, -1, addr, gfp);
}
struct sta_info *sta_info_alloc_with_link(struct ieee80211_sub_if_data *sdata,
const u8 *mld_addr,
unsigned int link_id,
const u8 *link_addr,
gfp_t gfp)
{
return __sta_info_alloc(sdata, mld_addr, link_id, link_addr, gfp);
}
static int sta_info_insert_check(struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
lockdep_assert_wiphy(sdata->local->hw.wiphy);
/*
* Can't be a WARN_ON because it can be triggered through a race:
* something inserts a STA (on one CPU) without holding the RTNL
* and another CPU turns off the net device.
*/
if (unlikely(!ieee80211_sdata_running(sdata)))
return -ENETDOWN;
if (WARN_ON(ether_addr_equal(sta->sta.addr, sdata->vif.addr) ||
!is_valid_ether_addr(sta->sta.addr)))
return -EINVAL;
/* The RCU read lock is required by rhashtable due to
* asynchronous resize/rehash. We also require the mutex
* for correctness.
*/
rcu_read_lock();
if (ieee80211_hw_check(&sdata->local->hw, NEEDS_UNIQUE_STA_ADDR) &&
ieee80211_find_sta_by_ifaddr(&sdata->local->hw, sta->addr, NULL)) {
rcu_read_unlock();
return -ENOTUNIQ;
}
rcu_read_unlock();
return 0;
}
static int sta_info_insert_drv_state(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct sta_info *sta)
{
enum ieee80211_sta_state state;
int err = 0;
for (state = IEEE80211_STA_NOTEXIST; state < sta->sta_state; state++) {
err = drv_sta_state(local, sdata, sta, state, state + 1);
if (err)
break;
}
if (!err) {
/*
* Drivers using legacy sta_add/sta_remove callbacks only
* get uploaded set to true after sta_add is called.
*/
if (!local->ops->sta_add)
sta->uploaded = true;
return 0;
}
if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
sdata_info(sdata,
"failed to move IBSS STA %pM to state %d (%d) - keeping it anyway\n",
sta->sta.addr, state + 1, err);
err = 0;
}
/* unwind on error */
for (; state > IEEE80211_STA_NOTEXIST; state--)
WARN_ON(drv_sta_state(local, sdata, sta, state, state - 1));
return err;
}
static void
ieee80211_recalc_p2p_go_ps_allowed(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
bool allow_p2p_go_ps = sdata->vif.p2p;
struct sta_info *sta;
rcu_read_lock();
list_for_each_entry_rcu(sta, &local->sta_list, list) {
if (sdata != sta->sdata ||
!test_sta_flag(sta, WLAN_STA_ASSOC))
continue;
if (!sta->sta.support_p2p_ps) {
allow_p2p_go_ps = false;
break;
}
}
rcu_read_unlock();
if (allow_p2p_go_ps != sdata->vif.bss_conf.allow_p2p_go_ps) {
sdata->vif.bss_conf.allow_p2p_go_ps = allow_p2p_go_ps;
ieee80211_link_info_change_notify(sdata, &sdata->deflink,
BSS_CHANGED_P2P_PS);
}
}
static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
{
struct ieee80211_local *local = sta->local;
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct station_info *sinfo = NULL;
int err = 0;
lockdep_assert_wiphy(local->hw.wiphy);
/* check if STA exists already */
if (sta_info_get_bss(sdata, sta->sta.addr)) {
err = -EEXIST;
mac80211: fix a memory leak where sta_info is not freed The following is from a system that went OOM due to a memory leak: wlan0: Allocated STA 74:83:c2:64:0b:87 wlan0: Allocated STA 74:83:c2:64:0b:87 wlan0: IBSS finish 74:83:c2:64:0b:87 (---from ieee80211_ibss_add_sta) wlan0: Adding new IBSS station 74:83:c2:64:0b:87 wlan0: moving STA 74:83:c2:64:0b:87 to state 2 wlan0: moving STA 74:83:c2:64:0b:87 to state 3 wlan0: Inserted STA 74:83:c2:64:0b:87 wlan0: IBSS finish 74:83:c2:64:0b:87 (---from ieee80211_ibss_work) wlan0: Adding new IBSS station 74:83:c2:64:0b:87 wlan0: moving STA 74:83:c2:64:0b:87 to state 2 wlan0: moving STA 74:83:c2:64:0b:87 to state 3 . . wlan0: expiring inactive not authorized STA 74:83:c2:64:0b:87 wlan0: moving STA 74:83:c2:64:0b:87 to state 2 wlan0: moving STA 74:83:c2:64:0b:87 to state 1 wlan0: Removed STA 74:83:c2:64:0b:87 wlan0: Destroyed STA 74:83:c2:64:0b:87 The ieee80211_ibss_finish_sta() is called twice on the same STA from 2 different locations. On the second attempt, the allocated STA is not destroyed creating a kernel memory leak. This is happening because sta_info_insert_finish() does not call sta_info_free() the second time when the STA already exists (returns -EEXIST). Note that the caller sta_info_insert_rcu() assumes STA is destroyed upon errors. Same fix is applied to -ENOMEM. Signed-off-by: Ahmed Zaki <anzaki@gmail.com> Link: https://lore.kernel.org/r/20211002145329.3125293-1-anzaki@gmail.com [change the error path label to use the existing code] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2021-10-02 14:53:29 +00:00
goto out_cleanup;
}
sinfo = kzalloc(sizeof(struct station_info), GFP_KERNEL);
if (!sinfo) {
err = -ENOMEM;
mac80211: fix a memory leak where sta_info is not freed The following is from a system that went OOM due to a memory leak: wlan0: Allocated STA 74:83:c2:64:0b:87 wlan0: Allocated STA 74:83:c2:64:0b:87 wlan0: IBSS finish 74:83:c2:64:0b:87 (---from ieee80211_ibss_add_sta) wlan0: Adding new IBSS station 74:83:c2:64:0b:87 wlan0: moving STA 74:83:c2:64:0b:87 to state 2 wlan0: moving STA 74:83:c2:64:0b:87 to state 3 wlan0: Inserted STA 74:83:c2:64:0b:87 wlan0: IBSS finish 74:83:c2:64:0b:87 (---from ieee80211_ibss_work) wlan0: Adding new IBSS station 74:83:c2:64:0b:87 wlan0: moving STA 74:83:c2:64:0b:87 to state 2 wlan0: moving STA 74:83:c2:64:0b:87 to state 3 . . wlan0: expiring inactive not authorized STA 74:83:c2:64:0b:87 wlan0: moving STA 74:83:c2:64:0b:87 to state 2 wlan0: moving STA 74:83:c2:64:0b:87 to state 1 wlan0: Removed STA 74:83:c2:64:0b:87 wlan0: Destroyed STA 74:83:c2:64:0b:87 The ieee80211_ibss_finish_sta() is called twice on the same STA from 2 different locations. On the second attempt, the allocated STA is not destroyed creating a kernel memory leak. This is happening because sta_info_insert_finish() does not call sta_info_free() the second time when the STA already exists (returns -EEXIST). Note that the caller sta_info_insert_rcu() assumes STA is destroyed upon errors. Same fix is applied to -ENOMEM. Signed-off-by: Ahmed Zaki <anzaki@gmail.com> Link: https://lore.kernel.org/r/20211002145329.3125293-1-anzaki@gmail.com [change the error path label to use the existing code] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2021-10-02 14:53:29 +00:00
goto out_cleanup;
}
local->num_sta++;
local->sta_generation++;
smp_mb();
/* simplify things and don't accept BA sessions yet */
set_sta_flag(sta, WLAN_STA_BLOCK_BA);
/* make the station visible */
err = sta_info_hash_add(local, sta);
if (err)
goto out_drop_sta;
if (sta->sta.valid_links) {
err = link_sta_info_hash_add(local, &sta->deflink);
if (err) {
sta_info_hash_del(local, sta);
goto out_drop_sta;
}
}
list_add_tail_rcu(&sta->list, &local->sta_list);
/* update channel context before notifying the driver about state
* change, this enables driver using the updated channel context right away.
*/
if (sta->sta_state >= IEEE80211_STA_ASSOC) {
ieee80211_recalc_min_chandef(sta->sdata, -1);
if (!sta->sta.support_p2p_ps)
ieee80211_recalc_p2p_go_ps_allowed(sta->sdata);
}
/* notify driver */
err = sta_info_insert_drv_state(local, sdata, sta);
if (err)
goto out_remove;
set_sta_flag(sta, WLAN_STA_INSERTED);
/* accept BA sessions now */
clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
ieee80211_sta_debugfs_add(sta);
rate_control_add_sta_debugfs(sta);
if (sta->sta.valid_links) {
int i;
for (i = 0; i < ARRAY_SIZE(sta->link); i++) {
struct link_sta_info *link_sta;
link_sta = rcu_dereference_protected(sta->link[i],
lockdep_is_held(&local->hw.wiphy->mtx));
if (!link_sta)
continue;
ieee80211_link_sta_debugfs_add(link_sta);
if (sdata->vif.active_links & BIT(i))
ieee80211_link_sta_debugfs_drv_add(link_sta);
}
} else {
ieee80211_link_sta_debugfs_add(&sta->deflink);
ieee80211_link_sta_debugfs_drv_add(&sta->deflink);
}
sinfo->generation = local->sta_generation;
cfg80211_new_sta(sdata->dev, sta->sta.addr, sinfo, GFP_KERNEL);
kfree(sinfo);
sta_dbg(sdata, "Inserted STA %pM\n", sta->sta.addr);
/* move reference to rcu-protected */
rcu_read_lock();
if (ieee80211_vif_is_mesh(&sdata->vif))
mesh_accept_plinks_update(sdata);
ieee80211_check_fast_xmit(sta);
return 0;
out_remove:
if (sta->sta.valid_links)
link_sta_info_hash_del(local, &sta->deflink);
sta_info_hash_del(local, sta);
list_del_rcu(&sta->list);
out_drop_sta:
local->num_sta--;
synchronize_net();
mac80211: fix a memory leak where sta_info is not freed The following is from a system that went OOM due to a memory leak: wlan0: Allocated STA 74:83:c2:64:0b:87 wlan0: Allocated STA 74:83:c2:64:0b:87 wlan0: IBSS finish 74:83:c2:64:0b:87 (---from ieee80211_ibss_add_sta) wlan0: Adding new IBSS station 74:83:c2:64:0b:87 wlan0: moving STA 74:83:c2:64:0b:87 to state 2 wlan0: moving STA 74:83:c2:64:0b:87 to state 3 wlan0: Inserted STA 74:83:c2:64:0b:87 wlan0: IBSS finish 74:83:c2:64:0b:87 (---from ieee80211_ibss_work) wlan0: Adding new IBSS station 74:83:c2:64:0b:87 wlan0: moving STA 74:83:c2:64:0b:87 to state 2 wlan0: moving STA 74:83:c2:64:0b:87 to state 3 . . wlan0: expiring inactive not authorized STA 74:83:c2:64:0b:87 wlan0: moving STA 74:83:c2:64:0b:87 to state 2 wlan0: moving STA 74:83:c2:64:0b:87 to state 1 wlan0: Removed STA 74:83:c2:64:0b:87 wlan0: Destroyed STA 74:83:c2:64:0b:87 The ieee80211_ibss_finish_sta() is called twice on the same STA from 2 different locations. On the second attempt, the allocated STA is not destroyed creating a kernel memory leak. This is happening because sta_info_insert_finish() does not call sta_info_free() the second time when the STA already exists (returns -EEXIST). Note that the caller sta_info_insert_rcu() assumes STA is destroyed upon errors. Same fix is applied to -ENOMEM. Signed-off-by: Ahmed Zaki <anzaki@gmail.com> Link: https://lore.kernel.org/r/20211002145329.3125293-1-anzaki@gmail.com [change the error path label to use the existing code] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2021-10-02 14:53:29 +00:00
out_cleanup:
cleanup_single_sta(sta);
kfree(sinfo);
rcu_read_lock();
return err;
}
int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU)
{
struct ieee80211_local *local = sta->local;
int err;
might_sleep();
lockdep_assert_wiphy(local->hw.wiphy);
err = sta_info_insert_check(sta);
if (err) {
sta_info_free(local, sta);
rcu_read_lock();
return err;
}
return sta_info_insert_finish(sta);
}
int sta_info_insert(struct sta_info *sta)
{
int err = sta_info_insert_rcu(sta);
rcu_read_unlock();
return err;
}
static inline void __bss_tim_set(u8 *tim, u16 id)
{
/*
* This format has been mandated by the IEEE specifications,
* so this line may not be changed to use the __set_bit() format.
*/
tim[id / 8] |= (1 << (id % 8));
}
static inline void __bss_tim_clear(u8 *tim, u16 id)
{
/*
* This format has been mandated by the IEEE specifications,
* so this line may not be changed to use the __clear_bit() format.
*/
tim[id / 8] &= ~(1 << (id % 8));
}
static inline bool __bss_tim_get(u8 *tim, u16 id)
{
/*
* This format has been mandated by the IEEE specifications,
* so this line may not be changed to use the test_bit() format.
*/
return tim[id / 8] & (1 << (id % 8));
}
static unsigned long ieee80211_tids_for_ac(int ac)
{
/* If we ever support TIDs > 7, this obviously needs to be adjusted */
switch (ac) {
case IEEE80211_AC_VO:
return BIT(6) | BIT(7);
case IEEE80211_AC_VI:
return BIT(4) | BIT(5);
case IEEE80211_AC_BE:
return BIT(0) | BIT(3);
case IEEE80211_AC_BK:
return BIT(1) | BIT(2);
default:
WARN_ON(1);
return 0;
}
}
static void __sta_info_recalc_tim(struct sta_info *sta, bool ignore_pending)
{
struct ieee80211_local *local = sta->local;
struct ps_data *ps;
bool indicate_tim = false;
u8 ignore_for_tim = sta->sta.uapsd_queues;
int ac;
u16 id = sta->sta.aid;
if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
if (WARN_ON_ONCE(!sta->sdata->bss))
return;
ps = &sta->sdata->bss->ps;
mac80211: mesh power save basics Add routines to - maintain a PS mode for each peer and a non-peer PS mode - indicate own PS mode in transmitted frames - track neighbor STAs power modes - buffer frames when neighbors are in PS mode - add TIM and Awake Window IE to beacons - release frames in Mesh Peer Service Periods Add local_pm to sta_info to represent the link-specific power mode at this station towards the remote station. When a peer link is established, use the default power mode stored in mesh config. Update the PS status if the peering status of a neighbor changes. Maintain a mesh power mode for non-peer mesh STAs. Set the non-peer power mode to active mode during peering. Authenticated mesh peering is currently not working when either node is configured to be in power save mode. Indicate the current power mode in transmitted frames. Use QoS Nulls to indicate mesh power mode transitions. For performance reasons, calls to the function setting the frame flags are placed in HWMP routing routines, as there the STA pointer is already available. Add peer_pm to sta_info to represent the peer's link-specific power mode towards the local station. Add nonpeer_pm to represent the peer's power mode towards all non-peer stations. Track power modes based on received frames. Add the ps_data structure to ieee80211_if_mesh (for TIM map, PS neighbor counter and group-addressed frame buffer). Set WLAN_STA_PS flag for STA in PS mode to use the unicast frame buffering routines in the tx path. Update num_sta_ps to buffer and release group-addressed frames after DTIM beacons. Announce the awake window duration in beacons if in light or deep sleep mode towards any peer or non-peer. Create a TIM IE similarly to AP mode and add it to mesh beacons. Parse received Awake Window IEs and check TIM IEs for buffered frames. Release frames towards peers in mesh Peer Service Periods. Use the corresponding trigger frames and monitor the MPSP status. Append a QoS Null as trigger frame if neccessary to properly end the MPSP. Currently, in HT channels MPSPs behave imperfectly and show large delay spikes and frame losses. Signed-off-by: Marco Porsch <marco@cozybit.com> Signed-off-by: Ivan Bezyazychnyy <ivan.bezyazychnyy@gmail.com> Signed-off-by: Mike Krinkin <krinkin.m.u@gmail.com> Signed-off-by: Max Filippov <jcmvbkbc@gmail.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2013-01-30 17:14:08 +00:00
#ifdef CONFIG_MAC80211_MESH
} else if (ieee80211_vif_is_mesh(&sta->sdata->vif)) {
ps = &sta->sdata->u.mesh.ps;
#endif
} else {
return;
}
/* No need to do anything if the driver does all */
if (ieee80211_hw_check(&local->hw, AP_LINK_PS) && !local->ops->set_tim)
return;
if (sta->dead)
goto done;
/*
* If all ACs are delivery-enabled then we should build
* the TIM bit for all ACs anyway; if only some are then
* we ignore those and build the TIM bit using only the
* non-enabled ones.
*/
if (ignore_for_tim == BIT(IEEE80211_NUM_ACS) - 1)
ignore_for_tim = 0;
if (ignore_pending)
ignore_for_tim = BIT(IEEE80211_NUM_ACS) - 1;
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
unsigned long tids;
if (ignore_for_tim & ieee80211_ac_to_qos_mask[ac])
continue;
indicate_tim |= !skb_queue_empty(&sta->tx_filtered[ac]) ||
!skb_queue_empty(&sta->ps_tx_buf[ac]);
if (indicate_tim)
break;
tids = ieee80211_tids_for_ac(ac);
indicate_tim |=
sta->driver_buffered_tids & tids;
indicate_tim |=
sta->txq_buffered_tids & tids;
}
done:
spin_lock_bh(&local->tim_lock);
if (indicate_tim == __bss_tim_get(ps->tim, id))
goto out_unlock;
if (indicate_tim)
__bss_tim_set(ps->tim, id);
else
__bss_tim_clear(ps->tim, id);
if (local->ops->set_tim && !WARN_ON(sta->dead)) {
local->tim_in_locked_section = true;
drv_set_tim(local, &sta->sta, indicate_tim);
local->tim_in_locked_section = false;
}
out_unlock:
spin_unlock_bh(&local->tim_lock);
}
void sta_info_recalc_tim(struct sta_info *sta)
{
__sta_info_recalc_tim(sta, false);
}
static bool sta_info_buffer_expired(struct sta_info *sta, struct sk_buff *skb)
{
struct ieee80211_tx_info *info;
int timeout;
if (!skb)
return false;
info = IEEE80211_SKB_CB(skb);
/* Timeout: (2 * listen_interval * beacon_int * 1024 / 1000000) sec */
timeout = (sta->listen_interval *
sta->sdata->vif.bss_conf.beacon_int *
32 / 15625) * HZ;
if (timeout < STA_TX_BUFFER_EXPIRE)
timeout = STA_TX_BUFFER_EXPIRE;
return time_after(jiffies, info->control.jiffies + timeout);
}
static bool sta_info_cleanup_expire_buffered_ac(struct ieee80211_local *local,
struct sta_info *sta, int ac)
{
unsigned long flags;
struct sk_buff *skb;
/*
* First check for frames that should expire on the filtered
* queue. Frames here were rejected by the driver and are on
* a separate queue to avoid reordering with normal PS-buffered
* frames. They also aren't accounted for right now in the
* total_ps_buffered counter.
*/
for (;;) {
spin_lock_irqsave(&sta->tx_filtered[ac].lock, flags);
skb = skb_peek(&sta->tx_filtered[ac]);
if (sta_info_buffer_expired(sta, skb))
skb = __skb_dequeue(&sta->tx_filtered[ac]);
else
skb = NULL;
spin_unlock_irqrestore(&sta->tx_filtered[ac].lock, flags);
/*
* Frames are queued in order, so if this one
* hasn't expired yet we can stop testing. If
* we actually reached the end of the queue we
* also need to stop, of course.
*/
if (!skb)
break;
ieee80211_free_txskb(&local->hw, skb);
}
/*
* Now also check the normal PS-buffered queue, this will
* only find something if the filtered queue was emptied
* since the filtered frames are all before the normal PS
* buffered frames.
*/
for (;;) {
spin_lock_irqsave(&sta->ps_tx_buf[ac].lock, flags);
skb = skb_peek(&sta->ps_tx_buf[ac]);
if (sta_info_buffer_expired(sta, skb))
skb = __skb_dequeue(&sta->ps_tx_buf[ac]);
else
skb = NULL;
spin_unlock_irqrestore(&sta->ps_tx_buf[ac].lock, flags);
/*
* frames are queued in order, so if this one
* hasn't expired yet (or we reached the end of
* the queue) we can stop testing
*/
if (!skb)
break;
local->total_ps_buffered--;
ps_dbg(sta->sdata, "Buffered frame expired (STA %pM)\n",
sta->sta.addr);
ieee80211_free_txskb(&local->hw, skb);
}
/*
* Finally, recalculate the TIM bit for this station -- it might
* now be clear because the station was too slow to retrieve its
* frames.
*/
sta_info_recalc_tim(sta);
/*
* Return whether there are any frames still buffered, this is
* used to check whether the cleanup timer still needs to run,
* if there are no frames we don't need to rearm the timer.
*/
return !(skb_queue_empty(&sta->ps_tx_buf[ac]) &&
skb_queue_empty(&sta->tx_filtered[ac]));
}
static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
struct sta_info *sta)
{
bool have_buffered = false;
int ac;
mac80211: mesh power save basics Add routines to - maintain a PS mode for each peer and a non-peer PS mode - indicate own PS mode in transmitted frames - track neighbor STAs power modes - buffer frames when neighbors are in PS mode - add TIM and Awake Window IE to beacons - release frames in Mesh Peer Service Periods Add local_pm to sta_info to represent the link-specific power mode at this station towards the remote station. When a peer link is established, use the default power mode stored in mesh config. Update the PS status if the peering status of a neighbor changes. Maintain a mesh power mode for non-peer mesh STAs. Set the non-peer power mode to active mode during peering. Authenticated mesh peering is currently not working when either node is configured to be in power save mode. Indicate the current power mode in transmitted frames. Use QoS Nulls to indicate mesh power mode transitions. For performance reasons, calls to the function setting the frame flags are placed in HWMP routing routines, as there the STA pointer is already available. Add peer_pm to sta_info to represent the peer's link-specific power mode towards the local station. Add nonpeer_pm to represent the peer's power mode towards all non-peer stations. Track power modes based on received frames. Add the ps_data structure to ieee80211_if_mesh (for TIM map, PS neighbor counter and group-addressed frame buffer). Set WLAN_STA_PS flag for STA in PS mode to use the unicast frame buffering routines in the tx path. Update num_sta_ps to buffer and release group-addressed frames after DTIM beacons. Announce the awake window duration in beacons if in light or deep sleep mode towards any peer or non-peer. Create a TIM IE similarly to AP mode and add it to mesh beacons. Parse received Awake Window IEs and check TIM IEs for buffered frames. Release frames towards peers in mesh Peer Service Periods. Use the corresponding trigger frames and monitor the MPSP status. Append a QoS Null as trigger frame if neccessary to properly end the MPSP. Currently, in HT channels MPSPs behave imperfectly and show large delay spikes and frame losses. Signed-off-by: Marco Porsch <marco@cozybit.com> Signed-off-by: Ivan Bezyazychnyy <ivan.bezyazychnyy@gmail.com> Signed-off-by: Mike Krinkin <krinkin.m.u@gmail.com> Signed-off-by: Max Filippov <jcmvbkbc@gmail.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2013-01-30 17:14:08 +00:00
/* This is only necessary for stations on BSS/MBSS interfaces */
if (!sta->sdata->bss &&
!ieee80211_vif_is_mesh(&sta->sdata->vif))
return false;
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
have_buffered |=
sta_info_cleanup_expire_buffered_ac(local, sta, ac);
return have_buffered;
}
static int __must_check __sta_info_destroy_part1(struct sta_info *sta)
{
struct ieee80211_local *local;
struct ieee80211_sub_if_data *sdata;
int ret, i;
might_sleep();
if (!sta)
return -ENOENT;
local = sta->local;
sdata = sta->sdata;
lockdep_assert_wiphy(local->hw.wiphy);
/*
* Before removing the station from the driver and
* rate control, it might still start new aggregation
* sessions -- block that to make sure the tear-down
* will be sufficient.
*/
set_sta_flag(sta, WLAN_STA_BLOCK_BA);
ieee80211_sta_tear_down_BA_sessions(sta, AGG_STOP_DESTROY_STA);
/*
* Before removing the station from the driver there might be pending
* rx frames on RSS queues sent prior to the disassociation - wait for
* all such frames to be processed.
*/
drv_sync_rx_queues(local, sta);
for (i = 0; i < ARRAY_SIZE(sta->link); i++) {
struct link_sta_info *link_sta;
if (!(sta->sta.valid_links & BIT(i)))
continue;
link_sta = rcu_dereference_protected(sta->link[i],
lockdep_is_held(&local->hw.wiphy->mtx));
link_sta_info_hash_del(local, link_sta);
}
ret = sta_info_hash_del(local, sta);
if (WARN_ON(ret))
return ret;
/*
* for TDLS peers, make sure to return to the base channel before
* removal.
*/
if (test_sta_flag(sta, WLAN_STA_TDLS_OFF_CHANNEL)) {
drv_tdls_cancel_channel_switch(local, sdata, &sta->sta);
clear_sta_flag(sta, WLAN_STA_TDLS_OFF_CHANNEL);
}
list_del_rcu(&sta->list);
sta->removed = true;
if (sta->uploaded)
drv_sta_pre_rcu_remove(local, sta->sdata, sta);
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
rcu_access_pointer(sdata->u.vlan.sta) == sta)
RCU_INIT_POINTER(sdata->u.vlan.sta, NULL);
return 0;
}
static int _sta_info_move_state(struct sta_info *sta,
enum ieee80211_sta_state new_state,
bool recalc)
{
struct ieee80211_local *local = sta->local;
might_sleep();
if (sta->sta_state == new_state)
return 0;
/* check allowed transitions first */
switch (new_state) {
case IEEE80211_STA_NONE:
if (sta->sta_state != IEEE80211_STA_AUTH)
return -EINVAL;
break;
case IEEE80211_STA_AUTH:
if (sta->sta_state != IEEE80211_STA_NONE &&
sta->sta_state != IEEE80211_STA_ASSOC)
return -EINVAL;
break;
case IEEE80211_STA_ASSOC:
if (sta->sta_state != IEEE80211_STA_AUTH &&
sta->sta_state != IEEE80211_STA_AUTHORIZED)
return -EINVAL;
break;
case IEEE80211_STA_AUTHORIZED:
if (sta->sta_state != IEEE80211_STA_ASSOC)
return -EINVAL;
break;
default:
WARN(1, "invalid state %d", new_state);
return -EINVAL;
}
sta_dbg(sta->sdata, "moving STA %pM to state %d\n",
sta->sta.addr, new_state);
/* notify the driver before the actual changes so it can
* fail the transition
*/
if (test_sta_flag(sta, WLAN_STA_INSERTED)) {
int err = drv_sta_state(sta->local, sta->sdata, sta,
sta->sta_state, new_state);
if (err)
return err;
}
/* reflect the change in all state variables */
switch (new_state) {
case IEEE80211_STA_NONE:
if (sta->sta_state == IEEE80211_STA_AUTH)
clear_bit(WLAN_STA_AUTH, &sta->_flags);
break;
case IEEE80211_STA_AUTH:
if (sta->sta_state == IEEE80211_STA_NONE) {
set_bit(WLAN_STA_AUTH, &sta->_flags);
} else if (sta->sta_state == IEEE80211_STA_ASSOC) {
clear_bit(WLAN_STA_ASSOC, &sta->_flags);
if (recalc) {
ieee80211_recalc_min_chandef(sta->sdata, -1);
if (!sta->sta.support_p2p_ps)
ieee80211_recalc_p2p_go_ps_allowed(sta->sdata);
}
}
break;
case IEEE80211_STA_ASSOC:
if (sta->sta_state == IEEE80211_STA_AUTH) {
set_bit(WLAN_STA_ASSOC, &sta->_flags);
sta->assoc_at = ktime_get_boottime_ns();
if (recalc) {
ieee80211_recalc_min_chandef(sta->sdata, -1);
if (!sta->sta.support_p2p_ps)
ieee80211_recalc_p2p_go_ps_allowed(sta->sdata);
}
} else if (sta->sta_state == IEEE80211_STA_AUTHORIZED) {
ieee80211_vif_dec_num_mcast(sta->sdata);
clear_bit(WLAN_STA_AUTHORIZED, &sta->_flags);
/*
* If we have encryption offload, flush (station) queues
* (after ensuring concurrent TX completed) so we won't
* transmit anything later unencrypted if/when keys are
* also removed, which might otherwise happen depending
* on how the hardware offload works.
*/
if (local->ops->set_key) {
synchronize_net();
if (local->ops->flush_sta)
drv_flush_sta(local, sta->sdata, sta);
else
ieee80211_flush_queues(local,
sta->sdata,
false);
}
ieee80211_clear_fast_xmit(sta);
ieee80211_clear_fast_rx(sta);
}
break;
case IEEE80211_STA_AUTHORIZED:
if (sta->sta_state == IEEE80211_STA_ASSOC) {
ieee80211_vif_inc_num_mcast(sta->sdata);
set_bit(WLAN_STA_AUTHORIZED, &sta->_flags);
ieee80211_check_fast_xmit(sta);
ieee80211_check_fast_rx(sta);
}
if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
sta->sdata->vif.type == NL80211_IFTYPE_AP)
cfg80211_send_layer2_update(sta->sdata->dev,
sta->sta.addr);
break;
default:
break;
}
sta->sta_state = new_state;
return 0;
}
int sta_info_move_state(struct sta_info *sta,
enum ieee80211_sta_state new_state)
{
return _sta_info_move_state(sta, new_state, true);
}
static void __sta_info_destroy_part2(struct sta_info *sta, bool recalc)
{
struct ieee80211_local *local = sta->local;
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct station_info *sinfo;
int ret;
/*
* NOTE: This assumes at least synchronize_net() was done
* after _part1 and before _part2!
*/
/*
* There's a potential race in _part1 where we set WLAN_STA_BLOCK_BA
* but someone might have just gotten past a check, and not yet into
* queuing the work/creating the data/etc.
*
* Do another round of destruction so that the worker is certainly
* canceled before we later free the station.
*
* Since this is after synchronize_rcu()/synchronize_net() we're now
* certain that nobody can actually hold a reference to the STA and
* be calling e.g. ieee80211_start_tx_ba_session().
*/
ieee80211_sta_tear_down_BA_sessions(sta, AGG_STOP_DESTROY_STA);
might_sleep();
lockdep_assert_wiphy(local->hw.wiphy);
if (sta->sta_state == IEEE80211_STA_AUTHORIZED) {
ret = _sta_info_move_state(sta, IEEE80211_STA_ASSOC, recalc);
WARN_ON_ONCE(ret);
}
/* now keys can no longer be reached */
ieee80211_free_sta_keys(local, sta);
/* disable TIM bit - last chance to tell driver */
__sta_info_recalc_tim(sta, true);
sta->dead = true;
local->num_sta--;
local->sta_generation++;
while (sta->sta_state > IEEE80211_STA_NONE) {
ret = _sta_info_move_state(sta, sta->sta_state - 1, recalc);
if (ret) {
WARN_ON_ONCE(1);
break;
}
}
if (sta->uploaded) {
ret = drv_sta_state(local, sdata, sta, IEEE80211_STA_NONE,
IEEE80211_STA_NOTEXIST);
WARN_ON_ONCE(ret != 0);
}
sta_dbg(sdata, "Removed STA %pM\n", sta->sta.addr);
sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL);
if (sinfo)
sta_set_sinfo(sta, sinfo, true);
cfg80211_del_sta_sinfo(sdata->dev, sta->sta.addr, sinfo, GFP_KERNEL);
kfree(sinfo);
ieee80211_sta_debugfs_remove(sta);
ieee80211_destroy_frag_cache(&sta->frags);
cleanup_single_sta(sta);
}
int __must_check __sta_info_destroy(struct sta_info *sta)
{
int err = __sta_info_destroy_part1(sta);
if (err)
return err;
synchronize_net();
__sta_info_destroy_part2(sta, true);
return 0;
}
int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata, const u8 *addr)
{
struct sta_info *sta;
lockdep_assert_wiphy(sdata->local->hw.wiphy);
sta = sta_info_get(sdata, addr);
return __sta_info_destroy(sta);
}
int sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata,
const u8 *addr)
{
struct sta_info *sta;
lockdep_assert_wiphy(sdata->local->hw.wiphy);
sta = sta_info_get_bss(sdata, addr);
return __sta_info_destroy(sta);
}
static void sta_info_cleanup(struct timer_list *t)
{
struct ieee80211_local *local = from_timer(local, t, sta_cleanup);
struct sta_info *sta;
bool timer_needed = false;
rcu_read_lock();
list_for_each_entry_rcu(sta, &local->sta_list, list)
if (sta_info_cleanup_expire_buffered(local, sta))
timer_needed = true;
rcu_read_unlock();
if (local->quiescing)
return;
if (!timer_needed)
return;
mod_timer(&local->sta_cleanup,
round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL));
}
int sta_info_init(struct ieee80211_local *local)
{
int err;
err = rhltable_init(&local->sta_hash, &sta_rht_params);
if (err)
return err;
err = rhltable_init(&local->link_sta_hash, &link_sta_rht_params);
if (err) {
rhltable_destroy(&local->sta_hash);
return err;
}
spin_lock_init(&local->tim_lock);
INIT_LIST_HEAD(&local->sta_list);
timer_setup(&local->sta_cleanup, sta_info_cleanup, 0);
return 0;
}
void sta_info_stop(struct ieee80211_local *local)
{
del_timer_sync(&local->sta_cleanup);
rhltable_destroy(&local->sta_hash);
rhltable_destroy(&local->link_sta_hash);
}
int __sta_info_flush(struct ieee80211_sub_if_data *sdata, bool vlans,
int link_id)
{
struct ieee80211_local *local = sdata->local;
struct sta_info *sta, *tmp;
LIST_HEAD(free_list);
int ret = 0;
might_sleep();
lockdep_assert_wiphy(local->hw.wiphy);
WARN_ON(vlans && sdata->vif.type != NL80211_IFTYPE_AP);
WARN_ON(vlans && !sdata->bss);
list_for_each_entry_safe(sta, tmp, &local->sta_list, list) {
if (sdata != sta->sdata &&
(!vlans || sdata->bss != sta->sdata->bss))
continue;
if (link_id >= 0 && sta->sta.valid_links &&
!(sta->sta.valid_links & BIT(link_id)))
continue;
if (!WARN_ON(__sta_info_destroy_part1(sta)))
list_add(&sta->free_list, &free_list);
ret++;
}
if (!list_empty(&free_list)) {
bool support_p2p_ps = true;
synchronize_net();
list_for_each_entry_safe(sta, tmp, &free_list, free_list) {
if (!sta->sta.support_p2p_ps)
support_p2p_ps = false;
__sta_info_destroy_part2(sta, false);
}
ieee80211_recalc_min_chandef(sdata, -1);
if (!support_p2p_ps)
ieee80211_recalc_p2p_go_ps_allowed(sdata);
}
return ret;
}
void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
unsigned long exp_time)
{
struct ieee80211_local *local = sdata->local;
struct sta_info *sta, *tmp;
lockdep_assert_wiphy(local->hw.wiphy);
mac80211: fix kernel panic in IBSS due to a regression kernel panic occurs when we create an IBSS mode and leave it for sometime without any joiner and this is introduced by the commit ec2b774e7c91094d8c00de579646f1162b87b01e where we don't put proper braces for 'list_for_each_entry_safe' and we pass an invalid 'sta' pointer to __sta_info_destroy EIP is at __list_add+0xe/0xa0 EAX: f3b63db4 EBX: 00000000 ECX: eab88c1c EDX: 00000000 ESI: 00000000 EDI: 00000246 EBP: f3b63d80 ESP: f3b63d58 DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 Process kworker/u:2 (pid: 198, ti=f3b62000 task=f3afbea0 task.ti=f3b62000) Stack: 00000000 00000000 f9ef9821 00000000 00000000 eab88c30 f3b63d80 c017f623 eab88bf0 eab88bf0 f3b63dd0 c066f925 00000000 00000002 00000000 f9ef9821 f3b63da0 c0180a2b eab88c1c eab88c30 00000002 f3afbea0 eab88bf4 f3b63db4 Call Trace: [<f9ef9821>] ? __ieee80211_stop_tx_ba_session+0x31/0x60 [mac80211] [<c017f623>] ? debug_mutex_add_waiter+0x23/0x60 [<c066f925>] __mutex_lock_common+0xd5/0x390 [<f9ef9821>] ? __ieee80211_stop_tx_ba_session+0x31/0x60 [mac80211] [<c0180a2b>] ? trace_hardirqs_off+0xb/0x10 [<c066fd37>] mutex_lock_nested+0x47/0x60 [<f9ef9821>] ? __ieee80211_stop_tx_ba_session+0x31/0x60 [mac80211] [<f9ef9821>] __ieee80211_stop_tx_ba_session+0x31/0x60 [mac80211] [<f9ef8989>] ieee80211_sta_tear_down_BA_sessions+0x39/0x60 [mac80211] [<f9ef1a67>] __sta_info_destroy+0x57/0x780 [mac80211] [<f9ef2223>] ieee80211_sta_expire+0x93/0xb0 [mac80211] [<f9efc8f6>] ieee80211_ibss_work+0x2d6/0x530 [mac80211] Cc: Marek Lindner <lindner_marek@yahoo.de> Signed-off-by: Mohammed Shafi Shajakhan <mohammed@qca.qualcomm.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2011-12-26 05:13:29 +00:00
list_for_each_entry_safe(sta, tmp, &local->sta_list, list) {
unsigned long last_active = ieee80211_sta_last_active(sta);
if (sdata != sta->sdata)
continue;
if (time_is_before_jiffies(last_active + exp_time)) {
sta_dbg(sta->sdata, "expiring inactive STA %pM\n",
sta->sta.addr);
mac80211: mesh power save basics Add routines to - maintain a PS mode for each peer and a non-peer PS mode - indicate own PS mode in transmitted frames - track neighbor STAs power modes - buffer frames when neighbors are in PS mode - add TIM and Awake Window IE to beacons - release frames in Mesh Peer Service Periods Add local_pm to sta_info to represent the link-specific power mode at this station towards the remote station. When a peer link is established, use the default power mode stored in mesh config. Update the PS status if the peering status of a neighbor changes. Maintain a mesh power mode for non-peer mesh STAs. Set the non-peer power mode to active mode during peering. Authenticated mesh peering is currently not working when either node is configured to be in power save mode. Indicate the current power mode in transmitted frames. Use QoS Nulls to indicate mesh power mode transitions. For performance reasons, calls to the function setting the frame flags are placed in HWMP routing routines, as there the STA pointer is already available. Add peer_pm to sta_info to represent the peer's link-specific power mode towards the local station. Add nonpeer_pm to represent the peer's power mode towards all non-peer stations. Track power modes based on received frames. Add the ps_data structure to ieee80211_if_mesh (for TIM map, PS neighbor counter and group-addressed frame buffer). Set WLAN_STA_PS flag for STA in PS mode to use the unicast frame buffering routines in the tx path. Update num_sta_ps to buffer and release group-addressed frames after DTIM beacons. Announce the awake window duration in beacons if in light or deep sleep mode towards any peer or non-peer. Create a TIM IE similarly to AP mode and add it to mesh beacons. Parse received Awake Window IEs and check TIM IEs for buffered frames. Release frames towards peers in mesh Peer Service Periods. Use the corresponding trigger frames and monitor the MPSP status. Append a QoS Null as trigger frame if neccessary to properly end the MPSP. Currently, in HT channels MPSPs behave imperfectly and show large delay spikes and frame losses. Signed-off-by: Marco Porsch <marco@cozybit.com> Signed-off-by: Ivan Bezyazychnyy <ivan.bezyazychnyy@gmail.com> Signed-off-by: Mike Krinkin <krinkin.m.u@gmail.com> Signed-off-by: Max Filippov <jcmvbkbc@gmail.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2013-01-30 17:14:08 +00:00
if (ieee80211_vif_is_mesh(&sdata->vif) &&
test_sta_flag(sta, WLAN_STA_PS_STA))
atomic_dec(&sdata->u.mesh.ps.num_sta_ps);
WARN_ON(__sta_info_destroy(sta));
}
mac80211: fix kernel panic in IBSS due to a regression kernel panic occurs when we create an IBSS mode and leave it for sometime without any joiner and this is introduced by the commit ec2b774e7c91094d8c00de579646f1162b87b01e where we don't put proper braces for 'list_for_each_entry_safe' and we pass an invalid 'sta' pointer to __sta_info_destroy EIP is at __list_add+0xe/0xa0 EAX: f3b63db4 EBX: 00000000 ECX: eab88c1c EDX: 00000000 ESI: 00000000 EDI: 00000246 EBP: f3b63d80 ESP: f3b63d58 DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 Process kworker/u:2 (pid: 198, ti=f3b62000 task=f3afbea0 task.ti=f3b62000) Stack: 00000000 00000000 f9ef9821 00000000 00000000 eab88c30 f3b63d80 c017f623 eab88bf0 eab88bf0 f3b63dd0 c066f925 00000000 00000002 00000000 f9ef9821 f3b63da0 c0180a2b eab88c1c eab88c30 00000002 f3afbea0 eab88bf4 f3b63db4 Call Trace: [<f9ef9821>] ? __ieee80211_stop_tx_ba_session+0x31/0x60 [mac80211] [<c017f623>] ? debug_mutex_add_waiter+0x23/0x60 [<c066f925>] __mutex_lock_common+0xd5/0x390 [<f9ef9821>] ? __ieee80211_stop_tx_ba_session+0x31/0x60 [mac80211] [<c0180a2b>] ? trace_hardirqs_off+0xb/0x10 [<c066fd37>] mutex_lock_nested+0x47/0x60 [<f9ef9821>] ? __ieee80211_stop_tx_ba_session+0x31/0x60 [mac80211] [<f9ef9821>] __ieee80211_stop_tx_ba_session+0x31/0x60 [mac80211] [<f9ef8989>] ieee80211_sta_tear_down_BA_sessions+0x39/0x60 [mac80211] [<f9ef1a67>] __sta_info_destroy+0x57/0x780 [mac80211] [<f9ef2223>] ieee80211_sta_expire+0x93/0xb0 [mac80211] [<f9efc8f6>] ieee80211_ibss_work+0x2d6/0x530 [mac80211] Cc: Marek Lindner <lindner_marek@yahoo.de> Signed-off-by: Mohammed Shafi Shajakhan <mohammed@qca.qualcomm.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2011-12-26 05:13:29 +00:00
}
}
struct ieee80211_sta *ieee80211_find_sta_by_ifaddr(struct ieee80211_hw *hw,
const u8 *addr,
const u8 *localaddr)
{
struct ieee80211_local *local = hw_to_local(hw);
struct rhlist_head *tmp;
struct sta_info *sta;
/*
* Just return a random station if localaddr is NULL
* ... first in list.
*/
for_each_sta_info(local, addr, sta, tmp) {
if (localaddr &&
!ether_addr_equal(sta->sdata->vif.addr, localaddr))
continue;
if (!sta->uploaded)
return NULL;
return &sta->sta;
}
return NULL;
}
EXPORT_SYMBOL_GPL(ieee80211_find_sta_by_ifaddr);
struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif,
const u8 *addr)
{
struct sta_info *sta;
if (!vif)
return NULL;
sta = sta_info_get_bss(vif_to_sdata(vif), addr);
if (!sta)
return NULL;
if (!sta->uploaded)
return NULL;
return &sta->sta;
}
EXPORT_SYMBOL(ieee80211_find_sta);
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
/* powersave support code */
void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
struct sk_buff_head pending;
int filtered = 0, buffered = 0, ac, i;
unsigned long flags;
struct ps_data *ps;
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
sdata = container_of(sdata->bss, struct ieee80211_sub_if_data,
u.ap);
if (sdata->vif.type == NL80211_IFTYPE_AP)
ps = &sdata->bss->ps;
mac80211: mesh power save basics Add routines to - maintain a PS mode for each peer and a non-peer PS mode - indicate own PS mode in transmitted frames - track neighbor STAs power modes - buffer frames when neighbors are in PS mode - add TIM and Awake Window IE to beacons - release frames in Mesh Peer Service Periods Add local_pm to sta_info to represent the link-specific power mode at this station towards the remote station. When a peer link is established, use the default power mode stored in mesh config. Update the PS status if the peering status of a neighbor changes. Maintain a mesh power mode for non-peer mesh STAs. Set the non-peer power mode to active mode during peering. Authenticated mesh peering is currently not working when either node is configured to be in power save mode. Indicate the current power mode in transmitted frames. Use QoS Nulls to indicate mesh power mode transitions. For performance reasons, calls to the function setting the frame flags are placed in HWMP routing routines, as there the STA pointer is already available. Add peer_pm to sta_info to represent the peer's link-specific power mode towards the local station. Add nonpeer_pm to represent the peer's power mode towards all non-peer stations. Track power modes based on received frames. Add the ps_data structure to ieee80211_if_mesh (for TIM map, PS neighbor counter and group-addressed frame buffer). Set WLAN_STA_PS flag for STA in PS mode to use the unicast frame buffering routines in the tx path. Update num_sta_ps to buffer and release group-addressed frames after DTIM beacons. Announce the awake window duration in beacons if in light or deep sleep mode towards any peer or non-peer. Create a TIM IE similarly to AP mode and add it to mesh beacons. Parse received Awake Window IEs and check TIM IEs for buffered frames. Release frames towards peers in mesh Peer Service Periods. Use the corresponding trigger frames and monitor the MPSP status. Append a QoS Null as trigger frame if neccessary to properly end the MPSP. Currently, in HT channels MPSPs behave imperfectly and show large delay spikes and frame losses. Signed-off-by: Marco Porsch <marco@cozybit.com> Signed-off-by: Ivan Bezyazychnyy <ivan.bezyazychnyy@gmail.com> Signed-off-by: Mike Krinkin <krinkin.m.u@gmail.com> Signed-off-by: Max Filippov <jcmvbkbc@gmail.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2013-01-30 17:14:08 +00:00
else if (ieee80211_vif_is_mesh(&sdata->vif))
ps = &sdata->u.mesh.ps;
else
return;
clear_sta_flag(sta, WLAN_STA_SP);
BUILD_BUG_ON(BITS_TO_LONGS(IEEE80211_NUM_TIDS) > 1);
sta->driver_buffered_tids = 0;
sta->txq_buffered_tids = 0;
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
if (!ieee80211_hw_check(&local->hw, AP_LINK_PS))
drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta);
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
if (!sta->sta.txq[i] || !txq_has_queue(sta->sta.txq[i]))
continue;
schedule_and_wake_txq(local, to_txq_info(sta->sta.txq[i]));
}
skb_queue_head_init(&pending);
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
mac80211: fix AP powersave TX vs. wakeup race There is a race between the TX path and the STA wakeup: while a station is sleeping, mac80211 buffers frames until it wakes up, then the frames are transmitted. However, the RX and TX path are concurrent, so the packet indicating wakeup can be processed while a packet is being transmitted. This can lead to a situation where the buffered frames list is emptied on the one side, while a frame is being added on the other side, as the station is still seen as sleeping in the TX path. As a result, the newly added frame will not be send anytime soon. It might be sent much later (and out of order) when the station goes to sleep and wakes up the next time. Additionally, it can lead to the crash below. Fix all this by synchronising both paths with a new lock. Both path are not fastpath since they handle PS situations. In a later patch we'll remove the extra skb queue locks to reduce locking overhead. BUG: unable to handle kernel NULL pointer dereference at 000000b0 IP: [<ff6f1791>] ieee80211_report_used_skb+0x11/0x3e0 [mac80211] *pde = 00000000 Oops: 0000 [#1] SMP DEBUG_PAGEALLOC EIP: 0060:[<ff6f1791>] EFLAGS: 00210282 CPU: 1 EIP is at ieee80211_report_used_skb+0x11/0x3e0 [mac80211] EAX: e5900da0 EBX: 00000000 ECX: 00000001 EDX: 00000000 ESI: e41d00c0 EDI: e5900da0 EBP: ebe458e4 ESP: ebe458b0 DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 CR0: 8005003b CR2: 000000b0 CR3: 25a78000 CR4: 000407d0 DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000 DR6: ffff0ff0 DR7: 00000400 Process iperf (pid: 3934, ti=ebe44000 task=e757c0b0 task.ti=ebe44000) iwlwifi 0000:02:00.0: I iwl_pcie_enqueue_hcmd Sending command LQ_CMD (#4e), seq: 0x0903, 92 bytes at 3[3]:9 Stack: e403b32c ebe458c4 00200002 00200286 e403b338 ebe458cc c10960bb e5900da0 ff76a6ec ebe458d8 00000000 e41d00c0 e5900da0 ebe458f0 ff6f1b75 e403b210 ebe4598c ff723dc1 00000000 ff76a6ec e597c978 e403b758 00000002 00000002 Call Trace: [<ff6f1b75>] ieee80211_free_txskb+0x15/0x20 [mac80211] [<ff723dc1>] invoke_tx_handlers+0x1661/0x1780 [mac80211] [<ff7248a5>] ieee80211_tx+0x75/0x100 [mac80211] [<ff7249bf>] ieee80211_xmit+0x8f/0xc0 [mac80211] [<ff72550e>] ieee80211_subif_start_xmit+0x4fe/0xe20 [mac80211] [<c149ef70>] dev_hard_start_xmit+0x450/0x950 [<c14b9aa9>] sch_direct_xmit+0xa9/0x250 [<c14b9c9b>] __qdisc_run+0x4b/0x150 [<c149f732>] dev_queue_xmit+0x2c2/0xca0 Cc: stable@vger.kernel.org Reported-by: Yaara Rozenblum <yaara.rozenblum@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Reviewed-by: Stanislaw Gruszka <sgruszka@redhat.com> [reword commit log, use a separate lock] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2014-02-20 07:22:11 +00:00
/* sync with ieee80211_tx_h_unicast_ps_buf */
wifi: mac80211: Fix deadlock in ieee80211_sta_ps_deliver_wakeup() The ieee80211_sta_ps_deliver_wakeup() function takes sta->ps_lock to synchronizes with ieee80211_tx_h_unicast_ps_buf() which is called from softirq context. However using only spin_lock() to get sta->ps_lock in ieee80211_sta_ps_deliver_wakeup() does not prevent softirq to execute on this same CPU, to run ieee80211_tx_h_unicast_ps_buf() and try to take this same lock ending in deadlock. Below is an example of rcu stall that arises in such situation. rcu: INFO: rcu_sched self-detected stall on CPU rcu: 2-....: (42413413 ticks this GP) idle=b154/1/0x4000000000000000 softirq=1763/1765 fqs=21206996 rcu: (t=42586894 jiffies g=2057 q=362405 ncpus=4) CPU: 2 PID: 719 Comm: wpa_supplicant Tainted: G W 6.4.0-02158-g1b062f552873 #742 Hardware name: RPT (r1) (DT) pstate: 00000005 (nzcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : queued_spin_lock_slowpath+0x58/0x2d0 lr : invoke_tx_handlers_early+0x5b4/0x5c0 sp : ffff00001ef64660 x29: ffff00001ef64660 x28: ffff000009bc1070 x27: ffff000009bc0ad8 x26: ffff000009bc0900 x25: ffff00001ef647a8 x24: 0000000000000000 x23: ffff000009bc0900 x22: ffff000009bc0900 x21: ffff00000ac0e000 x20: ffff00000a279e00 x19: ffff00001ef646e8 x18: 0000000000000000 x17: ffff800016468000 x16: ffff00001ef608c0 x15: 0010533c93f64f80 x14: 0010395c9faa3946 x13: 0000000000000000 x12: 00000000fa83b2da x11: 000000012edeceea x10: ffff0000010fbe00 x9 : 0000000000895440 x8 : 000000000010533c x7 : ffff00000ad8b740 x6 : ffff00000c350880 x5 : 0000000000000007 x4 : 0000000000000001 x3 : 0000000000000000 x2 : 0000000000000000 x1 : 0000000000000001 x0 : ffff00000ac0e0e8 Call trace: queued_spin_lock_slowpath+0x58/0x2d0 ieee80211_tx+0x80/0x12c ieee80211_tx_pending+0x110/0x278 tasklet_action_common.constprop.0+0x10c/0x144 tasklet_action+0x20/0x28 _stext+0x11c/0x284 ____do_softirq+0xc/0x14 call_on_irq_stack+0x24/0x34 do_softirq_own_stack+0x18/0x20 do_softirq+0x74/0x7c __local_bh_enable_ip+0xa0/0xa4 _ieee80211_wake_txqs+0x3b0/0x4b8 __ieee80211_wake_queue+0x12c/0x168 ieee80211_add_pending_skbs+0xec/0x138 ieee80211_sta_ps_deliver_wakeup+0x2a4/0x480 ieee80211_mps_sta_status_update.part.0+0xd8/0x11c ieee80211_mps_sta_status_update+0x18/0x24 sta_apply_parameters+0x3bc/0x4c0 ieee80211_change_station+0x1b8/0x2dc nl80211_set_station+0x444/0x49c genl_family_rcv_msg_doit.isra.0+0xa4/0xfc genl_rcv_msg+0x1b0/0x244 netlink_rcv_skb+0x38/0x10c genl_rcv+0x34/0x48 netlink_unicast+0x254/0x2bc netlink_sendmsg+0x190/0x3b4 ____sys_sendmsg+0x1e8/0x218 ___sys_sendmsg+0x68/0x8c __sys_sendmsg+0x44/0x84 __arm64_sys_sendmsg+0x20/0x28 do_el0_svc+0x6c/0xe8 el0_svc+0x14/0x48 el0t_64_sync_handler+0xb0/0xb4 el0t_64_sync+0x14c/0x150 Using spin_lock_bh()/spin_unlock_bh() instead prevents softirq to raise on the same CPU that is holding the lock. Fixes: 1d147bfa6429 ("mac80211: fix AP powersave TX vs. wakeup race") Signed-off-by: Remi Pommarel <repk@triplefau.lt> Link: https://msgid.link/8e36fe07d0fbc146f89196cd47a53c8a0afe84aa.1716910344.git.repk@triplefau.lt Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2024-05-29 06:57:53 +00:00
spin_lock_bh(&sta->ps_lock);
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
/* Send all buffered frames to the station */
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
int count = skb_queue_len(&pending), tmp;
spin_lock_irqsave(&sta->tx_filtered[ac].lock, flags);
skb_queue_splice_tail_init(&sta->tx_filtered[ac], &pending);
spin_unlock_irqrestore(&sta->tx_filtered[ac].lock, flags);
tmp = skb_queue_len(&pending);
filtered += tmp - count;
count = tmp;
spin_lock_irqsave(&sta->ps_tx_buf[ac].lock, flags);
skb_queue_splice_tail_init(&sta->ps_tx_buf[ac], &pending);
spin_unlock_irqrestore(&sta->ps_tx_buf[ac].lock, flags);
tmp = skb_queue_len(&pending);
buffered += tmp - count;
}
ieee80211_add_pending_skbs(local, &pending);
/* now we're no longer in the deliver code */
clear_sta_flag(sta, WLAN_STA_PS_DELIVER);
/* The station might have polled and then woken up before we responded,
* so clear these flags now to avoid them sticking around.
*/
clear_sta_flag(sta, WLAN_STA_PSPOLL);
clear_sta_flag(sta, WLAN_STA_UAPSD);
wifi: mac80211: Fix deadlock in ieee80211_sta_ps_deliver_wakeup() The ieee80211_sta_ps_deliver_wakeup() function takes sta->ps_lock to synchronizes with ieee80211_tx_h_unicast_ps_buf() which is called from softirq context. However using only spin_lock() to get sta->ps_lock in ieee80211_sta_ps_deliver_wakeup() does not prevent softirq to execute on this same CPU, to run ieee80211_tx_h_unicast_ps_buf() and try to take this same lock ending in deadlock. Below is an example of rcu stall that arises in such situation. rcu: INFO: rcu_sched self-detected stall on CPU rcu: 2-....: (42413413 ticks this GP) idle=b154/1/0x4000000000000000 softirq=1763/1765 fqs=21206996 rcu: (t=42586894 jiffies g=2057 q=362405 ncpus=4) CPU: 2 PID: 719 Comm: wpa_supplicant Tainted: G W 6.4.0-02158-g1b062f552873 #742 Hardware name: RPT (r1) (DT) pstate: 00000005 (nzcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : queued_spin_lock_slowpath+0x58/0x2d0 lr : invoke_tx_handlers_early+0x5b4/0x5c0 sp : ffff00001ef64660 x29: ffff00001ef64660 x28: ffff000009bc1070 x27: ffff000009bc0ad8 x26: ffff000009bc0900 x25: ffff00001ef647a8 x24: 0000000000000000 x23: ffff000009bc0900 x22: ffff000009bc0900 x21: ffff00000ac0e000 x20: ffff00000a279e00 x19: ffff00001ef646e8 x18: 0000000000000000 x17: ffff800016468000 x16: ffff00001ef608c0 x15: 0010533c93f64f80 x14: 0010395c9faa3946 x13: 0000000000000000 x12: 00000000fa83b2da x11: 000000012edeceea x10: ffff0000010fbe00 x9 : 0000000000895440 x8 : 000000000010533c x7 : ffff00000ad8b740 x6 : ffff00000c350880 x5 : 0000000000000007 x4 : 0000000000000001 x3 : 0000000000000000 x2 : 0000000000000000 x1 : 0000000000000001 x0 : ffff00000ac0e0e8 Call trace: queued_spin_lock_slowpath+0x58/0x2d0 ieee80211_tx+0x80/0x12c ieee80211_tx_pending+0x110/0x278 tasklet_action_common.constprop.0+0x10c/0x144 tasklet_action+0x20/0x28 _stext+0x11c/0x284 ____do_softirq+0xc/0x14 call_on_irq_stack+0x24/0x34 do_softirq_own_stack+0x18/0x20 do_softirq+0x74/0x7c __local_bh_enable_ip+0xa0/0xa4 _ieee80211_wake_txqs+0x3b0/0x4b8 __ieee80211_wake_queue+0x12c/0x168 ieee80211_add_pending_skbs+0xec/0x138 ieee80211_sta_ps_deliver_wakeup+0x2a4/0x480 ieee80211_mps_sta_status_update.part.0+0xd8/0x11c ieee80211_mps_sta_status_update+0x18/0x24 sta_apply_parameters+0x3bc/0x4c0 ieee80211_change_station+0x1b8/0x2dc nl80211_set_station+0x444/0x49c genl_family_rcv_msg_doit.isra.0+0xa4/0xfc genl_rcv_msg+0x1b0/0x244 netlink_rcv_skb+0x38/0x10c genl_rcv+0x34/0x48 netlink_unicast+0x254/0x2bc netlink_sendmsg+0x190/0x3b4 ____sys_sendmsg+0x1e8/0x218 ___sys_sendmsg+0x68/0x8c __sys_sendmsg+0x44/0x84 __arm64_sys_sendmsg+0x20/0x28 do_el0_svc+0x6c/0xe8 el0_svc+0x14/0x48 el0t_64_sync_handler+0xb0/0xb4 el0t_64_sync+0x14c/0x150 Using spin_lock_bh()/spin_unlock_bh() instead prevents softirq to raise on the same CPU that is holding the lock. Fixes: 1d147bfa6429 ("mac80211: fix AP powersave TX vs. wakeup race") Signed-off-by: Remi Pommarel <repk@triplefau.lt> Link: https://msgid.link/8e36fe07d0fbc146f89196cd47a53c8a0afe84aa.1716910344.git.repk@triplefau.lt Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2024-05-29 06:57:53 +00:00
spin_unlock_bh(&sta->ps_lock);
atomic_dec(&ps->num_sta_ps);
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
local->total_ps_buffered -= buffered;
sta_info_recalc_tim(sta);
ps_dbg(sdata,
"STA %pM aid %d sending %d filtered/%d PS frames since STA woke up\n",
sta->sta.addr, sta->sta.aid, filtered, buffered);
ieee80211_check_fast_xmit(sta);
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
}
static void ieee80211_send_null_response(struct sta_info *sta, int tid,
enum ieee80211_frame_release_type reason,
bool call_driver, bool more_data)
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
struct ieee80211_local *local = sdata->local;
struct ieee80211_qos_hdr *nullfunc;
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
struct sk_buff *skb;
int size = sizeof(*nullfunc);
__le16 fc;
bool qos = sta->sta.wme;
struct ieee80211_tx_info *info;
struct ieee80211_chanctx_conf *chanctx_conf;
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
if (qos) {
fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
IEEE80211_STYPE_QOS_NULLFUNC |
IEEE80211_FCTL_FROMDS);
} else {
size -= 2;
fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
IEEE80211_STYPE_NULLFUNC |
IEEE80211_FCTL_FROMDS);
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
}
skb = dev_alloc_skb(local->hw.extra_tx_headroom + size);
if (!skb)
return;
skb_reserve(skb, local->hw.extra_tx_headroom);
nullfunc = skb_put(skb, size);
nullfunc->frame_control = fc;
nullfunc->duration_id = 0;
memcpy(nullfunc->addr1, sta->sta.addr, ETH_ALEN);
memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN);
memcpy(nullfunc->addr3, sdata->vif.addr, ETH_ALEN);
nullfunc->seq_ctrl = 0;
skb->priority = tid;
skb_set_queue_mapping(skb, ieee802_1d_to_ac[tid]);
if (qos) {
nullfunc->qos_ctrl = cpu_to_le16(tid);
if (reason == IEEE80211_FRAME_RELEASE_UAPSD) {
nullfunc->qos_ctrl |=
cpu_to_le16(IEEE80211_QOS_CTL_EOSP);
if (more_data)
nullfunc->frame_control |=
cpu_to_le16(IEEE80211_FCTL_MOREDATA);
}
}
info = IEEE80211_SKB_CB(skb);
/*
* Tell TX path to send this frame even though the
* STA may still remain is PS mode after this frame
* exchange. Also set EOSP to indicate this packet
* ends the poll/service period.
*/
info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER |
IEEE80211_TX_STATUS_EOSP |
IEEE80211_TX_CTL_REQ_TX_STATUS;
info->control.flags |= IEEE80211_TX_CTRL_PS_RESPONSE;
if (call_driver)
drv_allow_buffered_frames(local, sta, BIT(tid), 1,
reason, false);
skb->dev = sdata->dev;
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf);
if (WARN_ON(!chanctx_conf)) {
rcu_read_unlock();
kfree_skb(skb);
return;
}
info->band = chanctx_conf->def.chan->band;
ieee80211_xmit(sdata, sta, skb);
rcu_read_unlock();
}
static int find_highest_prio_tid(unsigned long tids)
{
/* lower 3 TIDs aren't ordered perfectly */
if (tids & 0xF8)
return fls(tids) - 1;
/* TID 0 is BE just like TID 3 */
if (tids & BIT(0))
return 0;
return fls(tids) - 1;
}
/* Indicates if the MORE_DATA bit should be set in the last
* frame obtained by ieee80211_sta_ps_get_frames.
* Note that driver_release_tids is relevant only if
* reason = IEEE80211_FRAME_RELEASE_PSPOLL
*/
static bool
ieee80211_sta_ps_more_data(struct sta_info *sta, u8 ignored_acs,
enum ieee80211_frame_release_type reason,
unsigned long driver_release_tids)
{
int ac;
/* If the driver has data on more than one TID then
* certainly there's more data if we release just a
* single frame now (from a single TID). This will
* only happen for PS-Poll.
*/
if (reason == IEEE80211_FRAME_RELEASE_PSPOLL &&
hweight16(driver_release_tids) > 1)
return true;
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
if (ignored_acs & ieee80211_ac_to_qos_mask[ac])
continue;
if (!skb_queue_empty(&sta->tx_filtered[ac]) ||
!skb_queue_empty(&sta->ps_tx_buf[ac]))
return true;
}
return false;
}
static void
ieee80211_sta_ps_get_frames(struct sta_info *sta, int n_frames, u8 ignored_acs,
enum ieee80211_frame_release_type reason,
struct sk_buff_head *frames,
unsigned long *driver_release_tids)
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
int ac;
/* Get response frame(s) and more data bit for the last one. */
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
unsigned long tids;
if (ignored_acs & ieee80211_ac_to_qos_mask[ac])
continue;
tids = ieee80211_tids_for_ac(ac);
/* if we already have frames from software, then we can't also
* release from hardware queues
*/
if (skb_queue_empty(frames)) {
*driver_release_tids |=
sta->driver_buffered_tids & tids;
*driver_release_tids |= sta->txq_buffered_tids & tids;
}
if (!*driver_release_tids) {
struct sk_buff *skb;
while (n_frames > 0) {
skb = skb_dequeue(&sta->tx_filtered[ac]);
if (!skb) {
skb = skb_dequeue(
&sta->ps_tx_buf[ac]);
if (skb)
local->total_ps_buffered--;
}
if (!skb)
break;
n_frames--;
__skb_queue_tail(frames, skb);
}
}
/* If we have more frames buffered on this AC, then abort the
* loop since we can't send more data from other ACs before
* the buffered frames from this.
*/
if (!skb_queue_empty(&sta->tx_filtered[ac]) ||
!skb_queue_empty(&sta->ps_tx_buf[ac]))
break;
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
}
}
static void
ieee80211_sta_ps_deliver_response(struct sta_info *sta,
int n_frames, u8 ignored_acs,
enum ieee80211_frame_release_type reason)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
unsigned long driver_release_tids = 0;
struct sk_buff_head frames;
bool more_data;
/* Service or PS-Poll period starts */
set_sta_flag(sta, WLAN_STA_SP);
__skb_queue_head_init(&frames);
ieee80211_sta_ps_get_frames(sta, n_frames, ignored_acs, reason,
&frames, &driver_release_tids);
more_data = ieee80211_sta_ps_more_data(sta, ignored_acs, reason, driver_release_tids);
mac80211: fix PS-Poll handling My commit below broken PS-Poll handling. In case the driver has no frames buffered, driver_release_tids will be 0, but calling find_highest_prio_tid() with 0 as a parameter is not a good idea: fls(0) - 1 = -1. This bug caused mac80211 to think that frames were buffered in the driver which in turn was confused because mac80211 was asking to release frames that were not reported to exist. On iwlwifi, this led to the WARNING below: WARNING: CPU: 0 PID: 11230 at drivers/net/wireless/intel/iwlwifi/mvm/sta.c:1733 iwl_mvm_sta_modify_sleep_tx_count+0x2af/0x320 [iwlmvm]() ffffffffc0627c60 ffff8800069b7648 ffffffff81888913 0000000000000000 0000000000000000 ffff8800069b7688 ffffffff81089d6a ffff8800069b7678 0000000000000001 ffff88003b35abf0 ffff88000698b128 ffff8800069b76d4 Call Trace: [<ffffffff81888913>] dump_stack+0x4c/0x65 [<ffffffff81089d6a>] warn_slowpath_common+0x8a/0xc0 [<ffffffff81089e5a>] warn_slowpath_null+0x1a/0x20 [<ffffffffc05f36bf>] iwl_mvm_sta_modify_sleep_tx_count+0x2af/0x320 [iwlmvm] [<ffffffffc05dae41>] iwl_mvm_mac_release_buffered_frames+0x31/0x40 [iwlmvm] [<ffffffffc045d8b6>] ieee80211_sta_ps_deliver_response+0x6e6/0xd80 [mac80211] [<ffffffffc0461296>] ieee80211_sta_ps_deliver_poll_response+0x26/0x30 [mac80211] [<ffffffffc048f743>] ieee80211_rx_handlers+0xa83/0x2900 [mac80211] [<ffffffffc04917ad>] ieee80211_prepare_and_rx_handle+0x1ed/0xa70 [mac80211] [<ffffffffc045e3d5>] ? sta_info_get_bss+0x5/0x4a0 [mac80211] [<ffffffffc04925b6>] ieee80211_rx_napi+0x586/0xcd0 [mac80211] [<ffffffffc05eaa3e>] iwl_mvm_rx_rx_mpdu+0x59e/0xc60 [iwlmvm] Fixes: 0ead2510f8ce ("mac80211: allow the driver to send EOSP when needed") Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2015-12-20 11:50:00 +00:00
if (driver_release_tids && reason == IEEE80211_FRAME_RELEASE_PSPOLL)
driver_release_tids =
BIT(find_highest_prio_tid(driver_release_tids));
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
if (skb_queue_empty(&frames) && !driver_release_tids) {
int tid, ac;
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
/*
* For PS-Poll, this can only happen due to a race condition
* when we set the TIM bit and the station notices it, but
* before it can poll for the frame we expire it.
*
* For uAPSD, this is said in the standard (11.2.1.5 h):
* At each unscheduled SP for a non-AP STA, the AP shall
* attempt to transmit at least one MSDU or MMPDU, but no
* more than the value specified in the Max SP Length field
* in the QoS Capability element from delivery-enabled ACs,
* that are destined for the non-AP STA.
*
* Since we have no other MSDU/MMPDU, transmit a QoS null frame.
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
*/
/* This will evaluate to 1, 3, 5 or 7. */
for (ac = IEEE80211_AC_VO; ac < IEEE80211_NUM_ACS; ac++)
if (!(ignored_acs & ieee80211_ac_to_qos_mask[ac]))
break;
tid = 7 - 2 * ac;
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
ieee80211_send_null_response(sta, tid, reason, true, false);
} else if (!driver_release_tids) {
struct sk_buff_head pending;
struct sk_buff *skb;
int num = 0;
u16 tids = 0;
bool need_null = false;
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
skb_queue_head_init(&pending);
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
while ((skb = __skb_dequeue(&frames))) {
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (void *) skb->data;
u8 *qoshdr = NULL;
num++;
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
/*
* Tell TX path to send this frame even though the
* STA may still remain is PS mode after this frame
* exchange.
*/
info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER;
info->control.flags |= IEEE80211_TX_CTRL_PS_RESPONSE;
/*
* Use MoreData flag to indicate whether there are
* more buffered frames for this STA
*/
if (more_data || !skb_queue_empty(&frames))
hdr->frame_control |=
cpu_to_le16(IEEE80211_FCTL_MOREDATA);
else
hdr->frame_control &=
cpu_to_le16(~IEEE80211_FCTL_MOREDATA);
if (ieee80211_is_data_qos(hdr->frame_control) ||
ieee80211_is_qos_nullfunc(hdr->frame_control))
qoshdr = ieee80211_get_qos_ctl(hdr);
tids |= BIT(skb->priority);
__skb_queue_tail(&pending, skb);
/* end service period after last frame or add one */
if (!skb_queue_empty(&frames))
continue;
if (reason != IEEE80211_FRAME_RELEASE_UAPSD) {
/* for PS-Poll, there's only one frame */
info->flags |= IEEE80211_TX_STATUS_EOSP |
IEEE80211_TX_CTL_REQ_TX_STATUS;
break;
}
/* For uAPSD, things are a bit more complicated. If the
* last frame has a QoS header (i.e. is a QoS-data or
* QoS-nulldata frame) then just set the EOSP bit there
* and be done.
* If the frame doesn't have a QoS header (which means
* it should be a bufferable MMPDU) then we can't set
* the EOSP bit in the QoS header; add a QoS-nulldata
* frame to the list to send it after the MMPDU.
*
* Note that this code is only in the mac80211-release
* code path, we assume that the driver will not buffer
* anything but QoS-data frames, or if it does, will
* create the QoS-nulldata frame by itself if needed.
*
* Cf. 802.11-2012 10.2.1.10 (c).
*/
if (qoshdr) {
*qoshdr |= IEEE80211_QOS_CTL_EOSP;
info->flags |= IEEE80211_TX_STATUS_EOSP |
IEEE80211_TX_CTL_REQ_TX_STATUS;
} else {
/* The standard isn't completely clear on this
* as it says the more-data bit should be set
* if there are more BUs. The QoS-Null frame
* we're about to send isn't buffered yet, we
* only create it below, but let's pretend it
* was buffered just in case some clients only
* expect more-data=0 when eosp=1.
*/
hdr->frame_control |=
cpu_to_le16(IEEE80211_FCTL_MOREDATA);
need_null = true;
num++;
}
break;
}
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
drv_allow_buffered_frames(local, sta, tids, num,
reason, more_data);
ieee80211_add_pending_skbs(local, &pending);
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
if (need_null)
ieee80211_send_null_response(
sta, find_highest_prio_tid(tids),
reason, false, false);
sta_info_recalc_tim(sta);
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
} else {
int tid;
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
/*
* We need to release a frame that is buffered somewhere in the
* driver ... it'll have to handle that.
* Note that the driver also has to check the number of frames
* on the TIDs we're releasing from - if there are more than
* n_frames it has to set the more-data bit (if we didn't ask
* it to set it anyway due to other buffered frames); if there
* are fewer than n_frames it has to make sure to adjust that
* to allow the service period to end properly.
*/
drv_release_buffered_frames(local, sta, driver_release_tids,
n_frames, reason, more_data);
/*
* Note that we don't recalculate the TIM bit here as it would
* most likely have no effect at all unless the driver told us
* that the TID(s) became empty before returning here from the
* release function.
* Either way, however, when the driver tells us that the TID(s)
* became empty or we find that a txq became empty, we'll do the
* TIM recalculation.
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
*/
for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) {
if (!sta->sta.txq[tid] ||
!(driver_release_tids & BIT(tid)) ||
txq_has_queue(sta->sta.txq[tid]))
continue;
sta_info_recalc_tim(sta);
break;
}
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
}
}
void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta)
{
u8 ignore_for_response = sta->sta.uapsd_queues;
/*
* If all ACs are delivery-enabled then we should reply
* from any of them, if only some are enabled we reply
* only from the non-enabled ones.
*/
if (ignore_for_response == BIT(IEEE80211_NUM_ACS) - 1)
ignore_for_response = 0;
ieee80211_sta_ps_deliver_response(sta, 1, ignore_for_response,
IEEE80211_FRAME_RELEASE_PSPOLL);
}
void ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta)
{
int n_frames = sta->sta.max_sp;
u8 delivery_enabled = sta->sta.uapsd_queues;
/*
* If we ever grow support for TSPEC this might happen if
* the TSPEC update from hostapd comes in between a trigger
* frame setting WLAN_STA_UAPSD in the RX path and this
* actually getting called.
*/
if (!delivery_enabled)
return;
switch (sta->sta.max_sp) {
case 1:
n_frames = 2;
break;
case 2:
n_frames = 4;
break;
case 3:
n_frames = 6;
break;
case 0:
/* XXX: what is a good value? */
n_frames = 128;
break;
}
ieee80211_sta_ps_deliver_response(sta, n_frames, ~delivery_enabled,
IEEE80211_FRAME_RELEASE_UAPSD);
}
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
struct ieee80211_sta *pubsta, bool block)
{
struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
trace_api_sta_block_awake(sta->local, pubsta, block);
if (block) {
set_sta_flag(sta, WLAN_STA_PS_DRIVER);
ieee80211_clear_fast_xmit(sta);
return;
}
if (!test_sta_flag(sta, WLAN_STA_PS_DRIVER))
return;
if (!test_sta_flag(sta, WLAN_STA_PS_STA)) {
set_sta_flag(sta, WLAN_STA_PS_DELIVER);
clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
ieee80211_queue_work(hw, &sta->drv_deliver_wk);
} else if (test_sta_flag(sta, WLAN_STA_PSPOLL) ||
test_sta_flag(sta, WLAN_STA_UAPSD)) {
/* must be asleep in this case */
clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
ieee80211_queue_work(hw, &sta->drv_deliver_wk);
} else {
clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
ieee80211_check_fast_xmit(sta);
}
mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-11-06 10:35:50 +00:00
}
EXPORT_SYMBOL(ieee80211_sta_block_awake);
void ieee80211_sta_eosp(struct ieee80211_sta *pubsta)
{
struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
struct ieee80211_local *local = sta->local;
trace_api_eosp(local, pubsta);
clear_sta_flag(sta, WLAN_STA_SP);
}
EXPORT_SYMBOL(ieee80211_sta_eosp);
void ieee80211_send_eosp_nullfunc(struct ieee80211_sta *pubsta, int tid)
{
struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
enum ieee80211_frame_release_type reason;
bool more_data;
trace_api_send_eosp_nullfunc(sta->local, pubsta, tid);
reason = IEEE80211_FRAME_RELEASE_UAPSD;
more_data = ieee80211_sta_ps_more_data(sta, ~sta->sta.uapsd_queues,
reason, 0);
ieee80211_send_null_response(sta, tid, reason, false, more_data);
}
EXPORT_SYMBOL(ieee80211_send_eosp_nullfunc);
void ieee80211_sta_set_buffered(struct ieee80211_sta *pubsta,
u8 tid, bool buffered)
{
struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
if (WARN_ON(tid >= IEEE80211_NUM_TIDS))
return;
trace_api_sta_set_buffered(sta->local, pubsta, tid, buffered);
if (buffered)
set_bit(tid, &sta->driver_buffered_tids);
else
clear_bit(tid, &sta->driver_buffered_tids);
sta_info_recalc_tim(sta);
}
EXPORT_SYMBOL(ieee80211_sta_set_buffered);
void ieee80211_sta_register_airtime(struct ieee80211_sta *pubsta, u8 tid,
u32 tx_airtime, u32 rx_airtime)
mac80211: Add airtime accounting and scheduling to TXQs This adds airtime accounting and scheduling to the mac80211 TXQ scheduler. A new callback, ieee80211_sta_register_airtime(), is added that drivers can call to report airtime usage for stations. When airtime information is present, mac80211 will schedule TXQs (through ieee80211_next_txq()) in a way that enforces airtime fairness between active stations. This scheduling works the same way as the ath9k in-driver airtime fairness scheduling. If no airtime usage is reported by the driver, the scheduler will default to round-robin scheduling. For drivers that don't control TXQ scheduling in software, a new API function, ieee80211_txq_may_transmit(), is added which the driver can use to check if the TXQ is eligible for transmission, or should be throttled to enforce fairness. Calls to this function must also be enclosed in ieee80211_txq_schedule_{start,end}() calls to ensure proper locking. The API ieee80211_txq_may_transmit() also ensures that TXQ list will be aligned aginst driver's own round-robin scheduler list. i.e it rotates the TXQ list till it makes the requested node becomes the first entry in TXQ list. Thus both the TXQ list and driver's list are in sync. Co-developed-by: Rajkumar Manoharan <rmanohar@codeaurora.org> Signed-off-by: Louie Lu <git@louie.lu> [added debugfs write op to reset airtime counter] Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk> Signed-off-by: Rajkumar Manoharan <rmanohar@codeaurora.org> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2018-12-19 01:02:08 +00:00
{
struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
struct ieee80211_local *local = sta->sdata->local;
u8 ac = ieee80211_ac_from_tid(tid);
mac80211: Add airtime accounting and scheduling to TXQs This adds airtime accounting and scheduling to the mac80211 TXQ scheduler. A new callback, ieee80211_sta_register_airtime(), is added that drivers can call to report airtime usage for stations. When airtime information is present, mac80211 will schedule TXQs (through ieee80211_next_txq()) in a way that enforces airtime fairness between active stations. This scheduling works the same way as the ath9k in-driver airtime fairness scheduling. If no airtime usage is reported by the driver, the scheduler will default to round-robin scheduling. For drivers that don't control TXQ scheduling in software, a new API function, ieee80211_txq_may_transmit(), is added which the driver can use to check if the TXQ is eligible for transmission, or should be throttled to enforce fairness. Calls to this function must also be enclosed in ieee80211_txq_schedule_{start,end}() calls to ensure proper locking. The API ieee80211_txq_may_transmit() also ensures that TXQ list will be aligned aginst driver's own round-robin scheduler list. i.e it rotates the TXQ list till it makes the requested node becomes the first entry in TXQ list. Thus both the TXQ list and driver's list are in sync. Co-developed-by: Rajkumar Manoharan <rmanohar@codeaurora.org> Signed-off-by: Louie Lu <git@louie.lu> [added debugfs write op to reset airtime counter] Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk> Signed-off-by: Rajkumar Manoharan <rmanohar@codeaurora.org> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2018-12-19 01:02:08 +00:00
u32 airtime = 0;
if (sta->local->airtime_flags & AIRTIME_USE_TX)
mac80211: Add airtime accounting and scheduling to TXQs This adds airtime accounting and scheduling to the mac80211 TXQ scheduler. A new callback, ieee80211_sta_register_airtime(), is added that drivers can call to report airtime usage for stations. When airtime information is present, mac80211 will schedule TXQs (through ieee80211_next_txq()) in a way that enforces airtime fairness between active stations. This scheduling works the same way as the ath9k in-driver airtime fairness scheduling. If no airtime usage is reported by the driver, the scheduler will default to round-robin scheduling. For drivers that don't control TXQ scheduling in software, a new API function, ieee80211_txq_may_transmit(), is added which the driver can use to check if the TXQ is eligible for transmission, or should be throttled to enforce fairness. Calls to this function must also be enclosed in ieee80211_txq_schedule_{start,end}() calls to ensure proper locking. The API ieee80211_txq_may_transmit() also ensures that TXQ list will be aligned aginst driver's own round-robin scheduler list. i.e it rotates the TXQ list till it makes the requested node becomes the first entry in TXQ list. Thus both the TXQ list and driver's list are in sync. Co-developed-by: Rajkumar Manoharan <rmanohar@codeaurora.org> Signed-off-by: Louie Lu <git@louie.lu> [added debugfs write op to reset airtime counter] Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk> Signed-off-by: Rajkumar Manoharan <rmanohar@codeaurora.org> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2018-12-19 01:02:08 +00:00
airtime += tx_airtime;
if (sta->local->airtime_flags & AIRTIME_USE_RX)
mac80211: Add airtime accounting and scheduling to TXQs This adds airtime accounting and scheduling to the mac80211 TXQ scheduler. A new callback, ieee80211_sta_register_airtime(), is added that drivers can call to report airtime usage for stations. When airtime information is present, mac80211 will schedule TXQs (through ieee80211_next_txq()) in a way that enforces airtime fairness between active stations. This scheduling works the same way as the ath9k in-driver airtime fairness scheduling. If no airtime usage is reported by the driver, the scheduler will default to round-robin scheduling. For drivers that don't control TXQ scheduling in software, a new API function, ieee80211_txq_may_transmit(), is added which the driver can use to check if the TXQ is eligible for transmission, or should be throttled to enforce fairness. Calls to this function must also be enclosed in ieee80211_txq_schedule_{start,end}() calls to ensure proper locking. The API ieee80211_txq_may_transmit() also ensures that TXQ list will be aligned aginst driver's own round-robin scheduler list. i.e it rotates the TXQ list till it makes the requested node becomes the first entry in TXQ list. Thus both the TXQ list and driver's list are in sync. Co-developed-by: Rajkumar Manoharan <rmanohar@codeaurora.org> Signed-off-by: Louie Lu <git@louie.lu> [added debugfs write op to reset airtime counter] Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk> Signed-off-by: Rajkumar Manoharan <rmanohar@codeaurora.org> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2018-12-19 01:02:08 +00:00
airtime += rx_airtime;
spin_lock_bh(&local->active_txq_lock[ac]);
sta->airtime[ac].tx_airtime += tx_airtime;
sta->airtime[ac].rx_airtime += rx_airtime;
if (ieee80211_sta_keep_active(sta, ac))
sta->airtime[ac].deficit -= airtime;
spin_unlock_bh(&local->active_txq_lock[ac]);
mac80211: Add airtime accounting and scheduling to TXQs This adds airtime accounting and scheduling to the mac80211 TXQ scheduler. A new callback, ieee80211_sta_register_airtime(), is added that drivers can call to report airtime usage for stations. When airtime information is present, mac80211 will schedule TXQs (through ieee80211_next_txq()) in a way that enforces airtime fairness between active stations. This scheduling works the same way as the ath9k in-driver airtime fairness scheduling. If no airtime usage is reported by the driver, the scheduler will default to round-robin scheduling. For drivers that don't control TXQ scheduling in software, a new API function, ieee80211_txq_may_transmit(), is added which the driver can use to check if the TXQ is eligible for transmission, or should be throttled to enforce fairness. Calls to this function must also be enclosed in ieee80211_txq_schedule_{start,end}() calls to ensure proper locking. The API ieee80211_txq_may_transmit() also ensures that TXQ list will be aligned aginst driver's own round-robin scheduler list. i.e it rotates the TXQ list till it makes the requested node becomes the first entry in TXQ list. Thus both the TXQ list and driver's list are in sync. Co-developed-by: Rajkumar Manoharan <rmanohar@codeaurora.org> Signed-off-by: Louie Lu <git@louie.lu> [added debugfs write op to reset airtime counter] Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk> Signed-off-by: Rajkumar Manoharan <rmanohar@codeaurora.org> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2018-12-19 01:02:08 +00:00
}
EXPORT_SYMBOL(ieee80211_sta_register_airtime);
void __ieee80211_sta_recalc_aggregates(struct sta_info *sta, u16 active_links)
{
bool first = true;
int link_id;
if (!sta->sta.valid_links || !sta->sta.mlo) {
sta->sta.cur = &sta->sta.deflink.agg;
return;
}
rcu_read_lock();
for (link_id = 0; link_id < ARRAY_SIZE((sta)->link); link_id++) {
struct ieee80211_link_sta *link_sta;
int i;
if (!(active_links & BIT(link_id)))
continue;
link_sta = rcu_dereference(sta->sta.link[link_id]);
if (!link_sta)
continue;
if (first) {
sta->cur = sta->sta.deflink.agg;
first = false;
continue;
}
sta->cur.max_amsdu_len =
min(sta->cur.max_amsdu_len,
link_sta->agg.max_amsdu_len);
sta->cur.max_rc_amsdu_len =
min(sta->cur.max_rc_amsdu_len,
link_sta->agg.max_rc_amsdu_len);
for (i = 0; i < ARRAY_SIZE(sta->cur.max_tid_amsdu_len); i++)
sta->cur.max_tid_amsdu_len[i] =
min(sta->cur.max_tid_amsdu_len[i],
link_sta->agg.max_tid_amsdu_len[i]);
}
rcu_read_unlock();
sta->sta.cur = &sta->cur;
}
void ieee80211_sta_recalc_aggregates(struct ieee80211_sta *pubsta)
{
struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
__ieee80211_sta_recalc_aggregates(sta, sta->sdata->vif.active_links);
}
EXPORT_SYMBOL(ieee80211_sta_recalc_aggregates);
mac80211: Implement Airtime-based Queue Limit (AQL) In order for the Fq_CoDel algorithm integrated in mac80211 layer to operate effectively to control excessive queueing latency, the CoDel algorithm requires an accurate measure of how long packets stays in the queue, AKA sojourn time. The sojourn time measured at the mac80211 layer doesn't include queueing latency in the lower layer (firmware/hardware) and CoDel expects lower layer to have a short queue. However, most 802.11ac chipsets offload tasks such TX aggregation to firmware or hardware, thus have a deep lower layer queue. Without a mechanism to control the lower layer queue size, packets only stay in mac80211 layer transiently before being sent to firmware queue. As a result, the sojourn time measured by CoDel in the mac80211 layer is almost always lower than the CoDel latency target, hence CoDel does little to control the latency, even when the lower layer queue causes excessive latency. The Byte Queue Limits (BQL) mechanism is commonly used to address the similar issue with wired network interface. However, this method cannot be applied directly to the wireless network interface. "Bytes" is not a suitable measure of queue depth in the wireless network, as the data rate can vary dramatically from station to station in the same network, from a few Mbps to over Gbps. This patch implements an Airtime-based Queue Limit (AQL) to make CoDel work effectively with wireless drivers that utilized firmware/hardware offloading. AQL allows each txq to release just enough packets to the lower layer to form 1-2 large aggregations to keep hardware fully utilized and retains the rest of the frames in mac80211 layer to be controlled by the CoDel algorithm. Signed-off-by: Kan Yan <kyan@google.com> [ Toke: Keep API to set pending airtime internal, fix nits in commit msg ] Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com> Link: https://lore.kernel.org/r/20191119060610.76681-4-kyan@google.com Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2019-11-19 06:06:09 +00:00
void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local,
struct sta_info *sta, u8 ac,
u16 tx_airtime, bool tx_completed)
{
int tx_pending;
if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL))
return;
mac80211: Implement Airtime-based Queue Limit (AQL) In order for the Fq_CoDel algorithm integrated in mac80211 layer to operate effectively to control excessive queueing latency, the CoDel algorithm requires an accurate measure of how long packets stays in the queue, AKA sojourn time. The sojourn time measured at the mac80211 layer doesn't include queueing latency in the lower layer (firmware/hardware) and CoDel expects lower layer to have a short queue. However, most 802.11ac chipsets offload tasks such TX aggregation to firmware or hardware, thus have a deep lower layer queue. Without a mechanism to control the lower layer queue size, packets only stay in mac80211 layer transiently before being sent to firmware queue. As a result, the sojourn time measured by CoDel in the mac80211 layer is almost always lower than the CoDel latency target, hence CoDel does little to control the latency, even when the lower layer queue causes excessive latency. The Byte Queue Limits (BQL) mechanism is commonly used to address the similar issue with wired network interface. However, this method cannot be applied directly to the wireless network interface. "Bytes" is not a suitable measure of queue depth in the wireless network, as the data rate can vary dramatically from station to station in the same network, from a few Mbps to over Gbps. This patch implements an Airtime-based Queue Limit (AQL) to make CoDel work effectively with wireless drivers that utilized firmware/hardware offloading. AQL allows each txq to release just enough packets to the lower layer to form 1-2 large aggregations to keep hardware fully utilized and retains the rest of the frames in mac80211 layer to be controlled by the CoDel algorithm. Signed-off-by: Kan Yan <kyan@google.com> [ Toke: Keep API to set pending airtime internal, fix nits in commit msg ] Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com> Link: https://lore.kernel.org/r/20191119060610.76681-4-kyan@google.com Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2019-11-19 06:06:09 +00:00
if (!tx_completed) {
if (sta)
atomic_add(tx_airtime,
&sta->airtime[ac].aql_tx_pending);
atomic_add(tx_airtime, &local->aql_total_pending_airtime);
atomic_add(tx_airtime, &local->aql_ac_pending_airtime[ac]);
mac80211: Implement Airtime-based Queue Limit (AQL) In order for the Fq_CoDel algorithm integrated in mac80211 layer to operate effectively to control excessive queueing latency, the CoDel algorithm requires an accurate measure of how long packets stays in the queue, AKA sojourn time. The sojourn time measured at the mac80211 layer doesn't include queueing latency in the lower layer (firmware/hardware) and CoDel expects lower layer to have a short queue. However, most 802.11ac chipsets offload tasks such TX aggregation to firmware or hardware, thus have a deep lower layer queue. Without a mechanism to control the lower layer queue size, packets only stay in mac80211 layer transiently before being sent to firmware queue. As a result, the sojourn time measured by CoDel in the mac80211 layer is almost always lower than the CoDel latency target, hence CoDel does little to control the latency, even when the lower layer queue causes excessive latency. The Byte Queue Limits (BQL) mechanism is commonly used to address the similar issue with wired network interface. However, this method cannot be applied directly to the wireless network interface. "Bytes" is not a suitable measure of queue depth in the wireless network, as the data rate can vary dramatically from station to station in the same network, from a few Mbps to over Gbps. This patch implements an Airtime-based Queue Limit (AQL) to make CoDel work effectively with wireless drivers that utilized firmware/hardware offloading. AQL allows each txq to release just enough packets to the lower layer to form 1-2 large aggregations to keep hardware fully utilized and retains the rest of the frames in mac80211 layer to be controlled by the CoDel algorithm. Signed-off-by: Kan Yan <kyan@google.com> [ Toke: Keep API to set pending airtime internal, fix nits in commit msg ] Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com> Link: https://lore.kernel.org/r/20191119060610.76681-4-kyan@google.com Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2019-11-19 06:06:09 +00:00
return;
}
if (sta) {
tx_pending = atomic_sub_return(tx_airtime,
&sta->airtime[ac].aql_tx_pending);
if (tx_pending < 0)
mac80211: Implement Airtime-based Queue Limit (AQL) In order for the Fq_CoDel algorithm integrated in mac80211 layer to operate effectively to control excessive queueing latency, the CoDel algorithm requires an accurate measure of how long packets stays in the queue, AKA sojourn time. The sojourn time measured at the mac80211 layer doesn't include queueing latency in the lower layer (firmware/hardware) and CoDel expects lower layer to have a short queue. However, most 802.11ac chipsets offload tasks such TX aggregation to firmware or hardware, thus have a deep lower layer queue. Without a mechanism to control the lower layer queue size, packets only stay in mac80211 layer transiently before being sent to firmware queue. As a result, the sojourn time measured by CoDel in the mac80211 layer is almost always lower than the CoDel latency target, hence CoDel does little to control the latency, even when the lower layer queue causes excessive latency. The Byte Queue Limits (BQL) mechanism is commonly used to address the similar issue with wired network interface. However, this method cannot be applied directly to the wireless network interface. "Bytes" is not a suitable measure of queue depth in the wireless network, as the data rate can vary dramatically from station to station in the same network, from a few Mbps to over Gbps. This patch implements an Airtime-based Queue Limit (AQL) to make CoDel work effectively with wireless drivers that utilized firmware/hardware offloading. AQL allows each txq to release just enough packets to the lower layer to form 1-2 large aggregations to keep hardware fully utilized and retains the rest of the frames in mac80211 layer to be controlled by the CoDel algorithm. Signed-off-by: Kan Yan <kyan@google.com> [ Toke: Keep API to set pending airtime internal, fix nits in commit msg ] Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com> Link: https://lore.kernel.org/r/20191119060610.76681-4-kyan@google.com Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2019-11-19 06:06:09 +00:00
atomic_cmpxchg(&sta->airtime[ac].aql_tx_pending,
tx_pending, 0);
}
atomic_sub(tx_airtime, &local->aql_total_pending_airtime);
mac80211: Implement Airtime-based Queue Limit (AQL) In order for the Fq_CoDel algorithm integrated in mac80211 layer to operate effectively to control excessive queueing latency, the CoDel algorithm requires an accurate measure of how long packets stays in the queue, AKA sojourn time. The sojourn time measured at the mac80211 layer doesn't include queueing latency in the lower layer (firmware/hardware) and CoDel expects lower layer to have a short queue. However, most 802.11ac chipsets offload tasks such TX aggregation to firmware or hardware, thus have a deep lower layer queue. Without a mechanism to control the lower layer queue size, packets only stay in mac80211 layer transiently before being sent to firmware queue. As a result, the sojourn time measured by CoDel in the mac80211 layer is almost always lower than the CoDel latency target, hence CoDel does little to control the latency, even when the lower layer queue causes excessive latency. The Byte Queue Limits (BQL) mechanism is commonly used to address the similar issue with wired network interface. However, this method cannot be applied directly to the wireless network interface. "Bytes" is not a suitable measure of queue depth in the wireless network, as the data rate can vary dramatically from station to station in the same network, from a few Mbps to over Gbps. This patch implements an Airtime-based Queue Limit (AQL) to make CoDel work effectively with wireless drivers that utilized firmware/hardware offloading. AQL allows each txq to release just enough packets to the lower layer to form 1-2 large aggregations to keep hardware fully utilized and retains the rest of the frames in mac80211 layer to be controlled by the CoDel algorithm. Signed-off-by: Kan Yan <kyan@google.com> [ Toke: Keep API to set pending airtime internal, fix nits in commit msg ] Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com> Link: https://lore.kernel.org/r/20191119060610.76681-4-kyan@google.com Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2019-11-19 06:06:09 +00:00
tx_pending = atomic_sub_return(tx_airtime,
&local->aql_ac_pending_airtime[ac]);
mac80211: Implement Airtime-based Queue Limit (AQL) In order for the Fq_CoDel algorithm integrated in mac80211 layer to operate effectively to control excessive queueing latency, the CoDel algorithm requires an accurate measure of how long packets stays in the queue, AKA sojourn time. The sojourn time measured at the mac80211 layer doesn't include queueing latency in the lower layer (firmware/hardware) and CoDel expects lower layer to have a short queue. However, most 802.11ac chipsets offload tasks such TX aggregation to firmware or hardware, thus have a deep lower layer queue. Without a mechanism to control the lower layer queue size, packets only stay in mac80211 layer transiently before being sent to firmware queue. As a result, the sojourn time measured by CoDel in the mac80211 layer is almost always lower than the CoDel latency target, hence CoDel does little to control the latency, even when the lower layer queue causes excessive latency. The Byte Queue Limits (BQL) mechanism is commonly used to address the similar issue with wired network interface. However, this method cannot be applied directly to the wireless network interface. "Bytes" is not a suitable measure of queue depth in the wireless network, as the data rate can vary dramatically from station to station in the same network, from a few Mbps to over Gbps. This patch implements an Airtime-based Queue Limit (AQL) to make CoDel work effectively with wireless drivers that utilized firmware/hardware offloading. AQL allows each txq to release just enough packets to the lower layer to form 1-2 large aggregations to keep hardware fully utilized and retains the rest of the frames in mac80211 layer to be controlled by the CoDel algorithm. Signed-off-by: Kan Yan <kyan@google.com> [ Toke: Keep API to set pending airtime internal, fix nits in commit msg ] Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com> Link: https://lore.kernel.org/r/20191119060610.76681-4-kyan@google.com Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2019-11-19 06:06:09 +00:00
if (WARN_ONCE(tx_pending < 0,
"Device %s AC %d pending airtime underflow: %u, %u",
wiphy_name(local->hw.wiphy), ac, tx_pending,
tx_airtime)) {
atomic_cmpxchg(&local->aql_ac_pending_airtime[ac],
mac80211: Implement Airtime-based Queue Limit (AQL) In order for the Fq_CoDel algorithm integrated in mac80211 layer to operate effectively to control excessive queueing latency, the CoDel algorithm requires an accurate measure of how long packets stays in the queue, AKA sojourn time. The sojourn time measured at the mac80211 layer doesn't include queueing latency in the lower layer (firmware/hardware) and CoDel expects lower layer to have a short queue. However, most 802.11ac chipsets offload tasks such TX aggregation to firmware or hardware, thus have a deep lower layer queue. Without a mechanism to control the lower layer queue size, packets only stay in mac80211 layer transiently before being sent to firmware queue. As a result, the sojourn time measured by CoDel in the mac80211 layer is almost always lower than the CoDel latency target, hence CoDel does little to control the latency, even when the lower layer queue causes excessive latency. The Byte Queue Limits (BQL) mechanism is commonly used to address the similar issue with wired network interface. However, this method cannot be applied directly to the wireless network interface. "Bytes" is not a suitable measure of queue depth in the wireless network, as the data rate can vary dramatically from station to station in the same network, from a few Mbps to over Gbps. This patch implements an Airtime-based Queue Limit (AQL) to make CoDel work effectively with wireless drivers that utilized firmware/hardware offloading. AQL allows each txq to release just enough packets to the lower layer to form 1-2 large aggregations to keep hardware fully utilized and retains the rest of the frames in mac80211 layer to be controlled by the CoDel algorithm. Signed-off-by: Kan Yan <kyan@google.com> [ Toke: Keep API to set pending airtime internal, fix nits in commit msg ] Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com> Link: https://lore.kernel.org/r/20191119060610.76681-4-kyan@google.com Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2019-11-19 06:06:09 +00:00
tx_pending, 0);
atomic_sub(tx_pending, &local->aql_total_pending_airtime);
}
mac80211: Implement Airtime-based Queue Limit (AQL) In order for the Fq_CoDel algorithm integrated in mac80211 layer to operate effectively to control excessive queueing latency, the CoDel algorithm requires an accurate measure of how long packets stays in the queue, AKA sojourn time. The sojourn time measured at the mac80211 layer doesn't include queueing latency in the lower layer (firmware/hardware) and CoDel expects lower layer to have a short queue. However, most 802.11ac chipsets offload tasks such TX aggregation to firmware or hardware, thus have a deep lower layer queue. Without a mechanism to control the lower layer queue size, packets only stay in mac80211 layer transiently before being sent to firmware queue. As a result, the sojourn time measured by CoDel in the mac80211 layer is almost always lower than the CoDel latency target, hence CoDel does little to control the latency, even when the lower layer queue causes excessive latency. The Byte Queue Limits (BQL) mechanism is commonly used to address the similar issue with wired network interface. However, this method cannot be applied directly to the wireless network interface. "Bytes" is not a suitable measure of queue depth in the wireless network, as the data rate can vary dramatically from station to station in the same network, from a few Mbps to over Gbps. This patch implements an Airtime-based Queue Limit (AQL) to make CoDel work effectively with wireless drivers that utilized firmware/hardware offloading. AQL allows each txq to release just enough packets to the lower layer to form 1-2 large aggregations to keep hardware fully utilized and retains the rest of the frames in mac80211 layer to be controlled by the CoDel algorithm. Signed-off-by: Kan Yan <kyan@google.com> [ Toke: Keep API to set pending airtime internal, fix nits in commit msg ] Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com> Link: https://lore.kernel.org/r/20191119060610.76681-4-kyan@google.com Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2019-11-19 06:06:09 +00:00
}
static struct ieee80211_sta_rx_stats *
sta_get_last_rx_stats(struct sta_info *sta)
{
mac80211: prepare sta handling for MLO support Currently in mac80211 each STA object is represented using sta_info datastructure with the associated STA specific information and drivers access ieee80211_sta part of it. With MLO (Multi Link Operation) support being added in 802.11be standard, though the association is logically with a single Multi Link capable STA, at the physical level communication can happen via different advertised links (uniquely identified by Channel, operating class, BSSID) and hence the need to handle multiple link STA parameters within a composite sta_info object called the MLD STA. The different link STA part of MLD STA are identified using the link address which can be same or different as the MLD STA address and unique link id based on the link vif. To support extension of such a model, the sta_info datastructure is modified to hold multiple link STA objects with link specific params currently within sta_info moved to this new structure. Similarly this is done for ieee80211_sta as well which will be accessed within mac80211 as well as by drivers, hence trivial driver changes are expected to support this. For current non MLO supported drivers, only one link STA is present and link information is accessed via 'deflink' member. For MLO drivers, we still need to define the APIs etc. to get the correct link ID and access the correct part of the station info. Currently in mac80211, all link STA info are accessed directly via deflink. These will be updated to access via link pointers indexed by link id with MLO support patches, with link id being 0 for non MLO supported cases. Except for couple of macro related changes, below spatch takes care of updating mac80211 and driver code to access to the link STA info via deflink. @ieee80211_sta@ struct ieee80211_sta *s; struct sta_info *si; identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr}; @@ ( s-> - var + deflink.var | si->sta. - var + deflink.var ) @sta_info@ struct sta_info *si; identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth}; @@ ( si-> - var + deflink.var ) Signed-off-by: Sriram R <quic_srirrama@quicinc.com> Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com [remove MLO-drivers notes from commit message, not clear yet; run spatch] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 15:41:23 +00:00
struct ieee80211_sta_rx_stats *stats = &sta->deflink.rx_stats;
int cpu;
mac80211: prepare sta handling for MLO support Currently in mac80211 each STA object is represented using sta_info datastructure with the associated STA specific information and drivers access ieee80211_sta part of it. With MLO (Multi Link Operation) support being added in 802.11be standard, though the association is logically with a single Multi Link capable STA, at the physical level communication can happen via different advertised links (uniquely identified by Channel, operating class, BSSID) and hence the need to handle multiple link STA parameters within a composite sta_info object called the MLD STA. The different link STA part of MLD STA are identified using the link address which can be same or different as the MLD STA address and unique link id based on the link vif. To support extension of such a model, the sta_info datastructure is modified to hold multiple link STA objects with link specific params currently within sta_info moved to this new structure. Similarly this is done for ieee80211_sta as well which will be accessed within mac80211 as well as by drivers, hence trivial driver changes are expected to support this. For current non MLO supported drivers, only one link STA is present and link information is accessed via 'deflink' member. For MLO drivers, we still need to define the APIs etc. to get the correct link ID and access the correct part of the station info. Currently in mac80211, all link STA info are accessed directly via deflink. These will be updated to access via link pointers indexed by link id with MLO support patches, with link id being 0 for non MLO supported cases. Except for couple of macro related changes, below spatch takes care of updating mac80211 and driver code to access to the link STA info via deflink. @ieee80211_sta@ struct ieee80211_sta *s; struct sta_info *si; identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr}; @@ ( s-> - var + deflink.var | si->sta. - var + deflink.var ) @sta_info@ struct sta_info *si; identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth}; @@ ( si-> - var + deflink.var ) Signed-off-by: Sriram R <quic_srirrama@quicinc.com> Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com [remove MLO-drivers notes from commit message, not clear yet; run spatch] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 15:41:23 +00:00
if (!sta->deflink.pcpu_rx_stats)
return stats;
for_each_possible_cpu(cpu) {
struct ieee80211_sta_rx_stats *cpustats;
mac80211: prepare sta handling for MLO support Currently in mac80211 each STA object is represented using sta_info datastructure with the associated STA specific information and drivers access ieee80211_sta part of it. With MLO (Multi Link Operation) support being added in 802.11be standard, though the association is logically with a single Multi Link capable STA, at the physical level communication can happen via different advertised links (uniquely identified by Channel, operating class, BSSID) and hence the need to handle multiple link STA parameters within a composite sta_info object called the MLD STA. The different link STA part of MLD STA are identified using the link address which can be same or different as the MLD STA address and unique link id based on the link vif. To support extension of such a model, the sta_info datastructure is modified to hold multiple link STA objects with link specific params currently within sta_info moved to this new structure. Similarly this is done for ieee80211_sta as well which will be accessed within mac80211 as well as by drivers, hence trivial driver changes are expected to support this. For current non MLO supported drivers, only one link STA is present and link information is accessed via 'deflink' member. For MLO drivers, we still need to define the APIs etc. to get the correct link ID and access the correct part of the station info. Currently in mac80211, all link STA info are accessed directly via deflink. These will be updated to access via link pointers indexed by link id with MLO support patches, with link id being 0 for non MLO supported cases. Except for couple of macro related changes, below spatch takes care of updating mac80211 and driver code to access to the link STA info via deflink. @ieee80211_sta@ struct ieee80211_sta *s; struct sta_info *si; identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr}; @@ ( s-> - var + deflink.var | si->sta. - var + deflink.var ) @sta_info@ struct sta_info *si; identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth}; @@ ( si-> - var + deflink.var ) Signed-off-by: Sriram R <quic_srirrama@quicinc.com> Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com [remove MLO-drivers notes from commit message, not clear yet; run spatch] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 15:41:23 +00:00
cpustats = per_cpu_ptr(sta->deflink.pcpu_rx_stats, cpu);
if (time_after(cpustats->last_rx, stats->last_rx))
stats = cpustats;
}
return stats;
}
static void sta_stats_decode_rate(struct ieee80211_local *local, u32 rate,
struct rate_info *rinfo)
{
rinfo->bw = STA_STATS_GET(BW, rate);
switch (STA_STATS_GET(TYPE, rate)) {
case STA_STATS_RATE_TYPE_VHT:
rinfo->flags = RATE_INFO_FLAGS_VHT_MCS;
rinfo->mcs = STA_STATS_GET(VHT_MCS, rate);
rinfo->nss = STA_STATS_GET(VHT_NSS, rate);
if (STA_STATS_GET(SGI, rate))
rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI;
break;
case STA_STATS_RATE_TYPE_HT:
rinfo->flags = RATE_INFO_FLAGS_MCS;
rinfo->mcs = STA_STATS_GET(HT_MCS, rate);
if (STA_STATS_GET(SGI, rate))
rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI;
break;
case STA_STATS_RATE_TYPE_LEGACY: {
struct ieee80211_supported_band *sband;
u16 brate;
unsigned int shift;
int band = STA_STATS_GET(LEGACY_BAND, rate);
int rate_idx = STA_STATS_GET(LEGACY_IDX, rate);
sband = local->hw.wiphy->bands[band];
if (WARN_ON_ONCE(!sband->bitrates))
break;
brate = sband->bitrates[rate_idx].bitrate;
if (rinfo->bw == RATE_INFO_BW_5)
shift = 2;
else if (rinfo->bw == RATE_INFO_BW_10)
shift = 1;
else
shift = 0;
rinfo->legacy = DIV_ROUND_UP(brate, 1 << shift);
break;
}
case STA_STATS_RATE_TYPE_HE:
rinfo->flags = RATE_INFO_FLAGS_HE_MCS;
rinfo->mcs = STA_STATS_GET(HE_MCS, rate);
rinfo->nss = STA_STATS_GET(HE_NSS, rate);
rinfo->he_gi = STA_STATS_GET(HE_GI, rate);
rinfo->he_ru_alloc = STA_STATS_GET(HE_RU, rate);
rinfo->he_dcm = STA_STATS_GET(HE_DCM, rate);
break;
case STA_STATS_RATE_TYPE_EHT:
rinfo->flags = RATE_INFO_FLAGS_EHT_MCS;
rinfo->mcs = STA_STATS_GET(EHT_MCS, rate);
rinfo->nss = STA_STATS_GET(EHT_NSS, rate);
rinfo->eht_gi = STA_STATS_GET(EHT_GI, rate);
rinfo->eht_ru_alloc = STA_STATS_GET(EHT_RU, rate);
break;
}
}
static int sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo)
{
u32 rate = READ_ONCE(sta_get_last_rx_stats(sta)->last_rate);
if (rate == STA_STATS_RATE_INVALID)
return -EINVAL;
sta_stats_decode_rate(sta->local, rate, rinfo);
return 0;
}
static inline u64 sta_get_tidstats_msdu(struct ieee80211_sta_rx_stats *rxstats,
int tid)
{
unsigned int start;
u64 value;
do {
start = u64_stats_fetch_begin(&rxstats->syncp);
value = rxstats->msdu[tid];
} while (u64_stats_fetch_retry(&rxstats->syncp, start));
return value;
}
static void sta_set_tidstats(struct sta_info *sta,
struct cfg80211_tid_stats *tidstats,
int tid)
{
struct ieee80211_local *local = sta->local;
int cpu;
if (!(tidstats->filled & BIT(NL80211_TID_STATS_RX_MSDU))) {
mac80211: prepare sta handling for MLO support Currently in mac80211 each STA object is represented using sta_info datastructure with the associated STA specific information and drivers access ieee80211_sta part of it. With MLO (Multi Link Operation) support being added in 802.11be standard, though the association is logically with a single Multi Link capable STA, at the physical level communication can happen via different advertised links (uniquely identified by Channel, operating class, BSSID) and hence the need to handle multiple link STA parameters within a composite sta_info object called the MLD STA. The different link STA part of MLD STA are identified using the link address which can be same or different as the MLD STA address and unique link id based on the link vif. To support extension of such a model, the sta_info datastructure is modified to hold multiple link STA objects with link specific params currently within sta_info moved to this new structure. Similarly this is done for ieee80211_sta as well which will be accessed within mac80211 as well as by drivers, hence trivial driver changes are expected to support this. For current non MLO supported drivers, only one link STA is present and link information is accessed via 'deflink' member. For MLO drivers, we still need to define the APIs etc. to get the correct link ID and access the correct part of the station info. Currently in mac80211, all link STA info are accessed directly via deflink. These will be updated to access via link pointers indexed by link id with MLO support patches, with link id being 0 for non MLO supported cases. Except for couple of macro related changes, below spatch takes care of updating mac80211 and driver code to access to the link STA info via deflink. @ieee80211_sta@ struct ieee80211_sta *s; struct sta_info *si; identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr}; @@ ( s-> - var + deflink.var | si->sta. - var + deflink.var ) @sta_info@ struct sta_info *si; identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth}; @@ ( si-> - var + deflink.var ) Signed-off-by: Sriram R <quic_srirrama@quicinc.com> Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com [remove MLO-drivers notes from commit message, not clear yet; run spatch] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 15:41:23 +00:00
tidstats->rx_msdu += sta_get_tidstats_msdu(&sta->deflink.rx_stats,
tid);
mac80211: prepare sta handling for MLO support Currently in mac80211 each STA object is represented using sta_info datastructure with the associated STA specific information and drivers access ieee80211_sta part of it. With MLO (Multi Link Operation) support being added in 802.11be standard, though the association is logically with a single Multi Link capable STA, at the physical level communication can happen via different advertised links (uniquely identified by Channel, operating class, BSSID) and hence the need to handle multiple link STA parameters within a composite sta_info object called the MLD STA. The different link STA part of MLD STA are identified using the link address which can be same or different as the MLD STA address and unique link id based on the link vif. To support extension of such a model, the sta_info datastructure is modified to hold multiple link STA objects with link specific params currently within sta_info moved to this new structure. Similarly this is done for ieee80211_sta as well which will be accessed within mac80211 as well as by drivers, hence trivial driver changes are expected to support this. For current non MLO supported drivers, only one link STA is present and link information is accessed via 'deflink' member. For MLO drivers, we still need to define the APIs etc. to get the correct link ID and access the correct part of the station info. Currently in mac80211, all link STA info are accessed directly via deflink. These will be updated to access via link pointers indexed by link id with MLO support patches, with link id being 0 for non MLO supported cases. Except for couple of macro related changes, below spatch takes care of updating mac80211 and driver code to access to the link STA info via deflink. @ieee80211_sta@ struct ieee80211_sta *s; struct sta_info *si; identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr}; @@ ( s-> - var + deflink.var | si->sta. - var + deflink.var ) @sta_info@ struct sta_info *si; identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth}; @@ ( si-> - var + deflink.var ) Signed-off-by: Sriram R <quic_srirrama@quicinc.com> Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com [remove MLO-drivers notes from commit message, not clear yet; run spatch] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 15:41:23 +00:00
if (sta->deflink.pcpu_rx_stats) {
for_each_possible_cpu(cpu) {
struct ieee80211_sta_rx_stats *cpurxs;
mac80211: prepare sta handling for MLO support Currently in mac80211 each STA object is represented using sta_info datastructure with the associated STA specific information and drivers access ieee80211_sta part of it. With MLO (Multi Link Operation) support being added in 802.11be standard, though the association is logically with a single Multi Link capable STA, at the physical level communication can happen via different advertised links (uniquely identified by Channel, operating class, BSSID) and hence the need to handle multiple link STA parameters within a composite sta_info object called the MLD STA. The different link STA part of MLD STA are identified using the link address which can be same or different as the MLD STA address and unique link id based on the link vif. To support extension of such a model, the sta_info datastructure is modified to hold multiple link STA objects with link specific params currently within sta_info moved to this new structure. Similarly this is done for ieee80211_sta as well which will be accessed within mac80211 as well as by drivers, hence trivial driver changes are expected to support this. For current non MLO supported drivers, only one link STA is present and link information is accessed via 'deflink' member. For MLO drivers, we still need to define the APIs etc. to get the correct link ID and access the correct part of the station info. Currently in mac80211, all link STA info are accessed directly via deflink. These will be updated to access via link pointers indexed by link id with MLO support patches, with link id being 0 for non MLO supported cases. Except for couple of macro related changes, below spatch takes care of updating mac80211 and driver code to access to the link STA info via deflink. @ieee80211_sta@ struct ieee80211_sta *s; struct sta_info *si; identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr}; @@ ( s-> - var + deflink.var | si->sta. - var + deflink.var ) @sta_info@ struct sta_info *si; identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth}; @@ ( si-> - var + deflink.var ) Signed-off-by: Sriram R <quic_srirrama@quicinc.com> Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com [remove MLO-drivers notes from commit message, not clear yet; run spatch] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 15:41:23 +00:00
cpurxs = per_cpu_ptr(sta->deflink.pcpu_rx_stats,
cpu);
tidstats->rx_msdu +=
sta_get_tidstats_msdu(cpurxs, tid);
}
}
tidstats->filled |= BIT(NL80211_TID_STATS_RX_MSDU);
}
if (!(tidstats->filled & BIT(NL80211_TID_STATS_TX_MSDU))) {
tidstats->filled |= BIT(NL80211_TID_STATS_TX_MSDU);
mac80211: prepare sta handling for MLO support Currently in mac80211 each STA object is represented using sta_info datastructure with the associated STA specific information and drivers access ieee80211_sta part of it. With MLO (Multi Link Operation) support being added in 802.11be standard, though the association is logically with a single Multi Link capable STA, at the physical level communication can happen via different advertised links (uniquely identified by Channel, operating class, BSSID) and hence the need to handle multiple link STA parameters within a composite sta_info object called the MLD STA. The different link STA part of MLD STA are identified using the link address which can be same or different as the MLD STA address and unique link id based on the link vif. To support extension of such a model, the sta_info datastructure is modified to hold multiple link STA objects with link specific params currently within sta_info moved to this new structure. Similarly this is done for ieee80211_sta as well which will be accessed within mac80211 as well as by drivers, hence trivial driver changes are expected to support this. For current non MLO supported drivers, only one link STA is present and link information is accessed via 'deflink' member. For MLO drivers, we still need to define the APIs etc. to get the correct link ID and access the correct part of the station info. Currently in mac80211, all link STA info are accessed directly via deflink. These will be updated to access via link pointers indexed by link id with MLO support patches, with link id being 0 for non MLO supported cases. Except for couple of macro related changes, below spatch takes care of updating mac80211 and driver code to access to the link STA info via deflink. @ieee80211_sta@ struct ieee80211_sta *s; struct sta_info *si; identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr}; @@ ( s-> - var + deflink.var | si->sta. - var + deflink.var ) @sta_info@ struct sta_info *si; identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth}; @@ ( si-> - var + deflink.var ) Signed-off-by: Sriram R <quic_srirrama@quicinc.com> Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com [remove MLO-drivers notes from commit message, not clear yet; run spatch] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 15:41:23 +00:00
tidstats->tx_msdu = sta->deflink.tx_stats.msdu[tid];
}
if (!(tidstats->filled & BIT(NL80211_TID_STATS_TX_MSDU_RETRIES)) &&
ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
tidstats->filled |= BIT(NL80211_TID_STATS_TX_MSDU_RETRIES);
mac80211: prepare sta handling for MLO support Currently in mac80211 each STA object is represented using sta_info datastructure with the associated STA specific information and drivers access ieee80211_sta part of it. With MLO (Multi Link Operation) support being added in 802.11be standard, though the association is logically with a single Multi Link capable STA, at the physical level communication can happen via different advertised links (uniquely identified by Channel, operating class, BSSID) and hence the need to handle multiple link STA parameters within a composite sta_info object called the MLD STA. The different link STA part of MLD STA are identified using the link address which can be same or different as the MLD STA address and unique link id based on the link vif. To support extension of such a model, the sta_info datastructure is modified to hold multiple link STA objects with link specific params currently within sta_info moved to this new structure. Similarly this is done for ieee80211_sta as well which will be accessed within mac80211 as well as by drivers, hence trivial driver changes are expected to support this. For current non MLO supported drivers, only one link STA is present and link information is accessed via 'deflink' member. For MLO drivers, we still need to define the APIs etc. to get the correct link ID and access the correct part of the station info. Currently in mac80211, all link STA info are accessed directly via deflink. These will be updated to access via link pointers indexed by link id with MLO support patches, with link id being 0 for non MLO supported cases. Except for couple of macro related changes, below spatch takes care of updating mac80211 and driver code to access to the link STA info via deflink. @ieee80211_sta@ struct ieee80211_sta *s; struct sta_info *si; identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr}; @@ ( s-> - var + deflink.var | si->sta. - var + deflink.var ) @sta_info@ struct sta_info *si; identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth}; @@ ( si-> - var + deflink.var ) Signed-off-by: Sriram R <quic_srirrama@quicinc.com> Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com [remove MLO-drivers notes from commit message, not clear yet; run spatch] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 15:41:23 +00:00
tidstats->tx_msdu_retries = sta->deflink.status_stats.msdu_retries[tid];
}
if (!(tidstats->filled & BIT(NL80211_TID_STATS_TX_MSDU_FAILED)) &&
ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
tidstats->filled |= BIT(NL80211_TID_STATS_TX_MSDU_FAILED);
mac80211: prepare sta handling for MLO support Currently in mac80211 each STA object is represented using sta_info datastructure with the associated STA specific information and drivers access ieee80211_sta part of it. With MLO (Multi Link Operation) support being added in 802.11be standard, though the association is logically with a single Multi Link capable STA, at the physical level communication can happen via different advertised links (uniquely identified by Channel, operating class, BSSID) and hence the need to handle multiple link STA parameters within a composite sta_info object called the MLD STA. The different link STA part of MLD STA are identified using the link address which can be same or different as the MLD STA address and unique link id based on the link vif. To support extension of such a model, the sta_info datastructure is modified to hold multiple link STA objects with link specific params currently within sta_info moved to this new structure. Similarly this is done for ieee80211_sta as well which will be accessed within mac80211 as well as by drivers, hence trivial driver changes are expected to support this. For current non MLO supported drivers, only one link STA is present and link information is accessed via 'deflink' member. For MLO drivers, we still need to define the APIs etc. to get the correct link ID and access the correct part of the station info. Currently in mac80211, all link STA info are accessed directly via deflink. These will be updated to access via link pointers indexed by link id with MLO support patches, with link id being 0 for non MLO supported cases. Except for couple of macro related changes, below spatch takes care of updating mac80211 and driver code to access to the link STA info via deflink. @ieee80211_sta@ struct ieee80211_sta *s; struct sta_info *si; identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr}; @@ ( s-> - var + deflink.var | si->sta. - var + deflink.var ) @sta_info@ struct sta_info *si; identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth}; @@ ( si-> - var + deflink.var ) Signed-off-by: Sriram R <quic_srirrama@quicinc.com> Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com [remove MLO-drivers notes from commit message, not clear yet; run spatch] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 15:41:23 +00:00
tidstats->tx_msdu_failed = sta->deflink.status_stats.msdu_failed[tid];
}
if (tid < IEEE80211_NUM_TIDS) {
spin_lock_bh(&local->fq.lock);
rcu_read_lock();
tidstats->filled |= BIT(NL80211_TID_STATS_TXQ_STATS);
ieee80211_fill_txq_stats(&tidstats->txq_stats,
to_txq_info(sta->sta.txq[tid]));
rcu_read_unlock();
spin_unlock_bh(&local->fq.lock);
}
}
static inline u64 sta_get_stats_bytes(struct ieee80211_sta_rx_stats *rxstats)
{
unsigned int start;
u64 value;
do {
start = u64_stats_fetch_begin(&rxstats->syncp);
value = rxstats->bytes;
} while (u64_stats_fetch_retry(&rxstats->syncp, start));
return value;
}
void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
bool tidstats)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
u32 thr = 0;
int i, ac, cpu;
struct ieee80211_sta_rx_stats *last_rxstats;
last_rxstats = sta_get_last_rx_stats(sta);
sinfo->generation = sdata->local->sta_generation;
/* do before driver, so beacon filtering drivers have a
* chance to e.g. just add the number of filtered beacons
* (or just modify the value entirely, of course)
*/
if (sdata->vif.type == NL80211_IFTYPE_STATION)
sinfo->rx_beacon = sdata->deflink.u.mgd.count_beacon_signal;
drv_sta_statistics(local, sdata, &sta->sta, sinfo);
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_INACTIVE_TIME) |
BIT_ULL(NL80211_STA_INFO_STA_FLAGS) |
BIT_ULL(NL80211_STA_INFO_BSS_PARAM) |
BIT_ULL(NL80211_STA_INFO_CONNECTED_TIME) |
BIT_ULL(NL80211_STA_INFO_ASSOC_AT_BOOTTIME) |
BIT_ULL(NL80211_STA_INFO_RX_DROP_MISC);
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
sinfo->beacon_loss_count =
sdata->deflink.u.mgd.beacon_loss_count;
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_BEACON_LOSS);
}
sinfo->connected_time = ktime_get_seconds() - sta->last_connected;
sinfo->assoc_at = sta->assoc_at;
sinfo->inactive_time =
jiffies_to_msecs(jiffies - ieee80211_sta_last_active(sta));
if (!(sinfo->filled & (BIT_ULL(NL80211_STA_INFO_TX_BYTES64) |
BIT_ULL(NL80211_STA_INFO_TX_BYTES)))) {
sinfo->tx_bytes = 0;
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
mac80211: prepare sta handling for MLO support Currently in mac80211 each STA object is represented using sta_info datastructure with the associated STA specific information and drivers access ieee80211_sta part of it. With MLO (Multi Link Operation) support being added in 802.11be standard, though the association is logically with a single Multi Link capable STA, at the physical level communication can happen via different advertised links (uniquely identified by Channel, operating class, BSSID) and hence the need to handle multiple link STA parameters within a composite sta_info object called the MLD STA. The different link STA part of MLD STA are identified using the link address which can be same or different as the MLD STA address and unique link id based on the link vif. To support extension of such a model, the sta_info datastructure is modified to hold multiple link STA objects with link specific params currently within sta_info moved to this new structure. Similarly this is done for ieee80211_sta as well which will be accessed within mac80211 as well as by drivers, hence trivial driver changes are expected to support this. For current non MLO supported drivers, only one link STA is present and link information is accessed via 'deflink' member. For MLO drivers, we still need to define the APIs etc. to get the correct link ID and access the correct part of the station info. Currently in mac80211, all link STA info are accessed directly via deflink. These will be updated to access via link pointers indexed by link id with MLO support patches, with link id being 0 for non MLO supported cases. Except for couple of macro related changes, below spatch takes care of updating mac80211 and driver code to access to the link STA info via deflink. @ieee80211_sta@ struct ieee80211_sta *s; struct sta_info *si; identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr}; @@ ( s-> - var + deflink.var | si->sta. - var + deflink.var ) @sta_info@ struct sta_info *si; identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth}; @@ ( si-> - var + deflink.var ) Signed-off-by: Sriram R <quic_srirrama@quicinc.com> Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com [remove MLO-drivers notes from commit message, not clear yet; run spatch] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 15:41:23 +00:00
sinfo->tx_bytes += sta->deflink.tx_stats.bytes[ac];
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BYTES64);
}
if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_PACKETS))) {
sinfo->tx_packets = 0;
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
mac80211: prepare sta handling for MLO support Currently in mac80211 each STA object is represented using sta_info datastructure with the associated STA specific information and drivers access ieee80211_sta part of it. With MLO (Multi Link Operation) support being added in 802.11be standard, though the association is logically with a single Multi Link capable STA, at the physical level communication can happen via different advertised links (uniquely identified by Channel, operating class, BSSID) and hence the need to handle multiple link STA parameters within a composite sta_info object called the MLD STA. The different link STA part of MLD STA are identified using the link address which can be same or different as the MLD STA address and unique link id based on the link vif. To support extension of such a model, the sta_info datastructure is modified to hold multiple link STA objects with link specific params currently within sta_info moved to this new structure. Similarly this is done for ieee80211_sta as well which will be accessed within mac80211 as well as by drivers, hence trivial driver changes are expected to support this. For current non MLO supported drivers, only one link STA is present and link information is accessed via 'deflink' member. For MLO drivers, we still need to define the APIs etc. to get the correct link ID and access the correct part of the station info. Currently in mac80211, all link STA info are accessed directly via deflink. These will be updated to access via link pointers indexed by link id with MLO support patches, with link id being 0 for non MLO supported cases. Except for couple of macro related changes, below spatch takes care of updating mac80211 and driver code to access to the link STA info via deflink. @ieee80211_sta@ struct ieee80211_sta *s; struct sta_info *si; identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr}; @@ ( s-> - var + deflink.var | si->sta. - var + deflink.var ) @sta_info@ struct sta_info *si; identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth}; @@ ( si-> - var + deflink.var ) Signed-off-by: Sriram R <quic_srirrama@quicinc.com> Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com [remove MLO-drivers notes from commit message, not clear yet; run spatch] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 15:41:23 +00:00
sinfo->tx_packets += sta->deflink.tx_stats.packets[ac];
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_PACKETS);
}
if (!(sinfo->filled & (BIT_ULL(NL80211_STA_INFO_RX_BYTES64) |
BIT_ULL(NL80211_STA_INFO_RX_BYTES)))) {
mac80211: prepare sta handling for MLO support Currently in mac80211 each STA object is represented using sta_info datastructure with the associated STA specific information and drivers access ieee80211_sta part of it. With MLO (Multi Link Operation) support being added in 802.11be standard, though the association is logically with a single Multi Link capable STA, at the physical level communication can happen via different advertised links (uniquely identified by Channel, operating class, BSSID) and hence the need to handle multiple link STA parameters within a composite sta_info object called the MLD STA. The different link STA part of MLD STA are identified using the link address which can be same or different as the MLD STA address and unique link id based on the link vif. To support extension of such a model, the sta_info datastructure is modified to hold multiple link STA objects with link specific params currently within sta_info moved to this new structure. Similarly this is done for ieee80211_sta as well which will be accessed within mac80211 as well as by drivers, hence trivial driver changes are expected to support this. For current non MLO supported drivers, only one link STA is present and link information is accessed via 'deflink' member. For MLO drivers, we still need to define the APIs etc. to get the correct link ID and access the correct part of the station info. Currently in mac80211, all link STA info are accessed directly via deflink. These will be updated to access via link pointers indexed by link id with MLO support patches, with link id being 0 for non MLO supported cases. Except for couple of macro related changes, below spatch takes care of updating mac80211 and driver code to access to the link STA info via deflink. @ieee80211_sta@ struct ieee80211_sta *s; struct sta_info *si; identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr}; @@ ( s-> - var + deflink.var | si->sta. - var + deflink.var ) @sta_info@ struct sta_info *si; identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth}; @@ ( si-> - var + deflink.var ) Signed-off-by: Sriram R <quic_srirrama@quicinc.com> Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com [remove MLO-drivers notes from commit message, not clear yet; run spatch] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 15:41:23 +00:00
sinfo->rx_bytes += sta_get_stats_bytes(&sta->deflink.rx_stats);
mac80211: prepare sta handling for MLO support Currently in mac80211 each STA object is represented using sta_info datastructure with the associated STA specific information and drivers access ieee80211_sta part of it. With MLO (Multi Link Operation) support being added in 802.11be standard, though the association is logically with a single Multi Link capable STA, at the physical level communication can happen via different advertised links (uniquely identified by Channel, operating class, BSSID) and hence the need to handle multiple link STA parameters within a composite sta_info object called the MLD STA. The different link STA part of MLD STA are identified using the link address which can be same or different as the MLD STA address and unique link id based on the link vif. To support extension of such a model, the sta_info datastructure is modified to hold multiple link STA objects with link specific params currently within sta_info moved to this new structure. Similarly this is done for ieee80211_sta as well which will be accessed within mac80211 as well as by drivers, hence trivial driver changes are expected to support this. For current non MLO supported drivers, only one link STA is present and link information is accessed via 'deflink' member. For MLO drivers, we still need to define the APIs etc. to get the correct link ID and access the correct part of the station info. Currently in mac80211, all link STA info are accessed directly via deflink. These will be updated to access via link pointers indexed by link id with MLO support patches, with link id being 0 for non MLO supported cases. Except for couple of macro related changes, below spatch takes care of updating mac80211 and driver code to access to the link STA info via deflink. @ieee80211_sta@ struct ieee80211_sta *s; struct sta_info *si; identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr}; @@ ( s-> - var + deflink.var | si->sta. - var + deflink.var ) @sta_info@ struct sta_info *si; identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth}; @@ ( si-> - var + deflink.var ) Signed-off-by: Sriram R <quic_srirrama@quicinc.com> Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com [remove MLO-drivers notes from commit message, not clear yet; run spatch] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 15:41:23 +00:00
if (sta->deflink.pcpu_rx_stats) {
for_each_possible_cpu(cpu) {
struct ieee80211_sta_rx_stats *cpurxs;
mac80211: prepare sta handling for MLO support Currently in mac80211 each STA object is represented using sta_info datastructure with the associated STA specific information and drivers access ieee80211_sta part of it. With MLO (Multi Link Operation) support being added in 802.11be standard, though the association is logically with a single Multi Link capable STA, at the physical level communication can happen via different advertised links (uniquely identified by Channel, operating class, BSSID) and hence the need to handle multiple link STA parameters within a composite sta_info object called the MLD STA. The different link STA part of MLD STA are identified using the link address which can be same or different as the MLD STA address and unique link id based on the link vif. To support extension of such a model, the sta_info datastructure is modified to hold multiple link STA objects with link specific params currently within sta_info moved to this new structure. Similarly this is done for ieee80211_sta as well which will be accessed within mac80211 as well as by drivers, hence trivial driver changes are expected to support this. For current non MLO supported drivers, only one link STA is present and link information is accessed via 'deflink' member. For MLO drivers, we still need to define the APIs etc. to get the correct link ID and access the correct part of the station info. Currently in mac80211, all link STA info are accessed directly via deflink. These will be updated to access via link pointers indexed by link id with MLO support patches, with link id being 0 for non MLO supported cases. Except for couple of macro related changes, below spatch takes care of updating mac80211 and driver code to access to the link STA info via deflink. @ieee80211_sta@ struct ieee80211_sta *s; struct sta_info *si; identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr}; @@ ( s-> - var + deflink.var | si->sta. - var + deflink.var ) @sta_info@ struct sta_info *si; identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth}; @@ ( si-> - var + deflink.var ) Signed-off-by: Sriram R <quic_srirrama@quicinc.com> Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com [remove MLO-drivers notes from commit message, not clear yet; run spatch] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 15:41:23 +00:00
cpurxs = per_cpu_ptr(sta->deflink.pcpu_rx_stats,
cpu);
sinfo->rx_bytes += sta_get_stats_bytes(cpurxs);
}
}
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BYTES64);
}
if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_RX_PACKETS))) {
mac80211: prepare sta handling for MLO support Currently in mac80211 each STA object is represented using sta_info datastructure with the associated STA specific information and drivers access ieee80211_sta part of it. With MLO (Multi Link Operation) support being added in 802.11be standard, though the association is logically with a single Multi Link capable STA, at the physical level communication can happen via different advertised links (uniquely identified by Channel, operating class, BSSID) and hence the need to handle multiple link STA parameters within a composite sta_info object called the MLD STA. The different link STA part of MLD STA are identified using the link address which can be same or different as the MLD STA address and unique link id based on the link vif. To support extension of such a model, the sta_info datastructure is modified to hold multiple link STA objects with link specific params currently within sta_info moved to this new structure. Similarly this is done for ieee80211_sta as well which will be accessed within mac80211 as well as by drivers, hence trivial driver changes are expected to support this. For current non MLO supported drivers, only one link STA is present and link information is accessed via 'deflink' member. For MLO drivers, we still need to define the APIs etc. to get the correct link ID and access the correct part of the station info. Currently in mac80211, all link STA info are accessed directly via deflink. These will be updated to access via link pointers indexed by link id with MLO support patches, with link id being 0 for non MLO supported cases. Except for couple of macro related changes, below spatch takes care of updating mac80211 and driver code to access to the link STA info via deflink. @ieee80211_sta@ struct ieee80211_sta *s; struct sta_info *si; identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr}; @@ ( s-> - var + deflink.var | si->sta. - var + deflink.var ) @sta_info@ struct sta_info *si; identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth}; @@ ( si-> - var + deflink.var ) Signed-off-by: Sriram R <quic_srirrama@quicinc.com> Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com [remove MLO-drivers notes from commit message, not clear yet; run spatch] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 15:41:23 +00:00
sinfo->rx_packets = sta->deflink.rx_stats.packets;
if (sta->deflink.pcpu_rx_stats) {
for_each_possible_cpu(cpu) {
struct ieee80211_sta_rx_stats *cpurxs;
mac80211: prepare sta handling for MLO support Currently in mac80211 each STA object is represented using sta_info datastructure with the associated STA specific information and drivers access ieee80211_sta part of it. With MLO (Multi Link Operation) support being added in 802.11be standard, though the association is logically with a single Multi Link capable STA, at the physical level communication can happen via different advertised links (uniquely identified by Channel, operating class, BSSID) and hence the need to handle multiple link STA parameters within a composite sta_info object called the MLD STA. The different link STA part of MLD STA are identified using the link address which can be same or different as the MLD STA address and unique link id based on the link vif. To support extension of such a model, the sta_info datastructure is modified to hold multiple link STA objects with link specific params currently within sta_info moved to this new structure. Similarly this is done for ieee80211_sta as well which will be accessed within mac80211 as well as by drivers, hence trivial driver changes are expected to support this. For current non MLO supported drivers, only one link STA is present and link information is accessed via 'deflink' member. For MLO drivers, we still need to define the APIs etc. to get the correct link ID and access the correct part of the station info. Currently in mac80211, all link STA info are accessed directly via deflink. These will be updated to access via link pointers indexed by link id with MLO support patches, with link id being 0 for non MLO supported cases. Except for couple of macro related changes, below spatch takes care of updating mac80211 and driver code to access to the link STA info via deflink. @ieee80211_sta@ struct ieee80211_sta *s; struct sta_info *si; identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr}; @@ ( s-> - var + deflink.var | si->sta. - var + deflink.var ) @sta_info@ struct sta_info *si; identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth}; @@ ( si-> - var + deflink.var ) Signed-off-by: Sriram R <quic_srirrama@quicinc.com> Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com [remove MLO-drivers notes from commit message, not clear yet; run spatch] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 15:41:23 +00:00
cpurxs = per_cpu_ptr(sta->deflink.pcpu_rx_stats,
cpu);
sinfo->rx_packets += cpurxs->packets;
}
}
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_PACKETS);
}
if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_RETRIES))) {
mac80211: prepare sta handling for MLO support Currently in mac80211 each STA object is represented using sta_info datastructure with the associated STA specific information and drivers access ieee80211_sta part of it. With MLO (Multi Link Operation) support being added in 802.11be standard, though the association is logically with a single Multi Link capable STA, at the physical level communication can happen via different advertised links (uniquely identified by Channel, operating class, BSSID) and hence the need to handle multiple link STA parameters within a composite sta_info object called the MLD STA. The different link STA part of MLD STA are identified using the link address which can be same or different as the MLD STA address and unique link id based on the link vif. To support extension of such a model, the sta_info datastructure is modified to hold multiple link STA objects with link specific params currently within sta_info moved to this new structure. Similarly this is done for ieee80211_sta as well which will be accessed within mac80211 as well as by drivers, hence trivial driver changes are expected to support this. For current non MLO supported drivers, only one link STA is present and link information is accessed via 'deflink' member. For MLO drivers, we still need to define the APIs etc. to get the correct link ID and access the correct part of the station info. Currently in mac80211, all link STA info are accessed directly via deflink. These will be updated to access via link pointers indexed by link id with MLO support patches, with link id being 0 for non MLO supported cases. Except for couple of macro related changes, below spatch takes care of updating mac80211 and driver code to access to the link STA info via deflink. @ieee80211_sta@ struct ieee80211_sta *s; struct sta_info *si; identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr}; @@ ( s-> - var + deflink.var | si->sta. - var + deflink.var ) @sta_info@ struct sta_info *si; identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth}; @@ ( si-> - var + deflink.var ) Signed-off-by: Sriram R <quic_srirrama@quicinc.com> Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com [remove MLO-drivers notes from commit message, not clear yet; run spatch] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 15:41:23 +00:00
sinfo->tx_retries = sta->deflink.status_stats.retry_count;
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES);
}
if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_FAILED))) {
mac80211: prepare sta handling for MLO support Currently in mac80211 each STA object is represented using sta_info datastructure with the associated STA specific information and drivers access ieee80211_sta part of it. With MLO (Multi Link Operation) support being added in 802.11be standard, though the association is logically with a single Multi Link capable STA, at the physical level communication can happen via different advertised links (uniquely identified by Channel, operating class, BSSID) and hence the need to handle multiple link STA parameters within a composite sta_info object called the MLD STA. The different link STA part of MLD STA are identified using the link address which can be same or different as the MLD STA address and unique link id based on the link vif. To support extension of such a model, the sta_info datastructure is modified to hold multiple link STA objects with link specific params currently within sta_info moved to this new structure. Similarly this is done for ieee80211_sta as well which will be accessed within mac80211 as well as by drivers, hence trivial driver changes are expected to support this. For current non MLO supported drivers, only one link STA is present and link information is accessed via 'deflink' member. For MLO drivers, we still need to define the APIs etc. to get the correct link ID and access the correct part of the station info. Currently in mac80211, all link STA info are accessed directly via deflink. These will be updated to access via link pointers indexed by link id with MLO support patches, with link id being 0 for non MLO supported cases. Except for couple of macro related changes, below spatch takes care of updating mac80211 and driver code to access to the link STA info via deflink. @ieee80211_sta@ struct ieee80211_sta *s; struct sta_info *si; identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr}; @@ ( s-> - var + deflink.var | si->sta. - var + deflink.var ) @sta_info@ struct sta_info *si; identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth}; @@ ( si-> - var + deflink.var ) Signed-off-by: Sriram R <quic_srirrama@quicinc.com> Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com [remove MLO-drivers notes from commit message, not clear yet; run spatch] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 15:41:23 +00:00
sinfo->tx_failed = sta->deflink.status_stats.retry_failed;
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED);
}
mac80211: Add airtime accounting and scheduling to TXQs This adds airtime accounting and scheduling to the mac80211 TXQ scheduler. A new callback, ieee80211_sta_register_airtime(), is added that drivers can call to report airtime usage for stations. When airtime information is present, mac80211 will schedule TXQs (through ieee80211_next_txq()) in a way that enforces airtime fairness between active stations. This scheduling works the same way as the ath9k in-driver airtime fairness scheduling. If no airtime usage is reported by the driver, the scheduler will default to round-robin scheduling. For drivers that don't control TXQ scheduling in software, a new API function, ieee80211_txq_may_transmit(), is added which the driver can use to check if the TXQ is eligible for transmission, or should be throttled to enforce fairness. Calls to this function must also be enclosed in ieee80211_txq_schedule_{start,end}() calls to ensure proper locking. The API ieee80211_txq_may_transmit() also ensures that TXQ list will be aligned aginst driver's own round-robin scheduler list. i.e it rotates the TXQ list till it makes the requested node becomes the first entry in TXQ list. Thus both the TXQ list and driver's list are in sync. Co-developed-by: Rajkumar Manoharan <rmanohar@codeaurora.org> Signed-off-by: Louie Lu <git@louie.lu> [added debugfs write op to reset airtime counter] Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk> Signed-off-by: Rajkumar Manoharan <rmanohar@codeaurora.org> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2018-12-19 01:02:08 +00:00
if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_RX_DURATION))) {
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
sinfo->rx_duration += sta->airtime[ac].rx_airtime;
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DURATION);
}
if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_DURATION))) {
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
sinfo->tx_duration += sta->airtime[ac].tx_airtime;
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_DURATION);
}
if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT))) {
sinfo->airtime_weight = sta->airtime_weight;
mac80211: Add airtime accounting and scheduling to TXQs This adds airtime accounting and scheduling to the mac80211 TXQ scheduler. A new callback, ieee80211_sta_register_airtime(), is added that drivers can call to report airtime usage for stations. When airtime information is present, mac80211 will schedule TXQs (through ieee80211_next_txq()) in a way that enforces airtime fairness between active stations. This scheduling works the same way as the ath9k in-driver airtime fairness scheduling. If no airtime usage is reported by the driver, the scheduler will default to round-robin scheduling. For drivers that don't control TXQ scheduling in software, a new API function, ieee80211_txq_may_transmit(), is added which the driver can use to check if the TXQ is eligible for transmission, or should be throttled to enforce fairness. Calls to this function must also be enclosed in ieee80211_txq_schedule_{start,end}() calls to ensure proper locking. The API ieee80211_txq_may_transmit() also ensures that TXQ list will be aligned aginst driver's own round-robin scheduler list. i.e it rotates the TXQ list till it makes the requested node becomes the first entry in TXQ list. Thus both the TXQ list and driver's list are in sync. Co-developed-by: Rajkumar Manoharan <rmanohar@codeaurora.org> Signed-off-by: Louie Lu <git@louie.lu> [added debugfs write op to reset airtime counter] Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk> Signed-off-by: Rajkumar Manoharan <rmanohar@codeaurora.org> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2018-12-19 01:02:08 +00:00
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT);
}
mac80211: prepare sta handling for MLO support Currently in mac80211 each STA object is represented using sta_info datastructure with the associated STA specific information and drivers access ieee80211_sta part of it. With MLO (Multi Link Operation) support being added in 802.11be standard, though the association is logically with a single Multi Link capable STA, at the physical level communication can happen via different advertised links (uniquely identified by Channel, operating class, BSSID) and hence the need to handle multiple link STA parameters within a composite sta_info object called the MLD STA. The different link STA part of MLD STA are identified using the link address which can be same or different as the MLD STA address and unique link id based on the link vif. To support extension of such a model, the sta_info datastructure is modified to hold multiple link STA objects with link specific params currently within sta_info moved to this new structure. Similarly this is done for ieee80211_sta as well which will be accessed within mac80211 as well as by drivers, hence trivial driver changes are expected to support this. For current non MLO supported drivers, only one link STA is present and link information is accessed via 'deflink' member. For MLO drivers, we still need to define the APIs etc. to get the correct link ID and access the correct part of the station info. Currently in mac80211, all link STA info are accessed directly via deflink. These will be updated to access via link pointers indexed by link id with MLO support patches, with link id being 0 for non MLO supported cases. Except for couple of macro related changes, below spatch takes care of updating mac80211 and driver code to access to the link STA info via deflink. @ieee80211_sta@ struct ieee80211_sta *s; struct sta_info *si; identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr}; @@ ( s-> - var + deflink.var | si->sta. - var + deflink.var ) @sta_info@ struct sta_info *si; identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth}; @@ ( si-> - var + deflink.var ) Signed-off-by: Sriram R <quic_srirrama@quicinc.com> Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com [remove MLO-drivers notes from commit message, not clear yet; run spatch] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 15:41:23 +00:00
sinfo->rx_dropped_misc = sta->deflink.rx_stats.dropped;
if (sta->deflink.pcpu_rx_stats) {
for_each_possible_cpu(cpu) {
struct ieee80211_sta_rx_stats *cpurxs;
mac80211: prepare sta handling for MLO support Currently in mac80211 each STA object is represented using sta_info datastructure with the associated STA specific information and drivers access ieee80211_sta part of it. With MLO (Multi Link Operation) support being added in 802.11be standard, though the association is logically with a single Multi Link capable STA, at the physical level communication can happen via different advertised links (uniquely identified by Channel, operating class, BSSID) and hence the need to handle multiple link STA parameters within a composite sta_info object called the MLD STA. The different link STA part of MLD STA are identified using the link address which can be same or different as the MLD STA address and unique link id based on the link vif. To support extension of such a model, the sta_info datastructure is modified to hold multiple link STA objects with link specific params currently within sta_info moved to this new structure. Similarly this is done for ieee80211_sta as well which will be accessed within mac80211 as well as by drivers, hence trivial driver changes are expected to support this. For current non MLO supported drivers, only one link STA is present and link information is accessed via 'deflink' member. For MLO drivers, we still need to define the APIs etc. to get the correct link ID and access the correct part of the station info. Currently in mac80211, all link STA info are accessed directly via deflink. These will be updated to access via link pointers indexed by link id with MLO support patches, with link id being 0 for non MLO supported cases. Except for couple of macro related changes, below spatch takes care of updating mac80211 and driver code to access to the link STA info via deflink. @ieee80211_sta@ struct ieee80211_sta *s; struct sta_info *si; identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr}; @@ ( s-> - var + deflink.var | si->sta. - var + deflink.var ) @sta_info@ struct sta_info *si; identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth}; @@ ( si-> - var + deflink.var ) Signed-off-by: Sriram R <quic_srirrama@quicinc.com> Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com [remove MLO-drivers notes from commit message, not clear yet; run spatch] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 15:41:23 +00:00
cpurxs = per_cpu_ptr(sta->deflink.pcpu_rx_stats, cpu);
sinfo->rx_dropped_misc += cpurxs->dropped;
}
}
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
!(sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER)) {
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_BEACON_RX) |
BIT_ULL(NL80211_STA_INFO_BEACON_SIGNAL_AVG);
sinfo->rx_beacon_signal_avg = ieee80211_ave_rssi(&sdata->vif);
}
if (ieee80211_hw_check(&sta->local->hw, SIGNAL_DBM) ||
ieee80211_hw_check(&sta->local->hw, SIGNAL_UNSPEC)) {
if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_SIGNAL))) {
sinfo->signal = (s8)last_rxstats->last_signal;
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL);
}
mac80211: prepare sta handling for MLO support Currently in mac80211 each STA object is represented using sta_info datastructure with the associated STA specific information and drivers access ieee80211_sta part of it. With MLO (Multi Link Operation) support being added in 802.11be standard, though the association is logically with a single Multi Link capable STA, at the physical level communication can happen via different advertised links (uniquely identified by Channel, operating class, BSSID) and hence the need to handle multiple link STA parameters within a composite sta_info object called the MLD STA. The different link STA part of MLD STA are identified using the link address which can be same or different as the MLD STA address and unique link id based on the link vif. To support extension of such a model, the sta_info datastructure is modified to hold multiple link STA objects with link specific params currently within sta_info moved to this new structure. Similarly this is done for ieee80211_sta as well which will be accessed within mac80211 as well as by drivers, hence trivial driver changes are expected to support this. For current non MLO supported drivers, only one link STA is present and link information is accessed via 'deflink' member. For MLO drivers, we still need to define the APIs etc. to get the correct link ID and access the correct part of the station info. Currently in mac80211, all link STA info are accessed directly via deflink. These will be updated to access via link pointers indexed by link id with MLO support patches, with link id being 0 for non MLO supported cases. Except for couple of macro related changes, below spatch takes care of updating mac80211 and driver code to access to the link STA info via deflink. @ieee80211_sta@ struct ieee80211_sta *s; struct sta_info *si; identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr}; @@ ( s-> - var + deflink.var | si->sta. - var + deflink.var ) @sta_info@ struct sta_info *si; identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth}; @@ ( si-> - var + deflink.var ) Signed-off-by: Sriram R <quic_srirrama@quicinc.com> Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com [remove MLO-drivers notes from commit message, not clear yet; run spatch] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 15:41:23 +00:00
if (!sta->deflink.pcpu_rx_stats &&
!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG))) {
sinfo->signal_avg =
mac80211: prepare sta handling for MLO support Currently in mac80211 each STA object is represented using sta_info datastructure with the associated STA specific information and drivers access ieee80211_sta part of it. With MLO (Multi Link Operation) support being added in 802.11be standard, though the association is logically with a single Multi Link capable STA, at the physical level communication can happen via different advertised links (uniquely identified by Channel, operating class, BSSID) and hence the need to handle multiple link STA parameters within a composite sta_info object called the MLD STA. The different link STA part of MLD STA are identified using the link address which can be same or different as the MLD STA address and unique link id based on the link vif. To support extension of such a model, the sta_info datastructure is modified to hold multiple link STA objects with link specific params currently within sta_info moved to this new structure. Similarly this is done for ieee80211_sta as well which will be accessed within mac80211 as well as by drivers, hence trivial driver changes are expected to support this. For current non MLO supported drivers, only one link STA is present and link information is accessed via 'deflink' member. For MLO drivers, we still need to define the APIs etc. to get the correct link ID and access the correct part of the station info. Currently in mac80211, all link STA info are accessed directly via deflink. These will be updated to access via link pointers indexed by link id with MLO support patches, with link id being 0 for non MLO supported cases. Except for couple of macro related changes, below spatch takes care of updating mac80211 and driver code to access to the link STA info via deflink. @ieee80211_sta@ struct ieee80211_sta *s; struct sta_info *si; identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr}; @@ ( s-> - var + deflink.var | si->sta. - var + deflink.var ) @sta_info@ struct sta_info *si; identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth}; @@ ( si-> - var + deflink.var ) Signed-off-by: Sriram R <quic_srirrama@quicinc.com> Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com [remove MLO-drivers notes from commit message, not clear yet; run spatch] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 15:41:23 +00:00
-ewma_signal_read(&sta->deflink.rx_stats_avg.signal);
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG);
}
}
/* for the average - if pcpu_rx_stats isn't set - rxstats must point to
* the sta->rx_stats struct, so the check here is fine with and without
* pcpu statistics
*/
if (last_rxstats->chains &&
!(sinfo->filled & (BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL) |
BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)))) {
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL);
mac80211: prepare sta handling for MLO support Currently in mac80211 each STA object is represented using sta_info datastructure with the associated STA specific information and drivers access ieee80211_sta part of it. With MLO (Multi Link Operation) support being added in 802.11be standard, though the association is logically with a single Multi Link capable STA, at the physical level communication can happen via different advertised links (uniquely identified by Channel, operating class, BSSID) and hence the need to handle multiple link STA parameters within a composite sta_info object called the MLD STA. The different link STA part of MLD STA are identified using the link address which can be same or different as the MLD STA address and unique link id based on the link vif. To support extension of such a model, the sta_info datastructure is modified to hold multiple link STA objects with link specific params currently within sta_info moved to this new structure. Similarly this is done for ieee80211_sta as well which will be accessed within mac80211 as well as by drivers, hence trivial driver changes are expected to support this. For current non MLO supported drivers, only one link STA is present and link information is accessed via 'deflink' member. For MLO drivers, we still need to define the APIs etc. to get the correct link ID and access the correct part of the station info. Currently in mac80211, all link STA info are accessed directly via deflink. These will be updated to access via link pointers indexed by link id with MLO support patches, with link id being 0 for non MLO supported cases. Except for couple of macro related changes, below spatch takes care of updating mac80211 and driver code to access to the link STA info via deflink. @ieee80211_sta@ struct ieee80211_sta *s; struct sta_info *si; identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr}; @@ ( s-> - var + deflink.var | si->sta. - var + deflink.var ) @sta_info@ struct sta_info *si; identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth}; @@ ( si-> - var + deflink.var ) Signed-off-by: Sriram R <quic_srirrama@quicinc.com> Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com [remove MLO-drivers notes from commit message, not clear yet; run spatch] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 15:41:23 +00:00
if (!sta->deflink.pcpu_rx_stats)
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL_AVG);
sinfo->chains = last_rxstats->chains;
for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) {
sinfo->chain_signal[i] =
last_rxstats->chain_signal_last[i];
sinfo->chain_signal_avg[i] =
mac80211: prepare sta handling for MLO support Currently in mac80211 each STA object is represented using sta_info datastructure with the associated STA specific information and drivers access ieee80211_sta part of it. With MLO (Multi Link Operation) support being added in 802.11be standard, though the association is logically with a single Multi Link capable STA, at the physical level communication can happen via different advertised links (uniquely identified by Channel, operating class, BSSID) and hence the need to handle multiple link STA parameters within a composite sta_info object called the MLD STA. The different link STA part of MLD STA are identified using the link address which can be same or different as the MLD STA address and unique link id based on the link vif. To support extension of such a model, the sta_info datastructure is modified to hold multiple link STA objects with link specific params currently within sta_info moved to this new structure. Similarly this is done for ieee80211_sta as well which will be accessed within mac80211 as well as by drivers, hence trivial driver changes are expected to support this. For current non MLO supported drivers, only one link STA is present and link information is accessed via 'deflink' member. For MLO drivers, we still need to define the APIs etc. to get the correct link ID and access the correct part of the station info. Currently in mac80211, all link STA info are accessed directly via deflink. These will be updated to access via link pointers indexed by link id with MLO support patches, with link id being 0 for non MLO supported cases. Except for couple of macro related changes, below spatch takes care of updating mac80211 and driver code to access to the link STA info via deflink. @ieee80211_sta@ struct ieee80211_sta *s; struct sta_info *si; identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr}; @@ ( s-> - var + deflink.var | si->sta. - var + deflink.var ) @sta_info@ struct sta_info *si; identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth}; @@ ( si-> - var + deflink.var ) Signed-off-by: Sriram R <quic_srirrama@quicinc.com> Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com [remove MLO-drivers notes from commit message, not clear yet; run spatch] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 15:41:23 +00:00
-ewma_signal_read(&sta->deflink.rx_stats_avg.chain_signal[i]);
}
}
if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_BITRATE)) &&
!sta->sta.valid_links &&
ieee80211_rate_valid(&sta->deflink.tx_stats.last_rate)) {
mac80211: prepare sta handling for MLO support Currently in mac80211 each STA object is represented using sta_info datastructure with the associated STA specific information and drivers access ieee80211_sta part of it. With MLO (Multi Link Operation) support being added in 802.11be standard, though the association is logically with a single Multi Link capable STA, at the physical level communication can happen via different advertised links (uniquely identified by Channel, operating class, BSSID) and hence the need to handle multiple link STA parameters within a composite sta_info object called the MLD STA. The different link STA part of MLD STA are identified using the link address which can be same or different as the MLD STA address and unique link id based on the link vif. To support extension of such a model, the sta_info datastructure is modified to hold multiple link STA objects with link specific params currently within sta_info moved to this new structure. Similarly this is done for ieee80211_sta as well which will be accessed within mac80211 as well as by drivers, hence trivial driver changes are expected to support this. For current non MLO supported drivers, only one link STA is present and link information is accessed via 'deflink' member. For MLO drivers, we still need to define the APIs etc. to get the correct link ID and access the correct part of the station info. Currently in mac80211, all link STA info are accessed directly via deflink. These will be updated to access via link pointers indexed by link id with MLO support patches, with link id being 0 for non MLO supported cases. Except for couple of macro related changes, below spatch takes care of updating mac80211 and driver code to access to the link STA info via deflink. @ieee80211_sta@ struct ieee80211_sta *s; struct sta_info *si; identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr}; @@ ( s-> - var + deflink.var | si->sta. - var + deflink.var ) @sta_info@ struct sta_info *si; identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth}; @@ ( si-> - var + deflink.var ) Signed-off-by: Sriram R <quic_srirrama@quicinc.com> Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com [remove MLO-drivers notes from commit message, not clear yet; run spatch] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 15:41:23 +00:00
sta_set_rate_info_tx(sta, &sta->deflink.tx_stats.last_rate,
&sinfo->txrate);
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
}
if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_RX_BITRATE)) &&
!sta->sta.valid_links) {
if (sta_set_rate_info_rx(sta, &sinfo->rxrate) == 0)
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BITRATE);
}
if (tidstats && !cfg80211_sinfo_alloc_tid_stats(sinfo, GFP_KERNEL)) {
for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++)
sta_set_tidstats(sta, &sinfo->pertid[i], i);
}
if (ieee80211_vif_is_mesh(&sdata->vif)) {
#ifdef CONFIG_MAC80211_MESH
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_LLID) |
BIT_ULL(NL80211_STA_INFO_PLID) |
BIT_ULL(NL80211_STA_INFO_PLINK_STATE) |
BIT_ULL(NL80211_STA_INFO_LOCAL_PM) |
BIT_ULL(NL80211_STA_INFO_PEER_PM) |
BIT_ULL(NL80211_STA_INFO_NONPEER_PM) |
BIT_ULL(NL80211_STA_INFO_CONNECTED_TO_GATE) |
BIT_ULL(NL80211_STA_INFO_CONNECTED_TO_AS);
sinfo->llid = sta->mesh->llid;
sinfo->plid = sta->mesh->plid;
sinfo->plink_state = sta->mesh->plink_state;
if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) {
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_T_OFFSET);
sinfo->t_offset = sta->mesh->t_offset;
}
sinfo->local_pm = sta->mesh->local_pm;
sinfo->peer_pm = sta->mesh->peer_pm;
sinfo->nonpeer_pm = sta->mesh->nonpeer_pm;
sinfo->connected_to_gate = sta->mesh->connected_to_gate;
sinfo->connected_to_as = sta->mesh->connected_to_as;
#endif
}
sinfo->bss_param.flags = 0;
if (sdata->vif.bss_conf.use_cts_prot)
sinfo->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT;
if (sdata->vif.bss_conf.use_short_preamble)
sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
if (sdata->vif.bss_conf.use_short_slot)
sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
sinfo->bss_param.dtim_period = sdata->vif.bss_conf.dtim_period;
sinfo->bss_param.beacon_interval = sdata->vif.bss_conf.beacon_int;
sinfo->sta_flags.set = 0;
sinfo->sta_flags.mask = BIT(NL80211_STA_FLAG_AUTHORIZED) |
BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
BIT(NL80211_STA_FLAG_WME) |
BIT(NL80211_STA_FLAG_MFP) |
BIT(NL80211_STA_FLAG_AUTHENTICATED) |
BIT(NL80211_STA_FLAG_ASSOCIATED) |
BIT(NL80211_STA_FLAG_TDLS_PEER);
if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
if (test_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE))
sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
if (sta->sta.wme)
sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_WME);
if (test_sta_flag(sta, WLAN_STA_MFP))
sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_MFP);
if (test_sta_flag(sta, WLAN_STA_AUTH))
sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
if (test_sta_flag(sta, WLAN_STA_ASSOC))
sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER))
sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
thr = sta_get_expected_throughput(sta);
if (thr != 0) {
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_EXPECTED_THROUGHPUT);
sinfo->expected_throughput = thr;
}
if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL)) &&
mac80211: prepare sta handling for MLO support Currently in mac80211 each STA object is represented using sta_info datastructure with the associated STA specific information and drivers access ieee80211_sta part of it. With MLO (Multi Link Operation) support being added in 802.11be standard, though the association is logically with a single Multi Link capable STA, at the physical level communication can happen via different advertised links (uniquely identified by Channel, operating class, BSSID) and hence the need to handle multiple link STA parameters within a composite sta_info object called the MLD STA. The different link STA part of MLD STA are identified using the link address which can be same or different as the MLD STA address and unique link id based on the link vif. To support extension of such a model, the sta_info datastructure is modified to hold multiple link STA objects with link specific params currently within sta_info moved to this new structure. Similarly this is done for ieee80211_sta as well which will be accessed within mac80211 as well as by drivers, hence trivial driver changes are expected to support this. For current non MLO supported drivers, only one link STA is present and link information is accessed via 'deflink' member. For MLO drivers, we still need to define the APIs etc. to get the correct link ID and access the correct part of the station info. Currently in mac80211, all link STA info are accessed directly via deflink. These will be updated to access via link pointers indexed by link id with MLO support patches, with link id being 0 for non MLO supported cases. Except for couple of macro related changes, below spatch takes care of updating mac80211 and driver code to access to the link STA info via deflink. @ieee80211_sta@ struct ieee80211_sta *s; struct sta_info *si; identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr}; @@ ( s-> - var + deflink.var | si->sta. - var + deflink.var ) @sta_info@ struct sta_info *si; identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth}; @@ ( si-> - var + deflink.var ) Signed-off-by: Sriram R <quic_srirrama@quicinc.com> Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com [remove MLO-drivers notes from commit message, not clear yet; run spatch] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 15:41:23 +00:00
sta->deflink.status_stats.ack_signal_filled) {
sinfo->ack_signal = sta->deflink.status_stats.last_ack_signal;
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL);
}
if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG)) &&
mac80211: prepare sta handling for MLO support Currently in mac80211 each STA object is represented using sta_info datastructure with the associated STA specific information and drivers access ieee80211_sta part of it. With MLO (Multi Link Operation) support being added in 802.11be standard, though the association is logically with a single Multi Link capable STA, at the physical level communication can happen via different advertised links (uniquely identified by Channel, operating class, BSSID) and hence the need to handle multiple link STA parameters within a composite sta_info object called the MLD STA. The different link STA part of MLD STA are identified using the link address which can be same or different as the MLD STA address and unique link id based on the link vif. To support extension of such a model, the sta_info datastructure is modified to hold multiple link STA objects with link specific params currently within sta_info moved to this new structure. Similarly this is done for ieee80211_sta as well which will be accessed within mac80211 as well as by drivers, hence trivial driver changes are expected to support this. For current non MLO supported drivers, only one link STA is present and link information is accessed via 'deflink' member. For MLO drivers, we still need to define the APIs etc. to get the correct link ID and access the correct part of the station info. Currently in mac80211, all link STA info are accessed directly via deflink. These will be updated to access via link pointers indexed by link id with MLO support patches, with link id being 0 for non MLO supported cases. Except for couple of macro related changes, below spatch takes care of updating mac80211 and driver code to access to the link STA info via deflink. @ieee80211_sta@ struct ieee80211_sta *s; struct sta_info *si; identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr}; @@ ( s-> - var + deflink.var | si->sta. - var + deflink.var ) @sta_info@ struct sta_info *si; identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth}; @@ ( si-> - var + deflink.var ) Signed-off-by: Sriram R <quic_srirrama@quicinc.com> Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com [remove MLO-drivers notes from commit message, not clear yet; run spatch] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 15:41:23 +00:00
sta->deflink.status_stats.ack_signal_filled) {
sinfo->avg_ack_signal =
-(s8)ewma_avg_signal_read(
mac80211: prepare sta handling for MLO support Currently in mac80211 each STA object is represented using sta_info datastructure with the associated STA specific information and drivers access ieee80211_sta part of it. With MLO (Multi Link Operation) support being added in 802.11be standard, though the association is logically with a single Multi Link capable STA, at the physical level communication can happen via different advertised links (uniquely identified by Channel, operating class, BSSID) and hence the need to handle multiple link STA parameters within a composite sta_info object called the MLD STA. The different link STA part of MLD STA are identified using the link address which can be same or different as the MLD STA address and unique link id based on the link vif. To support extension of such a model, the sta_info datastructure is modified to hold multiple link STA objects with link specific params currently within sta_info moved to this new structure. Similarly this is done for ieee80211_sta as well which will be accessed within mac80211 as well as by drivers, hence trivial driver changes are expected to support this. For current non MLO supported drivers, only one link STA is present and link information is accessed via 'deflink' member. For MLO drivers, we still need to define the APIs etc. to get the correct link ID and access the correct part of the station info. Currently in mac80211, all link STA info are accessed directly via deflink. These will be updated to access via link pointers indexed by link id with MLO support patches, with link id being 0 for non MLO supported cases. Except for couple of macro related changes, below spatch takes care of updating mac80211 and driver code to access to the link STA info via deflink. @ieee80211_sta@ struct ieee80211_sta *s; struct sta_info *si; identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr}; @@ ( s-> - var + deflink.var | si->sta. - var + deflink.var ) @sta_info@ struct sta_info *si; identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth}; @@ ( si-> - var + deflink.var ) Signed-off-by: Sriram R <quic_srirrama@quicinc.com> Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com [remove MLO-drivers notes from commit message, not clear yet; run spatch] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 15:41:23 +00:00
&sta->deflink.status_stats.avg_ack_signal);
sinfo->filled |=
BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG);
}
if (ieee80211_vif_is_mesh(&sdata->vif)) {
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_AIRTIME_LINK_METRIC);
sinfo->airtime_link_metric =
airtime_link_metric_get(local, sta);
}
}
u32 sta_get_expected_throughput(struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
struct rate_control_ref *ref = NULL;
u32 thr = 0;
if (test_sta_flag(sta, WLAN_STA_RATE_CONTROL))
ref = local->rate_ctrl;
/* check if the driver has a SW RC implementation */
if (ref && ref->ops->get_expected_throughput)
thr = ref->ops->get_expected_throughput(sta->rate_ctrl_priv);
else
thr = drv_get_expected_throughput(local, sta);
return thr;
}
unsigned long ieee80211_sta_last_active(struct sta_info *sta)
{
struct ieee80211_sta_rx_stats *stats = sta_get_last_rx_stats(sta);
mac80211: prepare sta handling for MLO support Currently in mac80211 each STA object is represented using sta_info datastructure with the associated STA specific information and drivers access ieee80211_sta part of it. With MLO (Multi Link Operation) support being added in 802.11be standard, though the association is logically with a single Multi Link capable STA, at the physical level communication can happen via different advertised links (uniquely identified by Channel, operating class, BSSID) and hence the need to handle multiple link STA parameters within a composite sta_info object called the MLD STA. The different link STA part of MLD STA are identified using the link address which can be same or different as the MLD STA address and unique link id based on the link vif. To support extension of such a model, the sta_info datastructure is modified to hold multiple link STA objects with link specific params currently within sta_info moved to this new structure. Similarly this is done for ieee80211_sta as well which will be accessed within mac80211 as well as by drivers, hence trivial driver changes are expected to support this. For current non MLO supported drivers, only one link STA is present and link information is accessed via 'deflink' member. For MLO drivers, we still need to define the APIs etc. to get the correct link ID and access the correct part of the station info. Currently in mac80211, all link STA info are accessed directly via deflink. These will be updated to access via link pointers indexed by link id with MLO support patches, with link id being 0 for non MLO supported cases. Except for couple of macro related changes, below spatch takes care of updating mac80211 and driver code to access to the link STA info via deflink. @ieee80211_sta@ struct ieee80211_sta *s; struct sta_info *si; identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr}; @@ ( s-> - var + deflink.var | si->sta. - var + deflink.var ) @sta_info@ struct sta_info *si; identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth}; @@ ( si-> - var + deflink.var ) Signed-off-by: Sriram R <quic_srirrama@quicinc.com> Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com [remove MLO-drivers notes from commit message, not clear yet; run spatch] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 15:41:23 +00:00
if (!sta->deflink.status_stats.last_ack ||
time_after(stats->last_rx, sta->deflink.status_stats.last_ack))
return stats->last_rx;
mac80211: prepare sta handling for MLO support Currently in mac80211 each STA object is represented using sta_info datastructure with the associated STA specific information and drivers access ieee80211_sta part of it. With MLO (Multi Link Operation) support being added in 802.11be standard, though the association is logically with a single Multi Link capable STA, at the physical level communication can happen via different advertised links (uniquely identified by Channel, operating class, BSSID) and hence the need to handle multiple link STA parameters within a composite sta_info object called the MLD STA. The different link STA part of MLD STA are identified using the link address which can be same or different as the MLD STA address and unique link id based on the link vif. To support extension of such a model, the sta_info datastructure is modified to hold multiple link STA objects with link specific params currently within sta_info moved to this new structure. Similarly this is done for ieee80211_sta as well which will be accessed within mac80211 as well as by drivers, hence trivial driver changes are expected to support this. For current non MLO supported drivers, only one link STA is present and link information is accessed via 'deflink' member. For MLO drivers, we still need to define the APIs etc. to get the correct link ID and access the correct part of the station info. Currently in mac80211, all link STA info are accessed directly via deflink. These will be updated to access via link pointers indexed by link id with MLO support patches, with link id being 0 for non MLO supported cases. Except for couple of macro related changes, below spatch takes care of updating mac80211 and driver code to access to the link STA info via deflink. @ieee80211_sta@ struct ieee80211_sta *s; struct sta_info *si; identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr}; @@ ( s-> - var + deflink.var | si->sta. - var + deflink.var ) @sta_info@ struct sta_info *si; identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth}; @@ ( si-> - var + deflink.var ) Signed-off-by: Sriram R <quic_srirrama@quicinc.com> Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com [remove MLO-drivers notes from commit message, not clear yet; run spatch] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 15:41:23 +00:00
return sta->deflink.status_stats.last_ack;
}
static void sta_update_codel_params(struct sta_info *sta, u32 thr)
{
if (thr && thr < STA_SLOW_THRESHOLD * sta->local->num_sta) {
sta->cparams.target = MS2TIME(50);
sta->cparams.interval = MS2TIME(300);
sta->cparams.ecn = false;
} else {
sta->cparams.target = MS2TIME(20);
sta->cparams.interval = MS2TIME(100);
sta->cparams.ecn = true;
}
}
void ieee80211_sta_set_expected_throughput(struct ieee80211_sta *pubsta,
u32 thr)
{
struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
sta_update_codel_params(sta, thr);
}
int ieee80211_sta_allocate_link(struct sta_info *sta, unsigned int link_id)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct sta_link_alloc *alloc;
int ret;
lockdep_assert_wiphy(sdata->local->hw.wiphy);
WARN_ON(!test_sta_flag(sta, WLAN_STA_INSERTED));
/* must represent an MLD from the start */
if (WARN_ON(!sta->sta.valid_links))
return -EINVAL;
if (WARN_ON(sta->sta.valid_links & BIT(link_id) ||
sta->link[link_id]))
return -EBUSY;
alloc = kzalloc(sizeof(*alloc), GFP_KERNEL);
if (!alloc)
return -ENOMEM;
ret = sta_info_alloc_link(sdata->local, &alloc->info, GFP_KERNEL);
if (ret) {
kfree(alloc);
return ret;
}
sta_info_add_link(sta, link_id, &alloc->info, &alloc->sta);
ieee80211_link_sta_debugfs_add(&alloc->info);
return 0;
}
void ieee80211_sta_free_link(struct sta_info *sta, unsigned int link_id)
{
lockdep_assert_wiphy(sta->sdata->local->hw.wiphy);
WARN_ON(!test_sta_flag(sta, WLAN_STA_INSERTED));
sta_remove_link(sta, link_id, false);
}
int ieee80211_sta_activate_link(struct sta_info *sta, unsigned int link_id)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct link_sta_info *link_sta;
u16 old_links = sta->sta.valid_links;
u16 new_links = old_links | BIT(link_id);
int ret;
link_sta = rcu_dereference_protected(sta->link[link_id],
lockdep_is_held(&sdata->local->hw.wiphy->mtx));
if (WARN_ON(old_links == new_links || !link_sta))
return -EINVAL;
rcu_read_lock();
if (link_sta_info_hash_lookup(sdata->local, link_sta->addr)) {
rcu_read_unlock();
return -EALREADY;
}
/* we only modify under the mutex so this is fine */
rcu_read_unlock();
sta->sta.valid_links = new_links;
if (WARN_ON(!test_sta_flag(sta, WLAN_STA_INSERTED)))
goto hash;
ieee80211_recalc_min_chandef(sdata, link_id);
/* Ensure the values are updated for the driver,
* redone by sta_remove_link on failure.
*/
ieee80211_sta_recalc_aggregates(&sta->sta);
ret = drv_change_sta_links(sdata->local, sdata, &sta->sta,
old_links, new_links);
if (ret) {
sta->sta.valid_links = old_links;
sta_remove_link(sta, link_id, false);
return ret;
}
hash:
ret = link_sta_info_hash_add(sdata->local, link_sta);
WARN_ON(ret);
return 0;
}
void ieee80211_sta_remove_link(struct sta_info *sta, unsigned int link_id)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
u16 old_links = sta->sta.valid_links;
lockdep_assert_wiphy(sdata->local->hw.wiphy);
sta->sta.valid_links &= ~BIT(link_id);
if (!WARN_ON(!test_sta_flag(sta, WLAN_STA_INSERTED)))
drv_change_sta_links(sdata->local, sdata, &sta->sta,
old_links, sta->sta.valid_links);
sta_remove_link(sta, link_id, true);
}
void ieee80211_sta_set_max_amsdu_subframes(struct sta_info *sta,
const u8 *ext_capab,
unsigned int ext_capab_len)
{
u8 val;
sta->sta.max_amsdu_subframes = 0;
if (ext_capab_len < 8)
return;
/* The sender might not have sent the last bit, consider it to be 0 */
val = u8_get_bits(ext_capab[7], WLAN_EXT_CAPA8_MAX_MSDU_IN_AMSDU_LSB);
/* we did get all the bits, take the MSB as well */
if (ext_capab_len >= 9)
val |= u8_get_bits(ext_capab[8],
WLAN_EXT_CAPA9_MAX_MSDU_IN_AMSDU_MSB) << 1;
if (val)
sta->sta.max_amsdu_subframes = 4 << (4 - val);
}
#ifdef CONFIG_LOCKDEP
bool lockdep_sta_mutex_held(struct ieee80211_sta *pubsta)
{
struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
return lockdep_is_held(&sta->local->hw.wiphy->mtx);
}
EXPORT_SYMBOL(lockdep_sta_mutex_held);
#endif