Coverage Report

Created: 2026-02-26 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hostap/src/common/ieee802_11_common.c
Line
Count
Source
1
/*
2
 * IEEE 802.11 Common routines
3
 * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
4
 *
5
 * This software may be distributed under the terms of the BSD license.
6
 * See README for more details.
7
 */
8
9
#include "includes.h"
10
11
#include "common.h"
12
#include "defs.h"
13
#include "wpa_common.h"
14
#include "drivers/driver.h"
15
#include "qca-vendor.h"
16
#include "ieee802_11_defs.h"
17
#include "ieee802_11_common.h"
18
19
20
static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
21
              struct ieee802_11_elems *elems,
22
              int show_errors)
23
0
{
24
0
  unsigned int oui;
25
26
  /* first 3 bytes in vendor specific information element are the IEEE
27
   * OUI of the vendor. The following byte is used a vendor specific
28
   * sub-type. */
29
0
  if (elen < 4) {
30
0
    if (show_errors) {
31
0
      wpa_printf(MSG_MSGDUMP, "short vendor specific "
32
0
           "information element ignored (len=%lu)",
33
0
           (unsigned long) elen);
34
0
    }
35
0
    return -1;
36
0
  }
37
38
0
  oui = WPA_GET_BE24(pos);
39
0
  switch (oui) {
40
0
  case OUI_MICROSOFT:
41
    /* Microsoft/Wi-Fi information elements are further typed and
42
     * subtyped */
43
0
    switch (pos[3]) {
44
0
    case 1:
45
      /* Microsoft OUI (00:50:F2) with OUI Type 1:
46
       * real WPA information element */
47
0
      elems->wpa_ie = pos;
48
0
      elems->wpa_ie_len = elen;
49
0
      break;
50
0
    case WMM_OUI_TYPE:
51
      /* WMM information element */
52
0
      if (elen < 5) {
53
0
        wpa_printf(MSG_MSGDUMP, "short WMM "
54
0
             "information element ignored "
55
0
             "(len=%lu)",
56
0
             (unsigned long) elen);
57
0
        return -1;
58
0
      }
59
0
      switch (pos[4]) {
60
0
      case WMM_OUI_SUBTYPE_INFORMATION_ELEMENT:
61
0
      case WMM_OUI_SUBTYPE_PARAMETER_ELEMENT:
62
        /*
63
         * Share same pointer since only one of these
64
         * is used and they start with same data.
65
         * Length field can be used to distinguish the
66
         * IEs.
67
         */
68
0
        elems->wmm = pos;
69
0
        elems->wmm_len = elen;
70
0
        break;
71
0
      case WMM_OUI_SUBTYPE_TSPEC_ELEMENT:
72
0
        elems->wmm_tspec = pos;
73
0
        elems->wmm_tspec_len = elen;
74
0
        break;
75
0
      default:
76
0
        wpa_printf(MSG_EXCESSIVE, "unknown WMM "
77
0
             "information element ignored "
78
0
             "(subtype=%d len=%lu)",
79
0
             pos[4], (unsigned long) elen);
80
0
        return -1;
81
0
      }
82
0
      break;
83
0
    case 4:
84
      /* Wi-Fi Protected Setup (WPS) IE */
85
0
      elems->wps_ie = pos;
86
0
      elems->wps_ie_len = elen;
87
0
      break;
88
0
    default:
89
0
      wpa_printf(MSG_EXCESSIVE, "Unknown Microsoft "
90
0
           "information element ignored "
91
0
           "(type=%d len=%lu)",
92
0
           pos[3], (unsigned long) elen);
93
0
      return -1;
94
0
    }
95
0
    break;
96
97
0
  case OUI_WFA:
98
0
    switch (pos[3]) {
99
0
    case P2P_OUI_TYPE:
100
      /* Wi-Fi Alliance - P2P IE */
101
0
      elems->p2p = pos;
102
0
      elems->p2p_len = elen;
103
0
      break;
104
0
    case WFD_OUI_TYPE:
105
      /* Wi-Fi Alliance - WFD IE */
106
0
      elems->wfd = pos;
107
0
      elems->wfd_len = elen;
108
0
      break;
109
0
    case HS20_INDICATION_OUI_TYPE:
110
      /* Hotspot 2.0 */
111
0
      elems->hs20 = pos;
112
0
      elems->hs20_len = elen;
113
0
      break;
114
0
    case MBO_OUI_TYPE:
115
      /* MBO-OCE */
116
0
      elems->mbo = pos;
117
0
      elems->mbo_len = elen;
118
0
      break;
119
0
    case HS20_ROAMING_CONS_SEL_OUI_TYPE:
120
      /* Hotspot 2.0 Roaming Consortium Selection */
121
0
      elems->roaming_cons_sel = pos;
122
0
      elems->roaming_cons_sel_len = elen;
123
0
      break;
124
0
    case MULTI_AP_OUI_TYPE:
125
0
      elems->multi_ap = pos;
126
0
      elems->multi_ap_len = elen;
127
0
      break;
128
0
    case OWE_OUI_TYPE:
129
      /* OWE Transition Mode element */
130
0
      break;
131
0
    case DPP_CC_OUI_TYPE:
132
      /* DPP Configurator Connectivity element */
133
0
      break;
134
0
    case SAE_PK_OUI_TYPE:
135
0
      elems->sae_pk = pos + 4;
136
0
      elems->sae_pk_len = elen - 4;
137
0
      break;
138
0
    case WFA_CAPA_OUI_TYPE:
139
0
      elems->wfa_capab = pos + 4;
140
0
      elems->wfa_capab_len = elen - 4;
141
0
      break;
142
0
    case WFA_RSNE_OVERRIDE_OUI_TYPE:
143
0
      elems->rsne_override = pos;
144
0
      elems->rsne_override_len = elen;
145
0
      break;
146
0
    case WFA_RSNE_OVERRIDE_2_OUI_TYPE:
147
0
      elems->rsne_override_2 = pos;
148
0
      elems->rsne_override_2_len = elen;
149
0
      break;
150
0
    case WFA_RSNXE_OVERRIDE_OUI_TYPE:
151
0
      elems->rsnxe_override = pos;
152
0
      elems->rsnxe_override_len = elen;
153
0
      break;
154
0
    case WFA_RSN_SELECTION_OUI_TYPE:
155
0
      if (elen < 4 + 1) {
156
0
        wpa_printf(MSG_DEBUG,
157
0
             "Too short RSN Selection element ignored");
158
0
        return -1;
159
0
      }
160
0
      elems->rsn_selection = pos + 4;
161
0
      elems->rsn_selection_len = elen - 4;
162
0
      break;
163
0
    case P2P2_OUI_TYPE:
164
      /* Wi-Fi Alliance - P2P2 IE */
165
0
      elems->p2p2_ie = pos;
166
0
      elems->p2p2_ie_len = elen;
167
0
      break;
168
0
    case PR_OUI_TYPE:
169
      /* Wi-Fi Alliance - Proximity Ranging element */
170
0
      elems->proximity_ranging = pos;
171
0
      elems->proximity_ranging_len = elen;
172
0
      break;
173
0
    default:
174
0
      wpa_printf(MSG_MSGDUMP, "Unknown WFA "
175
0
           "information element ignored "
176
0
           "(type=%d len=%lu)",
177
0
           pos[3], (unsigned long) elen);
178
0
      return -1;
179
0
    }
180
0
    break;
181
182
0
  case OUI_BROADCOM:
183
0
    switch (pos[3]) {
184
0
    case VENDOR_HT_CAPAB_OUI_TYPE:
185
0
      elems->vendor_ht_cap = pos;
186
0
      elems->vendor_ht_cap_len = elen;
187
0
      break;
188
0
    case VENDOR_VHT_TYPE:
189
0
      if (elen > 4 &&
190
0
          (pos[4] == VENDOR_VHT_SUBTYPE ||
191
0
           pos[4] == VENDOR_VHT_SUBTYPE2)) {
192
0
        elems->vendor_vht = pos;
193
0
        elems->vendor_vht_len = elen;
194
0
      } else
195
0
        return -1;
196
0
      break;
197
0
    default:
198
0
      wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom "
199
0
           "information element ignored "
200
0
           "(type=%d len=%lu)",
201
0
           pos[3], (unsigned long) elen);
202
0
      return -1;
203
0
    }
204
0
    break;
205
206
0
  case OUI_QCA:
207
0
    switch (pos[3]) {
208
0
    case QCA_VENDOR_ELEM_P2P_PREF_CHAN_LIST:
209
0
      elems->pref_freq_list = pos;
210
0
      elems->pref_freq_list_len = elen;
211
0
      break;
212
0
    default:
213
0
      wpa_printf(MSG_EXCESSIVE,
214
0
           "Unknown QCA information element ignored (type=%d len=%lu)",
215
0
           pos[3], (unsigned long) elen);
216
0
      return -1;
217
0
    }
218
0
    break;
219
220
0
  default:
221
0
    wpa_printf(MSG_EXCESSIVE, "unknown vendor specific "
222
0
         "information element ignored (vendor OUI "
223
0
         "%02x:%02x:%02x len=%lu)",
224
0
         pos[0], pos[1], pos[2], (unsigned long) elen);
225
0
    return -1;
226
0
  }
227
228
0
  return 0;
229
0
}
230
231
232
static int ieee802_11_parse_mle(const u8 *pos, size_t elen, size_t **total_len,
233
        struct ieee802_11_elems *elems,
234
        int show_errors)
235
0
{
236
0
  u8 mle_type = pos[0] & MULTI_LINK_CONTROL_TYPE_MASK;
237
238
0
  switch (mle_type) {
239
0
  case MULTI_LINK_CONTROL_TYPE_BASIC:
240
0
    elems->basic_mle = pos;
241
0
    elems->basic_mle_len = elen;
242
0
    *total_len = &elems->basic_mle_len;
243
0
    break;
244
0
  case MULTI_LINK_CONTROL_TYPE_PROBE_REQ:
245
0
    elems->probe_req_mle = pos;
246
0
    elems->probe_req_mle_len = elen;
247
0
    *total_len = &elems->probe_req_mle_len;
248
0
    break;
249
0
  case MULTI_LINK_CONTROL_TYPE_RECONF:
250
0
    elems->reconf_mle = pos;
251
0
    elems->reconf_mle_len = elen;
252
0
    *total_len = &elems->reconf_mle_len;
253
0
    break;
254
0
  case MULTI_LINK_CONTROL_TYPE_TDLS:
255
0
    elems->tdls_mle = pos;
256
0
    elems->tdls_mle_len = elen;
257
0
    *total_len = &elems->tdls_mle_len;
258
0
    break;
259
0
  case MULTI_LINK_CONTROL_TYPE_PRIOR_ACCESS:
260
0
    elems->prior_access_mle = pos;
261
0
    elems->prior_access_mle_len = elen;
262
0
    *total_len = &elems->prior_access_mle_len;
263
0
    break;
264
0
  default:
265
0
    if (show_errors) {
266
0
      wpa_printf(MSG_MSGDUMP,
267
0
           "Unknown Multi-Link element type %u",
268
0
           mle_type);
269
0
    }
270
0
    return -1;
271
0
  }
272
273
0
  return 0;
274
0
}
275
276
277
static size_t ieee802_11_fragments_length(struct ieee802_11_elems *elems,
278
            const u8 *start, size_t len)
279
0
{
280
0
  const struct element *elem;
281
0
  size_t frags_len = 0;
282
283
0
  for_each_element(elem, start, len) {
284
0
    if (elem->id != WLAN_EID_FRAGMENT)
285
0
      break;
286
287
0
    frags_len += elem->datalen + 2;
288
0
    elems->num_frag_elems++;
289
0
  }
290
291
0
  return frags_len;
292
0
}
293
294
295
static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
296
              struct ieee802_11_elems *elems,
297
              const u8 *start, size_t len,
298
              int show_errors)
299
0
{
300
0
  u8 ext_id;
301
0
  size_t *total_len = NULL;
302
303
0
  if (elen < 1) {
304
0
    if (show_errors) {
305
0
      wpa_printf(MSG_MSGDUMP,
306
0
           "short information element (Ext)");
307
0
    }
308
0
    return -1;
309
0
  }
310
311
0
  ext_id = *pos++;
312
0
  elen--;
313
314
0
  switch (ext_id) {
315
0
  case WLAN_EID_EXT_ASSOC_DELAY_INFO:
316
0
    if (elen != 1)
317
0
      break;
318
0
    elems->assoc_delay_info = pos;
319
0
    break;
320
0
  case WLAN_EID_EXT_FILS_REQ_PARAMS:
321
0
    if (elen < 3)
322
0
      break;
323
0
    elems->fils_req_params = pos;
324
0
    elems->fils_req_params_len = elen;
325
0
    break;
326
0
  case WLAN_EID_EXT_FILS_KEY_CONFIRM:
327
0
    elems->fils_key_confirm = pos;
328
0
    elems->fils_key_confirm_len = elen;
329
0
    break;
330
0
  case WLAN_EID_EXT_FILS_SESSION:
331
0
    if (elen != FILS_SESSION_LEN)
332
0
      break;
333
0
    elems->fils_session = pos;
334
0
    break;
335
0
  case WLAN_EID_EXT_FILS_HLP_CONTAINER:
336
0
    if (elen < 2 * ETH_ALEN)
337
0
      break;
338
0
    elems->fils_hlp = pos;
339
0
    elems->fils_hlp_len = elen;
340
0
    total_len = &elems->fils_hlp_len;
341
0
    break;
342
0
  case WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN:
343
0
    if (elen < 1)
344
0
      break;
345
0
    elems->fils_ip_addr_assign = pos;
346
0
    elems->fils_ip_addr_assign_len = elen;
347
0
    break;
348
0
  case WLAN_EID_EXT_KEY_DELIVERY:
349
0
    if (elen < WPA_KEY_RSC_LEN)
350
0
      break;
351
0
    elems->key_delivery = pos;
352
0
    elems->key_delivery_len = elen;
353
0
    break;
354
0
  case WLAN_EID_EXT_WRAPPED_DATA:
355
0
    elems->wrapped_data = pos;
356
0
    elems->wrapped_data_len = elen;
357
0
    total_len = &elems->wrapped_data_len;
358
0
    break;
359
0
  case WLAN_EID_EXT_FILS_PUBLIC_KEY:
360
0
    if (elen < 1)
361
0
      break;
362
0
    elems->fils_pk = pos;
363
0
    elems->fils_pk_len = elen;
364
0
    break;
365
0
  case WLAN_EID_EXT_NONCE:
366
0
    if (elen != NONCE_LEN)
367
0
      break;
368
0
    elems->nonce = pos;
369
0
    break;
370
0
  case WLAN_EID_EXT_OWE_DH_PARAM:
371
0
    if (elen < 2)
372
0
      break;
373
0
    elems->owe_dh = pos;
374
0
    elems->owe_dh_len = elen;
375
0
    break;
376
0
  case WLAN_EID_EXT_PASSWORD_IDENTIFIER:
377
0
    elems->password_id = pos;
378
0
    elems->password_id_len = elen;
379
0
    break;
380
0
  case WLAN_EID_EXT_HE_CAPABILITIES:
381
0
    if (elen < HE_CAPABILITIES_ELEM_MIN_LEN)
382
0
      break;
383
0
    elems->he_capabilities = pos;
384
0
    elems->he_capabilities_len = elen;
385
0
    break;
386
0
  case WLAN_EID_EXT_HE_OPERATION:
387
0
    if (elen < HE_OPERATION_ELEM_MIN_LEN)
388
0
      break;
389
0
    elems->he_operation = pos;
390
0
    elems->he_operation_len = elen;
391
0
    break;
392
0
  case WLAN_EID_EXT_OCV_OCI:
393
0
    elems->oci = pos;
394
0
    elems->oci_len = elen;
395
0
    break;
396
0
  case WLAN_EID_EXT_SHORT_SSID_LIST:
397
0
    elems->short_ssid_list = pos;
398
0
    elems->short_ssid_list_len = elen;
399
0
    break;
400
0
  case WLAN_EID_EXT_HE_6GHZ_BAND_CAP:
401
0
    if (elen < sizeof(struct ieee80211_he_6ghz_band_cap))
402
0
      break;
403
0
    elems->he_6ghz_band_cap = pos;
404
0
    break;
405
0
  case WLAN_EID_EXT_PASN_PARAMS:
406
0
    elems->pasn_params = pos;
407
0
    elems->pasn_params_len = elen;
408
0
    break;
409
0
  case WLAN_EID_EXT_EHT_CAPABILITIES:
410
0
    if (elen < EHT_CAPABILITIES_ELEM_MIN_LEN)
411
0
      break;
412
0
    elems->eht_capabilities = pos;
413
0
    elems->eht_capabilities_len = elen;
414
0
    break;
415
0
  case WLAN_EID_EXT_EHT_OPERATION:
416
0
    if (elen < EHT_OPERATION_ELEM_MIN_LEN)
417
0
      break;
418
0
    elems->eht_operation = pos;
419
0
    elems->eht_operation_len = elen;
420
0
    break;
421
0
  case WLAN_EID_EXT_MULTI_LINK:
422
0
    if (elen < 2)
423
0
      break;
424
0
    if (ieee802_11_parse_mle(pos, elen, &total_len, elems,
425
0
           show_errors))
426
0
      return -1;
427
0
    break;
428
0
  case WLAN_EID_EXT_KNOWN_BSSID:
429
0
    elems->mbssid_known_bss = pos;
430
0
    elems->mbssid_known_bss_len = elen;
431
0
    break;
432
0
  case WLAN_EID_EXT_PASN_ENCRYPTED_DATA:
433
0
    elems->pasn_encrypted_data = pos;
434
0
    elems->pasn_encrypted_data_len = elen;
435
0
    break;
436
0
  default:
437
0
    if (show_errors) {
438
0
      wpa_printf(MSG_MSGDUMP,
439
0
           "IEEE 802.11 element parsing ignored unknown element extension (ext_id=%u elen=%u)",
440
0
           ext_id, (unsigned int) elen);
441
0
    }
442
0
    return -1;
443
0
  }
444
445
0
  if (elen == 254 && total_len)
446
0
    *total_len += ieee802_11_fragments_length(
447
0
      elems, pos + elen, (start + len) - (pos + elen));
448
449
0
  return 0;
450
0
}
451
452
453
static ParseRes __ieee802_11_parse_elems(const u8 *start, size_t len,
454
           struct ieee802_11_elems *elems,
455
           int show_errors)
