wifi: ieee80211: correctly mark FTM frames non-bufferable
[carl9170fw.git] / include / linux / ieee80211.h
index 3ec463ba9eda4226127a7ce943d7f9017ee0d78d..1ec899d08031878f9c8388ed53ddb5ee35005d5a 100644 (file)
@@ -9,7 +9,7 @@
  * 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 - 2022 Intel Corporation
+ * Copyright (c) 2018 - 2023 Intel Corporation
  */
 
 #ifndef __LINUX_IEEE80211_H
@@ -306,21 +306,34 @@ struct ieee80211_hdr {
 } __packed __aligned(2);
 
 struct ieee80211_hdr_3addr {
+       __le16 frame_control;
+       __le16 duration_id;
+       struct_group(addrs,
+               u8 addr1[6];
+               u8 addr2[6];
+               u8 addr3[6];
+       );
+       __le16 seq_ctrl;
+} __packed __aligned(2);
+
+struct ieee80211_qos_hdr {
        __le16 frame_control;
        __le16 duration_id;
        u8 addr1[6];
        u8 addr2[6];
        u8 addr3[6];
        __le16 seq_ctrl;
+       __le16 qos_ctrl;
 } __packed __aligned(2);
 
-struct ieee80211_qos_hdr {
+struct ieee80211_qos_hdr_4addr {
        __le16 frame_control;
        __le16 duration_id;
        u8 addr1[6];
        u8 addr2[6];
        u8 addr3[6];
        __le16 seq_ctrl;
+       u8 addr4[6];
        __le16 qos_ctrl;
 } __packed __aligned(2);
 
@@ -773,20 +786,6 @@ static inline bool ieee80211_is_any_nullfunc(__le16 fc)
        return (ieee80211_is_nullfunc(fc) || ieee80211_is_qos_nullfunc(fc));
 }
 
-/**
- * ieee80211_is_bufferable_mmpdu - check if frame is bufferable MMPDU
- * @fc: frame control field in little-endian byteorder
- */
-static inline bool ieee80211_is_bufferable_mmpdu(__le16 fc)
-{
-       /* IEEE 802.11-2012, definition of "bufferable management frame";
-        * note that this ignores the IBSS special case. */
-       return ieee80211_is_mgmt(fc) &&
-              (ieee80211_is_action(fc) ||
-               ieee80211_is_disassoc(fc) ||
-               ieee80211_is_deauth(fc));
-}
-
 /**
  * ieee80211_is_first_frag - check if IEEE80211_SCTL_FRAG is not set
  * @seq_ctrl: frame sequence control bytes in little-endian byteorder
@@ -1333,8 +1332,18 @@ struct ieee80211_mgmt {
                                        u8 action_code;
                                        u8 variable[];
                                } __packed s1g;
+                               struct {
+                                       u8 action_code;
+                                       u8 dialog_token;
+                                       u8 follow_up;
+                                       u32 tod;
+                                       u32 toa;
+                                       u8 max_tod_error;
+                                       u8 max_toa_error;
+                               } __packed wnm_timing_msr;
                        } u;
                } __packed __aligned(4) action;
+               DECLARE_FLEX_ARRAY(u8, body); /* Generic frame body */
        } u __aligned(2);
 } __packed __aligned(2);
 
