Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

wifi: ieee80211: split S1G definitions out

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>

+591 -569
+575
include/linux/ieee80211-s1g.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * IEEE 802.11 S1G definitions 4 + * 5 + * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen 6 + * <jkmaline@cc.hut.fi> 7 + * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi> 8 + * Copyright (c) 2005, Devicescape Software, Inc. 9 + * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net> 10 + * Copyright (c) 2013 - 2014 Intel Mobile Communications GmbH 11 + * Copyright (c) 2016 - 2017 Intel Deutschland GmbH 12 + * Copyright (c) 2018 - 2025 Intel Corporation 13 + */ 14 + 15 + #ifndef LINUX_IEEE80211_S1G_H 16 + #define LINUX_IEEE80211_S1G_H 17 + 18 + #include <linux/types.h> 19 + #include <linux/if_ether.h> 20 + 21 + /* bits unique to S1G beacon frame control */ 22 + #define IEEE80211_S1G_BCN_NEXT_TBTT 0x100 23 + #define IEEE80211_S1G_BCN_CSSID 0x200 24 + #define IEEE80211_S1G_BCN_ANO 0x400 25 + 26 + /* see 802.11ah-2016 9.9 NDP CMAC frames */ 27 + #define IEEE80211_S1G_1MHZ_NDP_BITS 25 28 + #define IEEE80211_S1G_1MHZ_NDP_BYTES 4 29 + #define IEEE80211_S1G_2MHZ_NDP_BITS 37 30 + #define IEEE80211_S1G_2MHZ_NDP_BYTES 5 31 + 32 + /** 33 + * ieee80211_is_s1g_beacon - check if IEEE80211_FTYPE_EXT && 34 + * IEEE80211_STYPE_S1G_BEACON 35 + * @fc: frame control bytes in little-endian byteorder 36 + * Return: whether or not the frame is an S1G beacon 37 + */ 38 + static inline bool ieee80211_is_s1g_beacon(__le16 fc) 39 + { 40 + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | 41 + IEEE80211_FCTL_STYPE)) == 42 + cpu_to_le16(IEEE80211_FTYPE_EXT | IEEE80211_STYPE_S1G_BEACON); 43 + } 44 + 45 + /** 46 + * ieee80211_s1g_has_next_tbtt - check if IEEE80211_S1G_BCN_NEXT_TBTT 47 + * @fc: frame control bytes in little-endian byteorder 48 + * Return: whether or not the frame contains the variable-length 49 + * next TBTT field 50 + */ 51 + static inline bool ieee80211_s1g_has_next_tbtt(__le16 fc) 52 + { 53 + return ieee80211_is_s1g_beacon(fc) && 54 + (fc & cpu_to_le16(IEEE80211_S1G_BCN_NEXT_TBTT)); 55 + } 56 + 57 + /** 58 + * ieee80211_s1g_has_ano - check if IEEE80211_S1G_BCN_ANO 59 + * @fc: frame control bytes in little-endian byteorder 60 + * Return: whether or not the frame contains the variable-length 61 + * ANO field 62 + */ 63 + static inline bool ieee80211_s1g_has_ano(__le16 fc) 64 + { 65 + return ieee80211_is_s1g_beacon(fc) && 66 + (fc & cpu_to_le16(IEEE80211_S1G_BCN_ANO)); 67 + } 68 + 69 + /** 70 + * ieee80211_s1g_has_cssid - check if IEEE80211_S1G_BCN_CSSID 71 + * @fc: frame control bytes in little-endian byteorder 72 + * Return: whether or not the frame contains the variable-length 73 + * compressed SSID field 74 + */ 75 + static inline bool ieee80211_s1g_has_cssid(__le16 fc) 76 + { 77 + return ieee80211_is_s1g_beacon(fc) && 78 + (fc & cpu_to_le16(IEEE80211_S1G_BCN_CSSID)); 79 + } 80 + 81 + /** 82 + * enum ieee80211_s1g_chanwidth - S1G channel widths 83 + * These are defined in IEEE802.11-2016ah Table 10-20 84 + * as BSS Channel Width 85 + * 86 + * @IEEE80211_S1G_CHANWIDTH_1MHZ: 1MHz operating channel 87 + * @IEEE80211_S1G_CHANWIDTH_2MHZ: 2MHz operating channel 88 + * @IEEE80211_S1G_CHANWIDTH_4MHZ: 4MHz operating channel 89 + * @IEEE80211_S1G_CHANWIDTH_8MHZ: 8MHz operating channel 90 + * @IEEE80211_S1G_CHANWIDTH_16MHZ: 16MHz operating channel 91 + */ 92 + enum ieee80211_s1g_chanwidth { 93 + IEEE80211_S1G_CHANWIDTH_1MHZ = 0, 94 + IEEE80211_S1G_CHANWIDTH_2MHZ = 1, 95 + IEEE80211_S1G_CHANWIDTH_4MHZ = 3, 96 + IEEE80211_S1G_CHANWIDTH_8MHZ = 7, 97 + IEEE80211_S1G_CHANWIDTH_16MHZ = 15, 98 + }; 99 + 100 + /** 101 + * enum ieee80211_s1g_pri_chanwidth - S1G primary channel widths 102 + * described in IEEE80211-2024 Table 10-39. 103 + * 104 + * @IEEE80211_S1G_PRI_CHANWIDTH_2MHZ: 2MHz primary channel 105 + * @IEEE80211_S1G_PRI_CHANWIDTH_1MHZ: 1MHz primary channel 106 + */ 107 + enum ieee80211_s1g_pri_chanwidth { 108 + IEEE80211_S1G_PRI_CHANWIDTH_2MHZ = 0, 109 + IEEE80211_S1G_PRI_CHANWIDTH_1MHZ = 1, 110 + }; 111 + 112 + /** 113 + * struct ieee80211_s1g_bcn_compat_ie - S1G Beacon Compatibility element 114 + * @compat_info: Compatibility Information 115 + * @beacon_int: Beacon Interval 116 + * @tsf_completion: TSF Completion 117 + * 118 + * This structure represents the payload of the "S1G Beacon 119 + * Compatibility element" as described in IEEE Std 802.11-2020 section 120 + * 9.4.2.196. 121 + */ 122 + struct ieee80211_s1g_bcn_compat_ie { 123 + __le16 compat_info; 124 + __le16 beacon_int; 125 + __le32 tsf_completion; 126 + } __packed; 127 + 128 + /** 129 + * struct ieee80211_s1g_oper_ie - S1G Operation element 130 + * @ch_width: S1G Operation Information Channel Width 131 + * @oper_class: S1G Operation Information Operating Class 132 + * @primary_ch: S1G Operation Information Primary Channel Number 133 + * @oper_ch: S1G Operation Information Channel Center Frequency 134 + * @basic_mcs_nss: Basic S1G-MCS and NSS Set 135 + * 136 + * This structure represents the payload of the "S1G Operation 137 + * element" as described in IEEE Std 802.11-2020 section 9.4.2.212. 138 + */ 139 + struct ieee80211_s1g_oper_ie { 140 + u8 ch_width; 141 + u8 oper_class; 142 + u8 primary_ch; 143 + u8 oper_ch; 144 + __le16 basic_mcs_nss; 145 + } __packed; 146 + 147 + /** 148 + * struct ieee80211_aid_response_ie - AID Response element 149 + * @aid: AID/Group AID 150 + * @switch_count: AID Switch Count 151 + * @response_int: AID Response Interval 152 + * 153 + * This structure represents the payload of the "AID Response element" 154 + * as described in IEEE Std 802.11-2020 section 9.4.2.194. 155 + */ 156 + struct ieee80211_aid_response_ie { 157 + __le16 aid; 158 + u8 switch_count; 159 + __le16 response_int; 160 + } __packed; 161 + 162 + struct ieee80211_s1g_cap { 163 + u8 capab_info[10]; 164 + u8 supp_mcs_nss[5]; 165 + } __packed; 166 + 167 + /** 168 + * ieee80211_s1g_optional_len - determine length of optional S1G beacon fields 169 + * @fc: frame control bytes in little-endian byteorder 170 + * Return: total length in bytes of the optional fixed-length fields 171 + * 172 + * S1G beacons may contain up to three optional fixed-length fields that 173 + * precede the variable-length elements. Whether these fields are present 174 + * is indicated by flags in the frame control field. 175 + * 176 + * From IEEE 802.11-2024 section 9.3.4.3: 177 + * - Next TBTT field may be 0 or 3 bytes 178 + * - Short SSID field may be 0 or 4 bytes 179 + * - Access Network Options (ANO) field may be 0 or 1 byte 180 + */ 181 + static inline size_t 182 + ieee80211_s1g_optional_len(__le16 fc) 183 + { 184 + size_t len = 0; 185 + 186 + if (ieee80211_s1g_has_next_tbtt(fc)) 187 + len += 3; 188 + 189 + if (ieee80211_s1g_has_cssid(fc)) 190 + len += 4; 191 + 192 + if (ieee80211_s1g_has_ano(fc)) 193 + len += 1; 194 + 195 + return len; 196 + } 197 + 198 + /* S1G Capabilities Information field */ 199 + #define IEEE80211_S1G_CAPABILITY_LEN 15 200 + 201 + #define S1G_CAP0_S1G_LONG BIT(0) 202 + #define S1G_CAP0_SGI_1MHZ BIT(1) 203 + #define S1G_CAP0_SGI_2MHZ BIT(2) 204 + #define S1G_CAP0_SGI_4MHZ BIT(3) 205 + #define S1G_CAP0_SGI_8MHZ BIT(4) 206 + #define S1G_CAP0_SGI_16MHZ BIT(5) 207 + #define S1G_CAP0_SUPP_CH_WIDTH GENMASK(7, 6) 208 + 209 + #define S1G_SUPP_CH_WIDTH_2 0 210 + #define S1G_SUPP_CH_WIDTH_4 1 211 + #define S1G_SUPP_CH_WIDTH_8 2 212 + #define S1G_SUPP_CH_WIDTH_16 3 213 + #define S1G_SUPP_CH_WIDTH_MAX(cap) ((1 << FIELD_GET(S1G_CAP0_SUPP_CH_WIDTH, \ 214 + cap[0])) << 1) 215 + 216 + #define S1G_CAP1_RX_LDPC BIT(0) 217 + #define S1G_CAP1_TX_STBC BIT(1) 218 + #define S1G_CAP1_RX_STBC BIT(2) 219 + #define S1G_CAP1_SU_BFER BIT(3) 220 + #define S1G_CAP1_SU_BFEE BIT(4) 221 + #define S1G_CAP1_BFEE_STS GENMASK(7, 5) 222 + 223 + #define S1G_CAP2_SOUNDING_DIMENSIONS GENMASK(2, 0) 224 + #define S1G_CAP2_MU_BFER BIT(3) 225 + #define S1G_CAP2_MU_BFEE BIT(4) 226 + #define S1G_CAP2_PLUS_HTC_VHT BIT(5) 227 + #define S1G_CAP2_TRAVELING_PILOT GENMASK(7, 6) 228 + 229 + #define S1G_CAP3_RD_RESPONDER BIT(0) 230 + #define S1G_CAP3_HT_DELAYED_BA BIT(1) 231 + #define S1G_CAP3_MAX_MPDU_LEN BIT(2) 232 + #define S1G_CAP3_MAX_AMPDU_LEN_EXP GENMASK(4, 3) 233 + #define S1G_CAP3_MIN_MPDU_START GENMASK(7, 5) 234 + 235 + #define S1G_CAP4_UPLINK_SYNC BIT(0) 236 + #define S1G_CAP4_DYNAMIC_AID BIT(1) 237 + #define S1G_CAP4_BAT BIT(2) 238 + #define S1G_CAP4_TIME_ADE BIT(3) 239 + #define S1G_CAP4_NON_TIM BIT(4) 240 + #define S1G_CAP4_GROUP_AID BIT(5) 241 + #define S1G_CAP4_STA_TYPE GENMASK(7, 6) 242 + 243 + #define S1G_CAP5_CENT_AUTH_CONTROL BIT(0) 244 + #define S1G_CAP5_DIST_AUTH_CONTROL BIT(1) 245 + #define S1G_CAP5_AMSDU BIT(2) 246 + #define S1G_CAP5_AMPDU BIT(3) 247 + #define S1G_CAP5_ASYMMETRIC_BA BIT(4) 248 + #define S1G_CAP5_FLOW_CONTROL BIT(5) 249 + #define S1G_CAP5_SECTORIZED_BEAM GENMASK(7, 6) 250 + 251 + #define S1G_CAP6_OBSS_MITIGATION BIT(0) 252 + #define S1G_CAP6_FRAGMENT_BA BIT(1) 253 + #define S1G_CAP6_NDP_PS_POLL BIT(2) 254 + #define S1G_CAP6_RAW_OPERATION BIT(3) 255 + #define S1G_CAP6_PAGE_SLICING BIT(4) 256 + #define S1G_CAP6_TXOP_SHARING_IMP_ACK BIT(5) 257 + #define S1G_CAP6_VHT_LINK_ADAPT GENMASK(7, 6) 258 + 259 + #define S1G_CAP7_TACK_AS_PS_POLL BIT(0) 260 + #define S1G_CAP7_DUP_1MHZ BIT(1) 261 + #define S1G_CAP7_MCS_NEGOTIATION BIT(2) 262 + #define S1G_CAP7_1MHZ_CTL_RESPONSE_PREAMBLE BIT(3) 263 + #define S1G_CAP7_NDP_BFING_REPORT_POLL BIT(4) 264 + #define S1G_CAP7_UNSOLICITED_DYN_AID BIT(5) 265 + #define S1G_CAP7_SECTOR_TRAINING_OPERATION BIT(6) 266 + #define S1G_CAP7_TEMP_PS_MODE_SWITCH BIT(7) 267 + 268 + #define S1G_CAP8_TWT_GROUPING BIT(0) 269 + #define S1G_CAP8_BDT BIT(1) 270 + #define S1G_CAP8_COLOR GENMASK(4, 2) 271 + #define S1G_CAP8_TWT_REQUEST BIT(5) 272 + #define S1G_CAP8_TWT_RESPOND BIT(6) 273 + #define S1G_CAP8_PV1_FRAME BIT(7) 274 + 275 + #define S1G_CAP9_LINK_ADAPT_PER_CONTROL_RESPONSE BIT(0) 276 + 277 + #define S1G_OPER_CH_WIDTH_PRIMARY BIT(0) 278 + #define S1G_OPER_CH_WIDTH_OPER GENMASK(4, 1) 279 + #define S1G_OPER_CH_PRIMARY_LOCATION BIT(5) 280 + 281 + #define S1G_2M_PRIMARY_LOCATION_LOWER 0 282 + #define S1G_2M_PRIMARY_LOCATION_UPPER 1 283 + 284 + #define LISTEN_INT_USF GENMASK(15, 14) 285 + #define LISTEN_INT_UI GENMASK(13, 0) 286 + 287 + #define IEEE80211_MAX_USF FIELD_MAX(LISTEN_INT_USF) 288 + #define IEEE80211_MAX_UI FIELD_MAX(LISTEN_INT_UI) 289 + 290 + /* S1G encoding types */ 291 + #define IEEE80211_S1G_TIM_ENC_MODE_BLOCK 0 292 + #define IEEE80211_S1G_TIM_ENC_MODE_SINGLE 1 293 + #define IEEE80211_S1G_TIM_ENC_MODE_OLB 2 294 + 295 + enum ieee80211_s1g_actioncode { 296 + WLAN_S1G_AID_SWITCH_REQUEST, 297 + WLAN_S1G_AID_SWITCH_RESPONSE, 298 + WLAN_S1G_SYNC_CONTROL, 299 + WLAN_S1G_STA_INFO_ANNOUNCE, 300 + WLAN_S1G_EDCA_PARAM_SET, 301 + WLAN_S1G_EL_OPERATION, 302 + WLAN_S1G_TWT_SETUP, 303 + WLAN_S1G_TWT_TEARDOWN, 304 + WLAN_S1G_SECT_GROUP_ID_LIST, 305 + WLAN_S1G_SECT_ID_FEEDBACK, 306 + WLAN_S1G_TWT_INFORMATION = 11, 307 + }; 308 + 309 + /** 310 + * ieee80211_is_s1g_short_beacon - check if frame is an S1G short beacon 311 + * @fc: frame control bytes in little-endian byteorder 312 + * @variable: pointer to the beacon frame elements 313 + * @variable_len: length of the frame elements 314 + * Return: whether or not the frame is an S1G short beacon. As per 315 + * IEEE80211-2024 11.1.3.10.1, The S1G beacon compatibility element shall 316 + * always be present as the first element in beacon frames generated at a 317 + * TBTT (Target Beacon Transmission Time), so any frame not containing 318 + * this element must have been generated at a TSBTT (Target Short Beacon 319 + * Transmission Time) that is not a TBTT. Additionally, short beacons are 320 + * prohibited from containing the S1G beacon compatibility element as per 321 + * IEEE80211-2024 9.3.4.3 Table 9-76, so if we have an S1G beacon with 322 + * either no elements or the first element is not the beacon compatibility 323 + * element, we have a short beacon. 324 + */ 325 + static inline bool ieee80211_is_s1g_short_beacon(__le16 fc, const u8 *variable, 326 + size_t variable_len) 327 + { 328 + if (!ieee80211_is_s1g_beacon(fc)) 329 + return false; 330 + 331 + /* 332 + * If the frame does not contain at least 1 element (this is perfectly 333 + * valid in a short beacon) and is an S1G beacon, we have a short 334 + * beacon. 335 + */ 336 + if (variable_len < 2) 337 + return true; 338 + 339 + return variable[0] != WLAN_EID_S1G_BCN_COMPAT; 340 + } 341 + 342 + struct s1g_tim_aid { 343 + u16 aid; 344 + u8 target_blk; /* Target block index */ 345 + u8 target_subblk; /* Target subblock index */ 346 + u8 target_subblk_bit; /* Target subblock bit */ 347 + }; 348 + 349 + struct s1g_tim_enc_block { 350 + u8 enc_mode; 351 + bool inverse; 352 + const u8 *ptr; 353 + u8 len; 354 + 355 + /* 356 + * For an OLB encoded block that spans multiple blocks, this 357 + * is the offset into the span described by that encoded block. 358 + */ 359 + u8 olb_blk_offset; 360 + }; 361 + 362 + /* 363 + * Helper routines to quickly extract the length of an encoded block. Validation 364 + * is also performed to ensure the length extracted lies within the TIM. 365 + */ 366 + 367 + static inline int ieee80211_s1g_len_bitmap(const u8 *ptr, const u8 *end) 368 + { 369 + u8 blkmap; 370 + u8 n_subblks; 371 + 372 + if (ptr >= end) 373 + return -EINVAL; 374 + 375 + blkmap = *ptr; 376 + n_subblks = hweight8(blkmap); 377 + 378 + if (ptr + 1 + n_subblks > end) 379 + return -EINVAL; 380 + 381 + return 1 + n_subblks; 382 + } 383 + 384 + static inline int ieee80211_s1g_len_single(const u8 *ptr, const u8 *end) 385 + { 386 + return (ptr + 1 > end) ? -EINVAL : 1; 387 + } 388 + 389 + static inline int ieee80211_s1g_len_olb(const u8 *ptr, const u8 *end) 390 + { 391 + if (ptr >= end) 392 + return -EINVAL; 393 + 394 + return (ptr + 1 + *ptr > end) ? -EINVAL : 1 + *ptr; 395 + } 396 + 397 + /* 398 + * Enumerate all encoded blocks until we find the encoded block that describes 399 + * our target AID. OLB is a special case as a single encoded block can describe 400 + * multiple blocks as a single encoded block. 401 + */ 402 + static inline int ieee80211_s1g_find_target_block(struct s1g_tim_enc_block *enc, 403 + const struct s1g_tim_aid *aid, 404 + const u8 *ptr, const u8 *end) 405 + { 406 + /* need at least block-control octet */ 407 + while (ptr + 1 <= end) { 408 + u8 ctrl = *ptr++; 409 + u8 mode = ctrl & 0x03; 410 + bool contains, inverse = ctrl & BIT(2); 411 + u8 span, blk_off = ctrl >> 3; 412 + int len; 413 + 414 + switch (mode) { 415 + case IEEE80211_S1G_TIM_ENC_MODE_BLOCK: 416 + len = ieee80211_s1g_len_bitmap(ptr, end); 417 + contains = blk_off == aid->target_blk; 418 + break; 419 + case IEEE80211_S1G_TIM_ENC_MODE_SINGLE: 420 + len = ieee80211_s1g_len_single(ptr, end); 421 + contains = blk_off == aid->target_blk; 422 + break; 423 + case IEEE80211_S1G_TIM_ENC_MODE_OLB: 424 + len = ieee80211_s1g_len_olb(ptr, end); 425 + /* 426 + * An OLB encoded block can describe more then one 427 + * block, meaning an encoded OLB block can span more 428 + * then a single block. 429 + */ 430 + if (len > 0) { 431 + /* Minus one for the length octet */ 432 + span = DIV_ROUND_UP(len - 1, 8); 433 + /* 434 + * Check if our target block lies within the 435 + * block span described by this encoded block. 436 + */ 437 + contains = (aid->target_blk >= blk_off) && 438 + (aid->target_blk < blk_off + span); 439 + } 440 + break; 441 + default: 442 + return -EOPNOTSUPP; 443 + } 444 + 445 + if (len < 0) 446 + return len; 447 + 448 + if (contains) { 449 + enc->enc_mode = mode; 450 + enc->inverse = inverse; 451 + enc->ptr = ptr; 452 + enc->len = (u8)len; 453 + enc->olb_blk_offset = blk_off; 454 + return 0; 455 + } 456 + 457 + ptr += len; 458 + } 459 + 460 + return -ENOENT; 461 + } 462 + 463 + static inline bool ieee80211_s1g_parse_bitmap(struct s1g_tim_enc_block *enc, 464 + struct s1g_tim_aid *aid) 465 + { 466 + const u8 *ptr = enc->ptr; 467 + u8 blkmap = *ptr++; 468 + 469 + /* 470 + * If our block bitmap does not contain a set bit that corresponds 471 + * to our AID, it could mean a variety of things depending on if 472 + * the encoding mode is inverted or not. 473 + * 474 + * 1. If inverted, it means the entire subblock is present and hence 475 + * our AID has been set. 476 + * 2. If not inverted, it means our subblock is not present and hence 477 + * it is all zero meaning our AID is not set. 478 + */ 479 + if (!(blkmap & BIT(aid->target_subblk))) 480 + return enc->inverse; 481 + 482 + /* 483 + * Increment ptr by the number of set subblocks that appear before our 484 + * target subblock. If our target subblock is 0, do nothing as ptr 485 + * already points to our target subblock. 486 + */ 487 + if (aid->target_subblk) 488 + ptr += hweight8(blkmap & GENMASK(aid->target_subblk - 1, 0)); 489 + 490 + return !!(*ptr & BIT(aid->target_subblk_bit)) ^ enc->inverse; 491 + } 492 + 493 + static inline bool ieee80211_s1g_parse_single(struct s1g_tim_enc_block *enc, 494 + struct s1g_tim_aid *aid) 495 + { 496 + /* 497 + * Single AID mode describes, as the name suggests, a single AID 498 + * within the block described by the encoded block. The octet 499 + * contains the 6 LSBs of the AID described in the block. The other 500 + * 2 bits are reserved. When inversed, every single AID described 501 + * by the current block have buffered traffic except for the AID 502 + * described in the single AID octet. 503 + */ 504 + return ((*enc->ptr & 0x3f) == (aid->aid & 0x3f)) ^ enc->inverse; 505 + } 506 + 507 + static inline bool ieee80211_s1g_parse_olb(struct s1g_tim_enc_block *enc, 508 + struct s1g_tim_aid *aid) 509 + { 510 + const u8 *ptr = enc->ptr; 511 + u8 blk_len = *ptr++; 512 + /* 513 + * Given an OLB encoded block that describes multiple blocks, 514 + * calculate the offset into the span. Then calculate the 515 + * subblock location normally. 516 + */ 517 + u16 span_offset = aid->target_blk - enc->olb_blk_offset; 518 + u16 subblk_idx = span_offset * 8 + aid->target_subblk; 519 + 520 + if (subblk_idx >= blk_len) 521 + return enc->inverse; 522 + 523 + return !!(ptr[subblk_idx] & BIT(aid->target_subblk_bit)) ^ enc->inverse; 524 + } 525 + 526 + /* 527 + * An S1G PVB has 3 non optional encoding types, each that can be inverted. 528 + * An S1G PVB is constructed with zero or more encoded block subfields. Each 529 + * encoded block represents a single "block" of AIDs (64), and each encoded 530 + * block can contain one of the 3 encoding types alongside a single bit for 531 + * whether the bits should be inverted. 532 + * 533 + * As the standard makes no guarantee about the ordering of encoded blocks, 534 + * we must parse every encoded block in the worst case scenario given an 535 + * AID that lies within the last block. 536 + */ 537 + static inline bool ieee80211_s1g_check_tim(const struct ieee80211_tim_ie *tim, 538 + u8 tim_len, u16 aid) 539 + { 540 + int err; 541 + struct s1g_tim_aid target_aid; 542 + struct s1g_tim_enc_block enc_blk; 543 + 544 + if (tim_len < 3) 545 + return false; 546 + 547 + target_aid.aid = aid; 548 + target_aid.target_blk = (aid >> 6) & 0x1f; 549 + target_aid.target_subblk = (aid >> 3) & 0x7; 550 + target_aid.target_subblk_bit = aid & 0x7; 551 + 552 + /* 553 + * Find our AIDs target encoded block and fill &enc_blk with the 554 + * encoded blocks information. If no entry is found or an error 555 + * occurs return false. 556 + */ 557 + err = ieee80211_s1g_find_target_block(&enc_blk, &target_aid, 558 + tim->virtual_map, 559 + (const u8 *)tim + tim_len + 2); 560 + if (err) 561 + return false; 562 + 563 + switch (enc_blk.enc_mode) { 564 + case IEEE80211_S1G_TIM_ENC_MODE_BLOCK: 565 + return ieee80211_s1g_parse_bitmap(&enc_blk, &target_aid); 566 + case IEEE80211_S1G_TIM_ENC_MODE_SINGLE: 567 + return ieee80211_s1g_parse_single(&enc_blk, &target_aid); 568 + case IEEE80211_S1G_TIM_ENC_MODE_OLB: 569 + return ieee80211_s1g_parse_olb(&enc_blk, &target_aid); 570 + default: 571 + return false; 572 + } 573 + } 574 + 575 + #endif /* LINUX_IEEE80211_H */
+16 -569
include/linux/ieee80211.h
··· 109 109 #define IEEE80211_STYPE_DMG_BEACON 0x0000 110 110 #define IEEE80211_STYPE_S1G_BEACON 0x0010 111 111 112 - /* bits unique to S1G beacon */ 113 - #define IEEE80211_S1G_BCN_NEXT_TBTT 0x100 114 - #define IEEE80211_S1G_BCN_CSSID 0x200 115 - #define IEEE80211_S1G_BCN_ANO 0x400 116 - 117 - /* see 802.11ah-2016 9.9 NDP CMAC frames */ 118 - #define IEEE80211_S1G_1MHZ_NDP_BITS 25 119 - #define IEEE80211_S1G_1MHZ_NDP_BYTES 4 120 - #define IEEE80211_S1G_2MHZ_NDP_BITS 37 121 - #define IEEE80211_S1G_2MHZ_NDP_BYTES 5 122 - 123 112 #define IEEE80211_NDP_FTYPE_CTS 0 124 113 #define IEEE80211_NDP_FTYPE_CF_END 0 125 114 #define IEEE80211_NDP_FTYPE_PS_POLL 1 ··· 209 220 #define IEEE80211_MAX_AID_S1G 8191 210 221 #define IEEE80211_MAX_TIM_LEN 251 211 222 #define IEEE80211_MAX_MESH_PEERINGS 63 212 - 213 - /* S1G encoding types */ 214 - #define IEEE80211_S1G_TIM_ENC_MODE_BLOCK 0 215 - #define IEEE80211_S1G_TIM_ENC_MODE_SINGLE 1 216 - #define IEEE80211_S1G_TIM_ENC_MODE_OLB 2 217 223 218 224 /* Maximum size for the MA-UNITDATA primitive, 802.11 standard section 219 225 6.2.1.1.2. ··· 589 605 } 590 606 591 607 /** 592 - * ieee80211_is_s1g_beacon - check if IEEE80211_FTYPE_EXT && 593 - * IEEE80211_STYPE_S1G_BEACON 594 - * @fc: frame control bytes in little-endian byteorder 595 - * Return: whether or not the frame is an S1G beacon 596 - */ 597 - static inline bool ieee80211_is_s1g_beacon(__le16 fc) 598 - { 599 - return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | 600 - IEEE80211_FCTL_STYPE)) == 601 - cpu_to_le16(IEEE80211_FTYPE_EXT | IEEE80211_STYPE_S1G_BEACON); 602 - } 603 - 604 - /** 605 - * ieee80211_s1g_has_next_tbtt - check if IEEE80211_S1G_BCN_NEXT_TBTT 606 - * @fc: frame control bytes in little-endian byteorder 607 - * Return: whether or not the frame contains the variable-length 608 - * next TBTT field 609 - */ 610 - static inline bool ieee80211_s1g_has_next_tbtt(__le16 fc) 611 - { 612 - return ieee80211_is_s1g_beacon(fc) && 613 - (fc & cpu_to_le16(IEEE80211_S1G_BCN_NEXT_TBTT)); 614 - } 615 - 616 - /** 617 - * ieee80211_s1g_has_ano - check if IEEE80211_S1G_BCN_ANO 618 - * @fc: frame control bytes in little-endian byteorder 619 - * Return: whether or not the frame contains the variable-length 620 - * ANO field 621 - */ 622 - static inline bool ieee80211_s1g_has_ano(__le16 fc) 623 - { 624 - return ieee80211_is_s1g_beacon(fc) && 625 - (fc & cpu_to_le16(IEEE80211_S1G_BCN_ANO)); 626 - } 627 - 628 - /** 629 - * ieee80211_s1g_has_cssid - check if IEEE80211_S1G_BCN_CSSID 630 - * @fc: frame control bytes in little-endian byteorder 631 - * Return: whether or not the frame contains the variable-length 632 - * compressed SSID field 633 - */ 634 - static inline bool ieee80211_s1g_has_cssid(__le16 fc) 635 - { 636 - return ieee80211_is_s1g_beacon(fc) && 637 - (fc & cpu_to_le16(IEEE80211_S1G_BCN_CSSID)); 638 - } 639 - 640 - /** 641 608 * ieee80211_is_atim - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_ATIM 642 609 * @fc: frame control bytes in little-endian byteorder 643 610 * Return: whether or not the frame is an ATIM frame ··· 919 984 }; 920 985 } __packed; 921 986 922 - /** 923 - * enum ieee80211_s1g_chanwidth - S1G channel widths 924 - * These are defined in IEEE802.11-2016ah Table 10-20 925 - * as BSS Channel Width 926 - * 927 - * @IEEE80211_S1G_CHANWIDTH_1MHZ: 1MHz operating channel 928 - * @IEEE80211_S1G_CHANWIDTH_2MHZ: 2MHz operating channel 929 - * @IEEE80211_S1G_CHANWIDTH_4MHZ: 4MHz operating channel 930 - * @IEEE80211_S1G_CHANWIDTH_8MHZ: 8MHz operating channel 931 - * @IEEE80211_S1G_CHANWIDTH_16MHZ: 16MHz operating channel 932 - */ 933 - enum ieee80211_s1g_chanwidth { 934 - IEEE80211_S1G_CHANWIDTH_1MHZ = 0, 935 - IEEE80211_S1G_CHANWIDTH_2MHZ = 1, 936 - IEEE80211_S1G_CHANWIDTH_4MHZ = 3, 937 - IEEE80211_S1G_CHANWIDTH_8MHZ = 7, 938 - IEEE80211_S1G_CHANWIDTH_16MHZ = 15, 939 - }; 940 - 941 - /** 942 - * enum ieee80211_s1g_pri_chanwidth - S1G primary channel widths 943 - * described in IEEE80211-2024 Table 10-39. 944 - * 945 - * @IEEE80211_S1G_PRI_CHANWIDTH_2MHZ: 2MHz primary channel 946 - * @IEEE80211_S1G_PRI_CHANWIDTH_1MHZ: 1MHz primary channel 947 - */ 948 - enum ieee80211_s1g_pri_chanwidth { 949 - IEEE80211_S1G_PRI_CHANWIDTH_2MHZ = 0, 950 - IEEE80211_S1G_PRI_CHANWIDTH_1MHZ = 1, 951 - }; 952 - 953 987 #define WLAN_SA_QUERY_TR_ID_LEN 2 954 988 #define WLAN_MEMBERSHIP_LEN 8 955 989 #define WLAN_USER_POSITION_LEN 16 ··· 946 1042 u8 data; 947 1043 } __packed; 948 1044 949 - /** 950 - * struct ieee80211_s1g_bcn_compat_ie - S1G Beacon Compatibility element 951 - * @compat_info: Compatibility Information 952 - * @beacon_int: Beacon Interval 953 - * @tsf_completion: TSF Completion 954 - * 955 - * This structure represents the payload of the "S1G Beacon 956 - * Compatibility element" as described in IEEE Std 802.11-2020 section 957 - * 9.4.2.196. 958 - */ 959 - struct ieee80211_s1g_bcn_compat_ie { 960 - __le16 compat_info; 961 - __le16 beacon_int; 962 - __le32 tsf_completion; 963 - } __packed; 964 - 965 - /** 966 - * struct ieee80211_s1g_oper_ie - S1G Operation element 967 - * @ch_width: S1G Operation Information Channel Width 968 - * @oper_class: S1G Operation Information Operating Class 969 - * @primary_ch: S1G Operation Information Primary Channel Number 970 - * @oper_ch: S1G Operation Information Channel Center Frequency 971 - * @basic_mcs_nss: Basic S1G-MCS and NSS Set 972 - * 973 - * This structure represents the payload of the "S1G Operation 974 - * element" as described in IEEE Std 802.11-2020 section 9.4.2.212. 975 - */ 976 - struct ieee80211_s1g_oper_ie { 977 - u8 ch_width; 978 - u8 oper_class; 979 - u8 primary_ch; 980 - u8 oper_ch; 981 - __le16 basic_mcs_nss; 982 - } __packed; 983 - 984 - /** 985 - * struct ieee80211_aid_response_ie - AID Response element 986 - * @aid: AID/Group AID 987 - * @switch_count: AID Switch Count 988 - * @response_int: AID Response Interval 989 - * 990 - * This structure represents the payload of the "AID Response element" 991 - * as described in IEEE Std 802.11-2020 section 9.4.2.194. 992 - */ 993 - struct ieee80211_aid_response_ie { 994 - __le16 aid; 995 - u8 switch_count; 996 - __le16 response_int; 997 - } __packed; 998 - 999 - struct ieee80211_s1g_cap { 1000 - u8 capab_info[10]; 1001 - u8 supp_mcs_nss[5]; 1002 - } __packed; 1003 - 1004 1045 struct ieee80211_ext { 1005 1046 __le16 frame_control; 1006 1047 __le16 duration; ··· 958 1109 } __packed s1g_beacon; 959 1110 } u; 960 1111 } __packed __aligned(2); 961 - 962 - /** 963 - * ieee80211_s1g_optional_len - determine length of optional S1G beacon fields 964 - * @fc: frame control bytes in little-endian byteorder 965 - * Return: total length in bytes of the optional fixed-length fields 966 - * 967 - * S1G beacons may contain up to three optional fixed-length fields that 968 - * precede the variable-length elements. Whether these fields are present 969 - * is indicated by flags in the frame control field. 970 - * 971 - * From IEEE 802.11-2024 section 9.3.4.3: 972 - * - Next TBTT field may be 0 or 3 bytes 973 - * - Short SSID field may be 0 or 4 bytes 974 - * - Access Network Options (ANO) field may be 0 or 1 byte 975 - */ 976 - static inline size_t 977 - ieee80211_s1g_optional_len(__le16 fc) 978 - { 979 - size_t len = 0; 980 - 981 - if (ieee80211_s1g_has_next_tbtt(fc)) 982 - len += 3; 983 - 984 - if (ieee80211_s1g_has_cssid(fc)) 985 - len += 4; 986 - 987 - if (ieee80211_s1g_has_ano(fc)) 988 - len += 1; 989 - 990 - return len; 991 - } 992 1112 993 1113 /** 994 1114 * struct ieee80211_bss_load_elem - BSS Load elemen ··· 1384 1566 1385 1567 #define IEEE80211_P2P_OPPPS_ENABLE_BIT BIT(7) 1386 1568 #define IEEE80211_P2P_OPPPS_CTWINDOW_MASK 0x7F 1387 - 1388 - /* S1G Capabilities Information field */ 1389 - #define IEEE80211_S1G_CAPABILITY_LEN 15 1390 - 1391 - #define S1G_CAP0_S1G_LONG BIT(0) 1392 - #define S1G_CAP0_SGI_1MHZ BIT(1) 1393 - #define S1G_CAP0_SGI_2MHZ BIT(2) 1394 - #define S1G_CAP0_SGI_4MHZ BIT(3) 1395 - #define S1G_CAP0_SGI_8MHZ BIT(4) 1396 - #define S1G_CAP0_SGI_16MHZ BIT(5) 1397 - #define S1G_CAP0_SUPP_CH_WIDTH GENMASK(7, 6) 1398 - 1399 - #define S1G_SUPP_CH_WIDTH_2 0 1400 - #define S1G_SUPP_CH_WIDTH_4 1 1401 - #define S1G_SUPP_CH_WIDTH_8 2 1402 - #define S1G_SUPP_CH_WIDTH_16 3 1403 - #define S1G_SUPP_CH_WIDTH_MAX(cap) ((1 << FIELD_GET(S1G_CAP0_SUPP_CH_WIDTH, \ 1404 - cap[0])) << 1) 1405 - 1406 - #define S1G_CAP1_RX_LDPC BIT(0) 1407 - #define S1G_CAP1_TX_STBC BIT(1) 1408 - #define S1G_CAP1_RX_STBC BIT(2) 1409 - #define S1G_CAP1_SU_BFER BIT(3) 1410 - #define S1G_CAP1_SU_BFEE BIT(4) 1411 - #define S1G_CAP1_BFEE_STS GENMASK(7, 5) 1412 - 1413 - #define S1G_CAP2_SOUNDING_DIMENSIONS GENMASK(2, 0) 1414 - #define S1G_CAP2_MU_BFER BIT(3) 1415 - #define S1G_CAP2_MU_BFEE BIT(4) 1416 - #define S1G_CAP2_PLUS_HTC_VHT BIT(5) 1417 - #define S1G_CAP2_TRAVELING_PILOT GENMASK(7, 6) 1418 - 1419 - #define S1G_CAP3_RD_RESPONDER BIT(0) 1420 - #define S1G_CAP3_HT_DELAYED_BA BIT(1) 1421 - #define S1G_CAP3_MAX_MPDU_LEN BIT(2) 1422 - #define S1G_CAP3_MAX_AMPDU_LEN_EXP GENMASK(4, 3) 1423 - #define S1G_CAP3_MIN_MPDU_START GENMASK(7, 5) 1424 - 1425 - #define S1G_CAP4_UPLINK_SYNC BIT(0) 1426 - #define S1G_CAP4_DYNAMIC_AID BIT(1) 1427 - #define S1G_CAP4_BAT BIT(2) 1428 - #define S1G_CAP4_TIME_ADE BIT(3) 1429 - #define S1G_CAP4_NON_TIM BIT(4) 1430 - #define S1G_CAP4_GROUP_AID BIT(5) 1431 - #define S1G_CAP4_STA_TYPE GENMASK(7, 6) 1432 - 1433 - #define S1G_CAP5_CENT_AUTH_CONTROL BIT(0) 1434 - #define S1G_CAP5_DIST_AUTH_CONTROL BIT(1) 1435 - #define S1G_CAP5_AMSDU BIT(2) 1436 - #define S1G_CAP5_AMPDU BIT(3) 1437 - #define S1G_CAP5_ASYMMETRIC_BA BIT(4) 1438 - #define S1G_CAP5_FLOW_CONTROL BIT(5) 1439 - #define S1G_CAP5_SECTORIZED_BEAM GENMASK(7, 6) 1440 - 1441 - #define S1G_CAP6_OBSS_MITIGATION BIT(0) 1442 - #define S1G_CAP6_FRAGMENT_BA BIT(1) 1443 - #define S1G_CAP6_NDP_PS_POLL BIT(2) 1444 - #define S1G_CAP6_RAW_OPERATION BIT(3) 1445 - #define S1G_CAP6_PAGE_SLICING BIT(4) 1446 - #define S1G_CAP6_TXOP_SHARING_IMP_ACK BIT(5) 1447 - #define S1G_CAP6_VHT_LINK_ADAPT GENMASK(7, 6) 1448 - 1449 - #define S1G_CAP7_TACK_AS_PS_POLL BIT(0) 1450 - #define S1G_CAP7_DUP_1MHZ BIT(1) 1451 - #define S1G_CAP7_MCS_NEGOTIATION BIT(2) 1452 - #define S1G_CAP7_1MHZ_CTL_RESPONSE_PREAMBLE BIT(3) 1453 - #define S1G_CAP7_NDP_BFING_REPORT_POLL BIT(4) 1454 - #define S1G_CAP7_UNSOLICITED_DYN_AID BIT(5) 1455 - #define S1G_CAP7_SECTOR_TRAINING_OPERATION BIT(6) 1456 - #define S1G_CAP7_TEMP_PS_MODE_SWITCH BIT(7) 1457 - 1458 - #define S1G_CAP8_TWT_GROUPING BIT(0) 1459 - #define S1G_CAP8_BDT BIT(1) 1460 - #define S1G_CAP8_COLOR GENMASK(4, 2) 1461 - #define S1G_CAP8_TWT_REQUEST BIT(5) 1462 - #define S1G_CAP8_TWT_RESPOND BIT(6) 1463 - #define S1G_CAP8_PV1_FRAME BIT(7) 1464 - 1465 - #define S1G_CAP9_LINK_ADAPT_PER_CONTROL_RESPONSE BIT(0) 1466 - 1467 - #define S1G_OPER_CH_WIDTH_PRIMARY BIT(0) 1468 - #define S1G_OPER_CH_WIDTH_OPER GENMASK(4, 1) 1469 - #define S1G_OPER_CH_PRIMARY_LOCATION BIT(5) 1470 - 1471 - #define S1G_2M_PRIMARY_LOCATION_LOWER 0 1472 - #define S1G_2M_PRIMARY_LOCATION_UPPER 1 1473 - 1474 - #define LISTEN_INT_USF GENMASK(15, 14) 1475 - #define LISTEN_INT_UI GENMASK(13, 0) 1476 - 1477 - #define IEEE80211_MAX_USF FIELD_MAX(LISTEN_INT_USF) 1478 - #define IEEE80211_MAX_UI FIELD_MAX(LISTEN_INT_UI) 1479 1569 1480 1570 /* Authentication algorithms */ 1481 1571 #define WLAN_AUTH_OPEN 0 ··· 1913 2187 WLAN_KEY_LEN_BIP_CMAC_256 = 32, 1914 2188 WLAN_KEY_LEN_BIP_GMAC_128 = 16, 1915 2189 WLAN_KEY_LEN_BIP_GMAC_256 = 32, 1916 - }; 1917 - 1918 - enum ieee80211_s1g_actioncode { 1919 - WLAN_S1G_AID_SWITCH_REQUEST, 1920 - WLAN_S1G_AID_SWITCH_RESPONSE, 1921 - WLAN_S1G_SYNC_CONTROL, 1922 - WLAN_S1G_STA_INFO_ANNOUNCE, 1923 - WLAN_S1G_EDCA_PARAM_SET, 1924 - WLAN_S1G_EL_OPERATION, 1925 - WLAN_S1G_TWT_SETUP, 1926 - WLAN_S1G_TWT_TEARDOWN, 1927 - WLAN_S1G_SECT_GROUP_ID_LIST, 1928 - WLAN_S1G_SECT_ID_FEEDBACK, 1929 - WLAN_S1G_TWT_INFORMATION = 11, 1930 2190 }; 1931 2191 1932 2192 /* Radio measurement action codes as defined in IEEE 802.11-2024 - Table 9-470 */ ··· 2589 2877 return !!(tim->virtual_map[index] & mask); 2590 2878 } 2591 2879 2592 - struct s1g_tim_aid { 2593 - u16 aid; 2594 - u8 target_blk; /* Target block index */ 2595 - u8 target_subblk; /* Target subblock index */ 2596 - u8 target_subblk_bit; /* Target subblock bit */ 2597 - }; 2598 - 2599 - struct s1g_tim_enc_block { 2600 - u8 enc_mode; 2601 - bool inverse; 2602 - const u8 *ptr; 2603 - u8 len; 2604 - 2605 - /* 2606 - * For an OLB encoded block that spans multiple blocks, this 2607 - * is the offset into the span described by that encoded block. 2608 - */ 2609 - u8 olb_blk_offset; 2610 - }; 2611 - 2612 - /* 2613 - * Helper routines to quickly extract the length of an encoded block. Validation 2614 - * is also performed to ensure the length extracted lies within the TIM. 2615 - */ 2616 - 2617 - static inline int ieee80211_s1g_len_bitmap(const u8 *ptr, const u8 *end) 2618 - { 2619 - u8 blkmap; 2620 - u8 n_subblks; 2621 - 2622 - if (ptr >= end) 2623 - return -EINVAL; 2624 - 2625 - blkmap = *ptr; 2626 - n_subblks = hweight8(blkmap); 2627 - 2628 - if (ptr + 1 + n_subblks > end) 2629 - return -EINVAL; 2630 - 2631 - return 1 + n_subblks; 2632 - } 2633 - 2634 - static inline int ieee80211_s1g_len_single(const u8 *ptr, const u8 *end) 2635 - { 2636 - return (ptr + 1 > end) ? -EINVAL : 1; 2637 - } 2638 - 2639 - static inline int ieee80211_s1g_len_olb(const u8 *ptr, const u8 *end) 2640 - { 2641 - if (ptr >= end) 2642 - return -EINVAL; 2643 - 2644 - return (ptr + 1 + *ptr > end) ? -EINVAL : 1 + *ptr; 2645 - } 2646 - 2647 - /* 2648 - * Enumerate all encoded blocks until we find the encoded block that describes 2649 - * our target AID. OLB is a special case as a single encoded block can describe 2650 - * multiple blocks as a single encoded block. 2651 - */ 2652 - static inline int ieee80211_s1g_find_target_block(struct s1g_tim_enc_block *enc, 2653 - const struct s1g_tim_aid *aid, 2654 - const u8 *ptr, const u8 *end) 2655 - { 2656 - /* need at least block-control octet */ 2657 - while (ptr + 1 <= end) { 2658 - u8 ctrl = *ptr++; 2659 - u8 mode = ctrl & 0x03; 2660 - bool contains, inverse = ctrl & BIT(2); 2661 - u8 span, blk_off = ctrl >> 3; 2662 - int len; 2663 - 2664 - switch (mode) { 2665 - case IEEE80211_S1G_TIM_ENC_MODE_BLOCK: 2666 - len = ieee80211_s1g_len_bitmap(ptr, end); 2667 - contains = blk_off == aid->target_blk; 2668 - break; 2669 - case IEEE80211_S1G_TIM_ENC_MODE_SINGLE: 2670 - len = ieee80211_s1g_len_single(ptr, end); 2671 - contains = blk_off == aid->target_blk; 2672 - break; 2673 - case IEEE80211_S1G_TIM_ENC_MODE_OLB: 2674 - len = ieee80211_s1g_len_olb(ptr, end); 2675 - /* 2676 - * An OLB encoded block can describe more then one 2677 - * block, meaning an encoded OLB block can span more 2678 - * then a single block. 2679 - */ 2680 - if (len > 0) { 2681 - /* Minus one for the length octet */ 2682 - span = DIV_ROUND_UP(len - 1, 8); 2683 - /* 2684 - * Check if our target block lies within the 2685 - * block span described by this encoded block. 2686 - */ 2687 - contains = (aid->target_blk >= blk_off) && 2688 - (aid->target_blk < blk_off + span); 2689 - } 2690 - break; 2691 - default: 2692 - return -EOPNOTSUPP; 2693 - } 2694 - 2695 - if (len < 0) 2696 - return len; 2697 - 2698 - if (contains) { 2699 - enc->enc_mode = mode; 2700 - enc->inverse = inverse; 2701 - enc->ptr = ptr; 2702 - enc->len = (u8)len; 2703 - enc->olb_blk_offset = blk_off; 2704 - return 0; 2705 - } 2706 - 2707 - ptr += len; 2708 - } 2709 - 2710 - return -ENOENT; 2711 - } 2712 - 2713 - static inline bool ieee80211_s1g_parse_bitmap(struct s1g_tim_enc_block *enc, 2714 - struct s1g_tim_aid *aid) 2715 - { 2716 - const u8 *ptr = enc->ptr; 2717 - u8 blkmap = *ptr++; 2718 - 2719 - /* 2720 - * If our block bitmap does not contain a set bit that corresponds 2721 - * to our AID, it could mean a variety of things depending on if 2722 - * the encoding mode is inverted or not. 2723 - * 2724 - * 1. If inverted, it means the entire subblock is present and hence 2725 - * our AID has been set. 2726 - * 2. If not inverted, it means our subblock is not present and hence 2727 - * it is all zero meaning our AID is not set. 2728 - */ 2729 - if (!(blkmap & BIT(aid->target_subblk))) 2730 - return enc->inverse; 2731 - 2732 - /* 2733 - * Increment ptr by the number of set subblocks that appear before our 2734 - * target subblock. If our target subblock is 0, do nothing as ptr 2735 - * already points to our target subblock. 2736 - */ 2737 - if (aid->target_subblk) 2738 - ptr += hweight8(blkmap & GENMASK(aid->target_subblk - 1, 0)); 2739 - 2740 - return !!(*ptr & BIT(aid->target_subblk_bit)) ^ enc->inverse; 2741 - } 2742 - 2743 - static inline bool ieee80211_s1g_parse_single(struct s1g_tim_enc_block *enc, 2744 - struct s1g_tim_aid *aid) 2745 - { 2746 - /* 2747 - * Single AID mode describes, as the name suggests, a single AID 2748 - * within the block described by the encoded block. The octet 2749 - * contains the 6 LSBs of the AID described in the block. The other 2750 - * 2 bits are reserved. When inversed, every single AID described 2751 - * by the current block have buffered traffic except for the AID 2752 - * described in the single AID octet. 2753 - */ 2754 - return ((*enc->ptr & 0x3f) == (aid->aid & 0x3f)) ^ enc->inverse; 2755 - } 2756 - 2757 - static inline bool ieee80211_s1g_parse_olb(struct s1g_tim_enc_block *enc, 2758 - struct s1g_tim_aid *aid) 2759 - { 2760 - const u8 *ptr = enc->ptr; 2761 - u8 blk_len = *ptr++; 2762 - /* 2763 - * Given an OLB encoded block that describes multiple blocks, 2764 - * calculate the offset into the span. Then calculate the 2765 - * subblock location normally. 2766 - */ 2767 - u16 span_offset = aid->target_blk - enc->olb_blk_offset; 2768 - u16 subblk_idx = span_offset * 8 + aid->target_subblk; 2769 - 2770 - if (subblk_idx >= blk_len) 2771 - return enc->inverse; 2772 - 2773 - return !!(ptr[subblk_idx] & BIT(aid->target_subblk_bit)) ^ enc->inverse; 2774 - } 2775 - 2776 - /* 2777 - * An S1G PVB has 3 non optional encoding types, each that can be inverted. 2778 - * An S1G PVB is constructed with zero or more encoded block subfields. Each 2779 - * encoded block represents a single "block" of AIDs (64), and each encoded 2780 - * block can contain one of the 3 encoding types alongside a single bit for 2781 - * whether the bits should be inverted. 2782 - * 2783 - * As the standard makes no guarantee about the ordering of encoded blocks, 2784 - * we must parse every encoded block in the worst case scenario given an 2785 - * AID that lies within the last block. 2786 - */ 2787 - static inline bool ieee80211_s1g_check_tim(const struct ieee80211_tim_ie *tim, 2788 - u8 tim_len, u16 aid) 2789 - { 2790 - int err; 2791 - struct s1g_tim_aid target_aid; 2792 - struct s1g_tim_enc_block enc_blk; 2793 - 2794 - if (tim_len < 3) 2795 - return false; 2796 - 2797 - target_aid.aid = aid; 2798 - target_aid.target_blk = (aid >> 6) & 0x1f; 2799 - target_aid.target_subblk = (aid >> 3) & 0x7; 2800 - target_aid.target_subblk_bit = aid & 0x7; 2801 - 2802 - /* 2803 - * Find our AIDs target encoded block and fill &enc_blk with the 2804 - * encoded blocks information. If no entry is found or an error 2805 - * occurs return false. 2806 - */ 2807 - err = ieee80211_s1g_find_target_block(&enc_blk, &target_aid, 2808 - tim->virtual_map, 2809 - (const u8 *)tim + tim_len + 2); 2810 - if (err) 2811 - return false; 2812 - 2813 - switch (enc_blk.enc_mode) { 2814 - case IEEE80211_S1G_TIM_ENC_MODE_BLOCK: 2815 - return ieee80211_s1g_parse_bitmap(&enc_blk, &target_aid); 2816 - case IEEE80211_S1G_TIM_ENC_MODE_SINGLE: 2817 - return ieee80211_s1g_parse_single(&enc_blk, &target_aid); 2818 - case IEEE80211_S1G_TIM_ENC_MODE_OLB: 2819 - return ieee80211_s1g_parse_olb(&enc_blk, &target_aid); 2820 - default: 2821 - return false; 2822 - } 2823 - } 2824 - 2825 - /** 2826 - * ieee80211_check_tim - check if AID bit is set in TIM 2827 - * @tim: the TIM IE 2828 - * @tim_len: length of the TIM IE 2829 - * @aid: the AID to look for 2830 - * @s1g: whether the TIM is from an S1G PPDU 2831 - * Return: whether or not traffic is indicated in the TIM for the given AID 2832 - */ 2833 - static inline bool ieee80211_check_tim(const struct ieee80211_tim_ie *tim, 2834 - u8 tim_len, u16 aid, bool s1g) 2835 - { 2836 - return s1g ? ieee80211_s1g_check_tim(tim, tim_len, aid) : 2837 - __ieee80211_check_tim(tim, tim_len, aid); 2838 - } 2839 - 2840 2880 /** 2841 2881 * ieee80211_get_tdls_action - get TDLS action code 2842 2882 * @skb: the skb containing the frame, length will not be checked ··· 2720 3256 return true; 2721 3257 2722 3258 return false; 2723 - } 2724 - 2725 - /** 2726 - * ieee80211_is_s1g_short_beacon - check if frame is an S1G short beacon 2727 - * @fc: frame control bytes in little-endian byteorder 2728 - * @variable: pointer to the beacon frame elements 2729 - * @variable_len: length of the frame elements 2730 - * Return: whether or not the frame is an S1G short beacon. As per 2731 - * IEEE80211-2024 11.1.3.10.1, The S1G beacon compatibility element shall 2732 - * always be present as the first element in beacon frames generated at a 2733 - * TBTT (Target Beacon Transmission Time), so any frame not containing 2734 - * this element must have been generated at a TSBTT (Target Short Beacon 2735 - * Transmission Time) that is not a TBTT. Additionally, short beacons are 2736 - * prohibited from containing the S1G beacon compatibility element as per 2737 - * IEEE80211-2024 9.3.4.3 Table 9-76, so if we have an S1G beacon with 2738 - * either no elements or the first element is not the beacon compatibility 2739 - * element, we have a short beacon. 2740 - */ 2741 - static inline bool ieee80211_is_s1g_short_beacon(__le16 fc, const u8 *variable, 2742 - size_t variable_len) 2743 - { 2744 - if (!ieee80211_is_s1g_beacon(fc)) 2745 - return false; 2746 - 2747 - /* 2748 - * If the frame does not contain at least 1 element (this is perfectly 2749 - * valid in a short beacon) and is an S1G beacon, we have a short 2750 - * beacon. 2751 - */ 2752 - if (variable_len < 2) 2753 - return true; 2754 - 2755 - return variable[0] != WLAN_EID_S1G_BCN_COMPAT; 2756 3259 } 2757 3260 2758 3261 struct element { ··· 2877 3446 #include "ieee80211-he.h" 2878 3447 #include "ieee80211-eht.h" 2879 3448 #include "ieee80211-mesh.h" 3449 + #include "ieee80211-s1g.h" 3450 + 3451 + /** 3452 + * ieee80211_check_tim - check if AID bit is set in TIM 3453 + * @tim: the TIM IE 3454 + * @tim_len: length of the TIM IE 3455 + * @aid: the AID to look for 3456 + * @s1g: whether the TIM is from an S1G PPDU 3457 + * Return: whether or not traffic is indicated in the TIM for the given AID 3458 + */ 3459 + static inline bool ieee80211_check_tim(const struct ieee80211_tim_ie *tim, 3460 + u8 tim_len, u16 aid, bool s1g) 3461 + { 3462 + return s1g ? ieee80211_s1g_check_tim(tim, tim_len, aid) : 3463 + __ieee80211_check_tim(tim, tim_len, aid); 3464 + } 2880 3465 2881 3466 #endif /* LINUX_IEEE80211_H */