456
0
{
457
0
  const struct element *elem;
458
0
  int unknown = 0;
459
460
0
  if (!start)
461
0
    return ParseOK;
462
463
0
  for_each_element(elem, start, len) {
464
0
    u8 id = elem->id, elen = elem->datalen;
465
0
    const u8 *pos = elem->data;
466
0
    size_t *total_len = NULL;
467
468
0
    if (id == WLAN_EID_FRAGMENT && elems->num_frag_elems > 0) {
469
0
      elems->num_frag_elems--;
470
0
      continue;
471
0
    }
472
0
    elems->num_frag_elems = 0;
473
474
0
    switch (id) {
475
0
    case WLAN_EID_SSID:
476
0
      if (elen > SSID_MAX_LEN) {
477
0
        wpa_printf(MSG_DEBUG,
478
0
             "Ignored too long SSID element (elen=%u)",
479
0
             elen);
480
0
        break;
481
0
      }
482
0
      if (elems->ssid) {
483
0
        wpa_printf(MSG_MSGDUMP,
484
0
             "Ignored duplicated SSID element");
485
0
        break;
486
0
      }
487
0
      elems->ssid = pos;
488
0
      elems->ssid_len = elen;
489
0
      break;
490
0
    case WLAN_EID_SUPP_RATES:
491
0
      elems->supp_rates = pos;
492
0
      elems->supp_rates_len = elen;
493
0
      break;
494
0
    case WLAN_EID_DS_PARAMS:
495
0
      if (elen < 1)
496
0
        break;
497
0
      elems->ds_params = pos;
498
0
      break;
499
0
    case WLAN_EID_CF_PARAMS:
500
0
    case WLAN_EID_TIM:
501
0
      break;
502
0
    case WLAN_EID_CHALLENGE:
503
0
      elems->challenge = pos;
504
0
      elems->challenge_len = elen;
505
0
      break;
506
0
    case WLAN_EID_ERP_INFO:
507
0
      if (elen < 1)
508
0
        break;
509
0
      elems->erp_info = pos;
510
0
      break;
511
0
    case WLAN_EID_EXT_SUPP_RATES:
512
0
      elems->ext_supp_rates = pos;
513
0
      elems->ext_supp_rates_len = elen;
514
0
      break;
515
0
    case WLAN_EID_VENDOR_SPECIFIC:
516
0
      if (ieee802_11_parse_vendor_specific(pos, elen,
517
0
                   elems,
518
0
                   show_errors))
519
0
        unknown++;
520
0
      break;
521
0
    case WLAN_EID_RSN:
522
0
      elems->rsn_ie = pos;
523
0
      elems->rsn_ie_len = elen;
524
0
      break;
525
0
    case WLAN_EID_RSNX:
526
0
      elems->rsnxe = pos;
527
0
      elems->rsnxe_len = elen;
528
0
      break;
529
0
    case WLAN_EID_PWR_CAPABILITY:
530
0
      if (elen < 2)
531
0
        break;
532
0
      elems->power_capab = pos;
533
0
      elems->power_capab_len = elen;
534
0
      break;
535
0
    case WLAN_EID_SUPPORTED_CHANNELS:
536
0
      elems->supp_channels = pos;
537
0
      elems->supp_channels_len = elen;
538
0
      break;
539
0
    case WLAN_EID_MOBILITY_DOMAIN:
540
0
      if (elen < sizeof(struct rsn_mdie))
541
0
        break;
542
0
      elems->mdie = pos;
543
0
      elems->mdie_len = elen;
544
0
      break;
545
0
    case WLAN_EID_FAST_BSS_TRANSITION:
546
0
      if (elen < sizeof(struct rsn_ftie))
547
0
        break;
548
0
      elems->ftie = pos;
549
0
      elems->ftie_len = elen;
550
0
      elems->fte_defrag_len = elen;
551
0
      total_len = &elems->fte_defrag_len;
552
0
      break;
553
0
    case WLAN_EID_TIMEOUT_INTERVAL:
554
0
      if (elen != 5)
555
0
        break;
556
0
      elems->timeout_int = pos;
557
0
      break;
558
0
    case WLAN_EID_HT_CAP:
559
0
      if (elen < sizeof(struct ieee80211_ht_capabilities))
560
0
        break;
561
0
      elems->ht_capabilities = pos;
562
0
      break;
563
0
    case WLAN_EID_HT_OPERATION:
564
0
      if (elen < sizeof(struct ieee80211_ht_operation))
565
0
        break;
566
0
      elems->ht_operation = pos;
567
0
      break;
568
0
    case WLAN_EID_MESH_CONFIG:
569
0
      elems->mesh_config = pos;
570
0
      elems->mesh_config_len = elen;
571
0
      break;
572
0
    case WLAN_EID_MESH_ID:
573
0
      elems->mesh_id = pos;
574
0
      elems->mesh_id_len = elen;
575
0
      break;
576
0
    case WLAN_EID_PEER_MGMT:
577
0
      elems->peer_mgmt = pos;
578
0
      elems->peer_mgmt_len = elen;
579
0
      break;
580
0
    case WLAN_EID_VHT_CAP:
581
0
      if (elen < sizeof(struct ieee80211_vht_capabilities))
582
0
        break;
583
0
      elems->vht_capabilities = pos;
584
0
      break;
585
0
    case WLAN_EID_VHT_OPERATION:
586
0
      if (elen < sizeof(struct ieee80211_vht_operation))
587
0
        break;
588
0
      elems->vht_operation = pos;
589
0
      break;
590
0
    case WLAN_EID_OPERATING_MODE_NOTIFICATION:
591
0
      if (elen != 1)
592
0
        break;
593
0
      elems->opmode_notif = pos;
594
0
      break;
595
0
    case WLAN_EID_LINK_ID:
596
0
      if (elen < 18)
597
0
        break;
598
0
      elems->link_id = pos;
599
0
      break;
600
0
    case WLAN_EID_INTERWORKING:
601
0
      elems->interworking = pos;
602
0
      elems->interworking_len = elen;
603
0
      break;
604
0
    case WLAN_EID_QOS_MAP_SET:
605
0
      if (elen < 16)
606
0
        break;
607
0
      elems->qos_map_set = pos;
608
0
      elems->qos_map_set_len = elen;
609
0
      break;
610
0
    case WLAN_EID_EXT_CAPAB:
611
0
      elems->ext_capab = pos;
612
0
      elems->ext_capab_len = elen;
613
0
      break;
614
0
    case WLAN_EID_BSS_MAX_IDLE_PERIOD:
615
0
      if (elen < 3)
616
0
        break;
617
0
      elems->bss_max_idle_period = pos;
618
0
      break;
619
0
    case WLAN_EID_SSID_LIST:
620
0
      elems->ssid_list = pos;
621
0
      elems->ssid_list_len = elen;
622
0
      break;
623
0
    case WLAN_EID_AMPE:
624
0
      elems->ampe = pos;
625
0
      elems->ampe_len = elen;
626
0
      break;
627
0
    case WLAN_EID_MIC:
628
0
      elems->mic = pos;
629
0
      elems->mic_len = elen;
630
      /* after mic everything is encrypted, so stop. */
631
0
      goto done;
632
0
    case WLAN_EID_MULTI_BAND:
633
0
      if (elems->mb_ies.nof_ies >= MAX_NOF_MB_IES_SUPPORTED) {
634
0
        wpa_printf(MSG_MSGDUMP,
635
0
             "IEEE 802.11 element parse ignored MB IE (id=%d elen=%d)",
636
0
             id, elen);
637
0
        break;
638
0
      }
639
640
0
      elems->mb_ies.ies[elems->mb_ies.nof_ies].ie = pos;
641
0
      elems->mb_ies.ies[elems->mb_ies.nof_ies].ie_len = elen;
642
0
      elems->mb_ies.nof_ies++;
643
0
      break;
644
0
    case WLAN_EID_SUPPORTED_OPERATING_CLASSES:
645
0
      elems->supp_op_classes = pos;
646
0
      elems->supp_op_classes_len = elen;
647
0
      break;
648
0
    case WLAN_EID_RRM_ENABLED_CAPABILITIES:
649
0
      elems->rrm_enabled = pos;
650
0
      elems->rrm_enabled_len = elen;
651
0
      break;
652
0
    case WLAN_EID_MULTIPLE_BSSID:
653
0
      if (elen < 1)
654
0
        break;
655
0
      elems->mbssid = pos;
656
0
      elems->mbssid_len = elen;
657
0
      break;
658
0
    case WLAN_EID_CAG_NUMBER:
659
0
      elems->cag_number = pos;
660
0
      elems->cag_number_len = elen;
661
0
      break;
662
0
    case WLAN_EID_AP_CSN:
663
0
      if (elen < 1)
664
0
        break;
665
0
      elems->ap_csn = pos;
666
0
      break;
667
0
    case WLAN_EID_FILS_INDICATION:
668
0
      if (elen < 2)
669
0
        break;
670
0
      elems->fils_indic = pos;
671
0
      elems->fils_indic_len = elen;
672
0
      break;
673
0
    case WLAN_EID_DILS:
674
0
      if (elen < 2)
675
0
        break;
676
0
      elems->dils = pos;
677
0
      elems->dils_len = elen;
678
0
      break;
679
0
    case WLAN_EID_S1G_CAPABILITIES:
680
0
      if (elen < 15)
681
0
        break;
682
0
      elems->s1g_capab = pos;
683
0
      break;
684
0
    case WLAN_EID_FRAGMENT:
685
0
      wpa_printf(MSG_MSGDUMP,
686
0
           "Fragment without a valid last element - skip");
687
688
0
      break;
689
0
    case WLAN_EID_EXTENSION:
690
0
      if (ieee802_11_parse_extension(pos, elen, elems, start,
691
0
                   len, show_errors))
692
0
        unknown++;
693
0
      break;
694
0
    default:
695
0
      unknown++;
696
0
      if (!show_errors)
697
0
        break;
698
0
      wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse "
699
0
           "ignored unknown element (id=%d elen=%d)",
700
0
           id, elen);
701
0
      break;
702
0
    }
703
704
0
    if (elen == 255 && total_len)
705
0
      *total_len += ieee802_11_fragments_length(
706
0
        elems, pos + elen,
707
0
        (start + len) - (pos + elen));
708
709
0
  }
710
711
0
  if (!for_each_element_completed(elem, start, len)) {
712
0
    if (show_errors) {
713
0
      wpa_printf(MSG_DEBUG,
714
0
           "IEEE 802.11 element parse failed @%d",
715
0
           (int) (start + len - (const u8 *) elem));
716
0
      wpa_hexdump(MSG_MSGDUMP, "IEs", start, len);
717
0
    }
718
0
    return ParseFailed;
719
0
  }
720
721
0
done:
722
0
  return unknown ? ParseUnknown : ParseOK;
723
0
}
724
725
726
/**
727
 * ieee802_11_parse_elems - Parse information elements in management frames
728
 * @start: Pointer to the start of IEs
729
 * @len: Length of IE buffer in octets
730
 * @elems: Data structure for parsed elements
731
 * @show_errors: Whether to show parsing errors in debug log
732
 * Returns: Parsing result
733
 */
734
ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
735
        struct ieee802_11_elems *elems,
736
        int show_errors)
737
0
{
738
0
  os_memset(elems, 0, sizeof(*elems));
739
740
0
  return __ieee802_11_parse_elems(start, len, elems, show_errors);
741
0
}
742
743
744
/**
745
 * ieee802_11_elems_clear_ids - Clear the data for the given element IDs
746
 * @ids: Array of element IDs for which data should be cleared.
747
 * @num: The number of entries in the array
748
 */
749
void ieee802_11_elems_clear_ids(struct ieee802_11_elems *elems,
750
        const u8 *ids, size_t num)
751
0
{
752
0
  size_t i;
753
754
0
  for (i = 0; i < num; i++) {
755
0
    switch (ids[i]) {
756
0
    case WLAN_EID_SSID:
757
0
      elems->ssid = NULL;
758
0
      elems->ssid_len = 0;
759
0
      break;
760
0
    case WLAN_EID_SUPP_RATES:
761
0
      elems->supp_rates = NULL;
762
0
      elems->supp_rates_len = 0;
763
0
      break;
764
0
    case WLAN_EID_DS_PARAMS:
765
0
      elems->ds_params = NULL;
766
0
      break;
767
0
    case WLAN_EID_CHALLENGE:
768
0
      elems->challenge = NULL;
769
0
      elems->challenge_len = 0;
770
0
      break;
771
0
    case WLAN_EID_ERP_INFO:
772
0
      elems->erp_info = NULL;
773
0
      break;
774
0
    case WLAN_EID_EXT_SUPP_RATES:
775
0
      elems->ext_supp_rates = NULL;
776
0
      elems->ext_supp_rates_len = 0;
777
0
      break;
778
0
    case WLAN_EID_RSN:
779
0
      elems->rsn_ie = NULL;
780
0
      elems->rsn_ie_len = 0;
781
0
      break;
782
0
    case WLAN_EID_RSNX:
783
0
      elems->rsnxe = NULL;
784
0
      elems->rsnxe_len = 0;
785
0
      break;
786
0
    case WLAN_EID_PWR_CAPABILITY:
787
0
      elems->power_capab = NULL;
788
0
      elems->power_capab_len = 0;
789
0
      break;
790
0
    case WLAN_EID_SUPPORTED_CHANNELS:
791
0
      elems->supp_channels = NULL;
792
0
      elems->supp_channels_len = 0;
793
0
      break;
794
0
    case WLAN_EID_MOBILITY_DOMAIN:
795
0
      elems->mdie = NULL;
796
0
      elems->mdie_len = 0;
797
0
      break;
798
0
    case WLAN_EID_FAST_BSS_TRANSITION:
799
0
      elems->ftie = NULL;
800
0
      elems->ftie_len = 0;
801
0
      break;
802
0
    case WLAN_EID_TIMEOUT_INTERVAL:
803
0
      elems->timeout_int = NULL;
804
0
      break;
805
0
    case WLAN_EID_HT_CAP:
806
0
      elems->ht_capabilities = NULL;
807
0
      break;
808
0
    case WLAN_EID_HT_OPERATION:
809
0
      elems->ht_operation = NULL;
810
0
      break;
811
0
    case WLAN_EID_MESH_CONFIG:
812
0
      elems->mesh_config = NULL;
813
0
      elems->mesh_config_len = 0;
814
0
      break;
815
0
    case WLAN_EID_MESH_ID:
816
0
      elems->mesh_id = NULL;
817
0
      elems->mesh_id_len = 0;
818
0
      break;
819
0
    case WLAN_EID_PEER_MGMT:
820
0
      elems->peer_mgmt = NULL;
821
0
      elems->peer_mgmt_len = 0;
822
0
      break;
823
0
    case WLAN_EID_VHT_CAP:
824
0
      elems->vht_capabilities = NULL;
825
0
      break;
826
0
    case WLAN_EID_VHT_OPERATION:
827
0
      elems->vht_operation = NULL;
828
0
      break;
829
0
    case WLAN_EID_OPERATING_MODE_NOTIFICATION:
830
0
      elems->opmode_notif = NULL;
831
0
      break;
832
0
    case WLAN_EID_LINK_ID:
833
0
      elems->link_id = NULL;
834
0
      break;
835
0
    case WLAN_EID_INTERWORKING:
836
0
      elems->interworking = NULL;
837
0
      elems->interworking_len = 0;
838
0
      break;
839
0
    case WLAN_EID_QOS_MAP_SET:
840
0
      elems->qos_map_set = NULL;
841
0
      elems->qos_map_set_len = 0;
842
0
      break;
843
0
    case WLAN_EID_EXT_CAPAB:
844
0
      elems->ext_capab = NULL;
845
0
      elems->ext_capab_len = 0;
846
0
      break;
847
0
    case WLAN_EID_BSS_MAX_IDLE_PERIOD:
848
0
      elems->bss_max_idle_period = NULL;
849
0
      break;
850
0
    case WLAN_EID_SSID_LIST:
851
0
      elems->ssid_list = NULL;
852
0
      elems->ssid_list_len = 0;
853
0
      break;
854
0
    case WLAN_EID_AMPE:
855
0
      elems->ampe = NULL;
856
0
      elems->ampe_len = 0;
857
0
      break;
858
0
    case WLAN_EID_MIC:
859
0
      elems->mic = NULL;
860
0
      elems->mic_len = 0;
861
0
      break;
862
0
    case WLAN_EID_MULTI_BAND:
863
0
      os_memset(&elems->mb_ies, 0, sizeof(elems->mb_ies));
864
0
      elems->mb_ies.nof_ies = 0;
865
0
      break;
866
0
    case WLAN_EID_SUPPORTED_OPERATING_CLASSES:
867
0
      elems->supp_op_classes = NULL;
868
0
      elems->supp_op_classes_len = 0;
869
0
      break;
870
0
    case WLAN_EID_RRM_ENABLED_CAPABILITIES:
871
0
      elems->rrm_enabled = NULL;
872
0
      elems->rrm_enabled_len = 0;
873
0
      break;
874
0
    case WLAN_EID_CAG_NUMBER:
875
0
      elems->cag_number = NULL;
876
0
      elems->cag_number_len = 0;
877
0
      break;
878
0
    case WLAN_EID_AP_CSN:
879
0
      elems->ap_csn = NULL;
880
0
      break;
881
0
    case WLAN_EID_FILS_INDICATION:
882
0
      elems->fils_indic = NULL;
883
0
      elems->fils_indic_len = 0;
884
0
      break;
885
0
    case WLAN_EID_DILS:
886
0
      elems->dils = NULL;
887
0
      elems->dils_len = 0;
888
0
      break;
889
0
    case WLAN_EID_S1G_CAPABILITIES:
890
0
      elems->s1g_capab = NULL;
891
0
      break;
892
0
    }
893
0
  }
894
0
}
895
896
897
/**
898
 * ieee802_11_elems_clear_ext_ids - Clear the data for the given element
899
 * extension IDs
900
 * @ids: Array of element extension IDs for which data should be cleared.
901
 * @num: The number of entries in the array
902
 */
903
void ieee802_11_elems_clear_ext_ids(struct ieee802_11_elems *elems,
904
            const u8 *ids, size_t num)
905
0
{
906
0
  size_t i;
907
908
0
  for (i = 0; i < num; i++) {
909
0
    switch (ids[i]) {
910
0
    case WLAN_EID_EXT_ASSOC_DELAY_INFO:
911
0
      elems->assoc_delay_info = NULL;
912
0
      break;
913
0
    case WLAN_EID_EXT_FILS_REQ_PARAMS:
914
0
      elems->fils_req_params = NULL;
915
0
      elems->fils_req_params_len = 0;
916
0
      break;
917
0
    case WLAN_EID_EXT_FILS_KEY_CONFIRM:
918
0
      elems->fils_key_confirm = NULL;
919
0
      elems->fils_key_confirm_len = 0;
920
0
      break;
921
0
    case WLAN_EID_EXT_FILS_SESSION:
922
0
      elems->fils_session = NULL;
923
0
      break;
924
0
    case WLAN_EID_EXT_FILS_HLP_CONTAINER:
925
0
      elems->fils_hlp = NULL;
926
0
      elems->fils_hlp_len = 0;
927
0
      break;
928
0
    case WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN:
929
0
      elems->fils_ip_addr_assign = NULL;
930
0
      elems->fils_ip_addr_assign_len = 0;
931
0
      break;
932
0
    case WLAN_EID_EXT_KEY_DELIVERY:
933
0
      elems->key_delivery = NULL;
934
0
      elems->key_delivery_len = 0;
935
0
      break;
936
0
    case WLAN_EID_EXT_WRAPPED_DATA:
937
0
      elems->wrapped_data = NULL;
938
0
      elems->wrapped_data_len = 0;
939
0
      break;
940
0
    case WLAN_EID_EXT_FILS_PUBLIC_KEY:
941
0
      elems->fils_pk = NULL;
942
0
      elems->fils_pk_len = 0;
943
0
      break;
944
0
    case WLAN_EID_EXT_NONCE:
945
0
      elems->nonce = NULL;
946
0
      break;
947
0
    case WLAN_EID_EXT_OWE_DH_PARAM:
948
0
      elems->owe_dh = NULL;
949
0
      elems->owe_dh_len = 0;
950
0
      break;
951
0
    case WLAN_EID_EXT_PASSWORD_IDENTIFIER:
952
0
      elems->password_id = NULL;
953
0
      elems->password_id_len = 0;
954
0
      break;
955
0
    case WLAN_EID_EXT_HE_CAPABILITIES:
956
0
      elems->he_capabilities = NULL;
957
0
      elems->he_capabilities_len = 0;
958
0
      break;
959
0
    case WLAN_EID_EXT_HE_OPERATION:
960
0
      elems->he_operation = NULL;
961
0
      elems->he_operation_len = 0;
962
0
      break;
963
0
    case WLAN_EID_EXT_OCV_OCI:
964
0
      elems->oci = NULL;
965
0
      elems->oci_len = 0;
966
0
      break;
967
0
    case WLAN_EID_EXT_SHORT_SSID_LIST:
968
0
      elems->short_ssid_list = NULL;
969
0
      elems->short_ssid_list_len = 0;
970
0
      break;
971
0
    case WLAN_EID_EXT_HE_6GHZ_BAND_CAP:
972
0
      elems->he_6ghz_band_cap = NULL;
973
0
      break;
974
0
    case WLAN_EID_EXT_PASN_PARAMS:
975
0
      elems->pasn_params = NULL;
976
0
      elems->pasn_params_len = 0;
977
0
      break;
978
0
    case WLAN_EID_EXT_MULTI_LINK:
979
0
      elems->basic_mle = NULL;
980
0
      elems->probe_req_mle = NULL;
981
0
      elems->reconf_mle = NULL;
982
0
      elems->tdls_mle = NULL;
983
0
      elems->prior_access_mle = NULL;
984
985
0
      elems->basic_mle_len = 0;
986
0
      elems->probe_req_mle_len = 0;
987
0
      elems->reconf_mle_len = 0;
988
0
      elems->tdls_mle_len = 0;
989
0
      elems->prior_access_mle_len = 0;
990
0
      break;
991
0
    case WLAN_EID_EXT_EHT_CAPABILITIES:
992
0
      elems->eht_capabilities = NULL;
993
0
      elems->eht_capabilities_len = 0;
994
0
      break;
995
0
    case WLAN_EID_EXT_EHT_OPERATION:
996
0
      elems->eht_operation = NULL;
997
0
      elems->eht_operation_len = 0;
998
0
      break;
999
0
    }
1000
0
  }
1001
0
}
1002
1003
1004
static ParseRes ieee802_11_parse_link_profile(struct ieee802_11_elems *elems,
1005
                struct wpabuf *mlbuf,
1006
                u8 link_id, bool show_errors,
1007
                bool is_assoc_resp)
1008
0
{
1009
0
  const struct ieee80211_eht_ml *ml;
1010
0
  const u8 *pos;
1011
0
  ParseRes res = ParseFailed;
1012
0
  size_t len;
1013
1014
0
  pos = wpabuf_head(mlbuf);
1015
0
  len = wpabuf_len(mlbuf);
1016
1017
  /* Must have control and common info length */
1018
0
  if (len < sizeof(*ml) + 1 || len < sizeof(*ml) + pos[sizeof(*ml)])
1019
0
    goto out;
1020
1021
0
  ml = (const struct ieee80211_eht_ml *) pos;
1022
1023
  /* As we are interested with the Per-STA profile, ignore other types */
1024
0
  if ((le_to_host16(ml->ml_control) & MULTI_LINK_CONTROL_TYPE_MASK) !=
1025
0
       MULTI_LINK_CONTROL_TYPE_BASIC)
1026
0
    goto out;
1027
1028
  /* Skip the common info */
1029
0
  len -= sizeof(*ml) + pos[sizeof(*ml)];
1030
0
  pos += sizeof(*ml) + pos[sizeof(*ml)];
1031
1032
0
  while (len > 2) {
1033
0
    size_t sub_elem_len, sta_info_len;
1034
0
    u16 link_info_control;
1035
0
    const u8 *non_inherit;
1036
0
    int num_frag_subelems;
1037
1038
0
    num_frag_subelems =
1039
0
      ieee802_11_defrag_mle_subelem(mlbuf, pos,
1040
0
                  &sub_elem_len);
1041
0
    if (num_frag_subelems < 0) {
1042
0
      wpa_printf(MSG_DEBUG,
1043
0
           "MLD: Failed to parse MLE subelem");
1044
0
      goto out;
1045
0
    }
1046
0
    if ((size_t) num_frag_subelems * 2 > len)
1047
0
      goto out;
1048
0
    len -= num_frag_subelems * 2;
1049
1050
0
    wpa_printf(MSG_DEBUG,
1051
0
         "MLD: sub element: len=%zu, sub_elem_len=%zu, Fragment subelems=%u",
1052
0
         len, sub_elem_len, num_frag_subelems);
1053
1054
0
    if (2 + sub_elem_len > len) {
1055
0
      if (show_errors)
1056
0
        wpa_printf(MSG_DEBUG,
1057
0
             "MLD: error: len=%zu, sub_elem_len=%zu",
1058
0
             len, sub_elem_len);
1059
0
      goto out;
1060
0
    }
1061
1062
0
    if (*pos != 0) {
1063
0
      pos += 2 + sub_elem_len;
1064
0
      len -= 2 + sub_elem_len;
1065
0
      continue;
1066
0
    }
1067
1068
0
    if (sub_elem_len < 5) {
1069
0
      if (show_errors)
1070
0
        wpa_printf(MSG_DEBUG,
1071
0
             "MLD: error: sub_elem_len=%zu < 5",
1072
0
             sub_elem_len);
1073
0
      goto out;
1074
0
    }
1075
1076
0
    link_info_control = WPA_GET_LE16(pos + 2);
1077
0
    if ((link_info_control & BASIC_MLE_STA_CTRL_LINK_ID_MASK) !=
1078
0
        link_id) {
1079
0
      pos += 2 + sub_elem_len;
1080
0
      len -= 2 + sub_elem_len;
1081
0
      continue;
1082
0
    }
1083
1084
0
    sta_info_len = *(pos + 4);
1085
0
    if (sub_elem_len < sta_info_len + 3 || sta_info_len < 1) {
1086
0
      if (show_errors)
1087
0
        wpa_printf(MSG_DEBUG,
1088
0
             "MLD: error: sub_elem_len=%zu, sta_info_len=%zu",
1089
0
             sub_elem_len, sta_info_len);
1090
0
      goto out;
1091
0
    }
1092
1093
0
    pos += sta_info_len + 4;
1094
0
    sub_elem_len -= sta_info_len + 2;
1095
1096
0
    if (sub_elem_len < 2) {
1097
0
      if (show_errors)
1098
0
        wpa_printf(MSG_DEBUG,
1099
0
             "MLD: missing capability info");
1100
0
      goto out;
1101
0
    }
1102
1103
0
    pos += 2;
1104
0
    sub_elem_len -= 2;
1105
1106
    /* For association response, check status code */
1107
0
    if (is_assoc_resp) {
1108
0
      u16 status_code;
1109
1110
0
      if (sub_elem_len < 2) {
1111
0
        if (show_errors)
1112
0
          wpa_printf(MSG_DEBUG,
1113
0
               "MLD: missing status code");
1114
0
        goto out;
1115
0
      }
1116
1117
0
      status_code = WPA_GET_LE16(pos);
1118
0
      if (status_code != WLAN_STATUS_SUCCESS) {
1119
0
        wpa_printf(MSG_DEBUG,
1120
0
             "MLD: status code %u", status_code);
1121
0
        goto out;
1122
0
      }
1123
1124
0
      pos += 2;
1125
0
      sub_elem_len -= 2;
1126
0
    }
1127
1128
    /* Handle non-inheritance */
1129
0
    non_inherit = get_ie_ext(pos, sub_elem_len,
1130
0
           WLAN_EID_EXT_NON_INHERITANCE);
1131
0
    if (non_inherit && non_inherit[1] > 1) {
1132
0
      u8 non_inherit_len = non_inherit[1] - 1;
1133
1134
      /*
1135
       * Do not include the Non-Inheritance element when
1136
       * parsing below. It should be the last element in the
1137
       * subelement.
1138
       */
1139
0
      if (3U + non_inherit_len > sub_elem_len)
1140
0
        goto out;
1141
0
      sub_elem_len -= 3 + non_inherit_len;
1142
1143
      /* Skip the ID, length and extension ID */
1144
0
      non_inherit += 3;
1145
1146
0
      if (non_inherit_len < 1UL + non_inherit[0]) {
1147
0
        if (show_errors)
1148
0
          wpa_printf(MSG_DEBUG,
1149
0
               "MLD: Invalid inheritance");
1150
0
        goto out;
1151
0
      }
1152
1153
0
      ieee802_11_elems_clear_ids(elems, &non_inherit[1],
1154
0
               non_inherit[0]);
1155
1156
0
      non_inherit_len -= 1 + non_inherit[0];
1157
0
      non_inherit += 1 + non_inherit[0];
1158
1159
0
      if (non_inherit_len < 1UL ||
1160
0
          non_inherit_len < 1UL + non_inherit[0]) {
1161
0
        if (show_errors)
1162
0
          wpa_printf(MSG_DEBUG,
1163
0
               "MLD: Invalid inheritance");
1164
0
        goto out;
1165
0
      }
1166
1167
0
      ieee802_11_elems_clear_ext_ids(elems, &non_inherit[1],
1168
0
                   non_inherit[0]);
1169
0
    }
1170
1171
0
    wpa_printf(MSG_DEBUG, "MLD: link: sub_elem_len=%zu",
1172
0
         sub_elem_len);
1173
1174
0
    if (sub_elem_len)
1175
0
      res = __ieee802_11_parse_elems(pos, sub_elem_len,
1176
0
                   elems, show_errors);
1177
0
    else
1178
0
      res = ParseOK;
1179
0
    break;
1180
0
  }
1181
1182
0
out:
1183
0
  return res;
1184
0
}
1185
1186
1187
ParseRes ieee802_11_parse_link_assoc_req(struct ieee802_11_elems *elems,
1188
           struct wpabuf *mlbuf,
1189
           u8 link_id, bool show_errors)
