1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
|
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* IEEE 802.11 UHR definitions
*
* Copyright (c) 2025-2026 Intel Corporation
*/
#ifndef LINUX_IEEE80211_UHR_H
#define LINUX_IEEE80211_UHR_H
#include <linux/types.h>
#include <linux/bitfield.h>
#include <linux/if_ether.h>
#include "ieee80211-eht.h"
#define IEEE80211_UHR_OPER_PARAMS_DPS_ENA 0x0001
#define IEEE80211_UHR_OPER_PARAMS_NPCA_ENA 0x0002
#define IEEE80211_UHR_OPER_PARAMS_PEDCA_ENA 0x0004
#define IEEE80211_UHR_OPER_PARAMS_DBE_ENA 0x0008
#define IEEE80211_UHR_OPER_PARAMS_DBE_BW 0x0070
#define IEEE80211_UHR_OPER_PARAMS_DUO_PRES 0x0080
#define IEEE80211_UHR_OPER_PARAMS_DPS_PRES 0x0100
#define IEEE80211_UHR_OPER_PARAMS_NPCA_PRES 0x0200
#define IEEE80211_UHR_OPER_PARAMS_PEDCA_PRES 0x0400
#define IEEE80211_UHR_OPER_PARAMS_DBE_PRES 0x0800
struct ieee80211_uhr_operation {
__le16 params;
u8 basic_mcs_nss_set[4];
u8 variable[];
} __packed;
#define IEEE80211_UHR_NPCA_PARAMS_PRIMARY_CHAN_OFFS 0x0000000F
#define IEEE80211_UHR_NPCA_PARAMS_MIN_DUR_THRESH 0x000000F0
#define IEEE80211_UHR_NPCA_PARAMS_SWITCH_DELAY 0x00003F00
#define IEEE80211_UHR_NPCA_PARAMS_SWITCH_BACK_DELAY 0x000FC000
#define IEEE80211_UHR_NPCA_PARAMS_INIT_QSRC 0x00300000
#define IEEE80211_UHR_NPCA_PARAMS_MOPLEN 0x00400000
#define IEEE80211_UHR_NPCA_PARAMS_DIS_SUBCH_BMAP_PRES 0x00800000
/**
* struct ieee80211_uhr_npca_info - npca operation information
*
* This structure is the "NPCA Operation Parameters field format" of "UHR
* Operation Element" fields as described in P802.11bn_D1.3
* subclause 9.4.2.353. See Figure 9-aa4.
*
* Refer to IEEE80211_UHR_NPCA*
* @params:
* NPCA Primary Channel - NPCA primary channel
* NPCA_Min Duration Threshold - Minimum duration of inter-BSS activity
* NPCA Switching Delay -
* Time needed by an NPCA AP to switch from the
* BSS primary channel to the NPCA primary channel
* in the unit of 4 µs.
* NPCA Switching Back Delay -
* Time to switch from the NPCA primary channel
* to the BSS primary channel in the unit of 4 µs.
* NPCA Initial QSRC -
* Initialize the EDCAF QSRC[AC] variables
* when an NPCA STA in the BSS
* switches to NPCA operation.
* NPCA MOPLEN -
* Indicates which conditions can be used to
* initiate an NPCA operation,
* 1 -> both PHYLEN NPCA operation and MOPLEN
* NPCA operation are
* permitted in the BSS
* 0 -> only PHYLEN NPCA operation is allowed in the BSS.
* NPCA Disabled Subchannel Bitmap Present -
* Indicates whether the NPCA Disabled Subchannel
* Bitmap field is present. A 1 in this field indicates that
* the NPCA Disabled Subchannel Bitmap field is present
* @dis_subch_bmap:
* A bit in the bitmap that lies within the BSS bandwidth is set
* to 1 to indicate that the corresponding 20 MHz subchannel is
* punctured and is set to 0 to indicate that the corresponding
* 20 MHz subchannel is not punctured. A bit in the bitmap that
* falls outside of the BSS bandwidth is reserved. This field is
* present when the value of the NPCA Disabled Subchannel Bitmap
* Field Present field is equal to 1, and not present, otherwise
*/
struct ieee80211_uhr_npca_info {
__le32 params;
__le16 dis_subch_bmap[];
} __packed;
#define IEEE80211_UHR_DPS_PADDING_DELAY 0x0000003F
#define IEEE80211_UHR_DPS_TRANSITION_DELAY 0x00003F00
#define IEEE80211_UHR_DPS_ICF_REQUIRED 0x00010000
#define IEEE80211_UHR_DPS_PARAMETERIZED_FLAG 0x00020000
#define IEEE80211_UHR_DPS_LC_MODE_BW 0x001C0000
#define IEEE80211_UHR_DPS_LC_MODE_NSS 0x01E00000
#define IEEE80211_UHR_DPS_LC_MODE_MCS 0x1E000000
#define IEEE80211_UHR_DPS_MOBILE_AP_DPS_STATIC_HCM 0x20000000
/**
* struct ieee80211_uhr_dps_info - DPS operation information
*
* This structure is the "DPS Operation Parameter field" of "UHR
* Operation Element" fields as described in P802.11bn_D1.3
* subclause 9.4.1.87. See Figure 9-207u.
*
* Refer to IEEE80211_UHR_DPS*
* @params:
* DPS Padding Delay -
* Indicates the minimum MAC padding
* duration that is required by a DPS STA
* in an ICF to cause the STA to transition
* from the lower capability mode to the
* higher capability mode. The DPS Padding
* Delay field is in units of 4 µs.
* DPS Transition Delay -
* Indicates the amount of time required by a
* DPS STA to transition from the higher
* capability mode to the lower capability
* mode. The DPS Transition Delay field is in
* units of 4 µs.
* ICF Required -
* Indicates when the DPS assisting STA needs
* to transmit an ICF frame to the peer DPS STA
* before performing the frame exchanges with
* the peer DPS STA in a TXOP.
* 1 -> indicates that the transmission of the
* ICF frame to the peer DPS STA prior to
* any frame exchange is needed.
* 0 -> ICF transmission before the frame
* exchanges with the peer DPS STA is only
* needed if the frame exchange is performed
* in the HC mode.
* Parameterized Flag -
* 0 -> indicates that only 20 MHz, 1 SS,
* non-HT PPDU format with the data
* rate of 6, 12, and 24 Mb/s as the
* default mode are supported by the
* DPS STA in the LC mode
* 1 -> indicates that a bandwidth up to the
* bandwidth indicated in the LC Mode
* Bandwidth field, a number of spatial
* streams up to the NSS indicated in
* the LC Mode Nss field, and an MCS up
* to the MCS indicated in the LC Mode
* MCS fields are supported by the DPS
* STA in the LC mode as the
* parameterized mode.
* LC Mode Bandwidth -
* Indicates the maximum bandwidth supported
* by the STA in the LC mode.
* LC Mode NSS -
* Indicates the maximum number of the spatial
* streams supported by the STA in the LC mode.
* LC Mode MCS -
* Indicates the highest MCS supported by the STA
* in the LC mode.
* Mobile AP DPS Static HCM -
* 1 -> indicates that it will remain in the DPS high
* capability mode until the next TBTT on that
* link.
* 0 -> otherwise.
*/
struct ieee80211_uhr_dps_info {
__le32 params;
} __packed;
#define IEEE80211_UHR_DBE_OPER_BANDWIDTH 0x07
#define IEEE80211_UHR_DBE_OPER_DIS_SUBCHANNEL_BITMAP_PRES 0x08
/**
* enum ieee80211_uhr_dbe_oper_bw - DBE Operational Bandwidth
*
* Encoding for the DBE Operational Bandwidth field in the UHR Operation
* element (DBE Operation Parameters).
*
* @IEEE80211_UHR_DBE_OPER_BW_40: 40 MHz operational DBE bandwidth
* @IEEE80211_UHR_DBE_OPER_BW_80: 80 MHz operational DBE bandwidth
* @IEEE80211_UHR_DBE_OPER_BW_160: 160 MHz operational DBE bandwidth
* @IEEE80211_UHR_DBE_OPER_BW_320_1: 320-1 MHz operational DBE bandwidth
* @IEEE80211_UHR_DBE_OPER_BW_320_2: 320-2 MHz operational DBE bandwidth
*/
enum ieee80211_uhr_dbe_oper_bw {
IEEE80211_UHR_DBE_OPER_BW_40 = 1,
IEEE80211_UHR_DBE_OPER_BW_80 = 2,
IEEE80211_UHR_DBE_OPER_BW_160 = 3,
IEEE80211_UHR_DBE_OPER_BW_320_1 = 4,
IEEE80211_UHR_DBE_OPER_BW_320_2 = 5,
};
/**
* ieee80211_uhr_dbe_bw_mhz - get bandwidth in MHz from UHR DBE bandwidth
* @bw: UHR DBE bandwidth
*
* Return: the bandwidth in MHz, or -1 for invalid values
*/
static inline int ieee80211_uhr_dbe_bw_mhz(enum ieee80211_uhr_dbe_oper_bw bw)
{
switch (bw) {
case IEEE80211_UHR_DBE_OPER_BW_40:
return 40;
case IEEE80211_UHR_DBE_OPER_BW_80:
return 80;
case IEEE80211_UHR_DBE_OPER_BW_160:
return 160;
case IEEE80211_UHR_DBE_OPER_BW_320_1:
case IEEE80211_UHR_DBE_OPER_BW_320_2:
return 320;
default:
return -1;
}
}
/**
* struct ieee80211_uhr_dbe_info - DBE operation information
*
* This structure is the "DBE Operation Parameters field" of
* "UHR Operation Element" fields as described in P802.11bn_D1.3
* subclause 9.4.2.353. See Figure 9-aa6.
*
* Refer to IEEE80211_UHR_DBE_OPER*
* @params:
* B0-B2 - DBE Operational Bandwidth field, see
* "enum ieee80211_uhr_dbe_oper_bw" for values.
* Value 0 is reserved.
* Value 1 indicates 40 MHz operational DBE bandwidth.
* Value 2 indicates 80 MHz operational DBE bandwidth.
* Value 3 indicates 160 MHz operational DBE bandwidth.
* Value 4 indicates 320-1 MHz operational DBE bandwidth.
* Value 5 indicates 320-2 MHz operational DBE bandwidth.
* Values 6 to 7 are reserved.
* B3 - DBE Disabled Subchannel Bitmap Present.
* @dis_subch_bmap: DBE Disabled Subchannel Bitmap field is set to indicate
* disabled 20 MHz subchannels within the DBE Bandwidth.
*/
struct ieee80211_uhr_dbe_info {
u8 params;
__le16 dis_subch_bmap[];
} __packed;
#define IEEE80211_UHR_P_EDCA_ECWMIN 0x0F
#define IEEE80211_UHR_P_EDCA_ECWMAX 0xF0
#define IEEE80211_UHR_P_EDCA_AIFSN 0x000F
#define IEEE80211_UHR_P_EDCA_CW_DS 0x0030
#define IEEE80211_UHR_P_EDCA_PSRC_THRESHOLD 0x01C0
#define IEEE80211_UHR_P_EDCA_QSRC_THRESHOLD 0x0600
/**
* struct ieee80211_uhr_p_edca_info - P-EDCA operation information
*
* This structure is the "P-EDCA Operation Parameters field" of
* "UHR Operation Element" fields as described in P802.11bn_D1.3
* subclause 9.4.2.353. See Figure 9-aa5.
*
* Refer to IEEE80211_UHR_P_EDCA*
* @p_edca_ec: P-EDCA ECWmin and ECWmax.
* These fields indicate the CWmin and CWmax values used by a
* P-EDCA STA during P-EDCA contention.
* @params: AIFSN, CW DS, PSRC threshold, and QSRC threshold.
* - The AIFSN field indicates the AIFSN value used by a P-EDCA STA
* during P-EDCA contention.
* - The CW DS field indicates the value used for randomization of the
* transmission slot of the DS-CTS frame. The value 3 is reserved.
* The value 0 indicates that randomization is not enabled.
* - The P-EDCA PSRC threshold field indicates the maximum number of
* allowed consecutive DS-CTS transmissions. The value 0 and values
* greater than 4 are reserved.
* - The P-EDCA QSRC threshold field indicates the value of the
* QSRC[AC_VO] counter required to start P-EDCA contention. The
* value 0 is reserved.
*/
struct ieee80211_uhr_p_edca_info {
u8 p_edca_ec;
__le16 params;
} __packed;
static inline bool ieee80211_uhr_oper_size_ok(const u8 *data, u8 len)
{
const struct ieee80211_uhr_operation *oper = (const void *)data;
u8 needed = sizeof(*oper);
if (len < needed)
return false;
/* DPS Operation Parameters (fixed 4 bytes) */
if (oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_DPS_PRES)) {
needed += sizeof(struct ieee80211_uhr_dps_info);
if (len < needed)
return false;
}
/* NPCA Operation Parameters (fixed 4 bytes + optional 2 bytes) */
if (oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_NPCA_PRES)) {
const struct ieee80211_uhr_npca_info *npca =
(const void *)(data + needed);
needed += sizeof(*npca);
if (len < needed)
return false;
if (npca->params &
cpu_to_le32(IEEE80211_UHR_NPCA_PARAMS_DIS_SUBCH_BMAP_PRES)) {
needed += sizeof(npca->dis_subch_bmap[0]);
if (len < needed)
return false;
}
}
/* P-EDCA Operation Parameters (fixed 3 bytes) */
if (oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_PEDCA_PRES)) {
needed += sizeof(struct ieee80211_uhr_p_edca_info);
if (len < needed)
return false;
}
/* DBE Operation Parameters (fixed 1 byte + optional 2 bytes) */
if (oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_DBE_PRES)) {
const struct ieee80211_uhr_dbe_info *dbe =
(const void *)(data + needed);
needed += sizeof(*dbe);
if (len < needed)
return false;
if (dbe->params &
IEEE80211_UHR_DBE_OPER_DIS_SUBCHANNEL_BITMAP_PRES) {
needed += sizeof(dbe->dis_subch_bmap[0]);
if (len < needed)
return false;
}
}
return len >= needed;
}
/* Note: must ensure ieee80211_uhr_oper_size_ok(...) first */
static inline const struct ieee80211_uhr_npca_info *
ieee80211_uhr_npca_info(const struct ieee80211_uhr_operation *oper)
{
const u8 *pos = oper->variable;
if (!(oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_NPCA_PRES)))
return NULL;
if (!(oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_NPCA_ENA)))
return NULL;
if (oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_DPS_PRES))
pos += sizeof(struct ieee80211_uhr_dps_info);
return (const void *)pos;
}
static inline const __le16 *
ieee80211_uhr_npca_dis_subch_bitmap(const struct ieee80211_uhr_operation *oper)
{
const struct ieee80211_uhr_npca_info *npca;
npca = ieee80211_uhr_npca_info(oper);
if (!npca)
return NULL;
if (!(npca->params & cpu_to_le32(IEEE80211_UHR_NPCA_PARAMS_DIS_SUBCH_BMAP_PRES)))
return NULL;
return npca->dis_subch_bmap;
}
/* Note: must ensure ieee80211_uhr_oper_size_ok(...) first */
static inline const struct ieee80211_uhr_dbe_info *
ieee80211_uhr_oper_dbe_info(const struct ieee80211_uhr_operation *oper)
{
const u8 *pos = oper->variable;
if (!(oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_DBE_PRES)))
return NULL;
if (!(oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_DBE_ENA)))
return NULL;
if (oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_DPS_PRES))
pos += sizeof(struct ieee80211_uhr_dps_info);
if (oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_NPCA_PRES)) {
const struct ieee80211_uhr_npca_info *npca = (const void *)pos;
pos += sizeof(*npca);
if (npca->params & cpu_to_le32(IEEE80211_UHR_NPCA_PARAMS_DIS_SUBCH_BMAP_PRES))
pos += sizeof(npca->dis_subch_bmap[0]);
}
if (oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_PEDCA_PRES))
pos += sizeof(struct ieee80211_uhr_p_edca_info);
return (const void *)pos;
}
#define IEEE80211_UHR_MAC_CAP0_DPS_SUPP 0x01
#define IEEE80211_UHR_MAC_CAP0_DPS_ASSIST_SUPP 0x02
#define IEEE80211_UHR_MAC_CAP0_DPS_AP_STATIC_HCM_SUPP 0x04
#define IEEE80211_UHR_MAC_CAP0_NPCA_SUPP 0x10
#define IEEE80211_UHR_MAC_CAP0_ENH_BSR_SUPP 0x20
#define IEEE80211_UHR_MAC_CAP0_ADD_MAP_TID_SUPP 0x40
#define IEEE80211_UHR_MAC_CAP0_EOTSP_SUPP 0x80
#define IEEE80211_UHR_MAC_CAP1_DSO_SUPP 0x01
#define IEEE80211_UHR_MAC_CAP1_PEDCA_SUPP 0x02
#define IEEE80211_UHR_MAC_CAP1_DBE_SUPP 0x04
#define IEEE80211_UHR_MAC_CAP1_UL_LLI_SUPP 0x08
#define IEEE80211_UHR_MAC_CAP1_P2P_LLI_SUPP 0x10
#define IEEE80211_UHR_MAC_CAP1_PUO_SUPP 0x20
#define IEEE80211_UHR_MAC_CAP1_AP_PUO_SUPP 0x40
#define IEEE80211_UHR_MAC_CAP1_DUO_SUPP 0x80
#define IEEE80211_UHR_MAC_CAP2_OMC_UL_MU_DIS_RX_SUPP 0x01
#define IEEE80211_UHR_MAC_CAP2_AOM_SUPP 0x02
#define IEEE80211_UHR_MAC_CAP2_IFCS_LOC_SUPP 0x04
#define IEEE80211_UHR_MAC_CAP2_UHR_TRS_SUPP 0x08
#define IEEE80211_UHR_MAC_CAP2_TXSPG_SUPP 0x10
#define IEEE80211_UHR_MAC_CAP2_TXOP_RET_IN_TXSPG 0x20
#define IEEE80211_UHR_MAC_CAP2_UHR_OM_PU_TO_LOW 0xC0
#define IEEE80211_UHR_MAC_CAP3_UHR_OM_PU_TO_HIGH 0x03
#define IEEE80211_UHR_MAC_CAP3_PARAM_UPD_ADV_NOTIF_INTV 0x1C
#define IEEE80211_UHR_MAC_CAP3_UPD_IND_TIM_INTV_LOW 0xE0
#define IEEE80211_UHR_MAC_CAP4_UPD_IND_TIM_INTV_HIGH 0x03
#define IEEE80211_UHR_MAC_CAP4_BOUNDED_ESS 0x04
#define IEEE80211_UHR_MAC_CAP4_BTM_ASSURANCE 0x08
#define IEEE80211_UHR_MAC_CAP4_CO_BF_SUPP 0x10
#define IEEE80211_UHR_MAC_CAP_DBE_MAX_BW 0x07
#define IEEE80211_UHR_MAC_CAP_DBE_EHT_MCS_MAP_160_PRES 0x08
#define IEEE80211_UHR_MAC_CAP_DBE_EHT_MCS_MAP_320_PRES 0x10
struct ieee80211_uhr_cap_dbe {
u8 cap;
/* present 0, 1 or 2 times depending on _PRES bits */
struct ieee80211_eht_mcs_nss_supp_bw eht_mcs_map[];
} __packed;
/**
* enum ieee80211_uhr_dbe_max_supported_bw - DBE Maximum Supported Bandwidth
*
* As per spec P802.11bn_D1.3 "Table 9-bb5—Encoding of the DBE Maximum
* Supported Bandwidth field".
*
* @IEEE80211_UHR_DBE_MAX_BW_40: Indicates 40 MHz DBE max supported bw
* @IEEE80211_UHR_DBE_MAX_BW_80: Indicates 80 MHz DBE max supported bw
* @IEEE80211_UHR_DBE_MAX_BW_160: Indicates 160 MHz DBE max supported bw
* @IEEE80211_UHR_DBE_MAX_BW_320: Indicates 320 MHz DBE max supported bw
*/
enum ieee80211_uhr_dbe_max_supported_bw {
IEEE80211_UHR_DBE_MAX_BW_40 = 1,
IEEE80211_UHR_DBE_MAX_BW_80 = 2,
IEEE80211_UHR_DBE_MAX_BW_160 = 3,
IEEE80211_UHR_DBE_MAX_BW_320 = 4,
};
struct ieee80211_uhr_cap_mac {
u8 mac_cap[6];
} __packed;
#define IEEE80211_UHR_PHY_CAP_MAX_NSS_RX_SND_NDP_LE80 0x00000001
#define IEEE80211_UHR_PHY_CAP_MAX_NSS_RX_DL_MU_LE80 0x00000002
#define IEEE80211_UHR_PHY_CAP_MAX_NSS_RX_SND_NDP_160 0x00000004
#define IEEE80211_UHR_PHY_CAP_MAX_NSS_RX_DL_MU_160 0x00000008
#define IEEE80211_UHR_PHY_CAP_MAX_NSS_RX_SND_NDP_320 0x00000010
#define IEEE80211_UHR_PHY_CAP_MAX_NSS_RX_DL_MU_320 0x00000020
#define IEEE80211_UHR_PHY_CAP_ELR_TX 0x00000040
#define IEEE80211_UHR_PHY_CAP_ELR_RX 0x00000080
#define IEEE80211_UHR_PHY_CAP_PART_BW_DL_MUMIMO 0x00000100
#define IEEE80211_UHR_PHY_CAP_PART_BW_UL_MUMIMO 0x00000200
#define IEEE80211_UHR_PHY_CAP_MCS15 0x00000400
#define IEEE80211_UHR_PHY_CAP_2XLDPC_TX 0x00000800
#define IEEE80211_UHR_PHY_CAP_2XLDPC_RX 0x00001000
#define IEEE80211_UHR_PHY_CAP_UEQM_TX_MAX_NSS 0x00006000
#define IEEE80211_UHR_PHY_CAP_UEQM_RX_MAX_NSS 0x00018000
#define IEEE80211_UHR_PHY_CAP_CO_BF_JOINT_SOUNDING 0x00040000
#define IEEE80211_UHR_PHY_CAP_IM_TX 0x00080000
#define IEEE80211_UHR_PHY_CAP_IM_RX 0x00100000
#define IEEE80211_UHR_PHY_CAP_CO_SR_MODE_1 0x00200000
#define IEEE80211_UHR_PHY_CAP_CO_SR_MODE_2 0x00400000
#define IEEE80211_UHR_PHY_CAP_DRU_DBW_20_IN_PBW_20 0x00800000
#define IEEE80211_UHR_PHY_CAP_DRU_DBW_40_IN_PBW_40 0x01000000
#define IEEE80211_UHR_PHY_CAP_DRU_DBW_80_IN_PBW_80 0x02000000
#define IEEE80211_UHR_PHY_CAP_DRU_DBW_80_IN_PBW_160 0x04000000
#define IEEE80211_UHR_PHY_CAP_DRU_DBW_80_IN_PBW_320 0x08000000
#define IEEE80211_UHR_PHY_CAP_DRU_DBW_20_IN_PBW_GE80 0x10000000
#define IEEE80211_UHR_PHY_CAP_DRU_DBW_40_IN_PBW_GE80 0x20000000
#define IEEE80211_UHR_PHY_CAP_DRU_DBW_60_IN_PBW_GE80 0x40000000
#define IEEE80211_UHR_PHY_CAP_DRU_RRU_HYBRID_MODE 0x80000000
struct ieee80211_uhr_cap_phy {
__le32 cap;
u8 reserved;
} __packed;
struct ieee80211_uhr_cap {
struct ieee80211_uhr_cap_mac mac;
struct ieee80211_uhr_cap_phy phy;
/* optional DBE capabilities */
u8 variable[];
} __packed;
static inline bool ieee80211_uhr_capa_size_ok(const u8 *data, u8 len,
bool from_ap)
{
const struct ieee80211_uhr_cap *cap = (const void *)data;
size_t needed = sizeof(*cap);
if (len < needed)
return false;
/*
* A non-AP STA does not include the DBE Capability Parameters field
* in the UHR MAC Capabilities Information field.
*/
if (from_ap && cap->mac.mac_cap[1] & IEEE80211_UHR_MAC_CAP1_DBE_SUPP) {
const struct ieee80211_uhr_cap_dbe *dbe;
needed += sizeof(struct ieee80211_uhr_cap_dbe);
if (len < needed)
return false;
dbe = (const void *)cap->variable;
if (dbe->cap & IEEE80211_UHR_MAC_CAP_DBE_EHT_MCS_MAP_160_PRES)
needed += sizeof(dbe->eht_mcs_map[0]);
if (dbe->cap & IEEE80211_UHR_MAC_CAP_DBE_EHT_MCS_MAP_320_PRES)
needed += sizeof(dbe->eht_mcs_map[0]);
}
return len >= needed;
}
#define IEEE80211_UHR_OM_PU_TO_128TU 11
/**
* ieee80211_uhr_capa_get_om_pu_to_us - get OM parameter update timeout in usec
* @cap: the UHR capability element, size must be validated
*
* Return: the OM parameter update timeout in usec, or -1 if it's not valid
*/
static inline int
ieee80211_uhr_capa_get_om_pu_to_us(const struct ieee80211_uhr_cap *cap)
{
u8 timeout;
timeout = u8_get_bits(cap->mac.mac_cap[3],
IEEE80211_UHR_MAC_CAP3_UHR_OM_PU_TO_HIGH);
timeout <<= 2;
timeout |= u8_get_bits(cap->mac.mac_cap[2],
IEEE80211_UHR_MAC_CAP2_UHR_OM_PU_TO_LOW);
if (timeout > IEEE80211_UHR_OM_PU_TO_128TU)
return -1;
if (!timeout)
return 0;
return 128 << (timeout - 1);
}
/* only valid from AP, must check ieee80211_uhr_capa_size_ok(..., true) */
static inline const struct ieee80211_uhr_cap_dbe *
ieee80211_uhr_dbe_cap(const struct ieee80211_uhr_cap *cap)
{
if (!(cap->mac.mac_cap[1] & IEEE80211_UHR_MAC_CAP1_DBE_SUPP))
return NULL;
return (const void *)cap->variable;
}
#define IEEE80211_SMD_INFO_CAPA_DL_DATA_FWD 0x01
#define IEEE80211_SMD_INFO_CAPA_MAX_NUM_PREP 0x0E
#define IEEE80211_SMD_INFO_CAPA_TYPE 0x10
#define IEEE80211_SMD_INFO_CAPA_PTK_PER_AP_MLD 0x20
struct ieee80211_smd_info {
u8 id[ETH_ALEN];
u8 capa;
__le16 timeout;
} __packed;
enum ieee80211_protected_uhr_action {
IEEE80211_PROTECTED_UHR_ACTION_LINK_RECONFIG_REQUEST = 0,
IEEE80211_PROTECTED_UHR_ACTION_LINK_RECONFIG_RESPONSE = 1,
IEEE80211_PROTECTED_UHR_ACTION_LINK_RECONFIG_NOTIFY = 2,
};
enum ieee80211_uhr_link_reconfig_request_type {
IEEE80211_UHR_LINK_RECONFIG_REQUEST_ST_PREP = 0,
IEEE80211_UHR_LINK_RECONFIG_REQUEST_ST_EXEC = 1,
IEEE80211_UHR_LINK_RECONFIG_REQUEST_OMP_REQUEST = 3,
};
enum ieee80211_uhr_link_reconfig_response_type {
IEEE80211_UHR_LINK_RECONFIG_RESPONSE_ST_PREP = 0,
IEEE80211_UHR_LINK_RECONFIG_RESPONSE_ST_EXEC = 1,
};
enum ieee80211_uhr_link_reconfig_notify_type {
IEEE80211_UHR_LINK_RECONFIG_NOTIFY_DL_DRAINED = 2,
IEEE80211_UHR_LINK_RECONFIG_NOTIFY_OMP_RESPONSE = 3,
};
enum ieee80211_uhr_mode_change_control {
IEEE80211_UHR_MODE_CHANGE_CONTROL_MODE_ID = 0x003f,
IEEE80211_UHR_MODE_CHANGE_CONTROL_MODE_ENABLE = 0x0040,
IEEE80211_UHR_MODE_CHANGE_CONTROL_MODE_UPDATE = 0x0080,
IEEE80211_UHR_MODE_CHANGE_CONTROL_MODE_LENGTH = 0x0f00,
IEEE80211_UHR_MODE_CHANGE_CONTROL_MODE_SPECIFIC = 0xf000,
};
enum ieee80211_uhr_mode_change_mode_id {
IEEE80211_UHR_MODE_CHANGE_MODE_ID_DPS = 0,
IEEE80211_UHR_MODE_CHANGE_MODE_ID_NPCA = 1,
IEEE80211_UHR_MODE_CHANGE_MODE_ID_DUO = 2,
IEEE80211_UHR_MODE_CHANGE_MODE_ID_DSO = 3,
IEEE80211_UHR_MODE_CHANGE_MODE_ID_P_EDCA = 4,
IEEE80211_UHR_MODE_CHANGE_MODE_ID_ELR_RX = 5,
IEEE80211_UHR_MODE_CHANGE_MODE_ID_AOM = 6,
IEEE80211_UHR_MODE_CHANGE_MODE_ID_LLI = 7,
IEEE80211_UHR_MODE_CHANGE_MODE_ID_CO_BF = 8,
IEEE80211_UHR_MODE_CHANGE_MODE_ID_CO_SR = 9,
IEEE80211_UHR_MODE_CHANGE_MODE_ID_EMLSR = 10,
IEEE80211_UHR_MODE_CHANGE_MODE_ID_DBE = 11,
};
struct ieee80211_uhr_mode_change_tuple {
__le16 control;
u8 variable[];
} __packed;
static inline int
ieee80211_uhr_mode_change_tuple_size(const struct ieee80211_uhr_mode_change_tuple *tuple)
{
return sizeof(*tuple) +
le16_get_bits(tuple->control,
IEEE80211_UHR_MODE_CHANGE_CONTROL_MODE_LENGTH);
}
#define for_each_uhr_mode_change_tuple(data, len, tuple) \
for (tuple = (const void *)(data); \
(len) - ((const u8 *)tuple - (data)) >= sizeof(*tuple) && \
(len) - ((const u8 *)tuple - (data)) >= \
ieee80211_uhr_mode_change_tuple_size(tuple); \
tuple = (const void *)((const u8 *)tuple + \
ieee80211_uhr_mode_change_tuple_size(tuple)))
#endif /* LINUX_IEEE80211_UHR_H */
|