Skip to content

Commit 4f0fcdb

Browse files
donnaskiezgregkh
authored andcommitted
wifi: cfg80211/mac80211: correctly parse S1G beacon optional elements
[ Upstream commit 1e1f706 ] S1G beacons are not traditional beacons but a type of extension frame. Extension frames contain the frame control and duration fields, followed by zero or more optional fields before the frame body. These optional fields are distinct from the variable length elements. The presence of optional fields is indicated in the frame control field. To correctly locate the elements offset, the frame control must be parsed to identify which optional fields are present. Currently, mac80211 parses S1G beacons based on fixed assumptions about the frame layout, without inspecting the frame control field. This can result in incorrect offsets to the "variable" portion of the frame. Properly parse S1G beacon frames by using the field lengths defined in IEEE 802.11-2024, section 9.3.4.3, ensuring that the elements offset is calculated accurately. Fixes: 9eaffe5 ("cfg80211: convert S1G beacon to scan results") Fixes: cd418ba ("mac80211: convert S1G beacon to scan results") Signed-off-by: Lachlan Hodges <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Johannes Berg <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent b2fc08d commit 4f0fcdb

File tree

4 files changed

+83
-32
lines changed

4 files changed

+83
-32
lines changed

include/linux/ieee80211.h

Lines changed: 69 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@
111111

112112
/* bits unique to S1G beacon */
113113
#define IEEE80211_S1G_BCN_NEXT_TBTT 0x100
114+
#define IEEE80211_S1G_BCN_CSSID 0x200
115+
#define IEEE80211_S1G_BCN_ANO 0x400
114116

115117
/* see 802.11ah-2016 9.9 NDP CMAC frames */
116118
#define IEEE80211_S1G_1MHZ_NDP_BITS 25
@@ -153,9 +155,6 @@
153155

154156
#define IEEE80211_ANO_NETTYPE_WILD 15
155157

156-
/* bits unique to S1G beacon */
157-
#define IEEE80211_S1G_BCN_NEXT_TBTT 0x100
158-
159158
/* control extension - for IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTL_EXT */
160159
#define IEEE80211_CTL_EXT_POLL 0x2000
161160
#define IEEE80211_CTL_EXT_SPR 0x3000
@@ -627,6 +626,42 @@ static inline bool ieee80211_is_s1g_beacon(__le16 fc)
627626
cpu_to_le16(IEEE80211_FTYPE_EXT | IEEE80211_STYPE_S1G_BEACON);
628627
}
629628

629+
/**
630+
* ieee80211_s1g_has_next_tbtt - check if IEEE80211_S1G_BCN_NEXT_TBTT
631+
* @fc: frame control bytes in little-endian byteorder
632+
* Return: whether or not the frame contains the variable-length
633+
* next TBTT field
634+
*/
635+
static inline bool ieee80211_s1g_has_next_tbtt(__le16 fc)
636+
{
637+
return ieee80211_is_s1g_beacon(fc) &&
638+
(fc & cpu_to_le16(IEEE80211_S1G_BCN_NEXT_TBTT));
639+
}
640+
641+
/**
642+
* ieee80211_s1g_has_ano - check if IEEE80211_S1G_BCN_ANO
643+
* @fc: frame control bytes in little-endian byteorder
644+
* Return: whether or not the frame contains the variable-length
645+
* ANO field
646+
*/
647+
static inline bool ieee80211_s1g_has_ano(__le16 fc)
648+
{
649+
return ieee80211_is_s1g_beacon(fc) &&
650+
(fc & cpu_to_le16(IEEE80211_S1G_BCN_ANO));
651+
}
652+
653+
/**
654+
* ieee80211_s1g_has_cssid - check if IEEE80211_S1G_BCN_CSSID
655+
* @fc: frame control bytes in little-endian byteorder
656+
* Return: whether or not the frame contains the variable-length
657+
* compressed SSID field
658+
*/
659+
static inline bool ieee80211_s1g_has_cssid(__le16 fc)
660+
{
661+
return ieee80211_is_s1g_beacon(fc) &&
662+
(fc & cpu_to_le16(IEEE80211_S1G_BCN_CSSID));
663+
}
664+
630665
/**
631666
* ieee80211_is_s1g_short_beacon - check if frame is an S1G short beacon
632667
* @fc: frame control bytes in little-endian byteorder
@@ -1245,16 +1280,40 @@ struct ieee80211_ext {
12451280
u8 change_seq;
12461281
u8 variable[0];
12471282
} __packed s1g_beacon;
1248-
struct {
1249-
u8 sa[ETH_ALEN];
1250-
__le32 timestamp;
1251-
u8 change_seq;
1252-
u8 next_tbtt[3];
1253-
u8 variable[0];
1254-
} __packed s1g_short_beacon;
12551283
} u;
12561284
} __packed __aligned(2);
12571285

1286+
/**
1287+
* ieee80211_s1g_optional_len - determine length of optional S1G beacon fields
1288+
* @fc: frame control bytes in little-endian byteorder
1289+
* Return: total length in bytes of the optional fixed-length fields
1290+
*
1291+
* S1G beacons may contain up to three optional fixed-length fields that
1292+
* precede the variable-length elements. Whether these fields are present
1293+
* is indicated by flags in the frame control field.
1294+
*
1295+
* From IEEE 802.11-2024 section 9.3.4.3:
1296+
* - Next TBTT field may be 0 or 3 bytes
1297+
* - Short SSID field may be 0 or 4 bytes
1298+
* - Access Network Options (ANO) field may be 0 or 1 byte
1299+
*/
1300+
static inline size_t
1301+
ieee80211_s1g_optional_len(__le16 fc)
1302+
{
1303+
size_t len = 0;
1304+
1305+
if (ieee80211_s1g_has_next_tbtt(fc))
1306+
len += 3;
1307+
1308+
if (ieee80211_s1g_has_cssid(fc))
1309+
len += 4;
1310+
1311+
if (ieee80211_s1g_has_ano(fc))
1312+
len += 1;
1313+
1314+
return len;
1315+
}
1316+
12581317
#define IEEE80211_TWT_CONTROL_NDP BIT(0)
12591318
#define IEEE80211_TWT_CONTROL_RESP_MODE BIT(1)
12601319
#define IEEE80211_TWT_CONTROL_NEG_TYPE_BROADCAST BIT(3)

