blob: 2e3d9046698a4f8d8990e4743302fda3dd64e742 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * hostapd / IEEE 802.11 Management: Beacon and Probe Request/Response
3 * Copyright (c) 2002-2004, Instant802 Networks, Inc.
4 * Copyright (c) 2005-2006, Devicescape Software, Inc.
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005 * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006 *
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007 * This software may be distributed under the terms of the BSD license.
8 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009 */
10
11#include "utils/includes.h"
12
13#ifndef CONFIG_NATIVE_WINDOWS
14
15#include "utils/common.h"
16#include "common/ieee802_11_defs.h"
17#include "common/ieee802_11_common.h"
Dmitry Shmidt7f656022015-02-25 14:36:37 -080018#include "common/hw_features_common.h"
Roshan Pius3a1667e2018-07-03 15:17:14 -070019#include "common/wpa_ctrl.h"
Sunil Ravi2a14cf12023-11-21 00:54:38 +000020#include "crypto/sha1.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070021#include "wps/wps_defs.h"
22#include "p2p/p2p.h"
23#include "hostapd.h"
24#include "ieee802_11.h"
25#include "wpa_auth.h"
26#include "wmm.h"
27#include "ap_config.h"
28#include "sta_info.h"
29#include "p2p_hostapd.h"
30#include "ap_drv_ops.h"
31#include "beacon.h"
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070032#include "hs20.h"
Dmitry Shmidtf21452a2014-02-26 10:55:25 -080033#include "dfs.h"
Dmitry Shmidtaca489e2016-09-28 15:44:14 -070034#include "taxonomy.h"
Roshan Pius3a1667e2018-07-03 15:17:14 -070035#include "ieee802_11_auth.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070036
37
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080038#ifdef NEED_AP_MLME
39
Dmitry Shmidt051af732013-10-22 13:52:46 -070040static u8 * hostapd_eid_bss_load(struct hostapd_data *hapd, u8 *eid, size_t len)
41{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080042 if (len < 2 + 5)
43 return eid;
44
Dmitry Shmidt051af732013-10-22 13:52:46 -070045#ifdef CONFIG_TESTING_OPTIONS
46 if (hapd->conf->bss_load_test_set) {
Dmitry Shmidt051af732013-10-22 13:52:46 -070047 *eid++ = WLAN_EID_BSS_LOAD;
48 *eid++ = 5;
49 os_memcpy(eid, hapd->conf->bss_load_test, 5);
50 eid += 5;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080051 return eid;
Dmitry Shmidt051af732013-10-22 13:52:46 -070052 }
53#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080054 if (hapd->conf->bss_load_update_period) {
55 *eid++ = WLAN_EID_BSS_LOAD;
56 *eid++ = 5;
57 WPA_PUT_LE16(eid, hapd->num_sta);
58 eid += 2;
59 *eid++ = hapd->iface->channel_utilization;
60 WPA_PUT_LE16(eid, 0); /* no available admission capabity */
61 eid += 2;
62 }
Dmitry Shmidt051af732013-10-22 13:52:46 -070063 return eid;
64}
65
66
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070067static u8 ieee802_11_erp_info(struct hostapd_data *hapd)
68{
69 u8 erp = 0;
70
71 if (hapd->iface->current_mode == NULL ||
72 hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
73 return 0;
74
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080075 if (hapd->iface->olbc)
76 erp |= ERP_INFO_USE_PROTECTION;
77 if (hapd->iface->num_sta_non_erp > 0) {
78 erp |= ERP_INFO_NON_ERP_PRESENT |
79 ERP_INFO_USE_PROTECTION;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070080 }
81 if (hapd->iface->num_sta_no_short_preamble > 0 ||
82 hapd->iconf->preamble == LONG_PREAMBLE)
83 erp |= ERP_INFO_BARKER_PREAMBLE_MODE;
84
85 return erp;
86}
87
88
89static u8 * hostapd_eid_ds_params(struct hostapd_data *hapd, u8 *eid)
90{
Sunil Ravi2a14cf12023-11-21 00:54:38 +000091 enum hostapd_hw_mode hw_mode = hapd->iconf->hw_mode;
92
93 if (hw_mode != HOSTAPD_MODE_IEEE80211G &&
94 hw_mode != HOSTAPD_MODE_IEEE80211B)
95 return eid;
96
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070097 *eid++ = WLAN_EID_DS_PARAMS;
98 *eid++ = 1;
99 *eid++ = hapd->iconf->channel;
100 return eid;
101}
102
103
104static u8 * hostapd_eid_erp_info(struct hostapd_data *hapd, u8 *eid)
105{
106 if (hapd->iface->current_mode == NULL ||
107 hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
108 return eid;
109
110 /* Set NonERP_present and use_protection bits if there
111 * are any associated NonERP stations. */
112 /* TODO: use_protection bit can be set to zero even if
113 * there are NonERP stations present. This optimization
114 * might be useful if NonERP stations are "quiet".
115 * See 802.11g/D6 E-1 for recommended practice.
116 * In addition, Non ERP present might be set, if AP detects Non ERP
117 * operation on other APs. */
118
119 /* Add ERP Information element */
120 *eid++ = WLAN_EID_ERP_INFO;
121 *eid++ = 1;
122 *eid++ = ieee802_11_erp_info(hapd);
123
124 return eid;
125}
126
127
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800128static u8 * hostapd_eid_pwr_constraint(struct hostapd_data *hapd, u8 *eid)
129{
130 u8 *pos = eid;
131 u8 local_pwr_constraint = 0;
132 int dfs;
133
134 if (hapd->iface->current_mode == NULL ||
135 hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
136 return eid;
137
Dmitry Shmidt661b4f72014-09-29 14:58:27 -0700138 /* Let host drivers add this IE if DFS support is offloaded */
139 if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
140 return eid;
141
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800142 /*
143 * There is no DFS support and power constraint was not directly
144 * requested by config option.
145 */
146 if (!hapd->iconf->ieee80211h &&
147 hapd->iconf->local_pwr_constraint == -1)
148 return eid;
149
150 /* Check if DFS is required by regulatory. */
151 dfs = hostapd_is_dfs_required(hapd->iface);
152 if (dfs < 0) {
153 wpa_printf(MSG_WARNING, "Failed to check if DFS is required; ret=%d",
154 dfs);
155 dfs = 0;
156 }
157
158 if (dfs == 0 && hapd->iconf->local_pwr_constraint == -1)
159 return eid;
160
161 /*
162 * ieee80211h (DFS) is enabled so Power Constraint element shall
163 * be added when running on DFS channel whenever local_pwr_constraint
164 * is configured or not. In order to meet regulations when TPC is not
165 * implemented using a transmit power that is below the legal maximum
166 * (including any mitigation factor) should help. In this case,
167 * indicate 3 dB below maximum allowed transmit power.
168 */
169 if (hapd->iconf->local_pwr_constraint == -1)
170 local_pwr_constraint = 3;
171
172 /*
173 * A STA that is not an AP shall use a transmit power less than or
174 * equal to the local maximum transmit power level for the channel.
175 * The local maximum transmit power can be calculated from the formula:
176 * local max TX pwr = max TX pwr - local pwr constraint
177 * Where max TX pwr is maximum transmit power level specified for
178 * channel in Country element and local pwr constraint is specified
179 * for channel in this Power Constraint element.
180 */
181
182 /* Element ID */
183 *pos++ = WLAN_EID_PWR_CONSTRAINT;
184 /* Length */
185 *pos++ = 1;
186 /* Local Power Constraint */
187 if (local_pwr_constraint)
188 *pos++ = local_pwr_constraint;
189 else
190 *pos++ = hapd->iconf->local_pwr_constraint;
191
192 return pos;
193}
194
195
Sunil Ravia04bd252022-05-02 22:54:18 -0700196static u8 * hostapd_eid_country_add(struct hostapd_data *hapd, u8 *pos,
197 u8 *end, int chan_spacing,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700198 struct hostapd_channel_data *start,
199 struct hostapd_channel_data *prev)
200{
201 if (end - pos < 3)
202 return pos;
203
204 /* first channel number */
205 *pos++ = start->chan;
206 /* number of channels */
207 *pos++ = (prev->chan - start->chan) / chan_spacing + 1;
208 /* maximum transmit power level */
Sunil Ravia04bd252022-05-02 22:54:18 -0700209 if (!is_6ghz_op_class(hapd->iconf->op_class))
210 *pos++ = start->max_tx_power;
211 else
212 *pos++ = 0; /* Reserved when operating on the 6 GHz band */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700213
214 return pos;
215}
216
217
Sunil Ravia04bd252022-05-02 22:54:18 -0700218static u8 * hostapd_fill_subband_triplets(struct hostapd_data *hapd, u8 *pos,
219 u8 *end)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700220{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700221 int i;
222 struct hostapd_hw_modes *mode;
223 struct hostapd_channel_data *start, *prev;
224 int chan_spacing = 1;
225
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700226 mode = hapd->iface->current_mode;
227 if (mode->mode == HOSTAPD_MODE_IEEE80211A)
228 chan_spacing = 4;
229
230 start = prev = NULL;
231 for (i = 0; i < mode->num_channels; i++) {
232 struct hostapd_channel_data *chan = &mode->channels[i];
233 if (chan->flag & HOSTAPD_CHAN_DISABLED)
234 continue;
235 if (start && prev &&
236 prev->chan + chan_spacing == chan->chan &&
237 start->max_tx_power == chan->max_tx_power) {
238 prev = chan;
239 continue; /* can use same entry */
240 }
241
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000242 if (start && prev)
Sunil Ravia04bd252022-05-02 22:54:18 -0700243 pos = hostapd_eid_country_add(hapd, pos, end,
244 chan_spacing,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700245 start, prev);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700246
247 /* Start new group */
248 start = prev = chan;
249 }
250
251 if (start) {
Sunil Ravia04bd252022-05-02 22:54:18 -0700252 pos = hostapd_eid_country_add(hapd, pos, end, chan_spacing,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700253 start, prev);
254 }
255
Sunil Ravia04bd252022-05-02 22:54:18 -0700256 return pos;
257}
258
259
260static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
261 int max_len)
262{
263 u8 *pos = eid;
264 u8 *end = eid + max_len;
265
266 if (!hapd->iconf->ieee80211d || max_len < 6 ||
267 hapd->iface->current_mode == NULL)
268 return eid;
269
270 *pos++ = WLAN_EID_COUNTRY;
271 pos++; /* length will be set later */
272 os_memcpy(pos, hapd->iconf->country, 3); /* e.g., 'US ' */
273 pos += 3;
274
275 if (is_6ghz_op_class(hapd->iconf->op_class)) {
276 /* Force the third octet of the country string to indicate
277 * Global Operating Class (Table E-4) */
278 eid[4] = 0x04;
279
280 /* Operating Triplet field */
281 /* Operating Extension Identifier (>= 201 to indicate this is
282 * not a Subband Triplet field) */
283 *pos++ = 201;
284 /* Operating Class */
285 *pos++ = hapd->iconf->op_class;
286 /* Coverage Class */
287 *pos++ = 0;
288 /* Subband Triplets are required only for the 20 MHz case */
289 if (hapd->iconf->op_class == 131 ||
290 hapd->iconf->op_class == 136)
291 pos = hostapd_fill_subband_triplets(hapd, pos, end);
292 } else {
293 pos = hostapd_fill_subband_triplets(hapd, pos, end);
294 }
295
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700296 if ((pos - eid) & 1) {
297 if (end - pos < 1)
298 return eid;
299 *pos++ = 0; /* pad for 16-bit alignment */
300 }
301
302 eid[1] = (pos - eid) - 2;
303
304 return pos;
305}
306
307
Hai Shalom60840252021-02-19 19:02:11 -0800308const u8 * hostapd_wpa_ie(struct hostapd_data *hapd, u8 eid)
Hai Shalomfdcde762020-04-02 11:19:20 -0700309{
310 const u8 *ies;
311 size_t ies_len;
312
313 ies = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ies_len);
314 if (!ies)
315 return NULL;
316
317 return get_ie(ies, ies_len, eid);
318}
319
320
321static const u8 * hostapd_vendor_wpa_ie(struct hostapd_data *hapd,
322 u32 vendor_type)
323{
324 const u8 *ies;
325 size_t ies_len;
326
327 ies = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ies_len);
328 if (!ies)
329 return NULL;
330
331 return get_vendor_ie(ies, ies_len, vendor_type);
332}
333
334
335static u8 * hostapd_get_rsne(struct hostapd_data *hapd, u8 *pos, size_t len)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700336{
337 const u8 *ie;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700338
Hai Shalomfdcde762020-04-02 11:19:20 -0700339 ie = hostapd_wpa_ie(hapd, WLAN_EID_RSN);
340 if (!ie || 2U + ie[1] > len)
341 return pos;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700342
Hai Shalomfdcde762020-04-02 11:19:20 -0700343 os_memcpy(pos, ie, 2 + ie[1]);
344 return pos + 2 + ie[1];
345}
346
347
348static u8 * hostapd_get_mde(struct hostapd_data *hapd, u8 *pos, size_t len)
349{
350 const u8 *ie;
351
352 ie = hostapd_wpa_ie(hapd, WLAN_EID_MOBILITY_DOMAIN);
353 if (!ie || 2U + ie[1] > len)
354 return pos;
355
356 os_memcpy(pos, ie, 2 + ie[1]);
357 return pos + 2 + ie[1];
358}
359
360
361static u8 * hostapd_get_rsnxe(struct hostapd_data *hapd, u8 *pos, size_t len)
362{
363 const u8 *ie;
364
365#ifdef CONFIG_TESTING_OPTIONS
366 if (hapd->conf->no_beacon_rsnxe) {
367 wpa_printf(MSG_INFO, "TESTING: Do not add RSNXE into Beacon");
368 return pos;
369 }
370#endif /* CONFIG_TESTING_OPTIONS */
371 ie = hostapd_wpa_ie(hapd, WLAN_EID_RSNX);
372 if (!ie || 2U + ie[1] > len)
373 return pos;
374
375 os_memcpy(pos, ie, 2 + ie[1]);
376 return pos + 2 + ie[1];
377}
378
379
380static u8 * hostapd_get_wpa_ie(struct hostapd_data *hapd, u8 *pos, size_t len)
381{
382 const u8 *ie;
383
384 ie = hostapd_vendor_wpa_ie(hapd, WPA_IE_VENDOR_TYPE);
385 if (!ie || 2U + ie[1] > len)
386 return pos;
387
388 os_memcpy(pos, ie, 2 + ie[1]);
389 return pos + 2 + ie[1];
390}
391
392
393static u8 * hostapd_get_osen_ie(struct hostapd_data *hapd, u8 *pos, size_t len)
394{
395 const u8 *ie;
396
397 ie = hostapd_vendor_wpa_ie(hapd, OSEN_IE_VENDOR_TYPE);
398 if (!ie || 2U + ie[1] > len)
399 return pos;
400
401 os_memcpy(pos, ie, 2 + ie[1]);
402 return pos + 2 + ie[1];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700403}
404
405
Sunil Ravi7f769292024-07-23 22:21:32 +0000406static u8 * hostapd_get_rsne_override(struct hostapd_data *hapd, u8 *pos,
407 size_t len)
408{
409 const u8 *ie;
410
411 ie = hostapd_vendor_wpa_ie(hapd, RSNE_OVERRIDE_IE_VENDOR_TYPE);
412 if (!ie || 2U + ie[1] > len)
413 return pos;
414
415 os_memcpy(pos, ie, 2 + ie[1]);
416 return pos + 2 + ie[1];
417}
418
419
420static u8 * hostapd_get_rsne_override_2(struct hostapd_data *hapd, u8 *pos,
421 size_t len)
422{
423 const u8 *ie;
424
425 ie = hostapd_vendor_wpa_ie(hapd, RSNE_OVERRIDE_2_IE_VENDOR_TYPE);
426 if (!ie || 2U + ie[1] > len)
427 return pos;
428
429 os_memcpy(pos, ie, 2 + ie[1]);
430 return pos + 2 + ie[1];
431}
432
433
434static u8 * hostapd_get_rsnxe_override(struct hostapd_data *hapd, u8 *pos,
435 size_t len)
436{
437 const u8 *ie;
438
439 ie = hostapd_vendor_wpa_ie(hapd, RSNXE_OVERRIDE_IE_VENDOR_TYPE);
440 if (!ie || 2U + ie[1] > len)
441 return pos;
442
443 os_memcpy(pos, ie, 2 + ie[1]);
444 return pos + 2 + ie[1];
445}
446
447
448static size_t hostapd_get_rsne_override_len(struct hostapd_data *hapd)
449{
450 const u8 *ie;
451
452 ie = hostapd_vendor_wpa_ie(hapd, RSNE_OVERRIDE_IE_VENDOR_TYPE);
453 if (!ie)
454 return 0;
455 return 2 + ie[1];
456}
457
458
459static size_t hostapd_get_rsne_override_2_len(struct hostapd_data *hapd)
460{
461 const u8 *ie;
462
463 ie = hostapd_vendor_wpa_ie(hapd, RSNE_OVERRIDE_2_IE_VENDOR_TYPE);
464 if (!ie)
465 return 0;
466 return 2 + ie[1];
467}
468
469
470static size_t hostapd_get_rsnxe_override_len(struct hostapd_data *hapd)
471{
472 const u8 *ie;
473
474 ie = hostapd_vendor_wpa_ie(hapd, RSNXE_OVERRIDE_IE_VENDOR_TYPE);
475 if (!ie)
476 return 0;
477 return 2 + ie[1];
478}
479
480
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -0800481static u8 * hostapd_eid_csa(struct hostapd_data *hapd, u8 *eid)
482{
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800483#ifdef CONFIG_TESTING_OPTIONS
484 if (hapd->iface->cs_oper_class && hapd->iconf->ecsa_ie_only)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -0800485 return eid;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800486#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -0800487
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800488 if (!hapd->cs_freq_params.channel)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -0800489 return eid;
490
491 *eid++ = WLAN_EID_CHANNEL_SWITCH;
492 *eid++ = 3;
Dmitry Shmidtd30ac602014-06-30 09:54:22 -0700493 *eid++ = hapd->cs_block_tx;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800494 *eid++ = hapd->cs_freq_params.channel;
Dmitry Shmidtd30ac602014-06-30 09:54:22 -0700495 *eid++ = hapd->cs_count;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -0800496
497 return eid;
498}
499
500
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800501static u8 * hostapd_eid_ecsa(struct hostapd_data *hapd, u8 *eid)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800502{
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800503 if (!hapd->cs_freq_params.channel || !hapd->iface->cs_oper_class)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800504 return eid;
505
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800506 *eid++ = WLAN_EID_EXT_CHANSWITCH_ANN;
507 *eid++ = 4;
508 *eid++ = hapd->cs_block_tx;
509 *eid++ = hapd->iface->cs_oper_class;
510 *eid++ = hapd->cs_freq_params.channel;
511 *eid++ = hapd->cs_count;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800512
513 return eid;
514}
515
516
Sunil Ravic0f5d412024-09-11 22:12:49 +0000517static u8 * hostapd_eid_max_cs_time(struct hostapd_data *hapd, u8 *eid)
518{
519#ifdef CONFIG_IEEE80211BE
520 u32 switch_time;
521
522 /* Add Max Channel Switch Time element only if this AP is affiliated
523 * with an AP MLD and channel switch is in process. */
524 if (!hapd->conf->mld_ap || !hapd->cs_freq_params.channel)
525 return eid;
526
527 /* Switch time is basically time between CSA count 1 and CSA count
528 * 0 (1 beacon interval) + time for interface restart + time to
529 * send a Beacon frame in the new channel (1 beacon interval).
530 *
531 * TODO: Use dynamic interface restart time. For now, assume 1 sec.
532 */
533 switch_time = USEC_TO_TU(1000 * 1000) + 2 * hapd->iconf->beacon_int;
534
535 *eid++ = WLAN_EID_EXTENSION;
536 *eid++ = 4;
537 *eid++ = WLAN_EID_EXT_MAX_CHANNEL_SWITCH_TIME;
538 WPA_PUT_LE24(eid, switch_time);
539 eid += 3;
540#endif /* CONFIG_IEEE80211BE */
541
542 return eid;
543}
544
545
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800546static u8 * hostapd_eid_supported_op_classes(struct hostapd_data *hapd, u8 *eid)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800547{
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800548 u8 op_class, channel;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800549
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800550 if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA) ||
551 !hapd->iface->freq)
552 return eid;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800553
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800554 if (ieee80211_freq_to_channel_ext(hapd->iface->freq,
555 hapd->iconf->secondary_channel,
Hai Shalom81f62d82019-07-22 12:10:00 -0700556 hostapd_get_oper_chwidth(hapd->iconf),
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800557 &op_class, &channel) ==
558 NUM_HOSTAPD_MODES)
559 return eid;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800560
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800561 *eid++ = WLAN_EID_SUPPORTED_OPERATING_CLASSES;
562 *eid++ = 2;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800563
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800564 /* Current Operating Class */
565 *eid++ = op_class;
566
567 /* TODO: Advertise all the supported operating classes */
568 *eid++ = 0;
569
570 return eid;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800571}
572
573
Sunil Ravi77d572f2023-01-17 23:58:31 +0000574static int
575ieee802_11_build_ap_params_mbssid(struct hostapd_data *hapd,
576 struct wpa_driver_ap_params *params)
577{
578 struct hostapd_iface *iface = hapd->iface;
579 struct hostapd_data *tx_bss;
Sunil Ravi640215c2023-06-28 23:08:09 +0000580 size_t len, rnr_len = 0;
Sunil Ravi77d572f2023-01-17 23:58:31 +0000581 u8 elem_count = 0, *elem = NULL, **elem_offset = NULL, *end;
Sunil Ravi640215c2023-06-28 23:08:09 +0000582 u8 rnr_elem_count = 0, *rnr_elem = NULL, **rnr_elem_offset = NULL;
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000583 size_t i;
Sunil Ravi77d572f2023-01-17 23:58:31 +0000584
585 if (!iface->mbssid_max_interfaces ||
586 iface->num_bss > iface->mbssid_max_interfaces ||
587 (iface->conf->mbssid == ENHANCED_MBSSID_ENABLED &&
588 !iface->ema_max_periodicity))
589 goto fail;
590
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000591 /* Make sure bss->xrates_supported is set for all BSSs to know whether
592 * it need to be non-inherited. */
593 for (i = 0; i < iface->num_bss; i++) {
594 u8 buf[100];
595
596 hostapd_eid_ext_supp_rates(iface->bss[i], buf);
597 }
598
Sunil Ravi77d572f2023-01-17 23:58:31 +0000599 tx_bss = hostapd_mbssid_get_tx_bss(hapd);
600 len = hostapd_eid_mbssid_len(tx_bss, WLAN_FC_STYPE_BEACON, &elem_count,
Sunil Ravi640215c2023-06-28 23:08:09 +0000601 NULL, 0, &rnr_len);
Sunil Ravi77d572f2023-01-17 23:58:31 +0000602 if (!len || (iface->conf->mbssid == ENHANCED_MBSSID_ENABLED &&
603 elem_count > iface->ema_max_periodicity))
604 goto fail;
605
606 elem = os_zalloc(len);
607 if (!elem)
608 goto fail;
609
610 elem_offset = os_zalloc(elem_count * sizeof(u8 *));
611 if (!elem_offset)
612 goto fail;
613
Sunil Ravi640215c2023-06-28 23:08:09 +0000614 if (rnr_len) {
615 rnr_elem = os_zalloc(rnr_len);
616 if (!rnr_elem)
617 goto fail;
618
619 rnr_elem_offset = os_calloc(elem_count + 1, sizeof(u8 *));
620 if (!rnr_elem_offset)
621 goto fail;
622 }
623
Sunil Ravi77d572f2023-01-17 23:58:31 +0000624 end = hostapd_eid_mbssid(tx_bss, elem, elem + len, WLAN_FC_STYPE_BEACON,
Sunil Ravi640215c2023-06-28 23:08:09 +0000625 elem_count, elem_offset, NULL, 0, rnr_elem,
626 &rnr_elem_count, rnr_elem_offset, rnr_len);
Sunil Ravi77d572f2023-01-17 23:58:31 +0000627
628 params->mbssid_tx_iface = tx_bss->conf->iface;
629 params->mbssid_index = hostapd_mbssid_get_bss_index(hapd);
630 params->mbssid_elem = elem;
631 params->mbssid_elem_len = end - elem;
632 params->mbssid_elem_count = elem_count;
633 params->mbssid_elem_offset = elem_offset;
Sunil Ravi640215c2023-06-28 23:08:09 +0000634 params->rnr_elem = rnr_elem;
635 params->rnr_elem_len = rnr_len;
636 params->rnr_elem_count = rnr_elem_count;
637 params->rnr_elem_offset = rnr_elem_offset;
Sunil Ravi77d572f2023-01-17 23:58:31 +0000638 if (iface->conf->mbssid == ENHANCED_MBSSID_ENABLED)
639 params->ema = true;
640
641 return 0;
642
643fail:
Sunil Ravi640215c2023-06-28 23:08:09 +0000644 os_free(rnr_elem);
645 os_free(rnr_elem_offset);
646 os_free(elem_offset);
Sunil Ravi77d572f2023-01-17 23:58:31 +0000647 os_free(elem);
648 wpa_printf(MSG_ERROR, "MBSSID: Configuration failed");
649 return -1;
650}
651
652
653static u8 * hostapd_eid_mbssid_config(struct hostapd_data *hapd, u8 *eid,
654 u8 mbssid_elem_count)
655{
656 struct hostapd_iface *iface = hapd->iface;
657
658 if (iface->conf->mbssid == ENHANCED_MBSSID_ENABLED) {
659 *eid++ = WLAN_EID_EXTENSION;
660 *eid++ = 3;
661 *eid++ = WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION;
662 *eid++ = iface->num_bss;
663 *eid++ = mbssid_elem_count;
664 }
665
666 return eid;
667}
668
669
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000670static size_t he_elem_len(struct hostapd_data *hapd)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800671{
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000672 size_t len = 0;
673
674#ifdef CONFIG_IEEE80211AX
675 if (!hapd->iconf->ieee80211ax || hapd->conf->disable_11ax)
676 return len;
677
678 len += 3 + sizeof(struct ieee80211_he_capabilities) +
679 3 + sizeof(struct ieee80211_he_operation) +
680 3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) +
681 3 + sizeof(struct ieee80211_spatial_reuse);
682 if (is_6ghz_op_class(hapd->iconf->op_class)) {
683 len += sizeof(struct ieee80211_he_6ghz_oper_info) +
684 3 + sizeof(struct ieee80211_he_6ghz_band_cap);
685 /* An additional Transmit Power Envelope element for
686 * subordinate client */
687 if (he_reg_is_indoor(hapd->iconf->he_6ghz_reg_pwr_type))
688 len += 4;
689
690 /* An additional Transmit Power Envelope element for
691 * default client with unit interpretation of regulatory
692 * client EIRP */
693 if (hapd->iconf->reg_def_cli_eirp != -1 &&
694 he_reg_is_sp(hapd->iconf->he_6ghz_reg_pwr_type))
695 len += 4;
696 }
697#endif /* CONFIG_IEEE80211AX */
698
699 return len;
700}
701
702
703struct probe_resp_params {
704 const struct ieee80211_mgmt *req;
705 bool is_p2p;
706
707 /* Generated IEs will be included inside an ML element */
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000708 struct hostapd_data *mld_ap;
709 struct mld_info *mld_info;
710
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800711 struct ieee80211_mgmt *resp;
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000712 size_t resp_len;
713 u8 *csa_pos;
714 u8 *ecsa_pos;
715 const u8 *known_bss;
716 u8 known_bss_len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800717
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000718#ifdef CONFIG_IEEE80211AX
719 u8 *cca_pos;
720#endif /* CONFIG_IEEE80211AX */
721};
Sunil Ravi77d572f2023-01-17 23:58:31 +0000722
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000723
724static void hostapd_free_probe_resp_params(struct probe_resp_params *params)
725{
726#ifdef CONFIG_IEEE80211BE
727 if (!params)
728 return;
Sunil Ravic0f5d412024-09-11 22:12:49 +0000729
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000730 os_free(params->mld_info);
731 params->mld_info = NULL;
732#endif /* CONFIG_IEEE80211BE */
733}
734
735
736static size_t hostapd_probe_resp_elems_len(struct hostapd_data *hapd,
737 struct probe_resp_params *params)
738{
739 size_t buflen = 0;
740
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800741#ifdef CONFIG_WPS
742 if (hapd->wps_probe_resp_ie)
743 buflen += wpabuf_len(hapd->wps_probe_resp_ie);
744#endif /* CONFIG_WPS */
745#ifdef CONFIG_P2P
746 if (hapd->p2p_probe_resp_ie)
747 buflen += wpabuf_len(hapd->p2p_probe_resp_ie);
748#endif /* CONFIG_P2P */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800749#ifdef CONFIG_FST
750 if (hapd->iface->fst_ies)
751 buflen += wpabuf_len(hapd->iface->fst_ies);
752#endif /* CONFIG_FST */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700753 if (hapd->conf->vendor_elements)
754 buflen += wpabuf_len(hapd->conf->vendor_elements);
Sunil Ravi7f769292024-07-23 22:21:32 +0000755#ifdef CONFIG_TESTING_OPTIONS
756 if (hapd->conf->presp_elements)
757 buflen += wpabuf_len(hapd->conf->presp_elements);
758#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800759 if (hapd->conf->vendor_vht) {
760 buflen += 5 + 2 + sizeof(struct ieee80211_vht_capabilities) +
761 2 + sizeof(struct ieee80211_vht_operation);
762 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800763
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000764 buflen += he_elem_len(hapd);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -0800765
Sunil Ravia04bd252022-05-02 22:54:18 -0700766#ifdef CONFIG_IEEE80211BE
767 if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
Sunil Ravic0f5d412024-09-11 22:12:49 +0000768 struct hostapd_data *ml_elem_ap =
769 params->mld_ap ? params->mld_ap : hapd;
770
Sunil Ravia04bd252022-05-02 22:54:18 -0700771 buflen += hostapd_eid_eht_capab_len(hapd, IEEE80211_MODE_AP);
772 buflen += 3 + sizeof(struct ieee80211_eht_operation);
Sunil Ravi036cec52023-03-29 11:35:17 -0700773 if (hapd->iconf->punct_bitmap)
774 buflen += EHT_OPER_DISABLED_SUBCHAN_BITMAP_SIZE;
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000775
Sunil Ravic0f5d412024-09-11 22:12:49 +0000776 if (ml_elem_ap->conf->mld_ap) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000777 buflen += hostapd_eid_eht_ml_beacon_len(
778 ml_elem_ap, params->mld_info, !!params->mld_ap);
Sunil Ravic0f5d412024-09-11 22:12:49 +0000779
780 /* For Max Channel Switch Time element during channel
781 * switch */
782 buflen += 6;
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000783 }
Sunil Ravia04bd252022-05-02 22:54:18 -0700784 }
785#endif /* CONFIG_IEEE80211BE */
786
Sunil Ravi77d572f2023-01-17 23:58:31 +0000787 buflen += hostapd_eid_mbssid_len(hapd, WLAN_FC_STYPE_PROBE_RESP, NULL,
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000788 params->known_bss,
789 params->known_bss_len, NULL);
Sunil Ravic0f5d412024-09-11 22:12:49 +0000790 buflen += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_PROBE_RESP, true);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800791 buflen += hostapd_mbo_ie_len(hapd);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700792 buflen += hostapd_eid_owe_trans_len(hapd);
Hai Shalomfdcde762020-04-02 11:19:20 -0700793 buflen += hostapd_eid_dpp_cc_len(hapd);
Sunil Ravi7f769292024-07-23 22:21:32 +0000794 buflen += hostapd_get_rsne_override_len(hapd);
795 buflen += hostapd_get_rsne_override_2_len(hapd);
796 buflen += hostapd_get_rsnxe_override_len(hapd);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800797
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000798 return buflen;
799}
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800800
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800801
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000802static u8 * hostapd_probe_resp_fill_elems(struct hostapd_data *hapd,
803 struct probe_resp_params *params,
804 u8 *pos, size_t len)
805{
806 u8 *csa_pos;
807 u8 *epos;
Sunil8cd6f4d2022-06-28 18:40:46 +0000808
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000809 epos = pos + len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800810
Sunil Ravic0f5d412024-09-11 22:12:49 +0000811 *pos++ = WLAN_EID_SSID;
812 *pos++ = hapd->conf->ssid.ssid_len;
813 os_memcpy(pos, hapd->conf->ssid.ssid,
814 hapd->conf->ssid.ssid_len);
815 pos += hapd->conf->ssid.ssid_len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800816
817 /* Supported rates */
818 pos = hostapd_eid_supp_rates(hapd, pos);
819
820 /* DS Params */
821 pos = hostapd_eid_ds_params(hapd, pos);
822
823 pos = hostapd_eid_country(hapd, pos, epos - pos);
824
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800825 /* Power Constraint element */
826 pos = hostapd_eid_pwr_constraint(hapd, pos);
827
Sunil Ravic0f5d412024-09-11 22:12:49 +0000828 /* CSA element */
829 csa_pos = hostapd_eid_csa(hapd, pos);
830 if (csa_pos != pos)
831 params->csa_pos = csa_pos - 1;
832 else
833 params->csa_pos = NULL;
834 pos = csa_pos;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800835
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800836 /* ERP Information element */
837 pos = hostapd_eid_erp_info(hapd, pos);
838
839 /* Extended supported rates */
840 pos = hostapd_eid_ext_supp_rates(hapd, pos);
841
Hai Shalomfdcde762020-04-02 11:19:20 -0700842 pos = hostapd_get_rsne(hapd, pos, epos - pos);
Dmitry Shmidt051af732013-10-22 13:52:46 -0700843 pos = hostapd_eid_bss_load(hapd, pos, epos - pos);
Sunil Ravi77d572f2023-01-17 23:58:31 +0000844 pos = hostapd_eid_mbssid(hapd, pos, epos, WLAN_FC_STYPE_PROBE_RESP, 0,
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000845 NULL, params->known_bss, params->known_bss_len,
846 NULL, NULL, NULL, 0);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800847 pos = hostapd_eid_rm_enabled_capab(hapd, pos, epos - pos);
Hai Shalomfdcde762020-04-02 11:19:20 -0700848 pos = hostapd_get_mde(hapd, pos, epos - pos);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800849
Sunil Ravic0f5d412024-09-11 22:12:49 +0000850 /* eCSA element */
851 csa_pos = hostapd_eid_ecsa(hapd, pos);
852 if (csa_pos != pos)
853 params->ecsa_pos = csa_pos - 1;
854 else
855 params->ecsa_pos = NULL;
856 pos = csa_pos;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800857
858 pos = hostapd_eid_supported_op_classes(hapd, pos);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800859 pos = hostapd_eid_ht_capabilities(hapd, pos);
860 pos = hostapd_eid_ht_operation(hapd, pos);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800861
Sunil Ravi77d572f2023-01-17 23:58:31 +0000862 /* Probe Response frames always include all non-TX profiles except
863 * when a list of known BSSes is included in the Probe Request frame. */
864 pos = hostapd_eid_ext_capab(hapd, pos,
865 hapd->iconf->mbssid >= MBSSID_ENABLED &&
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000866 !params->known_bss_len);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800867
868 pos = hostapd_eid_time_adv(hapd, pos);
869 pos = hostapd_eid_time_zone(hapd, pos);
870
871 pos = hostapd_eid_interworking(hapd, pos);
872 pos = hostapd_eid_adv_proto(hapd, pos);
873 pos = hostapd_eid_roaming_consortium(hapd, pos);
874
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800875#ifdef CONFIG_FST
876 if (hapd->iface->fst_ies) {
877 os_memcpy(pos, wpabuf_head(hapd->iface->fst_ies),
878 wpabuf_len(hapd->iface->fst_ies));
879 pos += wpabuf_len(hapd->iface->fst_ies);
880 }
881#endif /* CONFIG_FST */
882
Dmitry Shmidt04949592012-07-19 12:16:46 -0700883#ifdef CONFIG_IEEE80211AC
Hai Shalomc3565922019-10-28 11:58:20 -0700884 if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac &&
885 !is_6ghz_op_class(hapd->iconf->op_class)) {
Dmitry Shmidt7d175302016-09-06 13:11:34 -0700886 pos = hostapd_eid_vht_capabilities(hapd, pos, 0);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800887 pos = hostapd_eid_vht_operation(hapd, pos);
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -0800888 pos = hostapd_eid_txpower_envelope(hapd, pos);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800889 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800890#endif /* CONFIG_IEEE80211AC */
891
Hai Shalom60840252021-02-19 19:02:11 -0800892#ifdef CONFIG_IEEE80211AX
893 if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax &&
894 is_6ghz_op_class(hapd->iconf->op_class))
895 pos = hostapd_eid_txpower_envelope(hapd, pos);
896#endif /* CONFIG_IEEE80211AX */
897
Sunil Ravic0f5d412024-09-11 22:12:49 +0000898 pos = hostapd_eid_chsw_wrapper(hapd, pos);
Hai Shalom899fcc72020-10-19 14:38:18 -0700899
Sunil Ravic0f5d412024-09-11 22:12:49 +0000900 pos = hostapd_eid_rnr(hapd, pos, WLAN_FC_STYPE_PROBE_RESP, true);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800901 pos = hostapd_eid_fils_indic(hapd, pos, 0);
Sunil Ravic0f5d412024-09-11 22:12:49 +0000902
903 /* Max Channel Switch Time element */
904 pos = hostapd_eid_max_cs_time(hapd, pos);
905
Hai Shalomfdcde762020-04-02 11:19:20 -0700906 pos = hostapd_get_rsnxe(hapd, pos, epos - pos);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800907
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700908#ifdef CONFIG_IEEE80211AX
Hai Shalom60840252021-02-19 19:02:11 -0800909 if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
Sunil Ravia04bd252022-05-02 22:54:18 -0700910 u8 *cca_pos;
911
Hai Shalom81f62d82019-07-22 12:10:00 -0700912 pos = hostapd_eid_he_capab(hapd, pos, IEEE80211_MODE_AP);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700913 pos = hostapd_eid_he_operation(hapd, pos);
Sunil Ravia04bd252022-05-02 22:54:18 -0700914
915 /* BSS Color Change Announcement element */
916 cca_pos = hostapd_eid_cca(hapd, pos);
917 if (cca_pos != pos)
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000918 params->cca_pos = cca_pos - 2;
919 else
920 params->cca_pos = NULL;
Sunil Ravia04bd252022-05-02 22:54:18 -0700921 pos = cca_pos;
922
Hai Shalom81f62d82019-07-22 12:10:00 -0700923 pos = hostapd_eid_spatial_reuse(hapd, pos);
Hai Shalomfdcde762020-04-02 11:19:20 -0700924 pos = hostapd_eid_he_mu_edca_parameter_set(hapd, pos);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700925 pos = hostapd_eid_he_6ghz_band_cap(hapd, pos);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700926 }
927#endif /* CONFIG_IEEE80211AX */
928
Sunil Ravia04bd252022-05-02 22:54:18 -0700929#ifdef CONFIG_IEEE80211BE
930 if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000931 struct hostapd_data *ml_elem_ap =
932 params->mld_ap ? params->mld_ap : hapd;
933
934 if (ml_elem_ap->conf->mld_ap)
935 pos = hostapd_eid_eht_ml_beacon(
936 ml_elem_ap, params->mld_info,
937 pos, !!params->mld_ap);
938
Sunil Ravia04bd252022-05-02 22:54:18 -0700939 pos = hostapd_eid_eht_capab(hapd, pos, IEEE80211_MODE_AP);
940 pos = hostapd_eid_eht_operation(hapd, pos);
941 }
942#endif /* CONFIG_IEEE80211BE */
943
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800944#ifdef CONFIG_IEEE80211AC
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800945 if (hapd->conf->vendor_vht)
946 pos = hostapd_eid_vendor_vht(hapd, pos);
Dmitry Shmidt04949592012-07-19 12:16:46 -0700947#endif /* CONFIG_IEEE80211AC */
948
Hai Shalomfdcde762020-04-02 11:19:20 -0700949 /* WPA / OSEN */
950 pos = hostapd_get_wpa_ie(hapd, pos, epos - pos);
951 pos = hostapd_get_osen_ie(hapd, pos, epos - pos);
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800952
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800953 /* Wi-Fi Alliance WMM */
954 pos = hostapd_eid_wmm(hapd, pos);
955
956#ifdef CONFIG_WPS
957 if (hapd->conf->wps_state && hapd->wps_probe_resp_ie) {
958 os_memcpy(pos, wpabuf_head(hapd->wps_probe_resp_ie),
959 wpabuf_len(hapd->wps_probe_resp_ie));
960 pos += wpabuf_len(hapd->wps_probe_resp_ie);
961 }
962#endif /* CONFIG_WPS */
963
964#ifdef CONFIG_P2P
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000965 if ((hapd->conf->p2p & P2P_ENABLED) && params->is_p2p &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800966 hapd->p2p_probe_resp_ie) {
967 os_memcpy(pos, wpabuf_head(hapd->p2p_probe_resp_ie),
968 wpabuf_len(hapd->p2p_probe_resp_ie));
969 pos += wpabuf_len(hapd->p2p_probe_resp_ie);
970 }
971#endif /* CONFIG_P2P */
972#ifdef CONFIG_P2P_MANAGER
973 if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) ==
974 P2P_MANAGE)
975 pos = hostapd_eid_p2p_manage(hapd, pos);
976#endif /* CONFIG_P2P_MANAGER */
977
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700978#ifdef CONFIG_HS20
979 pos = hostapd_eid_hs20_indication(hapd, pos);
980#endif /* CONFIG_HS20 */
981
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000982 pos = hostapd_eid_mbo(hapd, pos, epos - pos);
983 pos = hostapd_eid_owe_trans(hapd, pos, epos - pos);
984 pos = hostapd_eid_dpp_cc(hapd, pos, epos - pos);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800985
Sunil Ravi7f769292024-07-23 22:21:32 +0000986 pos = hostapd_get_rsne_override(hapd, pos, epos - pos);
987 pos = hostapd_get_rsne_override_2(hapd, pos, epos - pos);
988 pos = hostapd_get_rsnxe_override(hapd, pos, epos - pos);
989
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700990 if (hapd->conf->vendor_elements) {
991 os_memcpy(pos, wpabuf_head(hapd->conf->vendor_elements),
992 wpabuf_len(hapd->conf->vendor_elements));
993 pos += wpabuf_len(hapd->conf->vendor_elements);
994 }
995
Sunil Ravi7f769292024-07-23 22:21:32 +0000996#ifdef CONFIG_TESTING_OPTIONS
997 if (hapd->conf->presp_elements) {
998 os_memcpy(pos, wpabuf_head(hapd->conf->presp_elements),
999 wpabuf_len(hapd->conf->presp_elements));
1000 pos += wpabuf_len(hapd->conf->presp_elements);
1001 }
1002#endif /* CONFIG_TESTING_OPTIONS */
1003
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001004 return pos;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001005}
1006
1007
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001008static void hostapd_gen_probe_resp(struct hostapd_data *hapd,
1009 struct probe_resp_params *params)
1010{
1011 u8 *pos;
1012 size_t buflen;
1013
1014 hapd = hostapd_mbssid_get_tx_bss(hapd);
1015
1016#define MAX_PROBERESP_LEN 768
1017 buflen = MAX_PROBERESP_LEN;
1018 buflen += hostapd_probe_resp_elems_len(hapd, params);
1019 params->resp = os_zalloc(buflen);
1020 if (!params->resp) {
1021 params->resp_len = 0;
1022 return;
1023 }
1024
1025 params->resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
1026 WLAN_FC_STYPE_PROBE_RESP);
1027 /* Unicast the response to all requests on bands other than 6 GHz. For
1028 * the 6 GHz, unicast is used only if the actual SSID is not included in
1029 * the Beacon frames. Otherwise, broadcast response is used per IEEE
1030 * Std 802.11ax-2021, 26.17.2.3.2. Broadcast address is also used for
1031 * the Probe Response frame template for the unsolicited (i.e., not as
1032 * a response to a specific request) case. */
1033 if (params->req && (!is_6ghz_op_class(hapd->iconf->op_class) ||
1034 hapd->conf->ignore_broadcast_ssid))
1035 os_memcpy(params->resp->da, params->req->sa, ETH_ALEN);
1036 else
1037 os_memset(params->resp->da, 0xff, ETH_ALEN);
1038 os_memcpy(params->resp->sa, hapd->own_addr, ETH_ALEN);
1039
1040 os_memcpy(params->resp->bssid, hapd->own_addr, ETH_ALEN);
1041 params->resp->u.probe_resp.beacon_int =
1042 host_to_le16(hapd->iconf->beacon_int);
1043
1044 /* hardware or low-level driver will setup seq_ctrl and timestamp */
1045 params->resp->u.probe_resp.capab_info =
1046 host_to_le16(hostapd_own_capab_info(hapd));
1047
1048 pos = hostapd_probe_resp_fill_elems(hapd, params,
1049 params->resp->u.probe_resp.variable,
1050 buflen);
1051
1052 params->resp_len = pos - (u8 *) params->resp;
1053}
1054
1055
1056#ifdef CONFIG_IEEE80211BE
1057static void hostapd_fill_probe_resp_ml_params(struct hostapd_data *hapd,
1058 struct probe_resp_params *params,
1059 const struct ieee80211_mgmt *mgmt,
1060 int mld_id, u16 links)
1061{
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001062 struct hostapd_data *link;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001063
1064 params->mld_ap = NULL;
1065 params->mld_info = os_zalloc(sizeof(*params->mld_info));
1066 if (!params->mld_info)
1067 return;
1068
1069 wpa_printf(MSG_DEBUG,
1070 "MLD: Got ML probe request with AP MLD ID %d for links %04x",
1071 mld_id, links);
1072
Sunil Ravi7f769292024-07-23 22:21:32 +00001073 for_each_mld_link(link, hapd) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001074 struct mld_link_info *link_info;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001075 u8 mld_link_id = link->mld_link_id;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001076
1077 /*
1078 * Set mld_ap iff the ML probe request explicitly
1079 * requested a specific MLD ID. In that case, the targeted
1080 * AP may have been a nontransmitted BSSID on the same
1081 * interface.
1082 */
1083 if (mld_id != -1 && link->iface == hapd->iface)
1084 params->mld_ap = link;
1085
1086 /* Never duplicate main Probe Response frame body */
1087 if (link == hapd)
1088 continue;
1089
1090 /* Only include requested links */
1091 if (!(BIT(mld_link_id) & links))
1092 continue;
1093
1094 link_info = &params->mld_info->links[mld_link_id];
Sunil Ravic0f5d412024-09-11 22:12:49 +00001095 os_memcpy(link_info, &hapd->partner_links[mld_link_id],
1096 sizeof(hapd->partner_links[mld_link_id]));
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001097
1098 wpa_printf(MSG_DEBUG,
Sunil Ravic0f5d412024-09-11 22:12:49 +00001099 "MLD: ML probe response includes link STA info for %d: %u bytes",
1100 mld_link_id, link_info->resp_sta_profile_len);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001101 }
1102
1103 if (mld_id != -1 && !params->mld_ap) {
1104 wpa_printf(MSG_DEBUG,
1105 "MLD: No nontransmitted BSSID for MLD ID %d",
1106 mld_id);
1107 goto fail;
1108 }
1109
1110 return;
1111
1112fail:
1113 hostapd_free_probe_resp_params(params);
1114 params->mld_ap = NULL;
1115 params->mld_info = NULL;
1116}
1117#endif /* CONFIG_IEEE80211BE */
1118
1119
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001120enum ssid_match_result {
1121 NO_SSID_MATCH,
1122 EXACT_SSID_MATCH,
Hai Shaloma20dcd72022-02-04 13:43:00 -08001123 WILDCARD_SSID_MATCH,
1124 CO_LOCATED_SSID_MATCH,
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001125};
1126
1127static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
1128 const u8 *ssid, size_t ssid_len,
1129 const u8 *ssid_list,
Hai Shalomfdcde762020-04-02 11:19:20 -07001130 size_t ssid_list_len,
1131 const u8 *short_ssid_list,
1132 size_t short_ssid_list_len)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001133{
1134 const u8 *pos, *end;
Hai Shaloma20dcd72022-02-04 13:43:00 -08001135 struct hostapd_iface *iface = hapd->iface;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001136 int wildcard = 0;
Hai Shaloma20dcd72022-02-04 13:43:00 -08001137 size_t i, j;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001138
1139 if (ssid_len == 0)
1140 wildcard = 1;
1141 if (ssid_len == hapd->conf->ssid.ssid_len &&
1142 os_memcmp(ssid, hapd->conf->ssid.ssid, ssid_len) == 0)
1143 return EXACT_SSID_MATCH;
1144
Hai Shalomfdcde762020-04-02 11:19:20 -07001145 if (ssid_list) {
1146 pos = ssid_list;
1147 end = ssid_list + ssid_list_len;
1148 while (end - pos >= 2) {
1149 if (2 + pos[1] > end - pos)
1150 break;
1151 if (pos[1] == 0)
1152 wildcard = 1;
1153 if (pos[1] == hapd->conf->ssid.ssid_len &&
1154 os_memcmp(pos + 2, hapd->conf->ssid.ssid,
1155 pos[1]) == 0)
1156 return EXACT_SSID_MATCH;
1157 pos += 2 + pos[1];
1158 }
1159 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001160
Hai Shalomfdcde762020-04-02 11:19:20 -07001161 if (short_ssid_list) {
1162 pos = short_ssid_list;
1163 end = short_ssid_list + short_ssid_list_len;
1164 while (end - pos >= 4) {
1165 if (hapd->conf->ssid.short_ssid == WPA_GET_LE32(pos))
1166 return EXACT_SSID_MATCH;
1167 pos += 4;
1168 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001169 }
1170
Hai Shaloma20dcd72022-02-04 13:43:00 -08001171 if (wildcard)
1172 return WILDCARD_SSID_MATCH;
1173
1174 if (!iface->interfaces || iface->interfaces->count <= 1 ||
1175 is_6ghz_op_class(hapd->iconf->op_class))
1176 return NO_SSID_MATCH;
1177
1178 for (i = 0; i < iface->interfaces->count; i++) {
1179 struct hostapd_iface *colocated;
1180
1181 colocated = iface->interfaces->iface[i];
1182
1183 if (colocated == iface ||
1184 !is_6ghz_op_class(colocated->conf->op_class))
1185 continue;
1186
1187 for (j = 0; j < colocated->num_bss; j++) {
1188 struct hostapd_bss_config *conf;
1189
1190 conf = colocated->bss[j]->conf;
1191 if (ssid_len == conf->ssid.ssid_len &&
1192 os_memcmp(ssid, conf->ssid.ssid, ssid_len) == 0)
1193 return CO_LOCATED_SSID_MATCH;
1194 }
1195 }
1196
1197 return NO_SSID_MATCH;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001198}
1199
1200
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001201void sta_track_expire(struct hostapd_iface *iface, int force)
1202{
1203 struct os_reltime now;
1204 struct hostapd_sta_info *info;
1205
1206 if (!iface->num_sta_seen)
1207 return;
1208
1209 os_get_reltime(&now);
1210 while ((info = dl_list_first(&iface->sta_seen, struct hostapd_sta_info,
1211 list))) {
1212 if (!force &&
1213 !os_reltime_expired(&now, &info->last_seen,
1214 iface->conf->track_sta_max_age))
1215 break;
1216 force = 0;
1217
1218 wpa_printf(MSG_MSGDUMP, "%s: Expire STA tracking entry for "
1219 MACSTR, iface->bss[0]->conf->iface,
1220 MAC2STR(info->addr));
1221 dl_list_del(&info->list);
1222 iface->num_sta_seen--;
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07001223 sta_track_del(info);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001224 }
1225}
1226
1227
1228static struct hostapd_sta_info * sta_track_get(struct hostapd_iface *iface,
1229 const u8 *addr)
1230{
1231 struct hostapd_sta_info *info;
1232
1233 dl_list_for_each(info, &iface->sta_seen, struct hostapd_sta_info, list)
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001234 if (ether_addr_equal(addr, info->addr))
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001235 return info;
1236
1237 return NULL;
1238}
1239
1240
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001241void sta_track_add(struct hostapd_iface *iface, const u8 *addr, int ssi_signal)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001242{
1243 struct hostapd_sta_info *info;
1244
1245 info = sta_track_get(iface, addr);
1246 if (info) {
1247 /* Move the most recent entry to the end of the list */
1248 dl_list_del(&info->list);
1249 dl_list_add_tail(&iface->sta_seen, &info->list);
1250 os_get_reltime(&info->last_seen);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001251 info->ssi_signal = ssi_signal;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001252 return;
1253 }
1254
1255 /* Add a new entry */
1256 info = os_zalloc(sizeof(*info));
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07001257 if (info == NULL)
1258 return;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001259 os_memcpy(info->addr, addr, ETH_ALEN);
1260 os_get_reltime(&info->last_seen);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001261 info->ssi_signal = ssi_signal;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001262
1263 if (iface->num_sta_seen >= iface->conf->track_sta_max_num) {
1264 /* Expire oldest entry to make room for a new one */
1265 sta_track_expire(iface, 1);
1266 }
1267
1268 wpa_printf(MSG_MSGDUMP, "%s: Add STA tracking entry for "
1269 MACSTR, iface->bss[0]->conf->iface, MAC2STR(addr));
1270 dl_list_add_tail(&iface->sta_seen, &info->list);
1271 iface->num_sta_seen++;
1272}
1273
1274
1275struct hostapd_data *
1276sta_track_seen_on(struct hostapd_iface *iface, const u8 *addr,
1277 const char *ifname)
1278{
1279 struct hapd_interfaces *interfaces = iface->interfaces;
1280 size_t i, j;
1281
1282 for (i = 0; i < interfaces->count; i++) {
1283 struct hostapd_data *hapd = NULL;
1284
1285 iface = interfaces->iface[i];
1286 for (j = 0; j < iface->num_bss; j++) {
1287 hapd = iface->bss[j];
1288 if (os_strcmp(ifname, hapd->conf->iface) == 0)
1289 break;
1290 hapd = NULL;
1291 }
1292
1293 if (hapd && sta_track_get(iface, addr))
1294 return hapd;
1295 }
1296
1297 return NULL;
1298}
1299
1300
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07001301#ifdef CONFIG_TAXONOMY
1302void sta_track_claim_taxonomy_info(struct hostapd_iface *iface, const u8 *addr,
1303 struct wpabuf **probe_ie_taxonomy)
1304{
1305 struct hostapd_sta_info *info;
1306
1307 info = sta_track_get(iface, addr);
1308 if (!info)
1309 return;
1310
1311 wpabuf_free(*probe_ie_taxonomy);
1312 *probe_ie_taxonomy = info->probe_ie_taxonomy;
1313 info->probe_ie_taxonomy = NULL;
1314}
1315#endif /* CONFIG_TAXONOMY */
1316
1317
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001318#ifdef CONFIG_IEEE80211BE
1319static bool parse_ml_probe_req(const struct ieee80211_eht_ml *ml, size_t ml_len,
1320 int *mld_id, u16 *links)
1321{
1322 u16 ml_control;
1323 const struct element *sub;
1324 const u8 *pos;
1325 size_t len;
1326
1327 *mld_id = -1;
1328 *links = 0xffff;
1329
1330 if (ml_len < sizeof(struct ieee80211_eht_ml))
1331 return false;
1332
1333 ml_control = le_to_host16(ml->ml_control);
1334 if ((ml_control & MULTI_LINK_CONTROL_TYPE_MASK) !=
1335 MULTI_LINK_CONTROL_TYPE_PROBE_REQ) {
1336 wpa_printf(MSG_DEBUG, "MLD: Not an ML probe req");
1337 return false;
1338 }
1339
1340 if (sizeof(struct ieee80211_eht_ml) + 1 > ml_len) {
1341 wpa_printf(MSG_DEBUG, "MLD: ML probe req too short");
1342 return false;
1343 }
1344
1345 pos = ml->variable;
1346 len = pos[0];
1347 if (len < 1 || sizeof(struct ieee80211_eht_ml) + len > ml_len) {
1348 wpa_printf(MSG_DEBUG,
1349 "MLD: ML probe request with invalid length");
1350 return false;
1351 }
1352
1353 if (ml_control & EHT_ML_PRES_BM_PROBE_REQ_AP_MLD_ID) {
1354 if (len < 2) {
1355 wpa_printf(MSG_DEBUG,
1356 "MLD: ML probe req too short for MLD ID");
1357 return false;
1358 }
1359
1360 *mld_id = pos[1];
1361 }
1362 pos += len;
1363
1364 /* Parse subelements (if there are any) */
1365 len = ml_len - len - sizeof(struct ieee80211_eht_ml);
1366 for_each_element_id(sub, 0, pos, len) {
1367 const struct ieee80211_eht_per_sta_profile *sta;
1368 u16 sta_control;
1369
1370 if (*links == 0xffff)
1371 *links = 0;
1372
1373 if (sub->datalen <
1374 sizeof(struct ieee80211_eht_per_sta_profile)) {
1375 wpa_printf(MSG_DEBUG,
1376 "MLD: ML probe req %d too short for sta profile",
1377 sub->datalen);
1378 return false;
1379 }
1380
1381 sta = (struct ieee80211_eht_per_sta_profile *) sub->data;
1382
1383 /*
1384 * Extract the link ID, do not return whether a complete or
1385 * partial profile was requested.
1386 */
1387 sta_control = le_to_host16(sta->sta_control);
1388 *links |= BIT(sta_control & EHT_PER_STA_CTRL_LINK_ID_MSK);
1389 }
1390
1391 if (!for_each_element_completed(sub, pos, len)) {
1392 wpa_printf(MSG_DEBUG,
1393 "MLD: ML probe req sub-elements parsing error");
1394 return false;
1395 }
1396
1397 return true;
1398}
1399#endif /* CONFIG_IEEE80211BE */
1400
1401
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001402void handle_probe_req(struct hostapd_data *hapd,
Dmitry Shmidt04949592012-07-19 12:16:46 -07001403 const struct ieee80211_mgmt *mgmt, size_t len,
1404 int ssi_signal)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001405{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001406 struct ieee802_11_elems elems;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001407 const u8 *ie;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001408 size_t ie_len;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001409 size_t i;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001410 int noack;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001411 enum ssid_match_result res;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001412 int ret;
1413 u16 csa_offs[2];
1414 size_t csa_offs_len;
Hai Shalomfdcde762020-04-02 11:19:20 -07001415 struct radius_sta rad_info;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001416 struct probe_resp_params params;
1417#ifdef CONFIG_IEEE80211BE
1418 int mld_id;
1419 u16 links;
1420#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001421
Hai Shalom60840252021-02-19 19:02:11 -08001422 if (hapd->iconf->rssi_ignore_probe_request && ssi_signal &&
1423 ssi_signal < hapd->iconf->rssi_ignore_probe_request)
1424 return;
1425
Dmitry Shmidte4663042016-04-04 10:07:49 -07001426 if (len < IEEE80211_HDRLEN)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001427 return;
Dmitry Shmidte4663042016-04-04 10:07:49 -07001428 ie = ((const u8 *) mgmt) + IEEE80211_HDRLEN;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001429 if (hapd->iconf->track_sta_max_num)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001430 sta_track_add(hapd->iface, mgmt->sa, ssi_signal);
Dmitry Shmidte4663042016-04-04 10:07:49 -07001431 ie_len = len - IEEE80211_HDRLEN;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001432
Hai Shalomfdcde762020-04-02 11:19:20 -07001433 ret = hostapd_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len,
1434 &rad_info, 1);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001435 if (ret == HOSTAPD_ACL_REJECT) {
1436 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
1437 "Ignore Probe Request frame from " MACSTR
1438 " due to ACL reject ", MAC2STR(mgmt->sa));
1439 return;
1440 }
1441
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001442 for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++)
1443 if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001444 mgmt->sa, mgmt->da, mgmt->bssid,
Dmitry Shmidt04949592012-07-19 12:16:46 -07001445 ie, ie_len, ssi_signal) > 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001446 return;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001447
Hai Shalom74f70d42019-02-11 14:42:39 -08001448 if (!hapd->conf->send_probe_response)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001449 return;
1450
1451 if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) {
1452 wpa_printf(MSG_DEBUG, "Could not parse ProbeReq from " MACSTR,
1453 MAC2STR(mgmt->sa));
1454 return;
1455 }
1456
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001457 if ((!elems.ssid || !elems.supp_rates)) {
1458 wpa_printf(MSG_DEBUG, "STA " MACSTR " sent probe request "
1459 "without SSID or supported rates element",
1460 MAC2STR(mgmt->sa));
1461 return;
1462 }
1463
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001464 /*
1465 * No need to reply if the Probe Request frame was sent on an adjacent
1466 * channel. IEEE Std 802.11-2012 describes this as a requirement for an
1467 * AP with dot11RadioMeasurementActivated set to true, but strictly
1468 * speaking does not allow such ignoring of Probe Request frames if
1469 * dot11RadioMeasurementActivated is false. Anyway, this can help reduce
1470 * number of unnecessary Probe Response frames for cases where the STA
1471 * is less likely to see them (Probe Request frame sent on a
1472 * neighboring, but partially overlapping, channel).
1473 */
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07001474 if (elems.ds_params &&
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001475 hapd->iface->current_mode &&
1476 (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G ||
1477 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211B) &&
1478 hapd->iconf->channel != elems.ds_params[0]) {
1479 wpa_printf(MSG_DEBUG,
1480 "Ignore Probe Request due to DS Params mismatch: chan=%u != ds.chan=%u",
1481 hapd->iconf->channel, elems.ds_params[0]);
1482 return;
1483 }
1484
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001485#ifdef CONFIG_P2P
Dmitry Shmidtde47be72016-01-07 12:52:55 -08001486 if (hapd->p2p && hapd->p2p_group && elems.wps_ie) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001487 struct wpabuf *wps;
1488 wps = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA);
1489 if (wps && !p2p_group_match_dev_type(hapd->p2p_group, wps)) {
1490 wpa_printf(MSG_MSGDUMP, "P2P: Ignore Probe Request "
1491 "due to mismatch with Requested Device "
1492 "Type");
1493 wpabuf_free(wps);
1494 return;
1495 }
1496 wpabuf_free(wps);
1497 }
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001498
Dmitry Shmidtde47be72016-01-07 12:52:55 -08001499 if (hapd->p2p && hapd->p2p_group && elems.p2p) {
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001500 struct wpabuf *p2p;
1501 p2p = ieee802_11_vendor_ie_concat(ie, ie_len, P2P_IE_VENDOR_TYPE);
1502 if (p2p && !p2p_group_match_dev_id(hapd->p2p_group, p2p)) {
1503 wpa_printf(MSG_MSGDUMP, "P2P: Ignore Probe Request "
1504 "due to mismatch with Device ID");
1505 wpabuf_free(p2p);
1506 return;
1507 }
1508 wpabuf_free(p2p);
1509 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001510#endif /* CONFIG_P2P */
1511
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001512 if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0 &&
Hai Shalomfdcde762020-04-02 11:19:20 -07001513 elems.ssid_list_len == 0 && elems.short_ssid_list_len == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001514 wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for "
1515 "broadcast SSID ignored", MAC2STR(mgmt->sa));
1516 return;
1517 }
1518
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001519#ifdef CONFIG_P2P
1520 if ((hapd->conf->p2p & P2P_GROUP_OWNER) &&
1521 elems.ssid_len == P2P_WILDCARD_SSID_LEN &&
1522 os_memcmp(elems.ssid, P2P_WILDCARD_SSID,
1523 P2P_WILDCARD_SSID_LEN) == 0) {
1524 /* Process P2P Wildcard SSID like Wildcard SSID */
1525 elems.ssid_len = 0;
1526 }
1527#endif /* CONFIG_P2P */
1528
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07001529#ifdef CONFIG_TAXONOMY
1530 {
1531 struct sta_info *sta;
1532 struct hostapd_sta_info *info;
1533
1534 if ((sta = ap_get_sta(hapd, mgmt->sa)) != NULL) {
1535 taxonomy_sta_info_probe_req(hapd, sta, ie, ie_len);
1536 } else if ((info = sta_track_get(hapd->iface,
1537 mgmt->sa)) != NULL) {
1538 taxonomy_hostapd_sta_info_probe_req(hapd, info,
1539 ie, ie_len);
1540 }
1541 }
1542#endif /* CONFIG_TAXONOMY */
1543
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001544 res = ssid_match(hapd, elems.ssid, elems.ssid_len,
Hai Shalomfdcde762020-04-02 11:19:20 -07001545 elems.ssid_list, elems.ssid_list_len,
1546 elems.short_ssid_list, elems.short_ssid_list_len);
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07001547 if (res == NO_SSID_MATCH) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001548 if (!(mgmt->da[0] & 0x01)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001549 wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001550 " for foreign SSID '%s' (DA " MACSTR ")%s",
Dmitry Shmidt3c479372014-02-04 10:50:36 -08001551 MAC2STR(mgmt->sa),
1552 wpa_ssid_txt(elems.ssid, elems.ssid_len),
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001553 MAC2STR(mgmt->da),
1554 elems.ssid_list ? " (SSID list)" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001555 }
1556 return;
1557 }
1558
Hai Shalomfdcde762020-04-02 11:19:20 -07001559 if (hapd->conf->ignore_broadcast_ssid && res == WILDCARD_SSID_MATCH) {
1560 wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for "
1561 "broadcast SSID ignored", MAC2STR(mgmt->sa));
1562 return;
1563 }
1564
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001565#ifdef CONFIG_INTERWORKING
Dmitry Shmidtf9bdef92014-04-25 10:46:36 -07001566 if (hapd->conf->interworking &&
1567 elems.interworking && elems.interworking_len >= 1) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001568 u8 ant = elems.interworking[0] & 0x0f;
1569 if (ant != INTERWORKING_ANT_WILDCARD &&
1570 ant != hapd->conf->access_network_type) {
1571 wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
1572 " for mismatching ANT %u ignored",
1573 MAC2STR(mgmt->sa), ant);
1574 return;
1575 }
1576 }
1577
Dmitry Shmidtf9bdef92014-04-25 10:46:36 -07001578 if (hapd->conf->interworking && elems.interworking &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001579 (elems.interworking_len == 7 || elems.interworking_len == 9)) {
1580 const u8 *hessid;
1581 if (elems.interworking_len == 7)
1582 hessid = elems.interworking + 1;
1583 else
1584 hessid = elems.interworking + 1 + 2;
1585 if (!is_broadcast_ether_addr(hessid) &&
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001586 !ether_addr_equal(hessid, hapd->conf->hessid)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001587 wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
1588 " for mismatching HESSID " MACSTR
1589 " ignored",
1590 MAC2STR(mgmt->sa), MAC2STR(hessid));
1591 return;
1592 }
1593 }
1594#endif /* CONFIG_INTERWORKING */
1595
Dmitry Shmidt34af3062013-07-11 10:46:32 -07001596#ifdef CONFIG_P2P
1597 if ((hapd->conf->p2p & P2P_GROUP_OWNER) &&
1598 supp_rates_11b_only(&elems)) {
1599 /* Indicates support for 11b rates only */
1600 wpa_printf(MSG_EXCESSIVE, "P2P: Ignore Probe Request from "
1601 MACSTR " with only 802.11b rates",
1602 MAC2STR(mgmt->sa));
1603 return;
1604 }
1605#endif /* CONFIG_P2P */
1606
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001607 /* TODO: verify that supp_rates contains at least one matching rate
1608 * with AP configuration */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001609
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001610 if (hapd->conf->no_probe_resp_if_seen_on &&
1611 is_multicast_ether_addr(mgmt->da) &&
1612 is_multicast_ether_addr(mgmt->bssid) &&
1613 sta_track_seen_on(hapd->iface, mgmt->sa,
1614 hapd->conf->no_probe_resp_if_seen_on)) {
1615 wpa_printf(MSG_MSGDUMP, "%s: Ignore Probe Request from " MACSTR
1616 " since STA has been seen on %s",
1617 hapd->conf->iface, MAC2STR(mgmt->sa),
1618 hapd->conf->no_probe_resp_if_seen_on);
1619 return;
1620 }
1621
1622 if (hapd->conf->no_probe_resp_if_max_sta &&
1623 is_multicast_ether_addr(mgmt->da) &&
1624 is_multicast_ether_addr(mgmt->bssid) &&
1625 hapd->num_sta >= hapd->conf->max_num_sta &&
1626 !ap_get_sta(hapd, mgmt->sa)) {
1627 wpa_printf(MSG_MSGDUMP, "%s: Ignore Probe Request from " MACSTR
1628 " since no room for additional STA",
1629 hapd->conf->iface, MAC2STR(mgmt->sa));
1630 return;
1631 }
1632
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07001633#ifdef CONFIG_TESTING_OPTIONS
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07001634 if (hapd->iconf->ignore_probe_probability > 0.0 &&
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07001635 drand48() < hapd->iconf->ignore_probe_probability) {
1636 wpa_printf(MSG_INFO,
1637 "TESTING: ignoring probe request from " MACSTR,
1638 MAC2STR(mgmt->sa));
1639 return;
1640 }
1641#endif /* CONFIG_TESTING_OPTIONS */
1642
Sunil Ravi77d572f2023-01-17 23:58:31 +00001643 /* Do not send Probe Response frame from a non-transmitting multiple
1644 * BSSID profile unless the Probe Request frame is directed at that
1645 * particular BSS. */
1646 if (hapd != hostapd_mbssid_get_tx_bss(hapd) && res != EXACT_SSID_MATCH)
1647 return;
1648
Roshan Pius3a1667e2018-07-03 15:17:14 -07001649 wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, RX_PROBE_REQUEST "sa=" MACSTR
1650 " signal=%d", MAC2STR(mgmt->sa), ssi_signal);
1651
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001652 os_memset(&params, 0, sizeof(params));
1653
1654#ifdef CONFIG_IEEE80211BE
1655 if (hapd->conf->mld_ap && elems.probe_req_mle &&
1656 parse_ml_probe_req((struct ieee80211_eht_ml *) elems.probe_req_mle,
1657 elems.probe_req_mle_len, &mld_id, &links)) {
1658 hostapd_fill_probe_resp_ml_params(hapd, &params, mgmt,
1659 mld_id, links);
1660 }
1661#endif /* CONFIG_IEEE80211BE */
1662
1663 params.req = mgmt;
1664 params.is_p2p = !!elems.p2p;
1665 params.known_bss = elems.mbssid_known_bss;
1666 params.known_bss_len = elems.mbssid_known_bss_len;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001667
1668 hostapd_gen_probe_resp(hapd, &params);
1669
1670 hostapd_free_probe_resp_params(&params);
1671
1672 if (!params.resp)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001673 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001674
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001675 /*
1676 * If this is a broadcast probe request, apply no ack policy to avoid
1677 * excessive retries.
1678 */
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001679 noack = !!(res == WILDCARD_SSID_MATCH &&
1680 is_broadcast_ether_addr(mgmt->da));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001681
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001682 csa_offs_len = 0;
1683 if (hapd->csa_in_progress) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001684 if (params.csa_pos)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001685 csa_offs[csa_offs_len++] =
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001686 params.csa_pos - (u8 *) params.resp;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001687
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001688 if (params.ecsa_pos)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001689 csa_offs[csa_offs_len++] =
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001690 params.ecsa_pos - (u8 *) params.resp;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001691 }
1692
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001693 ret = hostapd_drv_send_mlme(hapd, params.resp, params.resp_len, noack,
Hai Shalomfdcde762020-04-02 11:19:20 -07001694 csa_offs_len ? csa_offs : NULL,
1695 csa_offs_len, 0);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001696
1697 if (ret < 0)
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001698 wpa_printf(MSG_INFO, "handle_probe_req: send failed");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001699
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001700 os_free(params.resp);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001701
1702 wpa_printf(MSG_EXCESSIVE, "STA " MACSTR " sent probe request for %s "
1703 "SSID", MAC2STR(mgmt->sa),
1704 elems.ssid_len == 0 ? "broadcast" : "our");
1705}
1706
1707
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001708static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd,
1709 size_t *resp_len)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001710{
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001711 struct probe_resp_params params;
1712
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001713 /* check probe response offloading caps and print warnings */
1714 if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD))
1715 return NULL;
1716
1717#ifdef CONFIG_WPS
1718 if (hapd->conf->wps_state && hapd->wps_probe_resp_ie &&
1719 (!(hapd->iface->probe_resp_offloads &
1720 (WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS |
1721 WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2))))
1722 wpa_printf(MSG_WARNING, "Device is trying to offload WPS "
1723 "Probe Response while not supporting this");
1724#endif /* CONFIG_WPS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001725
1726#ifdef CONFIG_P2P
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001727 if ((hapd->conf->p2p & P2P_ENABLED) && hapd->p2p_probe_resp_ie &&
1728 !(hapd->iface->probe_resp_offloads &
1729 WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P))
1730 wpa_printf(MSG_WARNING, "Device is trying to offload P2P "
1731 "Probe Response while not supporting this");
1732#endif /* CONFIG_P2P */
1733
1734 if (hapd->conf->interworking &&
1735 !(hapd->iface->probe_resp_offloads &
1736 WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING))
1737 wpa_printf(MSG_WARNING, "Device is trying to offload "
1738 "Interworking Probe Response while not supporting "
1739 "this");
1740
1741 /* Generate a Probe Response template for the non-P2P case */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001742 os_memset(&params, 0, sizeof(params));
1743 params.req = NULL;
1744 params.is_p2p = false;
1745 params.known_bss = NULL;
1746 params.known_bss_len = 0;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001747 params.mld_ap = NULL;
1748 params.mld_info = NULL;
1749
1750 hostapd_gen_probe_resp(hapd, &params);
1751 *resp_len = params.resp_len;
1752 if (!params.resp)
1753 return NULL;
1754
1755 /* TODO: Avoid passing these through struct hostapd_data */
1756 if (params.csa_pos)
1757 hapd->cs_c_off_proberesp = params.csa_pos - (u8 *) params.resp;
1758 if (params.ecsa_pos)
1759 hapd->cs_c_off_ecsa_proberesp = params.ecsa_pos -
1760 (u8 *) params.resp;
1761#ifdef CONFIG_IEEE80211AX
1762 if (params.cca_pos)
1763 hapd->cca_c_off_proberesp = params.cca_pos - (u8 *) params.resp;
1764#endif /* CONFIG_IEEE80211AX */
1765
1766 return (u8 *) params.resp;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001767}
1768
1769#endif /* NEED_AP_MLME */
1770
1771
Hai Shalom60840252021-02-19 19:02:11 -08001772#ifdef CONFIG_IEEE80211AX
1773/* Unsolicited broadcast Probe Response transmission, 6 GHz only */
Sunil Ravi7f769292024-07-23 22:21:32 +00001774u8 * hostapd_unsol_bcast_probe_resp(struct hostapd_data *hapd,
1775 struct unsol_bcast_probe_resp *ubpr)
Hai Shalom60840252021-02-19 19:02:11 -08001776{
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001777 struct probe_resp_params probe_params;
1778
Hai Shalom60840252021-02-19 19:02:11 -08001779 if (!is_6ghz_op_class(hapd->iconf->op_class))
1780 return NULL;
1781
Sunil Ravi7f769292024-07-23 22:21:32 +00001782 ubpr->unsol_bcast_probe_resp_interval =
Hai Shalom60840252021-02-19 19:02:11 -08001783 hapd->conf->unsol_bcast_probe_resp_interval;
1784
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001785 os_memset(&probe_params, 0, sizeof(probe_params));
1786 probe_params.req = NULL;
1787 probe_params.is_p2p = false;
1788 probe_params.known_bss = NULL;
1789 probe_params.known_bss_len = 0;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001790 probe_params.mld_ap = NULL;
1791 probe_params.mld_info = NULL;
1792
1793 hostapd_gen_probe_resp(hapd, &probe_params);
Sunil Ravi7f769292024-07-23 22:21:32 +00001794 ubpr->unsol_bcast_probe_resp_tmpl_len = probe_params.resp_len;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001795 return (u8 *) probe_params.resp;
Hai Shalom60840252021-02-19 19:02:11 -08001796}
1797#endif /* CONFIG_IEEE80211AX */
1798
1799
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07001800void sta_track_del(struct hostapd_sta_info *info)
1801{
1802#ifdef CONFIG_TAXONOMY
1803 wpabuf_free(info->probe_ie_taxonomy);
1804 info->probe_ie_taxonomy = NULL;
1805#endif /* CONFIG_TAXONOMY */
1806 os_free(info);
1807}
1808
1809
Hai Shalom60840252021-02-19 19:02:11 -08001810#ifdef CONFIG_FILS
1811
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001812static u16 hostapd_gen_fils_discovery_phy_index(struct hostapd_data *hapd)
1813{
1814#ifdef CONFIG_IEEE80211BE
1815 if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be)
1816 return FD_CAP_PHY_INDEX_EHT;
1817#endif /* CONFIG_IEEE80211BE */
1818
1819#ifdef CONFIG_IEEE80211AX
1820 if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax)
1821 return FD_CAP_PHY_INDEX_HE;
1822#endif /* CONFIG_IEEE80211AX */
1823
1824#ifdef CONFIG_IEEE80211AC
1825 if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac)
1826 return FD_CAP_PHY_INDEX_VHT;
1827#endif /* CONFIG_IEEE80211AC */
1828
1829 if (hapd->iconf->ieee80211n && !hapd->conf->disable_11n)
1830 return FD_CAP_PHY_INDEX_HT;
1831
1832 return 0;
1833}
1834
1835
1836static u16 hostapd_gen_fils_discovery_nss(struct hostapd_hw_modes *mode,
1837 u16 phy_index, u8 he_mcs_nss_size)
1838{
1839 u16 nss = 0;
1840
1841 if (!mode)
1842 return 0;
1843
1844 if (phy_index == FD_CAP_PHY_INDEX_HE) {
1845 const u8 *he_mcs = mode->he_capab[IEEE80211_MODE_AP].mcs;
1846 int i;
1847 u16 mcs[6];
1848
1849 os_memset(mcs, 0xff, 6 * sizeof(u16));
1850
1851 if (he_mcs_nss_size == 4) {
1852 mcs[0] = WPA_GET_LE16(&he_mcs[0]);
1853 mcs[1] = WPA_GET_LE16(&he_mcs[2]);
1854 }
1855
1856 if (he_mcs_nss_size == 8) {
1857 mcs[2] = WPA_GET_LE16(&he_mcs[4]);
1858 mcs[3] = WPA_GET_LE16(&he_mcs[6]);
1859 }
1860
1861 if (he_mcs_nss_size == 12) {
1862 mcs[4] = WPA_GET_LE16(&he_mcs[8]);
1863 mcs[5] = WPA_GET_LE16(&he_mcs[10]);
1864 }
1865
1866 for (i = 0; i < HE_NSS_MAX_STREAMS; i++) {
1867 u16 nss_mask = 0x3 << (i * 2);
1868
1869 /*
1870 * If Tx and/or Rx indicate support for a given NSS,
1871 * count it towards the maximum NSS.
1872 */
1873 if (he_mcs_nss_size == 4 &&
1874 (((mcs[0] & nss_mask) != nss_mask) ||
1875 ((mcs[1] & nss_mask) != nss_mask))) {
1876 nss++;
1877 continue;
1878 }
1879
1880 if (he_mcs_nss_size == 8 &&
1881 (((mcs[2] & nss_mask) != nss_mask) ||
1882 ((mcs[3] & nss_mask) != nss_mask))) {
1883 nss++;
1884 continue;
1885 }
1886
1887 if (he_mcs_nss_size == 12 &&
1888 (((mcs[4] & nss_mask) != nss_mask) ||
1889 ((mcs[5] & nss_mask) != nss_mask))) {
1890 nss++;
1891 continue;
1892 }
1893 }
1894 } else if (phy_index == FD_CAP_PHY_INDEX_EHT) {
1895 u8 rx_nss, tx_nss, max_nss = 0, i;
1896 u8 *mcs = mode->eht_capab[IEEE80211_MODE_AP].mcs;
1897
1898 /*
1899 * The Supported EHT-MCS And NSS Set field for the AP contains
1900 * one to three EHT-MCS Map fields based on the supported
1901 * bandwidth. Check the first byte (max NSS for Rx/Tx that
1902 * supports EHT-MCS 0-9) for each bandwidth (<= 80,
1903 * 160, 320) to find the maximum NSS. This assumes that
1904 * the lowest MCS rates support the largest number of spatial
1905 * streams. If values are different between Tx, Rx or the
1906 * bandwidths, choose the highest value.
1907 */
1908 for (i = 0; i < 3; i++) {
1909 rx_nss = mcs[3 * i] & 0x0F;
1910 if (rx_nss > max_nss)
1911 max_nss = rx_nss;
1912
1913 tx_nss = (mcs[3 * i] & 0xF0) >> 4;
1914 if (tx_nss > max_nss)
1915 max_nss = tx_nss;
1916 }
1917
1918 nss = max_nss;
1919 }
1920
1921 if (nss > 4)
1922 return FD_CAP_NSS_5_8 << FD_CAP_NSS_SHIFT;
1923 if (nss)
1924 return (nss - 1) << FD_CAP_NSS_SHIFT;
1925
1926 return 0;
1927}
1928
1929
Hai Shalom60840252021-02-19 19:02:11 -08001930static u16 hostapd_fils_discovery_cap(struct hostapd_data *hapd)
1931{
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001932 u16 cap_info, phy_index;
1933 u8 chwidth = FD_CAP_BSS_CHWIDTH_20, he_mcs_nss_size = 4;
Hai Shalom60840252021-02-19 19:02:11 -08001934 struct hostapd_hw_modes *mode = hapd->iface->current_mode;
1935
1936 cap_info = FD_CAP_ESS;
1937 if (hapd->conf->wpa)
1938 cap_info |= FD_CAP_PRIVACY;
1939
1940 if (is_6ghz_op_class(hapd->iconf->op_class)) {
Hai Shalom60840252021-02-19 19:02:11 -08001941 switch (hapd->iconf->op_class) {
Sunil Ravi036cec52023-03-29 11:35:17 -07001942 case 137:
1943 chwidth = FD_CAP_BSS_CHWIDTH_320;
1944 break;
Hai Shalom60840252021-02-19 19:02:11 -08001945 case 135:
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001946 he_mcs_nss_size += 4;
Hai Shalom60840252021-02-19 19:02:11 -08001947 /* fallthrough */
1948 case 134:
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001949 he_mcs_nss_size += 4;
Hai Shalom60840252021-02-19 19:02:11 -08001950 chwidth = FD_CAP_BSS_CHWIDTH_160_80_80;
1951 break;
1952 case 133:
1953 chwidth = FD_CAP_BSS_CHWIDTH_80;
1954 break;
1955 case 132:
1956 chwidth = FD_CAP_BSS_CHWIDTH_40;
1957 break;
1958 }
1959 } else {
1960 switch (hostapd_get_oper_chwidth(hapd->iconf)) {
Sunil8cd6f4d2022-06-28 18:40:46 +00001961 case CONF_OPER_CHWIDTH_80P80MHZ:
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001962 he_mcs_nss_size += 4;
Hai Shalom60840252021-02-19 19:02:11 -08001963 /* fallthrough */
Sunil8cd6f4d2022-06-28 18:40:46 +00001964 case CONF_OPER_CHWIDTH_160MHZ:
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001965 he_mcs_nss_size += 4;
Hai Shalom60840252021-02-19 19:02:11 -08001966 chwidth = FD_CAP_BSS_CHWIDTH_160_80_80;
1967 break;
Sunil8cd6f4d2022-06-28 18:40:46 +00001968 case CONF_OPER_CHWIDTH_80MHZ:
Hai Shalom60840252021-02-19 19:02:11 -08001969 chwidth = FD_CAP_BSS_CHWIDTH_80;
1970 break;
Sunil8cd6f4d2022-06-28 18:40:46 +00001971 case CONF_OPER_CHWIDTH_USE_HT:
Hai Shalom60840252021-02-19 19:02:11 -08001972 if (hapd->iconf->secondary_channel)
1973 chwidth = FD_CAP_BSS_CHWIDTH_40;
1974 else
1975 chwidth = FD_CAP_BSS_CHWIDTH_20;
1976 break;
Sunil8cd6f4d2022-06-28 18:40:46 +00001977 default:
1978 break;
Hai Shalom60840252021-02-19 19:02:11 -08001979 }
Hai Shalom60840252021-02-19 19:02:11 -08001980 }
1981
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001982 phy_index = hostapd_gen_fils_discovery_phy_index(hapd);
Hai Shalom60840252021-02-19 19:02:11 -08001983 cap_info |= phy_index << FD_CAP_PHY_INDEX_SHIFT;
1984 cap_info |= chwidth << FD_CAP_BSS_CHWIDTH_SHIFT;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001985 cap_info |= hostapd_gen_fils_discovery_nss(mode, phy_index,
1986 he_mcs_nss_size);
Hai Shalom60840252021-02-19 19:02:11 -08001987 return cap_info;
1988}
1989
1990
1991static u8 * hostapd_gen_fils_discovery(struct hostapd_data *hapd, size_t *len)
1992{
1993 struct ieee80211_mgmt *head;
1994 const u8 *mobility_domain;
1995 u8 *pos, *length_pos, buf[200];
1996 u16 ctl = 0;
1997 u8 fd_rsn_info[5];
1998 size_t total_len, buf_len;
1999
2000 total_len = 24 + 2 + 12;
2001
2002 /* FILS Discovery Frame Control */
2003 ctl = (sizeof(hapd->conf->ssid.short_ssid) - 1) |
2004 FD_FRAME_CTL_SHORT_SSID_PRESENT |
2005 FD_FRAME_CTL_LENGTH_PRESENT |
2006 FD_FRAME_CTL_CAP_PRESENT;
2007 total_len += 4 + 1 + 2;
2008
Sunil Ravi7f769292024-07-23 22:21:32 +00002009 /* Fill primary channel information for 6 GHz channels with over 20 MHz
2010 * bandwidth, if the primary channel is not a PSC */
2011 if (is_6ghz_op_class(hapd->iconf->op_class) &&
2012 !is_6ghz_psc_frequency(ieee80211_chan_to_freq(
2013 NULL, hapd->iconf->op_class,
2014 hapd->iconf->channel)) &&
2015 op_class_to_bandwidth(hapd->iconf->op_class) > 20) {
2016 ctl |= FD_FRAME_CTL_PRI_CHAN_PRESENT;
2017 total_len += 2;
2018 }
2019
Hai Shalom60840252021-02-19 19:02:11 -08002020 /* Check for optional subfields and calculate length */
2021 if (wpa_auth_write_fd_rsn_info(hapd->wpa_auth, fd_rsn_info)) {
2022 ctl |= FD_FRAME_CTL_RSN_INFO_PRESENT;
2023 total_len += sizeof(fd_rsn_info);
2024 }
2025
2026 mobility_domain = hostapd_wpa_ie(hapd, WLAN_EID_MOBILITY_DOMAIN);
2027 if (mobility_domain) {
2028 ctl |= FD_FRAME_CTL_MD_PRESENT;
2029 total_len += 3;
2030 }
2031
Sunil Ravi7f769292024-07-23 22:21:32 +00002032 total_len += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_ACTION, true);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002033
Hai Shalom60840252021-02-19 19:02:11 -08002034 pos = hostapd_eid_fils_indic(hapd, buf, 0);
2035 buf_len = pos - buf;
2036 total_len += buf_len;
2037
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002038 /* he_elem_len() may return too large a value for FD frame, but that is
2039 * fine here since this is used as the maximum length of the buffer. */
2040 total_len += he_elem_len(hapd);
Sunil Ravia04bd252022-05-02 22:54:18 -07002041
Hai Shalom60840252021-02-19 19:02:11 -08002042 head = os_zalloc(total_len);
2043 if (!head)
2044 return NULL;
2045
2046 head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
2047 WLAN_FC_STYPE_ACTION);
2048 os_memset(head->da, 0xff, ETH_ALEN);
2049 os_memcpy(head->sa, hapd->own_addr, ETH_ALEN);
2050 os_memcpy(head->bssid, hapd->own_addr, ETH_ALEN);
2051
2052 head->u.action.category = WLAN_ACTION_PUBLIC;
2053 head->u.action.u.public_action.action = WLAN_PA_FILS_DISCOVERY;
2054
2055 pos = &head->u.action.u.public_action.variable[0];
2056
2057 /* FILS Discovery Information field */
2058
2059 /* FILS Discovery Frame Control */
2060 WPA_PUT_LE16(pos, ctl);
2061 pos += 2;
2062
2063 /* Hardware or low-level driver will fill in the Timestamp value */
2064 pos += 8;
2065
2066 /* Beacon Interval */
2067 WPA_PUT_LE16(pos, hapd->iconf->beacon_int);
2068 pos += 2;
2069
2070 /* Short SSID */
2071 WPA_PUT_LE32(pos, hapd->conf->ssid.short_ssid);
2072 pos += sizeof(hapd->conf->ssid.short_ssid);
2073
2074 /* Store position of FILS discovery information element Length field */
2075 length_pos = pos++;
2076
2077 /* FD Capability */
2078 WPA_PUT_LE16(pos, hostapd_fils_discovery_cap(hapd));
2079 pos += 2;
2080
Sunil Ravi7f769292024-07-23 22:21:32 +00002081 /* Operating Class and Primary Channel - if a 6 GHz chan is non PSC */
2082 if (ctl & FD_FRAME_CTL_PRI_CHAN_PRESENT) {
2083 *pos++ = hapd->iconf->op_class;
2084 *pos++ = hapd->iconf->channel;
2085 }
Hai Shalom60840252021-02-19 19:02:11 -08002086
2087 /* AP Configuration Sequence Number - not present */
2088
2089 /* Access Network Options - not present */
2090
2091 /* FD RSN Information */
2092 if (ctl & FD_FRAME_CTL_RSN_INFO_PRESENT) {
2093 os_memcpy(pos, fd_rsn_info, sizeof(fd_rsn_info));
2094 pos += sizeof(fd_rsn_info);
2095 }
2096
2097 /* Channel Center Frequency Segment 1 - not present */
2098
2099 /* Mobility Domain */
2100 if (ctl & FD_FRAME_CTL_MD_PRESENT) {
2101 os_memcpy(pos, &mobility_domain[2], 3);
2102 pos += 3;
2103 }
2104
2105 /* Fill in the Length field value */
2106 *length_pos = pos - (length_pos + 1);
2107
Sunil Ravi7f769292024-07-23 22:21:32 +00002108 pos = hostapd_eid_rnr(hapd, pos, WLAN_FC_STYPE_ACTION, true);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002109
Hai Shalom60840252021-02-19 19:02:11 -08002110 /* FILS Indication element */
2111 if (buf_len) {
2112 os_memcpy(pos, buf, buf_len);
2113 pos += buf_len;
2114 }
2115
Sunil Ravia04bd252022-05-02 22:54:18 -07002116 if (is_6ghz_op_class(hapd->iconf->op_class))
2117 pos = hostapd_eid_txpower_envelope(hapd, pos);
2118
Hai Shalom60840252021-02-19 19:02:11 -08002119 *len = pos - (u8 *) head;
2120 wpa_hexdump(MSG_DEBUG, "FILS Discovery frame template",
2121 head, pos - (u8 *) head);
2122 return (u8 *) head;
2123}
2124
2125
2126/* Configure FILS Discovery frame transmission parameters */
2127static u8 * hostapd_fils_discovery(struct hostapd_data *hapd,
2128 struct wpa_driver_ap_params *params)
2129{
2130 params->fd_max_int = hapd->conf->fils_discovery_max_int;
2131 if (is_6ghz_op_class(hapd->iconf->op_class) &&
2132 params->fd_max_int > FD_MAX_INTERVAL_6GHZ)
2133 params->fd_max_int = FD_MAX_INTERVAL_6GHZ;
2134
2135 params->fd_min_int = hapd->conf->fils_discovery_min_int;
2136 if (params->fd_min_int > params->fd_max_int)
2137 params->fd_min_int = params->fd_max_int;
2138
2139 if (params->fd_max_int)
2140 return hostapd_gen_fils_discovery(hapd,
2141 &params->fd_frame_tmpl_len);
2142
2143 return NULL;
2144}
2145
2146#endif /* CONFIG_FILS */
2147
2148
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002149int ieee802_11_build_ap_params(struct hostapd_data *hapd,
2150 struct wpa_driver_ap_params *params)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002151{
2152 struct ieee80211_mgmt *head = NULL;
2153 u8 *tail = NULL;
2154 size_t head_len = 0, tail_len = 0;
2155 u8 *resp = NULL;
2156 size_t resp_len = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002157#ifdef NEED_AP_MLME
2158 u16 capab_info;
Hai Shalomfdcde762020-04-02 11:19:20 -07002159 u8 *pos, *tailpos, *tailend, *csa_pos;
Sunil Ravi77d572f2023-01-17 23:58:31 +00002160 bool complete = false;
2161#endif /* NEED_AP_MLME */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002162
Sunil Ravi77d572f2023-01-17 23:58:31 +00002163 os_memset(params, 0, sizeof(*params));
2164
2165#ifdef NEED_AP_MLME
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002166#define BEACON_HEAD_BUF_SIZE 256
Sunil Ravic0f5d412024-09-11 22:12:49 +00002167#define BEACON_TAIL_BUF_SIZE 1500
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002168 head = os_zalloc(BEACON_HEAD_BUF_SIZE);
2169 tail_len = BEACON_TAIL_BUF_SIZE;
2170#ifdef CONFIG_WPS
2171 if (hapd->conf->wps_state && hapd->wps_beacon_ie)
2172 tail_len += wpabuf_len(hapd->wps_beacon_ie);
2173#endif /* CONFIG_WPS */
2174#ifdef CONFIG_P2P
2175 if (hapd->p2p_beacon_ie)
2176 tail_len += wpabuf_len(hapd->p2p_beacon_ie);
2177#endif /* CONFIG_P2P */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002178#ifdef CONFIG_FST
2179 if (hapd->iface->fst_ies)
2180 tail_len += wpabuf_len(hapd->iface->fst_ies);
2181#endif /* CONFIG_FST */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002182 if (hapd->conf->vendor_elements)
2183 tail_len += wpabuf_len(hapd->conf->vendor_elements);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08002184
2185#ifdef CONFIG_IEEE80211AC
2186 if (hapd->conf->vendor_vht) {
2187 tail_len += 5 + 2 + sizeof(struct ieee80211_vht_capabilities) +
2188 2 + sizeof(struct ieee80211_vht_operation);
2189 }
2190#endif /* CONFIG_IEEE80211AC */
2191
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002192 tail_len += he_elem_len(hapd);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002193
Sunil Ravia04bd252022-05-02 22:54:18 -07002194#ifdef CONFIG_IEEE80211BE
2195 if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
2196 tail_len += hostapd_eid_eht_capab_len(hapd, IEEE80211_MODE_AP);
2197 tail_len += 3 + sizeof(struct ieee80211_eht_operation);
Sunil Ravi036cec52023-03-29 11:35:17 -07002198 if (hapd->iconf->punct_bitmap)
2199 tail_len += EHT_OPER_DISABLED_SUBCHAN_BITMAP_SIZE;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002200
2201 /*
2202 * TODO: Multi-Link element has variable length and can be
2203 * long based on the common info and number of per
2204 * station profiles. For now use 256.
2205 */
Sunil Ravic0f5d412024-09-11 22:12:49 +00002206 if (hapd->conf->mld_ap) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002207 tail_len += 256;
Sunil Ravic0f5d412024-09-11 22:12:49 +00002208
2209 /* for Max Channel Switch Time element during channel
2210 * switch */
2211 tail_len += 6;
2212 }
Sunil Ravia04bd252022-05-02 22:54:18 -07002213 }
2214#endif /* CONFIG_IEEE80211BE */
2215
Sunil Ravi77d572f2023-01-17 23:58:31 +00002216 if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED &&
2217 hapd == hostapd_mbssid_get_tx_bss(hapd))
2218 tail_len += 5; /* Multiple BSSID Configuration element */
Sunil Ravi7f769292024-07-23 22:21:32 +00002219 tail_len += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_BEACON, true);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002220 tail_len += hostapd_mbo_ie_len(hapd);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002221 tail_len += hostapd_eid_owe_trans_len(hapd);
Hai Shalomfdcde762020-04-02 11:19:20 -07002222 tail_len += hostapd_eid_dpp_cc_len(hapd);
Sunil Ravi7f769292024-07-23 22:21:32 +00002223 tail_len += hostapd_get_rsne_override_len(hapd);
2224 tail_len += hostapd_get_rsne_override_2_len(hapd);
2225 tail_len += hostapd_get_rsnxe_override_len(hapd);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002226
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002227 tailpos = tail = os_malloc(tail_len);
2228 if (head == NULL || tail == NULL) {
2229 wpa_printf(MSG_ERROR, "Failed to set beacon data");
2230 os_free(head);
2231 os_free(tail);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002232 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002233 }
Hai Shalomfdcde762020-04-02 11:19:20 -07002234 tailend = tail + tail_len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002235
2236 head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
2237 WLAN_FC_STYPE_BEACON);
2238 head->duration = host_to_le16(0);
2239 os_memset(head->da, 0xff, ETH_ALEN);
2240
2241 os_memcpy(head->sa, hapd->own_addr, ETH_ALEN);
2242 os_memcpy(head->bssid, hapd->own_addr, ETH_ALEN);
2243 head->u.beacon.beacon_int =
2244 host_to_le16(hapd->iconf->beacon_int);
2245
2246 /* hardware or low-level driver will setup seq_ctrl and timestamp */
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07002247 capab_info = hostapd_own_capab_info(hapd);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002248 head->u.beacon.capab_info = host_to_le16(capab_info);
2249 pos = &head->u.beacon.variable[0];
2250
2251 /* SSID */
2252 *pos++ = WLAN_EID_SSID;
2253 if (hapd->conf->ignore_broadcast_ssid == 2) {
2254 /* clear the data, but keep the correct length of the SSID */
2255 *pos++ = hapd->conf->ssid.ssid_len;
2256 os_memset(pos, 0, hapd->conf->ssid.ssid_len);
2257 pos += hapd->conf->ssid.ssid_len;
2258 } else if (hapd->conf->ignore_broadcast_ssid) {
2259 *pos++ = 0; /* empty SSID */
2260 } else {
2261 *pos++ = hapd->conf->ssid.ssid_len;
2262 os_memcpy(pos, hapd->conf->ssid.ssid,
2263 hapd->conf->ssid.ssid_len);
2264 pos += hapd->conf->ssid.ssid_len;
2265 }
2266
2267 /* Supported rates */
2268 pos = hostapd_eid_supp_rates(hapd, pos);
2269
2270 /* DS Params */
2271 pos = hostapd_eid_ds_params(hapd, pos);
2272
2273 head_len = pos - (u8 *) head;
2274
Hai Shalomfdcde762020-04-02 11:19:20 -07002275 tailpos = hostapd_eid_country(hapd, tailpos, tailend - tailpos);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002276
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002277 /* Power Constraint element */
2278 tailpos = hostapd_eid_pwr_constraint(hapd, tailpos);
2279
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002280 /* CSA IE */
2281 csa_pos = hostapd_eid_csa(hapd, tailpos);
2282 if (csa_pos != tailpos)
2283 hapd->cs_c_off_beacon = csa_pos - tail - 1;
2284 tailpos = csa_pos;
2285
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002286 /* ERP Information element */
2287 tailpos = hostapd_eid_erp_info(hapd, tailpos);
2288
2289 /* Extended supported rates */
2290 tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos);
2291
Hai Shalomfdcde762020-04-02 11:19:20 -07002292 tailpos = hostapd_get_rsne(hapd, tailpos, tailend - tailpos);
2293 tailpos = hostapd_eid_bss_load(hapd, tailpos, tailend - tailpos);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002294 tailpos = hostapd_eid_rm_enabled_capab(hapd, tailpos,
Hai Shalomfdcde762020-04-02 11:19:20 -07002295 tailend - tailpos);
2296 tailpos = hostapd_get_mde(hapd, tailpos, tailend - tailpos);
Dmitry Shmidt051af732013-10-22 13:52:46 -07002297
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002298 /* eCSA IE */
2299 csa_pos = hostapd_eid_ecsa(hapd, tailpos);
2300 if (csa_pos != tailpos)
2301 hapd->cs_c_off_ecsa_beacon = csa_pos - tail - 1;
2302 tailpos = csa_pos;
2303
2304 tailpos = hostapd_eid_supported_op_classes(hapd, tailpos);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002305 tailpos = hostapd_eid_ht_capabilities(hapd, tailpos);
2306 tailpos = hostapd_eid_ht_operation(hapd, tailpos);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002307
Sunil Ravi77d572f2023-01-17 23:58:31 +00002308 if (hapd->iconf->mbssid && hapd->iconf->num_bss > 1) {
2309 if (ieee802_11_build_ap_params_mbssid(hapd, params)) {
2310 os_free(head);
2311 os_free(tail);
2312 wpa_printf(MSG_ERROR,
2313 "MBSSID: Failed to set beacon data");
2314 return -1;
2315 }
2316 complete = hapd->iconf->mbssid == MBSSID_ENABLED ||
2317 (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED &&
2318 params->mbssid_elem_count == 1);
2319 }
2320
2321 tailpos = hostapd_eid_ext_capab(hapd, tailpos, complete);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002322
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002323 /*
2324 * TODO: Time Advertisement element should only be included in some
2325 * DTIM Beacon frames.
2326 */
2327 tailpos = hostapd_eid_time_adv(hapd, tailpos);
2328
2329 tailpos = hostapd_eid_interworking(hapd, tailpos);
2330 tailpos = hostapd_eid_adv_proto(hapd, tailpos);
2331 tailpos = hostapd_eid_roaming_consortium(hapd, tailpos);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002332
2333#ifdef CONFIG_FST
2334 if (hapd->iface->fst_ies) {
2335 os_memcpy(tailpos, wpabuf_head(hapd->iface->fst_ies),
2336 wpabuf_len(hapd->iface->fst_ies));
2337 tailpos += wpabuf_len(hapd->iface->fst_ies);
2338 }
2339#endif /* CONFIG_FST */
2340
Dmitry Shmidt04949592012-07-19 12:16:46 -07002341#ifdef CONFIG_IEEE80211AC
Hai Shalom60840252021-02-19 19:02:11 -08002342 if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac &&
2343 !is_6ghz_op_class(hapd->iconf->op_class)) {
Dmitry Shmidt7d175302016-09-06 13:11:34 -07002344 tailpos = hostapd_eid_vht_capabilities(hapd, tailpos, 0);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08002345 tailpos = hostapd_eid_vht_operation(hapd, tailpos);
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08002346 tailpos = hostapd_eid_txpower_envelope(hapd, tailpos);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08002347 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002348#endif /* CONFIG_IEEE80211AC */
2349
Hai Shalom60840252021-02-19 19:02:11 -08002350#ifdef CONFIG_IEEE80211AX
2351 if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax &&
2352 is_6ghz_op_class(hapd->iconf->op_class))
2353 tailpos = hostapd_eid_txpower_envelope(hapd, tailpos);
2354#endif /* CONFIG_IEEE80211AX */
2355
Sunil Ravic0f5d412024-09-11 22:12:49 +00002356 tailpos = hostapd_eid_chsw_wrapper(hapd, tailpos);
Hai Shalom899fcc72020-10-19 14:38:18 -07002357
Sunil Ravi7f769292024-07-23 22:21:32 +00002358 tailpos = hostapd_eid_rnr(hapd, tailpos, WLAN_FC_STYPE_BEACON, true);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002359 tailpos = hostapd_eid_fils_indic(hapd, tailpos, 0);
Sunil Ravic0f5d412024-09-11 22:12:49 +00002360
2361 /* Max Channel Switch Time element */
2362 tailpos = hostapd_eid_max_cs_time(hapd, tailpos);
2363
Hai Shalomfdcde762020-04-02 11:19:20 -07002364 tailpos = hostapd_get_rsnxe(hapd, tailpos, tailend - tailpos);
Sunil Ravi77d572f2023-01-17 23:58:31 +00002365 tailpos = hostapd_eid_mbssid_config(hapd, tailpos,
2366 params->mbssid_elem_count);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002367
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002368#ifdef CONFIG_IEEE80211AX
Hai Shalom60840252021-02-19 19:02:11 -08002369 if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
Sunil Ravia04bd252022-05-02 22:54:18 -07002370 u8 *cca_pos;
2371
Hai Shalom81f62d82019-07-22 12:10:00 -07002372 tailpos = hostapd_eid_he_capab(hapd, tailpos,
2373 IEEE80211_MODE_AP);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002374 tailpos = hostapd_eid_he_operation(hapd, tailpos);
Sunil Ravia04bd252022-05-02 22:54:18 -07002375
2376 /* BSS Color Change Announcement element */
2377 cca_pos = hostapd_eid_cca(hapd, tailpos);
2378 if (cca_pos != tailpos)
2379 hapd->cca_c_off_beacon = cca_pos - tail - 2;
2380 tailpos = cca_pos;
2381
Hai Shalom81f62d82019-07-22 12:10:00 -07002382 tailpos = hostapd_eid_spatial_reuse(hapd, tailpos);
Hai Shalomfdcde762020-04-02 11:19:20 -07002383 tailpos = hostapd_eid_he_mu_edca_parameter_set(hapd, tailpos);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002384 tailpos = hostapd_eid_he_6ghz_band_cap(hapd, tailpos);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002385 }
2386#endif /* CONFIG_IEEE80211AX */
2387
Sunil Ravia04bd252022-05-02 22:54:18 -07002388#ifdef CONFIG_IEEE80211BE
2389 if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002390 if (hapd->conf->mld_ap)
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002391 tailpos = hostapd_eid_eht_ml_beacon(hapd, NULL,
2392 tailpos, false);
Sunil Ravia04bd252022-05-02 22:54:18 -07002393 tailpos = hostapd_eid_eht_capab(hapd, tailpos,
2394 IEEE80211_MODE_AP);
2395 tailpos = hostapd_eid_eht_operation(hapd, tailpos);
2396 }
2397#endif /* CONFIG_IEEE80211BE */
2398
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002399#ifdef CONFIG_IEEE80211AC
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08002400 if (hapd->conf->vendor_vht)
2401 tailpos = hostapd_eid_vendor_vht(hapd, tailpos);
Dmitry Shmidt04949592012-07-19 12:16:46 -07002402#endif /* CONFIG_IEEE80211AC */
2403
Hai Shalomfdcde762020-04-02 11:19:20 -07002404 /* WPA / OSEN */
2405 tailpos = hostapd_get_wpa_ie(hapd, tailpos, tailend - tailpos);
2406 tailpos = hostapd_get_osen_ie(hapd, tailpos, tailend - tailpos);
Hai Shalom39ba6fc2019-01-22 12:40:38 -08002407
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002408 /* Wi-Fi Alliance WMM */
2409 tailpos = hostapd_eid_wmm(hapd, tailpos);
2410
2411#ifdef CONFIG_WPS
2412 if (hapd->conf->wps_state && hapd->wps_beacon_ie) {
2413 os_memcpy(tailpos, wpabuf_head(hapd->wps_beacon_ie),
2414 wpabuf_len(hapd->wps_beacon_ie));
2415 tailpos += wpabuf_len(hapd->wps_beacon_ie);
2416 }
2417#endif /* CONFIG_WPS */
2418
2419#ifdef CONFIG_P2P
2420 if ((hapd->conf->p2p & P2P_ENABLED) && hapd->p2p_beacon_ie) {
2421 os_memcpy(tailpos, wpabuf_head(hapd->p2p_beacon_ie),
2422 wpabuf_len(hapd->p2p_beacon_ie));
2423 tailpos += wpabuf_len(hapd->p2p_beacon_ie);
2424 }
2425#endif /* CONFIG_P2P */
2426#ifdef CONFIG_P2P_MANAGER
2427 if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) ==
2428 P2P_MANAGE)
2429 tailpos = hostapd_eid_p2p_manage(hapd, tailpos);
2430#endif /* CONFIG_P2P_MANAGER */
2431
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002432#ifdef CONFIG_HS20
2433 tailpos = hostapd_eid_hs20_indication(hapd, tailpos);
2434#endif /* CONFIG_HS20 */
2435
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002436 tailpos = hostapd_eid_mbo(hapd, tailpos, tail + tail_len - tailpos);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002437 tailpos = hostapd_eid_owe_trans(hapd, tailpos,
2438 tail + tail_len - tailpos);
Hai Shalomfdcde762020-04-02 11:19:20 -07002439 tailpos = hostapd_eid_dpp_cc(hapd, tailpos, tail + tail_len - tailpos);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002440
Sunil Ravi7f769292024-07-23 22:21:32 +00002441 tailpos = hostapd_get_rsne_override(hapd, tailpos,
2442 tail + tail_len - tailpos);
2443 tailpos = hostapd_get_rsne_override_2(hapd, tailpos,
2444 tail + tail_len - tailpos);
2445 tailpos = hostapd_get_rsnxe_override(hapd, tailpos,
2446 tail + tail_len - tailpos);
2447
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002448 if (hapd->conf->vendor_elements) {
2449 os_memcpy(tailpos, wpabuf_head(hapd->conf->vendor_elements),
2450 wpabuf_len(hapd->conf->vendor_elements));
2451 tailpos += wpabuf_len(hapd->conf->vendor_elements);
2452 }
2453
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002454 tail_len = tailpos > tail ? tailpos - tail : 0;
2455
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002456 resp = hostapd_probe_resp_offloads(hapd, &resp_len);
2457#endif /* NEED_AP_MLME */
2458
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002459 /* If key management offload is enabled, configure PSK to the driver. */
2460 if (wpa_key_mgmt_wpa_psk_no_sae(hapd->conf->wpa_key_mgmt) &&
2461 (hapd->iface->drv_flags2 &
2462 WPA_DRIVER_FLAGS2_4WAY_HANDSHAKE_AP_PSK)) {
2463 if (hapd->conf->ssid.wpa_psk && hapd->conf->ssid.wpa_psk_set) {
2464 os_memcpy(params->psk, hapd->conf->ssid.wpa_psk->psk,
2465 PMK_LEN);
2466 params->psk_len = PMK_LEN;
2467 } else if (hapd->conf->ssid.wpa_passphrase &&
2468 pbkdf2_sha1(hapd->conf->ssid.wpa_passphrase,
2469 hapd->conf->ssid.ssid,
2470 hapd->conf->ssid.ssid_len, 4096,
2471 params->psk, PMK_LEN) == 0) {
2472 params->psk_len = PMK_LEN;
2473 }
2474 }
2475
2476#ifdef CONFIG_SAE
2477 /* If SAE offload is enabled, provide password to lower layer for
2478 * SAE authentication and PMK generation.
2479 */
Sunil Ravi7f769292024-07-23 22:21:32 +00002480 if (wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt |
2481 hapd->conf->rsn_override_key_mgmt |
2482 hapd->conf->rsn_override_key_mgmt_2) &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002483 (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP)) {
2484 if (hostapd_sae_pk_in_use(hapd->conf)) {
2485 wpa_printf(MSG_ERROR,
2486 "SAE PK not supported with SAE offload");
2487 return -1;
2488 }
2489
2490 if (hostapd_sae_pw_id_in_use(hapd->conf)) {
2491 wpa_printf(MSG_ERROR,
2492 "SAE Password Identifiers not supported with SAE offload");
2493 return -1;
2494 }
2495
2496 params->sae_password = sae_get_password(hapd, NULL, NULL, NULL,
2497 NULL, NULL);
2498 if (!params->sae_password) {
2499 wpa_printf(MSG_ERROR, "SAE password not configured for offload");
2500 return -1;
2501 }
2502 }
2503#endif /* CONFIG_SAE */
2504
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002505 params->head = (u8 *) head;
2506 params->head_len = head_len;
2507 params->tail = tail;
2508 params->tail_len = tail_len;
2509 params->proberesp = resp;
2510 params->proberesp_len = resp_len;
2511 params->dtim_period = hapd->conf->dtim_period;
2512 params->beacon_int = hapd->iconf->beacon_int;
2513 params->basic_rates = hapd->iface->basic_rates;
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08002514 params->beacon_rate = hapd->iconf->beacon_rate;
2515 params->rate_type = hapd->iconf->rate_type;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002516 params->ssid = hapd->conf->ssid.ssid;
2517 params->ssid_len = hapd->conf->ssid.ssid_len;
Dmitry Shmidt7a53dbb2015-06-11 13:13:53 -07002518 if ((hapd->conf->wpa & (WPA_PROTO_WPA | WPA_PROTO_RSN)) ==
2519 (WPA_PROTO_WPA | WPA_PROTO_RSN))
2520 params->pairwise_ciphers = hapd->conf->wpa_pairwise |
2521 hapd->conf->rsn_pairwise;
2522 else if (hapd->conf->wpa & WPA_PROTO_RSN)
2523 params->pairwise_ciphers = hapd->conf->rsn_pairwise;
2524 else if (hapd->conf->wpa & WPA_PROTO_WPA)
2525 params->pairwise_ciphers = hapd->conf->wpa_pairwise;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002526 params->group_cipher = hapd->conf->wpa_group;
Sunil Ravi7f769292024-07-23 22:21:32 +00002527 params->key_mgmt_suites = hapd->conf->wpa_key_mgmt |
2528 hapd->conf->rsn_override_key_mgmt |
2529 hapd->conf->rsn_override_key_mgmt_2;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002530 params->auth_algs = hapd->conf->auth_algs;
2531 params->wpa_version = hapd->conf->wpa;
Hai Shalomfdcde762020-04-02 11:19:20 -07002532 params->privacy = hapd->conf->wpa;
2533#ifdef CONFIG_WEP
2534 params->privacy |= hapd->conf->ssid.wep.keys_set ||
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002535 (hapd->conf->ieee802_1x &&
2536 (hapd->conf->default_wep_key_len ||
2537 hapd->conf->individual_wep_key_len));
Hai Shalomfdcde762020-04-02 11:19:20 -07002538#endif /* CONFIG_WEP */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002539 switch (hapd->conf->ignore_broadcast_ssid) {
2540 case 0:
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002541 params->hide_ssid = NO_SSID_HIDING;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002542 break;
2543 case 1:
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002544 params->hide_ssid = HIDDEN_SSID_ZERO_LEN;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002545 break;
2546 case 2:
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002547 params->hide_ssid = HIDDEN_SSID_ZERO_CONTENTS;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002548 break;
2549 }
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002550 params->isolate = hapd->conf->isolate;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002551#ifdef NEED_AP_MLME
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002552 params->cts_protect = !!(ieee802_11_erp_info(hapd) &
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002553 ERP_INFO_USE_PROTECTION);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002554 params->preamble = hapd->iface->num_sta_no_short_preamble == 0 &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002555 hapd->iconf->preamble == SHORT_PREAMBLE;
2556 if (hapd->iface->current_mode &&
2557 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002558 params->short_slot_time =
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002559 hapd->iface->num_sta_no_short_slot_time > 0 ? 0 : 1;
2560 else
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002561 params->short_slot_time = -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002562 if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002563 params->ht_opmode = -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002564 else
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002565 params->ht_opmode = hapd->iface->ht_op_mode;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002566#endif /* NEED_AP_MLME */
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002567 params->interworking = hapd->conf->interworking;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002568 if (hapd->conf->interworking &&
2569 !is_zero_ether_addr(hapd->conf->hessid))
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002570 params->hessid = hapd->conf->hessid;
2571 params->access_network_type = hapd->conf->access_network_type;
2572 params->ap_max_inactivity = hapd->conf->ap_max_inactivity;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002573#ifdef CONFIG_P2P
2574 params->p2p_go_ctwindow = hapd->iconf->p2p_go_ctwindow;
2575#endif /* CONFIG_P2P */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002576#ifdef CONFIG_HS20
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002577 params->disable_dgaf = hapd->conf->disable_dgaf;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002578 if (hapd->conf->osen) {
2579 params->privacy = 1;
2580 params->osen = 1;
2581 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002582#endif /* CONFIG_HS20 */
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08002583 params->multicast_to_unicast = hapd->conf->multicast_to_unicast;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002584 params->pbss = hapd->conf->pbss;
Hai Shalom74f70d42019-02-11 14:42:39 -08002585
2586 if (hapd->conf->ftm_responder) {
2587 if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_FTM_RESPONDER) {
2588 params->ftm_responder = 1;
2589 params->lci = hapd->iface->conf->lci;
2590 params->civic = hapd->iface->conf->civic;
2591 } else {
2592 wpa_printf(MSG_WARNING,
2593 "Not configuring FTM responder as the driver doesn't advertise support for it");
2594 }
2595 }
2596
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002597#ifdef CONFIG_IEEE80211BE
2598 if (hapd->conf->mld_ap && hapd->iconf->ieee80211be &&
2599 !hapd->conf->disable_11be) {
2600 params->mld_ap = true;
2601 params->mld_link_id = hapd->mld_link_id;
2602 }
2603#endif /* CONFIG_IEEE80211BE */
2604
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002605 return 0;
2606}
2607
2608
2609void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params)
2610{
2611 os_free(params->tail);
2612 params->tail = NULL;
2613 os_free(params->head);
2614 params->head = NULL;
2615 os_free(params->proberesp);
2616 params->proberesp = NULL;
Sunil Ravi77d572f2023-01-17 23:58:31 +00002617 os_free(params->mbssid_elem);
2618 params->mbssid_elem = NULL;
2619 os_free(params->mbssid_elem_offset);
2620 params->mbssid_elem_offset = NULL;
Sunil Ravi640215c2023-06-28 23:08:09 +00002621 os_free(params->rnr_elem);
2622 params->rnr_elem = NULL;
2623 os_free(params->rnr_elem_offset);
2624 params->rnr_elem_offset = NULL;
Hai Shalom60840252021-02-19 19:02:11 -08002625#ifdef CONFIG_FILS
2626 os_free(params->fd_frame_tmpl);
2627 params->fd_frame_tmpl = NULL;
2628#endif /* CONFIG_FILS */
2629#ifdef CONFIG_IEEE80211AX
Sunil Ravi7f769292024-07-23 22:21:32 +00002630 os_free(params->ubpr.unsol_bcast_probe_resp_tmpl);
2631 params->ubpr.unsol_bcast_probe_resp_tmpl = NULL;
Hai Shalom60840252021-02-19 19:02:11 -08002632#endif /* CONFIG_IEEE80211AX */
Sunil Ravi640215c2023-06-28 23:08:09 +00002633 os_free(params->allowed_freqs);
2634 params->allowed_freqs = NULL;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002635}
2636
2637
Hai Shaloma20dcd72022-02-04 13:43:00 -08002638static int __ieee802_11_set_beacon(struct hostapd_data *hapd)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002639{
2640 struct wpa_driver_ap_params params;
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07002641 struct hostapd_freq_params freq;
2642 struct hostapd_iface *iface = hapd->iface;
2643 struct hostapd_config *iconf = iface->conf;
Hai Shalom81f62d82019-07-22 12:10:00 -07002644 struct hostapd_hw_modes *cmode = iface->current_mode;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002645 struct wpabuf *beacon, *proberesp, *assocresp;
Sunil Ravi7f769292024-07-23 22:21:32 +00002646 bool twt_he_responder = false;
Sunil Ravi640215c2023-06-28 23:08:09 +00002647 int res, ret = -1, i;
2648 struct hostapd_hw_modes *mode;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002649
Hai Shaloma20dcd72022-02-04 13:43:00 -08002650 if (!hapd->drv_priv) {
2651 wpa_printf(MSG_ERROR, "Interface is disabled");
2652 return -1;
2653 }
2654
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07002655 if (hapd->csa_in_progress) {
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002656 wpa_printf(MSG_ERROR, "Cannot set beacons during CSA period");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002657 return -1;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002658 }
2659
2660 hapd->beacon_set_done = 1;
2661
2662 if (ieee802_11_build_ap_params(hapd, &params) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002663 return -1;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002664
2665 if (hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp) <
2666 0)
2667 goto fail;
2668
2669 params.beacon_ies = beacon;
2670 params.proberesp_ies = proberesp;
2671 params.assocresp_ies = assocresp;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002672 params.reenable = hapd->reenable_beacon;
Hai Shalomc3565922019-10-28 11:58:20 -07002673#ifdef CONFIG_IEEE80211AX
Hai Shalom60840252021-02-19 19:02:11 -08002674 params.he_spr_ctrl = hapd->iface->conf->spr.sr_control;
2675 params.he_spr_non_srg_obss_pd_max_offset =
2676 hapd->iface->conf->spr.non_srg_obss_pd_max_offset;
Hai Shalomc3565922019-10-28 11:58:20 -07002677 params.he_spr_srg_obss_pd_min_offset =
2678 hapd->iface->conf->spr.srg_obss_pd_min_offset;
2679 params.he_spr_srg_obss_pd_max_offset =
2680 hapd->iface->conf->spr.srg_obss_pd_max_offset;
Hai Shalom60840252021-02-19 19:02:11 -08002681 os_memcpy(params.he_spr_bss_color_bitmap,
2682 hapd->iface->conf->spr.srg_bss_color_bitmap, 8);
2683 os_memcpy(params.he_spr_partial_bssid_bitmap,
2684 hapd->iface->conf->spr.srg_partial_bssid_bitmap, 8);
Hai Shalomfdcde762020-04-02 11:19:20 -07002685 params.he_bss_color_disabled =
2686 hapd->iface->conf->he_op.he_bss_color_disabled;
2687 params.he_bss_color_partial =
2688 hapd->iface->conf->he_op.he_bss_color_partial;
2689 params.he_bss_color = hapd->iface->conf->he_op.he_bss_color;
Sunil Ravi7f769292024-07-23 22:21:32 +00002690 twt_he_responder = hostapd_get_he_twt_responder(hapd,
2691 IEEE80211_MODE_AP);
2692 params.ubpr.unsol_bcast_probe_resp_tmpl =
2693 hostapd_unsol_bcast_probe_resp(hapd, &params.ubpr);
Hai Shalomc3565922019-10-28 11:58:20 -07002694#endif /* CONFIG_IEEE80211AX */
Sunil Ravi7f769292024-07-23 22:21:32 +00002695 params.twt_responder =
2696 twt_he_responder || hostapd_get_ht_vht_twt_responder(hapd);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002697 hapd->reenable_beacon = 0;
Hai Shalom60840252021-02-19 19:02:11 -08002698#ifdef CONFIG_SAE
2699 params.sae_pwe = hapd->conf->sae_pwe;
2700#endif /* CONFIG_SAE */
2701
2702#ifdef CONFIG_FILS
2703 params.fd_frame_tmpl = hostapd_fils_discovery(hapd, &params);
2704#endif /* CONFIG_FILS */
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002705
Sunil Ravi036cec52023-03-29 11:35:17 -07002706#ifdef CONFIG_IEEE80211BE
2707 params.punct_bitmap = iconf->punct_bitmap;
2708#endif /* CONFIG_IEEE80211BE */
2709
Hai Shalom81f62d82019-07-22 12:10:00 -07002710 if (cmode &&
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07002711 hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq,
Hai Shalomc3565922019-10-28 11:58:20 -07002712 iconf->channel, iconf->enable_edmg,
2713 iconf->edmg_channel, iconf->ieee80211n,
Hai Shalom81f62d82019-07-22 12:10:00 -07002714 iconf->ieee80211ac, iconf->ieee80211ax,
Sunil Ravia04bd252022-05-02 22:54:18 -07002715 iconf->ieee80211be,
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07002716 iconf->secondary_channel,
Hai Shalom81f62d82019-07-22 12:10:00 -07002717 hostapd_get_oper_chwidth(iconf),
2718 hostapd_get_oper_centr_freq_seg0_idx(iconf),
2719 hostapd_get_oper_centr_freq_seg1_idx(iconf),
2720 cmode->vht_capab,
Sunil Ravia04bd252022-05-02 22:54:18 -07002721 &cmode->he_capab[IEEE80211_MODE_AP],
Sunil Ravi99c035e2024-07-12 01:42:03 +00002722 &cmode->eht_capab[IEEE80211_MODE_AP],
Sunil Ravi7f769292024-07-23 22:21:32 +00002723 hostapd_get_punct_bitmap(hapd)) == 0) {
2724 freq.link_id = -1;
2725#ifdef CONFIG_IEEE80211BE
2726 if (hapd->conf->mld_ap)
2727 freq.link_id = hapd->mld_link_id;
2728#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07002729 params.freq = &freq;
Sunil Ravi7f769292024-07-23 22:21:32 +00002730 }
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07002731
Sunil Ravi640215c2023-06-28 23:08:09 +00002732 for (i = 0; i < hapd->iface->num_hw_features; i++) {
2733 mode = &hapd->iface->hw_features[i];
2734
2735 if (iconf->hw_mode != HOSTAPD_MODE_IEEE80211ANY &&
2736 iconf->hw_mode != mode->mode)
2737 continue;
2738
2739 hostapd_get_hw_mode_any_channels(hapd, mode,
2740 !(iconf->acs_freq_list.num ||
2741 iconf->acs_ch_list.num),
2742 true, &params.allowed_freqs);
2743 }
2744
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002745 res = hostapd_drv_set_ap(hapd, &params);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002746 hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002747 if (res)
2748 wpa_printf(MSG_ERROR, "Failed to set beacon parameters");
2749 else
2750 ret = 0;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002751fail:
2752 ieee802_11_free_ap_params(&params);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002753 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002754}
2755
2756
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002757void ieee802_11_set_beacon_per_bss_only(struct hostapd_data *hapd)
2758{
2759 __ieee802_11_set_beacon(hapd);
2760}
2761
2762
Sunil Ravic0f5d412024-09-11 22:12:49 +00002763#ifdef CONFIG_IEEE80211BE
2764
2765static int hostapd_get_probe_resp_tmpl(struct hostapd_data *hapd,
2766 struct probe_resp_params *params,
2767 bool is_ml_sta_info)
2768{
2769 os_memset(params, 0, sizeof(*params));
2770 hostapd_gen_probe_resp(hapd, params);
2771 if (!params->resp)
2772 return -1;
2773
2774 /* The caller takes care of freeing params->resp. */
2775 return 0;
2776}
2777
2778
2779static bool is_restricted_eid_in_sta_profile(u8 eid, bool tx_vap)
2780{
2781 switch (eid) {
2782 case WLAN_EID_TIM:
2783 case WLAN_EID_BSS_MAX_IDLE_PERIOD:
2784 case WLAN_EID_MULTIPLE_BSSID:
2785 case WLAN_EID_REDUCED_NEIGHBOR_REPORT:
2786 case WLAN_EID_NEIGHBOR_REPORT:
2787 return true;
2788 case WLAN_EID_SSID:
2789 /* SSID is not restricted for non-transmitted BSSID */
2790 return tx_vap;
2791 default:
2792 return false;
2793 }
2794}
2795
2796
2797static bool is_restricted_ext_eid_in_sta_profile(u8 ext_id)
2798{
2799 switch (ext_id) {
2800 case WLAN_EID_EXT_MULTI_LINK:
2801 return true;
2802 default:
2803 return false;
2804 }
2805}
2806
2807
2808/* Create the link STA profiles based on inheritance from the reporting
2809 * profile.
2810 *
2811 * NOTE: The same function is used for length calculation as well as filling
2812 * data in the given buffer. This avoids risk of not updating the length
2813 * function but filling function or vice versa.
2814 */
2815static size_t hostapd_add_sta_profile(struct ieee80211_mgmt *link_fdata,
2816 size_t link_data_len,
2817 struct ieee80211_mgmt *own_fdata,
2818 size_t own_data_len,
2819 u8 *sta_profile, bool tx_vap)
2820{
2821 const struct element *link_elem;
2822 size_t sta_profile_len = 0;
2823 const u8 *link_elem_data;
2824 u8 link_ele_len;
2825 u8 *link_data;
2826 const struct element *own_elem;
2827 u8 link_eid, own_eid, own_ele_len;
2828 const u8 *own_elem_data;
2829 u8 *own_data;
2830 bool is_ext;
2831 bool ie_found;
2832 u8 non_inherit_ele_ext_list[256] = { 0 };
2833 u8 non_inherit_ele_ext_list_len = 0;
2834 u8 non_inherit_ele_list[256] = { 0 };
2835 u8 non_inherit_ele_list_len = 0;
2836 u8 num_link_elem_vendor_ies = 0, num_own_elem_vendor_ies = 0;
2837 bool add_vendor_ies = false, is_identical_vendor_ies = true;
2838 /* The bitmap of parsed EIDs. There are 256 EIDs and ext EIDs, so 32
2839 * bytes to store the bitmaps. */
2840 u8 parsed_eid_bmap[32] = { 0 }, parsed_ext_eid_bmap[32] = { 0 };
2841 /* extra len used in the logic includes the element id and len */
2842 u8 extra_len = 2;
2843
2844 /* Include len for capab info */
2845 sta_profile_len += sizeof(le16);
2846 if (sta_profile) {
2847 os_memcpy(sta_profile, &link_fdata->u.probe_resp.capab_info,
2848 sizeof(le16));
2849 sta_profile += sizeof(le16);
2850 }
2851
2852 own_data = own_fdata->u.probe_resp.variable;
2853 link_data = link_fdata->u.probe_resp.variable;
2854
2855 /* The below logic takes the reporting BSS data and reported BSS data
2856 * and performs intersection to build the STA profile of the reported
2857 * BSS. Certain elements are not added to the STA profile as
2858 * recommended in standard. Matching element information in the
2859 * reporting BSS profile are ignored in the STA profile. Remaining
2860 * elements pertaining to the STA profile are appended at the end. */
2861 for_each_element(own_elem, own_data, own_data_len) {
2862 is_ext = false;
2863 ie_found = false;
2864
2865 /* Pick one of own elements and get its EID and length */
2866 own_elem_data = own_elem->data;
2867 own_ele_len = own_elem->datalen;
2868
2869 if (own_elem->id == WLAN_EID_EXTENSION) {
2870 is_ext = true;
2871 own_eid = *(own_elem_data);
2872 if (is_restricted_ext_eid_in_sta_profile(own_eid))
2873 continue;
2874 } else {
2875 own_eid = own_elem->id;
2876 if (is_restricted_eid_in_sta_profile(own_eid, tx_vap))
2877 continue;
2878 }
2879
2880 for_each_element(link_elem, link_data, link_data_len) {
2881 /* If the element type mismatches, do not consider
2882 * this link element for comparison. */
2883 if ((link_elem->id == WLAN_EID_EXTENSION &&
2884 !is_ext) ||
2885 (is_ext && link_elem->id != WLAN_EID_EXTENSION))
2886 continue;
2887
2888 /* Comparison can be done so get the link element and
2889 * its EID and length. */
2890 link_elem_data = link_elem->data;
2891 link_ele_len = link_elem->datalen;
2892
2893 if (link_elem->id == WLAN_EID_EXTENSION)
2894 link_eid = *(link_elem_data);
2895 else
2896 link_eid = link_elem->id;
2897
2898 /* Ignore if EID does not match */
2899 if (own_eid != link_eid)
2900 continue;
2901
2902 ie_found = true;
2903
2904 /* Ignore if the contents is identical. */
2905 if (own_ele_len == link_ele_len &&
2906 os_memcmp(own_elem->data, link_elem->data,
2907 own_ele_len) == 0) {
2908 if (own_eid == WLAN_EID_VENDOR_SPECIFIC) {
2909 is_identical_vendor_ies = true;
2910 num_own_elem_vendor_ies++;
2911 }
2912 continue;
2913 }
2914
2915 /* No need to include this non-matching Vendor Specific
2916 * element explicitly at this point. */
2917 if (own_eid == WLAN_EID_VENDOR_SPECIFIC) {
2918 is_identical_vendor_ies = false;
2919 continue;
2920 }
2921
2922 /* This element is present in the reported profile
2923 * as well as present in the reporting profile.
2924 * However, there is a mismatch in the contents and
2925 * hence, include this in the per STA profile. */
2926 sta_profile_len += link_ele_len + extra_len;
2927 if (sta_profile) {
2928 os_memcpy(sta_profile,
2929 link_elem->data - extra_len,
2930 link_ele_len + extra_len);
2931 sta_profile += link_ele_len + extra_len;
2932 }
2933
2934 /* Update the parsed EIDs bitmap */
2935 if (is_ext)
2936 parsed_ext_eid_bmap[own_eid / 8] |=
2937 BIT(own_eid % 8);
2938 else
2939 parsed_eid_bmap[own_eid / 8] |=
2940 BIT(own_eid % 8);
2941 break;
2942 }
2943
2944 /* We found at least one Vendor Specific element in reporting
2945 * link which is not same (or present) in the reported link. We
2946 * need to include all Vendor Specific elements from the
2947 * reported link. */
2948 if (!is_identical_vendor_ies)
2949 add_vendor_ies = true;
2950
2951 /* This is a unique element in the reporting profile which is
2952 * not present in the reported profile. Update the
2953 * non-inheritance list. */
2954 if (!ie_found) {
2955 u8 idx;
2956
2957 if (is_ext) {
2958 idx = non_inherit_ele_ext_list_len++;
2959 non_inherit_ele_ext_list[idx] = own_eid;
2960 } else {
2961 idx = non_inherit_ele_list_len++;
2962 non_inherit_ele_list[idx] = own_eid;
2963 }
2964 }
2965 }
2966
2967 /* Parse the remaining elements in the reported profile */
2968 for_each_element(link_elem, link_data, link_data_len) {
2969 link_elem_data = link_elem->data;
2970 link_ele_len = link_elem->datalen;
2971
2972 /* No need to check this Vendor Specific element at this point.
2973 * Just take the count and continue. */
2974 if (link_elem->id == WLAN_EID_VENDOR_SPECIFIC) {
2975 num_link_elem_vendor_ies++;
2976 continue;
2977 }
2978
2979 if (link_elem->id == WLAN_EID_EXTENSION) {
2980 link_eid = *(link_elem_data);
2981
2982 if ((parsed_ext_eid_bmap[link_eid / 8] &
2983 BIT(link_eid % 8)) ||
2984 is_restricted_ext_eid_in_sta_profile(link_eid))
2985 continue;
2986 } else {
2987 link_eid = link_elem->id;
2988
2989 if ((parsed_eid_bmap[link_eid / 8] &
2990 BIT(link_eid % 8)) ||
2991 is_restricted_eid_in_sta_profile(link_eid, tx_vap))
2992 continue;
2993 }
2994
2995 sta_profile_len += link_ele_len + extra_len;
2996 if (sta_profile) {
2997 os_memcpy(sta_profile, link_elem_data - extra_len,
2998 link_ele_len + extra_len);
2999 sta_profile += link_ele_len + extra_len;
3000 }
3001 }
3002
3003 /* Handle Vendor Specific elements
3004 * Add all the Vendor Specific elements of the reported link if
3005 * a. There is at least one non-matching Vendor Specific element, or
3006 * b. The number of Vendor Specific elements in reporting and reported
3007 * link is not same. */
3008 if (add_vendor_ies ||
3009 num_own_elem_vendor_ies != num_link_elem_vendor_ies) {
3010 for_each_element(link_elem, link_data, link_data_len) {
3011 link_elem_data = link_elem->data;
3012 link_ele_len = link_elem->datalen;
3013
3014 if (link_elem->id != WLAN_EID_VENDOR_SPECIFIC)
3015 continue;
3016
3017 sta_profile_len += link_ele_len + extra_len;
3018 if (sta_profile) {
3019 os_memcpy(sta_profile,
3020 link_elem_data - extra_len,
3021 link_ele_len + extra_len);
3022 sta_profile += link_ele_len + extra_len;
3023 }
3024 }
3025 }
3026
3027 /* Handle non-inheritance
3028 * Non-Inheritance element:
3029 * Element ID Ext: 1 octet
3030 * Length: 1 octet
3031 * Ext tag number: 1 octet
3032 * Length of Elements ID list: 1 octet
3033 * Elements ID list: variable
3034 * Length of Elements ID Extension list: 1 octet
3035 * Elements ID extensions list: variable
3036 */
3037 if (non_inherit_ele_list_len || non_inherit_ele_ext_list_len)
3038 sta_profile_len += 3 + 2 + non_inherit_ele_list_len +
3039 non_inherit_ele_ext_list_len;
3040
3041 if (sta_profile &&
3042 (non_inherit_ele_list_len || non_inherit_ele_ext_list_len)) {
3043 *sta_profile++ = WLAN_EID_EXTENSION;
3044 *sta_profile++ = non_inherit_ele_list_len +
3045 non_inherit_ele_ext_list_len + 3;
3046 *sta_profile++ = WLAN_EID_EXT_NON_INHERITANCE;
3047 *sta_profile++ = non_inherit_ele_list_len;
3048 os_memcpy(sta_profile, non_inherit_ele_list,
3049 non_inherit_ele_list_len);
3050 sta_profile += non_inherit_ele_list_len;
3051 *sta_profile++ = non_inherit_ele_ext_list_len;
3052 os_memcpy(sta_profile, non_inherit_ele_ext_list,
3053 non_inherit_ele_ext_list_len);
3054 sta_profile += non_inherit_ele_ext_list_len;
3055 }
3056
3057 return sta_profile_len;
3058}
3059
3060
3061static u8 * hostapd_gen_sta_profile(struct ieee80211_mgmt *link_data,
3062 size_t link_data_len,
3063 struct ieee80211_mgmt *own_data,
3064 size_t own_data_len,
3065 size_t *sta_profile_len, bool tx_vap)
3066{
3067 u8 *sta_profile;
3068
3069 /* Get the length first */
3070 *sta_profile_len = hostapd_add_sta_profile(link_data, link_data_len,
3071 own_data, own_data_len,
3072 NULL, tx_vap);
3073 if (!(*sta_profile_len) || *sta_profile_len > EHT_ML_MAX_STA_PROF_LEN)
3074 return NULL;
3075
3076 sta_profile = os_zalloc(*sta_profile_len);
3077 if (!sta_profile)
3078 return NULL;
3079
3080 /* Now fill in the data */
3081 hostapd_add_sta_profile(link_data, link_data_len, own_data,
3082 own_data_len, sta_profile, tx_vap);
3083
3084 /* The caller takes care of freeing the returned sta_profile */
3085 return sta_profile;
3086}
3087
3088
3089static void hostapd_gen_per_sta_profiles(struct hostapd_data *hapd)
3090{
3091 bool tx_vap = hapd == hostapd_mbssid_get_tx_bss(hapd);
3092 size_t link_data_len, sta_profile_len;
3093 size_t own_data_len;
3094 struct probe_resp_params link_params;
3095 struct probe_resp_params own_params;
3096 struct ieee80211_mgmt *link_data;
3097 struct ieee80211_mgmt *own_data;
3098 struct mld_link_info *link_info;
3099 struct hostapd_data *link_bss;
3100 u8 link_id, *sta_profile;
3101
3102 if (!hapd->conf->mld_ap)
3103 return;
3104
3105 wpa_printf(MSG_DEBUG, "MLD: Generating per STA profiles for MLD %s",
3106 hapd->conf->iface);
3107
3108 wpa_printf(MSG_DEBUG, "MLD: Reporting link %d", hapd->mld_link_id);
3109
3110 /* Generate a Probe Response template for self */
3111 if (hostapd_get_probe_resp_tmpl(hapd, &own_params, false)) {
3112 wpa_printf(MSG_ERROR,
3113 "MLD: Error in building per STA profiles");
3114 return;
3115 }
3116
3117 own_data = own_params.resp;
3118 own_data_len = own_params.resp_len;
3119
3120 /* Consider the length of the variable fields */
3121 own_data_len -= offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3122
3123 for_each_mld_link(link_bss, hapd) {
3124 if (link_bss == hapd || !link_bss->started)
3125 continue;
3126
3127 link_id = link_bss->mld_link_id;
3128 if (link_id >= MAX_NUM_MLD_LINKS)
3129 continue;
3130
3131 sta_profile = NULL;
3132 sta_profile_len = 0;
3133
3134 /* Generate a Probe Response frame template for partner link */
3135 if (hostapd_get_probe_resp_tmpl(link_bss, &link_params, true)) {
3136 wpa_printf(MSG_ERROR,
3137 "MLD: Could not get link STA probe response template for link %d",
3138 link_id);
3139 continue;
3140 }
3141
3142 link_data = link_params.resp;
3143 link_data_len = link_params.resp_len;
3144
3145 /* Consider length of the variable fields */
3146 link_data_len -= offsetof(struct ieee80211_mgmt,
3147 u.probe_resp.variable);
3148
3149 sta_profile = hostapd_gen_sta_profile(link_data, link_data_len,
3150 own_data, own_data_len,
3151 &sta_profile_len, tx_vap);
3152 if (!sta_profile) {
3153 wpa_printf(MSG_ERROR,
3154 "MLD: Could not generate link STA profile for link %d",
3155 link_id);
3156 continue;
3157 }
3158
3159 link_info = &hapd->partner_links[link_id];
3160 link_info->valid = true;
3161
3162 os_free(link_info->resp_sta_profile);
3163 link_info->resp_sta_profile_len = sta_profile_len;
3164
3165 link_info->resp_sta_profile = os_memdup(sta_profile,
3166 sta_profile_len);
3167 if (!link_info->resp_sta_profile)
3168 link_info->resp_sta_profile_len = 0;
3169
3170 os_memcpy(link_info->local_addr, link_bss->own_addr, ETH_ALEN);
3171
3172 wpa_printf(MSG_DEBUG,
3173 "MLD: Reported link STA info for %d: %u bytes",
3174 link_id, link_info->resp_sta_profile_len);
3175
3176 os_free(sta_profile);
3177 os_free(link_params.resp);
3178 }
3179
3180 os_free(own_params.resp);
3181}
3182
3183#endif /* CONFIG_IEEE80211BE */
3184
3185
Hai Shaloma20dcd72022-02-04 13:43:00 -08003186int ieee802_11_set_beacon(struct hostapd_data *hapd)
3187{
3188 struct hostapd_iface *iface = hapd->iface;
3189 int ret;
3190 size_t i, j;
Sunil Ravi7f769292024-07-23 22:21:32 +00003191 bool is_6g, hapd_mld = false;
Sunil Ravic0f5d412024-09-11 22:12:49 +00003192#ifdef CONFIG_IEEE80211BE
3193 struct hostapd_data *link_bss;
3194#endif /* CONFIG_IEEE80211BE */
Hai Shaloma20dcd72022-02-04 13:43:00 -08003195
3196 ret = __ieee802_11_set_beacon(hapd);
3197 if (ret != 0)
3198 return ret;
3199
3200 if (!iface->interfaces || iface->interfaces->count <= 1)
3201 return 0;
3202
Sunil Ravi7f769292024-07-23 22:21:32 +00003203#ifdef CONFIG_IEEE80211BE
3204 hapd_mld = hapd->conf->mld_ap;
3205#endif /* CONFIG_IEEE80211BE */
3206
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003207 /* Update Beacon frames in case of 6 GHz colocation or AP MLD */
Hai Shaloma20dcd72022-02-04 13:43:00 -08003208 is_6g = is_6ghz_op_class(iface->conf->op_class);
3209 for (j = 0; j < iface->interfaces->count; j++) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003210 struct hostapd_iface *other;
Sunil Ravi7f769292024-07-23 22:21:32 +00003211 bool other_iface_6g;
Hai Shaloma20dcd72022-02-04 13:43:00 -08003212
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003213 other = iface->interfaces->iface[j];
3214 if (other == iface || !other || !other->conf)
Hai Shaloma20dcd72022-02-04 13:43:00 -08003215 continue;
3216
Sunil Ravi7f769292024-07-23 22:21:32 +00003217 other_iface_6g = is_6ghz_op_class(other->conf->op_class);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003218
Sunil Ravi7f769292024-07-23 22:21:32 +00003219 if (is_6g == other_iface_6g && !hapd_mld)
Hai Shaloma20dcd72022-02-04 13:43:00 -08003220 continue;
3221
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003222 for (i = 0; i < other->num_bss; i++) {
Sunil Ravi7f769292024-07-23 22:21:32 +00003223#ifdef CONFIG_IEEE80211BE
3224 if (is_6g == other_iface_6g &&
3225 !(hapd_mld && other->bss[i]->conf->mld_ap &&
3226 hostapd_is_ml_partner(hapd, other->bss[i])))
3227 continue;
3228#endif /* CONFIG_IEEE80211BE */
3229
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003230 if (other->bss[i] && other->bss[i]->started)
3231 __ieee802_11_set_beacon(other->bss[i]);
Hai Shaloma20dcd72022-02-04 13:43:00 -08003232 }
3233 }
3234
Sunil Ravic0f5d412024-09-11 22:12:49 +00003235#ifdef CONFIG_IEEE80211BE
3236 if (!hapd_mld)
3237 return 0;
3238
3239 /* Generate per STA profiles for each affiliated APs */
3240 for_each_mld_link(link_bss, hapd)
3241 hostapd_gen_per_sta_profiles(link_bss);
3242#endif /* CONFIG_IEEE80211BE */
3243
Hai Shaloma20dcd72022-02-04 13:43:00 -08003244 return 0;
3245}
3246
3247
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003248int ieee802_11_set_beacons(struct hostapd_iface *iface)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003249{
3250 size_t i;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003251 int ret = 0;
3252
Dmitry Shmidt292b0c32013-11-22 12:54:42 -08003253 for (i = 0; i < iface->num_bss; i++) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003254 if (iface->bss[i]->started &&
3255 ieee802_11_set_beacon(iface->bss[i]) < 0)
3256 ret = -1;
Dmitry Shmidt292b0c32013-11-22 12:54:42 -08003257 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003258
3259 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003260}
3261
Dmitry Shmidt04949592012-07-19 12:16:46 -07003262
3263/* only update beacons if started */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003264int ieee802_11_update_beacons(struct hostapd_iface *iface)
Dmitry Shmidt04949592012-07-19 12:16:46 -07003265{
3266 size_t i;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003267 int ret = 0;
3268
3269 for (i = 0; i < iface->num_bss; i++) {
3270 if (iface->bss[i]->beacon_set_done && iface->bss[i]->started &&
3271 ieee802_11_set_beacon(iface->bss[i]) < 0)
3272 ret = -1;
3273 }
3274
3275 return ret;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003276}
3277
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003278#endif /* CONFIG_NATIVE_WINDOWS */