/* 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_ANO_NETTYPE_WILD              15
 
-/* bits unique to S1G beacon */
-#define IEEE80211_S1G_BCN_NEXT_TBTT    0x100
-
 /* control extension - for IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTL_EXT */
 #define IEEE80211_CTL_EXT_POLL         0x2000
 #define IEEE80211_CTL_EXT_SPR          0x3000
               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_s1g_short_beacon - check if frame is an S1G short beacon
  * @fc: frame control bytes in little-endian byteorder
                        u8 change_seq;
                        u8 variable[0];
                } __packed s1g_beacon;
-               struct {
-                       u8 sa[ETH_ALEN];
-                       __le32 timestamp;
-                       u8 change_seq;
-                       u8 next_tbtt[3];
-                       u8 variable[0];
-               } __packed s1g_short_beacon;
        } 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;
+}
+
 #define IEEE80211_TWT_CONTROL_NDP                      BIT(0)
 #define IEEE80211_TWT_CONTROL_RESP_MODE                        BIT(1)
 #define IEEE80211_TWT_CONTROL_NEG_TYPE_BROADCAST       BIT(3)
 
        bssid = ieee80211_get_bssid(hdr, len, sdata->vif.type);
        if (ieee80211_is_s1g_beacon(mgmt->frame_control)) {
                struct ieee80211_ext *ext = (void *) mgmt;
-
-               if (ieee80211_is_s1g_short_beacon(ext->frame_control))
-                       variable = ext->u.s1g_short_beacon.variable;
-               else
-                       variable = ext->u.s1g_beacon.variable;
+               variable = ext->u.s1g_beacon.variable +
+                          ieee80211_s1g_optional_len(ext->frame_control);
        }
 
        baselen = (u8 *) variable - (u8 *) mgmt;
 
        struct ieee80211_mgmt *mgmt = (void *)skb->data;
        struct ieee80211_bss *bss;
        struct ieee80211_channel *channel;
+       struct ieee80211_ext *ext;
        size_t min_hdr_len = offsetof(struct ieee80211_mgmt,
                                      u.probe_resp.variable);
 
                return;
 
        if (ieee80211_is_s1g_beacon(mgmt->frame_control)) {
-               if (ieee80211_is_s1g_short_beacon(mgmt->frame_control))
-                       min_hdr_len = offsetof(struct ieee80211_ext,
-                                              u.s1g_short_beacon.variable);
-               else
-                       min_hdr_len = offsetof(struct ieee80211_ext,
-                                              u.s1g_beacon);
+               ext = (struct ieee80211_ext *)mgmt;
+               min_hdr_len =
+                       offsetof(struct ieee80211_ext, u.s1g_beacon.variable) +
+                       ieee80211_s1g_optional_len(ext->frame_control);
        }
 
        if (skb->len < min_hdr_len)
 
        const u8 *ie;
        size_t ielen;
        u64 tsf;
+       size_t s1g_optional_len;
 
        if (WARN_ON(!mgmt))
                return NULL;
 
        if (ieee80211_is_s1g_beacon(mgmt->frame_control)) {
                ext = (void *) mgmt;
-               if (ieee80211_is_s1g_short_beacon(mgmt->frame_control))
-                       min_hdr_len = offsetof(struct ieee80211_ext,
-                                              u.s1g_short_beacon.variable);
-               else
-                       min_hdr_len = offsetof(struct ieee80211_ext,
-                                              u.s1g_beacon.variable);
+               s1g_optional_len =
+                       ieee80211_s1g_optional_len(ext->frame_control);
+               min_hdr_len =
+                       offsetof(struct ieee80211_ext, u.s1g_beacon.variable) +
+                       s1g_optional_len;
        } else {
                /* same for beacons */
                min_hdr_len = offsetof(struct ieee80211_mgmt,
                const struct ieee80211_s1g_bcn_compat_ie *compat;
                const struct element *elem;
 
-               if (ieee80211_is_s1g_short_beacon(mgmt->frame_control))
-                       ie = ext->u.s1g_short_beacon.variable;
-               else
-                       ie = ext->u.s1g_beacon.variable;
-
+               ie = ext->u.s1g_beacon.variable + s1g_optional_len;
                elem = cfg80211_find_elem(WLAN_EID_S1G_BCN_COMPAT, ie, ielen);
                if (!elem)
                        return NULL;