1190
0
{
1191
0
  return ieee802_11_parse_link_profile(elems, mlbuf, link_id,
1192
0
               show_errors, false);
1193
0
}
1194
1195
1196
ParseRes ieee802_11_parse_link_assoc_resp(struct ieee802_11_elems *elems,
1197
          struct wpabuf *mlbuf,
1198
            u8 link_id, bool show_errors)
1199
0
{
1200
  /* ieee802_11_defrag_mle_subelem() handles subelement defragmentation
1201
   * in-place within mlbuf */
1202
0
  return ieee802_11_parse_link_profile(elems, mlbuf, link_id,
1203
0
               show_errors, true);
1204
0
}
1205
1206
1207
int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
1208
0
{
1209
0
  const struct element *elem;
1210
0
  int count = 0;
1211
1212
0
  if (ies == NULL)
1213
0
    return 0;
1214
1215
0
  for_each_element(elem, ies, ies_len)
1216
0
    count++;
1217
1218
0
  return count;
1219
0
}
1220
1221
1222
struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
1223
              u32 oui_type)
1224
0
{
1225
0
  struct wpabuf *buf;
1226
0
  const struct element *elem, *found = NULL;
1227
1228
0
  for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, ies_len) {
1229
0
    if (elem->datalen >= 4 &&
1230
0
        WPA_GET_BE32(elem->data) == oui_type) {
1231
0
      found = elem;
1232
0
      break;
1233
0
    }
1234
0
  }
1235
1236
0
  if (!found)
1237
0
    return NULL; /* No specified vendor IE found */
1238
1239
0
  buf = wpabuf_alloc(ies_len);
1240
0
  if (buf == NULL)
1241
0
    return NULL;
1242
1243
  /*
1244
   * There may be multiple vendor IEs in the message, so need to
1245
   * concatenate their data fields.
1246
   */
1247
0
  for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, ies_len) {
1248
0
    if (elem->datalen >= 4 && WPA_GET_BE32(elem->data) == oui_type)
1249
0
      wpabuf_put_data(buf, elem->data + 4, elem->datalen - 4);
1250
0
  }
1251
1252
0
  return buf;
1253
0
}
1254
1255
1256
const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
1257
0
{
1258
0
  u16 fc, type, stype;
1259
1260
  /*
1261
   * PS-Poll frames are 16 bytes. All other frames are
1262
   * 24 bytes or longer.
1263
   */
1264
0
  if (len < 16)
1265
0
    return NULL;
1266
1267
0
  fc = le_to_host16(hdr->frame_control);
1268
0
  type = WLAN_FC_GET_TYPE(fc);
1269
0
  stype = WLAN_FC_GET_STYPE(fc);
1270
1271
0
  switch (type) {
1272
0
  case WLAN_FC_TYPE_DATA:
1273
0
    if (len < 24)
1274
0
      return NULL;
1275
0
    switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
1276
0
    case WLAN_FC_FROMDS | WLAN_FC_TODS:
1277
0
    case WLAN_FC_TODS:
1278
0
      return hdr->addr1;
1279
0
    case WLAN_FC_FROMDS:
1280
0
      return hdr->addr2;
1281
0
    default:
1282
0
      return NULL;
1283
0
    }
1284
0
  case WLAN_FC_TYPE_CTRL:
1285
0
    if (stype != WLAN_FC_STYPE_PSPOLL)
1286
0
      return NULL;
1287
0
    return hdr->addr1;
1288
0
  case WLAN_FC_TYPE_MGMT:
1289
0
    return hdr->addr3;
1290
0
  default:
1291
0
    return NULL;
1292
0
  }
1293
0
}
1294
1295
1296
int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
1297
        const char *name, const char *val)
1298
0
{
1299
0
  int num, v;
1300
0
  const char *pos;
1301
0
  struct hostapd_wmm_ac_params *ac;
1302
1303
  /* skip 'wme_ac_' or 'wmm_ac_' prefix */
1304
0
  pos = name + 7;
1305
0
  if (os_strncmp(pos, "be_", 3) == 0) {
1306
0
    num = 0;
1307
0
    pos += 3;
1308
0
  } else if (os_strncmp(pos, "bk_", 3) == 0) {
1309
0
    num = 1;
1310
0
    pos += 3;
1311
0
  } else if (os_strncmp(pos, "vi_", 3) == 0) {
1312
0
    num = 2;
1313
0
    pos += 3;
1314
0
  } else if (os_strncmp(pos, "vo_", 3) == 0) {
1315
0
    num = 3;
1316
0
    pos += 3;
1317
0
  } else {
1318
0
    wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos);
1319
0
    return -1;
1320
0
  }
1321
1322
0
  ac = &wmm_ac_params[num];
1323
1324
0
  if (os_strcmp(pos, "aifs") == 0) {
1325
0
    v = atoi(val);
1326
0
    if (v < 1 || v > 255) {
1327
0
      wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v);
1328
0
      return -1;
1329
0
    }
1330
0
    ac->aifs = v;
1331
0
  } else if (os_strcmp(pos, "cwmin") == 0) {
1332
0
    v = atoi(val);
1333
0
    if (v < 0 || v > 15) {
1334
0
      wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v);
1335
0
      return -1;
1336
0
    }
1337
0
    ac->cwmin = v;
1338
0
  } else if (os_strcmp(pos, "cwmax") == 0) {
1339
0
    v = atoi(val);
1340
0
    if (v < 0 || v > 15) {
1341
0
      wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v);
1342
0
      return -1;
1343
0
    }
1344
0
    ac->cwmax = v;
1345
0
  } else if (os_strcmp(pos, "txop_limit") == 0) {
1346
0
    v = atoi(val);
1347
0
    if (v < 0 || v > 0xffff) {
1348
0
      wpa_printf(MSG_ERROR, "Invalid txop value %d", v);
1349
0
      return -1;
1350
0
    }
1351
0
    ac->txop_limit = v;
1352
0
  } else if (os_strcmp(pos, "acm") == 0) {
1353
0
    v = atoi(val);
1354
0
    if (v < 0 || v > 1) {
1355
0
      wpa_printf(MSG_ERROR, "Invalid acm value %d", v);
1356
0
      return -1;
1357
0
    }
1358
0
    ac->admission_control_mandatory = v;
1359
0
  } else {
1360
0
    wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos);
1361
0
    return -1;
1362
0
  }
1363
1364
0
  return 0;
1365
0
}
1366
1367
1368
/* convert floats with one decimal place to value*10 int, i.e.,
1369
 * "1.5" will return 15
1370
 */
1371
static int hostapd_config_read_int10(const char *value)
1372
0
{
1373
0
  int i, d;
1374
0
  char *pos;
1375
1376
0
  i = atoi(value);
1377
0
  pos = os_strchr(value, '.');
1378
0
  d = 0;
1379
0
  if (pos) {
1380
0
    pos++;
1381
0
    if (*pos >= '0' && *pos <= '9')
1382
0
      d = *pos - '0';
1383
0
  }
1384
1385
0
  return i * 10 + d;
1386
0
}
1387
1388
1389
static int valid_cw(int cw)
1390
0
{
1391
0
  return (cw == 1 || cw == 3 || cw == 7 || cw == 15 || cw == 31 ||
1392
0
    cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023 ||
1393
0
    cw == 2047 || cw == 4095 || cw == 8191 || cw == 16383 ||
1394
0
    cw == 32767);
1395
0
}
1396
1397
1398
int hostapd_config_tx_queue(struct hostapd_tx_queue_params tx_queue[],
1399
          const char *name, const char *val)
1400
0
{
1401
0
  int num;
1402
0
  const char *pos;
1403
0
  struct hostapd_tx_queue_params *queue;
1404
1405
  /* skip 'tx_queue_' prefix */
1406
0
  pos = name + 9;
1407
0
  if (os_strncmp(pos, "data", 4) == 0 &&
1408
0
      pos[4] >= '0' && pos[4] <= '9' && pos[5] == '_') {
1409
0
    num = pos[4] - '0';
1410
0
    pos += 6;
1411
0
  } else if (os_strncmp(pos, "after_beacon_", 13) == 0 ||
1412
0
       os_strncmp(pos, "beacon_", 7) == 0) {
1413
0
    wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
1414
0
    return 0;
1415
0
  } else {
1416
0
    wpa_printf(MSG_ERROR, "Unknown tx_queue name '%s'", pos);
1417
0
    return -1;
1418
0
  }
1419
1420
0
  if (num >= NUM_TX_QUEUES) {
1421
    /* for backwards compatibility, do not trigger failure */
1422
0
    wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
1423
0
    return 0;
1424
0
  }
1425
1426
0
  queue = &tx_queue[num];
1427
1428
0
  if (os_strcmp(pos, "aifs") == 0) {
1429
0
    queue->aifs = atoi(val);
1430
0
    if (queue->aifs < 0 || queue->aifs > 255) {
1431
0
      wpa_printf(MSG_ERROR, "Invalid AIFS value %d",
1432
0
           queue->aifs);
1433
0
      return -1;
1434
0
    }
1435
0
  } else if (os_strcmp(pos, "cwmin") == 0) {
1436
0
    queue->cwmin = atoi(val);
1437
0
    if (!valid_cw(queue->cwmin)) {
1438
0
      wpa_printf(MSG_ERROR, "Invalid cwMin value %d",
1439
0
           queue->cwmin);
1440
0
      return -1;
1441
0
    }
1442
0
  } else if (os_strcmp(pos, "cwmax") == 0) {
1443
0
    queue->cwmax = atoi(val);
1444
0
    if (!valid_cw(queue->cwmax)) {
1445
0
      wpa_printf(MSG_ERROR, "Invalid cwMax value %d",
1446
0
           queue->cwmax);
1447
0
      return -1;
1448
0
    }
1449
0
  } else if (os_strcmp(pos, "burst") == 0) {
1450
0
    queue->burst = hostapd_config_read_int10(val);
1451
0
  } else {
1452
0
    wpa_printf(MSG_ERROR, "Unknown queue field '%s'", pos);
1453
0
    return -1;
1454
0
  }
1455
1456
0
  return 0;
1457
0
}
1458
1459
1460
enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
1461
0
{
1462
0
  u8 op_class;
1463
1464
0
  return ieee80211_freq_to_channel_ext(freq, 0, CONF_OPER_CHWIDTH_USE_HT,
1465
0
               &op_class, channel);
1466
0
}
1467
1468
1469
/**
1470
 * ieee80211_freq_to_channel_ext - Convert frequency into channel info
1471
 * for HT40, VHT, and HE. DFS channels are not covered.
1472
 * @freq: Frequency (MHz) to convert
1473
 * @sec_channel: 0 = non-HT40, 1 = sec. channel above, -1 = sec. channel below
1474
 * @chanwidth: VHT/EDMG/etc. channel width
1475
 * @op_class: Buffer for returning operating class
1476
 * @channel: Buffer for returning channel number
1477
 * Returns: hw_mode on success, NUM_HOSTAPD_MODES on failure
1478
 */
1479
enum hostapd_hw_mode
1480
ieee80211_freq_to_channel_ext(unsigned int freq, int sec_channel,
1481
            enum oper_chan_width chanwidth,
1482
            u8 *op_class, u8 *channel)
1483
0
{
1484
0
  u8 vht_opclass;
1485
1486
  /* TODO: more operating classes */
1487
1488
0
  if (sec_channel > 1 || sec_channel < -1)
1489
0
    return NUM_HOSTAPD_MODES;
1490
1491
0
  if (freq >= 2412 && freq <= 2472) {
1492
0
    if ((freq - 2407) % 5)
1493
0
      return NUM_HOSTAPD_MODES;
1494
1495
0
    if (chanwidth)
1496
0
      return NUM_HOSTAPD_MODES;
1497
1498
    /* 2.407 GHz, channels 1..13 */
1499
0
    if (sec_channel == 1)
1500
0
      *op_class = 83;
1501
0
    else if (sec_channel == -1)
1502
0
      *op_class = 84;
1503
0
    else
1504
0
      *op_class = 81;
1505
1506
0
    *channel = (freq - 2407) / 5;
1507
1508
0
    return HOSTAPD_MODE_IEEE80211G;
1509
0
  }
1510
1511
0
  if (freq == 2484) {
1512
0
    if (sec_channel || chanwidth)
1513
0
      return NUM_HOSTAPD_MODES;
1514
1515
0
    *op_class = 82; /* channel 14 */
1516
0
    *channel = 14;
1517
1518
0
    return HOSTAPD_MODE_IEEE80211B;
1519
0
  }
1520
1521
0
  if (freq >= 4900 && freq < 5000) {
1522
0
    if ((freq - 4000) % 5)
1523
0
      return NUM_HOSTAPD_MODES;
1524
0
    *channel = (freq - 4000) / 5;
1525
0
    *op_class = 0; /* TODO */
1526
0
    return HOSTAPD_MODE_IEEE80211A;
1527
0
  }
1528
1529
0
  switch (chanwidth) {
1530
0
  case CONF_OPER_CHWIDTH_80MHZ:
1531
0
    vht_opclass = 128;
1532
0
    break;
1533
0
  case CONF_OPER_CHWIDTH_160MHZ:
1534
0
    vht_opclass = 129;
1535
0
    break;
1536
0
  case CONF_OPER_CHWIDTH_80P80MHZ:
1537
0
    vht_opclass = 130;
1538
0
    break;
1539
0
  default:
1540
0
    vht_opclass = 0;
1541
0
    break;
1542
0
  }
1543
1544
  /* 5 GHz, channels 36..48 */
1545
0
  if (freq >= 5180 && freq <= 5240) {
1546
0
    if ((freq - 5000) % 5)
1547
0
      return NUM_HOSTAPD_MODES;
1548
1549
0
    if (vht_opclass)
1550
0
      *op_class = vht_opclass;
1551
0
    else if (sec_channel == 1)
1552
0
      *op_class = 116;
1553
0
    else if (sec_channel == -1)
1554
0
      *op_class = 117;
1555
0
    else
1556
0
      *op_class = 115;
1557
1558
0
    *channel = (freq - 5000) / 5;
1559
1560
0
    return HOSTAPD_MODE_IEEE80211A;
1561
0
  }
1562
1563
  /* 5 GHz, channels 52..64 */
1564
0
  if (freq >= 5260 && freq <= 5320) {
1565
0
    if ((freq - 5000) % 5)
1566
0
      return NUM_HOSTAPD_MODES;
1567
1568
0
    if (vht_opclass)
1569
0
      *op_class = vht_opclass;
1570
0
    else if (sec_channel == 1)
1571
0
      *op_class = 119;
1572
0
    else if (sec_channel == -1)
1573
0
      *op_class = 120;
1574
0
    else
1575
0
      *op_class = 118;
1576
1577
0
    *channel = (freq - 5000) / 5;
1578
1579
0
    return HOSTAPD_MODE_IEEE80211A;
1580
0
  }
1581
1582
  /* 5 GHz, channels 149..177 */
1583
0
  if (freq >= 5745 && freq <= 5885) {
1584
0
    if ((freq - 5000) % 5)
1585
0
      return NUM_HOSTAPD_MODES;
1586
1587
0
    if (vht_opclass)
1588
0
      *op_class = vht_opclass;
1589
0
    else if (sec_channel == 1)
1590
0
      *op_class = 126;
1591
0
    else if (sec_channel == -1)
1592
0
      *op_class = 127;
1593
0
    else
1594
0
      *op_class = 125;
1595
1596
0
    *channel = (freq - 5000) / 5;
1597
1598
0
    return HOSTAPD_MODE_IEEE80211A;
1599
0
  }
1600
1601
  /* 5 GHz, channels 100..144 */
1602
0
  if (freq >= 5500 && freq <= 5720) {
1603
0
    if ((freq - 5000) % 5)
1604
0
      return NUM_HOSTAPD_MODES;
1605
1606
0
    if (vht_opclass)
1607
0
      *op_class = vht_opclass;
1608
0
    else if (sec_channel == 1)
1609
0
      *op_class = 122;
1610
0
    else if (sec_channel == -1)
1611
0
      *op_class = 123;
1612
0
    else
1613
0
      *op_class = 121;
1614
1615
0
    *channel = (freq - 5000) / 5;
1616
1617
0
    return HOSTAPD_MODE_IEEE80211A;
1618
0
  }
1619
1620
0
  if (freq >= 5000 && freq < 5900) {
1621
0
    if ((freq - 5000) % 5)
1622
0
      return NUM_HOSTAPD_MODES;
1623
0
    *channel = (freq - 5000) / 5;
1624
0
    *op_class = 0; /* TODO */
1625
0
    return HOSTAPD_MODE_IEEE80211A;
1626
0
  }
1627
1628
0
  if (freq > 5950 && freq <= 7115) {
1629
0
    if ((freq - 5950) % 5)
1630
0
      return NUM_HOSTAPD_MODES;
1631
1632
0
    switch (chanwidth) {
1633
0
    case CONF_OPER_CHWIDTH_80MHZ:
1634
0
      *op_class = 133;
1635
0
      break;
1636
0
    case CONF_OPER_CHWIDTH_160MHZ:
1637
0
      *op_class = 134;
1638
0
      break;
1639
0
    case CONF_OPER_CHWIDTH_80P80MHZ:
1640
0
      *op_class = 135;
1641
0
      break;
1642
0
    case CONF_OPER_CHWIDTH_320MHZ:
1643
0
      *op_class = 137;
1644
0
      break;
1645
0
    default:
1646
0
      if (sec_channel)
1647
0
        *op_class = 132;
1648
0
      else
1649
0
        *op_class = 131;
1650
0
      break;
1651
0
    }
1652
1653
0
    *channel = (freq - 5950) / 5;
1654
0
    return HOSTAPD_MODE_IEEE80211A;
1655
0
  }
1656
1657
0
  if (freq == 5935) {
1658
0
    *op_class = 136;
1659
0
    *channel = (freq - 5925) / 5;
1660
0
    return HOSTAPD_MODE_IEEE80211A;
1661
0
  }
1662
1663
  /* 56.16 GHz, channel 1..6 */
1664
0
  if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 6) {
1665
0
    if (sec_channel)
1666
0
      return NUM_HOSTAPD_MODES;
1667
1668
0
    switch (chanwidth) {
1669
0
    case CONF_OPER_CHWIDTH_USE_HT:
1670
0
    case CONF_OPER_CHWIDTH_2160MHZ:
1671
0
      *channel = (freq - 56160) / 2160;
1672
0
      *op_class = 180;
1673
0
      break;
1674
0
    case CONF_OPER_CHWIDTH_4320MHZ:
1675
      /* EDMG channels 9 - 13 */
1676
0
      if (freq > 56160 + 2160 * 5)
1677
0
        return NUM_HOSTAPD_MODES;
1678
1679
0
      *channel = (freq - 56160) / 2160 + 8;
1680
0
      *op_class = 181;
1681
0
      break;
1682
0
    case CONF_OPER_CHWIDTH_6480MHZ:
1683
      /* EDMG channels 17 - 20 */
1684
0
      if (freq > 56160 + 2160 * 4)
1685
0
        return NUM_HOSTAPD_MODES;
1686
1687
0
      *channel = (freq - 56160) / 2160 + 16;
1688
0
      *op_class = 182;
1689
0
      break;
1690
0
    case CONF_OPER_CHWIDTH_8640MHZ:
1691
      /* EDMG channels 25 - 27 */
1692
0
      if (freq > 56160 + 2160 * 3)
1693
0
        return NUM_HOSTAPD_MODES;
1694
1695
0
      *channel = (freq - 56160) / 2160 + 24;
1696
0
      *op_class = 183;
1697
0
      break;
1698
0
    default:
1699
0
      return NUM_HOSTAPD_MODES;
1700
0
    }
1701
1702
0
    return HOSTAPD_MODE_IEEE80211AD;
1703
0
  }
