// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2024-2025 Intel Corporation
*/
#include <linux/ieee80211.h>
#include <kunit/static_stub.h>
#include "sta.h"
#include "hcmd.h"
#include "iface.h"
#include "mlo.h"
#include "key.h"
#include "agg.h"
#include "tlc.h"
#include "fw/api/sta.h"
#include "fw/api/mac.h"
#include "fw/api/rx.h"
int iwl_mld_fw_sta_id_from_link_sta(struct iwl_mld *mld,
struct ieee80211_link_sta *link_sta)
{
struct iwl_mld_link_sta *mld_link_sta;
/* This function should only be used with the wiphy lock held,
* In other cases, it is not guaranteed that the link_sta will exist
* in the driver too, and it is checked here.
*/
lockdep_assert_wiphy(mld->wiphy);
/* This is not meant to be called with a NULL pointer */
if (WARN_ON(!link_sta))
return -ENOENT;
mld_link_sta = iwl_mld_link_sta_from_mac80211(link_sta);
if (!mld_link_sta) {
WARN_ON(!iwl_mld_error_before_recovery(mld));
return -ENOENT;
}
return mld_link_sta->fw_id;
}
static void
iwl_mld_fill_ampdu_size_and_dens(struct ieee80211_link_sta *link_sta,
struct ieee80211_bss_conf *link,
__le32 *tx_ampdu_max_size,
__le32 *tx_ampdu_spacing)
{
u32 agg_size = 0, mpdu_dens = 0;
if (WARN_ON(!link_sta || !link))
return;
/* Note that we always use only legacy & highest supported PPDUs, so
* of Draft P802.11be D.30 Table 10-12a--Fields used for calculating
* the maximum A-MPDU size of various PPDU types in different bands,
* we only need to worry about the highest supported PPDU type here.
*/
if (link_sta->ht_cap.ht_supported) {
agg_size = link_sta->ht_cap.ampdu_factor;
mpdu_dens = link_sta->ht_cap.ampdu_density;
}
if (link->chanreq.oper.chan->band == NL80211_BAND_6GHZ) {
/* overwrite HT values on 6 GHz */
mpdu_dens =
le16_get_bits(link_sta->he_6ghz_capa.capa,
IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START);
agg_size =
le16_get_bits(link_sta->he_6ghz_capa.capa,
IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP);
} else if (link_sta->vht_cap.vht_supported) {
/* if VHT supported overwrite HT value */
agg_size =
u32_get_bits(link_sta->vht_cap.cap,
IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK);
}
/* D6.0 10.12.2 A-MPDU length limit rules
* A STA indicates the maximum length of the A-MPDU preEOF padding
* that it can receive in an HE PPDU in the Maximum A-MPDU Length
* Exponent field in its HT Capabilities, VHT Capabilities,
* and HE 6 GHz Band Capabilities elements (if present) and the
* Maximum AMPDU Length Exponent Extension field in its HE
* Capabilities element
*/
if (link_sta->he_cap.has_he)
agg_size +=
u8_get_bits(link_sta->he_cap.he_cap_elem.mac_cap_info[3],
IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK);
if (link_sta->eht_cap.has_eht)
agg_size +=
u8_get_bits(link_sta->eht_cap.eht_cap_elem.mac_cap_info[1],
IEEE80211_EHT_MAC_CAP1_MAX_AMPDU_LEN_MASK);
/* Limit to max A-MPDU supported by FW */
agg_size = min_t(u32, agg_size,
STA_FLG_MAX_AGG_SIZE_4M >> STA_FLG_MAX_AGG_SIZE_SHIFT);
*tx_ampdu_max_size = cpu_to_le32(agg_size);
*tx_ampdu_spacing = cpu_to_le32(mpdu_dens);
}
static u8 iwl_mld_get_uapsd_acs(struct ieee80211_sta *sta)
{
u8 uapsd_acs = 0;
if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK)
uapsd_acs |= BIT(AC_BK);
if (sta