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:
commit
e949824730
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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, ¶ms)))
|
||||
!(ath12k_mac_get_fw_stats(ar, ¶ms))) {
|
||||
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, ¶ms)))
|
||||
!(ath12k_mac_get_fw_stats(ar, ¶ms))) {
|
||||
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, ¶ms)))
|
||||
!(ath12k_mac_get_fw_stats(ar, ¶ms))) {
|
||||
signal = arsta->rssi_beacon;
|
||||
ath12k_fw_stats_reset(ar);
|
||||
}
|
||||
|
||||
if (signal) {
|
||||
link_sinfo->signal =
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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 */
|
||||
|
||||
1182
include/linux/ieee80211-eht.h
Normal file
1182
include/linux/ieee80211-eht.h
Normal file
File diff suppressed because it is too large
Load Diff
824
include/linux/ieee80211-he.h
Normal file
824
include/linux/ieee80211-he.h
Normal 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 */
|
||||
292
include/linux/ieee80211-ht.h
Normal file
292
include/linux/ieee80211-ht.h
Normal 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 */
|
||||
230
include/linux/ieee80211-mesh.h
Normal file
230
include/linux/ieee80211-mesh.h
Normal 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 */
|
||||
35
include/linux/ieee80211-nan.h
Normal file
35
include/linux/ieee80211-nan.h
Normal 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 */
|
||||
71
include/linux/ieee80211-p2p.h
Normal file
71
include/linux/ieee80211-p2p.h
Normal 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 */
|
||||
575
include/linux/ieee80211-s1g.h
Normal file
575
include/linux/ieee80211-s1g.h
Normal 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 */
|
||||
236
include/linux/ieee80211-vht.h
Normal file
236
include/linux/ieee80211-vht.h
Normal 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
@ -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.
|
||||
|
||||
@ -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
|
||||
*
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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)) {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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))
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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(¶ms);
|
||||
}
|
||||
|
||||
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,
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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))
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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, ¶ms->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)) {
|
||||
|
||||
@ -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:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user