1704
1705
0
  return NUM_HOSTAPD_MODES;
1706
0
}
1707
1708
1709
int ieee80211_chaninfo_to_channel(unsigned int freq, enum chan_width chanwidth,
1710
          int sec_channel, u8 *op_class, u8 *channel)
1711
0
{
1712
0
  int cw = CHAN_WIDTH_UNKNOWN;
1713
1714
0
  switch (chanwidth) {
1715
0
  case CHAN_WIDTH_UNKNOWN:
1716
0
  case CHAN_WIDTH_20_NOHT:
1717
0
  case CHAN_WIDTH_20:
1718
0
  case CHAN_WIDTH_40:
1719
0
    cw = CONF_OPER_CHWIDTH_USE_HT;
1720
0
    break;
1721
0
  case CHAN_WIDTH_80:
1722
0
    cw = CONF_OPER_CHWIDTH_80MHZ;
1723
0
    break;
1724
0
  case CHAN_WIDTH_80P80:
1725
0
    cw = CONF_OPER_CHWIDTH_80P80MHZ;
1726
0
    break;
1727
0
  case CHAN_WIDTH_160:
1728
0
    cw = CONF_OPER_CHWIDTH_160MHZ;
1729
0
    break;
1730
0
  case CHAN_WIDTH_2160:
1731
0
    cw = CONF_OPER_CHWIDTH_2160MHZ;
1732
0
    break;
1733
0
  case CHAN_WIDTH_4320:
1734
0
    cw = CONF_OPER_CHWIDTH_4320MHZ;
1735
0
    break;
1736
0
  case CHAN_WIDTH_6480:
1737
0
    cw = CONF_OPER_CHWIDTH_6480MHZ;
1738
0
    break;
1739
0
  case CHAN_WIDTH_8640:
1740
0
    cw = CONF_OPER_CHWIDTH_8640MHZ;
1741
0
    break;
1742
0
  case CHAN_WIDTH_320:
1743
0
    cw = CONF_OPER_CHWIDTH_320MHZ;
1744
0
    break;
1745
0
  }
1746
1747
0
  if (ieee80211_freq_to_channel_ext(freq, sec_channel, cw, op_class,
1748
0
            channel) == NUM_HOSTAPD_MODES) {
1749
0
    wpa_printf(MSG_WARNING,
1750
0
         "Cannot determine operating class and channel (freq=%u chanwidth=%d sec_channel=%d)",
1751
0
         freq, chanwidth, sec_channel);
1752
0
    return -1;
1753
0
  }
1754
1755
0
  return 0;
1756
0
}
1757
1758
1759
static const char *const us_op_class_cc[] = {
1760
  "US", "CA", NULL
1761
};
1762
1763
static const char *const eu_op_class_cc[] = {
1764
  "AL", "AM", "AT", "AZ", "BA", "BE", "BG", "BY", "CH", "CY", "CZ", "DE",
1765
  "DK", "EE", "EL", "ES", "FI", "FR", "GE", "HR", "HU", "IE", "IS", "IT",
1766
  "LI", "LT", "LU", "LV", "MD", "ME", "MK", "MT", "NL", "NO", "PL", "PT",
1767
  "RO", "RS", "RU", "SE", "SI", "SK", "TR", "UA", "UK", NULL
1768
};
1769
1770
static const char *const jp_op_class_cc[] = {
1771
  "JP", NULL
1772
};
1773
1774
static const char *const cn_op_class_cc[] = {
1775
  "CN", NULL
1776
};
1777
1778
1779
static int country_match(const char *const cc[], const char *const country)
1780
0
{
1781
0
  int i;
1782
1783
0
  if (country == NULL)
1784
0
    return 0;
1785
0
  for (i = 0; cc[i]; i++) {
1786
0
    if (cc[i][0] == country[0] && cc[i][1] == country[1])
1787
0
      return 1;
1788
0
  }
1789
1790
0
  return 0;
1791
0
}
1792
1793
1794
static int ieee80211_chan_to_freq_us(u8 op_class, u8 chan)
1795
0
{
1796
0
  switch (op_class) {
1797
0
  case 12: /* channels 1..11 */
1798
0
  case 32: /* channels 1..7; 40 MHz */
1799
0
  case 33: /* channels 5..11; 40 MHz */
1800
0
    if (chan < 1 || chan > 11)
1801
0
      return -1;
1802
0
    return 2407 + 5 * chan;
1803
0
  case 1: /* channels 36,40,44,48 */
1804
0
  case 2: /* channels 52,56,60,64; dfs */
1805
0
  case 22: /* channels 36,44; 40 MHz */
1806
0
  case 23: /* channels 52,60; 40 MHz */
1807
0
  case 27: /* channels 40,48; 40 MHz */
1808
0
  case 28: /* channels 56,64; 40 MHz */
1809
0
    if (chan < 36 || chan > 64)
1810
0
      return -1;
1811
0
    return 5000 + 5 * chan;
1812
0
  case 4: /* channels 100-144 */
1813
0
  case 24: /* channels 100-140; 40 MHz */
1814
0
    if (chan < 100 || chan > 144)
1815
0
      return -1;
1816
0
    return 5000 + 5 * chan;
1817
0
  case 3: /* channels 149,153,157,161 */
1818
0
  case 25: /* channels 149,157; 40 MHz */
1819
0
  case 26: /* channels 149,157; 40 MHz */
1820
0
  case 30: /* channels 153,161; 40 MHz */
1821
0
  case 31: /* channels 153,161; 40 MHz */
1822
0
    if (chan < 149 || chan > 161)
1823
0
      return -1;
1824
0
    return 5000 + 5 * chan;
1825
0
  case 5: /* channels 149,153,157,161,165 */
1826
0
    if (chan < 149 || chan > 165)
1827
0
      return -1;
1828
0
    return 5000 + 5 * chan;
1829
0
  case 34: /* 60 GHz band, channels 1..8 */
1830
0
    if (chan < 1 || chan > 8)
1831
0
      return -1;
1832
0
    return 56160 + 2160 * chan;
1833
0
  case 37: /* 60 GHz band, EDMG CB2, channels 9..15 */
1834
0
    if (chan < 9 || chan > 15)
1835
0
      return -1;
1836
0
    return 56160 + 2160 * (chan - 8);
1837
0
  case 38: /* 60 GHz band, EDMG CB3, channels 17..22 */
1838
0
    if (chan < 17 || chan > 22)
1839
0
      return -1;
1840
0
    return 56160 + 2160 * (chan - 16);
1841
0
  case 39: /* 60 GHz band, EDMG CB4, channels 25..29 */
1842
0
    if (chan < 25 || chan > 29)
1843
0
      return -1;
1844
0
    return 56160 + 2160 * (chan - 24);
1845
0
  default:
1846
0
    return -1;
1847
0
  }
1848
0
}
1849
1850
1851
static int ieee80211_chan_to_freq_eu(u8 op_class, u8 chan)
1852
0
{
1853
0
  switch (op_class) {
1854
0
  case 4: /* channels 1..13 */
1855
0
  case 11: /* channels 1..9; 40 MHz */
1856
0
  case 12: /* channels 5..13; 40 MHz */
1857
0
    if (chan < 1 || chan > 13)
1858
0
      return -1;
1859
0
    return 2407 + 5 * chan;
1860
0
  case 1: /* channels 36,40,44,48 */
1861
0
  case 2: /* channels 52,56,60,64; dfs */
1862
0
  case 5: /* channels 36,44; 40 MHz */
1863
0
  case 6: /* channels 52,60; 40 MHz */
1864
0
  case 8: /* channels 40,48; 40 MHz */
1865
0
  case 9: /* channels 56,64; 40 MHz */
1866
0
    if (chan < 36 || chan > 64)
1867
0
      return -1;
1868
0
    return 5000 + 5 * chan;
1869
0
  case 3: /* channels 100-140 */
1870
0
  case 7: /* channels 100-132; 40 MHz */
1871
0
  case 10: /* channels 104-136; 40 MHz */
1872
0
  case 16: /* channels 100-140 */
1873
0
    if (chan < 100 || chan > 140)
1874
0
      return -1;
1875
0
    return 5000 + 5 * chan;
1876
0
  case 17: /* channels 149,153,157,161,165,169 */
1877
0
    if (chan < 149 || chan > 169)
1878
0
      return -1;
1879
0
    return 5000 + 5 * chan;
1880
0
  case 18: /* 60 GHz band, channels 1..6 */
1881
0
    if (chan < 1 || chan > 6)
1882
0
      return -1;
1883
0
    return 56160 + 2160 * chan;
1884
0
  case 21: /* 60 GHz band, EDMG CB2, channels 9..11 */
1885
0
    if (chan < 9 || chan > 11)
1886
0
      return -1;
1887
0
    return 56160 + 2160 * (chan - 8);
1888
0
  case 22: /* 60 GHz band, EDMG CB3, channels 17..18 */
1889
0
    if (chan < 17 || chan > 18)
1890
0
      return -1;
1891
0
    return 56160 + 2160 * (chan - 16);
1892
0
  case 23: /* 60 GHz band, EDMG CB4, channels 25 */
1893
0
    if (chan != 25)
1894
0
      return -1;
1895
0
    return 56160 + 2160 * (chan - 24);
1896
0
  default:
1897
0
    return -1;
1898
0
  }
1899
0
}
1900
1901
1902
static int ieee80211_chan_to_freq_jp(u8 op_class, u8 chan)
1903
0
{
1904
  /* Table E-3 in IEEE Std 802.11-2020 - Operating classes in Japan */
1905
0
  switch (op_class) {
1906
0
  case 30: /* channels 1..13 */
1907
0
  case 56: /* channels 1..9; 40 MHz */
1908
0
  case 57: /* channels 5..13; 40 MHz */
1909
0
    if (chan < 1 || chan > 13)
1910
0
      return -1;
1911
0
    return 2407 + 5 * chan;
1912
0
  case 31: /* channel 14 */
1913
0
    if (chan != 14)
1914
0
      return -1;
1915
0
    return 2414 + 5 * chan;
1916
0
  case 1: /* channels 34,38,42,46(old) or 36,40,44,48 */
1917
0
  case 32: /* channels 52,56,60,64 */
1918
0
  case 33: /* channels 52,56,60,64 */
1919
0
  case 36: /* channels 36,44; 40 MHz */
1920
0
  case 37: /* channels 52,60; 40 MHz */
1921
0
  case 38: /* channels 52,60; 40 MHz */
1922
0
  case 41: /* channels 40,48; 40 MHz */
1923
0
  case 42: /* channels 56,64; 40 MHz */
1924
0
  case 43: /* channels 56,64; 40 MHz */
1925
0
    if (chan < 34 || chan > 64)
1926
0
      return -1;
1927
0
    return 5000 + 5 * chan;
1928
0
  case 34: /* channels 100-144 */
1929
0
  case 35: /* reserved */
1930
0
  case 39: /* channels 100-140; 40 MHz */
1931
0
  case 40: /* reserved */
1932
0
  case 44: /* channels 104-144; 40 MHz */
1933
0
  case 45: /* reserved */
1934
0
  case 58: /* channels 100-144 */
1935
0
    if (chan < 100 || chan > 144)
1936
0
      return -1;
1937
0
    return 5000 + 5 * chan;
1938
0
  case 59: /* 60 GHz band, channels 1..6 */
1939
0
    if (chan < 1 || chan > 6)
1940
0
      return -1;
1941
0
    return 56160 + 2160 * chan;
1942
0
  case 62: /* 60 GHz band, EDMG CB2, channels 9..11 */
1943
0
    if (chan < 9 || chan > 11)
1944
0
      return -1;
1945
0
    return 56160 + 2160 * (chan - 8);
1946
0
  case 63: /* 60 GHz band, EDMG CB3, channels 17..18 */
1947
0
    if (chan < 17 || chan > 18)
1948
0
      return -1;
1949
0
    return 56160 + 2160 * (chan - 16);
1950
0
  case 64: /* 60 GHz band, EDMG CB4, channel 25 */
1951
0
    if (chan != 25)
1952
0
      return -1;
1953
0
    return 56160 + 2160 * (chan - 24);
1954
0
  default:
1955
0
    return -1;
1956
0
  }
1957
0
}
1958
1959
1960
static int ieee80211_chan_to_freq_cn(u8 op_class, u8 chan)
1961
0
{
1962
0
  switch (op_class) {
1963
0
  case 7: /* channels 1..13 */
1964
0
  case 8: /* channels 1..9; 40 MHz */
1965
0
  case 9: /* channels 5..13; 40 MHz */
1966
0
    if (chan < 1 || chan > 13)
1967
0
      return -1;
1968
0
    return 2407 + 5 * chan;
1969
0
  case 1: /* channels 36,40,44,48 */
1970
0
  case 2: /* channels 52,56,60,64; dfs */
1971
0
  case 4: /* channels 36,44; 40 MHz */
1972
0
  case 5: /* channels 52,60; 40 MHz */
1973
0
    if (chan < 36 || chan > 64)
1974
0
      return -1;
1975
0
    return 5000 + 5 * chan;
1976
0
  case 3: /* channels 149,153,157,161,165 */
1977
0
  case 6: /* channels 149,157; 40 MHz */
1978
0
    if (chan < 149 || chan > 165)
1979
0
      return -1;
1980
0
    return 5000 + 5 * chan;
1981
0
  default:
1982
0
    return -1;
1983
0
  }
1984
0
}
1985
1986
1987
static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan)
1988
0
{
1989
  /* Table E-4 in IEEE Std 802.11-2020 - Global operating classes */
1990
0
  switch (op_class) {
1991
0
  case 81:
1992
    /* channels 1..13 */
1993
0
    if (chan < 1 || chan > 13)
1994
0
      return -1;
1995
0
    return 2407 + 5 * chan;
1996
0
  case 82:
1997
    /* channel 14 */
1998
0
    if (chan != 14)
1999
0
      return -1;
2000
0
    return 2414 + 5 * chan;
2001
0
  case 83: /* channels 1..9; 40 MHz */
2002
0
  case 84: /* channels 5..13; 40 MHz */
2003
0
    if (chan < 1 || chan > 13)
2004
0
      return -1;
2005
0
    return 2407 + 5 * chan;
2006
0
  case 115: /* channels 36,40,44,48; indoor only */
2007
0
  case 116: /* channels 36,44; 40 MHz; indoor only */
2008
0
  case 117: /* channels 40,48; 40 MHz; indoor only */
2009
0
  case 118: /* channels 52,56,60,64; dfs */
2010
0
  case 119: /* channels 52,60; 40 MHz; dfs */
2011
0
  case 120: /* channels 56,64; 40 MHz; dfs */
2012
0
    if (chan < 36 || chan > 64)
2013
0
      return -1;
2014
0
    return 5000 + 5 * chan;
2015
0
  case 121: /* channels 100-144 */
2016
0
  case 122: /* channels 100-140; 40 MHz */
2017
0
  case 123: /* channels 104-144; 40 MHz */
2018
0
    if (chan < 100 || chan > 144)
2019
0
      return -1;
2020
0
    return 5000 + 5 * chan;
2021
0
  case 124: /* channels 149,153,157,161 */
2022
0
    if (chan < 149 || chan > 161)
2023
0
      return -1;
2024
0
    return 5000 + 5 * chan;
2025
0
  case 125: /* channels 149,153,157,161,165,169,173,177 */
2026
0
  case 126: /* channels 149,157,165,173; 40 MHz */
2027
0
  case 127: /* channels 153,161,169,177; 40 MHz */
2028
0
    if (chan < 149 || chan > 177)
2029
0
      return -1;
2030
0
    return 5000 + 5 * chan;
2031
0
  case 128: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80 MHz */
2032
0
  case 130: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80 MHz */
2033
0
    if (chan < 36 || chan > 177)
2034
0
      return -1;
2035
0
    return 5000 + 5 * chan;
2036
0
  case 129: /* center freqs 50, 114, 163; 160 MHz */
2037
0
    if (chan < 36 || chan > 177)
2038
0
      return -1;
2039
0
    return 5000 + 5 * chan;
2040
0
  case 131: /* UHB channels, 20 MHz: 1, 5, 9.. */
2041
0
  case 132: /* UHB channels, 40 MHz: 3, 11, 19.. */
2042
0
  case 133: /* UHB channels, 80 MHz: 7, 23, 39.. */
2043
0
  case 134: /* UHB channels, 160 MHz: 15, 47, 79.. */
2044
0
  case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
2045
0
  case 137: /* UHB channels, 320 MHz: 31, 63, 95, 127, 159, 191 */
2046
0
    if (chan < 1 || chan > 233)
2047
0
      return -1;
2048
0
    return 5950 + chan * 5;
2049
0
  case 136: /* UHB channels, 20 MHz: 2 */
2050
0
    if (chan == 2)
2051
0
      return 5935;
2052
0
    return -1;
2053
0
  case 180: /* 60 GHz band, channels 1..8 */
2054
0
    if (chan < 1 || chan > 8)
2055
0
      return -1;
2056
0
    return 56160 + 2160 * chan;
2057
0
  case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */
2058
0
    if (chan < 9 || chan > 15)
2059
0
      return -1;
2060
0
    return 56160 + 2160 * (chan - 8);
2061
0
  case 182: /* 60 GHz band, EDMG CB3, channels 17..22 */
2062
0
    if (chan < 17 || chan > 22)
2063
0
      return -1;
2064
0
    return 56160 + 2160 * (chan - 16);
2065
0
  case 183: /* 60 GHz band, EDMG CB4, channel 25..29 */
2066
0
    if (chan < 25 || chan > 29)
2067
0
      return -1;
2068
0
    return 56160 + 2160 * (chan - 24);
2069
0
  default:
2070
0
    return -1;
2071
0
  }
2072
0
}
2073
2074
/**
2075
 * ieee80211_chan_to_freq - Convert channel info to frequency
2076
 * @country: Country code, if known; otherwise, global operating class is used
2077
 * @op_class: Operating class
2078
 * @chan: Channel number
2079
 * Returns: Frequency in MHz or -1 if the specified channel is unknown
2080
 */
2081
int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan)
2082
0
{
2083
0
  int freq;
2084
2085
0
  if (country_match(us_op_class_cc, country)) {
2086
0
    freq = ieee80211_chan_to_freq_us(op_class, chan);
2087
0
    if (freq > 0)
2088
0
      return freq;
2089
0
  }
2090
2091
0
  if (country_match(eu_op_class_cc, country)) {
2092
0
    freq = ieee80211_chan_to_freq_eu(op_class, chan);
2093
0
    if (freq > 0)
2094
0
      return freq;
2095
0
  }
2096
2097
0
  if (country_match(jp_op_class_cc, country)) {
2098
0
    freq = ieee80211_chan_to_freq_jp(op_class, chan);
2099
0
    if (freq > 0)
2100
0
      return freq;
2101
0
  }
2102
2103
0
  if (country_match(cn_op_class_cc, country)) {
2104
0
    freq = ieee80211_chan_to_freq_cn(op_class, chan);
2105
0
    if (freq > 0)
2106
0
      return freq;
2107
0
  }
2108
2109
0
  return ieee80211_chan_to_freq_global(op_class, chan);
2110
0
}
2111
2112
2113
int ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes,
2114
         u16 num_modes)
2115
0
{
2116
0
  int i, j;
2117
2118
0
  if (!modes || !num_modes)
2119
0
    return (freq >= 5260 && freq <= 5320) ||
2120
0
      (freq >= 5500 && freq <= 5720);
2121
2122
0
  for (i = 0; i < num_modes; i++) {
2123
0
    for (j = 0; j < modes[i].num_channels; j++) {
2124
0
      if (modes[i].channels[j].freq == freq &&
2125
0
          (modes[i].channels[j].flag & HOSTAPD_CHAN_RADAR))
2126
0
        return 1;
2127
0
    }
2128
0
  }
2129
2130
0
  return 0;
2131
0
}
2132
2133
2134
/*
2135
 * 802.11-2020: Table E-4 - Global operating classes
2136
 * DFS_50_100_Behavior: 118, 119, 120, 121, 122, 123
2137
 */