net/mac80211/mlme.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6728,11 +6728,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link,
67286728
bssid = ieee80211_get_bssid(hdr, len, sdata->vif.type);
67296729
if (ieee80211_is_s1g_beacon(mgmt->frame_control)) {
67306730
struct ieee80211_ext *ext = (void *) mgmt;
6731-
6732-
if (ieee80211_is_s1g_short_beacon(ext->frame_control))
6733-
variable = ext->u.s1g_short_beacon.variable;
6734-
else
6735-
variable = ext->u.s1g_beacon.variable;
6731+
variable = ext->u.s1g_beacon.variable +
6732+
ieee80211_s1g_optional_len(ext->frame_control);
67366733
}
67376734

67386735
baselen = (u8 *) variable - (u8 *) mgmt;

net/mac80211/scan.c

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
260260
struct ieee80211_mgmt *mgmt = (void *)skb->data;
261261
struct ieee80211_bss *bss;
262262
struct ieee80211_channel *channel;
263+
struct ieee80211_ext *ext;
263264
size_t min_hdr_len = offsetof(struct ieee80211_mgmt,
264265
u.probe_resp.variable);
265266

@@ -269,12 +270,10 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
269270
return;
270271

271272
if (ieee80211_is_s1g_beacon(mgmt->frame_control)) {
272-
if (ieee80211_is_s1g_short_beacon(mgmt->frame_control))
273-
min_hdr_len = offsetof(struct ieee80211_ext,
274-
u.s1g_short_beacon.variable);
275-
else
276-
min_hdr_len = offsetof(struct ieee80211_ext,
277-
u.s1g_beacon);
273+
ext = (struct ieee80211_ext *)mgmt;
274+
min_hdr_len =
275+
offsetof(struct ieee80211_ext, u.s1g_beacon.variable) +
276+
ieee80211_s1g_optional_len(ext->frame_control);
278277
}
279278

280279
if (skb->len < min_hdr_len)

net/wireless/scan.c

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3213,6 +3213,7 @@ cfg80211_inform_bss_frame_data(struct wiphy *wiphy,
32133213
const u8 *ie;
32143214
size_t ielen;
32153215
u64 tsf;
3216+
size_t s1g_optional_len;
32163217

32173218
if (WARN_ON(!mgmt))
32183219
return NULL;
@@ -3227,12 +3228,11 @@ cfg80211_inform_bss_frame_data(struct wiphy *wiphy,
32273228

32283229
if (ieee80211_is_s1g_beacon(mgmt->frame_control)) {
32293230
ext = (void *) mgmt;
3230-
if (ieee80211_is_s1g_short_beacon(mgmt->frame_control))
3231-
min_hdr_len = offsetof(struct ieee80211_ext,
3232-
u.s1g_short_beacon.variable);
3233-
else
3234-
min_hdr_len = offsetof(struct ieee80211_ext,
3235-
u.s1g_beacon.variable);
3231+
s1g_optional_len =
3232+
ieee80211_s1g_optional_len(ext->frame_control);
3233+
min_hdr_len =
3234+
offsetof(struct ieee80211_ext, u.s1g_beacon.variable) +
3235+
s1g_optional_len;
32363236
} else {
32373237
/* same for beacons */
32383238
min_hdr_len = offsetof(struct ieee80211_mgmt,
@@ -3248,11 +3248,7 @@ cfg80211_inform_bss_frame_data(struct wiphy *wiphy,
32483248
const struct ieee80211_s1g_bcn_compat_ie *compat;
32493249
const struct element *elem;
32503250

3251-
if (ieee80211_is_s1g_short_beacon(mgmt->frame_control))
3252-
ie = ext->u.s1g_short_beacon.variable;
3253-
else
3254-
ie = ext->u.s1g_beacon.variable;
3255-
3251+
ie = ext->u.s1g_beacon.variable + s1g_optional_len;
32563252
elem = cfg80211_find_elem(WLAN_EID_S1G_BCN_COMPAT, ie, ielen);
32573253
if (!elem)
32583254
return NULL;

0 commit comments

Comments
 (0)