root/include/linux/ieee80211-he.h
/* 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_AP_ROLE_NOT_RELEVANT    7
#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 */