wifi: ieee80211: correctly mark FTM frames non-bufferable
[carl9170fw.git] / include / linux / ieee80211.h
index 23a8a1e93aecb24a67b051eae2040a18aa7d82b0..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
@@ -326,6 +326,17 @@ struct ieee80211_qos_hdr {
        __le16 qos_ctrl;
 } __packed __aligned(2);
 
+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);
+
 struct ieee80211_trigger {
        __le16 frame_control;
        __le16 duration;
@@ -775,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
@@ -1346,6 +1343,7 @@ struct ieee80211_mgmt {
                                } __packed wnm_timing_msr;
                        } u;
                } __packed __aligned(4) action;
+               DECLARE_FLEX_ARRAY(u8, body); /* Generic frame body */
        } u __aligned(2);
 } __packed __aligned(2);
 
@@ -3563,11 +3561,6 @@ enum ieee80211_unprotected_wnm_actioncode {
        WLAN_UNPROTECTED_WNM_ACTION_TIMING_MEASUREMENT_RESPONSE = 1,
 };
 
-/* Public action codes */
-enum ieee80211_public_actioncode {
-       WLAN_PUBLIC_ACTION_FTM_RESPONSE = 33,
-};
-
 /* Security key length */
 enum ieee80211_key_len {
        WLAN_KEY_LEN_WEP40 = 5,
@@ -3659,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,
 };
 
@@ -4078,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;
 }
 
 /**
@@ -4120,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
@@ -4283,7 +4319,7 @@ static inline bool ieee80211_is_ftm(struct ieee80211_hdr *hdr, size_t len)
                return false;
 
        if (mgmt->u.action.u.ftm.action_code ==
-               WLAN_PUBLIC_ACTION_FTM_RESPONSE &&
+               WLAN_PUB_ACTION_FTM_RESPONSE &&
            len >= offsetofend(typeof(*mgmt), u.action.u.ftm))
                return true;