@@ -2038,7 +2047,7 @@ struct ieee80211_eht_mcs_nss_supp_bw {
  * struct ieee80211_eht_cap_elem_fixed - EHT capabilities fixed data
  *
  * This structure is the "EHT Capabilities element" fixed fields as
- * described in P802.11be_D1.4 section 9.4.2.313.
+ * described in P802.11be_D2.0 section 9.4.2.313.
  *
  * @mac_cap_info: MAC capabilities, see IEEE80211_EHT_MAC_CAP*
  * @phy_cap_info: PHY capabilities, see IEEE80211_EHT_PHY_CAP*
@@ -2064,25 +2073,45 @@ struct ieee80211_eht_cap_elem {
        u8 optional[];
 } __packed;
 
+#define IEEE80211_EHT_OPER_INFO_PRESENT                                0x01
+#define IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT  0x02
+#define IEEE80211_EHT_OPER_EHT_DEF_PE_DURATION                 0x04
+#define IEEE80211_EHT_OPER_GROUP_ADDRESSED_BU_IND_LIMIT         0x08
+#define IEEE80211_EHT_OPER_GROUP_ADDRESSED_BU_IND_EXP_MASK      0x30
+
 /**
  * struct ieee80211_eht_operation - eht operation element
  *
  * This structure is the "EHT Operation Element" fields as
- * described in P802.11be_D1.4 section 9.4.2.311
+ * described in P802.11be_D2.0 section 9.4.2.311
  *
- * FIXME: The spec is unclear how big the fields are, and doesn't
- *       indicate the "Disabled Subchannel Bitmap Present" in the
- *       structure (Figure 9-1002a) at all ...
+ * @params: EHT operation element parameters. See &IEEE80211_EHT_OPER_*
+ * @basic_mcs_nss: indicates the EHT-MCSs for each number of spatial streams in
+ *     EHT PPDUs that are supported by all EHT STAs in the BSS in transmit and
+ *     receive.
+ * @optional: optional parts
  */
 struct ieee80211_eht_operation {
-       u8 chan_width;
-       u8 ccfs;
-       u8 present_bm;
-
-       u8 disable_subchannel_bitmap[];
+       u8 params;
+       __le32 basic_mcs_nss;
+       u8 optional[];
 } __packed;
 
-#define IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT  0x1
+/**
+ * struct ieee80211_eht_operation_info - eht operation information
+ *
+ * @control: EHT operation information control.
+ * @ccfs0: defines a channel center frequency for a 20, 40, 80, 160, or 320 MHz
+ *     EHT BSS.
+ * @ccfs1: defines a channel center frequency for a 160 or 320 MHz EHT BSS.
+ * @optional: optional parts
+ */
+struct ieee80211_eht_operation_info {
+       u8 control;
+       u8 ccfs0;
+       u8 ccfs1;
+       u8 optional[];
+} __packed;
 
 /* 802.11ac VHT Capabilities */
 #define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895                 0x00000000
@@ -2784,19 +2813,21 @@ ieee80211_he_spr_size(const u8 *he_spr_ie)
 #define S1G_OPER_CH_WIDTH_PRIMARY_1MHZ BIT(0)
 #define S1G_OPER_CH_WIDTH_OPER         GENMASK(4, 1)
 
-/* EHT MAC capabilities as defined in P802.11be_D1.4 section 9.4.2.313.2 */
-#define IEEE80211_EHT_MAC_CAP0_NSEP_PRIO_ACCESS                        0x01
+/* EHT MAC capabilities as defined in P802.11be_D2.0 section 9.4.2.313.2 */
+#define IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS                        0x01
 #define IEEE80211_EHT_MAC_CAP0_OM_CONTROL                      0x02
 #define IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1         0x04
 #define IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE2         0x08
 #define IEEE80211_EHT_MAC_CAP0_RESTRICTED_TWT                  0x10
 #define IEEE80211_EHT_MAC_CAP0_SCS_TRAFFIC_DESC                        0x20
-#define IEEE80211_EHT_MAC_CAP0_MAX_AMPDU_LEN_MASK              0xc0
-#define                IEEE80211_EHT_MAC_CAP0_MAX_AMPDU_LEN_3895       0
-#define                IEEE80211_EHT_MAC_CAP0_MAX_AMPDU_LEN_7991       1
-#define                IEEE80211_EHT_MAC_CAP0_MAX_AMPDU_LEN_11454      2
+#define IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_MASK               0xc0
+#define        IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_3895                0
+#define        IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_7991                1
+#define        IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_11454               2
+
+#define IEEE80211_EHT_MAC_CAP1_MAX_AMPDU_LEN_MASK              0x01
 
-/* EHT PHY capabilities as defined in P802.11be_D1.4 section 9.4.2.313.3 */
+/* EHT PHY capabilities as defined in P802.11be_D2.0 section 9.4.2.313.3 */
 #define IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ                  0x02
 #define IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ             0x04
 #define IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI             0x08
@@ -2861,7 +2892,7 @@ ieee80211_he_spr_size(const u8 *he_spr_ie)
 #define IEEE80211_EHT_PHY_CAP8_RX_4096QAM_WIDER_BW_DL_OFDMA    0x02
 
 /*
- * EHT operation channel width as defined in P802.11be_D1.4 section 9.4.2.311
+ * EHT operation channel width as defined in P802.11be_D2.0 section 9.4.2.311
  */
 #define IEEE80211_EHT_OPER_CHAN_WIDTH          0x7
 #define IEEE80211_EHT_OPER_CHAN_WIDTH_20MHZ    0
@@ -2873,7 +2904,8 @@ ieee80211_he_spr_size(const u8 *he_spr_ie)
 /* Calculate 802.11be EHT capabilities IE Tx/Rx EHT MCS NSS Support Field size */
 static inline u8
 ieee80211_eht_mcs_nss_size(const struct ieee80211_he_cap_elem *he_cap,
-                          const struct ieee80211_eht_cap_elem_fixed *eht_cap)
+                          const struct ieee80211_eht_cap_elem_fixed *eht_cap,
+                          bool from_ap)
 {
        u8 count = 0;
 
@@ -2894,7 +2926,10 @@ ieee80211_eht_mcs_nss_size(const struct ieee80211_he_cap_elem *he_cap,
        if (eht_cap->phy_cap_info[0] & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ)
                count += 3;
 
-       return count ? count : 4;
+       if (count)
+               return count;
+
+       return from_ap ? 3 : 4;
 }
 
 /* 802.11be EHT PPE Thresholds */
@@ -2930,7 +2965,8 @@ ieee80211_eht_ppe_size(u16 ppe_thres_hdr, const u8 *phy_cap_info)
 }
 
 static inline bool