2138
int is_dfs_global_op_class(u8 op_class)
2139
0
{
2140
0
    return (op_class >= 118) && (op_class <= 123);
2141
0
}
2142
2143
2144
bool is_80plus_op_class(u8 op_class)
2145
0
{
2146
  /* Operating classes with "80+" behavior indication in Table E-4 */
2147
0
  return op_class == 130 || op_class == 135;
2148
0
}
2149
2150
2151
static int is_11b(u8 rate)
2152
0
{
2153
0
  return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;
2154
0
}
2155
2156
2157
int supp_rates_11b_only(struct ieee802_11_elems *elems)
2158
0
{
2159
0
  int num_11b = 0, num_others = 0;
2160
0
  int i;
2161
2162
0
  if (elems->supp_rates == NULL && elems->ext_supp_rates == NULL)
2163
0
    return 0;
2164
2165
0
  for (i = 0; elems->supp_rates && i < elems->supp_rates_len; i++) {
2166
0
    if (is_11b(elems->supp_rates[i]))
2167
0
      num_11b++;
2168
0
    else
2169
0
      num_others++;
2170
0
  }
2171
2172
0
  for (i = 0; elems->ext_supp_rates && i < elems->ext_supp_rates_len;
2173
0
       i++) {
2174
0
    if (is_11b(elems->ext_supp_rates[i]))
2175
0
      num_11b++;
2176
0
    else
2177
0
      num_others++;
2178
0
  }
2179
2180
0
  return num_11b > 0 && num_others == 0;
2181
0
}
2182
2183
2184
const char * fc2str(u16 fc)
2185
0
{
2186
0
  u16 stype = WLAN_FC_GET_STYPE(fc);
2187
0
#define C2S(x) case x: return #x;
2188
2189
0
  switch (WLAN_FC_GET_TYPE(fc)) {
2190
0
  case WLAN_FC_TYPE_MGMT:
2191
0
    switch (stype) {
2192
0
    C2S(WLAN_FC_STYPE_ASSOC_REQ)
2193
0
    C2S(WLAN_FC_STYPE_ASSOC_RESP)
2194
0
    C2S(WLAN_FC_STYPE_REASSOC_REQ)
2195
0
    C2S(WLAN_FC_STYPE_REASSOC_RESP)
2196
0
    C2S(WLAN_FC_STYPE_PROBE_REQ)
2197
0
    C2S(WLAN_FC_STYPE_PROBE_RESP)
2198
0
    C2S(WLAN_FC_STYPE_BEACON)
2199
0
    C2S(WLAN_FC_STYPE_ATIM)
2200
0
    C2S(WLAN_FC_STYPE_DISASSOC)
2201
0
    C2S(WLAN_FC_STYPE_AUTH)
2202
0
    C2S(WLAN_FC_STYPE_DEAUTH)
2203
0
    C2S(WLAN_FC_STYPE_ACTION)
2204
0
    }
2205
0
    break;
2206
0
  case WLAN_FC_TYPE_CTRL:
2207
0
    switch (stype) {
2208
0
    C2S(WLAN_FC_STYPE_PSPOLL)
2209
0
    C2S(WLAN_FC_STYPE_RTS)
2210
0
    C2S(WLAN_FC_STYPE_CTS)
2211
0
    C2S(WLAN_FC_STYPE_ACK)
2212
0
    C2S(WLAN_FC_STYPE_CFEND)
2213
0
    C2S(WLAN_FC_STYPE_CFENDACK)
2214
0
    }
2215
0
    break;
2216
0
  case WLAN_FC_TYPE_DATA:
2217
0
    switch (stype) {
2218
0
    C2S(WLAN_FC_STYPE_DATA)
2219
0
    C2S(WLAN_FC_STYPE_DATA_CFACK)
2220
0
    C2S(WLAN_FC_STYPE_DATA_CFPOLL)
2221
0
    C2S(WLAN_FC_STYPE_DATA_CFACKPOLL)
2222
0
    C2S(WLAN_FC_STYPE_NULLFUNC)
2223
0
    C2S(WLAN_FC_STYPE_CFACK)
2224
0
    C2S(WLAN_FC_STYPE_CFPOLL)
2225
0
    C2S(WLAN_FC_STYPE_CFACKPOLL)
2226
0
    C2S(WLAN_FC_STYPE_QOS_DATA)
2227
0
    C2S(WLAN_FC_STYPE_QOS_DATA_CFACK)
2228
0
    C2S(WLAN_FC_STYPE_QOS_DATA_CFPOLL)
2229
0
    C2S(WLAN_FC_STYPE_QOS_DATA_CFACKPOLL)
2230
0
    C2S(WLAN_FC_STYPE_QOS_NULL)
2231
0
    C2S(WLAN_FC_STYPE_QOS_CFPOLL)
2232
0
    C2S(WLAN_FC_STYPE_QOS_CFACKPOLL)
2233
0
    }
2234
0
    break;
2235
0
  }
2236
0
  return "WLAN_FC_TYPE_UNKNOWN";
2237
0
#undef C2S
2238
0
}
2239
2240
2241
const char * reason2str(u16 reason)
2242
0
{
2243
0
#define R2S(r) case WLAN_REASON_ ## r: return #r;
2244
0
  switch (reason) {
2245
0
  R2S(UNSPECIFIED)
2246
0
  R2S(PREV_AUTH_NOT_VALID)
2247
0
  R2S(DEAUTH_LEAVING)
2248
0
  R2S(DISASSOC_DUE_TO_INACTIVITY)
2249
0
  R2S(DISASSOC_AP_BUSY)
2250
0
  R2S(CLASS2_FRAME_FROM_NONAUTH_STA)
2251
0
  R2S(CLASS3_FRAME_FROM_NONASSOC_STA)
2252
0
  R2S(DISASSOC_STA_HAS_LEFT)
2253
0
  R2S(STA_REQ_ASSOC_WITHOUT_AUTH)
2254
0
  R2S(PWR_CAPABILITY_NOT_VALID)
2255
0
  R2S(SUPPORTED_CHANNEL_NOT_VALID)
2256
0
  R2S(BSS_TRANSITION_DISASSOC)
2257
0
  R2S(INVALID_IE)
2258
0
  R2S(MICHAEL_MIC_FAILURE)
2259
0
  R2S(4WAY_HANDSHAKE_TIMEOUT)
2260
0
  R2S(GROUP_KEY_UPDATE_TIMEOUT)
2261
0
  R2S(IE_IN_4WAY_DIFFERS)
2262
0
  R2S(GROUP_CIPHER_NOT_VALID)
2263
0
  R2S(PAIRWISE_CIPHER_NOT_VALID)
2264
0
  R2S(AKMP_NOT_VALID)
2265
0
  R2S(UNSUPPORTED_RSN_IE_VERSION)
2266
0
  R2S(INVALID_RSN_IE_CAPAB)
2267
0
  R2S(IEEE_802_1X_AUTH_FAILED)
2268
0
  R2S(CIPHER_SUITE_REJECTED)
2269
0
  R2S(TDLS_TEARDOWN_UNREACHABLE)
2270
0
  R2S(TDLS_TEARDOWN_UNSPECIFIED)
2271
0
  R2S(SSP_REQUESTED_DISASSOC)
2272
0
  R2S(NO_SSP_ROAMING_AGREEMENT)
2273
0
  R2S(BAD_CIPHER_OR_AKM)
2274
0
  R2S(NOT_AUTHORIZED_THIS_LOCATION)
2275
0
  R2S(SERVICE_CHANGE_PRECLUDES_TS)
2276
0
  R2S(UNSPECIFIED_QOS_REASON)
2277
0
  R2S(NOT_ENOUGH_BANDWIDTH)
2278
0
  R2S(DISASSOC_LOW_ACK)
2279
0
  R2S(EXCEEDED_TXOP)
2280
0
  R2S(STA_LEAVING)
2281
0
  R2S(END_TS_BA_DLS)
2282
0
  R2S(UNKNOWN_TS_BA)
2283
0
  R2S(TIMEOUT)
2284
0
  R2S(PEERKEY_MISMATCH)
2285
0
  R2S(AUTHORIZED_ACCESS_LIMIT_REACHED)
2286
0
  R2S(EXTERNAL_SERVICE_REQUIREMENTS)
2287
0
  R2S(INVALID_FT_ACTION_FRAME_COUNT)
2288
0
  R2S(INVALID_PMKID)
2289
0
  R2S(INVALID_MDE)
2290
0
  R2S(INVALID_FTE)
2291
0
  R2S(MESH_PEERING_CANCELLED)
2292
0
  R2S(MESH_MAX_PEERS)
2293
0
  R2S(MESH_CONFIG_POLICY_VIOLATION)
2294
0
  R2S(MESH_CLOSE_RCVD)
2295
0
  R2S(MESH_MAX_RETRIES)
2296
0
  R2S(MESH_CONFIRM_TIMEOUT)
2297
0
  R2S(MESH_INVALID_GTK)
2298
0
  R2S(MESH_INCONSISTENT_PARAMS)
2299
0
  R2S(MESH_INVALID_SECURITY_CAP)
2300
0
  R2S(MESH_PATH_ERROR_NO_PROXY_INFO)
2301
0
  R2S(MESH_PATH_ERROR_NO_FORWARDING_INFO)
2302
0
  R2S(MESH_PATH_ERROR_DEST_UNREACHABLE)
2303
0
  R2S(MAC_ADDRESS_ALREADY_EXISTS_IN_MBSS)
2304
0
  R2S(MESH_CHANNEL_SWITCH_REGULATORY_REQ)
2305
0
  R2S(MESH_CHANNEL_SWITCH_UNSPECIFIED)
2306
0
  }
2307
0
  return "UNKNOWN";
2308
0
#undef R2S
2309
0
}
2310
2311
2312
const char * status2str(u16 status)
2313
0
{
2314
0
#define S2S(s) case WLAN_STATUS_ ## s: return #s;
2315
0
  switch (status) {
2316
0
  S2S(SUCCESS)
2317
0
  S2S(UNSPECIFIED_FAILURE)
2318
0
  S2S(TDLS_WAKEUP_ALTERNATE)
2319
0
  S2S(TDLS_WAKEUP_REJECT)
2320
0
  S2S(SECURITY_DISABLED)
2321
0
  S2S(UNACCEPTABLE_LIFETIME)
2322
0
  S2S(NOT_IN_SAME_BSS)
2323
0
  S2S(CAPS_UNSUPPORTED)
2324
0
  S2S(REASSOC_NO_ASSOC)
2325
0
  S2S(ASSOC_DENIED_UNSPEC)
2326
0
  S2S(NOT_SUPPORTED_AUTH_ALG)
2327
0
  S2S(UNKNOWN_AUTH_TRANSACTION)
2328
0
  S2S(CHALLENGE_FAIL)
2329
0
  S2S(AUTH_TIMEOUT)
2330
0
  S2S(AP_UNABLE_TO_HANDLE_NEW_STA)
2331
0
  S2S(ASSOC_DENIED_RATES)
2332
0
  S2S(ASSOC_DENIED_NOSHORT)
2333
0
  S2S(SPEC_MGMT_REQUIRED)
2334
0
  S2S(PWR_CAPABILITY_NOT_VALID)
2335
0
  S2S(SUPPORTED_CHANNEL_NOT_VALID)
2336
0
  S2S(ASSOC_DENIED_NO_SHORT_SLOT_TIME)
2337
0
  S2S(ASSOC_DENIED_NO_HT)
2338
0
  S2S(R0KH_UNREACHABLE)
2339
0
  S2S(ASSOC_DENIED_NO_PCO)
2340
0
  S2S(ASSOC_REJECTED_TEMPORARILY)
2341
0
  S2S(ROBUST_MGMT_FRAME_POLICY_VIOLATION)
2342
0
  S2S(UNSPECIFIED_QOS_FAILURE)
2343
0
  S2S(DENIED_INSUFFICIENT_BANDWIDTH)
2344
0
  S2S(DENIED_POOR_CHANNEL_CONDITIONS)
2345
0
  S2S(DENIED_QOS_NOT_SUPPORTED)
2346
0
  S2S(REQUEST_DECLINED)
2347
0
  S2S(INVALID_PARAMETERS)
2348
0
  S2S(REJECTED_WITH_SUGGESTED_CHANGES)
2349
0
  S2S(INVALID_IE)
2350
0
  S2S(GROUP_CIPHER_NOT_VALID)
2351
0
  S2S(PAIRWISE_CIPHER_NOT_VALID)
2352
0
  S2S(AKMP_NOT_VALID)
2353
0
  S2S(UNSUPPORTED_RSN_IE_VERSION)
2354
0
  S2S(INVALID_RSN_IE_CAPAB)
2355
0
  S2S(CIPHER_REJECTED_PER_POLICY)
2356
0
  S2S(TS_NOT_CREATED)
2357
0
  S2S(DIRECT_LINK_NOT_ALLOWED)
2358
0
  S2S(DEST_STA_NOT_PRESENT)
2359
0
  S2S(DEST_STA_NOT_QOS_STA)
2360
0
  S2S(ASSOC_DENIED_LISTEN_INT_TOO_LARGE)
2361
0
  S2S(INVALID_FT_ACTION_FRAME_COUNT)
2362
0
  S2S(INVALID_PMKID)
2363
0
  S2S(INVALID_MDIE)
2364
0
  S2S(INVALID_FTIE)
2365
0
  S2S(REQUESTED_TCLAS_NOT_SUPPORTED)
2366
0
  S2S(INSUFFICIENT_TCLAS_PROCESSING_RESOURCES)
2367
0
  S2S(TRY_ANOTHER_BSS)
2368
0
  S2S(GAS_ADV_PROTO_NOT_SUPPORTED)
2369
0
  S2S(NO_OUTSTANDING_GAS_REQ)
2370
0
  S2S(GAS_RESP_NOT_RECEIVED)
2371
0
  S2S(STA_TIMED_OUT_WAITING_FOR_GAS_RESP)
2372
0
  S2S(GAS_RESP_LARGER_THAN_LIMIT)
2373
0
  S2S(REQ_REFUSED_HOME)
2374
0
  S2S(ADV_SRV_UNREACHABLE)
2375
0
  S2S(REQ_REFUSED_SSPN)
2376
0
  S2S(REQ_REFUSED_UNAUTH_ACCESS)
2377
0
  S2S(INVALID_RSNIE)
2378
0
  S2S(U_APSD_COEX_NOT_SUPPORTED)
2379
0
  S2S(U_APSD_COEX_MODE_NOT_SUPPORTED)
2380
0
  S2S(BAD_INTERVAL_WITH_U_APSD_COEX)
2381
0
  S2S(ANTI_CLOGGING_TOKEN_REQ)
2382
0
  S2S(FINITE_CYCLIC_GROUP_NOT_SUPPORTED)
2383
0
  S2S(CANNOT_FIND_ALT_TBTT)
2384
0
  S2S(TRANSMISSION_FAILURE)
2385
0
  S2S(REQ_TCLAS_NOT_SUPPORTED)
2386
0
  S2S(TCLAS_RESOURCES_EXCHAUSTED)
2387
0
  S2S(REJECTED_WITH_SUGGESTED_BSS_TRANSITION)
2388
0
  S2S(REJECT_WITH_SCHEDULE)
2389
0
  S2S(REJECT_NO_WAKEUP_SPECIFIED)
2390
0
  S2S(SUCCESS_POWER_SAVE_MODE)
2391
0
  S2S(PENDING_ADMITTING_FST_SESSION)
2392
0
  S2S(PERFORMING_FST_NOW)
2393
0
  S2S(PENDING_GAP_IN_BA_WINDOW)
2394
0
  S2S(REJECT_U_PID_SETTING)
2395
0
  S2S(REFUSED_EXTERNAL_REASON)
2396
0
  S2S(REFUSED_AP_OUT_OF_MEMORY)
2397
0
  S2S(REJECTED_EMERGENCY_SERVICE_NOT_SUPPORTED)
2398
0
  S2S(QUERY_RESP_OUTSTANDING)
2399
0
  S2S(REJECT_DSE_BAND)
2400
0
  S2S(TCLAS_PROCESSING_TERMINATED)
2401
0
  S2S(TS_SCHEDULE_CONFLICT)
2402
0
  S2S(DENIED_WITH_SUGGESTED_BAND_AND_CHANNEL)
2403
0
  S2S(MCCAOP_RESERVATION_CONFLICT)
2404
0
  S2S(MAF_LIMIT_EXCEEDED)
2405
0
  S2S(MCCA_TRACK_LIMIT_EXCEEDED)
2406
0
  S2S(DENIED_DUE_TO_SPECTRUM_MANAGEMENT)
2407
0
  S2S(ASSOC_DENIED_NO_VHT)
2408
0
  S2S(ENABLEMENT_DENIED)
2409
0
  S2S(RESTRICTION_FROM_AUTHORIZED_GDB)
2410
0
  S2S(AUTHORIZATION_DEENABLED)
2411
0
  S2S(FILS_AUTHENTICATION_FAILURE)
2412
0
  S2S(UNKNOWN_AUTHENTICATION_SERVER)
2413
0
  S2S(UNKNOWN_PASSWORD_IDENTIFIER)
2414
0
  S2S(DENIED_HE_NOT_SUPPORTED)
2415
0
  S2S(SAE_HASH_TO_ELEMENT)
2416
0
  S2S(SAE_PK)
2417
0
  S2S(INVALID_PUBLIC_KEY)
2418
0
  S2S(PASN_BASE_AKMP_FAILED)
2419
0
  S2S(OCI_MISMATCH)
2420
0
  }
2421
0
  return "UNKNOWN";
2422
0
#undef S2S
2423
0
}
2424
2425
2426
int mb_ies_info_by_ies(struct mb_ies_info *info, const u8 *ies_buf,
2427
           size_t ies_len)
2428
0
{
2429
0
  const struct element *elem;
2430
2431
0
  os_memset(info, 0, sizeof(*info));
2432
2433
0
  if (!ies_buf)
2434
0
    return 0;
2435
2436
0
  for_each_element_id(elem, WLAN_EID_MULTI_BAND, ies_buf, ies_len) {
2437
0
    if (info->nof_ies >= MAX_NOF_MB_IES_SUPPORTED)
2438
0
      return 0;
2439
2440
0
    wpa_printf(MSG_DEBUG, "MB IE of %u bytes found",
2441
0
         elem->datalen + 2);
2442
0
    info->ies[info->nof_ies].ie = elem->data;
2443
0
    info->ies[info->nof_ies].ie_len = elem->datalen;
2444
0
    info->nof_ies++;
2445
0
  }
2446
2447
0
  if (!for_each_element_completed(elem, ies_buf, ies_len)) {
2448
0
    wpa_hexdump(MSG_DEBUG, "Truncated IEs", ies_buf, ies_len);
2449
0
    return -1;
2450
0
  }
2451
2452
0
  return 0;
2453
0
}
2454
2455
2456
struct wpabuf * mb_ies_by_info(struct mb_ies_info *info)
2457
0
{
2458
0
  struct wpabuf *mb_ies = NULL;
2459
2460
0
  WPA_ASSERT(info != NULL);
2461
2462
0
  if (info->nof_ies) {
2463
0
    u8 i;
2464
0
    size_t mb_ies_size = 0;
2465
2466
0
    for (i = 0; i < info->nof_ies; i++)
2467
0
      mb_ies_size += 2 + info->ies[i].ie_len;
2468
2469
0
    mb_ies = wpabuf_alloc(mb_ies_size);
2470
0
    if (mb_ies) {
2471
0
      for (i = 0; i < info->nof_ies; i++) {
2472
0
        wpabuf_put_u8(mb_ies, WLAN_EID_MULTI_BAND);
2473
0
        wpabuf_put_u8(mb_ies, info->ies[i].ie_len);
2474
0
        wpabuf_put_data(mb_ies,
2475
0
            info->ies[i].ie,
2476
0
            info->ies[i].ie_len);
2477
0
      }
2478
0
    }
2479
0
  }
2480
2481
0
  return mb_ies;
2482
0
}
2483
2484
2485
const struct oper_class_map global_op_class[] = {
2486
  { HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1, BW20, P2P_SUPP },
2487
  { HOSTAPD_MODE_IEEE80211G, 82, 14, 14, 1, BW20, NO_P2P_SUPP },
2488
2489
  /* Do not enable HT40 on 2.4 GHz for P2P use for now */
2490
  { HOSTAPD_MODE_IEEE80211G, 83, 1, 9, 1, BW40PLUS, NO_P2P_SUPP },
2491
  { HOSTAPD_MODE_IEEE80211G, 84, 5, 13, 1, BW40MINUS, NO_P2P_SUPP },
2492
2493
  { HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4, BW20, P2P_SUPP },
2494
  { HOSTAPD_MODE_IEEE80211A, 116, 36, 44, 8, BW40PLUS, P2P_SUPP },
2495
  { HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS, P2P_SUPP },
2496
  { HOSTAPD_MODE_IEEE80211A, 118, 52, 64, 4, BW20, NO_P2P_SUPP },
2497
  { HOSTAPD_MODE_IEEE80211A, 119, 52, 60, 8, BW40PLUS, NO_P2P_SUPP },
2498
  { HOSTAPD_MODE_IEEE80211A, 120, 56, 64, 8, BW40MINUS, NO_P2P_SUPP },
2499
  { HOSTAPD_MODE_IEEE80211A, 121, 100, 144, 4, BW20, NO_P2P_SUPP },
2500
  { HOSTAPD_MODE_IEEE80211A, 122, 100, 140, 8, BW40PLUS, NO_P2P_SUPP },
2501
  { HOSTAPD_MODE_IEEE80211A, 123, 104, 144, 8, BW40MINUS, NO_P2P_SUPP },
2502
  { HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20, P2P_SUPP },
2503
  { HOSTAPD_MODE_IEEE80211A, 125, 149, 177, 4, BW20, P2P_SUPP },
2504
  { HOSTAPD_MODE_IEEE80211A, 126, 149, 173, 8, BW40PLUS, P2P_SUPP },
2505
  { HOSTAPD_MODE_IEEE80211A, 127, 153, 177, 8, BW40MINUS, P2P_SUPP },
2506
2507
  /*
2508
   * IEEE Std 802.11ax-2021, Table E-4 actually talks about channel center
2509
   * frequency index for operation classes 128, 129, 130, 132, 133, 134,
2510
   * and 135, but currently use the lowest 20 MHz channel for simplicity
2511
   * (these center frequencies are not actual channels, which makes
2512
   * wpas_p2p_verify_channel() fail).
2513
   * Specially for the operation class 136, it is also defined to use the
2514
   * channel center frequency index value, but it happens to be a 20 MHz
2515
   * channel and the channel number in the channel set would match the
2516
   * value in for the frequency center.
2517
   *
2518
   * Operating class value pair 128 and 130 is used to describe a 80+80
2519
   * MHz channel on the 5 GHz band. 130 is identified with "80+", so this
2520
   * is encoded with two octets 130 and 128. Similarly, operating class
2521
   * value pair 133 and 135 is used to describe a 80+80 MHz channel on
2522
   * the 6 GHz band (135 being the one with "80+" indication). All other
2523
   * operating classes listed here are used as 1-octet values.
2524
   */
2525
  { HOSTAPD_MODE_IEEE80211A, 128, 36, 177, 4, BW80, P2P_SUPP },
2526
  { HOSTAPD_MODE_IEEE80211A, 129, 36, 177, 4, BW160, P2P_SUPP },
2527
  { HOSTAPD_MODE_IEEE80211A, 130, 36, 177, 4, BW80P80, P2P_SUPP },
2528
  { HOSTAPD_MODE_IEEE80211A, 131, 1, 233, 4, BW20, P2P_SUPP },
2529
  { HOSTAPD_MODE_IEEE80211A, 132, 1, 233, 8, BW40, P2P_SUPP },
2530
  { HOSTAPD_MODE_IEEE80211A, 133, 1, 233, 16, BW80, P2P_SUPP },
2531
  { HOSTAPD_MODE_IEEE80211A, 134, 1, 233, 32, BW160, P2P_SUPP },
2532
  { HOSTAPD_MODE_IEEE80211A, 135, 1, 233, 16, BW80P80, NO_P2P_SUPP },
2533
  { HOSTAPD_MODE_IEEE80211A, 136, 2, 2, 4, BW20, NO_P2P_SUPP },
2534
2535
  /* IEEE Std 802.11be-2024, Table E-4 (Global operating classes) */
2536
  { HOSTAPD_MODE_IEEE80211A, 137, 31, 191, 32, BW320, NO_P2P_SUPP },
2537
2538
  /*
2539
   * IEEE Std 802.11ad-2012 and P802.ay/D5.0 60 GHz operating classes.
2540
   * Class 180 has the legacy channels 1-6. Classes 181-183 include
2541
   * channels which implement channel bonding features.
2542
   */
2543
  { HOSTAPD_MODE_IEEE80211AD, 180, 1, 6, 1, BW2160, P2P_SUPP },
2544
  { HOSTAPD_MODE_IEEE80211AD, 181, 9, 13, 1, BW4320, P2P_SUPP },
2545
  { HOSTAPD_MODE_IEEE80211AD, 182, 17, 20, 1, BW6480, P2P_SUPP },
2546
  { HOSTAPD_MODE_IEEE80211AD, 183, 25, 27, 1, BW8640, P2P_SUPP },
2547
2548
  { -1, 0, 0, 0, 0, BW20, NO_P2P_SUPP }
2549
};
2550
2551
2552
static enum phy_type ieee80211_phy_type_by_freq(int freq)
2553
0
{
2554
0
  enum hostapd_hw_mode hw_mode;
2555
0
  u8 channel;
2556
2557
0
  hw_mode = ieee80211_freq_to_chan(freq, &channel);
2558
2559
0
  switch (hw_mode) {
2560
0
  case HOSTAPD_MODE_IEEE80211A:
2561
0
    return PHY_TYPE_OFDM;
2562
0
  case HOSTAPD_MODE_IEEE80211B:
2563
0
    return PHY_TYPE_HRDSSS;
2564
0
  case HOSTAPD_MODE_IEEE80211G:
2565
0
    return PHY_TYPE_ERP;
2566
0
  case HOSTAPD_MODE_IEEE80211AD:
2567
0
    return PHY_TYPE_DMG;
2568
0
  default:
2569
0
    return PHY_TYPE_UNSPECIFIED;
2570
0
  };
2571
0
}
2572
2573
2574
/* ieee80211_get_phy_type - Derive the phy type by freq and bandwidth */
2575
enum phy_type ieee80211_get_phy_type(int freq, bool ht, bool vht, bool he)
2576
0
{
2577
0
  if (he)
2578
0
    return PHY_TYPE_HE;
2579
0
  if (vht)
2580
0
    return PHY_TYPE_VHT;
2581
0
  if (ht)
2582
0
    return PHY_TYPE_HT;
2583
2584
0
  return ieee80211_phy_type_by_freq(freq);
2585
0
}
2586
2587
2588
size_t global_op_class_size = ARRAY_SIZE(global_op_class);
2589
2590
2591
/**
2592
 * get_ie - Fetch a specified information element from IEs buffer
2593
 * @ies: Information elements buffer
2594
 * @len: Information elements buffer length
2595
 * @eid: Information element identifier (WLAN_EID_*)
2596
 * Returns: Pointer to the information element (id field) or %NULL if not found
2597
 *
2598
 * This function returns the first matching information element in the IEs
2599
 * buffer or %NULL in case the element is not found.
2600
 */
