xref: /linux/include/linux/ieee80211-s1g.h (revision 7bbf6d15e935abbb3d604c1fa157350e84a26f98)
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 */
576