-ieee80211_eht_capa_size_ok(const u8 *he_capa, const u8 *data, u8 len)
+ieee80211_eht_capa_size_ok(const u8 *he_capa, const u8 *data, u8 len,
+                          bool from_ap)
 {
        const struct ieee80211_eht_cap_elem_fixed *elem = (const void *)data;
        u8 needed = sizeof(struct ieee80211_eht_cap_elem_fixed);
@@ -2939,7 +2975,8 @@ ieee80211_eht_capa_size_ok(const u8 *he_capa, const u8 *data, u8 len)
                return false;
 
        needed += ieee80211_eht_mcs_nss_size((const void *)he_capa,
-                                            (const void *)data);
+                                            (const void *)data,
+                                            from_ap);
        if (len < needed)
                return false;
 
@@ -2967,8 +3004,13 @@ ieee80211_eht_oper_size_ok(const u8 *data, u8 len)
        if (len < needed)
                return false;
 
-       if (elem->present_bm & IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT)
-               needed += 2;
+       if (elem->params & IEEE80211_EHT_OPER_INFO_PRESENT) {
+               needed += 3;
+
+               if (elem->params &
+                   IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT)
+                       needed += 2;
+       }
 
        return len >= needed;
 }
@@ -3513,6 +3555,12 @@ enum ieee80211_mesh_actioncode {
        WLAN_MESH_ACTION_TBTT_ADJUSTMENT_RESPONSE,
 };
 