2601
const u8 * get_ie(const u8 *ies, size_t len, u8 eid)
2602
0
{
2603
0
  const struct element *elem;
2604
2605
0
  if (!ies)
2606
0
    return NULL;
2607
2608
0
  for_each_element_id(elem, eid, ies, len)
2609
0
    return &elem->id;
2610
2611
0
  return NULL;
2612
0
}
2613
2614
2615
/**
2616
 * get_ie_ext - Fetch a specified extended information element from IEs buffer
2617
 * @ies: Information elements buffer
2618
 * @len: Information elements buffer length
2619
 * @ext: Information element extension identifier (WLAN_EID_EXT_*)
2620
 * Returns: Pointer to the information element (id field) or %NULL if not found
2621
 *
2622
 * This function returns the first matching information element in the IEs
2623
 * buffer or %NULL in case the element is not found.
2624
 */
2625
const u8 * get_ie_ext(const u8 *ies, size_t len, u8 ext)
2626
0
{
2627
0
  const struct element *elem;
2628
2629
0
  if (!ies)
2630
0
    return NULL;
2631
2632
0
  for_each_element_extid(elem, ext, ies, len)
2633
0
    return &elem->id;
2634
2635
0
  return NULL;
2636
0
}
2637
2638
2639
const u8 * get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type)
2640
0
{
2641
0
  const struct element *elem;
2642
2643
0
  if (!ies)
2644
0
    return NULL;
2645
2646
0
  for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, len) {
2647
0
    if (elem->datalen >= 4 &&
2648
0
        vendor_type == WPA_GET_BE32(elem->data))
2649
0
      return &elem->id;
2650
0
  }
2651
2652
0
  return NULL;
2653
0
}
2654
2655
2656
size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len)
2657
0
{
2658
  /*
2659
   * MBO IE requires 6 bytes without the attributes: EID (1), length (1),
2660
   * OUI (3), OUI type (1).
2661
   */
2662
0
  if (len < 6 + attr_len) {
2663
0
    wpa_printf(MSG_DEBUG,
2664
0
         "MBO: Not enough room in buffer for MBO IE: buf len = %zu, attr_len = %zu",
2665
0
         len, attr_len);
2666
0
    return 0;
2667
0
  }
2668
2669
0
  *buf++ = WLAN_EID_VENDOR_SPECIFIC;
2670
0
  *buf++ = attr_len + 4;
2671
0
  WPA_PUT_BE24(buf, OUI_WFA);
2672
0
  buf += 3;
2673
0
  *buf++ = MBO_OUI_TYPE;
2674
0
  os_memcpy(buf, attr, attr_len);
2675
2676
0
  return 6 + attr_len;
2677
0
}
2678
2679
2680
u16 check_multi_ap_ie(const u8 *multi_ap_ie, size_t multi_ap_len,
2681
          struct multi_ap_params *multi_ap)
2682
0
{
2683
0
  const struct element *elem;
2684
0
  bool ext_present = false;
2685
0
  unsigned int vlan_id;
2686
2687
0
  os_memset(multi_ap, 0, sizeof(*multi_ap));
2688
2689
  /* Default profile is 1, when Multi-AP profile subelement is not
2690
   * present in the element. */
2691
0
  multi_ap->profile = 1;
2692
2693
0
  for_each_element(elem, multi_ap_ie, multi_ap_len) {
2694
0
    u8 id = elem->id, elen = elem->datalen;
2695
0
    const u8 *pos = elem->data;
2696
2697
0
    switch (id) {
2698
0
    case MULTI_AP_SUB_ELEM_TYPE:
2699
0
      if (elen >= 1) {
2700
0
        multi_ap->capability = *pos;
2701
0
        ext_present = true;
2702
0
      } else {
2703
0
        wpa_printf(MSG_DEBUG,
2704
0
             "Multi-AP invalid Multi-AP subelement");
2705
0
        return WLAN_STATUS_INVALID_IE;
2706
0
      }
2707
0
      break;
2708
0
    case MULTI_AP_PROFILE_SUB_ELEM_TYPE:
2709
0
      if (elen < 1) {
2710
0
        wpa_printf(MSG_DEBUG,
2711
0
             "Multi-AP IE invalid Multi-AP profile subelement");
2712
0
        return WLAN_STATUS_INVALID_IE;
2713
0
      }
2714
2715
0
      multi_ap->profile = *pos;
2716
0
      if (multi_ap->profile > MULTI_AP_PROFILE_MAX) {
2717
0
        wpa_printf(MSG_DEBUG,
2718
0
             "Multi-AP IE with invalid profile 0x%02x",
2719
0
             multi_ap->profile);
2720
0
        return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
2721
0
      }
2722
0
      break;
2723
0
    case MULTI_AP_VLAN_SUB_ELEM_TYPE:
2724
0
      if (multi_ap->profile < MULTI_AP_PROFILE_2) {
2725
0
        wpa_printf(MSG_DEBUG,
2726
0
             "Multi-AP IE invalid profile to read VLAN IE");
2727
0
        return WLAN_STATUS_INVALID_IE;
2728
0
      }
2729
0
      if (elen < 2) {
2730
0
        wpa_printf(MSG_DEBUG,
2731
0
             "Multi-AP IE invalid Multi-AP VLAN subelement");
2732
0
        return WLAN_STATUS_INVALID_IE;
2733
0
      }
2734
2735
0
      vlan_id = WPA_GET_LE16(pos);
2736
0
      if (vlan_id < 1 || vlan_id > 4094) {
2737
0
        wpa_printf(MSG_INFO,
2738
0
             "Multi-AP IE invalid Multi-AP VLAN ID %d",
2739
0
             vlan_id);
2740
0
        return WLAN_STATUS_INVALID_IE;
2741
0
      }
2742
0
      multi_ap->vlanid = vlan_id;
2743
0
      break;
2744
0
    default:
2745
0
      wpa_printf(MSG_DEBUG,
2746
0
           "Ignore unknown subelement %u in Multi-AP IE",
2747
0
           id);
2748
0
      break;
2749
0
    }
2750
0
  }
2751
2752
0
  if (!for_each_element_completed(elem, multi_ap_ie, multi_ap_len)) {
2753
0
    wpa_printf(MSG_DEBUG, "Multi AP IE parse failed @%d",
2754
0
         (int) (multi_ap_ie + multi_ap_len -
2755
0
          (const u8 *) elem));
2756
0
    wpa_hexdump(MSG_MSGDUMP, "IEs", multi_ap_ie, multi_ap_len);
2757
0
  }
2758
2759
0
  if (!ext_present) {
2760
0
    wpa_printf(MSG_DEBUG,
2761
0
         "Multi-AP element without Multi-AP Extension subelement");
2762
0
    return WLAN_STATUS_INVALID_IE;
2763
0
  }
2764
2765
0
  return WLAN_STATUS_SUCCESS;
2766
0
}
2767
2768
2769
size_t add_multi_ap_ie(u8 *buf, size_t len,
2770
           const struct multi_ap_params *multi_ap)
2771
0
{
2772
0
  u8 *pos = buf;
2773
0
  u8 *len_ptr;
2774
2775
0
  if (len < 6)
2776
0
    return 0;
2777
2778
0
  *pos++ = WLAN_EID_VENDOR_SPECIFIC;
2779
0
  len_ptr = pos; /* Length field to be set at the end */
2780
0
  pos++;
2781
0
  WPA_PUT_BE24(pos, OUI_WFA);
2782
0
  pos += 3;
2783
0
  *pos++ = MULTI_AP_OUI_TYPE;
2784
2785
  /* Multi-AP Extension subelement */
2786
0
  if (buf + len - pos < 3)
2787
0
    return 0;
2788
0
  *pos++ = MULTI_AP_SUB_ELEM_TYPE;
2789
0
  *pos++ = 1; /* len */
2790
0
  *pos++ = multi_ap->capability;
2791
2792
  /* Add Multi-AP Profile subelement only for R2 or newer configuration */
2793
0
  if (multi_ap->profile >= MULTI_AP_PROFILE_2) {
2794
0
    if (buf + len - pos < 3)
2795
0
      return 0;
2796
0
    *pos++ = MULTI_AP_PROFILE_SUB_ELEM_TYPE;
2797
0
    *pos++ = 1;
2798
0
    *pos++ = multi_ap->profile;
2799
0
  }
2800
2801
  /* Add Multi-AP Default 802.1Q Setting subelement only for backhaul BSS
2802
   */
2803
0
  if (multi_ap->vlanid &&
2804
0
      multi_ap->profile >= MULTI_AP_PROFILE_2 &&
2805
0
      (multi_ap->capability & MULTI_AP_BACKHAUL_BSS)) {
2806
0
    if (buf + len - pos < 4)
2807
0
      return 0;
2808
0
    *pos++ = MULTI_AP_VLAN_SUB_ELEM_TYPE;
2809
0
    *pos++ = 2;
2810
0
    WPA_PUT_LE16(pos, multi_ap->vlanid);
2811
0
    pos += 2;
2812
0
  }
2813
2814
0
  *len_ptr = pos - len_ptr - 1;
2815
2816
0
  return pos - buf;
2817
0
}
2818
2819
2820
static const struct country_op_class us_op_class[] = {
2821
  { 1, 115 },
2822
  { 2, 118 },
2823
  { 3, 124 },
2824
  { 4, 121 },
2825
  { 5, 125 },
2826
  { 12, 81 },
2827
  { 22, 116 },
2828
  { 23, 119 },
2829
  { 24, 122 },
2830
  { 25, 126 },
2831
  { 26, 126 },
2832
  { 27, 117 },
2833
  { 28, 120 },
2834
  { 29, 123 },
2835
  { 30, 127 },
2836
  { 31, 127 },
2837
  { 32, 83 },
2838
  { 33, 84 },
2839
  { 34, 180 },
2840
};
2841
2842
static const struct country_op_class eu_op_class[] = {
2843
  { 1, 115 },
2844
  { 2, 118 },
2845
  { 3, 121 },
2846
  { 4, 81 },
2847
  { 5, 116 },
2848
  { 6, 119 },
2849
  { 7, 122 },
2850
  { 8, 117 },
2851
  { 9, 120 },
2852
  { 10, 123 },
2853
  { 11, 83 },
2854
  { 12, 84 },
2855
  { 17, 125 },
2856
  { 18, 180 },
2857
};
2858
2859
static const struct country_op_class jp_op_class[] = {
2860
  { 1, 115 },
2861
  { 30, 81 },
2862
  { 31, 82 },
2863
  { 32, 118 },
2864
  { 33, 118 },
2865
  { 34, 121 },
2866
  { 35, 121 },
2867
  { 36, 116 },
2868
  { 37, 119 },
2869
  { 38, 119 },
2870
  { 39, 122 },
2871
  { 40, 122 },
2872
  { 41, 117 },
2873
  { 42, 120 },
2874
  { 43, 120 },
2875
  { 44, 123 },
2876
  { 45, 123 },
2877
  { 56, 83 },
2878
  { 57, 84 },
2879
  { 58, 121 },
2880
  { 59, 180 },
2881
};
2882
2883
static const struct country_op_class cn_op_class[] = {
2884
  { 1, 115 },
2885
  { 2, 118 },
2886
  { 3, 125 },
2887
  { 4, 116 },
2888
  { 5, 119 },
2889
  { 6, 126 },
2890
  { 7, 81 },
2891
  { 8, 83 },
2892
  { 9, 84 },
2893
};
2894
2895
static u8
2896
global_op_class_from_country_array(u8 op_class, size_t array_size,
2897
           const struct country_op_class *country_array)
2898
0
{
2899
0
  size_t i;
2900
2901
0
  for (i = 0; i < array_size; i++) {
2902
0
    if (country_array[i].country_op_class == op_class)
2903
0
      return country_array[i].global_op_class;
2904
0
  }
2905
2906
0
  return 0;
2907
0
}
2908
2909
2910
u8 country_to_global_op_class(const char *country, u8 op_class)
2911
0
{
2912
0
  const struct country_op_class *country_array;
2913
0
  size_t size;
2914
0
  u8 g_op_class;
2915
2916
0
  if (country_match(us_op_class_cc, country)) {
2917
0
    country_array = us_op_class;
2918
0
    size = ARRAY_SIZE(us_op_class);
2919
0
  } else if (country_match(eu_op_class_cc, country)) {
2920
0
    country_array = eu_op_class;
2921
0
    size = ARRAY_SIZE(eu_op_class);
2922
0
  } else if (country_match(jp_op_class_cc, country)) {
2923
0
    country_array = jp_op_class;
2924
0
    size = ARRAY_SIZE(jp_op_class);
2925
0
  } else if (country_match(cn_op_class_cc, country)) {
2926
0
    country_array = cn_op_class;
2927
0
    size = ARRAY_SIZE(cn_op_class);
2928
0
  } else {
2929
    /*
2930
     * Countries that do not match any of the above countries use
2931
     * global operating classes
2932
     */
2933
0
    return op_class;
2934
0
  }
2935
2936
0
  g_op_class = global_op_class_from_country_array(op_class, size,
2937
0
              country_array);
2938
2939
  /*
2940
   * If the given operating class did not match any of the country's
2941
   * operating classes, assume that global operating class is used.
2942
   */
2943
0
  return g_op_class ? g_op_class : op_class;
2944
0
}
2945
2946
2947
const struct oper_class_map * get_oper_class(const char *country, u8 op_class)
2948
0
{
2949
0
  const struct oper_class_map *op;
2950
2951
0
  if (country)
2952
0
    op_class = country_to_global_op_class(country, op_class);
2953
2954
0
  op = &global_op_class[0];
2955
0
  while (op->op_class && op->op_class != op_class)
2956
0
    op++;
2957
2958
0
  if (!op->op_class)
2959
0
    return NULL;
2960
2961
0
  return op;
2962
0
}
2963
2964
2965
int oper_class_bw_to_int(const struct oper_class_map *map)
2966
0
{
2967
0
  switch (map->bw) {
2968
0
  case BW20:
2969
0
    return 20;
2970
0
  case BW40:
2971
0
  case BW40PLUS:
2972
0
  case BW40MINUS:
2973
0
    return 40;
2974
0
  case BW80:
2975
0
    return 80;
2976
0
  case BW80P80:
2977
0
  case BW160:
2978
0
    return 160;
2979
0
  case BW320:
2980
0
    return 320;
2981
0
  case BW2160:
2982
0
    return 2160;
2983
0
  default:
2984
0
    return 0;
2985
0
  }
2986
0
}
2987
2988
2989
bool is_24ghz_freq(int freq)
2990
0
{
2991
0
  return freq >= 2400 && freq <= 2484;
2992
0
}
2993
2994
2995
bool is_5ghz_freq(int freq)
2996
0
{
2997
0
  return freq >= 5150 && freq <= 5885;
2998
0
}
2999
3000
3001
int center_idx_to_bw_6ghz(u8 idx)
3002
0
{
3003
  /* Channel: 2 */
3004
0
  if (idx == 2)
3005
0
    return 0; /* 20 MHz */
3006
  /* channels: 1, 5, 9, 13... */
3007
0
  if ((idx & 0x3) == 0x1)
3008
0
    return 0; /* 20 MHz */
3009
  /* channels 3, 11, 19... */
3010
0
  if ((idx & 0x7) == 0x3)
3011
0
    return 1; /* 40 MHz */
3012
  /* channels 7, 23, 39.. */
3013
0
  if ((idx & 0xf) == 0x7)
3014
0
    return 2; /* 80 MHz */
3015
  /* channels 15, 47, 79...*/
3016
0
  if ((idx & 0x1f) == 0xf)
3017
0
    return 3; /* 160 MHz */
3018
  /* channels 31, 63, 95, 127, 159, 191 */
3019
0
  if ((idx & 0x1f) == 0x1f && idx < 192)
3020
0
    return 4; /* 320 MHz */
3021
3022
0
  return -1;
3023
0
}
3024
3025
3026
bool is_6ghz_freq(int freq)
3027
0
{
3028
0
  if (freq < 5935 || freq > 7115)
3029
0
    return false;
3030
3031
0
  if (freq == 5935)
3032
0
    return true;
3033
3034
0
  if (center_idx_to_bw_6ghz((freq - 5950) / 5) < 0)
3035
0
    return false;
3036
3037
0
  return true;
3038
0
}
3039
3040
3041
bool is_6ghz_op_class(u8 op_class)
3042
0
{
3043
0
  return op_class >= 131 && op_class <= 137;
3044
0
}
3045
3046
3047
bool is_6ghz_psc_frequency(int freq)
3048
0
{
3049
0
  int i;
3050
3051
0
  if (!is_6ghz_freq(freq) || freq == 5935)
3052
0
    return false;
3053
0
  if ((((freq - 5950) / 5) & 0x3) != 0x1)
3054
0
    return false;
3055
3056
0
  i = (freq - 5950 + 55) % 80;
3057
0
  if (i == 0)
3058
0
    i = (freq - 5950 + 55) / 80;
3059
3060
0
  if (i >= 1 && i <= 15)
3061
0
    return true;
3062
3063
0
  return false;
3064
0
}
3065
3066
3067
/**
3068
 * get_6ghz_sec_channel - Get the relative position of the secondary channel
3069
 * to the primary channel in 6 GHz
3070
 * @channel: Primary channel to be checked for (in global op class 131)
3071
 * Returns: 1 = secondary channel above, -1 = secondary channel below
3072
 */
3073
3074
int get_6ghz_sec_channel(int channel)
3075
0
{
3076
  /*
3077
   * In the 6 GHz band, primary channels are numbered as 1, 5, 9, 13.., so
3078
   * the 40 MHz channels are formed with the channel pairs as (1,5),
3079
   * (9,13), (17,21)..
3080
   * The secondary channel for a given primary channel is below the
3081
   * primary channel for the channels 5, 13, 21.. and it is above the
3082
   * primary channel for the channels 1, 9, 17..
3083
   */
3084
3085
0
  if (((channel - 1) / 4) % 2)
3086
0
    return -1;
3087
0
  return 1;
3088
0
}
3089
3090
3091
bool is_same_band(int freq1, int freq2)
3092
0
{
3093
0
  if (IS_2P4GHZ(freq1) && IS_2P4GHZ(freq2))
3094
0
    return true;
3095
3096
0
  if (IS_5GHZ(freq1) && IS_5GHZ(freq2))
3097
0
    return true;
3098
3099
0
  if (is_6ghz_freq(freq1) && is_6ghz_freq(freq2))
3100
0
    return true;
3101
3102
0
  return false;
3103
0
}
3104
3105
3106
int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
3107
            size_t nei_rep_len)
