Coverage Report

Created: 2026-10-28 06:04

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