+/* Unprotected WNM action codes */
+enum ieee80211_unprotected_wnm_actioncode {
+       WLAN_UNPROTECTED_WNM_ACTION_TIM = 0,
+       WLAN_UNPROTECTED_WNM_ACTION_TIMING_MEASUREMENT_RESPONSE = 1,
+};
+
 /* Security key length */
 enum ieee80211_key_len {
        WLAN_KEY_LEN_WEP40 = 5,
@@ -3604,7 +3652,7 @@ enum ieee80211_pub_actioncode {
        WLAN_PUB_ACTION_NETWORK_CHANNEL_CONTROL = 30,
        WLAN_PUB_ACTION_WHITE_SPACE_MAP_ANN = 31,
        WLAN_PUB_ACTION_FTM_REQUEST = 32,
-       WLAN_PUB_ACTION_FTM = 33,
+       WLAN_PUB_ACTION_FTM_RESPONSE = 33,
        WLAN_PUB_ACTION_FILS_DISCOVERY = 34,
 };
 
@@ -4023,16 +4071,21 @@ struct ieee80211_he_6ghz_capa {
  * @hdr: the frame
  *
  * The qos ctrl bytes come after the frame_control, duration, seq_num
- * and 3 or 4 addresses of length ETH_ALEN.
- * 3 addr: 2 + 2 + 2 + 3*6 = 24
- * 4 addr: 2 + 2 + 2 + 4*6 = 30
+ * and 3 or 4 addresses of length ETH_ALEN. Checks frame_control to choose
+ * between struct ieee80211_qos_hdr_4addr and struct ieee80211_qos_hdr.
  */
 static inline u8 *ieee80211_get_qos_ctl(struct ieee80211_hdr *hdr)
 {
-       if (ieee80211_has_a4(hdr->frame_control))
-               return (u8 *)hdr + 30;
+       union {
+               struct ieee80211_qos_hdr        addr3;
+               struct ieee80211_qos_hdr_4addr  addr4;
+       } *qos;
+
+       qos = (void *)hdr;
+       if (ieee80211_has_a4(qos->addr3.frame_control))
+               return (u8 *)&qos->addr4.qos_ctrl;
        else
-               return (u8 *)hdr + 24;
+               return (u8 *)&qos->addr3.qos_ctrl;
 }
 
 /**
@@ -4065,6 +4118,44 @@ static inline u8 *ieee80211_get_SA(struct ieee80211_hdr *hdr)
        return hdr->addr2;
 }
 
+/**
+ * ieee80211_is_bufferable_mmpdu - check if frame is bufferable MMPDU
+ * @skb: the skb to check, starting with the 802.11 header
+ */
+static inline bool ieee80211_is_bufferable_mmpdu(struct ieee80211_hdr *hdr, size_t len)
+{
+       struct ieee80211_mgmt *mgmt = (void *)hdr;
+       __le16 fc = mgmt->frame_control;
+
+       /*
+        * IEEE 802.11 REVme D2.0 definition of bufferable MMPDU;
+        * note that this ignores the IBSS special case.
+        */
+       if (!ieee80211_is_mgmt(fc))
+               return false;
+
+       if (ieee80211_is_disassoc(fc) || ieee80211_is_deauth(fc))
+               return true;
+
+       if (!ieee80211_is_action(fc))
+               return false;
+
+       if (len < offsetofend(typeof(*mgmt), u.action.u.ftm.action_code))
+               return true;
+
+       /* action frame - additionally check for non-bufferable FTM */
+
+       if (mgmt->u.action.category != WLAN_CATEGORY_PUBLIC &&
+           mgmt->u.action.category != WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION)
+               return true;
+
+       if (mgmt->u.action.u.ftm.action_code == WLAN_PUB_ACTION_FTM_REQUEST ||
+           mgmt->u.action.u.ftm.action_code == WLAN_PUB_ACTION_FTM_RESPONSE)
+               return false;
+
+       return true;
+}
+
 /**
  * ieee80211_get_DA - get pointer to DA
  * @hdr: the frame
@@ -4112,6 +4203,7 @@ static inline bool ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr)
                        *category != WLAN_CATEGORY_SELF_PROTECTED &&
                        *category != WLAN_CATEGORY_UNPROT_DMG &&
                        *category != WLAN_CATEGORY_VHT &&
+                       *category != WLAN_CATEGORY_S1G &&
                        *category != WLAN_CATEGORY_VENDOR_SPECIFIC;
        }
 
@@ -4200,6 +4292,40 @@ static inline bool ieee80211_check_tim(const struct ieee80211_tim_ie *tim,
 #define TU_TO_JIFFIES(x)       (usecs_to_jiffies((x) * 1024))
 #define TU_TO_EXP_TIME(x)      (jiffies + TU_TO_JIFFIES(x))
 
+static inline bool ieee80211_is_timing_measurement(struct ieee80211_hdr *hdr, size_t len)
+{
+       struct ieee80211_mgmt *mgmt = (void *)hdr;
+
+       if (len < IEEE80211_MIN_ACTION_SIZE)
+               return false;
+
+       if (!ieee80211_is_action(hdr->frame_control))
+               return false;
+
+       if (mgmt->u.action.category == WLAN_CATEGORY_WNM_UNPROTECTED &&
+           mgmt->u.action.u.wnm_timing_msr.action_code ==
+               WLAN_UNPROTECTED_WNM_ACTION_TIMING_MEASUREMENT_RESPONSE &&
+           len >= offsetofend(typeof(*mgmt), u.action.u.wnm_timing_msr))
+               return true;
+
+       return false;
+}
+
+static inline bool ieee80211_is_ftm(struct ieee80211_hdr *hdr, size_t len)
+{
+       struct ieee80211_mgmt *mgmt = (void *)hdr;
+
+       if (!ieee80211_is_public_action((void *)mgmt, len))
+               return false;
+
+       if (mgmt->u.action.u.ftm.action_code ==
+               WLAN_PUB_ACTION_FTM_RESPONSE &&
+           len >= offsetofend(typeof(*mgmt), u.action.u.ftm))
+               return true;
+
+       return false;
+}
+
 struct element {
        u8 id;
        u8 datalen;
@@ -4412,18 +4538,17 @@ static inline u8 ieee80211_mle_common_size(const u8 *data)
 
        switch (u16_get_bits(control, IEEE80211_ML_CONTROL_TYPE)) {
        case IEEE80211_ML_CONTROL_TYPE_BASIC:
-               common += sizeof(struct ieee80211_mle_basic_common_info);
-               break;
        case IEEE80211_ML_CONTROL_TYPE_PREQ:
-               common += sizeof(struct ieee80211_mle_preq_common_info);
+       case IEEE80211_ML_CONTROL_TYPE_TDLS:
+               /*
+                * The length is the first octet pointed by mle->variable so no
+                * need to add anything
+                */
                break;
        case IEEE80211_ML_CONTROL_TYPE_RECONF:
                if (control & IEEE80211_MLC_RECONF_PRES_MLD_MAC_ADDR)
                        common += 6;
                return common;
-       case IEEE80211_ML_CONTROL_TYPE_TDLS:
-               common += sizeof(struct ieee80211_mle_tdls_common_info);
-               break;
        case IEEE80211_ML_CONTROL_TYPE_PRIO_ACCESS:
                if (control & IEEE80211_MLC_PRIO_ACCESS_PRES_AP_MLD_MAC_ADDR)
                        common += 6;
@@ -4432,7 +4557,7 @@ static inline u8 ieee80211_mle_common_size(const u8 *data)
                return 0;
        }
 
-       return common + mle->variable[0];
+       return sizeof(*mle) + common + mle->variable[0];
 }
 
 /**
@@ -4440,7 +4565,7 @@ static inline u8 ieee80211_mle_common_size(const u8 *data)
  * @data: pointer to the element data
  * @len: length of the containing element
  */
