1
0
mirror of https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git synced 2026-01-12 01:20:14 +00:00

More -next material, notably:

- split ieee80211.h file, it's way too big
  - mac80211: initial chanctx work towards NAN
  - mac80211: MU-MIMO sniffer improvements
  - ath12k: statistics improvements
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEpeA8sTs3M8SN2hR410qiO8sPaAAFAmkUdDsACgkQ10qiO8sP
 aABeDhAAnBtrADnRQYo5BMbV6/7JsJL3GV6Zj5/Nrq6si8TE8vquf4kevUbISpgk
 Mi2tQ0UxFTW6LckT3LTOxzQSZzaPANSPO9AQm/q9/BLtAsdPpgc8yHQTkZlkiatF
 dS+WZFSZpF8hisKmkYCDvnggaqipnJUvnwtIY6xxSZftn3J4h6B9Wp+XjyCLtDxC
 2DvztdQJ3oqYBFsSpk6J0gA0/4lF+jlVmZ+DPpVSYlCRJivFAqcpwdx3vdh4Pib3
 dUNgh/MJuPv01RIA783TCsHBnOKPxuD5OfusQzkXdj33yX2bcPL6M2s57FgnFf8q
 l4B9+R/Q7/8ohp+qMOd4S+SteFa/7WlbJ+5UjJ71y7xScBKOaRZMf6wKKqSZozP1
 zOB4AxlC7COrL3tsljC0Vun9CgBL4Ov/XBe7G2WTOUIrZ2KOU328/3atndbLeVJg
 knwsiNdKJCJJpTkO3zHzaYfDhDghSaINj1fl67hZV7s3Jj7u4lAD8HfV/9CKoMRd
 X1ltgB84u/nFc2aL2fGQbQg7NJLVqIvyx6iyss6K58nNwQMf0ZFUJOihgkSMCRK3
 t4qQrXVdorWnRvioA/roHICkGBZdZw53Jz+0EltRxsjTfmzkki6EbXeGhWtRzlSo
 5Bx1L4vtK7143nMlD2H/JuwDopD1fOxAM8L3sTlqJE8nu/3plPA=
 =N5Tm
 -----END PGP SIGNATURE-----

Merge tag 'wireless-next-2025-11-12' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next

Johannes Berg says:

====================
More -next material, notably:
 - split ieee80211.h file, it's way too big
 - mac80211: initial chanctx work towards NAN
 - mac80211: MU-MIMO sniffer improvements
 - ath12k: statistics improvements

* tag 'wireless-next-2025-11-12' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next: (26 commits)
  wifi: cw1200: Fix potential memory leak in cw1200_bh_rx_helper()
  wifi: mac80211: make monitor link info check more specific
  wifi: mac80211: track MU-MIMO configuration on disabled interfaces
  wifi: cfg80211/mac80211: Add fallback mechanism for INDOOR_SP connection
  wifi: cfg80211/mac80211: clean up duplicate ap_power handling
  wifi: cfg80211: use a C99 initializer in wiphy_register
  wifi: cfg80211: fix doc of struct key_params
  wifi: mac80211: remove unnecessary vlan NULL check
  wifi: mac80211: pass frame type to element parsing
  wifi: mac80211: remove "disabling VHT" message
  wifi: mac80211: add and use chanctx usage iteration
  wifi: mac80211: simplify ieee80211_recalc_chanctx_min_def() API
  wifi: mac80211: remove chanctx to link back-references
  wifi: mac80211: make link iteration safe for 'break'
  wifi: mac80211: fix EHT typo
  wifi: cfg80211: fix EHT typo
  wifi: ieee80211: split NAN definitions out
  wifi: ieee80211: split P2P definitions out
  wifi: ieee80211: split S1G definitions out
  wifi: ieee80211: split EHT definitions out
  ...
====================

Link: https://patch.msgid.link/20251112115126.16223-4-johannes@sipsolutions.net
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2025-11-12 09:33:23 -08:00
commit e949824730
40 changed files with 4003 additions and 3653 deletions

View File

@ -1,7 +1,6 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
@ -1250,7 +1249,6 @@ void ath12k_fw_stats_reset(struct ath12k *ar)
spin_lock_bh(&ar->data_lock);
ath12k_fw_stats_free(&ar->fw_stats);
ar->fw_stats.num_vdev_recvd = 0;
ar->fw_stats.num_bcn_recvd = 0;
spin_unlock_bh(&ar->data_lock);
}

View File

@ -646,7 +646,6 @@ struct ath12k_fw_stats {
struct list_head vdevs;
struct list_head bcn;
u32 num_vdev_recvd;
u32 num_bcn_recvd;
};
struct ath12k_dbg_htt_stats {

View File

@ -1286,6 +1286,7 @@ static int ath12k_open_vdev_stats(struct inode *inode, struct file *file)
ath12k_wmi_fw_stats_dump(ar, &ar->fw_stats, param.stats_id,
buf);
ath12k_fw_stats_reset(ar);
file->private_data = no_free_ptr(buf);
@ -1352,12 +1353,7 @@ static int ath12k_open_bcn_stats(struct inode *inode, struct file *file)
ath12k_wmi_fw_stats_dump(ar, &ar->fw_stats, param.stats_id,
buf);
/* since beacon stats request is looped for all active VDEVs, saved fw
* stats is not freed for each request until done for all active VDEVs
*/
spin_lock_bh(&ar->data_lock);
ath12k_fw_stats_bcn_free(&ar->fw_stats.bcn);
spin_unlock_bh(&ar->data_lock);
ath12k_fw_stats_reset(ar);
file->private_data = no_free_ptr(buf);
@ -1418,6 +1414,7 @@ static int ath12k_open_pdev_stats(struct inode *inode, struct file *file)
ath12k_wmi_fw_stats_dump(ar, &ar->fw_stats, param.stats_id,
buf);
ath12k_fw_stats_reset(ar);
file->private_data = no_free_ptr(buf);

View File

@ -5079,8 +5079,6 @@ int ath12k_mac_get_fw_stats(struct ath12k *ar,
if (ah->state != ATH12K_HW_STATE_ON)
return -ENETDOWN;
ath12k_fw_stats_reset(ar);
reinit_completion(&ar->fw_stats_complete);
reinit_completion(&ar->fw_stats_done);
@ -5178,6 +5176,7 @@ static int ath12k_mac_op_get_txpower(struct ieee80211_hw *hw,
ar->chan_tx_pwr = pdev->chan_tx_power / 2;
spin_unlock_bh(&ar->data_lock);
ar->last_tx_power_update = jiffies;
ath12k_fw_stats_reset(ar);
send_tx_power:
*dbm = ar->chan_tx_pwr;
@ -13208,14 +13207,18 @@ static void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw,
if (!signal &&
ahsta->ahvif->vdev_type == WMI_VDEV_TYPE_STA &&
!(ath12k_mac_get_fw_stats(ar, &params)))
!(ath12k_mac_get_fw_stats(ar, &params))) {
signal = arsta->rssi_beacon;
ath12k_fw_stats_reset(ar);
}
params.stats_id = WMI_REQUEST_RSSI_PER_CHAIN_STAT;
if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL)) &&
ahsta->ahvif->vdev_type == WMI_VDEV_TYPE_STA &&
!(ath12k_mac_get_fw_stats(ar, &params)))
!(ath12k_mac_get_fw_stats(ar, &params))) {
ath12k_mac_put_chain_rssi(sinfo, arsta);
ath12k_fw_stats_reset(ar);
}
spin_lock_bh(&ar->data_lock);
noise_floor = ath12k_pdev_get_noise_floor(ar);
@ -13299,8 +13302,10 @@ static void ath12k_mac_op_link_sta_statistics(struct ieee80211_hw *hw,
if (!signal &&
ahsta->ahvif->vdev_type == WMI_VDEV_TYPE_STA &&
!(ath12k_mac_get_fw_stats(ar, &params)))
!(ath12k_mac_get_fw_stats(ar, &params))) {
signal = arsta->rssi_beacon;
ath12k_fw_stats_reset(ar);
}
if (signal) {
link_sinfo->signal =

View File

@ -8089,8 +8089,6 @@ void ath12k_wmi_fw_stats_dump(struct ath12k *ar,
buf[len - 1] = 0;
else
buf[len] = 0;
ath12k_fw_stats_reset(ar);
}
static void
@ -8487,18 +8485,10 @@ static void ath12k_wmi_fw_stats_process(struct ath12k *ar,
ath12k_warn(ab, "empty beacon stats");
return;
}
/* Mark end until we reached the count of all started VDEVs
* within the PDEV
*/
if (ar->num_started_vdevs)
is_end = ((++ar->fw_stats.num_bcn_recvd) ==
ar->num_started_vdevs);
list_splice_tail_init(&stats->bcn,
&ar->fw_stats.bcn);
if (is_end)
complete(&ar->fw_stats_done);
complete(&ar->fw_stats_done);
}
}

View File