3108
0
{
3109
0
  u8 *nei_pos = nei_rep;
3110
0
  const char *end;
3111
3112
  /*
3113
   * BSS Transition Candidate List Entries - Neighbor Report elements
3114
   * neighbor=<BSSID>,<BSSID Information>,<Operating Class>,
3115
   * <Channel Number>,<PHY Type>[,<hexdump of Optional Subelements>]
3116
   */
3117
0
  while (pos) {
3118
0
    u8 *nei_start;
3119
0
    long int val;
3120
0
    char *endptr, *tmp;
3121
3122
0
    pos = os_strstr(pos, " neighbor=");
3123
0
    if (!pos)
3124
0
      break;
3125
0
    if (nei_pos + 15 > nei_rep + nei_rep_len) {
3126
0
      wpa_printf(MSG_DEBUG,
3127
0
           "Not enough room for additional neighbor");
3128
0
      return -1;
3129
0
    }
3130
0
    pos += 10;
3131
3132
0
    nei_start = nei_pos;
3133
0
    *nei_pos++ = WLAN_EID_NEIGHBOR_REPORT;
3134
0
    nei_pos++; /* length to be filled in */
3135
3136
0
    if (hwaddr_aton(pos, nei_pos)) {
3137
0
      wpa_printf(MSG_DEBUG, "Invalid BSSID");
3138
0
      return -1;
3139
0
    }
3140
0
    nei_pos += ETH_ALEN;
3141
0
    pos += 17;
3142
0
    if (*pos != ',') {
3143
0
      wpa_printf(MSG_DEBUG, "Missing BSSID Information");
3144
0
      return -1;
3145
0
    }
3146
0
    pos++;
3147
3148
0
    val = strtol(pos, &endptr, 0);
3149
0
    WPA_PUT_LE32(nei_pos, val);
3150
0
    nei_pos += 4;
3151
0
    if (*endptr != ',') {
3152
0
      wpa_printf(MSG_DEBUG, "Missing Operating Class");
3153
0
      return -1;
3154
0
    }
3155
0
    pos = endptr + 1;
3156
3157
0
    *nei_pos++ = atoi(pos); /* Operating Class */
3158
0
    pos = os_strchr(pos, ',');
3159
0
    if (pos == NULL) {
3160
0
      wpa_printf(MSG_DEBUG, "Missing Channel Number");
3161
0
      return -1;
3162
0
    }
3163
0
    pos++;
3164
3165
0
    *nei_pos++ = atoi(pos); /* Channel Number */
3166
0
    pos = os_strchr(pos, ',');
3167
0
    if (pos == NULL) {
3168
0
      wpa_printf(MSG_DEBUG, "Missing PHY Type");
3169
0
      return -1;
3170
0
    }
3171
0
    pos++;
3172
3173
0
    *nei_pos++ = atoi(pos); /* PHY Type */
3174
0
    end = os_strchr(pos, ' ');
3175
0
    tmp = os_strchr(pos, ',');
3176
0
    if (tmp && (!end || tmp < end)) {
3177
      /* Optional Subelements (hexdump) */
3178
0
      size_t len;
3179
3180
0
      pos = tmp + 1;
3181
0
      end = os_strchr(pos, ' ');
3182
0
      if (end)
3183
0
        len = end - pos;
3184
0
      else
3185
0
        len = os_strlen(pos);
3186
0
      if (nei_pos + len / 2 > nei_rep + nei_rep_len) {
3187
0
        wpa_printf(MSG_DEBUG,
3188
0
             "Not enough room for neighbor subelements");
3189
0
        return -1;
3190
0
      }
3191
0
      if (len & 0x01 ||
3192
0
          hexstr2bin(pos, nei_pos, len / 2) < 0) {
3193
0
        wpa_printf(MSG_DEBUG,
3194
0
             "Invalid neighbor subelement info");
3195
0
        return -1;
3196
0
      }
3197
0
      nei_pos += len / 2;
3198
0
      pos = end;
3199
0
    }
3200
3201
0
    nei_start[1] = nei_pos - nei_start - 2;
3202
0
  }
3203
3204
0
  return nei_pos - nei_rep;
3205
0
}
3206
3207
3208
int ieee802_11_ext_capab(const u8 *ie, unsigned int capab)
3209
0
{
3210
0
  if (!ie || ie[1] <= capab / 8)
3211
0
    return 0;
3212
0
  return !!(ie[2 + capab / 8] & BIT(capab % 8));
3213
0
}
3214
3215
3216
bool ieee802_11_rsnx_capab_len(const u8 *rsnxe, size_t rsnxe_len,
3217
             unsigned int capab)
3218
0
{
3219
0
  const u8 *end;
3220
0
  size_t flen, i;
3221
0
  u32 capabs = 0;
3222
3223
0
  if (!rsnxe || rsnxe_len == 0)
3224
0
    return false;
3225
0
  end = rsnxe + rsnxe_len;
3226
0
  flen = (rsnxe[0] & 0x0f) + 1;
3227
0
  if (rsnxe + flen > end)
3228
0
    return false;
3229
0
  if (flen > 4)
3230
0
    flen = 4;
3231
0
  for (i = 0; i < flen; i++)
3232
0
    capabs |= (u32) rsnxe[i] << (8 * i);
3233
3234
0
  return !!(capabs & BIT(capab));
3235
0
}
3236
3237
3238
bool ieee802_11_rsnx_capab(const u8 *rsnxe, unsigned int capab)
3239
0
{
3240
0
  if (!rsnxe)
3241
0
    return false;
3242
0
  if (rsnxe[0] == WLAN_EID_VENDOR_SPECIFIC && rsnxe[1] >= 4 + 1)
3243
0
    return ieee802_11_rsnx_capab_len(rsnxe + 2 + 4, rsnxe[1] - 4,
3244
0
             capab);
3245
0
  return ieee802_11_rsnx_capab_len(rsnxe + 2, rsnxe[1], capab);
3246
0
}
3247
3248
3249
void hostapd_encode_edmg_chan(int edmg_enable, u8 edmg_channel,
3250
            int primary_channel,
3251
            struct ieee80211_edmg_config *edmg)
3252
0
{
3253
0
  if (!edmg_enable) {
3254
0
    edmg->channels = 0;
3255
0
    edmg->bw_config = 0;
3256
0
    return;
3257
0
  }
3258
3259
  /* Only EDMG CB1 and EDMG CB2 contiguous channels supported for now */
3260
0
  switch (edmg_channel) {
3261
0
  case EDMG_CHANNEL_9:
3262
0
    edmg->channels = EDMG_CHANNEL_9_SUBCHANNELS;
3263
0
    edmg->bw_config = EDMG_BW_CONFIG_5;
3264
0
    return;
3265
0
  case EDMG_CHANNEL_10:
3266
0
    edmg->channels = EDMG_CHANNEL_10_SUBCHANNELS;
3267
0
    edmg->bw_config = EDMG_BW_CONFIG_5;
3268
0
    return;
3269
0
  case EDMG_CHANNEL_11:
3270
0
    edmg->channels = EDMG_CHANNEL_11_SUBCHANNELS;
3271
0
    edmg->bw_config = EDMG_BW_CONFIG_5;
3272
0
    return;
3273
0
  case EDMG_CHANNEL_12:
3274
0
    edmg->channels = EDMG_CHANNEL_12_SUBCHANNELS;
3275
0
    edmg->bw_config = EDMG_BW_CONFIG_5;
3276
0
    return;
3277
0
  case EDMG_CHANNEL_13:
3278
0
    edmg->channels = EDMG_CHANNEL_13_SUBCHANNELS;
3279
0
    edmg->bw_config = EDMG_BW_CONFIG_5;
3280
0
    return;
3281
0
  default:
3282
0
    if (primary_channel > 0 && primary_channel < 7) {
3283
0
      edmg->channels = BIT(primary_channel - 1);
3284
0
      edmg->bw_config = EDMG_BW_CONFIG_4;
3285
0
    } else {
3286
0
      edmg->channels = 0;
3287
0
      edmg->bw_config = 0;
3288
0
    }
3289
0
    break;
3290
0
  }
3291
0
}
3292
3293
3294
/* Check if the requested EDMG configuration is a subset of the allowed
3295
 * EDMG configuration. */
3296
int ieee802_edmg_is_allowed(struct ieee80211_edmg_config allowed,
3297
          struct ieee80211_edmg_config requested)
3298
0
{
3299
  /*
3300
   * The validation check if the requested EDMG configuration
3301
   * is a subset of the allowed EDMG configuration:
3302
   * 1. Check that the requested channels are part (set) of the allowed
3303
   * channels.
3304
   * 2. P802.11ay defines the values of bw_config between 4 and 15.
3305
   * (bw config % 4) will give us 4 groups inside bw_config definition,
3306
   * inside each group we can check the subset just by comparing the
3307
   * bw_config value.
3308
   * Between this 4 groups, there is no subset relation - as a result of
3309
   * the P802.11ay definition.
3310
   * bw_config defined by IEEE P802.11ay/D4.0, 9.4.2.251, Table 13.
3311
   */
3312
0
  if (((requested.channels & allowed.channels) != requested.channels) ||
3313
0
      ((requested.bw_config % 4) > (allowed.bw_config % 4)) ||
3314
0
      requested.bw_config > allowed.bw_config)
3315
0
    return 0;
3316
3317
0
  return 1;
3318
0
}
3319
3320
3321
int op_class_to_bandwidth(u8 op_class)
3322
0
{
3323
0
  switch (op_class) {
3324
0
  case 81:
3325
0
  case 82:
3326
0
    return 20;
3327
0
  case 83: /* channels 1..9; 40 MHz */
3328
0
  case 84: /* channels 5..13; 40 MHz */
3329
0
    return 40;
3330
0
  case 115: /* channels 36,40,44,48; indoor only */
3331
0
    return 20;
3332
0
  case 116: /* channels 36,44; 40 MHz; indoor only */
3333
0
  case 117: /* channels 40,48; 40 MHz; indoor only */
3334
0
    return 40;
3335
0
  case 118: /* channels 52,56,60,64; dfs */
3336
0
    return 20;
3337
0
  case 119: /* channels 52,60; 40 MHz; dfs */
3338
0
  case 120: /* channels 56,64; 40 MHz; dfs */
3339
0
    return 40;
3340
0
  case 121: /* channels 100-144 */
3341
0
    return 20;
3342
0
  case 122: /* channels 100-140; 40 MHz */
3343
0
  case 123: /* channels 104-144; 40 MHz */
3344
0
    return 40;
3345
0
  case 124: /* channels 149,153,157,161 */
3346
0
  case 125: /* channels 149,153,157,161,165,169,173,177 */
3347
0
    return 20;
3348
0
  case 126: /* channels 149,157,161,165,169,173; 40 MHz */
3349
0
  case 127: /* channels 153..177; 40 MHz */
3350
0
    return 40;
3351
0
  case 128: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80 MHz */
3352
0
    return 80;
3353
0
  case 129: /* center freqs 50, 114, 163; 160 MHz */
3354
0
    return 160;
3355
0
  case 130: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80+80 MHz */
3356
0
    return 80;
3357
0
  case 131: /* UHB channels, 20 MHz: 1, 5, 9.. */
3358
0
    return 20;
3359
0
  case 132: /* UHB channels, 40 MHz: 3, 11, 19.. */
3360
0
    return 40;
3361
0
  case 133: /* UHB channels, 80 MHz: 7, 23, 39.. */
3362
0
    return 80;
3363
0
  case 134: /* UHB channels, 160 MHz: 15, 47, 79.. */
3364
0
  case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
3365
0
    return 160;
3366
0
  case 136: /* UHB channels, 20 MHz: 2 */
3367
0
    return 20;
3368
0
  case 137: /* UHB channels, 320 MHz: 31, 63, 95, 127, 159, 191 */
3369
0
    return 320;
3370
0
  case 180: /* 60 GHz band, channels 1..8 */
3371
0
    return 2160;
3372
0
  case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */
3373
0
    return 4320;
3374
0
  case 182: /* 60 GHz band, EDMG CB3, channels 17..22 */
3375
0
    return 6480;
3376
0
  case 183: /* 60 GHz band, EDMG CB4, channel 25..29 */
3377
0
    return 8640;
3378
0
  default:
3379
0
    return 20;
3380
0
  }
3381
0
}
3382
3383
3384
enum oper_chan_width op_class_to_ch_width(u8 op_class)
3385
0
{
3386
0
  switch (op_class) {
3387
0
  case 81:
3388
0
  case 82:
3389
0
    return CONF_OPER_CHWIDTH_USE_HT;
3390
0
  case 83: /* channels 1..9; 40 MHz */
3391
0
  case 84: /* channels 5..13; 40 MHz */
3392
0
    return CONF_OPER_CHWIDTH_USE_HT;
3393
0
  case 115: /* channels 36,40,44,48; indoor only */
3394
0
    return CONF_OPER_CHWIDTH_USE_HT;
3395
0
  case 116: /* channels 36,44; 40 MHz; indoor only */
3396
0
  case 117: /* channels 40,48; 40 MHz; indoor only */
3397
0
    return CONF_OPER_CHWIDTH_USE_HT;
3398
0
  case 118: /* channels 52,56,60,64; dfs */
3399
0
    return CONF_OPER_CHWIDTH_USE_HT;
3400
0
  case 119: /* channels 52,60; 40 MHz; dfs */
3401
0
  case 120: /* channels 56,64; 40 MHz; dfs */
3402
0
    return CONF_OPER_CHWIDTH_USE_HT;
3403
0
  case 121: /* channels 100-144 */
3404
0
    return CONF_OPER_CHWIDTH_USE_HT;
3405
0
  case 122: /* channels 100-140; 40 MHz */
3406
0
  case 123: /* channels 104-144; 40 MHz */
3407
0
    return CONF_OPER_CHWIDTH_USE_HT;
3408
0
  case 124: /* channels 149,153,157,161 */
3409
0
  case 125: /* channels 149,153,157,161,165,169,171 */
3410
0
    return CONF_OPER_CHWIDTH_USE_HT;
3411
0
  case 126: /* channels 149,157,165, 173; 40 MHz */
3412
0
  case 127: /* channels 153,161,169,177; 40 MHz */
3413
0
    return CONF_OPER_CHWIDTH_USE_HT;
3414
0
  case 128: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80 MHz */
3415
0
    return CONF_OPER_CHWIDTH_80MHZ;
3416
0
  case 129: /* center freqs 50, 114, 163; 160 MHz */
3417
0
    return CONF_OPER_CHWIDTH_160MHZ;
3418
0
  case 130: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80+80 MHz */
3419
0
    return CONF_OPER_CHWIDTH_80P80MHZ;
3420
0
  case 131: /* UHB channels, 20 MHz: 1, 5, 9.. */
3421
0
    return CONF_OPER_CHWIDTH_USE_HT;
3422
0
  case 132: /* UHB channels, 40 MHz: 3, 11, 19.. */
3423
0
    return CONF_OPER_CHWIDTH_USE_HT;
3424
0
  case 133: /* UHB channels, 80 MHz: 7, 23, 39.. */
3425
0
    return CONF_OPER_CHWIDTH_80MHZ;
3426
0
  case 134: /* UHB channels, 160 MHz: 15, 47, 79.. */
3427
0
    return CONF_OPER_CHWIDTH_160MHZ;
3428
0
  case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
3429
0
    return CONF_OPER_CHWIDTH_80P80MHZ;
3430
0
  case 136: /* UHB channels, 20 MHz: 2 */
3431
0
    return CONF_OPER_CHWIDTH_USE_HT;
3432
0
  case 137: /* UHB channels, 320 MHz: 31, 63, 95, 127, 159, 191 */
3433
0
    return CONF_OPER_CHWIDTH_320MHZ;
3434
0
  case 180: /* 60 GHz band, channels 1..8 */
3435
0
    return CONF_OPER_CHWIDTH_2160MHZ;
3436
0
  case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */
3437
0
    return CONF_OPER_CHWIDTH_4320MHZ;
3438
0
  case 182: /* 60 GHz band, EDMG CB3, channels 17..22 */
3439
0
    return CONF_OPER_CHWIDTH_6480MHZ;
3440
0
  case 183: /* 60 GHz band, EDMG CB4, channel 25..29 */
3441
0
    return CONF_OPER_CHWIDTH_8640MHZ;
3442
0
  default:
3443
0
    return CONF_OPER_CHWIDTH_USE_HT;
3444
0
  }
3445
0
}
3446
3447
3448
/**
3449
 * chwidth_freq2_to_ch_width - Determine channel width as enum oper_chan_width
3450
 * @chwidth: Channel width integer
3451
 * @freq2: Value for frequency 2. 0 is not used
3452
 * Returns: enum oper_chan_width, -1 on failure
3453
 */
3454
int chwidth_freq2_to_ch_width(int chwidth, int freq2)
3455
0
{
3456
0
  if (freq2 < 0)
3457
0
    return -1;
3458
0
  if (freq2)
3459
0
    return CONF_OPER_CHWIDTH_80P80MHZ;
3460
3461
0
  switch (chwidth) {
3462
0
  case 0:
3463
0
  case 20:
3464
0
  case 40:
3465
0
    return CONF_OPER_CHWIDTH_USE_HT;
3466
0
  case 80:
3467
0
    return CONF_OPER_CHWIDTH_80MHZ;
3468
0
  case 160:
3469
0
    return CONF_OPER_CHWIDTH_160MHZ;
3470
0
  case 320:
3471
0
    return CONF_OPER_CHWIDTH_320MHZ;
3472
0
  default:
3473
0
    wpa_printf(MSG_DEBUG, "Unknown max oper bandwidth: %d",
3474
0
         chwidth);
3475
0
    return -1;
3476
0
  }
3477
0
}
3478
3479
3480
struct wpabuf * ieee802_11_defrag(const u8 *data, size_t len, bool ext_elem)
3481
0
{
3482
0
  struct wpabuf *buf;
3483
0
  const u8 *pos, *end;
3484
0
  size_t min_defrag_len = ext_elem ? 255 : 256;
3485
3486
0
  if (!data || !len)
3487
0
    return NULL;
3488
3489
0
  if (len < min_defrag_len)
3490
0
    return wpabuf_alloc_copy(data, len);
3491
3492
0
  buf = wpabuf_alloc_copy(data, min_defrag_len - 1);
3493
0
  if (!buf)
3494
0
    return NULL;
3495
3496
0
  pos = &data[min_defrag_len - 1];
3497
0
  end = data + len;
3498
0
  len -= min_defrag_len - 1;
3499
0
  while (len > 2 && pos[0] == WLAN_EID_FRAGMENT && pos[1]) {
3500
0
    int ret;
3501
0
    size_t elen = 2 + pos[1];
3502
3503
0
    if (elen > (size_t) (end - pos) || elen > len)
3504
0
      break;
3505
0
    ret = wpabuf_resize(&buf, pos[1]);
3506
0
    if (ret < 0) {
3507
0
      wpabuf_free(buf);
3508
0
      return NULL;
3509
0
    }
3510
3511
    /* Copy only the fragment data (without the EID and length) */
3512
0
    wpabuf_put_data(buf, &pos[2], pos[1]);
3513
0
    pos += elen;
3514
0
    len -= elen;
3515
0
  }
3516
3517
0
  return buf;
3518
0
}
3519
3520
3521
/**
3522
 * ieee802_11_defrag_mle_subelem - Defragment Multi-Link element subelements
3523
 * @mlbuf: Defragmented mlbuf (defragmented using ieee802_11_defrag())
3524
 * @parent_subelem: Pointer to the subelement which may be fragmented
3525
 * @defrag_len: Defragmented length of the subelement
3526
 * Returns: Number of Fragment subelements parsed on success, -1 otherwise
3527
 *
3528
 * This function defragments a subelement present inside an Multi-Link element.
3529
 * It should be called individually for each subelement.
3530
 *
3531
 * Subelements can use the Fragment subelement if they pack more than 255 bytes
3532
 * of data, see IEEE Std 802.11be-2024, Figure 35-4 - Per-STA Profile subelement
3533
 * fragmentation within a fragmented Multi-Link element.
3534
 */
3535
ssize_t ieee802_11_defrag_mle_subelem(struct wpabuf *mlbuf,
3536
              const u8 *parent_subelem,
3537
              size_t *defrag_len)