-static inline bool ieee80211_mle_size_ok(const u8 *data, u8 len)
+static inline bool ieee80211_mle_size_ok(const u8 *data, size_t len)
 {
        const struct ieee80211_multi_link_elem *mle = (const void *)data;
        u8 fixed = sizeof(*mle);
@@ -4505,6 +4630,7 @@ static inline bool ieee80211_mle_size_ok(const u8 *data, u8 len)
 
 enum ieee80211_mle_subelems {
        IEEE80211_MLE_SUBELEM_PER_STA_PROFILE           = 0,
+       IEEE80211_MLE_SUBELEM_FRAGMENT                  = 254,
 };
 
 #define IEEE80211_MLE_STA_CONTROL_LINK_ID                      0x000f
@@ -4523,6 +4649,46 @@ struct ieee80211_mle_per_sta_profile {
        u8 variable[];
 } __packed;
 
+/**
+ * ieee80211_mle_sta_prof_size_ok - validate multi-link element sta profile size
+ * @data: pointer to the sub element data
+ * @len: length of the containing sub element
+ */
+static inline bool ieee80211_mle_sta_prof_size_ok(const u8 *data, size_t len)
+{
+       const struct ieee80211_mle_per_sta_profile *prof = (const void *)data;
+       u16 control;
+       u8 fixed = sizeof(*prof);
+       u8 info_len = 1;
+
+       if (len < fixed)
+               return false;
+
+       control = le16_to_cpu(prof->control);
+
+       if (control & IEEE80211_MLE_STA_CONTROL_STA_MAC_ADDR_PRESENT)
+               info_len += 6;
+       if (control & IEEE80211_MLE_STA_CONTROL_BEACON_INT_PRESENT)
+               info_len += 2;
+       if (control & IEEE80211_MLE_STA_CONTROL_TSF_OFFS_PRESENT)
+               info_len += 8;
+       if (control & IEEE80211_MLE_STA_CONTROL_DTIM_INFO_PRESENT)
+               info_len += 2;
+       if (control & IEEE80211_MLE_STA_CONTROL_BSS_PARAM_CHANGE_CNT_PRESENT)
+               info_len += 1;
+
+       if (control & IEEE80211_MLE_STA_CONTROL_COMPLETE_PROFILE &&
+           control & IEEE80211_MLE_STA_CONTROL_NSTR_BITMAP_SIZE) {
+               if (control & IEEE80211_MLE_STA_CONTROL_NSTR_BITMAP_SIZE)
+                       info_len += 2;
+               else
+                       info_len += 1;
+       }
+
+       return prof->sta_info_len >= info_len &&
+              fixed + prof->sta_info_len <= len;
+}
+
 #define for_each_mle_subelement(_elem, _data, _len)                    \
        if (ieee80211_mle_size_ok(_data, _len))                         \
                for_each_element(_elem,                                 \