@ -317,10 +317,12 @@ static int cw1200_bh_rx_helper(struct cw1200_common *priv,
if (wsm_id & 0x0400) {
int rc = wsm_release_tx_buffer(priv, 1);
if (WARN_ON(rc < 0))
if (WARN_ON(rc < 0)) {
dev_kfree_skb(skb_rx);
return rc;
else if (rc > 0)
} else if (rc > 0) {
*tx = 1;
}
}
/* cw1200_wsm_rx takes care on SKB livetime */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,824 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* IEEE 802.11 HE definitions
*
* Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
* <jkmaline@cc.hut.fi>
* Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
* Copyright (c) 2005, Devicescape Software, Inc.
* Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
* Copyright (c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright (c) 2016 - 2017 Intel Deutschland GmbH
* Copyright (c) 2018 - 2025 Intel Corporation
*/
#ifndef LINUX_IEEE80211_HE_H
#define LINUX_IEEE80211_HE_H
#include <linux/types.h>
#include <linux/if_ether.h>
#define IEEE80211_TWT_CONTROL_NDP BIT(0)
#define IEEE80211_TWT_CONTROL_RESP_MODE BIT(1)
#define IEEE80211_TWT_CONTROL_NEG_TYPE_BROADCAST BIT(3)
#define IEEE80211_TWT_CONTROL_RX_DISABLED BIT(4)
#define IEEE80211_TWT_CONTROL_WAKE_DUR_UNIT BIT(5)
#define IEEE80211_TWT_REQTYPE_REQUEST BIT(0)
#define IEEE80211_TWT_REQTYPE_SETUP_CMD GENMASK(3, 1)
#define IEEE80211_TWT_REQTYPE_TRIGGER BIT(4)
#define IEEE80211_TWT_REQTYPE_IMPLICIT BIT(5)
#define IEEE80211_TWT_REQTYPE_FLOWTYPE BIT(6)
#define IEEE80211_TWT_REQTYPE_FLOWID GENMASK(9, 7)
#define IEEE80211_TWT_REQTYPE_WAKE_INT_EXP GENMASK(14, 10)
#define IEEE80211_TWT_REQTYPE_PROTECTION BIT(15)
enum ieee80211_twt_setup_cmd {
TWT_SETUP_CMD_REQUEST,
TWT_SETUP_CMD_SUGGEST,
TWT_SETUP_CMD_DEMAND,
TWT_SETUP_CMD_GROUPING,
TWT_SETUP_CMD_ACCEPT,
TWT_SETUP_CMD_ALTERNATE,
TWT_SETUP_CMD_DICTATE,
TWT_SETUP_CMD_REJECT,
};
struct ieee80211_twt_params {
__le16 req_type;
__le64 twt;
u8 min_twt_dur;
__le16 mantissa;
u8 channel;
} __packed;
struct ieee80211_twt_setup {
u8 dialog_token;
u8 element_id;
u8 length;
u8 control;
u8 params[];
} __packed;
/**
* struct ieee80211_he_cap_elem - HE capabilities element
* @mac_cap_info: HE MAC Capabilities Information
* @phy_cap_info: HE PHY Capabilities Information
*
* This structure represents the fixed fields of the payload of the
* "HE capabilities element" as described in IEEE Std 802.11ax-2021
* sections 9.4.2.248.2 and 9.4.2.248.3.
*/
struct ieee80211_he_cap_elem {
u8 mac_cap_info[6];
u8 phy_cap_info[11];
} __packed;
#define IEEE80211_TX_RX_MCS_NSS_DESC_MAX_LEN 5
/**
* enum ieee80211_he_mcs_support - HE MCS support definitions
* @IEEE80211_HE_MCS_SUPPORT_0_7: MCSes 0-7 are supported for the
* number of streams
* @IEEE80211_HE_MCS_SUPPORT_0_9: MCSes 0-9 are supported
* @IEEE80211_HE_MCS_SUPPORT_0_11: MCSes 0-11 are supported
* @IEEE80211_HE_MCS_NOT_SUPPORTED: This number of streams isn't supported
*
* These definitions are used in each 2-bit subfield of the rx_mcs_*
* and tx_mcs_* fields of &struct ieee80211_he_mcs_nss_supp, which are
* both split into 8 subfields by number of streams. These values indicate
* which MCSes are supported for the number of streams the value appears
* for.
*/
enum ieee80211_he_mcs_support {
IEEE80211_HE_MCS_SUPPORT_0_7 = 0,
IEEE80211_HE_MCS_SUPPORT_0_9 = 1,
IEEE80211_HE_MCS_SUPPORT_0_11 = 2,
IEEE80211_HE_MCS_NOT_SUPPORTED = 3,
};
/**
* struct ieee80211_he_mcs_nss_supp - HE Tx/Rx HE MCS NSS Support Field
*
* This structure holds the data required for the Tx/Rx HE MCS NSS Support Field
* described in P802.11ax_D2.0 section 9.4.2.237.4
*
* @rx_mcs_80: Rx MCS map 2 bits for each stream, total 8 streams, for channel
* widths less than 80MHz.
* @tx_mcs_80: Tx MCS map 2 bits for each stream, total 8 streams, for channel
* widths less than 80MHz.
* @rx_mcs_160: Rx MCS map 2 bits for each stream, total 8 streams, for channel
* width 160MHz.
* @tx_mcs_160: Tx MCS map 2 bits for each stream, total 8 streams, for channel
* width 160MHz.
* @rx_mcs_80p80: Rx MCS map 2 bits for each stream, total 8 streams, for
* channel width 80p80MHz.
* @tx_mcs_80p80: Tx MCS map 2 bits for each stream, total 8 streams, for
* channel width 80p80MHz.
*/
struct ieee80211_he_mcs_nss_supp {
__le16 rx_mcs_80;
__le16 tx_mcs_80;
__le16 rx_mcs_160;
__le16 tx_mcs_160;
__le16 rx_mcs_80p80;
__le16 tx_mcs_80p80;
} __packed;
/**
* struct ieee80211_he_operation - HE Operation element
* @he_oper_params: HE Operation Parameters + BSS Color Information
* @he_mcs_nss_set: Basic HE-MCS And NSS Set
* @optional: Optional fields VHT Operation Information, Max Co-Hosted
* BSSID Indicator, and 6 GHz Operation Information
*
* This structure represents the payload of the "HE Operation
* element" as described in IEEE Std 802.11ax-2021 section 9.4.2.249.
*/
struct ieee80211_he_operation {
__le32 he_oper_params;
__le16 he_mcs_nss_set;
u8 optional[];
} __packed;
/**
* struct ieee80211_he_spr - Spatial Reuse Parameter Set element
* @he_sr_control: SR Control
* @optional: Optional fields Non-SRG OBSS PD Max Offset, SRG OBSS PD
* Min Offset, SRG OBSS PD Max Offset, SRG BSS Color
* Bitmap, and SRG Partial BSSID Bitmap
*
* This structure represents the payload of the "Spatial Reuse
* Parameter Set element" as described in IEEE Std 802.11ax-2021
* section 9.4.2.252.
*/
struct ieee80211_he_spr {
u8 he_sr_control;
u8 optional[];
} __packed;
/**
* struct ieee80211_he_mu_edca_param_ac_rec - MU AC Parameter Record field
* @aifsn: ACI/AIFSN
* @ecw_min_max: ECWmin/ECWmax
* @mu_edca_timer: MU EDCA Timer
*
* This structure represents the "MU AC Parameter Record" as described
* in IEEE Std 802.11ax-2021 section 9.4.2.251, Figure 9-788p.
*/
struct ieee80211_he_mu_edca_param_ac_rec {
u8 aifsn;
u8 ecw_min_max;
u8 mu_edca_timer;
} __packed;
/**
* struct ieee80211_mu_edca_param_set - MU EDCA Parameter Set element
* @mu_qos_info: QoS Info
* @ac_be: MU AC_BE Parameter Record
* @ac_bk: MU AC_BK Parameter Record
* @ac_vi: MU AC_VI Parameter Record
* @ac_vo: MU AC_VO Parameter Record
*
* This structure represents the payload of the "MU EDCA Parameter Set
* element" as described in IEEE Std 802.11ax-2021 section 9.4.2.251.
*/
struct ieee80211_mu_edca_param_set {
u8 mu_qos_info;
struct ieee80211_he_mu_edca_param_ac_rec ac_be;
struct ieee80211_he_mu_edca_param_ac_rec ac_bk;
struct ieee80211_he_mu_edca_param_ac_rec ac_vi;
struct ieee80211_he_mu_edca_param_ac_rec ac_vo;
} __packed;
/* 802.11ax HE MAC capabilities */
#define IEEE80211_HE_MAC_CAP0_HTC_HE 0x01
#define IEEE80211_HE_MAC_CAP0_TWT_REQ 0x02
#define IEEE80211_HE_MAC_CAP0_TWT_RES 0x04
#define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_NOT_SUPP 0x00
#define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_LEVEL_1 0x08
#define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_LEVEL_2 0x10
#define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_LEVEL_3 0x18
#define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_MASK 0x18
#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_1 0x00
#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_2 0x20
#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_4 0x40
#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_8 0x60
#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_16 0x80
#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_32 0xa0
#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_64 0xc0
#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_UNLIMITED 0xe0
#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_MASK 0xe0
#define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_UNLIMITED 0x00
#define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_128 0x01
#define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_256 0x02
#define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_512 0x03
#define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_MASK 0x03
#define IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_0US 0x00
#define IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_8US 0x04
#define IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US 0x08
#define IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_MASK 0x0c
#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_1 0x00
#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_2 0x10
#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_3 0x20
#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_4 0x30
#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_5 0x40
#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_6 0x50
#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_7 0x60
#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8 0x70
#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_MASK 0x70
/* Link adaptation is split between byte HE_MAC_CAP1 and
* HE_MAC_CAP2. It should be set only if IEEE80211_HE_MAC_CAP0_HTC_HE
* in which case the following values apply:
* 0 = No feedback.
* 1 = reserved.
* 2 = Unsolicited feedback.
* 3 = both
*/
#define IEEE80211_HE_MAC_CAP1_LINK_ADAPTATION 0x80
#define IEEE80211_HE_MAC_CAP2_LINK_ADAPTATION 0x01
#define IEEE80211_HE_MAC_CAP2_ALL_ACK 0x02
#define IEEE80211_HE_MAC_CAP2_TRS 0x04
#define IEEE80211_HE_MAC_CAP2_BSR 0x08
#define IEEE80211_HE_MAC_CAP2_BCAST_TWT 0x10
#define IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP 0x20
#define IEEE80211_HE_MAC_CAP2_MU_CASCADING 0x40
#define IEEE80211_HE_MAC_CAP2_ACK_EN 0x80
#define IEEE80211_HE_MAC_CAP3_OMI_CONTROL 0x02
#define IEEE80211_HE_MAC_CAP3_OFDMA_RA 0x04
/* The maximum length of an A-MDPU is defined by the combination of the Maximum
* A-MDPU Length Exponent field in the HT capabilities, VHT capabilities and the
* same field in the HE capabilities.
*/
#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_0 0x00
#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_1 0x08
#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_2 0x10
#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3 0x18
#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK 0x18
#define IEEE80211_HE_MAC_CAP3_AMSDU_FRAG 0x20
#define IEEE80211_HE_MAC_CAP3_FLEX_TWT_SCHED 0x40
#define IEEE80211_HE_MAC_CAP3_RX_CTRL_FRAME_TO_MULTIBSS 0x80
#define IEEE80211_HE_MAC_CAP4_BSRP_BQRP_A_MPDU_AGG 0x01
#define IEEE80211_HE_MAC_CAP4_QTP 0x02
#define IEEE80211_HE_MAC_CAP4_BQR 0x04
#define IEEE80211_HE_MAC_CAP4_PSR_RESP 0x08
#define IEEE80211_HE_MAC_CAP4_NDP_FB_REP 0x10
#define IEEE80211_HE_MAC_CAP4_OPS 0x20
#define IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU 0x40
/* Multi TID agg TX is split between byte #4 and #5
* The value is a combination of B39,B40,B41
*/
#define IEEE80211_HE_MAC_CAP4_MULTI_TID_AGG_TX_QOS_B39 0x80
#define IEEE80211_HE_MAC_CAP5_MULTI_TID_AGG_TX_QOS_B40 0x01
#define IEEE80211_HE_MAC_CAP5_MULTI_TID_AGG_TX_QOS_B41 0x02
#define IEEE80211_HE_MAC_CAP5_SUBCHAN_SELECTIVE_TRANSMISSION 0x04
#define IEEE80211_HE_MAC_CAP5_UL_2x996_TONE_RU 0x08
#define IEEE80211_HE_MAC_CAP5_OM_CTRL_UL_MU_DATA_DIS_RX 0x10
#define IEEE80211_HE_MAC_CAP5_HE_DYNAMIC_SM_PS 0x20
#define IEEE80211_HE_MAC_CAP5_PUNCTURED_SOUNDING 0x40
#define IEEE80211_HE_MAC_CAP5_HT_VHT_TRIG_FRAME_RX 0x80
#define IEEE80211_HE_VHT_MAX_AMPDU_FACTOR 20
#define IEEE80211_HE_HT_MAX_AMPDU_FACTOR 16
#define IEEE80211_HE_6GHZ_MAX_AMPDU_FACTOR 13
/* 802.11ax HE PHY capabilities */
#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G 0x02
#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G 0x04
#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G 0x08
#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G 0x10
#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK_ALL 0x1e
#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G 0x20
#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G 0x40
#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK 0xfe
#define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_80MHZ_ONLY_SECOND_20MHZ 0x01
#define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_80MHZ_ONLY_SECOND_40MHZ 0x02
#define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_160MHZ_ONLY_SECOND_20MHZ 0x04
#define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_160MHZ_ONLY_SECOND_40MHZ 0x08
#define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK 0x0f
#define IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A 0x10
#define IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD 0x20
#define IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US 0x40
/* Midamble RX/TX Max NSTS is split between byte #2 and byte #3 */
#define IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS 0x80
#define IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_TX_MAX_NSTS 0x01
#define IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US 0x02
#define IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ 0x04
#define IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ 0x08
#define IEEE80211_HE_PHY_CAP2_DOPPLER_TX 0x10
#define IEEE80211_HE_PHY_CAP2_DOPPLER_RX 0x20
/* Note that the meaning of UL MU below is different between an AP and a non-AP
* sta, where in the AP case it indicates support for Rx and in the non-AP sta
* case it indicates support for Tx.
*/
#define IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO 0x40
#define IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO 0x80
#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_NO_DCM 0x00
#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_BPSK 0x01
#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK 0x02
#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_16_QAM 0x03
#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_MASK 0x03
#define IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_1 0x00
#define IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_2 0x04
#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_NO_DCM 0x00
#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_BPSK 0x08
#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK 0x10
#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM 0x18
#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_MASK 0x18
#define IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1 0x00
#define IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_2 0x20
#define IEEE80211_HE_PHY_CAP3_RX_PARTIAL_BW_SU_IN_20MHZ_MU 0x40
#define IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER 0x80
#define IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE 0x01
#define IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER 0x02
/* Minimal allowed value of Max STS under 80MHz is 3 */
#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4 0x0c
#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_5 0x10
#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_6 0x14
#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_7 0x18
#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_8 0x1c
#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_MASK 0x1c
/* Minimal allowed value of Max STS above 80MHz is 3 */
#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4 0x60
#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_5 0x80
#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_6 0xa0
#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_7 0xc0
#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_8 0xe0
#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_MASK 0xe0
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_1 0x00
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2 0x01
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_3 0x02
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_4 0x03
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_5 0x04
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_6 0x05
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_7 0x06
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_8 0x07
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK 0x07
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_1 0x00
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2 0x08
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_3 0x10
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_4 0x18
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_5 0x20
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_6 0x28
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_7 0x30
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_8 0x38
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK 0x38
#define IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK 0x40
#define IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK 0x80
#define IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU 0x01
#define IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU 0x02
#define IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB 0x04
#define IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB 0x08
#define IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB 0x10
#define IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE 0x20
#define IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO 0x40
#define IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT 0x80
#define IEEE80211_HE_PHY_CAP7_PSR_BASED_SR 0x01
#define IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP 0x02
#define IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI 0x04
#define IEEE80211_HE_PHY_CAP7_MAX_NC_1 0x08
#define IEEE80211_HE_PHY_CAP7_MAX_NC_2 0x10
#define IEEE80211_HE_PHY_CAP7_MAX_NC_3 0x18
#define IEEE80211_HE_PHY_CAP7_MAX_NC_4 0x20
#define IEEE80211_HE_PHY_CAP7_MAX_NC_5 0x28
#define IEEE80211_HE_PHY_CAP7_MAX_NC_6 0x30
#define IEEE80211_HE_PHY_CAP7_MAX_NC_7 0x38
#define IEEE80211_HE_PHY_CAP7_MAX_NC_MASK 0x38
#define IEEE80211_HE_PHY_CAP7_STBC_TX_ABOVE_80MHZ 0x40
#define IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ 0x80
#define IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI 0x01
#define IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G 0x02
#define IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU 0x04
#define IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU 0x08
#define IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI 0x10
#define IEEE80211_HE_PHY_CAP8_MIDAMBLE_RX_TX_2X_AND_1XLTF 0x20
#define IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_242 0x00
#define IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_484 0x40
#define IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_996 0x80
#define IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_2x996 0xc0
#define IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_MASK 0xc0
#define IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM 0x01
#define IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK 0x02
#define IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU 0x04
#define IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU 0x08
#define IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB 0x10
#define IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB 0x20
#define IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_0US 0x0
#define IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_8US 0x1
#define IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US 0x2
#define IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_RESERVED 0x3
#define IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_POS 6
#define IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK 0xc0
#define IEEE80211_HE_PHY_CAP10_HE_MU_M1RU_MAX_LTF 0x01
/* 802.11ax HE TX/RX MCS NSS Support */
#define IEEE80211_TX_RX_MCS_NSS_SUPP_HIGHEST_MCS_POS (3)
#define IEEE80211_TX_RX_MCS_NSS_SUPP_TX_BITMAP_POS (6)
#define IEEE80211_TX_RX_MCS_NSS_SUPP_RX_BITMAP_POS (11)
#define IEEE80211_TX_RX_MCS_NSS_SUPP_TX_BITMAP_MASK 0x07c0
#define IEEE80211_TX_RX_MCS_NSS_SUPP_RX_BITMAP_MASK 0xf800
/* TX/RX HE MCS Support field Highest MCS subfield encoding */
enum ieee80211_he_highest_mcs_supported_subfield_enc {
HIGHEST_MCS_SUPPORTED_MCS7 = 0,
HIGHEST_MCS_SUPPORTED_MCS8,
HIGHEST_MCS_SUPPORTED_MCS9,
HIGHEST_MCS_SUPPORTED_MCS10,
HIGHEST_MCS_SUPPORTED_MCS11,
};
/* Calculate 802.11ax HE capabilities IE Tx/Rx HE MCS NSS Support Field size */
static inline u8
ieee80211_he_mcs_nss_size(const struct ieee80211_he_cap_elem *he_cap)
{
u8 count = 4;
if (he_cap->phy_cap_info[0] &
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G)
count += 4;
if (he_cap->phy_cap_info[0] &
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)
count += 4;
return count;
}
/* 802.11ax HE PPE Thresholds */
#define IEEE80211_PPE_THRES_NSS_SUPPORT_2NSS (1)
#define IEEE80211_PPE_THRES_NSS_POS (0)
#define IEEE80211_PPE_THRES_NSS_MASK (7)
#define IEEE80211_PPE_THRES_RU_INDEX_BITMASK_2x966_AND_966_RU \
(BIT(5) | BIT(6))
#define IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK 0x78
#define IEEE80211_PPE_THRES_RU_INDEX_BITMASK_POS (3)
#define IEEE80211_PPE_THRES_INFO_PPET_SIZE (3)
#define IEEE80211_HE_PPE_THRES_INFO_HEADER_SIZE (7)
/*
* Calculate 802.11ax HE capabilities IE PPE field size
* Input: Header byte of ppe_thres (first byte), and HE capa IE's PHY cap u8*
*/
static inline u8
ieee80211_he_ppe_size(u8 ppe_thres_hdr, const u8 *phy_cap_info)
{
u8 n;
if ((phy_cap_info[6] &
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) == 0)
return 0;
n = hweight8(ppe_thres_hdr &
IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK);
n *= (1 + ((ppe_thres_hdr & IEEE80211_PPE_THRES_NSS_MASK) >>
IEEE80211_PPE_THRES_NSS_POS));
/*
* Each pair is 6 bits, and we need to add the 7 "header" bits to the
* total size.
*/
n = (n * IEEE80211_PPE_THRES_INFO_PPET_SIZE * 2) + 7;
n = DIV_ROUND_UP(n, 8);
return n;
}
static inline bool ieee80211_he_capa_size_ok(const u8 *data, u8 len)
{
const struct ieee80211_he_cap_elem *he_cap_ie_elem = (const void *)data;
u8 needed = sizeof(*he_cap_ie_elem);
if (len < needed)
return false;
needed += ieee80211_he_mcs_nss_size(he_cap_ie_elem);
if (len < needed)
return false;
if (he_cap_ie_elem->phy_cap_info[6] &
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) {
if (len < needed + 1)
return false;
needed += ieee80211_he_ppe_size(data[needed],
he_cap_ie_elem->phy_cap_info);
}
return len >= needed;
}
/* HE Operation defines */
#define IEEE80211_HE_OPERATION_DFLT_PE_DURATION_MASK 0x00000007
#define IEEE80211_HE_OPERATION_TWT_REQUIRED 0x00000008
#define IEEE80211_HE_OPERATION_RTS_THRESHOLD_MASK 0x00003ff0
#define IEEE80211_HE_OPERATION_RTS_THRESHOLD_OFFSET 4
#define IEEE80211_HE_OPERATION_VHT_OPER_INFO 0x00004000
#define IEEE80211_HE_OPERATION_CO_HOSTED_BSS 0x00008000
#define IEEE80211_HE_OPERATION_ER_SU_DISABLE 0x00010000
#define IEEE80211_HE_OPERATION_6GHZ_OP_INFO 0x00020000
#define IEEE80211_HE_OPERATION_BSS_COLOR_MASK 0x3f000000
#define IEEE80211_HE_OPERATION_BSS_COLOR_OFFSET 24
#define IEEE80211_HE_OPERATION_PARTIAL_BSS_COLOR 0x40000000
#define IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED 0x80000000
#define IEEE80211_6GHZ_CTRL_REG_LPI_AP 0
#define IEEE80211_6GHZ_CTRL_REG_SP_AP 1
#define IEEE80211_6GHZ_CTRL_REG_VLP_AP 2
#define IEEE80211_6GHZ_CTRL_REG_INDOOR_LPI_AP 3
#define IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP_OLD 4
#define IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP 8
/**
* struct ieee80211_he_6ghz_oper - HE 6 GHz operation Information field
* @primary: primary channel
* @control: control flags
* @ccfs0: channel center frequency segment 0
* @ccfs1: channel center frequency segment 1
* @minrate: minimum rate (in 1 Mbps units)
*/
struct ieee80211_he_6ghz_oper {
u8 primary;
#define IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH 0x3
#define IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_20MHZ 0
#define IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_40MHZ 1
#define IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_80MHZ 2
#define IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_160MHZ 3
#define IEEE80211_HE_6GHZ_OPER_CTRL_DUP_BEACON 0x4
#define IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO 0x78
u8 control;
u8 ccfs0;
u8 ccfs1;
u8 minrate;
} __packed;
/**
* enum ieee80211_reg_conn_bits - represents Regulatory connectivity field bits.
*
* This enumeration defines bit flags used to represent regulatory connectivity
* field bits.
*
* @IEEE80211_REG_CONN_LPI_VALID: Indicates whether the LPI bit is valid.
* @IEEE80211_REG_CONN_LPI_VALUE: Represents the value of the LPI bit.
* @IEEE80211_REG_CONN_SP_VALID: Indicates whether the SP bit is valid.
* @IEEE80211_REG_CONN_SP_VALUE: Represents the value of the SP bit.
*/
enum ieee80211_reg_conn_bits {
IEEE80211_REG_CONN_LPI_VALID = BIT(0),
IEEE80211_REG_CONN_LPI_VALUE = BIT(1),
IEEE80211_REG_CONN_SP_VALID = BIT(2),
IEEE80211_REG_CONN_SP_VALUE = BIT(3),
};
/* transmit power interpretation type of transmit power envelope element */
enum ieee80211_tx_power_intrpt_type {
IEEE80211_TPE_LOCAL_EIRP,
IEEE80211_TPE_LOCAL_EIRP_PSD,
IEEE80211_TPE_REG_CLIENT_EIRP,
IEEE80211_TPE_REG_CLIENT_EIRP_PSD,
};
/* category type of transmit power envelope element */
enum ieee80211_tx_power_category_6ghz {
IEEE80211_TPE_CAT_6GHZ_DEFAULT = 0,
IEEE80211_TPE_CAT_6GHZ_SUBORDINATE = 1,
};
/*
* For IEEE80211_TPE_LOCAL_EIRP / IEEE80211_TPE_REG_CLIENT_EIRP,
* setting to 63.5 dBm means no constraint.
*/
#define IEEE80211_TPE_MAX_TX_PWR_NO_CONSTRAINT 127
/*
* For IEEE80211_TPE_LOCAL_EIRP_PSD / IEEE80211_TPE_REG_CLIENT_EIRP_PSD,
* setting to 127 indicates no PSD limit for the 20 MHz channel.
*/
#define IEEE80211_TPE_PSD_NO_LIMIT 127
/**
* struct ieee80211_tx_pwr_env - Transmit Power Envelope
* @info: Transmit Power Information field
* @variable: Maximum Transmit Power field
*
* This structure represents the payload of the "Transmit Power
* Envelope element" as described in IEEE Std 802.11ax-2021 section
* 9.4.2.161
*/
struct ieee80211_tx_pwr_env {
u8 info;
u8 variable[];
} __packed;
#define IEEE80211_TX_PWR_ENV_INFO_COUNT 0x7
#define IEEE80211_TX_PWR_ENV_INFO_INTERPRET 0x38
#define IEEE80211_TX_PWR_ENV_INFO_CATEGORY 0xC0
#define IEEE80211_TX_PWR_ENV_EXT_COUNT 0xF
static inline bool ieee80211_valid_tpe_element(const u8 *data, u8 len)
{
const struct ieee80211_tx_pwr_env *env = (const void *)data;
u8 count, interpret, category;
u8 needed = sizeof(*env);
u8 N; /* also called N in the spec */
if (len < needed)
return false;
count = u8_get_bits(env->info, IEEE80211_TX_PWR_ENV_INFO_COUNT);
interpret = u8_get_bits(env->info, IEEE80211_TX_PWR_ENV_INFO_INTERPRET);
category = u8_get_bits(env->info, IEEE80211_TX_PWR_ENV_INFO_CATEGORY);
switch (category) {
case IEEE80211_TPE_CAT_6GHZ_DEFAULT:
case IEEE80211_TPE_CAT_6GHZ_SUBORDINATE:
break;
default:
return false;
}
switch (interpret) {
case IEEE80211_TPE_LOCAL_EIRP:
case IEEE80211_TPE_REG_CLIENT_EIRP:
if (count > 3)
return false;
/* count == 0 encodes 1 value for 20 MHz, etc. */
needed += count + 1;
if (len < needed)
return false;
/* there can be extension fields not accounted for in 'count' */
return true;
case IEEE80211_TPE_LOCAL_EIRP_PSD:
case IEEE80211_TPE_REG_CLIENT_EIRP_PSD:
if (count > 4)
return false;
N = count ? 1 << (count - 1) : 1;
needed += N;
if (len < needed)
return false;
if (len > needed) {
u8 K = u8_get_bits(env->variable[N],
IEEE80211_TX_PWR_ENV_EXT_COUNT);
needed += 1 + K;
if (len < needed)
return false;
}
return true;
}
return false;
}
/*
* ieee80211_he_oper_size - calculate 802.11ax HE Operations IE size
* @he_oper_ie: byte data of the He Operations IE, stating from the byte
* after the ext ID byte. It is assumed that he_oper_ie has at least
* sizeof(struct ieee80211_he_operation) bytes, the caller must have
* validated this.
* @return the actual size of the IE data (not including header), or 0 on error
*/
static inline u8
ieee80211_he_oper_size(const u8 *he_oper_ie)
{
const struct ieee80211_he_operation *he_oper = (const void *)he_oper_ie;
u8 oper_len = sizeof(struct ieee80211_he_operation);
u32 he_oper_params;
/* Make sure the input is not NULL */
if (!he_oper_ie)
return 0;
/* Calc required length */
he_oper_params = le32_to_cpu(he_oper->he_oper_params);
if (he_oper_params & IEEE80211_HE_OPERATION_VHT_OPER_INFO)
oper_len += 3;
if (he_oper_params & IEEE80211_HE_OPERATION_CO_HOSTED_BSS)
oper_len++;
if (he_oper_params & IEEE80211_HE_OPERATION_6GHZ_OP_INFO)
oper_len += sizeof(struct ieee80211_he_6ghz_oper);
/* Add the first byte (extension ID) to the total length */
oper_len++;
return oper_len;
}
/**
* ieee80211_he_6ghz_oper - obtain 6 GHz operation field
* @he_oper: HE operation element (must be pre-validated for size)
* but may be %NULL
*
* Return: a pointer to the 6 GHz operation field, or %NULL
*/
static inline const struct ieee80211_he_6ghz_oper *
ieee80211_he_6ghz_oper(const struct ieee80211_he_operation *he_oper)
{
const u8 *ret;
u32 he_oper_params;
if (!he_oper)
return NULL;
ret = (const void *)&he_oper->optional;
he_oper_params = le32_to_cpu(he_oper->he_oper_params);
if (!(he_oper_params & IEEE80211_HE_OPERATION_6GHZ_OP_INFO))
return NULL;
if (he_oper_params & IEEE80211_HE_OPERATION_VHT_OPER_INFO)
ret += 3;
if (he_oper_params & IEEE80211_HE_OPERATION_CO_HOSTED_BSS)
ret++;
return (const void *)ret;
}
/* HE Spatial Reuse defines */
#define IEEE80211_HE_SPR_PSR_DISALLOWED BIT(0)
#define IEEE80211_HE_SPR_NON_SRG_OBSS_PD_SR_DISALLOWED BIT(1)
#define IEEE80211_HE_SPR_NON_SRG_OFFSET_PRESENT BIT(2)
#define IEEE80211_HE_SPR_SRG_INFORMATION_PRESENT BIT(3)
#define IEEE80211_HE_SPR_HESIGA_SR_VAL15_ALLOWED BIT(4)
/*
* ieee80211_he_spr_size - calculate 802.11ax HE Spatial Reuse IE size
* @he_spr_ie: byte data of the He Spatial Reuse IE, stating from the byte
* after the ext ID byte. It is assumed that he_spr_ie has at least
* sizeof(struct ieee80211_he_spr) bytes, the caller must have validated
* this
* @return the actual size of the IE data (not including header), or 0 on error
*/
static inline u8
ieee80211_he_spr_size(const u8 *he_spr_ie)
{
const struct ieee80211_he_spr *he_spr = (const void *)he_spr_ie;
u8 spr_len = sizeof(struct ieee80211_he_spr);
u8 he_spr_params;
/* Make sure the input is not NULL */
if (!he_spr_ie)
return 0;
/* Calc required length */
he_spr_params = he_spr->he_sr_control;
if (he_spr_params & IEEE80211_HE_SPR_NON_SRG_OFFSET_PRESENT)
spr_len++;
if (he_spr_params & IEEE80211_HE_SPR_SRG_INFORMATION_PRESENT)
spr_len += 18;
/* Add the first byte (extension ID) to the total length */
spr_len++;
return spr_len;
}
struct ieee80211_he_6ghz_capa {
/* uses IEEE80211_HE_6GHZ_CAP_* below */
__le16 capa;
} __packed;
/* HE 6 GHz band capabilities */
/* uses enum ieee80211_min_mpdu_spacing values */
#define IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START 0x0007
/* uses enum ieee80211_vht_max_ampdu_length_exp values */
#define IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP 0x0038
/* uses IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_* values */
#define IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN 0x00c0
/* WLAN_HT_CAP_SM_PS_* values */
#define IEEE80211_HE_6GHZ_CAP_SM_PS 0x0600
#define IEEE80211_HE_6GHZ_CAP_RD_RESPONDER 0x0800
#define IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS 0x1000
#define IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS 0x2000
#endif /* LINUX_IEEE80211_HE_H */

View File

@ -0,0 +1,292 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* IEEE 802.11 HT definitions
*
* Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
* <jkmaline@cc.hut.fi>
* Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
* Copyright (c) 2005, Devicescape Software, Inc.
* Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
* Copyright (c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright (c) 2016 - 2017 Intel Deutschland GmbH
* Copyright (c) 2018 - 2025 Intel Corporation
*/
#ifndef LINUX_IEEE80211_HT_H
#define LINUX_IEEE80211_HT_H
#include <linux/types.h>
#include <linux/if_ether.h>
/* Maximal size of an A-MSDU that can be transported in a HT BA session */
#define IEEE80211_MAX_MPDU_LEN_HT_BA 4095
/* Maximal size of an A-MSDU */
#define IEEE80211_MAX_MPDU_LEN_HT_3839 3839
#define IEEE80211_MAX_MPDU_LEN_HT_7935 7935
#define IEEE80211_HT_CTL_LEN 4
enum ieee80211_ht_chanwidth_values {
IEEE80211_HT_CHANWIDTH_20MHZ = 0,
IEEE80211_HT_CHANWIDTH_ANY = 1,
};
/**
* struct ieee80211_bar - Block Ack Request frame format
* @frame_control: Frame Control
* @duration: Duration
* @ra: RA
* @ta: TA
* @control: BAR Control
* @start_seq_num: Starting Sequence Number (see Figure 9-37)
*
* This structure represents the "BlockAckReq frame format"
* as described in IEEE Std 802.11-2020 section 9.3.1.7.
*/
struct ieee80211_bar {
__le16 frame_control;
__le16 duration;
__u8 ra[ETH_ALEN];
__u8 ta[ETH_ALEN];
__le16 control;
__le16 start_seq_num;
} __packed;
/* 802.11 BAR control masks */
#define IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL 0x0000
#define IEEE80211_BAR_CTRL_MULTI_TID 0x0002
#define IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA 0x0004
#define IEEE80211_BAR_CTRL_TID_INFO_MASK 0xf000
#define IEEE80211_BAR_CTRL_TID_INFO_SHIFT 12
#define IEEE80211_HT_MCS_MASK_LEN 10
/**
* struct ieee80211_mcs_info - Supported MCS Set field
* @rx_mask: RX mask
* @rx_highest: highest supported RX rate. If set represents
* the highest supported RX data rate in units of 1 Mbps.
* If this field is 0 this value should not be used to
* consider the highest RX data rate supported.
* @tx_params: TX parameters
* @reserved: Reserved bits
*
* This structure represents the "Supported MCS Set field" as
* described in IEEE Std 802.11-2020 section 9.4.2.55.4.
*/
struct ieee80211_mcs_info {
u8 rx_mask[IEEE80211_HT_MCS_MASK_LEN];
__le16 rx_highest;
u8 tx_params;
u8 reserved[3];
} __packed;
/* 802.11n HT capability MSC set */
#define IEEE80211_HT_MCS_RX_HIGHEST_MASK 0x3ff
#define IEEE80211_HT_MCS_TX_DEFINED 0x01
#define IEEE80211_HT_MCS_TX_RX_DIFF 0x02
/* value 0 == 1 stream etc */
#define IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK 0x0C
#define IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT 2
#define IEEE80211_HT_MCS_TX_MAX_STREAMS 4
#define IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION 0x10
#define IEEE80211_HT_MCS_CHAINS(mcs) ((mcs) == 32 ? 1 : (1 + ((mcs) >> 3)))
/*
* 802.11n D5.0 20.3.5 / 20.6 says:
* - indices 0 to 7 and 32 are single spatial stream
* - 8 to 31 are multiple spatial streams using equal modulation
* [8..15 for two streams, 16..23 for three and 24..31 for four]
* - remainder are multiple spatial streams using unequal modulation
*/
#define IEEE80211_HT_MCS_UNEQUAL_MODULATION_START 33
#define IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE \
(IEEE80211_HT_MCS_UNEQUAL_MODULATION_START / 8)
/**
* struct ieee80211_ht_cap - HT capabilities element
* @cap_info: HT Capability Information
* @ampdu_params_info: A-MPDU Parameters
* @mcs: Supported MCS Set
* @extended_ht_cap_info: HT Extended Capabilities
* @tx_BF_cap_info: Transmit Beamforming Capabilities
* @antenna_selection_info: ASEL Capability
*
* This structure represents the payload of the "HT Capabilities
* element" as described in IEEE Std 802.11-2020 section 9.4.2.55.
*/
struct ieee80211_ht_cap {
__le16 cap_info;
u8 ampdu_params_info;
/* 16 bytes MCS information */
struct ieee80211_mcs_info mcs;
__le16 extended_ht_cap_info;
__le32 tx_BF_cap_info;
u8 antenna_selection_info;
} __packed;
/* 802.11n HT capabilities masks (for cap_info) */
#define IEEE80211_HT_CAP_LDPC_CODING 0x0001
#define IEEE80211_HT_CAP_SUP_WIDTH_20_40 0x0002
#define IEEE80211_HT_CAP_SM_PS 0x000C
#define IEEE80211_HT_CAP_SM_PS_SHIFT 2
#define IEEE80211_HT_CAP_GRN_FLD 0x0010
#define IEEE80211_HT_CAP_SGI_20 0x0020
#define IEEE80211_HT_CAP_SGI_40 0x0040
#define IEEE80211_HT_CAP_TX_STBC 0x0080
#define IEEE80211_HT_CAP_RX_STBC 0x0300
#define IEEE80211_HT_CAP_RX_STBC_SHIFT 8
#define IEEE80211_HT_CAP_DELAY_BA 0x0400
#define IEEE80211_HT_CAP_MAX_AMSDU 0x0800
#define IEEE80211_HT_CAP_DSSSCCK40 0x1000
#define IEEE80211_HT_CAP_RESERVED 0x2000
#define IEEE80211_HT_CAP_40MHZ_INTOLERANT 0x4000
#define IEEE80211_HT_CAP_LSIG_TXOP_PROT 0x8000
/* 802.11n HT extended capabilities masks (for extended_ht_cap_info) */
#define IEEE80211_HT_EXT_CAP_PCO 0x0001
#define IEEE80211_HT_EXT_CAP_PCO_TIME 0x0006
#define IEEE80211_HT_EXT_CAP_PCO_TIME_SHIFT 1
#define IEEE80211_HT_EXT_CAP_MCS_FB 0x0300
#define IEEE80211_HT_EXT_CAP_MCS_FB_SHIFT 8
#define IEEE80211_HT_EXT_CAP_HTC_SUP 0x0400
#define IEEE80211_HT_EXT_CAP_RD_RESPONDER 0x0800
/* 802.11n HT capability AMPDU settings (for ampdu_params_info) */
#define IEEE80211_HT_AMPDU_PARM_FACTOR 0x03
#define IEEE80211_HT_AMPDU_PARM_DENSITY 0x1C
#define IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT 2
/*
* Maximum length of AMPDU that the STA can receive in high-throughput (HT).
* Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets)
*/
enum ieee80211_max_ampdu_length_exp {
IEEE80211_HT_MAX_AMPDU_8K = 0,
IEEE80211_HT_MAX_AMPDU_16K = 1,
IEEE80211_HT_MAX_AMPDU_32K = 2,
IEEE80211_HT_MAX_AMPDU_64K = 3
};
#define IEEE80211_HT_MAX_AMPDU_FACTOR 13
/* Minimum MPDU start spacing */
enum ieee80211_min_mpdu_spacing {
IEEE80211_HT_MPDU_DENSITY_NONE = 0, /* No restriction */
IEEE80211_HT_MPDU_DENSITY_0_25 = 1, /* 1/4 usec */
IEEE80211_HT_MPDU_DENSITY_0_5 = 2, /* 1/2 usec */
IEEE80211_HT_MPDU_DENSITY_1 = 3, /* 1 usec */
IEEE80211_HT_MPDU_DENSITY_2 = 4, /* 2 usec */
IEEE80211_HT_MPDU_DENSITY_4 = 5, /* 4 usec */
IEEE80211_HT_MPDU_DENSITY_8 = 6, /* 8 usec */
IEEE80211_HT_MPDU_DENSITY_16 = 7 /* 16 usec */
};
/**
* struct ieee80211_ht_operation - HT operation IE
* @primary_chan: Primary Channel
* @ht_param: HT Operation Information parameters
* @operation_mode: HT Operation Information operation mode
* @stbc_param: HT Operation Information STBC params
* @basic_set: Basic HT-MCS Set
*
* This structure represents the payload of the "HT Operation
* element" as described in IEEE Std 802.11-2020 section 9.4.2.56.
*/
struct ieee80211_ht_operation {
u8 primary_chan;
u8 ht_param;
__le16 operation_mode;
__le16 stbc_param;
u8 basic_set[16];
} __packed;
/* for ht_param */
#define IEEE80211_HT_PARAM_CHA_SEC_OFFSET 0x03
#define IEEE80211_HT_PARAM_CHA_SEC_NONE 0x00
#define IEEE80211_HT_PARAM_CHA_SEC_ABOVE 0x01
#define IEEE80211_HT_PARAM_CHA_SEC_BELOW 0x03
#define IEEE80211_HT_PARAM_CHAN_WIDTH_ANY 0x04
#define IEEE80211_HT_PARAM_RIFS_MODE 0x08
/* for operation_mode */
#define IEEE80211_HT_OP_MODE_PROTECTION 0x0003
#define IEEE80211_HT_OP_MODE_PROTECTION_NONE 0
#define IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER 1
#define IEEE80211_HT_OP_MODE_PROTECTION_20MHZ 2
#define IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED 3
#define IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT 0x0004
#define IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT 0x0010
#define IEEE80211_HT_OP_MODE_CCFS2_SHIFT 5
#define IEEE80211_HT_OP_MODE_CCFS2_MASK 0x1fe0
/* for stbc_param */
#define IEEE80211_HT_STBC_PARAM_DUAL_BEACON 0x0040
#define IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT 0x0080
#define IEEE80211_HT_STBC_PARAM_STBC_BEACON 0x0100
#define IEEE80211_HT_STBC_PARAM_LSIG_TXOP_FULLPROT 0x0200
#define IEEE80211_HT_STBC_PARAM_PCO_ACTIVE 0x0400
#define IEEE80211_HT_STBC_PARAM_PCO_PHASE 0x0800
/* block-ack parameters */
#define IEEE80211_ADDBA_PARAM_AMSDU_MASK 0x0001
#define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002
#define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C
#define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFC0
#define IEEE80211_DELBA_PARAM_TID_MASK 0xF000
#define IEEE80211_DELBA_PARAM_INITIATOR_MASK 0x0800
/*
* A-MPDU buffer sizes
* According to HT size varies from 8 to 64 frames
* HE adds the ability to have up to 256 frames.
* EHT adds the ability to have up to 1K frames.
*/
#define IEEE80211_MIN_AMPDU_BUF 0x8
#define IEEE80211_MAX_AMPDU_BUF_HT 0x40
#define IEEE80211_MAX_AMPDU_BUF_HE 0x100
#define IEEE80211_MAX_AMPDU_BUF_EHT 0x400
/* Spatial Multiplexing Power Save Modes (for capability) */
#define WLAN_HT_CAP_SM_PS_STATIC 0
#define WLAN_HT_CAP_SM_PS_DYNAMIC 1
#define WLAN_HT_CAP_SM_PS_INVALID 2
#define WLAN_HT_CAP_SM_PS_DISABLED 3
/* for SM power control field lower two bits */
#define WLAN_HT_SMPS_CONTROL_DISABLED 0
#define WLAN_HT_SMPS_CONTROL_STATIC 1
#define WLAN_HT_SMPS_CONTROL_DYNAMIC 3
/* HT action codes */
enum ieee80211_ht_actioncode {
WLAN_HT_ACTION_NOTIFY_CHANWIDTH = 0,
WLAN_HT_ACTION_SMPS = 1,
WLAN_HT_ACTION_PSMP = 2,
WLAN_HT_ACTION_PCO_PHASE = 3,
WLAN_HT_ACTION_CSI = 4,
WLAN_HT_ACTION_NONCOMPRESSED_BF = 5,
WLAN_HT_ACTION_COMPRESSED_BF = 6,
WLAN_HT_ACTION_ASEL_IDX_FEEDBACK = 7,
};
/* BACK action code */
enum ieee80211_back_actioncode {
WLAN_ACTION_ADDBA_REQ = 0,
WLAN_ACTION_ADDBA_RESP = 1,
WLAN_ACTION_DELBA = 2,
};
/* BACK (block-ack) parties */
enum ieee80211_back_parties {
WLAN_BACK_RECIPIENT = 0,
WLAN_BACK_INITIATOR = 1,
};
#endif /* LINUX_IEEE80211_HT_H */

View File

@ -0,0 +1,230 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* IEEE 802.11 mesh definitions
*
* Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
* <jkmaline@cc.hut.fi>
* Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
* Copyright (c) 2005, Devicescape Software, Inc.
* Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
* Copyright (c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright (c) 2016 - 2017 Intel Deutschland GmbH
* Copyright (c) 2018 - 2025 Intel Corporation
*/
#ifndef LINUX_IEEE80211_MESH_H
#define LINUX_IEEE80211_MESH_H
#include <linux/types.h>
#include <linux/if_ether.h>
#define IEEE80211_MAX_MESH_ID_LEN 32
struct ieee80211s_hdr {
u8 flags;
u8 ttl;
__le32 seqnum;
u8 eaddr1[ETH_ALEN];
u8 eaddr2[ETH_ALEN];
} __packed __aligned(2);
/* Mesh flags */
#define MESH_FLAGS_AE_A4 0x1
#define MESH_FLAGS_AE_A5_A6 0x2
#define MESH_FLAGS_AE 0x3
#define MESH_FLAGS_PS_DEEP 0x4
/**
* enum ieee80211_preq_flags - mesh PREQ element flags
*
* @IEEE80211_PREQ_PROACTIVE_PREP_FLAG: proactive PREP subfield
*/
enum ieee80211_preq_flags {
IEEE80211_PREQ_PROACTIVE_PREP_FLAG = 1<<2,
};
/**
* enum ieee80211_preq_target_flags - mesh PREQ element per target flags
*
* @IEEE80211_PREQ_TO_FLAG: target only subfield
* @IEEE80211_PREQ_USN_FLAG: unknown target HWMP sequence number subfield
*/
enum ieee80211_preq_target_flags {
IEEE80211_PREQ_TO_FLAG = 1<<0,
IEEE80211_PREQ_USN_FLAG = 1<<2,
};
/**
* struct ieee80211_mesh_chansw_params_ie - mesh channel switch parameters IE
* @mesh_ttl: Time To Live
* @mesh_flags: Flags
* @mesh_reason: Reason Code
* @mesh_pre_value: Precedence Value
*
* This structure represents the payload of the "Mesh Channel Switch
* Parameters element" as described in IEEE Std 802.11-2020 section
* 9.4.2.102.
*/
struct ieee80211_mesh_chansw_params_ie {
u8 mesh_ttl;
u8 mesh_flags;
__le16 mesh_reason;
__le16 mesh_pre_value;
} __packed;
/**
* struct ieee80211_meshconf_ie - Mesh Configuration element
* @meshconf_psel: Active Path Selection Protocol Identifier
* @meshconf_pmetric: Active Path Selection Metric Identifier
* @meshconf_congest: Congestion Control Mode Identifier
* @meshconf_synch: Synchronization Method Identifier
* @meshconf_auth: Authentication Protocol Identifier
* @meshconf_form: Mesh Formation Info
* @meshconf_cap: Mesh Capability (see &enum mesh_config_capab_flags)
*
* This structure represents the payload of the "Mesh Configuration
* element" as described in IEEE Std 802.11-2020 section 9.4.2.97.
*/
struct ieee80211_meshconf_ie {
u8 meshconf_psel;
u8 meshconf_pmetric;
u8 meshconf_congest;
u8 meshconf_synch;
u8 meshconf_auth;
u8 meshconf_form;
u8 meshconf_cap;
} __packed;
/**
* enum mesh_config_capab_flags - Mesh Configuration IE capability field flags
*
* @IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS: STA is willing to establish
* additional mesh peerings with other mesh STAs
* @IEEE80211_MESHCONF_CAPAB_FORWARDING: the STA forwards MSDUs
* @IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING: TBTT adjustment procedure
* is ongoing
* @IEEE80211_MESHCONF_CAPAB_POWER_SAVE_LEVEL: STA is in deep sleep mode or has
* neighbors in deep sleep mode
*
* Enumerates the "Mesh Capability" as described in IEEE Std
* 802.11-2020 section 9.4.2.97.7.
*/
enum mesh_config_capab_flags {
IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS = 0x01,
IEEE80211_MESHCONF_CAPAB_FORWARDING = 0x08,
IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING = 0x20,
IEEE80211_MESHCONF_CAPAB_POWER_SAVE_LEVEL = 0x40,
};
#define IEEE80211_MESHCONF_FORM_CONNECTED_TO_GATE 0x1
/*
* mesh channel switch parameters element's flag indicator
*
*/
#define WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT BIT(0)
#define WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR BIT(1)
#define WLAN_EID_CHAN_SWITCH_PARAM_REASON BIT(2)
/**
* struct ieee80211_rann_ie - RANN (root announcement) element
* @rann_flags: Flags
* @rann_hopcount: Hop Count
* @rann_ttl: Element TTL
* @rann_addr: Root Mesh STA Address
* @rann_seq: HWMP Sequence Number
* @rann_interval: Interval
* @rann_metric: Metric
*
* This structure represents the payload of the "RANN element" as
* described in IEEE Std 802.11-2020 section 9.4.2.111.
*/
struct ieee80211_rann_ie {
u8 rann_flags;
u8 rann_hopcount;
u8 rann_ttl;
u8 rann_addr[ETH_ALEN];
__le32 rann_seq;
__le32 rann_interval;
__le32 rann_metric;
} __packed;
enum ieee80211_rann_flags {
RANN_FLAG_IS_GATE = 1 << 0,
};
/* Mesh action codes */
enum ieee80211_mesh_actioncode {
WLAN_MESH_ACTION_LINK_METRIC_REPORT,
WLAN_MESH_ACTION_HWMP_PATH_SELECTION,
WLAN_MESH_ACTION_GATE_ANNOUNCEMENT,
WLAN_MESH_ACTION_CONGESTION_CONTROL_NOTIFICATION,
WLAN_MESH_ACTION_MCCA_SETUP_REQUEST,
WLAN_MESH_ACTION_MCCA_SETUP_REPLY,
WLAN_MESH_ACTION_MCCA_ADVERTISEMENT_REQUEST,
WLAN_MESH_ACTION_MCCA_ADVERTISEMENT,
WLAN_MESH_ACTION_MCCA_TEARDOWN,
WLAN_MESH_ACTION_TBTT_ADJUSTMENT_REQUEST,
WLAN_MESH_ACTION_TBTT_ADJUSTMENT_RESPONSE,
};
/**
* enum ieee80211_mesh_sync_method - mesh synchronization method identifier
*
* @IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET: the default synchronization method
* @IEEE80211_SYNC_METHOD_VENDOR: a vendor specific synchronization method
* that will be specified in a vendor specific information element
*/
enum ieee80211_mesh_sync_method {
IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET = 1,
IEEE80211_SYNC_METHOD_VENDOR = 255,
};
/**
* enum ieee80211_mesh_path_protocol - mesh path selection protocol identifier
*
* @IEEE80211_PATH_PROTOCOL_HWMP: the default path selection protocol
* @IEEE80211_PATH_PROTOCOL_VENDOR: a vendor specific protocol that will
* be specified in a vendor specific information element
*/
enum ieee80211_mesh_path_protocol {
IEEE80211_PATH_PROTOCOL_HWMP = 1,
IEEE80211_PATH_PROTOCOL_VENDOR = 255,
};
/**
* enum ieee80211_mesh_path_metric - mesh path selection metric identifier
*
* @IEEE80211_PATH_METRIC_AIRTIME: the default path selection metric
* @IEEE80211_PATH_METRIC_VENDOR: a vendor specific metric that will be
* specified in a vendor specific information element
*/
enum ieee80211_mesh_path_metric {
IEEE80211_PATH_METRIC_AIRTIME = 1,
IEEE80211_PATH_METRIC_VENDOR = 255,
};
/**
* enum ieee80211_root_mode_identifier - root mesh STA mode identifier
*
* These attribute are used by dot11MeshHWMPRootMode to set root mesh STA mode
*
* @IEEE80211_ROOTMODE_NO_ROOT: the mesh STA is not a root mesh STA (default)
* @IEEE80211_ROOTMODE_ROOT: the mesh STA is a root mesh STA if greater than
* this value
* @IEEE80211_PROACTIVE_PREQ_NO_PREP: the mesh STA is a root mesh STA supports
* the proactive PREQ with proactive PREP subfield set to 0
* @IEEE80211_PROACTIVE_PREQ_WITH_PREP: the mesh STA is a root mesh STA
* supports the proactive PREQ with proactive PREP subfield set to 1
* @IEEE80211_PROACTIVE_RANN: the mesh STA is a root mesh STA supports
* the proactive RANN
*/
enum ieee80211_root_mode_identifier {
IEEE80211_ROOTMODE_NO_ROOT = 0,
IEEE80211_ROOTMODE_ROOT = 1,
IEEE80211_PROACTIVE_PREQ_NO_PREP = 2,
IEEE80211_PROACTIVE_PREQ_WITH_PREP = 3,
IEEE80211_PROACTIVE_RANN = 4,
};
#endif /* LINUX_IEEE80211_MESH_H */

View File

@ -0,0 +1,35 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* WFA NAN definitions
*
* Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
* <jkmaline@cc.hut.fi>
* Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
* Copyright (c) 2005, Devicescape Software, Inc.
* Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
* Copyright (c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright (c) 2016 - 2017 Intel Deutschland GmbH
* Copyright (c) 2018 - 2025 Intel Corporation
*/
#ifndef LINUX_IEEE80211_NAN_H
#define LINUX_IEEE80211_NAN_H
/* NAN operation mode, as defined in Wi-Fi Aware (TM) specification Table 81 */
#define NAN_OP_MODE_PHY_MODE_VHT 0x01
#define NAN_OP_MODE_PHY_MODE_HE 0x10
#define NAN_OP_MODE_PHY_MODE_MASK 0x11
#define NAN_OP_MODE_80P80MHZ 0x02
#define NAN_OP_MODE_160MHZ 0x04
#define NAN_OP_MODE_PNDL_SUPPRTED 0x08
/* NAN Device capabilities, as defined in Wi-Fi Aware (TM) specification
* Table 79
*/
#define NAN_DEV_CAPA_DFS_OWNER 0x01
#define NAN_DEV_CAPA_EXT_KEY_ID_SUPPORTED 0x02
#define NAN_DEV_CAPA_SIM_NDP_RX_SUPPORTED 0x04
#define NAN_DEV_CAPA_NDPE_SUPPORTED 0x08
#define NAN_DEV_CAPA_S3_SUPPORTED 0x10
#endif /* LINUX_IEEE80211_NAN_H */

View File

@ -0,0 +1,71 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* WFA P2P definitions
*
* Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
* <jkmaline@cc.hut.fi>
* Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
* Copyright (c) 2005, Devicescape Software, Inc.
* Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
* Copyright (c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright (c) 2016 - 2017 Intel Deutschland GmbH
* Copyright (c) 2018 - 2025 Intel Corporation
*/
#ifndef LINUX_IEEE80211_P2P_H
#define LINUX_IEEE80211_P2P_H
#include <linux/types.h>
/*
* Peer-to-Peer IE attribute related definitions.
*/
/*
* enum ieee80211_p2p_attr_id - identifies type of peer-to-peer attribute.
*/
enum ieee80211_p2p_attr_id {
IEEE80211_P2P_ATTR_STATUS = 0,
IEEE80211_P2P_ATTR_MINOR_REASON,
IEEE80211_P2P_ATTR_CAPABILITY,
IEEE80211_P2P_ATTR_DEVICE_ID,
IEEE80211_P2P_ATTR_GO_INTENT,
IEEE80211_P2P_ATTR_GO_CONFIG_TIMEOUT,
IEEE80211_P2P_ATTR_LISTEN_CHANNEL,
IEEE80211_P2P_ATTR_GROUP_BSSID,
IEEE80211_P2P_ATTR_EXT_LISTEN_TIMING,
IEEE80211_P2P_ATTR_INTENDED_IFACE_ADDR,
IEEE80211_P2P_ATTR_MANAGABILITY,
IEEE80211_P2P_ATTR_CHANNEL_LIST,
IEEE80211_P2P_ATTR_ABSENCE_NOTICE,
IEEE80211_P2P_ATTR_DEVICE_INFO,
IEEE80211_P2P_ATTR_GROUP_INFO,
IEEE80211_P2P_ATTR_GROUP_ID,
IEEE80211_P2P_ATTR_INTERFACE,
IEEE80211_P2P_ATTR_OPER_CHANNEL,
IEEE80211_P2P_ATTR_INVITE_FLAGS,
/* 19 - 220: Reserved */
IEEE80211_P2P_ATTR_VENDOR_SPECIFIC = 221,
IEEE80211_P2P_ATTR_MAX
};
/* Notice of Absence attribute - described in P2P spec 4.1.14 */
/* Typical max value used here */
#define IEEE80211_P2P_NOA_DESC_MAX 4
struct ieee80211_p2p_noa_desc {
u8 count;
__le32 duration;
__le32 interval;
__le32 start_time;
} __packed;
struct ieee80211_p2p_noa_attr {
u8 index;
u8 oppps_ctwindow;
struct ieee80211_p2p_noa_desc desc[IEEE80211_P2P_NOA_DESC_MAX];
} __packed;
#define IEEE80211_P2P_OPPPS_ENABLE_BIT BIT(7)
#define IEEE80211_P2P_OPPPS_CTWINDOW_MASK 0x7F
#endif /* LINUX_IEEE80211_P2P_H */

View File

@ -0,0 +1,575 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* IEEE 802.11 S1G definitions
*
* Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
* <jkmaline@cc.hut.fi>
* Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
* Copyright (c) 2005, Devicescape Software, Inc.
* Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
* Copyright (c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright (c) 2016 - 2017 Intel Deutschland GmbH
* Copyright (c) 2018 - 2025 Intel Corporation
*/
#ifndef LINUX_IEEE80211_S1G_H
#define LINUX_IEEE80211_S1G_H
#include <linux/types.h>
#include <linux/if_ether.h>
/* bits unique to S1G beacon frame control */
#define IEEE80211_S1G_BCN_NEXT_TBTT 0x100
#define IEEE80211_S1G_BCN_CSSID 0x200
#define IEEE80211_S1G_BCN_ANO 0x400
/* see 802.11ah-2016 9.9 NDP CMAC frames */
#define IEEE80211_S1G_1MHZ_NDP_BITS 25
#define IEEE80211_S1G_1MHZ_NDP_BYTES 4
#define IEEE80211_S1G_2MHZ_NDP_BITS 37
#define IEEE80211_S1G_2MHZ_NDP_BYTES 5
/**
* ieee80211_is_s1g_beacon - check if IEEE80211_FTYPE_EXT &&
* IEEE80211_STYPE_S1G_BEACON
* @fc: frame control bytes in little-endian byteorder
* Return: whether or not the frame is an S1G beacon
*/
static inline bool ieee80211_is_s1g_beacon(__le16 fc)
{
return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE |
IEEE80211_FCTL_STYPE)) ==
cpu_to_le16(IEEE80211_FTYPE_EXT | IEEE80211_STYPE_S1G_BEACON);
}
/**
* ieee80211_s1g_has_next_tbtt - check if IEEE80211_S1G_BCN_NEXT_TBTT
* @fc: frame control bytes in little-endian byteorder
* Return: whether or not the frame contains the variable-length
* next TBTT field
*/
static inline bool ieee80211_s1g_has_next_tbtt(__le16 fc)
{
return ieee80211_is_s1g_beacon(fc) &&
(fc & cpu_to_le16(IEEE80211_S1G_BCN_NEXT_TBTT));
}
/**
* ieee80211_s1g_has_ano - check if IEEE80211_S1G_BCN_ANO
* @fc: frame control bytes in little-endian byteorder
* Return: whether or not the frame contains the variable-length
* ANO field
*/
static inline bool ieee80211_s1g_has_ano(__le16 fc)
{
return ieee80211_is_s1g_beacon(fc) &&
(fc & cpu_to_le16(IEEE80211_S1G_BCN_ANO));
}
/**
* ieee80211_s1g_has_cssid - check if IEEE80211_S1G_BCN_CSSID
* @fc: frame control bytes in little-endian byteorder
* Return: whether or not the frame contains the variable-length
* compressed SSID field
*/
static inline bool ieee80211_s1g_has_cssid(__le16 fc)
{
return ieee80211_is_s1g_beacon(fc) &&
(fc & cpu_to_le16(IEEE80211_S1G_BCN_CSSID));
}
/**
* enum ieee80211_s1g_chanwidth - S1G channel widths
* These are defined in IEEE802.11-2016ah Table 10-20
* as BSS Channel Width
*
* @IEEE80211_S1G_CHANWIDTH_1MHZ: 1MHz operating channel
* @IEEE80211_S1G_CHANWIDTH_2MHZ: 2MHz operating channel
* @IEEE80211_S1G_CHANWIDTH_4MHZ: 4MHz operating channel
* @IEEE80211_S1G_CHANWIDTH_8MHZ: 8MHz operating channel
* @IEEE80211_S1G_CHANWIDTH_16MHZ: 16MHz operating channel
*/
enum ieee80211_s1g_chanwidth {
IEEE80211_S1G_CHANWIDTH_1MHZ = 0,
IEEE80211_S1G_CHANWIDTH_2MHZ = 1,
IEEE80211_S1G_CHANWIDTH_4MHZ = 3,
IEEE80211_S1G_CHANWIDTH_8MHZ = 7,
IEEE80211_S1G_CHANWIDTH_16MHZ = 15,
};
/**
* enum ieee80211_s1g_pri_chanwidth - S1G primary channel widths
* described in IEEE80211-2024 Table 10-39.
*
* @IEEE80211_S1G_PRI_CHANWIDTH_2MHZ: 2MHz primary channel
* @IEEE80211_S1G_PRI_CHANWIDTH_1MHZ: 1MHz primary channel
*/
enum ieee80211_s1g_pri_chanwidth {
IEEE80211_S1G_PRI_CHANWIDTH_2MHZ = 0,
IEEE80211_S1G_PRI_CHANWIDTH_1MHZ = 1,
};
/**
* struct ieee80211_s1g_bcn_compat_ie - S1G Beacon Compatibility element
* @compat_info: Compatibility Information
* @beacon_int: Beacon Interval
* @tsf_completion: TSF Completion
*
* This structure represents the payload of the "S1G Beacon
* Compatibility element" as described in IEEE Std 802.11-2020 section
* 9.4.2.196.
*/
struct ieee80211_s1g_bcn_compat_ie {
__le16 compat_info;
__le16 beacon_int;
__le32 tsf_completion;
} __packed;
/**
* struct ieee80211_s1g_oper_ie - S1G Operation element
* @ch_width: S1G Operation Information Channel Width
* @oper_class: S1G Operation Information Operating Class
* @primary_ch: S1G Operation Information Primary Channel Number
* @oper_ch: S1G Operation Information Channel Center Frequency
* @basic_mcs_nss: Basic S1G-MCS and NSS Set
*
* This structure represents the payload of the "S1G Operation
* element" as described in IEEE Std 802.11-2020 section 9.4.2.212.
*/
struct ieee80211_s1g_oper_ie {
u8 ch_width;
u8 oper_class;
u8 primary_ch;
u8 oper_ch;
__le16 basic_mcs_nss;
} __packed;
/**
* struct ieee80211_aid_response_ie - AID Response element
* @aid: AID/Group AID
* @switch_count: AID Switch Count
* @response_int: AID Response Interval
*
* This structure represents the payload of the "AID Response element"
* as described in IEEE Std 802.11-2020 section 9.4.2.194.
*/
struct ieee80211_aid_response_ie {
__le16 aid;
u8 switch_count;
__le16 response_int;
} __packed;
struct ieee80211_s1g_cap {
u8 capab_info[10];
u8 supp_mcs_nss[5];
} __packed;
/**
* ieee80211_s1g_optional_len - determine length of optional S1G beacon fields
* @fc: frame control bytes in little-endian byteorder
* Return: total length in bytes of the optional fixed-length fields
*
* S1G beacons may contain up to three optional fixed-length fields that
* precede the variable-length elements. Whether these fields are present
* is indicated by flags in the frame control field.
*
* From IEEE 802.11-2024 section 9.3.4.3:
* - Next TBTT field may be 0 or 3 bytes
* - Short SSID field may be 0 or 4 bytes
* - Access Network Options (ANO) field may be 0 or 1 byte
*/
static inline size_t
ieee80211_s1g_optional_len(__le16 fc)
{
size_t len = 0;
if (ieee80211_s1g_has_next_tbtt(fc))
len += 3;
if (ieee80211_s1g_has_cssid(fc))
len += 4;
if (ieee80211_s1g_has_ano(fc))
len += 1;
return len;
}
/* S1G Capabilities Information field */
#define IEEE80211_S1G_CAPABILITY_LEN 15
#define S1G_CAP0_S1G_LONG BIT(0)
#define S1G_CAP0_SGI_1MHZ BIT(1)
#define S1G_CAP0_SGI_2MHZ BIT(2)
#define S1G_CAP0_SGI_4MHZ BIT(3)
#define S1G_CAP0_SGI_8MHZ BIT(4)
#define S1G_CAP0_SGI_16MHZ BIT(5)
#define S1G_CAP0_SUPP_CH_WIDTH GENMASK(7, 6)
#define S1G_SUPP_CH_WIDTH_2 0
#define S1G_SUPP_CH_WIDTH_4 1
#define S1G_SUPP_CH_WIDTH_8 2
#define S1G_SUPP_CH_WIDTH_16 3
#define S1G_SUPP_CH_WIDTH_MAX(cap) ((1 << FIELD_GET(S1G_CAP0_SUPP_CH_WIDTH, \
cap[0])) << 1)
#define S1G_CAP1_RX_LDPC BIT(0)
#define S1G_CAP1_TX_STBC BIT(1)
#define S1G_CAP1_RX_STBC BIT(2)
#define S1G_CAP1_SU_BFER BIT(3)
#define S1G_CAP1_SU_BFEE BIT(4)
#define S1G_CAP1_BFEE_STS GENMASK(7, 5)
#define S1G_CAP2_SOUNDING_DIMENSIONS GENMASK(2, 0)
#define S1G_CAP2_MU_BFER BIT(3)
#define S1G_CAP2_MU_BFEE BIT(4)
#define S1G_CAP2_PLUS_HTC_VHT BIT(5)
#define S1G_CAP2_TRAVELING_PILOT GENMASK(7, 6)
#define S1G_CAP3_RD_RESPONDER BIT(0)
#define S1G_CAP3_HT_DELAYED_BA BIT(1)
#define S1G_CAP3_MAX_MPDU_LEN BIT(2)
#define S1G_CAP3_MAX_AMPDU_LEN_EXP GENMASK(4, 3)
#define S1G_CAP3_MIN_MPDU_START GENMASK(7, 5)
#define S1G_CAP4_UPLINK_SYNC BIT(0)
#define S1G_CAP4_DYNAMIC_AID BIT(1)
#define S1G_CAP4_BAT BIT(2)
#define S1G_CAP4_TIME_ADE BIT(3)
#define S1G_CAP4_NON_TIM BIT(4)
#define S1G_CAP4_GROUP_AID BIT(5)
#define S1G_CAP4_STA_TYPE GENMASK(7, 6)
#define S1G_CAP5_CENT_AUTH_CONTROL BIT(0)
#define S1G_CAP5_DIST_AUTH_CONTROL BIT(1)
#define S1G_CAP5_AMSDU BIT(2)
#define S1G_CAP5_AMPDU BIT(3)
#define S1G_CAP5_ASYMMETRIC_BA BIT(4)
#define S1G_CAP5_FLOW_CONTROL BIT(5)
#define S1G_CAP5_SECTORIZED_BEAM GENMASK(7, 6)
#define S1G_CAP6_OBSS_MITIGATION BIT(0)
#define S1G_CAP6_FRAGMENT_BA BIT(1)
#define S1G_CAP6_NDP_PS_POLL BIT(2)
#define S1G_CAP6_RAW_OPERATION BIT(3)
#define S1G_CAP6_PAGE_SLICING BIT(4)
#define S1G_CAP6_TXOP_SHARING_IMP_ACK BIT(5)
#define S1G_CAP6_VHT_LINK_ADAPT GENMASK(7, 6)
#define S1G_CAP7_TACK_AS_PS_POLL BIT(0)
#define S1G_CAP7_DUP_1MHZ BIT(1)
#define S1G_CAP7_MCS_NEGOTIATION BIT(2)
#define S1G_CAP7_1MHZ_CTL_RESPONSE_PREAMBLE BIT(3)
#define S1G_CAP7_NDP_BFING_REPORT_POLL BIT(4)
#define S1G_CAP7_UNSOLICITED_DYN_AID BIT(5)
#define S1G_CAP7_SECTOR_TRAINING_OPERATION BIT(6)
#define S1G_CAP7_TEMP_PS_MODE_SWITCH BIT(7)
#define S1G_CAP8_TWT_GROUPING BIT(0)
#define S1G_CAP8_BDT BIT(1)
#define S1G_CAP8_COLOR GENMASK(4, 2)
#define S1G_CAP8_TWT_REQUEST BIT(5)
#define S1G_CAP8_TWT_RESPOND BIT(6)
#define S1G_CAP8_PV1_FRAME BIT(7)
#define S1G_CAP9_LINK_ADAPT_PER_CONTROL_RESPONSE BIT(0)
#define S1G_OPER_CH_WIDTH_PRIMARY BIT(0)
#define S1G_OPER_CH_WIDTH_OPER GENMASK(4, 1)
#define S1G_OPER_CH_PRIMARY_LOCATION BIT(5)
#define S1G_2M_PRIMARY_LOCATION_LOWER 0
#define S1G_2M_PRIMARY_LOCATION_UPPER 1
#define LISTEN_INT_USF GENMASK(15, 14)
#define LISTEN_INT_UI GENMASK(13, 0)
#define IEEE80211_MAX_USF FIELD_MAX(LISTEN_INT_USF)
#define IEEE80211_MAX_UI FIELD_MAX(LISTEN_INT_UI)
/* S1G encoding types */
#define IEEE80211_S1G_TIM_ENC_MODE_BLOCK 0
#define IEEE80211_S1G_TIM_ENC_MODE_SINGLE 1
#define IEEE80211_S1G_TIM_ENC_MODE_OLB 2
enum ieee80211_s1g_actioncode {
WLAN_S1G_AID_SWITCH_REQUEST,
WLAN_S1G_AID_SWITCH_RESPONSE,
WLAN_S1G_SYNC_CONTROL,
WLAN_S1G_STA_INFO_ANNOUNCE,
WLAN_S1G_EDCA_PARAM_SET,
WLAN_S1G_EL_OPERATION,
WLAN_S1G_TWT_SETUP,
WLAN_S1G_TWT_TEARDOWN,
WLAN_S1G_SECT_GROUP_ID_LIST,
WLAN_S1G_SECT_ID_FEEDBACK,
WLAN_S1G_TWT_INFORMATION = 11,
};
/**
* ieee80211_is_s1g_short_beacon - check if frame is an S1G short beacon
* @fc: frame control bytes in little-endian byteorder
* @variable: pointer to the beacon frame elements
* @variable_len: length of the frame elements
* Return: whether or not the frame is an S1G short beacon. As per
* IEEE80211-2024 11.1.3.10.1, The S1G beacon compatibility element shall
* always be present as the first element in beacon frames generated at a
* TBTT (Target Beacon Transmission Time), so any frame not containing
* this element must have been generated at a TSBTT (Target Short Beacon
* Transmission Time) that is not a TBTT. Additionally, short beacons are
* prohibited from containing the S1G beacon compatibility element as per
* IEEE80211-2024 9.3.4.3 Table 9-76, so if we have an S1G beacon with
* either no elements or the first element is not the beacon compatibility
* element, we have a short beacon.
*/
static inline bool ieee80211_is_s1g_short_beacon(__le16 fc, const u8 *variable,
size_t variable_len)
{
if (!ieee80211_is_s1g_beacon(fc))
return false;
/*
* If the frame does not contain at least 1 element (this is perfectly
* valid in a short beacon) and is an S1G beacon, we have a short
* beacon.
*/
if (variable_len < 2)
return true;
return variable[0] != WLAN_EID_S1G_BCN_COMPAT;
}
struct s1g_tim_aid {
u16 aid;
u8 target_blk; /* Target block index */
u8 target_subblk; /* Target subblock index */
u8 target_subblk_bit; /* Target subblock bit */
};
struct s1g_tim_enc_block {
u8 enc_mode;
bool inverse;
const u8 *ptr;
u8 len;
/*
* For an OLB encoded block that spans multiple blocks, this
* is the offset into the span described by that encoded block.
*/
u8 olb_blk_offset;
};
/*
* Helper routines to quickly extract the length of an encoded block. Validation
* is also performed to ensure the length extracted lies within the TIM.
*/
static inline int ieee80211_s1g_len_bitmap(const u8 *ptr, const u8 *end)
{
u8 blkmap;
u8 n_subblks;
if (ptr >= end)
return -EINVAL;
blkmap = *ptr;
n_subblks = hweight8(blkmap);
if (ptr + 1 + n_subblks > end)
return -EINVAL;
return 1 + n_subblks;
}
static inline int ieee80211_s1g_len_single(const u8 *ptr, const u8 *end)
{
return (ptr + 1 > end) ? -EINVAL : 1;
}
static inline int ieee80211_s1g_len_olb(const u8 *ptr, const u8 *end)
{
if (ptr >= end)
return -EINVAL;
return (ptr + 1 + *ptr > end) ? -EINVAL : 1 + *ptr;
}
/*
* Enumerate all encoded blocks until we find the encoded block that describes
* our target AID. OLB is a special case as a single encoded block can describe
* multiple blocks as a single encoded block.
*/
static inline int ieee80211_s1g_find_target_block(struct s1g_tim_enc_block *enc,
const struct s1g_tim_aid *aid,
const u8 *ptr, const u8 *end)
{
/* need at least block-control octet */
while (ptr + 1 <= end) {
u8 ctrl = *ptr++;
u8 mode = ctrl & 0x03;
bool contains, inverse = ctrl & BIT(2);
u8 span, blk_off = ctrl >> 3;
int len;
switch (mode) {
case IEEE80211_S1G_TIM_ENC_MODE_BLOCK:
len = ieee80211_s1g_len_bitmap(ptr, end);
contains = blk_off == aid->target_blk;
break;
case IEEE80211_S1G_TIM_ENC_MODE_SINGLE:
len = ieee80211_s1g_len_single(ptr, end);
contains = blk_off == aid->target_blk;
break;
case IEEE80211_S1G_TIM_ENC_MODE_OLB:
len = ieee80211_s1g_len_olb(ptr, end);
/*
* An OLB encoded block can describe more then one
* block, meaning an encoded OLB block can span more
* then a single block.
*/
if (len > 0) {
/* Minus one for the length octet */
span = DIV_ROUND_UP(len - 1, 8);
/*
* Check if our target block lies within the
* block span described by this encoded block.
*/
contains = (aid->target_blk >= blk_off) &&
(aid->target_blk < blk_off + span);
}
break;
default:
return -EOPNOTSUPP;
}
if (len < 0)
return len;
if (contains) {
enc->enc_mode = mode;
enc->inverse = inverse;
enc->ptr = ptr;
enc->len = (u8)len;
enc->olb_blk_offset = blk_off;
return 0;
}
ptr += len;
}
return -ENOENT;
}
static inline bool ieee80211_s1g_parse_bitmap(struct s1g_tim_enc_block *enc,
struct s1g_tim_aid *aid)
{
const u8 *ptr = enc->ptr;
u8 blkmap = *ptr++;
/*
* If our block bitmap does not contain a set bit that corresponds
* to our AID, it could mean a variety of things depending on if
* the encoding mode is inverted or not.
*
* 1. If inverted, it means the entire subblock is present and hence
* our AID has been set.
* 2. If not inverted, it means our subblock is not present and hence
* it is all zero meaning our AID is not set.
*/
if (!(blkmap & BIT(aid->target_subblk)))
return enc->inverse;
/*
* Increment ptr by the number of set subblocks that appear before our
* target subblock. If our target subblock is 0, do nothing as ptr
* already points to our target subblock.
*/
if (aid->target_subblk)
ptr += hweight8(blkmap & GENMASK(aid->target_subblk - 1, 0));
return !!(*ptr & BIT(aid->target_subblk_bit)) ^ enc->inverse;
}
static inline bool ieee80211_s1g_parse_single(struct s1g_tim_enc_block *enc,
struct s1g_tim_aid *aid)
{
/*
* Single AID mode describes, as the name suggests, a single AID
* within the block described by the encoded block. The octet
* contains the 6 LSBs of the AID described in the block. The other
* 2 bits are reserved. When inversed, every single AID described
* by the current block have buffered traffic except for the AID
* described in the single AID octet.
*/
return ((*enc->ptr & 0x3f) == (aid->aid & 0x3f)) ^ enc->inverse;
}
static inline bool ieee80211_s1g_parse_olb(struct s1g_tim_enc_block *enc,
struct s1g_tim_aid *aid)
{
const u8 *ptr = enc->ptr;
u8 blk_len = *ptr++;
/*
* Given an OLB encoded block that describes multiple blocks,
* calculate the offset into the span. Then calculate the
* subblock location normally.
*/
u16 span_offset = aid->target_blk - enc->olb_blk_offset;
u16 subblk_idx = span_offset * 8 + aid->target_subblk;
if (subblk_idx >= blk_len)
return enc->inverse;
return !!(ptr[subblk_idx] & BIT(aid->target_subblk_bit)) ^ enc->inverse;
}
/*
* An S1G PVB has 3 non optional encoding types, each that can be inverted.
* An S1G PVB is constructed with zero or more encoded block subfields. Each
* encoded block represents a single "block" of AIDs (64), and each encoded
* block can contain one of the 3 encoding types alongside a single bit for
* whether the bits should be inverted.
*
* As the standard makes no guarantee about the ordering of encoded blocks,
* we must parse every encoded block in the worst case scenario given an
* AID that lies within the last block.
*/
static inline bool ieee80211_s1g_check_tim(const struct ieee80211_tim_ie *tim,
u8 tim_len, u16 aid)
{
int err;
struct s1g_tim_aid target_aid;
struct s1g_tim_enc_block enc_blk;
if (tim_len < 3)
return false;
target_aid.aid = aid;
target_aid.target_blk = (aid >> 6) & 0x1f;
target_aid.target_subblk = (aid >> 3) & 0x7;
target_aid.target_subblk_bit = aid & 0x7;
/*
* Find our AIDs target encoded block and fill &enc_blk with the
* encoded blocks information. If no entry is found or an error
* occurs return false.
*/
err = ieee80211_s1g_find_target_block(&enc_blk, &target_aid,
tim->virtual_map,
(const u8 *)tim + tim_len + 2);
if (err)
return false;
switch (enc_blk.enc_mode) {
case IEEE80211_S1G_TIM_ENC_MODE_BLOCK:
return ieee80211_s1g_parse_bitmap(&enc_blk, &target_aid);
case IEEE80211_S1G_TIM_ENC_MODE_SINGLE:
return ieee80211_s1g_parse_single(&enc_blk, &target_aid);
case IEEE80211_S1G_TIM_ENC_MODE_OLB:
return ieee80211_s1g_parse_olb(&enc_blk, &target_aid);
default:
return false;
}
}
#endif /* LINUX_IEEE80211_H */

View File

@ -0,0 +1,236 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* IEEE 802.11 VHT definitions
*
* Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
* <jkmaline@cc.hut.fi>
* Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
* Copyright (c) 2005, Devicescape Software, Inc.
* Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
* Copyright (c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright (c) 2016 - 2017 Intel Deutschland GmbH
* Copyright (c) 2018 - 2025 Intel Corporation
*/
#ifndef LINUX_IEEE80211_VHT_H
#define LINUX_IEEE80211_VHT_H
#include <linux/types.h>
#include <linux/if_ether.h>
#define IEEE80211_MAX_MPDU_LEN_VHT_3895 3895
#define IEEE80211_MAX_MPDU_LEN_VHT_7991 7991
#define IEEE80211_MAX_MPDU_LEN_VHT_11454 11454
/**
* enum ieee80211_vht_opmode_bits - VHT operating mode field bits
* @IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK: channel width mask
* @IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ: 20 MHz channel width
* @IEEE80211_OPMODE_NOTIF_CHANWIDTH_40MHZ: 40 MHz channel width
* @IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ: 80 MHz channel width
* @IEEE80211_OPMODE_NOTIF_CHANWIDTH_160MHZ: 160 MHz or 80+80 MHz channel width
* @IEEE80211_OPMODE_NOTIF_BW_160_80P80: 160 / 80+80 MHz indicator flag
* @IEEE80211_OPMODE_NOTIF_RX_NSS_MASK: number of spatial streams mask
* (the NSS value is the value of this field + 1)
* @IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT: number of spatial streams shift
* @IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF: indicates streams in SU-MIMO PPDU
* using a beamforming steering matrix
*/
enum ieee80211_vht_opmode_bits {
IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK = 0x03,
IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ = 0,
IEEE80211_OPMODE_NOTIF_CHANWIDTH_40MHZ = 1,
IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ = 2,
IEEE80211_OPMODE_NOTIF_CHANWIDTH_160MHZ = 3,
IEEE80211_OPMODE_NOTIF_BW_160_80P80 = 0x04,
IEEE80211_OPMODE_NOTIF_RX_NSS_MASK = 0x70,
IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT = 4,
IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF = 0x80,
};
/*
* Maximum length of AMPDU that the STA can receive in VHT.
* Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets)
*/
enum ieee80211_vht_max_ampdu_length_exp {
IEEE80211_VHT_MAX_AMPDU_8K = 0,
IEEE80211_VHT_MAX_AMPDU_16K = 1,
IEEE80211_VHT_MAX_AMPDU_32K = 2,
IEEE80211_VHT_MAX_AMPDU_64K = 3,
IEEE80211_VHT_MAX_AMPDU_128K = 4,
IEEE80211_VHT_MAX_AMPDU_256K = 5,
IEEE80211_VHT_MAX_AMPDU_512K = 6,
IEEE80211_VHT_MAX_AMPDU_1024K = 7
};
/**
* struct ieee80211_vht_mcs_info - VHT MCS information
* @rx_mcs_map: RX MCS map 2 bits for each stream, total 8 streams
* @rx_highest: Indicates highest long GI VHT PPDU data rate
* STA can receive. Rate expressed in units of 1 Mbps.
* If this field is 0 this value should not be used to
* consider the highest RX data rate supported.
* The top 3 bits of this field indicate the Maximum NSTS,total
* (a beamformee capability.)
* @tx_mcs_map: TX MCS map 2 bits for each stream, total 8 streams
* @tx_highest: Indicates highest long GI VHT PPDU data rate
* STA can transmit. Rate expressed in units of 1 Mbps.
* If this field is 0 this value should not be used to
* consider the highest TX data rate supported.
* The top 2 bits of this field are reserved, the
* 3rd bit from the top indiciates VHT Extended NSS BW
* Capability.
*/
struct ieee80211_vht_mcs_info {
__le16 rx_mcs_map;
__le16 rx_highest;
__le16 tx_mcs_map;
__le16 tx_highest;
} __packed;
/* for rx_highest */
#define IEEE80211_VHT_MAX_NSTS_TOTAL_SHIFT 13
#define IEEE80211_VHT_MAX_NSTS_TOTAL_MASK (7 << IEEE80211_VHT_MAX_NSTS_TOTAL_SHIFT)
/* for tx_highest */
#define IEEE80211_VHT_EXT_NSS_BW_CAPABLE (1 << 13)
/**
* enum ieee80211_vht_mcs_support - VHT MCS support definitions
* @IEEE80211_VHT_MCS_SUPPORT_0_7: MCSes 0-7 are supported for the
* number of streams
* @IEEE80211_VHT_MCS_SUPPORT_0_8: MCSes 0-8 are supported
* @IEEE80211_VHT_MCS_SUPPORT_0_9: MCSes 0-9 are supported
* @IEEE80211_VHT_MCS_NOT_SUPPORTED: This number of streams isn't supported
*
* These definitions are used in each 2-bit subfield of the @rx_mcs_map
* and @tx_mcs_map fields of &struct ieee80211_vht_mcs_info, which are
* both split into 8 subfields by number of streams. These values indicate
* which MCSes are supported for the number of streams the value appears
* for.
*/
enum ieee80211_vht_mcs_support {
IEEE80211_VHT_MCS_SUPPORT_0_7 = 0,
IEEE80211_VHT_MCS_SUPPORT_0_8 = 1,
IEEE80211_VHT_MCS_SUPPORT_0_9 = 2,
IEEE80211_VHT_MCS_NOT_SUPPORTED = 3,
};
/**
* struct ieee80211_vht_cap - VHT capabilities
*
* This structure is the "VHT capabilities element" as
* described in 802.11ac D3.0 8.4.2.160
* @vht_cap_info: VHT capability info
* @supp_mcs: VHT MCS supported rates
*/
struct ieee80211_vht_cap {
__le32 vht_cap_info;
struct ieee80211_vht_mcs_info supp_mcs;
} __packed;
/**
* enum ieee80211_vht_chanwidth - VHT channel width
* @IEEE80211_VHT_CHANWIDTH_USE_HT: use the HT operation IE to
* determine the channel width (20 or 40 MHz)
* @IEEE80211_VHT_CHANWIDTH_80MHZ: 80 MHz bandwidth
* @IEEE80211_VHT_CHANWIDTH_160MHZ: 160 MHz bandwidth
* @IEEE80211_VHT_CHANWIDTH_80P80MHZ: 80+80 MHz bandwidth
*/
enum ieee80211_vht_chanwidth {
IEEE80211_VHT_CHANWIDTH_USE_HT = 0,
IEEE80211_VHT_CHANWIDTH_80MHZ = 1,
IEEE80211_VHT_CHANWIDTH_160MHZ = 2,
IEEE80211_VHT_CHANWIDTH_80P80MHZ = 3,
};
/**
* struct ieee80211_vht_operation - VHT operation IE
*
* This structure is the "VHT operation element" as
* described in 802.11ac D3.0 8.4.2.161
* @chan_width: Operating channel width
* @center_freq_seg0_idx: center freq segment 0 index
* @center_freq_seg1_idx: center freq segment 1 index
* @basic_mcs_set: VHT Basic MCS rate set
*/
struct ieee80211_vht_operation {
u8 chan_width;
u8 center_freq_seg0_idx;
u8 center_freq_seg1_idx;
__le16 basic_mcs_set;
} __packed;
/* 802.11ac VHT Capabilities */
#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 0x00000000
#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 0x00000001
#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 0x00000002
#define IEEE80211_VHT_CAP_MAX_MPDU_MASK 0x00000003
#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ 0x00000004
#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ 0x00000008
#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK 0x0000000C
#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_SHIFT 2
#define IEEE80211_VHT_CAP_RXLDPC 0x00000010
#define IEEE80211_VHT_CAP_SHORT_GI_80 0x00000020
#define IEEE80211_VHT_CAP_SHORT_GI_160 0x00000040
#define IEEE80211_VHT_CAP_TXSTBC 0x00000080
#define IEEE80211_VHT_CAP_RXSTBC_1 0x00000100
#define IEEE80211_VHT_CAP_RXSTBC_2 0x00000200
#define IEEE80211_VHT_CAP_RXSTBC_3 0x00000300
#define IEEE80211_VHT_CAP_RXSTBC_4 0x00000400
#define IEEE80211_VHT_CAP_RXSTBC_MASK 0x00000700
#define IEEE80211_VHT_CAP_RXSTBC_SHIFT 8
#define IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE 0x00000800
#define IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE 0x00001000
#define IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT 13
#define IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK \
(7 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT)
#define IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT 16
#define IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK \
(7 << IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT)
#define IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE 0x00080000
#define IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE 0x00100000
#define IEEE80211_VHT_CAP_VHT_TXOP_PS 0x00200000
#define IEEE80211_VHT_CAP_HTC_VHT 0x00400000
#define IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT 23
#define IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK \
(7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT)
#define IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB 0x08000000
#define IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB 0x0c000000
#define IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN 0x10000000
#define IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN 0x20000000
#define IEEE80211_VHT_CAP_EXT_NSS_BW_SHIFT 30
#define IEEE80211_VHT_CAP_EXT_NSS_BW_MASK 0xc0000000
/**
* ieee80211_get_vht_max_nss - return max NSS for a given bandwidth/MCS
* @cap: VHT capabilities of the peer
* @bw: bandwidth to use
* @mcs: MCS index to use
* @ext_nss_bw_capable: indicates whether or not the local transmitter
* (rate scaling algorithm) can deal with the new logic
* (dot11VHTExtendedNSSBWCapable)
* @max_vht_nss: current maximum NSS as advertised by the STA in
* operating mode notification, can be 0 in which case the
* capability data will be used to derive this (from MCS support)
* Return: The maximum NSS that can be used for the given bandwidth/MCS
* combination
*
* Due to the VHT Extended NSS Bandwidth Support, the maximum NSS can
* vary for a given BW/MCS. This function parses the data.
*
* Note: This function is exported by cfg80211.
*/
int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap,
enum ieee80211_vht_chanwidth bw,
int mcs, bool ext_nss_bw_capable,
unsigned int max_vht_nss);
/* VHT action codes */
enum ieee80211_vht_actioncode {
WLAN_VHT_ACTION_COMPRESSED_BF = 0,
WLAN_VHT_ACTION_GROUPID_MGMT = 1,
WLAN_VHT_ACTION_OPMODE_NOTIF = 2,
};
#endif /* LINUX_IEEE80211_VHT_H */

File diff suppressed because it is too large Load Diff

View File

@ -685,7 +685,7 @@ ieee80211_get_he_6ghz_capa(const struct ieee80211_supported_band *sband,
}
/**
* ieee80211_get_eht_iftype_cap - return ETH capabilities for an sband's iftype
* ieee80211_get_eht_iftype_cap - return EHT capabilities for an sband's iftype
* @sband: the sband to search for the iftype on
* @iftype: enum nl80211_iftype
*
@ -786,8 +786,7 @@ struct vif_params {
* @key: key material
* @key_len: length of key material
* @cipher: cipher suite selector
* @seq: sequence counter (IV/PN) for TKIP and CCMP keys, only used
* with the get_key() callback, must be in little endian,
* @seq: sequence counter (IV/PN), must be in little endian,
* length given by @seq_len.
* @seq_len: length of @seq.
* @vlan_id: vlan_id for VLAN group key (if nonzero)
@ -10135,6 +10134,35 @@ static inline int cfg80211_color_change_notify(struct net_device *dev,
0, 0, link_id);
}
/**
* cfg80211_6ghz_power_type - determine AP regulatory power type
* @control: control flags
* @client_flags: &enum ieee80211_channel_flags for station mode to enable
* SP to LPI fallback, zero otherwise.
*
* Return: regulatory power type from &enum ieee80211_ap_reg_power
*/
static inline enum ieee80211_ap_reg_power
cfg80211_6ghz_power_type(u8 control, u32 client_flags)
{
switch (u8_get_bits(control, IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO)) {
case IEEE80211_6GHZ_CTRL_REG_LPI_AP:
case IEEE80211_6GHZ_CTRL_REG_INDOOR_LPI_AP:
return IEEE80211_REG_LPI_AP;
case IEEE80211_6GHZ_CTRL_REG_SP_AP:
case IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP_OLD:
return IEEE80211_REG_SP_AP;
case IEEE80211_6GHZ_CTRL_REG_VLP_AP:
return IEEE80211_REG_VLP_AP;
case IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP:
if (client_flags & IEEE80211_CHAN_NO_6GHZ_AFC_CLIENT)
return IEEE80211_REG_LPI_AP;
return IEEE80211_REG_SP_AP;
default:
return IEEE80211_REG_UNSET_AP;
}
}
/**
* cfg80211_links_removed - Notify about removed STA MLD setup links.
* @dev: network device.

View File

@ -7223,7 +7223,7 @@ ieee80211_get_he_6ghz_capa_vif(const struct ieee80211_supported_band *sband,
}
/**
* ieee80211_get_eht_iftype_cap_vif - return ETH capabilities for sband/vif
* ieee80211_get_eht_iftype_cap_vif - return EHT capabilities for sband/vif
* @sband: the sband to search for the iftype on
* @vif: the vif to get the iftype from
*

View File

@ -9,7 +9,7 @@
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
* Copyright 2007-2010, Intel Corporation
* Copyright(c) 2015-2017 Intel Deutschland GmbH
* Copyright (C) 2018-2024 Intel Corporation
* Copyright (C) 2018-2025 Intel Corporation
*/
/**
@ -206,7 +206,10 @@ u8 ieee80211_retrieve_addba_ext_data(struct sta_info *sta,
if (elem_len <= 0)
return 0;
elems = ieee802_11_parse_elems(elem_data, elem_len, true, NULL);
elems = ieee802_11_parse_elems(elem_data, elem_len,
IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION,
NULL);
if (!elems || elems->parse_error || !elems->addba_ext_ie)
goto free;

View File

@ -63,12 +63,14 @@ static void ieee80211_set_mu_mimo_follow(struct ieee80211_sub_if_data *sdata,
memcpy(sdata->vif.bss_conf.mu_group.position,
params->vht_mumimo_groups + WLAN_MEMBERSHIP_LEN,
WLAN_USER_POSITION_LEN);
ieee80211_link_info_change_notify(sdata, &sdata->deflink,
BSS_CHANGED_MU_GROUPS);
/* don't care about endianness - just check for 0 */
memcpy(&membership, params->vht_mumimo_groups,
WLAN_MEMBERSHIP_LEN);
mu_mimo_groups = membership != 0;
/* Unset following if configured explicitly */
eth_broadcast_addr(sdata->u.mntr.mu_follow_addr);
}
if (params->vht_mumimo_follow_addr) {
@ -76,16 +78,26 @@ static void ieee80211_set_mu_mimo_follow(struct ieee80211_sub_if_data *sdata,
is_valid_ether_addr(params->vht_mumimo_follow_addr);
ether_addr_copy(sdata->u.mntr.mu_follow_addr,
params->vht_mumimo_follow_addr);
/* Unset current membership until a management frame is RXed */
memset(sdata->vif.bss_conf.mu_group.membership, 0,
WLAN_MEMBERSHIP_LEN);
}
sdata->vif.bss_conf.mu_mimo_owner = mu_mimo_groups || mu_mimo_follow;
/* Notify only after setting mu_mimo_owner */
if (sdata->vif.bss_conf.mu_mimo_owner &&
sdata->flags & IEEE80211_SDATA_IN_DRIVER)
ieee80211_link_info_change_notify(sdata, &sdata->deflink,
BSS_CHANGED_MU_GROUPS);
}
static int ieee80211_set_mon_options(struct ieee80211_sub_if_data *sdata,
struct vif_params *params)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_sub_if_data *monitor_sdata;
struct ieee80211_sub_if_data *monitor_sdata = NULL;
/* check flags first */
if (params->flags && ieee80211_sdata_running(sdata)) {
@ -103,23 +115,28 @@ static int ieee80211_set_mon_options(struct ieee80211_sub_if_data *sdata,
return -EBUSY;
}
/* also validate MU-MIMO change */
if (ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
monitor_sdata = sdata;
else
monitor_sdata = wiphy_dereference(local->hw.wiphy,
local->monitor_sdata);
if (!monitor_sdata &&
/* validate whether MU-MIMO can be configured */
if (!ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) &&
!ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR) &&
(params->vht_mumimo_groups || params->vht_mumimo_follow_addr))
return -EOPNOTSUPP;
/* Also update dependent monitor_sdata if required */
if (test_bit(SDATA_STATE_RUNNING, &sdata->state) &&
!ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
monitor_sdata = wiphy_dereference(local->hw.wiphy,
local->monitor_sdata);
/* apply all changes now - no failures allowed */
if (monitor_sdata &&
(ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) ||
ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)))
ieee80211_set_mu_mimo_follow(monitor_sdata, params);
if (ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) ||
ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
/* This is copied in when the VIF is activated */
ieee80211_set_mu_mimo_follow(sdata, params);
if (monitor_sdata)
ieee80211_set_mu_mimo_follow(monitor_sdata, params);
}
if (params->flags) {
if (ieee80211_sdata_running(sdata)) {

View File

@ -12,15 +12,131 @@
#include "driver-ops.h"
#include "rate.h"
struct ieee80211_chanctx_user_iter {
struct ieee80211_chan_req *chanreq;
struct ieee80211_sub_if_data *sdata;
struct ieee80211_link_data *link;
enum nl80211_iftype iftype;
bool reserved, radar_required, done;
enum {
CHANCTX_ITER_POS_ASSIGNED,
CHANCTX_ITER_POS_RESERVED,
CHANCTX_ITER_POS_DONE,
} per_link;
};
enum ieee80211_chanctx_iter_type {
CHANCTX_ITER_ALL,
CHANCTX_ITER_RESERVED,
CHANCTX_ITER_ASSIGNED,
};
static void ieee80211_chanctx_user_iter_next(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx,
struct ieee80211_chanctx_user_iter *iter,
enum ieee80211_chanctx_iter_type type,
bool start)
{
lockdep_assert_wiphy(local->hw.wiphy);
if (start) {
memset(iter, 0, sizeof(*iter));
goto next_interface;
}
next_link:
for (int link_id = iter->link ? iter->link->link_id : 0;
link_id < ARRAY_SIZE(iter->sdata->link);
link_id++) {
struct ieee80211_link_data *link;
link = sdata_dereference(iter->sdata->link[link_id],
iter->sdata);
if (!link)
continue;
switch (iter->per_link) {
case CHANCTX_ITER_POS_ASSIGNED:
iter->per_link = CHANCTX_ITER_POS_RESERVED;
if (type != CHANCTX_ITER_RESERVED &&
rcu_access_pointer(link->conf->chanctx_conf) == &ctx->conf) {
iter->link = link;
iter->reserved = false;
iter->radar_required = link->radar_required;
iter->chanreq = &link->conf->chanreq;
return;
}
fallthrough;
case CHANCTX_ITER_POS_RESERVED:
iter->per_link = CHANCTX_ITER_POS_DONE;
if (type != CHANCTX_ITER_ASSIGNED &&
link->reserved_chanctx == ctx) {
iter->link = link;
iter->reserved = true;
iter->radar_required =
link->reserved_radar_required;
iter->chanreq = &link->reserved;
return;
}
fallthrough;
case CHANCTX_ITER_POS_DONE:
iter->per_link = CHANCTX_ITER_POS_ASSIGNED;
continue;
}
}
next_interface:
/* next (or first) interface */
iter->sdata = list_prepare_entry(iter->sdata, &local->interfaces, list);
list_for_each_entry_continue(iter->sdata, &local->interfaces, list) {
/* AP_VLAN has a chanctx pointer but follows AP */
if (iter->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
continue;
iter->link = NULL;
iter->per_link = CHANCTX_ITER_POS_ASSIGNED;
iter->iftype = iter->sdata->vif.type;
goto next_link;
}
iter->done = true;
}
#define for_each_chanctx_user_assigned(local, ctx, iter) \
for (ieee80211_chanctx_user_iter_next(local, ctx, iter, \
CHANCTX_ITER_ASSIGNED, \
true); \
!((iter)->done); \
ieee80211_chanctx_user_iter_next(local, ctx, iter, \
CHANCTX_ITER_ASSIGNED, \
false))
#define for_each_chanctx_user_reserved(local, ctx, iter) \
for (ieee80211_chanctx_user_iter_next(local, ctx, iter, \
CHANCTX_ITER_RESERVED, \
true); \
!((iter)->done); \
ieee80211_chanctx_user_iter_next(local, ctx, iter, \
CHANCTX_ITER_RESERVED, \
false))
#define for_each_chanctx_user_all(local, ctx, iter) \
for (ieee80211_chanctx_user_iter_next(local, ctx, iter, \
CHANCTX_ITER_ALL, \
true); \
!((iter)->done); \
ieee80211_chanctx_user_iter_next(local, ctx, iter, \
CHANCTX_ITER_ALL, \
false))
static int ieee80211_chanctx_num_assigned(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx)
{
struct ieee80211_link_data *link;
struct ieee80211_chanctx_user_iter iter;
int num = 0;
lockdep_assert_wiphy(local->hw.wiphy);
list_for_each_entry(link, &ctx->assigned_links, assigned_chanctx_list)
for_each_chanctx_user_assigned(local, ctx, &iter)
num++;
return num;
@ -29,12 +145,10 @@ static int ieee80211_chanctx_num_assigned(struct ieee80211_local *local,
static int ieee80211_chanctx_num_reserved(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx)
{
struct ieee80211_link_data *link;
struct ieee80211_chanctx_user_iter iter;
int num = 0;
lockdep_assert_wiphy(local->hw.wiphy);
list_for_each_entry(link, &ctx->reserved_links, reserved_chanctx_list)
for_each_chanctx_user_reserved(local, ctx, &iter)
num++;
return num;
@ -43,8 +157,13 @@ static int ieee80211_chanctx_num_reserved(struct ieee80211_local *local,
int ieee80211_chanctx_refcount(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx)
{
return ieee80211_chanctx_num_assigned(local, ctx) +
ieee80211_chanctx_num_reserved(local, ctx);
struct ieee80211_chanctx_user_iter iter;
int num = 0;
for_each_chanctx_user_all(local, ctx, &iter)
num++;
return num;
}
static int ieee80211_num_chanctx(struct ieee80211_local *local, int radio_idx)
@ -143,15 +262,15 @@ ieee80211_chanctx_reserved_chanreq(struct ieee80211_local *local,
const struct ieee80211_chan_req *req,
struct ieee80211_chan_req *tmp)
{
struct ieee80211_link_data *link;
struct ieee80211_chanctx_user_iter iter;
lockdep_assert_wiphy(local->hw.wiphy);
if (WARN_ON(!req))
return NULL;
list_for_each_entry(link, &ctx->reserved_links, reserved_chanctx_list) {
req = ieee80211_chanreq_compatible(&link->reserved, req, tmp);
for_each_chanctx_user_reserved(local, ctx, &iter) {
req = ieee80211_chanreq_compatible(iter.chanreq, req, tmp);
if (!req)
break;
}
@ -165,18 +284,16 @@ ieee80211_chanctx_non_reserved_chandef(struct ieee80211_local *local,
const struct ieee80211_chan_req *compat,
struct ieee80211_chan_req *tmp)
{
struct ieee80211_link_data *link;
const struct ieee80211_chan_req *comp_def = compat;
struct ieee80211_chanctx_user_iter iter;
lockdep_assert_wiphy(local->hw.wiphy);
list_for_each_entry(link, &ctx->assigned_links, assigned_chanctx_list) {
struct ieee80211_bss_conf *link_conf = link->conf;
if (link->reserved_chanctx)
for_each_chanctx_user_assigned(local, ctx, &iter) {
if (iter.link->reserved_chanctx)
continue;
comp_def = ieee80211_chanreq_compatible(&link_conf->chanreq,
comp_def = ieee80211_chanreq_compatible(iter.chanreq,
comp_def, tmp);
if (!comp_def)
break;
@ -200,7 +317,7 @@ ieee80211_chanctx_can_reserve(struct ieee80211_local *local,
if (!ieee80211_chanctx_non_reserved_chandef(local, ctx, req, &tmp))
return false;
if (!list_empty(&ctx->reserved_links) &&
if (ieee80211_chanctx_num_reserved(local, ctx) != 0 &&
ieee80211_chanctx_reserved_chanreq(local, ctx, req, &tmp))
return true;
@ -389,10 +506,10 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
* channel context.
*/
static u32
_ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx,
struct ieee80211_link_data *rsvd_for,
bool check_reserved)
__ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx,
struct ieee80211_link_data *rsvd_for,
bool check_reserved)
{
enum nl80211_chan_width max_bw;
struct cfg80211_chan_def min_def;
@ -497,13 +614,14 @@ static void ieee80211_chan_bw_change(struct ieee80211_local *local,
* the max of min required widths of all the interfaces bound to this
* channel context.
*/
void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx,
struct ieee80211_link_data *rsvd_for,
bool check_reserved)
static void
_ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx,
struct ieee80211_link_data *rsvd_for,
bool check_reserved)
{
u32 changed = _ieee80211_recalc_chanctx_min_def(local, ctx, rsvd_for,
check_reserved);
u32 changed = __ieee80211_recalc_chanctx_min_def(local, ctx, rsvd_for,
check_reserved);
if (!changed)
return;
@ -517,6 +635,12 @@ void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
ieee80211_chan_bw_change(local, ctx, false, false);
}
void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx)
{
_ieee80211_recalc_chanctx_min_def(local, ctx, NULL, false);
}
static void _ieee80211_change_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx,
struct ieee80211_chanctx *old_ctx,
@ -551,7 +675,7 @@ static void _ieee80211_change_chanctx(struct ieee80211_local *local,
ieee80211_chan_bw_change(local, old_ctx, false, true);
if (ieee80211_chanreq_identical(&ctx_req, chanreq)) {
ieee80211_recalc_chanctx_min_def(local, ctx, rsvd_for, false);
_ieee80211_recalc_chanctx_min_def(local, ctx, rsvd_for, false);
return;
}
@ -572,7 +696,8 @@ static void _ieee80211_change_chanctx(struct ieee80211_local *local,
ctx->conf.ap = chanreq->ap;
/* check if min chanctx also changed */
changed |= _ieee80211_recalc_chanctx_min_def(local, ctx, rsvd_for, false);
changed |= __ieee80211_recalc_chanctx_min_def(local, ctx, rsvd_for,
false);
ieee80211_add_wbrf(local, &ctx->conf.def);
@ -633,8 +758,6 @@ ieee80211_find_chanctx(struct ieee80211_local *local,
* context to actually be removed.
*/
link->reserved_chanctx = ctx;
list_add(&link->reserved_chanctx_list,
&ctx->reserved_links);
ieee80211_change_chanctx(local, ctx, ctx, compat);
@ -675,17 +798,13 @@ static bool
ieee80211_chanctx_radar_required(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx)
{
struct ieee80211_chanctx_conf *conf = &ctx->conf;
struct ieee80211_link_data *link;
struct ieee80211_chanctx_user_iter iter;
lockdep_assert_wiphy(local->hw.wiphy);
for_each_sdata_link(local, link) {
if (rcu_access_pointer(link->conf->chanctx_conf) != conf)
continue;
if (!link->radar_required)
continue;
return true;
for_each_chanctx_user_assigned(local, ctx, &iter) {
if (iter.radar_required)
return true;
}
return false;
@ -705,8 +824,6 @@ ieee80211_alloc_chanctx(struct ieee80211_local *local,
if (!ctx)
return NULL;
INIT_LIST_HEAD(&ctx->assigned_links);
INIT_LIST_HEAD(&ctx->reserved_links);
ctx->conf.def = chanreq->oper;
ctx->conf.ap = chanreq->ap;
ctx->conf.rx_chains_static = 1;
@ -715,7 +832,7 @@ ieee80211_alloc_chanctx(struct ieee80211_local *local,
ctx->conf.radar_enabled = false;
ctx->conf.radio_idx = radio_idx;
ctx->radar_detected = false;
_ieee80211_recalc_chanctx_min_def(local, ctx, NULL, false);
__ieee80211_recalc_chanctx_min_def(local, ctx, NULL, false);
return ctx;
}
@ -804,27 +921,17 @@ void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
{
struct ieee80211_chanctx_conf *conf = &ctx->conf;
const struct ieee80211_chan_req *compat = NULL;
struct ieee80211_link_data *link;
struct ieee80211_chanctx_user_iter iter;
struct ieee80211_chan_req tmp;
struct sta_info *sta;
lockdep_assert_wiphy(local->hw.wiphy);
for_each_sdata_link(local, link) {
struct ieee80211_bss_conf *link_conf;
if (link->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
continue;
link_conf = link->conf;
if (rcu_access_pointer(link_conf->chanctx_conf) != conf)
continue;
for_each_chanctx_user_assigned(local, ctx, &iter) {
if (!compat)
compat = &link_conf->chanreq;
compat = iter.chanreq;
compat = ieee80211_chanreq_compatible(&link_conf->chanreq,
compat = ieee80211_chanreq_compatible(iter.chanreq,
compat, &tmp);
if (WARN_ON_ONCE(!compat))
return;
@ -837,6 +944,7 @@ void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
list_for_each_entry(sta, &local->sta_list, list) {
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_chan_req tdls_chanreq = {};
struct ieee80211_link_data *link;
int tdls_link_id;
if (!sta->uploaded ||
@ -904,12 +1012,11 @@ static int ieee80211_assign_link_chanctx(struct ieee80211_link_data *link,
drv_unassign_vif_chanctx(local, sdata, link->conf, curr_ctx);
conf = NULL;
list_del(&link->assigned_chanctx_list);
}
if (new_ctx) {
/* recalc considering the link we'll use it for now */
ieee80211_recalc_chanctx_min_def(local, new_ctx, link, false);
_ieee80211_recalc_chanctx_min_def(local, new_ctx, link, false);
ret = drv_assign_vif_chanctx(local, sdata, link->conf, new_ctx);
if (assign_on_failure || !ret) {
@ -919,9 +1026,6 @@ static int ieee80211_assign_link_chanctx(struct ieee80211_link_data *link,
/* succeeded, so commit it to the data structures */
conf = &new_ctx->conf;
if (!local->in_reconfig)
list_add(&link->assigned_chanctx_list,
&new_ctx->assigned_links);
}
} else {
ret = 0;
@ -933,12 +1037,12 @@ static int ieee80211_assign_link_chanctx(struct ieee80211_link_data *link,
ieee80211_recalc_chanctx_chantype(local, curr_ctx);
ieee80211_recalc_smps_chanctx(local, curr_ctx);
ieee80211_recalc_radar_chanctx(local, curr_ctx);
ieee80211_recalc_chanctx_min_def(local, curr_ctx, NULL, false);
ieee80211_recalc_chanctx_min_def(local, curr_ctx);
}
if (new_ctx && ieee80211_chanctx_num_assigned(local, new_ctx) > 0) {
ieee80211_recalc_txpower(link, false);
ieee80211_recalc_chanctx_min_def(local, new_ctx, NULL, false);
ieee80211_recalc_chanctx_min_def(local, new_ctx);
}
if (conf) {
@ -971,21 +1075,21 @@ static int ieee80211_assign_link_chanctx(struct ieee80211_link_data *link,
void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *chanctx)
{
struct ieee80211_chanctx_user_iter iter;
struct ieee80211_sub_if_data *sdata;
u8 rx_chains_static, rx_chains_dynamic;
struct ieee80211_link_data *link;
lockdep_assert_wiphy(local->hw.wiphy);
rx_chains_static = 1;
rx_chains_dynamic = 1;
for_each_sdata_link(local, link) {
for_each_chanctx_user_assigned(local, chanctx, &iter) {
u8 needed_static, needed_dynamic;
switch (link->sdata->vif.type) {
switch (iter.iftype) {
case NL80211_IFTYPE_STATION:
if (!link->sdata->u.mgd.associated)
if (!iter.sdata->u.mgd.associated)
continue;
break;
case NL80211_IFTYPE_MONITOR:
@ -1001,26 +1105,23 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
continue;
}
if (rcu_access_pointer(link->conf->chanctx_conf) != &chanctx->conf)
continue;
if (link->sdata->vif.type == NL80211_IFTYPE_MONITOR) {
if (iter.iftype == NL80211_IFTYPE_MONITOR) {
rx_chains_dynamic = rx_chains_static = local->rx_chains;
break;
}
switch (link->smps_mode) {
switch (iter.link->smps_mode) {
default:
WARN_ONCE(1, "Invalid SMPS mode %d\n",
link->smps_mode);
iter.link->smps_mode);
fallthrough;
case IEEE80211_SMPS_OFF:
needed_static = link->needed_rx_chains;
needed_dynamic = link->needed_rx_chains;
needed_static = iter.link->needed_rx_chains;
needed_dynamic = iter.link->needed_rx_chains;
break;
case IEEE80211_SMPS_DYNAMIC:
needed_static = 1;
needed_dynamic = link->needed_rx_chains;
needed_dynamic = iter.link->needed_rx_chains;
break;
case IEEE80211_SMPS_STATIC:
needed_static = 1;
@ -1108,7 +1209,6 @@ void ieee80211_link_unreserve_chanctx(struct ieee80211_link_data *link)
if (WARN_ON(!ctx))
return;
list_del(&link->reserved_chanctx_list);
link->reserved_chanctx = NULL;
if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0) {
@ -1142,9 +1242,9 @@ ieee80211_replace_chanctx(struct ieee80211_local *local,
struct wiphy *wiphy = local->hw.wiphy;
const struct wiphy_radio *radio;
if (!curr_ctx || (curr_ctx->replace_state ==
IEEE80211_CHANCTX_WILL_BE_REPLACED) ||
!list_empty(&curr_ctx->reserved_links)) {
if (!curr_ctx ||
curr_ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED ||
ieee80211_chanctx_num_reserved(local, curr_ctx) != 0) {
/*
* Another link already requested this context for a
* reservation. Find another one hoping all links assigned
@ -1167,7 +1267,7 @@ ieee80211_replace_chanctx(struct ieee80211_local *local,
IEEE80211_CHANCTX_REPLACE_NONE)
continue;
if (!list_empty(&ctx->reserved_links))
if (ieee80211_chanctx_num_reserved(local, ctx) != 0)
continue;
if (ctx->conf.radio_idx >= 0) {
@ -1185,9 +1285,9 @@ ieee80211_replace_chanctx(struct ieee80211_local *local,
* If that's true then all available contexts already have reservations
* and cannot be used.
*/
if (!curr_ctx || (curr_ctx->replace_state ==
IEEE80211_CHANCTX_WILL_BE_REPLACED) ||
!list_empty(&curr_ctx->reserved_links))
if (!curr_ctx ||
curr_ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED ||
ieee80211_chanctx_num_reserved(local, curr_ctx) != 0)
return ERR_PTR(-EBUSY);
new_ctx = ieee80211_alloc_chanctx(local, chanreq, mode, -1);
@ -1267,7 +1367,6 @@ int ieee80211_link_reserve_chanctx(struct ieee80211_link_data *link,
return PTR_ERR(new_ctx);
}
list_add(&link->reserved_chanctx_list, &new_ctx->reserved_links);
link->reserved_chanctx = new_ctx;
link->reserved = *chanreq;
link->reserved_radar_required = radar_required;
@ -1381,7 +1480,6 @@ ieee80211_link_use_reserved_reassign(struct ieee80211_link_data *link)
vif_chsw[0].new_ctx = &new_ctx->conf;
vif_chsw[0].link_conf = link->conf;
list_del(&link->reserved_chanctx_list);
link->reserved_chanctx = NULL;
err = drv_switch_vif_chanctx(local, vif_chsw, 1,
@ -1394,7 +1492,6 @@ ieee80211_link_use_reserved_reassign(struct ieee80211_link_data *link)
}
link->radar_required = link->reserved_radar_required;
list_move(&link->assigned_chanctx_list, &new_ctx->assigned_links);
rcu_assign_pointer(link_conf->chanctx_conf, &new_ctx->conf);
if (sdata->vif.type == NL80211_IFTYPE_AP)
@ -1405,7 +1502,7 @@ ieee80211_link_use_reserved_reassign(struct ieee80211_link_data *link)
if (ieee80211_chanctx_refcount(local, old_ctx) == 0)
ieee80211_free_chanctx(local, old_ctx, false);
ieee80211_recalc_chanctx_min_def(local, new_ctx, NULL, false);
ieee80211_recalc_chanctx_min_def(local, new_ctx);
ieee80211_recalc_smps_chanctx(local, new_ctx);
ieee80211_recalc_radar_chanctx(local, new_ctx);
@ -1451,7 +1548,6 @@ ieee80211_link_use_reserved_assign(struct ieee80211_link_data *link)
ieee80211_change_chanctx(local, new_ctx, new_ctx, chanreq);
list_del(&link->reserved_chanctx_list);
link->reserved_chanctx = NULL;
err = ieee80211_assign_link_chanctx(link, new_ctx, false);
@ -1497,7 +1593,6 @@ static int ieee80211_chsw_switch_vifs(struct ieee80211_local *local,
int n_vifs)
{
struct ieee80211_vif_chanctx_switch *vif_chsw;
struct ieee80211_link_data *link;
struct ieee80211_chanctx *ctx, *old_ctx;
int i, err;
@ -1509,6 +1604,8 @@ static int ieee80211_chsw_switch_vifs(struct ieee80211_local *local,
i = 0;
list_for_each_entry(ctx, &local->chanctx_list, list) {
struct ieee80211_chanctx_user_iter iter;
if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
continue;
@ -1517,16 +1614,15 @@ static int ieee80211_chsw_switch_vifs(struct ieee80211_local *local,
goto out;
}
list_for_each_entry(link, &ctx->reserved_links,
reserved_chanctx_list) {
if (!ieee80211_link_has_in_place_reservation(link))
for_each_chanctx_user_reserved(local, ctx, &iter) {
if (!ieee80211_link_has_in_place_reservation(iter.link))
continue;
old_ctx = ieee80211_link_get_chanctx(link);
vif_chsw[i].vif = &link->sdata->vif;
old_ctx = ieee80211_link_get_chanctx(iter.link);
vif_chsw[i].vif = &iter.sdata->vif;
vif_chsw[i].old_ctx = &old_ctx->conf;
vif_chsw[i].new_ctx = &ctx->conf;
vif_chsw[i].link_conf = link->conf;
vif_chsw[i].link_conf = iter.link->conf;
i++;
}
@ -1551,7 +1647,7 @@ static int ieee80211_chsw_switch_ctxs(struct ieee80211_local *local)
if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
continue;
if (!list_empty(&ctx->replace_ctx->assigned_links))
if (ieee80211_chanctx_num_assigned(local, ctx) != 0)
continue;
ieee80211_del_chanctx(local, ctx->replace_ctx, false);
@ -1568,7 +1664,7 @@ err:
if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
continue;
if (!list_empty(&ctx->replace_ctx->assigned_links))
if (ieee80211_chanctx_num_assigned(local, ctx) != 0)
continue;
ieee80211_del_chanctx(local, ctx, false);
@ -1603,7 +1699,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
*/
list_for_each_entry(ctx, &local->chanctx_list, list) {
struct ieee80211_link_data *link;
struct ieee80211_chanctx_user_iter iter;
if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
continue;
@ -1619,12 +1715,11 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
n_reserved = 0;
n_ready = 0;
list_for_each_entry(link, &ctx->replace_ctx->assigned_links,
assigned_chanctx_list) {
for_each_chanctx_user_assigned(local, ctx, &iter) {
n_assigned++;
if (link->reserved_chanctx) {
if (iter.link->reserved_chanctx) {
n_reserved++;
if (link->reserved_ready)
if (iter.link->reserved_ready)
n_ready++;
}
}
@ -1641,13 +1736,12 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
}
ctx->conf.radar_enabled = false;
list_for_each_entry(link, &ctx->reserved_links,
reserved_chanctx_list) {
if (ieee80211_link_has_in_place_reservation(link) &&
!link->reserved_ready)
for_each_chanctx_user_reserved(local, ctx, &iter) {
if (ieee80211_link_has_in_place_reservation(iter.link) &&
!iter.link->reserved_ready)
return -EAGAIN;
old_ctx = ieee80211_link_get_chanctx(link);
old_ctx = ieee80211_link_get_chanctx(iter.link);
if (old_ctx) {
if (old_ctx->replace_state ==
IEEE80211_CHANCTX_WILL_BE_REPLACED)
@ -1658,7 +1752,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
n_vifs_ctxless++;
}
if (link->reserved_radar_required)
if (iter.radar_required)
ctx->conf.radar_enabled = true;
}
}
@ -1673,7 +1767,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
/* update station rate control and min width before switch */
list_for_each_entry(ctx, &local->chanctx_list, list) {
struct ieee80211_link_data *link;
struct ieee80211_chanctx_user_iter iter;
if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
continue;
@ -1683,17 +1777,16 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
goto err;
}
list_for_each_entry(link, &ctx->reserved_links,
reserved_chanctx_list) {
if (!ieee80211_link_has_in_place_reservation(link))
for_each_chanctx_user_reserved(local, ctx, &iter) {
if (!ieee80211_link_has_in_place_reservation(iter.link))
continue;
ieee80211_chan_bw_change(local,
ieee80211_link_get_chanctx(link),
ieee80211_link_get_chanctx(iter.link),
true, true);
}
ieee80211_recalc_chanctx_min_def(local, ctx, NULL, true);
_ieee80211_recalc_chanctx_min_def(local, ctx, NULL, true);
}
/*
@ -1718,7 +1811,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
* context(s).
*/
list_for_each_entry(ctx, &local->chanctx_list, list) {
struct ieee80211_link_data *link, *link_tmp;
struct ieee80211_chanctx_user_iter iter;
if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
continue;
@ -1728,9 +1821,9 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
goto err;
}
list_for_each_entry(link, &ctx->reserved_links,
reserved_chanctx_list) {
struct ieee80211_sub_if_data *sdata = link->sdata;
for_each_chanctx_user_reserved(local, ctx, &iter) {
struct ieee80211_link_data *link = iter.link;
struct ieee80211_sub_if_data *sdata = iter.sdata;
struct ieee80211_bss_conf *link_conf = link->conf;
u64 changed = 0;
@ -1746,9 +1839,9 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
ieee80211_check_fast_xmit_iface(sdata);
link->radar_required = link->reserved_radar_required;
link->radar_required = iter.radar_required;
if (link_conf->chanreq.oper.width != link->reserved.oper.width)
if (link_conf->chanreq.oper.width != iter.chanreq->oper.width)
changed = BSS_CHANGED_BANDWIDTH;
ieee80211_link_update_chanreq(link, &link->reserved);
@ -1763,19 +1856,15 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
ieee80211_recalc_chanctx_chantype(local, ctx);
ieee80211_recalc_smps_chanctx(local, ctx);
ieee80211_recalc_radar_chanctx(local, ctx);
ieee80211_recalc_chanctx_min_def(local, ctx, NULL, false);
ieee80211_recalc_chanctx_min_def(local, ctx);
list_for_each_entry_safe(link, link_tmp, &ctx->reserved_links,
reserved_chanctx_list) {
if (ieee80211_link_get_chanctx(link) != ctx)
for_each_chanctx_user_reserved(local, ctx, &iter) {
if (ieee80211_link_get_chanctx(iter.link) != ctx)
continue;
list_del(&link->reserved_chanctx_list);
list_move(&link->assigned_chanctx_list,
&ctx->assigned_links);
link->reserved_chanctx = NULL;
iter.link->reserved_chanctx = NULL;
ieee80211_link_chanctx_reservation_complete(link);
ieee80211_link_chanctx_reservation_complete(iter.link);
ieee80211_chan_bw_change(local, ctx, false, false);
}
@ -1786,12 +1875,10 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
* reservation for originally requested interface has already
* succeeded at this point.
*/
list_for_each_entry_safe(link, link_tmp, &ctx->reserved_links,
reserved_chanctx_list) {
if (WARN_ON(ieee80211_link_has_in_place_reservation(link)))
continue;
for_each_chanctx_user_reserved(local, ctx, &iter) {
struct ieee80211_link_data *link = iter.link;
if (WARN_ON(link->reserved_chanctx != ctx))
if (WARN_ON(ieee80211_link_has_in_place_reservation(link)))
continue;
if (!link->reserved_ready)
@ -1834,15 +1921,14 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
err:
list_for_each_entry(ctx, &local->chanctx_list, list) {
struct ieee80211_link_data *link, *link_tmp;
struct ieee80211_chanctx_user_iter iter;
if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
continue;
list_for_each_entry_safe(link, link_tmp, &ctx->reserved_links,
reserved_chanctx_list) {
ieee80211_link_unreserve_chanctx(link);
ieee80211_link_chanctx_reservation_complete(link);
for_each_chanctx_user_reserved(local, ctx, &iter) {
ieee80211_link_unreserve_chanctx(iter.link);
ieee80211_link_chanctx_reservation_complete(iter.link);
}
}
@ -1949,7 +2035,6 @@ int _ieee80211_link_use_channel(struct ieee80211_link_data *link,
/* remove reservation */
WARN_ON(link->reserved_chanctx != ctx);
link->reserved_chanctx = NULL;
list_del(&link->reserved_chanctx_list);
}
if (ret) {
@ -2046,29 +2131,17 @@ ieee80211_chanctx_recheck(struct ieee80211_local *local,
struct ieee80211_chan_req *tmp)
{
const struct ieee80211_chan_req *ret = req;
struct ieee80211_link_data *link;
struct ieee80211_chanctx_user_iter iter;
lockdep_assert_wiphy(local->hw.wiphy);
for_each_sdata_link(local, link) {
if (link == skip_link)
for_each_chanctx_user_all(local, ctx, &iter) {
if (iter.link == skip_link)
continue;
if (rcu_access_pointer(link->conf->chanctx_conf) == &ctx->conf) {
ret = ieee80211_chanreq_compatible(ret,
&link->conf->chanreq,
tmp);
if (!ret)
return NULL;
}
if (link->reserved_chanctx == ctx) {
ret = ieee80211_chanreq_compatible(ret,
&link->reserved,
tmp);
if (!ret)
return NULL;
}
ret = ieee80211_chanreq_compatible(ret, iter.chanreq, tmp);
if (!ret)
return NULL;
}
*tmp = *ret;

View File

@ -476,8 +476,12 @@ void drv_link_info_changed(struct ieee80211_local *local,
if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE ||
sdata->vif.type == NL80211_IFTYPE_NAN ||
(sdata->vif.type == NL80211_IFTYPE_MONITOR &&
!sdata->vif.bss_conf.mu_mimo_owner &&
!(changed & BSS_CHANGED_TXPOWER))))
changed & ~(BSS_CHANGED_TXPOWER |
BSS_CHANGED_MU_GROUPS))))
return;
if (WARN_ON_ONCE(changed & BSS_CHANGED_MU_GROUPS &&
!sdata->vif.bss_conf.mu_mimo_owner))
return;
if (!check_sdata_in_driver(sdata))

View File

@ -3,7 +3,7 @@
* HE handling
*
* Copyright(c) 2017 Intel Deutschland GmbH
* Copyright(c) 2019 - 2024 Intel Corporation
* Copyright(c) 2019-2025 Intel Corporation
*/
#include "ieee80211_i.h"
@ -313,7 +313,7 @@ bool ieee80211_prepare_rx_omi_bw(struct ieee80211_link_sta *pub_link_sta,
ieee80211_link_sta_rc_update_omi(link, link_sta);
} else {
link_sta->rx_omi_bw_rx = bw;
ieee80211_recalc_chanctx_min_def(local, chanctx, NULL, false);
ieee80211_recalc_chanctx_min_def(local, chanctx);
}
link_sta->rx_omi_bw_staging = bw;
@ -359,7 +359,7 @@ void ieee80211_finalize_rx_omi_bw(struct ieee80211_link_sta *pub_link_sta)
/* channel context in finalize only when narrowing bandwidth */
WARN_ON(link_sta->rx_omi_bw_rx < link_sta->rx_omi_bw_staging);
link_sta->rx_omi_bw_rx = link_sta->rx_omi_bw_staging;
ieee80211_recalc_chanctx_min_def(local, chanctx, NULL, false);
ieee80211_recalc_chanctx_min_def(local, chanctx);
}
trace_api_return_void(local);

View File

@ -9,7 +9,7 @@
* Copyright 2009, Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright(c) 2016 Intel Deutschland GmbH
* Copyright(c) 2018-2024 Intel Corporation
* Copyright(c) 2018-2025 Intel Corporation
*/
#include <linux/delay.h>
@ -1554,6 +1554,7 @@ void ieee80211_rx_mgmt_probe_beacon(struct ieee80211_sub_if_data *sdata,
{
size_t baselen;
struct ieee802_11_elems *elems;
u16 type;
BUILD_BUG_ON(offsetof(typeof(mgmt->u.probe_resp), variable) !=
offsetof(typeof(mgmt->u.beacon), variable));
@ -1566,8 +1567,9 @@ void ieee80211_rx_mgmt_probe_beacon(struct ieee80211_sub_if_data *sdata,
if (baselen > len)
return;
type = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_TYPE;
elems = ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
len - baselen, false, NULL);
len - baselen, type, NULL);
if (elems) {
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, elems);
@ -1616,9 +1618,11 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
if (ies_len < 0)
break;
elems = ieee802_11_parse_elems(
mgmt->u.action.u.chan_switch.variable,
ies_len, true, NULL);
elems = ieee802_11_parse_elems(mgmt->u.action.u.chan_switch.variable,
ies_len,
IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION,
NULL);
if (elems && !elems->parse_error)
ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt,

View File

@ -916,9 +916,6 @@ struct ieee80211_chanctx {
struct list_head list;
struct rcu_head rcu_head;
struct list_head assigned_links;
struct list_head reserved_links;
enum ieee80211_chanctx_replace_state replace_state;
struct ieee80211_chanctx *replace_ctx;
@ -1071,9 +1068,6 @@ struct ieee80211_link_data {
struct ieee80211_sub_if_data *sdata;
unsigned int link_id;
struct list_head assigned_chanctx_list; /* protected by wiphy mutex */
struct list_head reserved_chanctx_list; /* protected by wiphy mutex */
/* multicast keys only */
struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS +
NUM_DEFAULT_MGMT_KEYS +
@ -1239,9 +1233,12 @@ struct ieee80211_sub_if_data *vif_to_sdata(struct ieee80211_vif *p)
for (struct ieee80211_sub_if_data *___sdata = NULL; \
!___sdata; \
___sdata = (void *)~0 /* always stop */) \
for (int ___link_id = ARRAY_SIZE(___sdata->link); \
___link_id; ___link_id = 0 /* always stop */) \
list_for_each_entry(___sdata, &(_local)->interfaces, list) \
if (ieee80211_sdata_running(___sdata)) \
for (int ___link_id = 0; \
if (___link_id == ARRAY_SIZE(___sdata->link) && \
ieee80211_sdata_running(___sdata)) \
for (___link_id = 0; \
___link_id < ARRAY_SIZE(___sdata->link); \
___link_id++) \
if ((_link = wiphy_dereference((_local)->hw.wiphy, \
@ -1255,9 +1252,12 @@ struct ieee80211_sub_if_data *vif_to_sdata(struct ieee80211_vif *p)
for (struct ieee80211_sub_if_data *___sdata = NULL; \
!___sdata; \
___sdata = (void *)~0 /* always stop */) \
list_for_each_entry_rcu(___sdata, &(_local)->interfaces, list) \
if (ieee80211_sdata_running(___sdata)) \
for (int ___link_id = 0; \
for (int ___link_id = ARRAY_SIZE(___sdata->link); \
___link_id; ___link_id = 0 /* always stop */) \
list_for_each_entry(___sdata, &(_local)->interfaces, list) \
if (___link_id == ARRAY_SIZE(___sdata->link) && \
ieee80211_sdata_running(___sdata)) \
for (___link_id = 0; \
___link_id < ARRAY_SIZE((___sdata)->link); \
___link_id++) \
if ((_link = rcu_dereference((___sdata)->link[___link_id])))
@ -2107,7 +2107,8 @@ void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,
const int offset);
int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up);
void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata);
int ieee80211_add_virtual_monitor(struct ieee80211_local *local);
int ieee80211_add_virtual_monitor(struct ieee80211_local *local,
struct ieee80211_sub_if_data *creator_sdata);
void ieee80211_del_virtual_monitor(struct ieee80211_local *local);
bool __ieee80211_recalc_txpower(struct ieee80211_link_data *link);
@ -2422,7 +2423,8 @@ static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata,
* @mode: connection mode for parsing
* @start: pointer to the elements
* @len: length of the elements
* @action: %true if the elements came from an action frame
* @type: type of the frame the elements came from
* (action, probe response, beacon, etc.)
* @filter: bitmap of element IDs to filter out while calculating
* the element CRC
* @crc: CRC starting value
@ -2440,7 +2442,7 @@ struct ieee80211_elems_parse_params {
enum ieee80211_conn_mode mode;
const u8 *start;
size_t len;
bool action;
u8 type;
u64 filter;
u32 crc;
struct cfg80211_bss *bss;
@ -2452,17 +2454,14 @@ struct ieee802_11_elems *
ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params);
static inline struct ieee802_11_elems *
ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
u64 filter, u32 crc,
struct cfg80211_bss *bss)
ieee802_11_parse_elems(const u8 *start, size_t len, u8 type,
struct cfg80211_bss *bss)
{
struct ieee80211_elems_parse_params params = {
.mode = IEEE80211_CONN_MODE_HIGHEST,
.start = start,
.len = len,
.action = action,
.filter = filter,
.crc = crc,
.type = type,
.bss = bss,
.link_id = -1,
};
@ -2470,13 +2469,6 @@ ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
return ieee802_11_parse_elems_full(&params);
}
static inline struct ieee802_11_elems *
ieee802_11_parse_elems(const u8 *start, size_t len, bool action,
struct cfg80211_bss *bss)
{
return ieee802_11_parse_elems_crc(start, len, action, 0, 0, bss);
}
extern const int ieee802_1d_to_ac[8];
static inline int ieee80211_ac_from_tid(int tid)
@ -2768,9 +2760,7 @@ int ieee80211_chanctx_refcount(struct ieee80211_local *local,
void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *chanctx);
void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx,
struct ieee80211_link_data *rsvd_for,
bool check_reserved);
struct ieee80211_chanctx *ctx);
bool ieee80211_is_radar_required(struct ieee80211_local *local,
struct cfg80211_scan_request *req);
bool ieee80211_is_radio_idx_in_scan_req(struct wiphy *wiphy,

View File

@ -733,8 +733,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
ieee80211_configure_filter(local);
ieee80211_hw_config(local, -1, hw_reconf_flags);
/* Passing NULL means an interface is picked for configuration */
if (local->virt_monitors == local->open_count)
ieee80211_add_virtual_monitor(local);
ieee80211_add_virtual_monitor(local, NULL);
}
void ieee80211_stop_mbssid(struct ieee80211_sub_if_data *sdata)
@ -1168,7 +1169,8 @@ static void ieee80211_sdata_init(struct ieee80211_local *local,
ieee80211_link_init(sdata, -1, &sdata->deflink, &sdata->vif.bss_conf);
}
int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
int ieee80211_add_virtual_monitor(struct ieee80211_local *local,
struct ieee80211_sub_if_data *creator_sdata)
{
struct ieee80211_sub_if_data *sdata;
int ret;
@ -1176,10 +1178,14 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
ASSERT_RTNL();
lockdep_assert_wiphy(local->hw.wiphy);
if (local->monitor_sdata ||
ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
if (ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
return 0;
/* Already have a monitor set up, configure it */
sdata = wiphy_dereference(local->hw.wiphy, local->monitor_sdata);
if (sdata)
goto configure_monitor;
sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL);
if (!sdata)
return -ENOMEM;
@ -1232,6 +1238,32 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
skb_queue_head_init(&sdata->status_queue);
wiphy_work_init(&sdata->work, ieee80211_iface_work);
configure_monitor:
/* Copy in the MU-MIMO configuration if set */
if (!creator_sdata) {
struct ieee80211_sub_if_data *other;
list_for_each_entry(other, &local->mon_list, list) {
if (!other->vif.bss_conf.mu_mimo_owner)
continue;
creator_sdata = other;
break;
}
}
if (creator_sdata && creator_sdata->vif.bss_conf.mu_mimo_owner) {
sdata->vif.bss_conf.mu_mimo_owner = true;
memcpy(&sdata->vif.bss_conf.mu_group,
&creator_sdata->vif.bss_conf.mu_group,
sizeof(sdata->vif.bss_conf.mu_group));
memcpy(&sdata->u.mntr.mu_follow_addr,
creator_sdata->u.mntr.mu_follow_addr, ETH_ALEN);
ieee80211_link_info_change_notify(sdata, &sdata->deflink,
BSS_CHANGED_MU_GROUPS);
}
return 0;
}
@ -1388,11 +1420,13 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
if (res)
goto err_stop;
} else {
if (local->virt_monitors == 0 && local->open_count == 0) {
res = ieee80211_add_virtual_monitor(local);
/* add/configure if there is no non-monitor interface */
if (local->virt_monitors == local->open_count) {
res = ieee80211_add_virtual_monitor(local, sdata);
if (res)
goto err_stop;
}
local->virt_monitors++;
/* must be before the call to ieee80211_configure_filter */

View File

@ -23,9 +23,6 @@ static void ieee80211_update_apvlan_links(struct ieee80211_sub_if_data *sdata)
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
int link_id;
if (!vlan)
continue;
/* No support for 4addr with MLO yet */
if (vlan->wdev.use_4addr)
return;
@ -119,8 +116,6 @@ void ieee80211_link_init(struct ieee80211_sub_if_data *sdata,
ieee80211_color_change_finalize_work);
wiphy_delayed_work_init(&link->color_collision_detect_work,
ieee80211_color_collision_detection_work);
INIT_LIST_HEAD(&link->assigned_chanctx_list);
INIT_LIST_HEAD(&link->reserved_chanctx_list);
wiphy_delayed_work_init(&link->dfs_cac_timer_work,
ieee80211_dfs_cac_timer_work);

View File

@ -356,8 +356,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE ||
sdata->vif.type == NL80211_IFTYPE_NAN ||
(sdata->vif.type == NL80211_IFTYPE_MONITOR &&
!sdata->vif.bss_conf.mu_mimo_owner &&
!(changed & BSS_CHANGED_TXPOWER))))
changed & ~BSS_CHANGED_TXPOWER)))
return;
if (!check_sdata_in_driver(sdata))

View File

@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2008, 2009 open80211s Ltd.
* Copyright (C) 2018 - 2024 Intel Corporation
* Copyright (C) 2018 - 2025 Intel Corporation
* Authors: Luis Carlos Cobo <luisca@cozybit.com>
* Javier Cardona <javier@cozybit.com>
*/
@ -1410,7 +1410,10 @@ ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata,
if (baselen > len)
return;
elems = ieee802_11_parse_elems(pos, len - baselen, false, NULL);
elems = ieee802_11_parse_elems(pos, len - baselen,
IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_PROBE_REQ,
NULL);
if (!elems)
return;
@ -1455,11 +1458,11 @@ free:
}
static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
u16 stype,
struct ieee80211_mgmt *mgmt,
size_t len,
struct ieee80211_rx_status *rx_status)
{
u16 type = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_TYPE;
struct ieee80211_local *local = sdata->local;
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
struct ieee802_11_elems *elems;
@ -1469,7 +1472,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
enum nl80211_band band = rx_status->band;
/* ignore ProbeResp to foreign address */
if (stype == IEEE80211_STYPE_PROBE_RESP &&
if (type == (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP) &&
!ether_addr_equal(mgmt->da, sdata->vif.addr))
return;
@ -1478,8 +1481,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
return;
elems = ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
len - baselen,
false, NULL);
len - baselen, type, NULL);
if (!elems)
return;
@ -1514,7 +1516,9 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
}
if (ifmsh->sync_ops)
ifmsh->sync_ops->rx_bcn_presp(sdata, stype, mgmt, len,
ifmsh->sync_ops->rx_bcn_presp(sdata,
type & IEEE80211_FCTL_STYPE,
mgmt, len,
elems->mesh_config, rx_status);
free:
kfree(elems);
@ -1622,7 +1626,10 @@ static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata,
pos = mgmt->u.action.u.chan_switch.variable;
baselen = offsetof(struct ieee80211_mgmt,
u.action.u.chan_switch.variable);
elems = ieee802_11_parse_elems(pos, len - baselen, true, NULL);
elems = ieee802_11_parse_elems(pos, len - baselen,
IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION,
NULL);
if (!elems)
return;
@ -1699,8 +1706,7 @@ void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
switch (stype) {
case IEEE80211_STYPE_PROBE_RESP:
case IEEE80211_STYPE_BEACON:
ieee80211_mesh_rx_bcn_presp(sdata, stype, mgmt, skb->len,
rx_status);
ieee80211_mesh_rx_bcn_presp(sdata, mgmt, skb->len, rx_status);
break;
case IEEE80211_STYPE_PROBE_REQ:
ieee80211_mesh_rx_probe_req(sdata, mgmt, skb->len);

View File

@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2008, 2009 open80211s Ltd.
* Copyright (C) 2019, 2021-2023 Intel Corporation
* Copyright (C) 2019, 2021-2023, 2025 Intel Corporation
* Author: Luis Carlos Cobo <luisca@cozybit.com>
*/
@ -951,7 +951,10 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt;
elems = ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable,
len - baselen, false, NULL);
len - baselen,
IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION,
NULL);
if (!elems)
return;

View File

@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2008, 2009 open80211s Ltd.
* Copyright (C) 2019, 2021-2024 Intel Corporation
* Copyright (C) 2019, 2021-2025 Intel Corporation
* Author: Luis Carlos Cobo <luisca@cozybit.com>
*/
#include <linux/gfp.h>
@ -1248,7 +1248,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
if (baselen > len)
return;
}
elems = ieee802_11_parse_elems(baseaddr, len - baselen, true, NULL);
elems = ieee802_11_parse_elems(baseaddr, len - baselen,
IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION,
NULL);
if (elems) {
mesh_process_plink_frame(sdata, mgmt, elems, rx_status);
kfree(elems);

View File

@ -276,11 +276,8 @@ ieee80211_determine_ap_chan(struct ieee80211_sub_if_data *sdata,
return IEEE80211_CONN_MODE_VHT;
}
} else if (!vht_oper || !elems->vht_cap_elem) {
if (sband->band == NL80211_BAND_5GHZ) {
sdata_info(sdata,
"VHT information is missing, disabling VHT\n");
if (sband->band == NL80211_BAND_5GHZ)
return IEEE80211_CONN_MODE_HT;
}
no_vht = true;
} else if (sband->band == NL80211_BAND_2GHZ) {
no_vht = true;
@ -1002,6 +999,9 @@ ieee80211_determine_chan_mode(struct ieee80211_sub_if_data *sdata,
.from_ap = true,
.start = ies->data,
.len = ies->len,
.type = ies->from_beacon ?
IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON :
IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP,
};
struct ieee802_11_elems *elems;
struct ieee80211_supported_band *sband;
@ -5180,7 +5180,9 @@ static void ieee80211_epcs_teardown(struct ieee80211_sub_if_data *sdata)
continue;
}
elems = ieee802_11_parse_elems(ies->data, ies->len, false,
elems = ieee802_11_parse_elems(ies->data, ies->len,
IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_BEACON,
NULL);
if (!elems) {
rcu_read_unlock();
@ -5226,6 +5228,7 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link,
.len = elem_len,
.link_id = link_id == assoc_data->assoc_link_id ? -1 : link_id,
.from_ap = true,
.type = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_TYPE,
};
bool is_5ghz = cbss->channel->band == NL80211_BAND_5GHZ;
bool is_6ghz = cbss->channel->band == NL80211_BAND_6GHZ;
@ -6031,24 +6034,6 @@ ieee80211_determine_our_sta_mode_assoc(struct ieee80211_sub_if_data *sdata,
conn->bw_limit, tmp.bw_limit);
}
static enum ieee80211_ap_reg_power
ieee80211_ap_power_type(u8 control)
{
switch (u8_get_bits(control, IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO)) {
case IEEE80211_6GHZ_CTRL_REG_LPI_AP:
case IEEE80211_6GHZ_CTRL_REG_INDOOR_LPI_AP:
return IEEE80211_REG_LPI_AP;
case IEEE80211_6GHZ_CTRL_REG_SP_AP:
case IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP:
case IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP_OLD:
return IEEE80211_REG_SP_AP;
case IEEE80211_6GHZ_CTRL_REG_VLP_AP:
return IEEE80211_REG_VLP_AP;
default:
return IEEE80211_REG_UNSET_AP;
}
}
static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
struct ieee80211_link_data *link,
int link_id,
@ -6091,7 +6076,8 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
he_6ghz_oper = ieee80211_he_6ghz_oper(elems->he_operation);
if (he_6ghz_oper)
link->conf->power_type =
ieee80211_ap_power_type(he_6ghz_oper->control);
cfg80211_6ghz_power_type(he_6ghz_oper->control,
cbss->channel->flags);
else
link_info(link,
"HE 6 GHz operation missing (on %d MHz), expect issues\n",
@ -6359,6 +6345,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
.bss = NULL,
.link_id = -1,
.from_ap = true,
.type = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_TYPE,
};
struct ieee802_11_elems *elems;
int ac;
@ -7267,7 +7254,9 @@ ieee80211_mgd_check_cross_link_csa(struct ieee80211_sub_if_data *sdata,
(prof->sta_info_len - 1),
len -
(prof->sta_info_len - 1),
false, NULL);
IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_BEACON,
NULL);
/* memory allocation failed - let's hope that's transient */
if (!prof_elems)
@ -7371,6 +7360,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link,
.mode = link->u.mgd.conn.mode,
.link_id = -1,
.from_ap = true,
.type = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_TYPE,
};
lockdep_assert_wiphy(local->hw.wiphy);
@ -7973,7 +7963,10 @@ void ieee80211_process_neg_ttlm_req(struct ieee80211_sub_if_data *sdata,
ies_len = len - offsetof(struct ieee80211_mgmt,
u.action.u.ttlm_req.variable);
elems = ieee802_11_parse_elems(mgmt->u.action.u.ttlm_req.variable,
ies_len, true, NULL);
ies_len,
IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION,
NULL);
if (!elems) {
ttlm_res = NEG_TTLM_RES_REJECT;
goto out;
@ -8179,9 +8172,11 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
break;
/* CSA IE cannot be overridden, no need for BSSID */
elems = ieee802_11_parse_elems(
mgmt->u.action.u.chan_switch.variable,
ies_len, true, NULL);
elems = ieee802_11_parse_elems(mgmt->u.action.u.chan_switch.variable,
ies_len,
IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION,
NULL);
if (elems && !elems->parse_error) {
enum ieee80211_csa_source src =
@ -8208,9 +8203,11 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
* extended CSA IE can't be overridden, no need for
* BSSID
*/
elems = ieee802_11_parse_elems(
mgmt->u.action.u.ext_chan_switch.variable,
ies_len, true, NULL);
elems = ieee802_11_parse_elems(mgmt->u.action.u.ext_chan_switch.variable,
ies_len,
IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION,
NULL);
if (elems && !elems->parse_error) {
enum ieee80211_csa_source src;
@ -10988,7 +10985,10 @@ static void ieee80211_ml_epcs(struct ieee80211_sub_if_data *sdata,
pos = scratch + sizeof(control);
len -= sizeof(control);
link_elems = ieee802_11_parse_elems(pos, len, false, NULL);
link_elems = ieee802_11_parse_elems(pos, len,
IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION,
NULL);
if (!link_elems)
continue;
@ -11039,7 +11039,10 @@ void ieee80211_process_epcs_ena_resp(struct ieee80211_sub_if_data *sdata,
u.action.u.epcs.variable) -
IEEE80211_EPCS_ENA_RESP_BODY_LEN;
elems = ieee802_11_parse_elems(pos, ies_len, true, NULL);
elems = ieee802_11_parse_elems(pos, ies_len,
IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION,
NULL);
if (!elems)
return;

View File

@ -6,7 +6,7 @@
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright (C) 2015-2017 Intel Deutschland GmbH
* Copyright (C) 2018-2024 Intel Corporation
* Copyright (C) 2018-2025 Intel Corporation
*
* element parsing for mac80211
*/
@ -286,6 +286,24 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
bitmap_zero(seen_elems, 256);
switch (params->type) {
/* we don't need to parse assoc request, luckily (it's value 0) */
case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ASSOC_REQ:
case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_REASSOC_REQ:
default:
WARN(1, "invalid frame type 0x%x for element parsing\n",
params->type);
break;
case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ASSOC_RESP:
case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_REASSOC_RESP:
case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ:
case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP:
case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON:
case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION:
case IEEE80211_FTYPE_EXT | IEEE80211_STYPE_S1G_BEACON:
break;
}
for_each_element(elem, params->start, params->len) {
const struct element *subelem;
u8 elem_parse_failed;
@ -566,7 +584,8 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
if (params->mode < IEEE80211_CONN_MODE_VHT)
break;
if (!params->action) {
if (params->type != (IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION)) {
elem_parse_failed =
IEEE80211_PARSE_ERR_UNEXPECTED_ELEM;
break;
@ -582,7 +601,8 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
case WLAN_EID_CHANNEL_SWITCH_WRAPPER:
if (params->mode < IEEE80211_CONN_MODE_VHT)
break;
if (params->action) {
if (params->type == (IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION)) {
elem_parse_failed =
IEEE80211_PARSE_ERR_UNEXPECTED_ELEM;
break;
@ -942,7 +962,7 @@ ieee80211_prep_mle_link_parse(struct ieee80211_elems_parse *elems_parse,
sub->len = end - sub->start;
sub->mode = params->mode;
sub->action = params->action;
sub->type = params->type;
sub->from_ap = params->from_ap;
sub->link_id = -1;
@ -1041,7 +1061,7 @@ ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params)
sub.start = elems_parse->scratch_pos;
sub.mode = params->mode;
sub.len = nontx_len;
sub.action = params->action;
sub.type = params->type;
sub.link_id = params->link_id;
/* consume the space used for non-transmitted profile */

View File

@ -76,7 +76,11 @@ void ieee80211_inform_bss(struct wiphy *wiphy,
if (!update_data)
return;
elems = ieee802_11_parse_elems(ies->data, ies->len, false, NULL);
elems = ieee802_11_parse_elems(ies->data, ies->len,
update_data->beacon ?
IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON :
IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP,
NULL);
if (!elems)
return;

View File

@ -6,7 +6,7 @@
* Copyright 2014, Intel Corporation
* Copyright 2014 Intel Mobile Communications GmbH
* Copyright 2015 - 2016 Intel Deutschland GmbH
* Copyright (C) 2019, 2021-2024 Intel Corporation
* Copyright (C) 2019, 2021-2025 Intel Corporation
*/
#include <linux/ieee80211.h>
@ -1783,7 +1783,10 @@ ieee80211_process_tdls_channel_switch_resp(struct ieee80211_sub_if_data *sdata,
}
elems = ieee802_11_parse_elems(tf->u.chan_switch_resp.variable,
skb->len - baselen, false, NULL);
skb->len - baselen,
IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION,
NULL);
if (!elems) {
ret = -ENOMEM;
goto out;
@ -1902,7 +1905,10 @@ ieee80211_process_tdls_channel_switch_req(struct ieee80211_sub_if_data *sdata,
}
elems = ieee802_11_parse_elems(tf->u.chan_switch_req.variable,
skb->len - baselen, false, NULL);
skb->len - baselen,
IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION,
NULL);
if (!elems)
return -ENOMEM;

View File

@ -2,7 +2,7 @@
/*
* KUnit tests for element parsing
*
* Copyright (C) 2023-2024 Intel Corporation
* Copyright (C) 2023-2025 Intel Corporation
*/
#include <kunit/test.h>
#include "../ieee80211_i.h"
@ -15,6 +15,8 @@ static void mle_defrag(struct kunit *test)
.link_id = 12,
.from_ap = true,
.mode = IEEE80211_CONN_MODE_EHT,
/* type is not really relevant here */
.type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON,
};
struct ieee802_11_elems *parsed;
struct sk_buff *skb;

View File

@ -2206,9 +2206,10 @@ int ieee80211_reconfig(struct ieee80211_local *local)
}
}
/* Passing NULL means an interface is picked for configuration */
if (local->virt_monitors > 0 &&
local->virt_monitors == local->open_count)
ieee80211_add_virtual_monitor(local);
ieee80211_add_virtual_monitor(local, NULL);
if (!suspended)
return 0;
@ -2347,7 +2348,7 @@ void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata,
chanctx = container_of(chanctx_conf, struct ieee80211_chanctx,
conf);
ieee80211_recalc_chanctx_min_def(local, chanctx, NULL, false);
ieee80211_recalc_chanctx_min_def(local, chanctx);
}
}
@ -4016,23 +4017,23 @@ static u8 ieee80211_chanctx_radar_detect(struct ieee80211_local *local,
if (WARN_ON(ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED))
return 0;
list_for_each_entry(link, &ctx->reserved_links, reserved_chanctx_list)
if (link->reserved_radar_required)
for_each_sdata_link(local, link) {
if (rcu_access_pointer(link->conf->chanctx_conf) == &ctx->conf) {
/*
* An in-place reservation context should not have any
* assigned links until it replaces the other context.
*/
WARN_ON(ctx->replace_state ==
IEEE80211_CHANCTX_REPLACES_OTHER);
if (link->radar_required)
radar_detect |=
BIT(link->conf->chanreq.oper.width);
}
if (link->reserved_chanctx == ctx &&
link->reserved_radar_required)
radar_detect |= BIT(link->reserved.oper.width);
/*
* An in-place reservation context should not have any assigned vifs
* until it replaces the other context.
*/
WARN_ON(ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER &&
!list_empty(&ctx->assigned_links));
list_for_each_entry(link, &ctx->assigned_links, assigned_chanctx_list) {
if (!link->radar_required)
continue;
radar_detect |=
BIT(link->conf->chanreq.oper.width);
}
return radar_detect;

View File

@ -1066,12 +1066,12 @@ int wiphy_register(struct wiphy *wiphy)
wiphy_regulatory_register(wiphy);
if (wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) {
struct regulatory_request request;
request.wiphy_idx = get_wiphy_idx(wiphy);
request.initiator = NL80211_REGDOM_SET_BY_DRIVER;
request.alpha2[0] = '9';
request.alpha2[1] = '9';
struct regulatory_request request = {
.wiphy_idx = get_wiphy_idx(wiphy),
.initiator = NL80211_REGDOM_SET_BY_DRIVER,
.alpha2[0] = '9',
.alpha2[1] = '9',
};
nl80211_send_reg_change_event(&request);
}

View File

@ -550,7 +550,8 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev,
bool signal_valid, unsigned long ts);
enum ieee80211_ap_reg_power
cfg80211_get_6ghz_power_type(const u8 *elems, size_t elems_len);
cfg80211_get_6ghz_power_type(const u8 *elems, size_t elems_len,
u32 client_flags);
#ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS
#define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond)

View File

@ -6748,7 +6748,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
beacon_check.relax = true;
beacon_check.reg_power =
cfg80211_get_6ghz_power_type(params->beacon.tail,
params->beacon.tail_len);
params->beacon.tail_len, 0);
if (!cfg80211_reg_check_beaconing(&rdev->wiphy, &params->chandef,
&beacon_check)) {
err = -EINVAL;
@ -6927,7 +6927,7 @@ static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info)
beacon_check.relax = true;
beacon_check.reg_power =
cfg80211_get_6ghz_power_type(params->beacon.tail,
params->beacon.tail_len);
params->beacon.tail_len, 0);
if (!cfg80211_reg_check_beaconing(&rdev->wiphy,
&wdev->links[link_id].ap.chandef,
&beacon_check)) {

View File

@ -2212,7 +2212,8 @@ struct cfg80211_inform_single_bss_data {
};
enum ieee80211_ap_reg_power
cfg80211_get_6ghz_power_type(const u8 *elems, size_t elems_len)
cfg80211_get_6ghz_power_type(const u8 *elems, size_t elems_len,
u32 client_flags)
{
const struct ieee80211_he_6ghz_oper *he_6ghz_oper;
struct ieee80211_he_operation *he_oper;
@ -2230,26 +2231,13 @@ cfg80211_get_6ghz_power_type(const u8 *elems, size_t elems_len)
if (!he_6ghz_oper)
return IEEE80211_REG_UNSET_AP;
switch (u8_get_bits(he_6ghz_oper->control,
IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO)) {
case IEEE80211_6GHZ_CTRL_REG_LPI_AP:
case IEEE80211_6GHZ_CTRL_REG_INDOOR_LPI_AP:
return IEEE80211_REG_LPI_AP;
case IEEE80211_6GHZ_CTRL_REG_SP_AP:
case IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP:
case IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP_OLD:
return IEEE80211_REG_SP_AP;
case IEEE80211_6GHZ_CTRL_REG_VLP_AP:
return IEEE80211_REG_VLP_AP;
default:
return IEEE80211_REG_UNSET_AP;
}
return cfg80211_6ghz_power_type(he_6ghz_oper->control, client_flags);
}
static bool cfg80211_6ghz_power_type_valid(const u8 *elems, size_t elems_len,
const u32 flags)
{
switch (cfg80211_get_6ghz_power_type(elems, elems_len)) {
switch (cfg80211_get_6ghz_power_type(elems, elems_len, flags)) {
case IEEE80211_REG_LPI_AP:
return true;
case IEEE80211_REG_SP_AP: