]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: ieee80211: split S1G definitions out
authorJohannes Berg <johannes.berg@intel.com>
Wed, 5 Nov 2025 14:36:54 +0000 (15:36 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 10 Nov 2025 09:38:15 +0000 (10:38 +0100)
The ieee80211.h file has gotten very long, continue splitting
it by putting S1G definitions into a separate file.

Link: https://patch.msgid.link/20251105153843.82c0bddee6e3.Ic6646615286dad240b42e31e9d428c7e4ea40ce0@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
include/linux/ieee80211-s1g.h [new file with mode: 0644]
include/linux/ieee80211.h

diff --git a/include/linux/ieee80211-s1g.h b/include/linux/ieee80211-s1g.h
new file mode 100644 (file)
index 0000000..5b9ed2d
--- /dev/null
@@ -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 */
index 63a9775b059d8c9933013c9b83914f4d344c04ee..1b27bbac145babf3deb578708f46d940fd3a5466 100644 (file)
 #define IEEE80211_STYPE_DMG_BEACON             0x0000
 #define IEEE80211_STYPE_S1G_BEACON             0x0010
 
-/* bits unique to S1G beacon */
-#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
-
 #define IEEE80211_NDP_FTYPE_CTS                        0
 #define IEEE80211_NDP_FTYPE_CF_END             0
 #define IEEE80211_NDP_FTYPE_PS_POLL            1
@@ -221,11 +210,6 @@ static inline u16 ieee80211_sn_sub(u16 sn1, u16 sn2)
 #define IEEE80211_MAX_TIM_LEN          251
 #define IEEE80211_MAX_MESH_PEERINGS    63
 
-/* 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
-
 /* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
    6.2.1.1.2.
 
@@ -604,55 +588,6 @@ static inline bool ieee80211_is_beacon(__le16 fc)
               cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON);
 }
 
-/**
- * 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));
-}
-
 /**
  * ieee80211_is_atim - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_ATIM
  * @fc: frame control bytes in little-endian byteorder
@@ -984,37 +919,6 @@ struct ieee80211_tim_ie {
        };
 } __packed;
 
-/**
- * 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,
-};
-
 #define WLAN_SA_QUERY_TR_ID_LEN 2
 #define WLAN_MEMBERSHIP_LEN 8
 #define WLAN_USER_POSITION_LEN 16
@@ -1042,61 +946,6 @@ struct ieee80211_addba_ext_ie {
        u8 data;
 } __packed;
 
-/**
- * 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;
-
 struct ieee80211_ext {
        __le16 frame_control;
        __le16 duration;
@@ -1110,37 +959,6 @@ struct ieee80211_ext {
        } u;
 } __packed __aligned(2);
 
-/**
- * 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;
-}
-
 /**
  * struct ieee80211_bss_load_elem - BSS Load elemen
  *
@@ -1567,98 +1385,6 @@ struct ieee80211_p2p_noa_attr {
 #define IEEE80211_P2P_OPPPS_ENABLE_BIT         BIT(7)
 #define IEEE80211_P2P_OPPPS_CTWINDOW_MASK      0x7F
 
-/* 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)
-
 /* Authentication algorithms */
 #define WLAN_AUTH_OPEN 0
 #define WLAN_AUTH_SHARED_KEY 1
@@ -2189,20 +1915,6 @@ enum ieee80211_key_len {
        WLAN_KEY_LEN_BIP_GMAC_256 = 32,
 };
 
-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,
-};
-
 /* Radio measurement action codes as defined in IEEE 802.11-2024 - Table 9-470 */
 enum ieee80211_radio_measurement_actioncode {
        WLAN_RM_ACTION_RADIO_MEASUREMENT_REQUEST = 0,
@@ -2877,254 +2589,6 @@ static inline bool __ieee80211_check_tim(const struct ieee80211_tim_ie *tim,
        return !!(tim->virtual_map[index] & mask);
 }
 
-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;
-       }
-}
-
-/**
- * ieee80211_check_tim - check if AID bit is set in TIM
- * @tim: the TIM IE
- * @tim_len: length of the TIM IE
- * @aid: the AID to look for
- * @s1g: whether the TIM is from an S1G PPDU
- * Return: whether or not traffic is indicated in the TIM for the given AID
- */
-static inline bool ieee80211_check_tim(const struct ieee80211_tim_ie *tim,
-                                      u8 tim_len, u16 aid, bool s1g)
-{
-       return s1g ? ieee80211_s1g_check_tim(tim, tim_len, aid) :
-                    __ieee80211_check_tim(tim, tim_len, aid);
-}
-
 /**
  * ieee80211_get_tdls_action - get TDLS action code
  * @skb: the skb containing the frame, length will not be checked
@@ -3258,39 +2722,6 @@ static inline bool ieee80211_is_ftm(struct sk_buff *skb)
        return false;
 }
 
-/**
- * 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 element {
        u8 id;
        u8 datalen;
@@ -3446,5 +2877,21 @@ struct ieee80211_tbtt_info_ge_11 {
 #include "ieee80211-he.h"
 #include "ieee80211-eht.h"
 #include "ieee80211-mesh.h"
+#include "ieee80211-s1g.h"
+
+/**
+ * ieee80211_check_tim - check if AID bit is set in TIM
+ * @tim: the TIM IE
+ * @tim_len: length of the TIM IE
+ * @aid: the AID to look for
+ * @s1g: whether the TIM is from an S1G PPDU
+ * Return: whether or not traffic is indicated in the TIM for the given AID
+ */
+static inline bool ieee80211_check_tim(const struct ieee80211_tim_ie *tim,
+                                      u8 tim_len, u16 aid, bool s1g)
+{
+       return s1g ? ieee80211_s1g_check_tim(tim, tim_len, aid) :
+                    __ieee80211_check_tim(tim, tim_len, aid);
+}
 
 #endif /* LINUX_IEEE80211_H */