3538
0
{
3539
0
  u8 *buf, *pos, *end;
3540
0
  size_t len, subelem_len;
3541
0
  const size_t min_defrag_len = 255;
3542
0
  int num_frag_subelems = 0;
3543
3544
0
  if (!mlbuf || !parent_subelem)
3545
0
    return -1;
3546
3547
0
  buf = wpabuf_mhead_u8(mlbuf);
3548
0
  len = wpabuf_len(mlbuf);
3549
0
  end = buf + len;
3550
3551
0
  *defrag_len = parent_subelem[1];
3552
0
  if (parent_subelem[1] < min_defrag_len)
3553
0
    return 0;
3554
3555
0
  pos = (u8 *) parent_subelem;
3556
0
  if (2 + parent_subelem[1] > end - pos)
3557
0
    return -1;
3558
0
  pos += 2 + parent_subelem[1];
3559
0
  subelem_len = parent_subelem[1];
3560
3561
0
  while (end - pos > 2 &&
3562
0
         pos[0] == MULTI_LINK_SUB_ELEM_ID_FRAGMENT && pos[1]) {
3563
0
    size_t elen = 2 + pos[1];
3564
3565
    /* This Multi-Link parent subelement has more data and is
3566
     * fragmented. */
3567
0
    num_frag_subelems++;
3568
3569
0
    if (elen > (size_t) (end - pos))
3570
0
      return -1;
3571
3572
0
    os_memmove(pos, pos + 2, end - (pos + 2));
3573
0
    end -= 2;
3574
0
    pos += elen - 2;
3575
0
    subelem_len += elen - 2;
3576
3577
    /* Deduct Fragment subelement header */
3578
0
    len -= 2;
3579
0
  }
3580
3581
0
  *defrag_len = subelem_len;
3582
0
  return num_frag_subelems;
3583
0
}
3584
3585
3586
const u8 * get_ml_ie(const u8 *ies, size_t len, u8 type)
3587
0
{
3588
0
  const struct element *elem;
3589
3590
0
  if (!ies)
3591
0
    return NULL;
3592
3593
0
  for_each_element_extid(elem, WLAN_EID_EXT_MULTI_LINK, ies, len) {
3594
0
    if (elem->datalen >= 2 &&
3595
0
        (elem->data[1] & MULTI_LINK_CONTROL_TYPE_MASK) == type)
3596
0
      return &elem->id;
3597
0
  }
3598
3599
0
  return NULL;
3600
0
}
3601
3602
3603
const u8 * get_basic_mle_mld_addr(const u8 *buf, size_t len)
3604
0
{
3605
0
  const size_t mld_addr_pos =
3606
0
    2 /* Control field */ +
3607
0
    1 /* Common Info Length field */;
3608
0
  const size_t fixed_len = mld_addr_pos +
3609
0
    ETH_ALEN /* MLD MAC Address field */;
3610
3611
0
  if (len < fixed_len)
3612
0
    return NULL;
3613
3614
0
  if ((buf[0] & MULTI_LINK_CONTROL_TYPE_MASK) !=
3615
0
      MULTI_LINK_CONTROL_TYPE_BASIC)
3616
0
    return NULL;
3617
3618
0
  return &buf[mld_addr_pos];
3619
0
}
3620
3621
3622
const u8 * get_basic_mle_eml_capa(const u8 *buf, size_t len)
3623
0
{
3624
0
  const struct ieee80211_eht_ml *ml =
3625
0
    (const struct ieee80211_eht_ml *) buf;
3626
0
  u16 ctrl;
3627
0
  size_t eml_capa_pos =
3628
0
    MULTI_LINK_CONTROL_LEN + /* Multi-Link Control field */
3629
0
    1 + /* Common Info Length field (Basic) */
3630
0
    ETH_ALEN; /* MLD MAC Address field (Basic) */
3631
0
  size_t common_info_limit;
3632
0
  u8 common_info_len;
3633
3634
0
  if (len < MULTI_LINK_CONTROL_LEN)
3635
0
    return NULL;
3636
3637
0
  ctrl = le_to_host16(ml->ml_control);
3638
0
  if ((ctrl & MULTI_LINK_CONTROL_TYPE_MASK) !=
3639
0
      MULTI_LINK_CONTROL_TYPE_BASIC)
3640
0
    return NULL;
3641
0
  if (!(ctrl & BASIC_MULTI_LINK_CTRL_PRES_EML_CAPA))
3642
0
    return NULL;
3643
3644
  /* Validate Common Info Length against available data */
3645
0
  common_info_len = buf[MULTI_LINK_CONTROL_LEN];
3646
0
  if (len < (size_t) MULTI_LINK_CONTROL_LEN + common_info_len)
3647
0
    return NULL;
3648
0
  common_info_limit = MULTI_LINK_CONTROL_LEN + common_info_len;
3649
3650
0
  if (ctrl & BASIC_MULTI_LINK_CTRL_PRES_LINK_ID)
3651
0
    eml_capa_pos += EHT_ML_LINK_ID_LEN;
3652
3653
0
  if (ctrl & BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT)
3654
0
    eml_capa_pos++;
3655
3656
0
  if (ctrl & BASIC_MULTI_LINK_CTRL_PRES_MSD_INFO)
3657
0
    eml_capa_pos += 2;
3658
3659
  /* Ensure EML Capabilities field fits within the declared Common Info */
3660
0
  if (eml_capa_pos + EHT_ML_EML_CAPA_LEN > common_info_limit)
3661
0
    return NULL;
3662
3663
0
  return &buf[eml_capa_pos];
3664
0
}
3665
3666
3667
int get_basic_mle_link_id(const u8 *buf, size_t len)
3668
0
{
3669
0
  struct ieee80211_eht_ml *ml = (struct ieee80211_eht_ml *) buf;
3670
0
  u16 ctrl;
3671
0
  size_t link_id_pos =
3672
0
    MULTI_LINK_CONTROL_LEN + /* Multi-Link Control field */
3673
0
    1 + /* Common Info Length field (Basic) */
3674
0
    ETH_ALEN; /* MLD MAC Address field (Basic) */
3675
0
  size_t common_info_limit;
3676
0
  u8 common_info_len;
3677
3678
0
  if (len < MULTI_LINK_CONTROL_LEN)
3679
0
    return -1;
3680
3681
0
  ctrl = le_to_host16(ml->ml_control);
3682
0
  if ((ctrl & MULTI_LINK_CONTROL_TYPE_MASK) !=
3683
0
      MULTI_LINK_CONTROL_TYPE_BASIC)
3684
0
    return -1;
3685
3686
  /* Validate Common Info Length against available data */
3687
0
  common_info_len = buf[MULTI_LINK_CONTROL_LEN];
3688
0
  if (len < (size_t) MULTI_LINK_CONTROL_LEN + common_info_len)
3689
0
    return -1;
3690
0
  common_info_limit = MULTI_LINK_CONTROL_LEN + common_info_len;
3691
3692
0
  if (!(ctrl & BASIC_MULTI_LINK_CTRL_PRES_LINK_ID))
3693
0
    return -1;
3694
3695
0
  if (link_id_pos + EHT_ML_LINK_ID_LEN > common_info_limit)
3696
0
    return -1;
3697
3698
0
  return buf[link_id_pos] & BASIC_MLE_STA_CTRL_LINK_ID_MASK;
3699
0
}
3700
3701
3702
/* Parse HT capabilities to get maximum number of supported spatial streams */
3703
static int
3704
parse_ht_mcs_set_for_max_nss(const struct ieee80211_ht_capabilities *htcaps,
3705
           bool parse_for_rx)
3706
0
{
3707
0
  int i, max_nss_rx = 1;
3708
0
  u8 supported_tx_mcs_set, tx_mcs_set_defined, tx_rx_mcs_set_not_equal;
3709
3710
0
  if (!htcaps)
3711
0
    return max_nss_rx;
3712
3713
0
  for (i = 4; i >= 1; i--) {
3714
0
    if (htcaps->supported_mcs_set[i - 1] > 0) {
3715
0
      max_nss_rx = i;
3716
0
      break;
3717
0
    }
3718
0
  }
3719
0
  if (parse_for_rx)
3720
0
    return max_nss_rx;
3721
3722
0
  supported_tx_mcs_set = htcaps->supported_mcs_set[12];
3723
0
  tx_mcs_set_defined = supported_tx_mcs_set & 0x1;
3724
0
  tx_rx_mcs_set_not_equal = (supported_tx_mcs_set >> 1) & 0x1;
3725
0
  if (tx_mcs_set_defined && tx_rx_mcs_set_not_equal) {
3726
0
    u8 max_nss_tx_field_value = (supported_tx_mcs_set >> 2) & 0x3;
3727
3728
    /*
3729
     * The maximum number of Tx streams is 1 more than the field
3730
     * value.
3731
     */
3732
0
    return max_nss_tx_field_value + 1;
3733
0
  }
3734
3735
0
  return max_nss_rx;
3736
0
}
3737
3738
3739
/* Parse MCS map to get maximum number of supported spatial streams */
3740
static unsigned int parse_mcs_map_for_max_nss(u16 mcs_map,
3741
                unsigned int max_streams_allowed)
3742
0
{
3743
0
  unsigned int i, max_nss = 1;
3744
3745
0
  for (i = max_streams_allowed; i >= 1; i--) {
3746
0
    unsigned int stream_map = (mcs_map >> ((i - 1) * 2)) & 0x3;
3747
3748
    /* 3 means unsupported */
3749
0
    if (stream_map != 3) {
3750
0
      max_nss = i;
3751
0
      break;
3752
0
    }
3753
0
  }
3754
3755
0
  return max_nss;
3756
0
}
3757
3758
3759
/* Parse capabilities elements to get maximum number of supported spatial
3760
 * streams */
3761
unsigned int get_max_nss_capability(struct ieee802_11_elems *elems,
3762
            bool parse_for_rx, enum chan_width bw)
3763
0
{
3764
0
  unsigned int max_nss = 1;
3765
0
  struct ieee80211_ht_capabilities *htcaps =
3766
0
    (struct ieee80211_ht_capabilities *) elems->ht_capabilities;
3767
0
  struct ieee80211_vht_capabilities *vhtcaps =
3768
0
    (struct ieee80211_vht_capabilities *) elems->vht_capabilities;
3769
0
  struct ieee80211_he_capabilities *hecaps =
3770
0
    (struct ieee80211_he_capabilities *) elems->he_capabilities;
3771
0
  le16 mcs_map;
3772
3773
0
  if (hecaps) {
3774
0
    unsigned int max_nss_he;
3775
0
    const u8 *optional = hecaps->optional;
3776
3777
0
    if (bw == CHAN_WIDTH_160) {
3778
0
      const le16 *mcs_160 = (const le16 *) &optional[0];
3779
3780
0
      mcs_map = parse_for_rx ? mcs_160[0] : mcs_160[1];
3781
0
    } else if (bw == CHAN_WIDTH_80P80) {
3782
0
      const le16 *mcs_80p80 = (const le16 *) &optional[4];
3783
3784
0
      mcs_map = parse_for_rx ? mcs_80p80[0] : mcs_80p80[1];
3785
0
    } else {
3786
0
      mcs_map = parse_for_rx ?
3787
0
        hecaps->he_basic_supported_mcs_set.rx_map :
3788
0
        hecaps->he_basic_supported_mcs_set.tx_map;
3789
0
    }
3790
3791
0
    max_nss_he = parse_mcs_map_for_max_nss(
3792
0
      le_to_host16(mcs_map), HE_NSS_MAX_STREAMS);
3793
0
    if (max_nss_he > max_nss)
3794
0
      max_nss = max_nss_he;
3795
0
  } else if (vhtcaps) {
3796
0
    unsigned int max_nss_vht;
3797
3798
0
    mcs_map = parse_for_rx ?
3799
0
      vhtcaps->vht_supported_mcs_set.rx_map :
3800
0
      vhtcaps->vht_supported_mcs_set.tx_map;
3801
0
    max_nss_vht = parse_mcs_map_for_max_nss(
3802
0
      le_to_host16(mcs_map), VHT_RX_NSS_MAX_STREAMS);
3803
0
    if (max_nss_vht > max_nss)
3804
0
      max_nss = max_nss_vht;
3805
0
  } else if (htcaps) {
3806
0
    unsigned int max_nss_ht;
3807
3808
0
    max_nss_ht = parse_ht_mcs_set_for_max_nss(htcaps, parse_for_rx);
3809
0
    if (max_nss_ht > max_nss)
3810
0
      max_nss = max_nss_ht;
3811
0
  }
3812
3813
0
  return max_nss;
3814
0
}
3815
3816
3817
/* Parse VHT/HE capabilities elements to get supported channel width */
3818
struct supported_chan_width
3819
get_supported_channel_width(struct ieee802_11_elems *elems)
3820
0
{
3821
0
  struct supported_chan_width supported_width;
3822
0
  struct ieee80211_vht_capabilities *vhtcaps;
3823
0
  struct ieee80211_he_capabilities *hecaps;
3824
0
  struct ieee80211_eht_capabilities *ehtcaps;
3825
3826
0
  supported_width.is_160_supported = false;
3827
0
  supported_width.is_80p80_supported = false;
3828
0
  supported_width.is_320_supported = false;
3829
0
  if (!elems)
3830
0
    return supported_width;
3831
3832
0
  vhtcaps = (struct ieee80211_vht_capabilities *) elems->vht_capabilities;
3833
0
  hecaps = (struct ieee80211_he_capabilities *) elems->he_capabilities;
3834
0
  ehtcaps = (struct ieee80211_eht_capabilities *) elems->eht_capabilities;
3835
3836
0
  if (vhtcaps) {
3837
0
    u32 vht_capabilities_info =
3838
0
      le_to_host32(vhtcaps->vht_capabilities_info);
3839
3840
0
    if (vht_capabilities_info & VHT_CAP_SUPP_CHAN_WIDTH_160MHZ)
3841
0
      supported_width.is_160_supported = true;
3842
0
    if (vht_capabilities_info &
3843
0
        VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) {
3844
0
      supported_width.is_160_supported = true;
3845
0
      supported_width.is_80p80_supported = true;
3846
0
    }
3847
0
  }
3848
3849
0
  if (hecaps) {
3850
0
    u8 channel_width_set = hecaps->he_phy_capab_info[
3851
0
      HE_PHYCAP_CHANNEL_WIDTH_SET_IDX];
3852
3853
0
    if (channel_width_set &
3854
0
        HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G)
3855
0
      supported_width.is_160_supported = true;
3856
0
    if (channel_width_set &
3857
0
        HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)
3858
0
      supported_width.is_80p80_supported = true;
3859
0
  }
3860
3861
0
  if (ehtcaps) {
3862
0
    if (ehtcaps->phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] &
3863
0
        EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK)
3864
0
      supported_width.is_320_supported = true;
3865
0
  }
3866
3867
0
  return supported_width;
3868
0
}
3869
3870
3871
/*
3872
 * Parse VHT operation info fields to get operation channel width
3873
 * note that VHT operation info fields could come from the VHT Operation element
3874
 * or from the HE Operation element.
3875
 */
3876
static enum chan_width get_vht_operation_channel_width(
3877
  const struct ieee80211_vht_operation *vht_oper_info)
3878
0
{
3879
0
  enum chan_width channel_width = CHAN_WIDTH_UNKNOWN;
3880
0
  u8 seg0, seg1;
3881
3882
0
  switch (vht_oper_info->vht_op_info_chwidth) {
3883
0
  case 1:
3884
0
    seg0 = vht_oper_info->vht_op_info_chan_center_freq_seg0_idx;
3885
0
    seg1 = vht_oper_info->vht_op_info_chan_center_freq_seg1_idx;
3886
0
    if (seg1 && abs(seg1 - seg0) == 8)
3887
0
      channel_width = CHAN_WIDTH_160;
3888
0
    else if (seg1)
3889
0
      channel_width = CHAN_WIDTH_80P80;
3890
0
    else
3891
0
      channel_width = CHAN_WIDTH_80;
3892
0
    break;
3893
0
  case 2:
3894
0
    channel_width = CHAN_WIDTH_160;
3895
0
    break;
3896
0
  case 3:
3897
0
    channel_width = CHAN_WIDTH_80P80;
3898
0
    break;
3899
0
  }
3900
3901
0
  return channel_width;
3902
0
}
3903
3904
3905
/* Parse 6 GHz operation info fields to get operation channel width */
3906
static enum chan_width get_6ghz_operation_channel_width(
3907
  const struct ieee80211_he_6ghz_oper_info *six_ghz_oper_info)
3908
0
{
3909
0
  enum chan_width channel_width = CHAN_WIDTH_UNKNOWN;
3910
0
  u8 seg0, seg1;
3911
3912
0
  switch (six_ghz_oper_info->control &
3913
0
    HE_6GHZ_OPER_INFO_CTRL_CHAN_WIDTH_MASK) {
3914
0
  case 0:
3915
0
    channel_width = CHAN_WIDTH_20;
3916
0
    break;
3917
0
  case 1:
3918
0
    channel_width = CHAN_WIDTH_40;
3919
0
    break;
3920
0
  case 2:
3921
0
    channel_width = CHAN_WIDTH_80;
3922
0
    break;
3923
0
  case 3:
3924
0
    seg0 = six_ghz_oper_info->chan_center_freq_seg0;
3925
0
    seg1 = six_ghz_oper_info->chan_center_freq_seg1;
3926
0
    if (abs(seg1 - seg0) == 8)
3927
0
      channel_width = CHAN_WIDTH_160;
3928
0
    else
3929
0
      channel_width = CHAN_WIDTH_80P80;
3930
0
    break;
3931
0
  }
3932
3933
0
  return channel_width;
3934
0
}
3935
3936
3937
/* Parse HE Operation element to get HE operation channel width */
3938
static enum chan_width get_he_operation_channel_width(
3939
  const struct ieee80211_he_operation *he_oper, size_t he_oper_len)
3940
0
{
3941
0
  enum chan_width channel_width = CHAN_WIDTH_UNKNOWN;
3942
0
  const u8 *he_oper_u8 = (const u8 *) he_oper;
3943
0
  bool is_6ghz_info_present, is_vht_info_present, is_cohosted_bss_present;
3944
0
  size_t expected_len;
3945
3946
0
  if (he_oper_len < HE_OPERATION_ELEM_MIN_LEN)
3947
0
    return channel_width;
3948
3949
0
  is_6ghz_info_present =
3950
0
    he_oper->he_oper_params & HE_OPERATION_6GHZ_OPER_INFO;
3951
0
  is_vht_info_present =
3952
0
    he_oper->he_oper_params & HE_OPERATION_VHT_OPER_INFO;
3953
0
  is_cohosted_bss_present =
3954
0
    he_oper->he_oper_params & HE_OPERATION_COHOSTED_BSS;
3955
0
  expected_len = HE_OPERATION_ELEM_MIN_LEN +
3956
0
    (is_6ghz_info_present ? HE_OPERATION_6GHZ_OPER_INFO_LEN : 0) +
3957
0
    (is_vht_info_present ? HE_OPERATION_VHT_OPER_INFO_LEN : 0) +
3958
0
    (is_cohosted_bss_present ?
3959
0
     HE_OPERATION_COHOSTED_BSSID_INDICATOR_LEN : 0);
3960
3961
0
  if (he_oper_len < expected_len)
3962
0
    return channel_width;
3963
3964
0
  if (is_6ghz_info_present) {
3965
0
    struct ieee80211_he_6ghz_oper_info *six_ghz_oper_info =
3966
0
      (struct ieee80211_he_6ghz_oper_info *)
3967
0
      (he_oper_u8 + HE_OPERATION_ELEM_MIN_LEN +
3968
0
       (is_vht_info_present ?
3969
0
        HE_OPERATION_VHT_OPER_INFO_LEN : 0) +
3970
0
       (is_cohosted_bss_present ?
3971
0
        HE_OPERATION_COHOSTED_BSSID_INDICATOR_LEN : 0));
3972
3973
0
    channel_width =
3974
0
      get_6ghz_operation_channel_width(six_ghz_oper_info);
3975
0
  }
3976
3977
0
  if (channel_width == CHAN_WIDTH_UNKNOWN && is_vht_info_present) {
3978
0
    struct ieee80211_vht_operation *vht_oper_info =
3979
0
      (struct ieee80211_vht_operation *)
3980
0
      (he_oper_u8 + HE_OPERATION_ELEM_MIN_LEN);
3981
3982
0
    channel_width = get_vht_operation_channel_width(vht_oper_info);
3983
0
  }
3984
3985
0
  return channel_width;
3986
0
}
3987
3988
3989
/* Parse EHT Operation element to get EHT operation channel width */
3990
static enum chan_width get_eht_operation_channel_width(
3991
  const struct ieee80211_eht_operation *eht_oper, size_t eht_oper_len)
3992
0
{
3993
0
  if (eht_oper_len < EHT_OPERATION_ELEM_MIN_LEN + EHT_OPER_INFO_MIN_LEN ||
3994
0
      !(eht_oper->oper_params & EHT_OPER_INFO_PRESENT))
3995
0
    return CHAN_WIDTH_UNKNOWN;
3996
3997
0
  switch (eht_oper->oper_info.control & EHT_OPER_CHANNEL_WIDTH_MASK) {
3998
0
  case EHT_OPER_CHANNEL_WIDTH_20MHZ:
3999
0
    return CHAN_WIDTH_20;
4000
0
  case EHT_OPER_CHANNEL_WIDTH_40MHZ:
4001
0
    return CHAN_WIDTH_40;
4002
0
  case EHT_OPER_CHANNEL_WIDTH_80MHZ:
4003
0
    return CHAN_WIDTH_80;
4004
0
  case EHT_OPER_CHANNEL_WIDTH_160MHZ:
4005
0
    return CHAN_WIDTH_160;
4006
0
  case EHT_OPER_CHANNEL_WIDTH_320MHZ:
4007
0
    return CHAN_WIDTH_320;
4008
0
  default:
4009
0
    return CHAN_WIDTH_UNKNOWN;
4010
0
  }
4011
0
}
4012
4013
4014
/* Parse HT/VHT/HE operation elements to get operation channel width */
4015
enum chan_width get_operation_channel_width(struct ieee802_11_elems *elems)
4016
0
{
4017
0
  enum chan_width channel_width = CHAN_WIDTH_UNKNOWN;
4018
0
  struct ieee80211_ht_operation *ht_oper;
4019
0
  struct ieee80211_vht_operation *vht_oper_info;
4020
0
  struct ieee80211_he_operation *he_oper;
4021
0
  struct ieee80211_eht_operation *eht_oper;
4022
4023
0
  if (!elems)
4024
0
    return channel_width;
4025
4026
0
  ht_oper = (struct ieee80211_ht_operation *) elems->ht_operation;
4027
0
  vht_oper_info = (struct ieee80211_vht_operation *) elems->vht_operation;
4028
0
  he_oper = (struct ieee80211_he_operation *) elems->he_operation;
4029
0
  eht_oper = (struct ieee80211_eht_operation *) elems->eht_operation;
4030
4031
0
  if (eht_oper)
4032
0
    channel_width = get_eht_operation_channel_width(
4033
0
      eht_oper, elems->eht_operation_len);
4034
4035
0
  if (channel_width == CHAN_WIDTH_UNKNOWN && he_oper)
4036
0
    channel_width = get_he_operation_channel_width(
4037
0
      he_oper, elems->he_operation_len);
4038
4039
0
  if (channel_width == CHAN_WIDTH_UNKNOWN && vht_oper_info)
4040
0
    channel_width = get_vht_operation_channel_width(vht_oper_info);
4041
4042
0
  if (channel_width == CHAN_WIDTH_UNKNOWN && ht_oper) {
4043
0
    u8 sec_chan_offset = ht_oper->ht_param &
4044
0
      HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK;
4045
4046
0
    channel_width = sec_chan_offset == 0 ?
4047
0
      CHAN_WIDTH_20 : CHAN_WIDTH_40;
4048
0
  }
4049
4050
0
  return channel_width;
4051
0
}
4052
4053
4054
/*
4055
 * Get STA operation channel width from AP's operation channel width and
4056
 * STA's supported channel width
4057
 */
4058
enum chan_width get_sta_operation_chan_width(
4059
  enum chan_width ap_operation_chan_width,
4060
  struct supported_chan_width sta_supported_chan_width)
4061
0
{
4062
0
  if (ap_operation_chan_width == CHAN_WIDTH_320 &&
4063
0
      sta_supported_chan_width.is_320_supported)
4064
0
    return CHAN_WIDTH_320;
4065
4066
0
  if (ap_operation_chan_width == CHAN_WIDTH_160 ||
4067
0
      ap_operation_chan_width == CHAN_WIDTH_320)
4068
0
    return sta_supported_chan_width.is_160_supported ?
4069
0
      CHAN_WIDTH_160 : CHAN_WIDTH_80;
4070
4071
0
  if (ap_operation_chan_width == CHAN_WIDTH_80P80)
4072
0
    return sta_supported_chan_width.is_80p80_supported ?
4073
0
      CHAN_WIDTH_80P80 : CHAN_WIDTH_80;
4074
4075
0
  return ap_operation_chan_width;
4076
0
}