1e28a4053SRui Paulo /*
2e28a4053SRui Paulo * hostapd / IEEE 802.11 Management: Beacon and Probe Request/Response
3e28a4053SRui Paulo * Copyright (c) 2002-2004, Instant802 Networks, Inc.
4e28a4053SRui Paulo * Copyright (c) 2005-2006, Devicescape Software, Inc.
5f05cddf9SRui Paulo * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
6e28a4053SRui Paulo *
75b9c547cSRui Paulo * This software may be distributed under the terms of the BSD license.
85b9c547cSRui Paulo * See README for more details.
9e28a4053SRui Paulo */
10e28a4053SRui Paulo
11e28a4053SRui Paulo #include "utils/includes.h"
12e28a4053SRui Paulo
13e28a4053SRui Paulo #ifndef CONFIG_NATIVE_WINDOWS
14e28a4053SRui Paulo
15e28a4053SRui Paulo #include "utils/common.h"
16e28a4053SRui Paulo #include "common/ieee802_11_defs.h"
17e28a4053SRui Paulo #include "common/ieee802_11_common.h"
185b9c547cSRui Paulo #include "common/hw_features_common.h"
1985732ac8SCy Schubert #include "common/wpa_ctrl.h"
20*a90b9d01SCy Schubert #include "crypto/sha1.h"
21f05cddf9SRui Paulo #include "wps/wps_defs.h"
22f05cddf9SRui Paulo #include "p2p/p2p.h"
23e28a4053SRui Paulo #include "hostapd.h"
24e28a4053SRui Paulo #include "ieee802_11.h"
25e28a4053SRui Paulo #include "wpa_auth.h"
26e28a4053SRui Paulo #include "wmm.h"
27e28a4053SRui Paulo #include "ap_config.h"
28e28a4053SRui Paulo #include "sta_info.h"
29f05cddf9SRui Paulo #include "p2p_hostapd.h"
30f05cddf9SRui Paulo #include "ap_drv_ops.h"
31e28a4053SRui Paulo #include "beacon.h"
32f05cddf9SRui Paulo #include "hs20.h"
335b9c547cSRui Paulo #include "dfs.h"
34780fb4a2SCy Schubert #include "taxonomy.h"
3585732ac8SCy Schubert #include "ieee802_11_auth.h"
36e28a4053SRui Paulo
37e28a4053SRui Paulo
38f05cddf9SRui Paulo #ifdef NEED_AP_MLME
39f05cddf9SRui Paulo
hostapd_eid_bss_load(struct hostapd_data * hapd,u8 * eid,size_t len)405b9c547cSRui Paulo static u8 * hostapd_eid_bss_load(struct hostapd_data *hapd, u8 *eid, size_t len)
415b9c547cSRui Paulo {
425b9c547cSRui Paulo if (len < 2 + 5)
435b9c547cSRui Paulo return eid;
445b9c547cSRui Paulo
455b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS
465b9c547cSRui Paulo if (hapd->conf->bss_load_test_set) {
475b9c547cSRui Paulo *eid++ = WLAN_EID_BSS_LOAD;
485b9c547cSRui Paulo *eid++ = 5;
495b9c547cSRui Paulo os_memcpy(eid, hapd->conf->bss_load_test, 5);
505b9c547cSRui Paulo eid += 5;
515b9c547cSRui Paulo return eid;
525b9c547cSRui Paulo }
535b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */
545b9c547cSRui Paulo if (hapd->conf->bss_load_update_period) {
555b9c547cSRui Paulo *eid++ = WLAN_EID_BSS_LOAD;
565b9c547cSRui Paulo *eid++ = 5;
575b9c547cSRui Paulo WPA_PUT_LE16(eid, hapd->num_sta);
585b9c547cSRui Paulo eid += 2;
595b9c547cSRui Paulo *eid++ = hapd->iface->channel_utilization;
605b9c547cSRui Paulo WPA_PUT_LE16(eid, 0); /* no available admission capabity */
615b9c547cSRui Paulo eid += 2;
625b9c547cSRui Paulo }
635b9c547cSRui Paulo return eid;
645b9c547cSRui Paulo }
655b9c547cSRui Paulo
665b9c547cSRui Paulo
ieee802_11_erp_info(struct hostapd_data * hapd)67e28a4053SRui Paulo static u8 ieee802_11_erp_info(struct hostapd_data *hapd)
68e28a4053SRui Paulo {
69e28a4053SRui Paulo u8 erp = 0;
70e28a4053SRui Paulo
71e28a4053SRui Paulo if (hapd->iface->current_mode == NULL ||
72e28a4053SRui Paulo hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
73e28a4053SRui Paulo return 0;
74e28a4053SRui Paulo
75e28a4053SRui Paulo if (hapd->iface->olbc)
76e28a4053SRui Paulo erp |= ERP_INFO_USE_PROTECTION;
77e28a4053SRui Paulo if (hapd->iface->num_sta_non_erp > 0) {
78e28a4053SRui Paulo erp |= ERP_INFO_NON_ERP_PRESENT |
79e28a4053SRui Paulo ERP_INFO_USE_PROTECTION;
80e28a4053SRui Paulo }
81e28a4053SRui Paulo if (hapd->iface->num_sta_no_short_preamble > 0 ||
82e28a4053SRui Paulo hapd->iconf->preamble == LONG_PREAMBLE)
83e28a4053SRui Paulo erp |= ERP_INFO_BARKER_PREAMBLE_MODE;
84e28a4053SRui Paulo
85e28a4053SRui Paulo return erp;
86e28a4053SRui Paulo }
87e28a4053SRui Paulo
88e28a4053SRui Paulo
hostapd_eid_ds_params(struct hostapd_data * hapd,u8 * eid)89e28a4053SRui Paulo static u8 * hostapd_eid_ds_params(struct hostapd_data *hapd, u8 *eid)
90e28a4053SRui Paulo {
91*a90b9d01SCy Schubert enum hostapd_hw_mode hw_mode = hapd->iconf->hw_mode;
92*a90b9d01SCy Schubert
93*a90b9d01SCy Schubert if (hw_mode != HOSTAPD_MODE_IEEE80211G &&
94*a90b9d01SCy Schubert hw_mode != HOSTAPD_MODE_IEEE80211B)
95*a90b9d01SCy Schubert return eid;
96*a90b9d01SCy Schubert
97e28a4053SRui Paulo *eid++ = WLAN_EID_DS_PARAMS;
98e28a4053SRui Paulo *eid++ = 1;
99e28a4053SRui Paulo *eid++ = hapd->iconf->channel;
100e28a4053SRui Paulo return eid;
101e28a4053SRui Paulo }
102e28a4053SRui Paulo
103e28a4053SRui Paulo
hostapd_eid_erp_info(struct hostapd_data * hapd,u8 * eid)104e28a4053SRui Paulo static u8 * hostapd_eid_erp_info(struct hostapd_data *hapd, u8 *eid)
105e28a4053SRui Paulo {
106e28a4053SRui Paulo if (hapd->iface->current_mode == NULL ||
107e28a4053SRui Paulo hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
108e28a4053SRui Paulo return eid;
109e28a4053SRui Paulo
110e28a4053SRui Paulo /* Set NonERP_present and use_protection bits if there
111e28a4053SRui Paulo * are any associated NonERP stations. */
112e28a4053SRui Paulo /* TODO: use_protection bit can be set to zero even if
113e28a4053SRui Paulo * there are NonERP stations present. This optimization
114e28a4053SRui Paulo * might be useful if NonERP stations are "quiet".
115e28a4053SRui Paulo * See 802.11g/D6 E-1 for recommended practice.
116e28a4053SRui Paulo * In addition, Non ERP present might be set, if AP detects Non ERP
117e28a4053SRui Paulo * operation on other APs. */
118e28a4053SRui Paulo
119e28a4053SRui Paulo /* Add ERP Information element */
120e28a4053SRui Paulo *eid++ = WLAN_EID_ERP_INFO;
121e28a4053SRui Paulo *eid++ = 1;
122e28a4053SRui Paulo *eid++ = ieee802_11_erp_info(hapd);
123e28a4053SRui Paulo
124e28a4053SRui Paulo return eid;
125e28a4053SRui Paulo }
126e28a4053SRui Paulo
127e28a4053SRui Paulo
hostapd_eid_pwr_constraint(struct hostapd_data * hapd,u8 * eid)1285b9c547cSRui Paulo static u8 * hostapd_eid_pwr_constraint(struct hostapd_data *hapd, u8 *eid)
1295b9c547cSRui Paulo {
1305b9c547cSRui Paulo u8 *pos = eid;
1315b9c547cSRui Paulo u8 local_pwr_constraint = 0;
1325b9c547cSRui Paulo int dfs;
1335b9c547cSRui Paulo
1345b9c547cSRui Paulo if (hapd->iface->current_mode == NULL ||
1355b9c547cSRui Paulo hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
1365b9c547cSRui Paulo return eid;
1375b9c547cSRui Paulo
1385b9c547cSRui Paulo /* Let host drivers add this IE if DFS support is offloaded */
1395b9c547cSRui Paulo if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
1405b9c547cSRui Paulo return eid;
1415b9c547cSRui Paulo
1425b9c547cSRui Paulo /*
1435b9c547cSRui Paulo * There is no DFS support and power constraint was not directly
1445b9c547cSRui Paulo * requested by config option.
1455b9c547cSRui Paulo */
1465b9c547cSRui Paulo if (!hapd->iconf->ieee80211h &&
1475b9c547cSRui Paulo hapd->iconf->local_pwr_constraint == -1)
1485b9c547cSRui Paulo return eid;
1495b9c547cSRui Paulo
1505b9c547cSRui Paulo /* Check if DFS is required by regulatory. */
1515b9c547cSRui Paulo dfs = hostapd_is_dfs_required(hapd->iface);
1525b9c547cSRui Paulo if (dfs < 0) {
1535b9c547cSRui Paulo wpa_printf(MSG_WARNING, "Failed to check if DFS is required; ret=%d",
1545b9c547cSRui Paulo dfs);
1555b9c547cSRui Paulo dfs = 0;
1565b9c547cSRui Paulo }
1575b9c547cSRui Paulo
1585b9c547cSRui Paulo if (dfs == 0 && hapd->iconf->local_pwr_constraint == -1)
1595b9c547cSRui Paulo return eid;
1605b9c547cSRui Paulo
1615b9c547cSRui Paulo /*
1625b9c547cSRui Paulo * ieee80211h (DFS) is enabled so Power Constraint element shall
1635b9c547cSRui Paulo * be added when running on DFS channel whenever local_pwr_constraint
1645b9c547cSRui Paulo * is configured or not. In order to meet regulations when TPC is not
1655b9c547cSRui Paulo * implemented using a transmit power that is below the legal maximum
1665b9c547cSRui Paulo * (including any mitigation factor) should help. In this case,
1675b9c547cSRui Paulo * indicate 3 dB below maximum allowed transmit power.
1685b9c547cSRui Paulo */
1695b9c547cSRui Paulo if (hapd->iconf->local_pwr_constraint == -1)
1705b9c547cSRui Paulo local_pwr_constraint = 3;
1715b9c547cSRui Paulo
1725b9c547cSRui Paulo /*
1735b9c547cSRui Paulo * A STA that is not an AP shall use a transmit power less than or
1745b9c547cSRui Paulo * equal to the local maximum transmit power level for the channel.
1755b9c547cSRui Paulo * The local maximum transmit power can be calculated from the formula:
1765b9c547cSRui Paulo * local max TX pwr = max TX pwr - local pwr constraint
1775b9c547cSRui Paulo * Where max TX pwr is maximum transmit power level specified for
1785b9c547cSRui Paulo * channel in Country element and local pwr constraint is specified
1795b9c547cSRui Paulo * for channel in this Power Constraint element.
1805b9c547cSRui Paulo */
1815b9c547cSRui Paulo
1825b9c547cSRui Paulo /* Element ID */
1835b9c547cSRui Paulo *pos++ = WLAN_EID_PWR_CONSTRAINT;
1845b9c547cSRui Paulo /* Length */
1855b9c547cSRui Paulo *pos++ = 1;
1865b9c547cSRui Paulo /* Local Power Constraint */
1875b9c547cSRui Paulo if (local_pwr_constraint)
1885b9c547cSRui Paulo *pos++ = local_pwr_constraint;
1895b9c547cSRui Paulo else
1905b9c547cSRui Paulo *pos++ = hapd->iconf->local_pwr_constraint;
1915b9c547cSRui Paulo
1925b9c547cSRui Paulo return pos;
1935b9c547cSRui Paulo }
1945b9c547cSRui Paulo
1955b9c547cSRui Paulo
hostapd_eid_country_add(struct hostapd_data * hapd,u8 * pos,u8 * end,int chan_spacing,struct hostapd_channel_data * start,struct hostapd_channel_data * prev)196*a90b9d01SCy Schubert static u8 * hostapd_eid_country_add(struct hostapd_data *hapd, u8 *pos,
197*a90b9d01SCy Schubert u8 *end, int chan_spacing,
198e28a4053SRui Paulo struct hostapd_channel_data *start,
199e28a4053SRui Paulo struct hostapd_channel_data *prev)
200e28a4053SRui Paulo {
201e28a4053SRui Paulo if (end - pos < 3)
202e28a4053SRui Paulo return pos;
203e28a4053SRui Paulo
204e28a4053SRui Paulo /* first channel number */
205e28a4053SRui Paulo *pos++ = start->chan;
206e28a4053SRui Paulo /* number of channels */
207e28a4053SRui Paulo *pos++ = (prev->chan - start->chan) / chan_spacing + 1;
208e28a4053SRui Paulo /* maximum transmit power level */
209*a90b9d01SCy Schubert if (!is_6ghz_op_class(hapd->iconf->op_class))
210e28a4053SRui Paulo *pos++ = start->max_tx_power;
211*a90b9d01SCy Schubert else
212*a90b9d01SCy Schubert *pos++ = 0; /* Reserved when operating on the 6 GHz band */
213e28a4053SRui Paulo
214e28a4053SRui Paulo return pos;
215e28a4053SRui Paulo }
216e28a4053SRui Paulo
217e28a4053SRui Paulo
hostapd_fill_subband_triplets(struct hostapd_data * hapd,u8 * pos,u8 * end)218*a90b9d01SCy Schubert static u8 * hostapd_fill_subband_triplets(struct hostapd_data *hapd, u8 *pos,
219*a90b9d01SCy Schubert u8 *end)
220e28a4053SRui Paulo {
221e28a4053SRui Paulo int i;
222e28a4053SRui Paulo struct hostapd_hw_modes *mode;
223e28a4053SRui Paulo struct hostapd_channel_data *start, *prev;
224e28a4053SRui Paulo int chan_spacing = 1;
225e28a4053SRui Paulo
226e28a4053SRui Paulo mode = hapd->iface->current_mode;
227e28a4053SRui Paulo if (mode->mode == HOSTAPD_MODE_IEEE80211A)
228e28a4053SRui Paulo chan_spacing = 4;
229e28a4053SRui Paulo
230e28a4053SRui Paulo start = prev = NULL;
231e28a4053SRui Paulo for (i = 0; i < mode->num_channels; i++) {
232e28a4053SRui Paulo struct hostapd_channel_data *chan = &mode->channels[i];
233e28a4053SRui Paulo if (chan->flag & HOSTAPD_CHAN_DISABLED)
234e28a4053SRui Paulo continue;
235e28a4053SRui Paulo if (start && prev &&
236e28a4053SRui Paulo prev->chan + chan_spacing == chan->chan &&
237e28a4053SRui Paulo start->max_tx_power == chan->max_tx_power) {
238e28a4053SRui Paulo prev = chan;
239e28a4053SRui Paulo continue; /* can use same entry */
240e28a4053SRui Paulo }
241e28a4053SRui Paulo
242*a90b9d01SCy Schubert if (start && prev)
243*a90b9d01SCy Schubert pos = hostapd_eid_country_add(hapd, pos, end,
244*a90b9d01SCy Schubert chan_spacing,
245e28a4053SRui Paulo start, prev);
246e28a4053SRui Paulo
247e28a4053SRui Paulo /* Start new group */
248e28a4053SRui Paulo start = prev = chan;
249e28a4053SRui Paulo }
250e28a4053SRui Paulo
251e28a4053SRui Paulo if (start) {
252*a90b9d01SCy Schubert pos = hostapd_eid_country_add(hapd, pos, end, chan_spacing,
253e28a4053SRui Paulo start, prev);
254e28a4053SRui Paulo }
255e28a4053SRui Paulo
256*a90b9d01SCy Schubert return pos;
257*a90b9d01SCy Schubert }
258*a90b9d01SCy Schubert
259*a90b9d01SCy Schubert
hostapd_eid_country(struct hostapd_data * hapd,u8 * eid,int max_len)260*a90b9d01SCy Schubert static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
261*a90b9d01SCy Schubert int max_len)
262*a90b9d01SCy Schubert {
263*a90b9d01SCy Schubert u8 *pos = eid;
264*a90b9d01SCy Schubert u8 *end = eid + max_len;
265*a90b9d01SCy Schubert
266*a90b9d01SCy Schubert if (!hapd->iconf->ieee80211d || max_len < 6 ||
267*a90b9d01SCy Schubert hapd->iface->current_mode == NULL)
268*a90b9d01SCy Schubert return eid;
269*a90b9d01SCy Schubert
270*a90b9d01SCy Schubert *pos++ = WLAN_EID_COUNTRY;
271*a90b9d01SCy Schubert pos++; /* length will be set later */
272*a90b9d01SCy Schubert os_memcpy(pos, hapd->iconf->country, 3); /* e.g., 'US ' */
273*a90b9d01SCy Schubert pos += 3;
274*a90b9d01SCy Schubert
275*a90b9d01SCy Schubert if (is_6ghz_op_class(hapd->iconf->op_class)) {
276*a90b9d01SCy Schubert /* Force the third octet of the country string to indicate
277*a90b9d01SCy Schubert * Global Operating Class (Table E-4) */
278*a90b9d01SCy Schubert eid[4] = 0x04;
279*a90b9d01SCy Schubert
280*a90b9d01SCy Schubert /* Operating Triplet field */
281*a90b9d01SCy Schubert /* Operating Extension Identifier (>= 201 to indicate this is
282*a90b9d01SCy Schubert * not a Subband Triplet field) */
283*a90b9d01SCy Schubert *pos++ = 201;
284*a90b9d01SCy Schubert /* Operating Class */
285*a90b9d01SCy Schubert *pos++ = hapd->iconf->op_class;
286*a90b9d01SCy Schubert /* Coverage Class */
287*a90b9d01SCy Schubert *pos++ = 0;
288*a90b9d01SCy Schubert /* Subband Triplets are required only for the 20 MHz case */
289*a90b9d01SCy Schubert if (hapd->iconf->op_class == 131 ||
290*a90b9d01SCy Schubert hapd->iconf->op_class == 136)
291*a90b9d01SCy Schubert pos = hostapd_fill_subband_triplets(hapd, pos, end);
292*a90b9d01SCy Schubert } else {
293*a90b9d01SCy Schubert pos = hostapd_fill_subband_triplets(hapd, pos, end);
294*a90b9d01SCy Schubert }
295*a90b9d01SCy Schubert
296e28a4053SRui Paulo if ((pos - eid) & 1) {
297e28a4053SRui Paulo if (end - pos < 1)
298e28a4053SRui Paulo return eid;
299e28a4053SRui Paulo *pos++ = 0; /* pad for 16-bit alignment */
300e28a4053SRui Paulo }
301e28a4053SRui Paulo
302e28a4053SRui Paulo eid[1] = (pos - eid) - 2;
303e28a4053SRui Paulo
304e28a4053SRui Paulo return pos;
305e28a4053SRui Paulo }
306e28a4053SRui Paulo
307e28a4053SRui Paulo
hostapd_wpa_ie(struct hostapd_data * hapd,u8 eid)308c1d255d3SCy Schubert const u8 * hostapd_wpa_ie(struct hostapd_data *hapd, u8 eid)
309c1d255d3SCy Schubert {
310c1d255d3SCy Schubert const u8 *ies;
311c1d255d3SCy Schubert size_t ies_len;
312c1d255d3SCy Schubert
313c1d255d3SCy Schubert ies = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ies_len);
314c1d255d3SCy Schubert if (!ies)
315c1d255d3SCy Schubert return NULL;
316c1d255d3SCy Schubert
317c1d255d3SCy Schubert return get_ie(ies, ies_len, eid);
318c1d255d3SCy Schubert }
319c1d255d3SCy Schubert
320c1d255d3SCy Schubert
hostapd_vendor_wpa_ie(struct hostapd_data * hapd,u32 vendor_type)321c1d255d3SCy Schubert static const u8 * hostapd_vendor_wpa_ie(struct hostapd_data *hapd,
322c1d255d3SCy Schubert u32 vendor_type)
323c1d255d3SCy Schubert {
324c1d255d3SCy Schubert const u8 *ies;
325c1d255d3SCy Schubert size_t ies_len;
326c1d255d3SCy Schubert
327c1d255d3SCy Schubert ies = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ies_len);
328c1d255d3SCy Schubert if (!ies)
329c1d255d3SCy Schubert return NULL;
330c1d255d3SCy Schubert
331c1d255d3SCy Schubert return get_vendor_ie(ies, ies_len, vendor_type);
332c1d255d3SCy Schubert }
333c1d255d3SCy Schubert
334c1d255d3SCy Schubert
hostapd_get_rsne(struct hostapd_data * hapd,u8 * pos,size_t len)335c1d255d3SCy Schubert static u8 * hostapd_get_rsne(struct hostapd_data *hapd, u8 *pos, size_t len)
336e28a4053SRui Paulo {
337e28a4053SRui Paulo const u8 *ie;
338e28a4053SRui Paulo
339c1d255d3SCy Schubert ie = hostapd_wpa_ie(hapd, WLAN_EID_RSN);
340c1d255d3SCy Schubert if (!ie || 2U + ie[1] > len)
341c1d255d3SCy Schubert return pos;
342e28a4053SRui Paulo
343c1d255d3SCy Schubert os_memcpy(pos, ie, 2 + ie[1]);
344c1d255d3SCy Schubert return pos + 2 + ie[1];
345c1d255d3SCy Schubert }
346c1d255d3SCy Schubert
347c1d255d3SCy Schubert
hostapd_get_mde(struct hostapd_data * hapd,u8 * pos,size_t len)348c1d255d3SCy Schubert static u8 * hostapd_get_mde(struct hostapd_data *hapd, u8 *pos, size_t len)
349c1d255d3SCy Schubert {
350c1d255d3SCy Schubert const u8 *ie;
351c1d255d3SCy Schubert
352c1d255d3SCy Schubert ie = hostapd_wpa_ie(hapd, WLAN_EID_MOBILITY_DOMAIN);
353c1d255d3SCy Schubert if (!ie || 2U + ie[1] > len)
354c1d255d3SCy Schubert return pos;
355c1d255d3SCy Schubert
356c1d255d3SCy Schubert os_memcpy(pos, ie, 2 + ie[1]);
357c1d255d3SCy Schubert return pos + 2 + ie[1];
358c1d255d3SCy Schubert }
359c1d255d3SCy Schubert
360c1d255d3SCy Schubert
hostapd_get_rsnxe(struct hostapd_data * hapd,u8 * pos,size_t len)361c1d255d3SCy Schubert static u8 * hostapd_get_rsnxe(struct hostapd_data *hapd, u8 *pos, size_t len)
362c1d255d3SCy Schubert {
363c1d255d3SCy Schubert const u8 *ie;
364c1d255d3SCy Schubert
365c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
366c1d255d3SCy Schubert if (hapd->conf->no_beacon_rsnxe) {
367c1d255d3SCy Schubert wpa_printf(MSG_INFO, "TESTING: Do not add RSNXE into Beacon");
368c1d255d3SCy Schubert return pos;
369c1d255d3SCy Schubert }
370c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
371c1d255d3SCy Schubert ie = hostapd_wpa_ie(hapd, WLAN_EID_RSNX);
372c1d255d3SCy Schubert if (!ie || 2U + ie[1] > len)
373c1d255d3SCy Schubert return pos;
374c1d255d3SCy Schubert
375c1d255d3SCy Schubert os_memcpy(pos, ie, 2 + ie[1]);
376c1d255d3SCy Schubert return pos + 2 + ie[1];
377c1d255d3SCy Schubert }
378c1d255d3SCy Schubert
379c1d255d3SCy Schubert
hostapd_get_wpa_ie(struct hostapd_data * hapd,u8 * pos,size_t len)380c1d255d3SCy Schubert static u8 * hostapd_get_wpa_ie(struct hostapd_data *hapd, u8 *pos, size_t len)
381c1d255d3SCy Schubert {
382c1d255d3SCy Schubert const u8 *ie;
383c1d255d3SCy Schubert
384c1d255d3SCy Schubert ie = hostapd_vendor_wpa_ie(hapd, WPA_IE_VENDOR_TYPE);
385c1d255d3SCy Schubert if (!ie || 2U + ie[1] > len)
386c1d255d3SCy Schubert return pos;
387c1d255d3SCy Schubert
388c1d255d3SCy Schubert os_memcpy(pos, ie, 2 + ie[1]);
389c1d255d3SCy Schubert return pos + 2 + ie[1];
390c1d255d3SCy Schubert }
391c1d255d3SCy Schubert
392c1d255d3SCy Schubert
hostapd_get_osen_ie(struct hostapd_data * hapd,u8 * pos,size_t len)393c1d255d3SCy Schubert static u8 * hostapd_get_osen_ie(struct hostapd_data *hapd, u8 *pos, size_t len)
394c1d255d3SCy Schubert {
395c1d255d3SCy Schubert const u8 *ie;
396c1d255d3SCy Schubert
397c1d255d3SCy Schubert ie = hostapd_vendor_wpa_ie(hapd, OSEN_IE_VENDOR_TYPE);
398c1d255d3SCy Schubert if (!ie || 2U + ie[1] > len)
399c1d255d3SCy Schubert return pos;
400c1d255d3SCy Schubert
401c1d255d3SCy Schubert os_memcpy(pos, ie, 2 + ie[1]);
402c1d255d3SCy Schubert return pos + 2 + ie[1];
403e28a4053SRui Paulo }
404e28a4053SRui Paulo
405e28a4053SRui Paulo
hostapd_eid_csa(struct hostapd_data * hapd,u8 * eid)4065b9c547cSRui Paulo static u8 * hostapd_eid_csa(struct hostapd_data *hapd, u8 *eid)
4075b9c547cSRui Paulo {
408780fb4a2SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
409780fb4a2SCy Schubert if (hapd->iface->cs_oper_class && hapd->iconf->ecsa_ie_only)
4105b9c547cSRui Paulo return eid;
411780fb4a2SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
4125b9c547cSRui Paulo
413780fb4a2SCy Schubert if (!hapd->cs_freq_params.channel)
4145b9c547cSRui Paulo return eid;
4155b9c547cSRui Paulo
4165b9c547cSRui Paulo *eid++ = WLAN_EID_CHANNEL_SWITCH;
4175b9c547cSRui Paulo *eid++ = 3;
4185b9c547cSRui Paulo *eid++ = hapd->cs_block_tx;
419780fb4a2SCy Schubert *eid++ = hapd->cs_freq_params.channel;
4205b9c547cSRui Paulo *eid++ = hapd->cs_count;
4215b9c547cSRui Paulo
4225b9c547cSRui Paulo return eid;
4235b9c547cSRui Paulo }
4245b9c547cSRui Paulo
4255b9c547cSRui Paulo
hostapd_eid_ecsa(struct hostapd_data * hapd,u8 * eid)426780fb4a2SCy Schubert static u8 * hostapd_eid_ecsa(struct hostapd_data *hapd, u8 *eid)
4275b9c547cSRui Paulo {
428780fb4a2SCy Schubert if (!hapd->cs_freq_params.channel || !hapd->iface->cs_oper_class)
4295b9c547cSRui Paulo return eid;
4305b9c547cSRui Paulo
431780fb4a2SCy Schubert *eid++ = WLAN_EID_EXT_CHANSWITCH_ANN;
432780fb4a2SCy Schubert *eid++ = 4;
433780fb4a2SCy Schubert *eid++ = hapd->cs_block_tx;
434780fb4a2SCy Schubert *eid++ = hapd->iface->cs_oper_class;
435780fb4a2SCy Schubert *eid++ = hapd->cs_freq_params.channel;
436780fb4a2SCy Schubert *eid++ = hapd->cs_count;
4375b9c547cSRui Paulo
4385b9c547cSRui Paulo return eid;
4395b9c547cSRui Paulo }
4405b9c547cSRui Paulo
4415b9c547cSRui Paulo
hostapd_eid_supported_op_classes(struct hostapd_data * hapd,u8 * eid)442780fb4a2SCy Schubert static u8 * hostapd_eid_supported_op_classes(struct hostapd_data *hapd, u8 *eid)
4435b9c547cSRui Paulo {
444780fb4a2SCy Schubert u8 op_class, channel;
4455b9c547cSRui Paulo
446780fb4a2SCy Schubert if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA) ||
447780fb4a2SCy Schubert !hapd->iface->freq)
448780fb4a2SCy Schubert return eid;
4495b9c547cSRui Paulo
450780fb4a2SCy Schubert if (ieee80211_freq_to_channel_ext(hapd->iface->freq,
451780fb4a2SCy Schubert hapd->iconf->secondary_channel,
452206b73d0SCy Schubert hostapd_get_oper_chwidth(hapd->iconf),
453780fb4a2SCy Schubert &op_class, &channel) ==
454780fb4a2SCy Schubert NUM_HOSTAPD_MODES)
455780fb4a2SCy Schubert return eid;
4565b9c547cSRui Paulo
457780fb4a2SCy Schubert *eid++ = WLAN_EID_SUPPORTED_OPERATING_CLASSES;
458780fb4a2SCy Schubert *eid++ = 2;
4595b9c547cSRui Paulo
460780fb4a2SCy Schubert /* Current Operating Class */
461780fb4a2SCy Schubert *eid++ = op_class;
462780fb4a2SCy Schubert
463780fb4a2SCy Schubert /* TODO: Advertise all the supported operating classes */
464780fb4a2SCy Schubert *eid++ = 0;
465780fb4a2SCy Schubert
466780fb4a2SCy Schubert return eid;
4675b9c547cSRui Paulo }
4685b9c547cSRui Paulo
4695b9c547cSRui Paulo
470*a90b9d01SCy Schubert static int
ieee802_11_build_ap_params_mbssid(struct hostapd_data * hapd,struct wpa_driver_ap_params * params)471*a90b9d01SCy Schubert ieee802_11_build_ap_params_mbssid(struct hostapd_data *hapd,
472*a90b9d01SCy Schubert struct wpa_driver_ap_params *params)
473e28a4053SRui Paulo {
474*a90b9d01SCy Schubert struct hostapd_iface *iface = hapd->iface;
475*a90b9d01SCy Schubert struct hostapd_data *tx_bss;
476*a90b9d01SCy Schubert size_t len, rnr_len = 0;
477*a90b9d01SCy Schubert u8 elem_count = 0, *elem = NULL, **elem_offset = NULL, *end;
478*a90b9d01SCy Schubert u8 rnr_elem_count = 0, *rnr_elem = NULL, **rnr_elem_offset = NULL;
479*a90b9d01SCy Schubert size_t i;
480e28a4053SRui Paulo
481*a90b9d01SCy Schubert if (!iface->mbssid_max_interfaces ||
482*a90b9d01SCy Schubert iface->num_bss > iface->mbssid_max_interfaces ||
483*a90b9d01SCy Schubert (iface->conf->mbssid == ENHANCED_MBSSID_ENABLED &&
484*a90b9d01SCy Schubert !iface->ema_max_periodicity))
485*a90b9d01SCy Schubert goto fail;
486*a90b9d01SCy Schubert
487*a90b9d01SCy Schubert /* Make sure bss->xrates_supported is set for all BSSs to know whether
488*a90b9d01SCy Schubert * it need to be non-inherited. */
489*a90b9d01SCy Schubert for (i = 0; i < iface->num_bss; i++) {
490*a90b9d01SCy Schubert u8 buf[100];
491*a90b9d01SCy Schubert
492*a90b9d01SCy Schubert hostapd_eid_ext_supp_rates(iface->bss[i], buf);
493*a90b9d01SCy Schubert }
494*a90b9d01SCy Schubert
495*a90b9d01SCy Schubert tx_bss = hostapd_mbssid_get_tx_bss(hapd);
496*a90b9d01SCy Schubert len = hostapd_eid_mbssid_len(tx_bss, WLAN_FC_STYPE_BEACON, &elem_count,
497*a90b9d01SCy Schubert NULL, 0, &rnr_len);
498*a90b9d01SCy Schubert if (!len || (iface->conf->mbssid == ENHANCED_MBSSID_ENABLED &&
499*a90b9d01SCy Schubert elem_count > iface->ema_max_periodicity))
500*a90b9d01SCy Schubert goto fail;
501*a90b9d01SCy Schubert
502*a90b9d01SCy Schubert elem = os_zalloc(len);
503*a90b9d01SCy Schubert if (!elem)
504*a90b9d01SCy Schubert goto fail;
505*a90b9d01SCy Schubert
506*a90b9d01SCy Schubert elem_offset = os_zalloc(elem_count * sizeof(u8 *));
507*a90b9d01SCy Schubert if (!elem_offset)
508*a90b9d01SCy Schubert goto fail;
509*a90b9d01SCy Schubert
510*a90b9d01SCy Schubert if (rnr_len) {
511*a90b9d01SCy Schubert rnr_elem = os_zalloc(rnr_len);
512*a90b9d01SCy Schubert if (!rnr_elem)
513*a90b9d01SCy Schubert goto fail;
514*a90b9d01SCy Schubert
515*a90b9d01SCy Schubert rnr_elem_offset = os_calloc(elem_count + 1, sizeof(u8 *));
516*a90b9d01SCy Schubert if (!rnr_elem_offset)
517*a90b9d01SCy Schubert goto fail;
518*a90b9d01SCy Schubert }
519*a90b9d01SCy Schubert
520*a90b9d01SCy Schubert end = hostapd_eid_mbssid(tx_bss, elem, elem + len, WLAN_FC_STYPE_BEACON,
521*a90b9d01SCy Schubert elem_count, elem_offset, NULL, 0, rnr_elem,
522*a90b9d01SCy Schubert &rnr_elem_count, rnr_elem_offset, rnr_len);
523*a90b9d01SCy Schubert
524*a90b9d01SCy Schubert params->mbssid_tx_iface = tx_bss->conf->iface;
525*a90b9d01SCy Schubert params->mbssid_index = hostapd_mbssid_get_bss_index(hapd);
526*a90b9d01SCy Schubert params->mbssid_elem = elem;
527*a90b9d01SCy Schubert params->mbssid_elem_len = end - elem;
528*a90b9d01SCy Schubert params->mbssid_elem_count = elem_count;
529*a90b9d01SCy Schubert params->mbssid_elem_offset = elem_offset;
530*a90b9d01SCy Schubert params->rnr_elem = rnr_elem;
531*a90b9d01SCy Schubert params->rnr_elem_len = rnr_len;
532*a90b9d01SCy Schubert params->rnr_elem_count = rnr_elem_count;
533*a90b9d01SCy Schubert params->rnr_elem_offset = rnr_elem_offset;
534*a90b9d01SCy Schubert if (iface->conf->mbssid == ENHANCED_MBSSID_ENABLED)
535*a90b9d01SCy Schubert params->ema = true;
536*a90b9d01SCy Schubert
537*a90b9d01SCy Schubert return 0;
538*a90b9d01SCy Schubert
539*a90b9d01SCy Schubert fail:
540*a90b9d01SCy Schubert os_free(rnr_elem);
541*a90b9d01SCy Schubert os_free(rnr_elem_offset);
542*a90b9d01SCy Schubert os_free(elem_offset);
543*a90b9d01SCy Schubert os_free(elem);
544*a90b9d01SCy Schubert wpa_printf(MSG_ERROR, "MBSSID: Configuration failed");
545*a90b9d01SCy Schubert return -1;
546*a90b9d01SCy Schubert }
547*a90b9d01SCy Schubert
548*a90b9d01SCy Schubert
hostapd_eid_mbssid_config(struct hostapd_data * hapd,u8 * eid,u8 mbssid_elem_count)549*a90b9d01SCy Schubert static u8 * hostapd_eid_mbssid_config(struct hostapd_data *hapd, u8 *eid,
550*a90b9d01SCy Schubert u8 mbssid_elem_count)
551*a90b9d01SCy Schubert {
552*a90b9d01SCy Schubert struct hostapd_iface *iface = hapd->iface;
553*a90b9d01SCy Schubert
554*a90b9d01SCy Schubert if (iface->conf->mbssid == ENHANCED_MBSSID_ENABLED) {
555*a90b9d01SCy Schubert *eid++ = WLAN_EID_EXTENSION;
556*a90b9d01SCy Schubert *eid++ = 3;
557*a90b9d01SCy Schubert *eid++ = WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION;
558*a90b9d01SCy Schubert *eid++ = iface->num_bss;
559*a90b9d01SCy Schubert *eid++ = mbssid_elem_count;
560*a90b9d01SCy Schubert }
561*a90b9d01SCy Schubert
562*a90b9d01SCy Schubert return eid;
563*a90b9d01SCy Schubert }
564*a90b9d01SCy Schubert
565*a90b9d01SCy Schubert
he_elem_len(struct hostapd_data * hapd)566*a90b9d01SCy Schubert static size_t he_elem_len(struct hostapd_data *hapd)
567*a90b9d01SCy Schubert {
568*a90b9d01SCy Schubert size_t len = 0;
569*a90b9d01SCy Schubert
570*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211AX
571*a90b9d01SCy Schubert if (!hapd->iconf->ieee80211ax || hapd->conf->disable_11ax)
572*a90b9d01SCy Schubert return len;
573*a90b9d01SCy Schubert
574*a90b9d01SCy Schubert len += 3 + sizeof(struct ieee80211_he_capabilities) +
575*a90b9d01SCy Schubert 3 + sizeof(struct ieee80211_he_operation) +
576*a90b9d01SCy Schubert 3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) +
577*a90b9d01SCy Schubert 3 + sizeof(struct ieee80211_spatial_reuse);
578*a90b9d01SCy Schubert if (is_6ghz_op_class(hapd->iconf->op_class)) {
579*a90b9d01SCy Schubert len += sizeof(struct ieee80211_he_6ghz_oper_info) +
580*a90b9d01SCy Schubert 3 + sizeof(struct ieee80211_he_6ghz_band_cap);
581*a90b9d01SCy Schubert /* An additional Transmit Power Envelope element for
582*a90b9d01SCy Schubert * subordinate client */
583*a90b9d01SCy Schubert if (he_reg_is_indoor(hapd->iconf->he_6ghz_reg_pwr_type))
584*a90b9d01SCy Schubert len += 4;
585*a90b9d01SCy Schubert
586*a90b9d01SCy Schubert /* An additional Transmit Power Envelope element for
587*a90b9d01SCy Schubert * default client with unit interpretation of regulatory
588*a90b9d01SCy Schubert * client EIRP */
589*a90b9d01SCy Schubert if (hapd->iconf->reg_def_cli_eirp != -1 &&
590*a90b9d01SCy Schubert he_reg_is_sp(hapd->iconf->he_6ghz_reg_pwr_type))
591*a90b9d01SCy Schubert len += 4;
592*a90b9d01SCy Schubert }
593*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211AX */
594*a90b9d01SCy Schubert
595*a90b9d01SCy Schubert return len;
596*a90b9d01SCy Schubert }
597*a90b9d01SCy Schubert
598*a90b9d01SCy Schubert
599*a90b9d01SCy Schubert struct probe_resp_params {
600*a90b9d01SCy Schubert const struct ieee80211_mgmt *req;
601*a90b9d01SCy Schubert bool is_p2p;
602*a90b9d01SCy Schubert
603*a90b9d01SCy Schubert /* Generated IEs will be included inside an ML element */
604*a90b9d01SCy Schubert bool is_ml_sta_info;
605*a90b9d01SCy Schubert struct hostapd_data *mld_ap;
606*a90b9d01SCy Schubert struct mld_info *mld_info;
607*a90b9d01SCy Schubert
608*a90b9d01SCy Schubert struct ieee80211_mgmt *resp;
609*a90b9d01SCy Schubert size_t resp_len;
610*a90b9d01SCy Schubert u8 *csa_pos;
611*a90b9d01SCy Schubert u8 *ecsa_pos;
612*a90b9d01SCy Schubert const u8 *known_bss;
613*a90b9d01SCy Schubert u8 known_bss_len;
614*a90b9d01SCy Schubert
615*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211AX
616*a90b9d01SCy Schubert u8 *cca_pos;
617*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211AX */
618*a90b9d01SCy Schubert };
619*a90b9d01SCy Schubert
620*a90b9d01SCy Schubert
hostapd_free_probe_resp_params(struct probe_resp_params * params)621*a90b9d01SCy Schubert static void hostapd_free_probe_resp_params(struct probe_resp_params *params)
622*a90b9d01SCy Schubert {
623*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211BE
624*a90b9d01SCy Schubert if (!params)
625*a90b9d01SCy Schubert return;
626*a90b9d01SCy Schubert ap_sta_free_sta_profile(params->mld_info);
627*a90b9d01SCy Schubert os_free(params->mld_info);
628*a90b9d01SCy Schubert params->mld_info = NULL;
629*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211BE */
630*a90b9d01SCy Schubert }
631*a90b9d01SCy Schubert
632*a90b9d01SCy Schubert
hostapd_probe_resp_elems_len(struct hostapd_data * hapd,struct probe_resp_params * params)633*a90b9d01SCy Schubert static size_t hostapd_probe_resp_elems_len(struct hostapd_data *hapd,
634*a90b9d01SCy Schubert struct probe_resp_params *params)
635*a90b9d01SCy Schubert {
636*a90b9d01SCy Schubert size_t buflen = 0;
637*a90b9d01SCy Schubert
638e28a4053SRui Paulo #ifdef CONFIG_WPS
639e28a4053SRui Paulo if (hapd->wps_probe_resp_ie)
640e28a4053SRui Paulo buflen += wpabuf_len(hapd->wps_probe_resp_ie);
641e28a4053SRui Paulo #endif /* CONFIG_WPS */
642f05cddf9SRui Paulo #ifdef CONFIG_P2P
643f05cddf9SRui Paulo if (hapd->p2p_probe_resp_ie)
644f05cddf9SRui Paulo buflen += wpabuf_len(hapd->p2p_probe_resp_ie);
645f05cddf9SRui Paulo #endif /* CONFIG_P2P */
646325151a3SRui Paulo #ifdef CONFIG_FST
647325151a3SRui Paulo if (hapd->iface->fst_ies)
648325151a3SRui Paulo buflen += wpabuf_len(hapd->iface->fst_ies);
649325151a3SRui Paulo #endif /* CONFIG_FST */
650f05cddf9SRui Paulo if (hapd->conf->vendor_elements)
651f05cddf9SRui Paulo buflen += wpabuf_len(hapd->conf->vendor_elements);
652*a90b9d01SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
653*a90b9d01SCy Schubert if (hapd->conf->presp_elements)
654*a90b9d01SCy Schubert buflen += wpabuf_len(hapd->conf->presp_elements);
655*a90b9d01SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
6565b9c547cSRui Paulo if (hapd->conf->vendor_vht) {
6575b9c547cSRui Paulo buflen += 5 + 2 + sizeof(struct ieee80211_vht_capabilities) +
6585b9c547cSRui Paulo 2 + sizeof(struct ieee80211_vht_operation);
6595b9c547cSRui Paulo }
660780fb4a2SCy Schubert
661*a90b9d01SCy Schubert buflen += he_elem_len(hapd);
66285732ac8SCy Schubert
663*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211BE
664*a90b9d01SCy Schubert if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
665*a90b9d01SCy Schubert buflen += hostapd_eid_eht_capab_len(hapd, IEEE80211_MODE_AP);
666*a90b9d01SCy Schubert buflen += 3 + sizeof(struct ieee80211_eht_operation);
667*a90b9d01SCy Schubert if (hapd->iconf->punct_bitmap)
668*a90b9d01SCy Schubert buflen += EHT_OPER_DISABLED_SUBCHAN_BITMAP_SIZE;
669*a90b9d01SCy Schubert
670*a90b9d01SCy Schubert if (!params->is_ml_sta_info && hapd->conf->mld_ap) {
671*a90b9d01SCy Schubert struct hostapd_data *ml_elem_ap =
672*a90b9d01SCy Schubert params->mld_ap ? params->mld_ap : hapd;
673*a90b9d01SCy Schubert
674*a90b9d01SCy Schubert buflen += hostapd_eid_eht_ml_beacon_len(
675*a90b9d01SCy Schubert ml_elem_ap, params->mld_info, !!params->mld_ap);
676*a90b9d01SCy Schubert }
677*a90b9d01SCy Schubert }
678*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211BE */
679*a90b9d01SCy Schubert
680*a90b9d01SCy Schubert buflen += hostapd_eid_mbssid_len(hapd, WLAN_FC_STYPE_PROBE_RESP, NULL,
681*a90b9d01SCy Schubert params->known_bss,
682*a90b9d01SCy Schubert params->known_bss_len, NULL);
683*a90b9d01SCy Schubert if (!params->is_ml_sta_info)
684*a90b9d01SCy Schubert buflen += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_PROBE_RESP,
685*a90b9d01SCy Schubert true);
686780fb4a2SCy Schubert buflen += hostapd_mbo_ie_len(hapd);
68785732ac8SCy Schubert buflen += hostapd_eid_owe_trans_len(hapd);
688c1d255d3SCy Schubert buflen += hostapd_eid_dpp_cc_len(hapd);
689780fb4a2SCy Schubert
690*a90b9d01SCy Schubert return buflen;
691*a90b9d01SCy Schubert }
692f05cddf9SRui Paulo
693e28a4053SRui Paulo
hostapd_probe_resp_fill_elems(struct hostapd_data * hapd,struct probe_resp_params * params,u8 * pos,size_t len)694*a90b9d01SCy Schubert static u8 * hostapd_probe_resp_fill_elems(struct hostapd_data *hapd,
695*a90b9d01SCy Schubert struct probe_resp_params *params,
696*a90b9d01SCy Schubert u8 *pos, size_t len)
697*a90b9d01SCy Schubert {
698*a90b9d01SCy Schubert u8 *csa_pos;
699*a90b9d01SCy Schubert u8 *epos;
700e28a4053SRui Paulo
701*a90b9d01SCy Schubert epos = pos + len;
702e28a4053SRui Paulo
703*a90b9d01SCy Schubert if (!params->is_ml_sta_info) {
704e28a4053SRui Paulo *pos++ = WLAN_EID_SSID;
705f05cddf9SRui Paulo *pos++ = hapd->conf->ssid.ssid_len;
706*a90b9d01SCy Schubert os_memcpy(pos, hapd->conf->ssid.ssid,
707*a90b9d01SCy Schubert hapd->conf->ssid.ssid_len);
708f05cddf9SRui Paulo pos += hapd->conf->ssid.ssid_len;
709*a90b9d01SCy Schubert }
710e28a4053SRui Paulo
711e28a4053SRui Paulo /* Supported rates */
712e28a4053SRui Paulo pos = hostapd_eid_supp_rates(hapd, pos);
713e28a4053SRui Paulo
714e28a4053SRui Paulo /* DS Params */
715e28a4053SRui Paulo pos = hostapd_eid_ds_params(hapd, pos);
716e28a4053SRui Paulo
717e28a4053SRui Paulo pos = hostapd_eid_country(hapd, pos, epos - pos);
718e28a4053SRui Paulo
7195b9c547cSRui Paulo /* Power Constraint element */
7205b9c547cSRui Paulo pos = hostapd_eid_pwr_constraint(hapd, pos);
7215b9c547cSRui Paulo
722*a90b9d01SCy Schubert /*
723*a90b9d01SCy Schubert * CSA IE
724*a90b9d01SCy Schubert * TODO: This should be included inside the ML sta profile
725*a90b9d01SCy Schubert */
726*a90b9d01SCy Schubert if (!params->is_ml_sta_info) {
727780fb4a2SCy Schubert csa_pos = hostapd_eid_csa(hapd, pos);
728780fb4a2SCy Schubert if (csa_pos != pos)
729*a90b9d01SCy Schubert params->csa_pos = csa_pos - 1;
730*a90b9d01SCy Schubert else
731*a90b9d01SCy Schubert params->csa_pos = NULL;
732780fb4a2SCy Schubert pos = csa_pos;
733*a90b9d01SCy Schubert }
734780fb4a2SCy Schubert
735e28a4053SRui Paulo /* ERP Information element */
736e28a4053SRui Paulo pos = hostapd_eid_erp_info(hapd, pos);
737e28a4053SRui Paulo
738e28a4053SRui Paulo /* Extended supported rates */
739e28a4053SRui Paulo pos = hostapd_eid_ext_supp_rates(hapd, pos);
740e28a4053SRui Paulo
741c1d255d3SCy Schubert pos = hostapd_get_rsne(hapd, pos, epos - pos);
7425b9c547cSRui Paulo pos = hostapd_eid_bss_load(hapd, pos, epos - pos);
743*a90b9d01SCy Schubert pos = hostapd_eid_mbssid(hapd, pos, epos, WLAN_FC_STYPE_PROBE_RESP, 0,
744*a90b9d01SCy Schubert NULL, params->known_bss, params->known_bss_len,
745*a90b9d01SCy Schubert NULL, NULL, NULL, 0);
7465b9c547cSRui Paulo pos = hostapd_eid_rm_enabled_capab(hapd, pos, epos - pos);
747c1d255d3SCy Schubert pos = hostapd_get_mde(hapd, pos, epos - pos);
7485b9c547cSRui Paulo
749*a90b9d01SCy Schubert /*
750*a90b9d01SCy Schubert * eCSA IE
751*a90b9d01SCy Schubert * TODO: This should be included inside the ML sta profile
752*a90b9d01SCy Schubert */
753*a90b9d01SCy Schubert if (!params->is_ml_sta_info) {
754780fb4a2SCy Schubert csa_pos = hostapd_eid_ecsa(hapd, pos);
755780fb4a2SCy Schubert if (csa_pos != pos)
756*a90b9d01SCy Schubert params->ecsa_pos = csa_pos - 1;
757*a90b9d01SCy Schubert else
758*a90b9d01SCy Schubert params->ecsa_pos = NULL;
759780fb4a2SCy Schubert pos = csa_pos;
760*a90b9d01SCy Schubert }
761780fb4a2SCy Schubert
762780fb4a2SCy Schubert pos = hostapd_eid_supported_op_classes(hapd, pos);
763e28a4053SRui Paulo pos = hostapd_eid_ht_capabilities(hapd, pos);
764e28a4053SRui Paulo pos = hostapd_eid_ht_operation(hapd, pos);
765e28a4053SRui Paulo
766*a90b9d01SCy Schubert /* Probe Response frames always include all non-TX profiles except
767*a90b9d01SCy Schubert * when a list of known BSSes is included in the Probe Request frame. */
768*a90b9d01SCy Schubert pos = hostapd_eid_ext_capab(hapd, pos,
769*a90b9d01SCy Schubert hapd->iconf->mbssid >= MBSSID_ENABLED &&
770*a90b9d01SCy Schubert !params->known_bss_len);
771f05cddf9SRui Paulo
772f05cddf9SRui Paulo pos = hostapd_eid_time_adv(hapd, pos);
773f05cddf9SRui Paulo pos = hostapd_eid_time_zone(hapd, pos);
774f05cddf9SRui Paulo
775f05cddf9SRui Paulo pos = hostapd_eid_interworking(hapd, pos);
776f05cddf9SRui Paulo pos = hostapd_eid_adv_proto(hapd, pos);
777f05cddf9SRui Paulo pos = hostapd_eid_roaming_consortium(hapd, pos);
778f05cddf9SRui Paulo
779325151a3SRui Paulo #ifdef CONFIG_FST
780325151a3SRui Paulo if (hapd->iface->fst_ies) {
781325151a3SRui Paulo os_memcpy(pos, wpabuf_head(hapd->iface->fst_ies),
782325151a3SRui Paulo wpabuf_len(hapd->iface->fst_ies));
783325151a3SRui Paulo pos += wpabuf_len(hapd->iface->fst_ies);
784325151a3SRui Paulo }
785325151a3SRui Paulo #endif /* CONFIG_FST */
786325151a3SRui Paulo
787f05cddf9SRui Paulo #ifdef CONFIG_IEEE80211AC
788c1d255d3SCy Schubert if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac &&
789c1d255d3SCy Schubert !is_6ghz_op_class(hapd->iconf->op_class)) {
790780fb4a2SCy Schubert pos = hostapd_eid_vht_capabilities(hapd, pos, 0);
791f05cddf9SRui Paulo pos = hostapd_eid_vht_operation(hapd, pos);
792780fb4a2SCy Schubert pos = hostapd_eid_txpower_envelope(hapd, pos);
7935b9c547cSRui Paulo }
79485732ac8SCy Schubert #endif /* CONFIG_IEEE80211AC */
79585732ac8SCy Schubert
796c1d255d3SCy Schubert #ifdef CONFIG_IEEE80211AX
797c1d255d3SCy Schubert if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax &&
798c1d255d3SCy Schubert is_6ghz_op_class(hapd->iconf->op_class))
799c1d255d3SCy Schubert pos = hostapd_eid_txpower_envelope(hapd, pos);
800c1d255d3SCy Schubert #endif /* CONFIG_IEEE80211AX */
801c1d255d3SCy Schubert
802c1d255d3SCy Schubert pos = hostapd_eid_wb_chsw_wrapper(hapd, pos);
803c1d255d3SCy Schubert
804*a90b9d01SCy Schubert if (!params->is_ml_sta_info)
805*a90b9d01SCy Schubert pos = hostapd_eid_rnr(hapd, pos, WLAN_FC_STYPE_PROBE_RESP,
806*a90b9d01SCy Schubert true);
80785732ac8SCy Schubert pos = hostapd_eid_fils_indic(hapd, pos, 0);
808c1d255d3SCy Schubert pos = hostapd_get_rsnxe(hapd, pos, epos - pos);
80985732ac8SCy Schubert
81085732ac8SCy Schubert #ifdef CONFIG_IEEE80211AX
811c1d255d3SCy Schubert if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
812*a90b9d01SCy Schubert u8 *cca_pos;
813*a90b9d01SCy Schubert
814206b73d0SCy Schubert pos = hostapd_eid_he_capab(hapd, pos, IEEE80211_MODE_AP);
81585732ac8SCy Schubert pos = hostapd_eid_he_operation(hapd, pos);
816*a90b9d01SCy Schubert
817*a90b9d01SCy Schubert /* BSS Color Change Announcement element */
818*a90b9d01SCy Schubert cca_pos = hostapd_eid_cca(hapd, pos);
819*a90b9d01SCy Schubert if (cca_pos != pos)
820*a90b9d01SCy Schubert params->cca_pos = cca_pos - 2;
821*a90b9d01SCy Schubert else
822*a90b9d01SCy Schubert params->cca_pos = NULL;
823*a90b9d01SCy Schubert pos = cca_pos;
824*a90b9d01SCy Schubert
825206b73d0SCy Schubert pos = hostapd_eid_spatial_reuse(hapd, pos);
826c1d255d3SCy Schubert pos = hostapd_eid_he_mu_edca_parameter_set(hapd, pos);
827c1d255d3SCy Schubert pos = hostapd_eid_he_6ghz_band_cap(hapd, pos);
82885732ac8SCy Schubert }
82985732ac8SCy Schubert #endif /* CONFIG_IEEE80211AX */
83085732ac8SCy Schubert
831*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211BE
832*a90b9d01SCy Schubert if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
833*a90b9d01SCy Schubert struct hostapd_data *ml_elem_ap =
834*a90b9d01SCy Schubert params->mld_ap ? params->mld_ap : hapd;
835*a90b9d01SCy Schubert
836*a90b9d01SCy Schubert if (ml_elem_ap->conf->mld_ap)
837*a90b9d01SCy Schubert pos = hostapd_eid_eht_ml_beacon(
838*a90b9d01SCy Schubert ml_elem_ap, params->mld_info,
839*a90b9d01SCy Schubert pos, !!params->mld_ap);
840*a90b9d01SCy Schubert
841*a90b9d01SCy Schubert pos = hostapd_eid_eht_capab(hapd, pos, IEEE80211_MODE_AP);
842*a90b9d01SCy Schubert pos = hostapd_eid_eht_operation(hapd, pos);
843*a90b9d01SCy Schubert }
844*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211BE */
845*a90b9d01SCy Schubert
84685732ac8SCy Schubert #ifdef CONFIG_IEEE80211AC
8475b9c547cSRui Paulo if (hapd->conf->vendor_vht)
8485b9c547cSRui Paulo pos = hostapd_eid_vendor_vht(hapd, pos);
849f05cddf9SRui Paulo #endif /* CONFIG_IEEE80211AC */
850f05cddf9SRui Paulo
851c1d255d3SCy Schubert /* WPA / OSEN */
852c1d255d3SCy Schubert pos = hostapd_get_wpa_ie(hapd, pos, epos - pos);
853c1d255d3SCy Schubert pos = hostapd_get_osen_ie(hapd, pos, epos - pos);
85485732ac8SCy Schubert
855e28a4053SRui Paulo /* Wi-Fi Alliance WMM */
856e28a4053SRui Paulo pos = hostapd_eid_wmm(hapd, pos);
857e28a4053SRui Paulo
858e28a4053SRui Paulo #ifdef CONFIG_WPS
859e28a4053SRui Paulo if (hapd->conf->wps_state && hapd->wps_probe_resp_ie) {
860e28a4053SRui Paulo os_memcpy(pos, wpabuf_head(hapd->wps_probe_resp_ie),
861e28a4053SRui Paulo wpabuf_len(hapd->wps_probe_resp_ie));
862e28a4053SRui Paulo pos += wpabuf_len(hapd->wps_probe_resp_ie);
863e28a4053SRui Paulo }
864e28a4053SRui Paulo #endif /* CONFIG_WPS */
865e28a4053SRui Paulo
866f05cddf9SRui Paulo #ifdef CONFIG_P2P
867*a90b9d01SCy Schubert if ((hapd->conf->p2p & P2P_ENABLED) && params->is_p2p &&
868f05cddf9SRui Paulo hapd->p2p_probe_resp_ie) {
869f05cddf9SRui Paulo os_memcpy(pos, wpabuf_head(hapd->p2p_probe_resp_ie),
870f05cddf9SRui Paulo wpabuf_len(hapd->p2p_probe_resp_ie));
871f05cddf9SRui Paulo pos += wpabuf_len(hapd->p2p_probe_resp_ie);
872f05cddf9SRui Paulo }
873f05cddf9SRui Paulo #endif /* CONFIG_P2P */
874f05cddf9SRui Paulo #ifdef CONFIG_P2P_MANAGER
875f05cddf9SRui Paulo if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) ==
876f05cddf9SRui Paulo P2P_MANAGE)
877f05cddf9SRui Paulo pos = hostapd_eid_p2p_manage(hapd, pos);
878f05cddf9SRui Paulo #endif /* CONFIG_P2P_MANAGER */
879f05cddf9SRui Paulo
880f05cddf9SRui Paulo #ifdef CONFIG_HS20
881f05cddf9SRui Paulo pos = hostapd_eid_hs20_indication(hapd, pos);
882f05cddf9SRui Paulo #endif /* CONFIG_HS20 */
883f05cddf9SRui Paulo
884*a90b9d01SCy Schubert pos = hostapd_eid_mbo(hapd, pos, epos - pos);
885*a90b9d01SCy Schubert pos = hostapd_eid_owe_trans(hapd, pos, epos - pos);
886*a90b9d01SCy Schubert pos = hostapd_eid_dpp_cc(hapd, pos, epos - pos);
887780fb4a2SCy Schubert
888f05cddf9SRui Paulo if (hapd->conf->vendor_elements) {
889f05cddf9SRui Paulo os_memcpy(pos, wpabuf_head(hapd->conf->vendor_elements),
890f05cddf9SRui Paulo wpabuf_len(hapd->conf->vendor_elements));
891f05cddf9SRui Paulo pos += wpabuf_len(hapd->conf->vendor_elements);
892f05cddf9SRui Paulo }
893f05cddf9SRui Paulo
894*a90b9d01SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
895*a90b9d01SCy Schubert if (hapd->conf->presp_elements) {
896*a90b9d01SCy Schubert os_memcpy(pos, wpabuf_head(hapd->conf->presp_elements),
897*a90b9d01SCy Schubert wpabuf_len(hapd->conf->presp_elements));
898*a90b9d01SCy Schubert pos += wpabuf_len(hapd->conf->presp_elements);
899f05cddf9SRui Paulo }
900*a90b9d01SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
901*a90b9d01SCy Schubert
902*a90b9d01SCy Schubert return pos;
903*a90b9d01SCy Schubert }
904*a90b9d01SCy Schubert
905*a90b9d01SCy Schubert
hostapd_gen_probe_resp(struct hostapd_data * hapd,struct probe_resp_params * params)906*a90b9d01SCy Schubert static void hostapd_gen_probe_resp(struct hostapd_data *hapd,
907*a90b9d01SCy Schubert struct probe_resp_params *params)
908*a90b9d01SCy Schubert {
909*a90b9d01SCy Schubert u8 *pos;
910*a90b9d01SCy Schubert size_t buflen;
911*a90b9d01SCy Schubert
912*a90b9d01SCy Schubert hapd = hostapd_mbssid_get_tx_bss(hapd);
913*a90b9d01SCy Schubert
914*a90b9d01SCy Schubert #define MAX_PROBERESP_LEN 768
915*a90b9d01SCy Schubert buflen = MAX_PROBERESP_LEN;
916*a90b9d01SCy Schubert buflen += hostapd_probe_resp_elems_len(hapd, params);
917*a90b9d01SCy Schubert params->resp = os_zalloc(buflen);
918*a90b9d01SCy Schubert if (!params->resp) {
919*a90b9d01SCy Schubert params->resp_len = 0;
920*a90b9d01SCy Schubert return;
921*a90b9d01SCy Schubert }
922*a90b9d01SCy Schubert
923*a90b9d01SCy Schubert params->resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
924*a90b9d01SCy Schubert WLAN_FC_STYPE_PROBE_RESP);
925*a90b9d01SCy Schubert /* Unicast the response to all requests on bands other than 6 GHz. For
926*a90b9d01SCy Schubert * the 6 GHz, unicast is used only if the actual SSID is not included in
927*a90b9d01SCy Schubert * the Beacon frames. Otherwise, broadcast response is used per IEEE
928*a90b9d01SCy Schubert * Std 802.11ax-2021, 26.17.2.3.2. Broadcast address is also used for
929*a90b9d01SCy Schubert * the Probe Response frame template for the unsolicited (i.e., not as
930*a90b9d01SCy Schubert * a response to a specific request) case. */
931*a90b9d01SCy Schubert if (params->req && (!is_6ghz_op_class(hapd->iconf->op_class) ||
932*a90b9d01SCy Schubert hapd->conf->ignore_broadcast_ssid))
933*a90b9d01SCy Schubert os_memcpy(params->resp->da, params->req->sa, ETH_ALEN);
934*a90b9d01SCy Schubert else
935*a90b9d01SCy Schubert os_memset(params->resp->da, 0xff, ETH_ALEN);
936*a90b9d01SCy Schubert os_memcpy(params->resp->sa, hapd->own_addr, ETH_ALEN);
937*a90b9d01SCy Schubert
938*a90b9d01SCy Schubert os_memcpy(params->resp->bssid, hapd->own_addr, ETH_ALEN);
939*a90b9d01SCy Schubert params->resp->u.probe_resp.beacon_int =
940*a90b9d01SCy Schubert host_to_le16(hapd->iconf->beacon_int);
941*a90b9d01SCy Schubert
942*a90b9d01SCy Schubert /* hardware or low-level driver will setup seq_ctrl and timestamp */
943*a90b9d01SCy Schubert params->resp->u.probe_resp.capab_info =
944*a90b9d01SCy Schubert host_to_le16(hostapd_own_capab_info(hapd));
945*a90b9d01SCy Schubert
946*a90b9d01SCy Schubert pos = hostapd_probe_resp_fill_elems(hapd, params,
947*a90b9d01SCy Schubert params->resp->u.probe_resp.variable,
948*a90b9d01SCy Schubert buflen);
949*a90b9d01SCy Schubert
950*a90b9d01SCy Schubert params->resp_len = pos - (u8 *) params->resp;
951*a90b9d01SCy Schubert }
952*a90b9d01SCy Schubert
953*a90b9d01SCy Schubert
954*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211BE
hostapd_fill_probe_resp_ml_params(struct hostapd_data * hapd,struct probe_resp_params * params,const struct ieee80211_mgmt * mgmt,int mld_id,u16 links)955*a90b9d01SCy Schubert static void hostapd_fill_probe_resp_ml_params(struct hostapd_data *hapd,
956*a90b9d01SCy Schubert struct probe_resp_params *params,
957*a90b9d01SCy Schubert const struct ieee80211_mgmt *mgmt,
958*a90b9d01SCy Schubert int mld_id, u16 links)
959*a90b9d01SCy Schubert {
960*a90b9d01SCy Schubert struct probe_resp_params sta_info_params;
961*a90b9d01SCy Schubert struct hostapd_data *link;
962*a90b9d01SCy Schubert
963*a90b9d01SCy Schubert params->mld_ap = NULL;
964*a90b9d01SCy Schubert params->mld_info = os_zalloc(sizeof(*params->mld_info));
965*a90b9d01SCy Schubert if (!params->mld_info)
966*a90b9d01SCy Schubert return;
967*a90b9d01SCy Schubert
968*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
969*a90b9d01SCy Schubert "MLD: Got ML probe request with AP MLD ID %d for links %04x",
970*a90b9d01SCy Schubert mld_id, links);
971*a90b9d01SCy Schubert
972*a90b9d01SCy Schubert for_each_mld_link(link, hapd) {
973*a90b9d01SCy Schubert struct mld_link_info *link_info;
974*a90b9d01SCy Schubert size_t buflen;
975*a90b9d01SCy Schubert u8 mld_link_id = link->mld_link_id;
976*a90b9d01SCy Schubert u8 *epos;
977*a90b9d01SCy Schubert u8 buf[EHT_ML_MAX_STA_PROF_LEN];
978*a90b9d01SCy Schubert
979*a90b9d01SCy Schubert /*
980*a90b9d01SCy Schubert * Set mld_ap iff the ML probe request explicitly
981*a90b9d01SCy Schubert * requested a specific MLD ID. In that case, the targeted
982*a90b9d01SCy Schubert * AP may have been a nontransmitted BSSID on the same
983*a90b9d01SCy Schubert * interface.
984*a90b9d01SCy Schubert */
985*a90b9d01SCy Schubert if (mld_id != -1 && link->iface == hapd->iface)
986*a90b9d01SCy Schubert params->mld_ap = link;
987*a90b9d01SCy Schubert
988*a90b9d01SCy Schubert /* Never duplicate main Probe Response frame body */
989*a90b9d01SCy Schubert if (link == hapd)
990*a90b9d01SCy Schubert continue;
991*a90b9d01SCy Schubert
992*a90b9d01SCy Schubert /* Only include requested links */
993*a90b9d01SCy Schubert if (!(BIT(mld_link_id) & links))
994*a90b9d01SCy Schubert continue;
995*a90b9d01SCy Schubert
996*a90b9d01SCy Schubert link_info = ¶ms->mld_info->links[mld_link_id];
997*a90b9d01SCy Schubert
998*a90b9d01SCy Schubert sta_info_params.req = params->req;
999*a90b9d01SCy Schubert sta_info_params.is_p2p = false;
1000*a90b9d01SCy Schubert sta_info_params.is_ml_sta_info = true;
1001*a90b9d01SCy Schubert sta_info_params.mld_ap = NULL;
1002*a90b9d01SCy Schubert sta_info_params.mld_info = NULL;
1003*a90b9d01SCy Schubert
1004*a90b9d01SCy Schubert buflen = MAX_PROBERESP_LEN;
1005*a90b9d01SCy Schubert buflen += hostapd_probe_resp_elems_len(link, &sta_info_params);
1006*a90b9d01SCy Schubert
1007*a90b9d01SCy Schubert if (buflen > EHT_ML_MAX_STA_PROF_LEN) {
1008*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
1009*a90b9d01SCy Schubert "MLD: Not including link %d in ML probe response (%zu bytes is too long)",
1010*a90b9d01SCy Schubert mld_link_id, buflen);
1011*a90b9d01SCy Schubert goto fail;
1012*a90b9d01SCy Schubert }
1013*a90b9d01SCy Schubert
1014*a90b9d01SCy Schubert /*
1015*a90b9d01SCy Schubert * NOTE: This does not properly handle inheritance and
1016*a90b9d01SCy Schubert * various other things.
1017*a90b9d01SCy Schubert */
1018*a90b9d01SCy Schubert link_info->valid = true;
1019*a90b9d01SCy Schubert epos = buf;
1020*a90b9d01SCy Schubert
1021*a90b9d01SCy Schubert /* Capabilities is the only fixed parameter */
1022*a90b9d01SCy Schubert WPA_PUT_LE16(epos, hostapd_own_capab_info(hapd));
1023*a90b9d01SCy Schubert epos += 2;
1024*a90b9d01SCy Schubert
1025*a90b9d01SCy Schubert epos = hostapd_probe_resp_fill_elems(
1026*a90b9d01SCy Schubert link, &sta_info_params, epos,
1027*a90b9d01SCy Schubert EHT_ML_MAX_STA_PROF_LEN - 2);
1028*a90b9d01SCy Schubert link_info->resp_sta_profile_len = epos - buf;
1029*a90b9d01SCy Schubert os_free(link_info->resp_sta_profile);
1030*a90b9d01SCy Schubert link_info->resp_sta_profile = os_memdup(
1031*a90b9d01SCy Schubert buf, link_info->resp_sta_profile_len);
1032*a90b9d01SCy Schubert if (!link_info->resp_sta_profile)
1033*a90b9d01SCy Schubert link_info->resp_sta_profile_len = 0;
1034*a90b9d01SCy Schubert os_memcpy(link_info->local_addr, link->own_addr, ETH_ALEN);
1035*a90b9d01SCy Schubert
1036*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
1037*a90b9d01SCy Schubert "MLD: ML probe response includes link sta info for %d: %u bytes (estimate %zu)",
1038*a90b9d01SCy Schubert mld_link_id, link_info->resp_sta_profile_len,
1039*a90b9d01SCy Schubert buflen);
1040*a90b9d01SCy Schubert }
1041*a90b9d01SCy Schubert
1042*a90b9d01SCy Schubert if (mld_id != -1 && !params->mld_ap) {
1043*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
1044*a90b9d01SCy Schubert "MLD: No nontransmitted BSSID for MLD ID %d",
1045*a90b9d01SCy Schubert mld_id);
1046*a90b9d01SCy Schubert goto fail;
1047*a90b9d01SCy Schubert }
1048*a90b9d01SCy Schubert
1049*a90b9d01SCy Schubert return;
1050*a90b9d01SCy Schubert
1051*a90b9d01SCy Schubert fail:
1052*a90b9d01SCy Schubert hostapd_free_probe_resp_params(params);
1053*a90b9d01SCy Schubert params->mld_ap = NULL;
1054*a90b9d01SCy Schubert params->mld_info = NULL;
1055*a90b9d01SCy Schubert }
1056*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211BE */
1057f05cddf9SRui Paulo
1058f05cddf9SRui Paulo
1059f05cddf9SRui Paulo enum ssid_match_result {
1060f05cddf9SRui Paulo NO_SSID_MATCH,
1061f05cddf9SRui Paulo EXACT_SSID_MATCH,
10624b72b91aSCy Schubert WILDCARD_SSID_MATCH,
10634b72b91aSCy Schubert CO_LOCATED_SSID_MATCH,
1064f05cddf9SRui Paulo };
1065f05cddf9SRui Paulo
ssid_match(struct hostapd_data * hapd,const u8 * ssid,size_t ssid_len,const u8 * ssid_list,size_t ssid_list_len,const u8 * short_ssid_list,size_t short_ssid_list_len)1066f05cddf9SRui Paulo static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
1067f05cddf9SRui Paulo const u8 *ssid, size_t ssid_len,
1068f05cddf9SRui Paulo const u8 *ssid_list,
1069c1d255d3SCy Schubert size_t ssid_list_len,
1070c1d255d3SCy Schubert const u8 *short_ssid_list,
1071c1d255d3SCy Schubert size_t short_ssid_list_len)
1072f05cddf9SRui Paulo {
1073f05cddf9SRui Paulo const u8 *pos, *end;
10744b72b91aSCy Schubert struct hostapd_iface *iface = hapd->iface;
1075f05cddf9SRui Paulo int wildcard = 0;
10764b72b91aSCy Schubert size_t i, j;
1077f05cddf9SRui Paulo
1078f05cddf9SRui Paulo if (ssid_len == 0)
1079f05cddf9SRui Paulo wildcard = 1;
1080f05cddf9SRui Paulo if (ssid_len == hapd->conf->ssid.ssid_len &&
1081f05cddf9SRui Paulo os_memcmp(ssid, hapd->conf->ssid.ssid, ssid_len) == 0)
1082f05cddf9SRui Paulo return EXACT_SSID_MATCH;
1083f05cddf9SRui Paulo
1084c1d255d3SCy Schubert if (ssid_list) {
1085f05cddf9SRui Paulo pos = ssid_list;
1086f05cddf9SRui Paulo end = ssid_list + ssid_list_len;
1087206b73d0SCy Schubert while (end - pos >= 2) {
1088780fb4a2SCy Schubert if (2 + pos[1] > end - pos)
1089f05cddf9SRui Paulo break;
1090f05cddf9SRui Paulo if (pos[1] == 0)
1091f05cddf9SRui Paulo wildcard = 1;
1092f05cddf9SRui Paulo if (pos[1] == hapd->conf->ssid.ssid_len &&
1093c1d255d3SCy Schubert os_memcmp(pos + 2, hapd->conf->ssid.ssid,
1094c1d255d3SCy Schubert pos[1]) == 0)
1095f05cddf9SRui Paulo return EXACT_SSID_MATCH;
1096f05cddf9SRui Paulo pos += 2 + pos[1];
1097f05cddf9SRui Paulo }
1098c1d255d3SCy Schubert }
1099c1d255d3SCy Schubert
1100c1d255d3SCy Schubert if (short_ssid_list) {
1101c1d255d3SCy Schubert pos = short_ssid_list;
1102c1d255d3SCy Schubert end = short_ssid_list + short_ssid_list_len;
1103c1d255d3SCy Schubert while (end - pos >= 4) {
1104c1d255d3SCy Schubert if (hapd->conf->ssid.short_ssid == WPA_GET_LE32(pos))
1105c1d255d3SCy Schubert return EXACT_SSID_MATCH;
1106c1d255d3SCy Schubert pos += 4;
1107c1d255d3SCy Schubert }
1108c1d255d3SCy Schubert }
1109f05cddf9SRui Paulo
11104b72b91aSCy Schubert if (wildcard)
11114b72b91aSCy Schubert return WILDCARD_SSID_MATCH;
11124b72b91aSCy Schubert
11134b72b91aSCy Schubert if (!iface->interfaces || iface->interfaces->count <= 1 ||
11144b72b91aSCy Schubert is_6ghz_op_class(hapd->iconf->op_class))
11154b72b91aSCy Schubert return NO_SSID_MATCH;
11164b72b91aSCy Schubert
11174b72b91aSCy Schubert for (i = 0; i < iface->interfaces->count; i++) {
11184b72b91aSCy Schubert struct hostapd_iface *colocated;
11194b72b91aSCy Schubert
11204b72b91aSCy Schubert colocated = iface->interfaces->iface[i];
11214b72b91aSCy Schubert
11224b72b91aSCy Schubert if (colocated == iface ||
11234b72b91aSCy Schubert !is_6ghz_op_class(colocated->conf->op_class))
11244b72b91aSCy Schubert continue;
11254b72b91aSCy Schubert
11264b72b91aSCy Schubert for (j = 0; j < colocated->num_bss; j++) {
11274b72b91aSCy Schubert struct hostapd_bss_config *conf;
11284b72b91aSCy Schubert
11294b72b91aSCy Schubert conf = colocated->bss[j]->conf;
11304b72b91aSCy Schubert if (ssid_len == conf->ssid.ssid_len &&
11314b72b91aSCy Schubert os_memcmp(ssid, conf->ssid.ssid, ssid_len) == 0)
11324b72b91aSCy Schubert return CO_LOCATED_SSID_MATCH;
11334b72b91aSCy Schubert }
11344b72b91aSCy Schubert }
11354b72b91aSCy Schubert
11364b72b91aSCy Schubert return NO_SSID_MATCH;
1137f05cddf9SRui Paulo }
1138f05cddf9SRui Paulo
1139f05cddf9SRui Paulo
sta_track_expire(struct hostapd_iface * iface,int force)1140325151a3SRui Paulo void sta_track_expire(struct hostapd_iface *iface, int force)
1141325151a3SRui Paulo {
1142325151a3SRui Paulo struct os_reltime now;
1143325151a3SRui Paulo struct hostapd_sta_info *info;
1144325151a3SRui Paulo
1145325151a3SRui Paulo if (!iface->num_sta_seen)
1146325151a3SRui Paulo return;
1147325151a3SRui Paulo
1148325151a3SRui Paulo os_get_reltime(&now);
1149325151a3SRui Paulo while ((info = dl_list_first(&iface->sta_seen, struct hostapd_sta_info,
1150325151a3SRui Paulo list))) {
1151325151a3SRui Paulo if (!force &&
1152325151a3SRui Paulo !os_reltime_expired(&now, &info->last_seen,
1153325151a3SRui Paulo iface->conf->track_sta_max_age))
1154325151a3SRui Paulo break;
1155325151a3SRui Paulo force = 0;
1156325151a3SRui Paulo
1157325151a3SRui Paulo wpa_printf(MSG_MSGDUMP, "%s: Expire STA tracking entry for "
1158325151a3SRui Paulo MACSTR, iface->bss[0]->conf->iface,
1159325151a3SRui Paulo MAC2STR(info->addr));
1160325151a3SRui Paulo dl_list_del(&info->list);
1161325151a3SRui Paulo iface->num_sta_seen--;
1162780fb4a2SCy Schubert sta_track_del(info);
1163325151a3SRui Paulo }
1164325151a3SRui Paulo }
1165325151a3SRui Paulo
1166325151a3SRui Paulo
sta_track_get(struct hostapd_iface * iface,const u8 * addr)1167325151a3SRui Paulo static struct hostapd_sta_info * sta_track_get(struct hostapd_iface *iface,
1168325151a3SRui Paulo const u8 *addr)
1169325151a3SRui Paulo {
1170325151a3SRui Paulo struct hostapd_sta_info *info;
1171325151a3SRui Paulo
1172325151a3SRui Paulo dl_list_for_each(info, &iface->sta_seen, struct hostapd_sta_info, list)
1173*a90b9d01SCy Schubert if (ether_addr_equal(addr, info->addr))
1174325151a3SRui Paulo return info;
1175325151a3SRui Paulo
1176325151a3SRui Paulo return NULL;
1177325151a3SRui Paulo }
1178325151a3SRui Paulo
1179325151a3SRui Paulo
sta_track_add(struct hostapd_iface * iface,const u8 * addr,int ssi_signal)118085732ac8SCy Schubert void sta_track_add(struct hostapd_iface *iface, const u8 *addr, int ssi_signal)
1181325151a3SRui Paulo {
1182325151a3SRui Paulo struct hostapd_sta_info *info;
1183325151a3SRui Paulo
1184325151a3SRui Paulo info = sta_track_get(iface, addr);
1185325151a3SRui Paulo if (info) {
1186325151a3SRui Paulo /* Move the most recent entry to the end of the list */
1187325151a3SRui Paulo dl_list_del(&info->list);
1188325151a3SRui Paulo dl_list_add_tail(&iface->sta_seen, &info->list);
1189325151a3SRui Paulo os_get_reltime(&info->last_seen);
119085732ac8SCy Schubert info->ssi_signal = ssi_signal;
1191325151a3SRui Paulo return;
1192325151a3SRui Paulo }
1193325151a3SRui Paulo
1194325151a3SRui Paulo /* Add a new entry */
1195325151a3SRui Paulo info = os_zalloc(sizeof(*info));
1196780fb4a2SCy Schubert if (info == NULL)
1197780fb4a2SCy Schubert return;
1198325151a3SRui Paulo os_memcpy(info->addr, addr, ETH_ALEN);
1199325151a3SRui Paulo os_get_reltime(&info->last_seen);
120085732ac8SCy Schubert info->ssi_signal = ssi_signal;
1201325151a3SRui Paulo
1202325151a3SRui Paulo if (iface->num_sta_seen >= iface->conf->track_sta_max_num) {
1203325151a3SRui Paulo /* Expire oldest entry to make room for a new one */
1204325151a3SRui Paulo sta_track_expire(iface, 1);
1205325151a3SRui Paulo }
1206325151a3SRui Paulo
1207325151a3SRui Paulo wpa_printf(MSG_MSGDUMP, "%s: Add STA tracking entry for "
1208325151a3SRui Paulo MACSTR, iface->bss[0]->conf->iface, MAC2STR(addr));
1209325151a3SRui Paulo dl_list_add_tail(&iface->sta_seen, &info->list);
1210325151a3SRui Paulo iface->num_sta_seen++;
1211325151a3SRui Paulo }
1212325151a3SRui Paulo
1213325151a3SRui Paulo
1214325151a3SRui Paulo struct hostapd_data *
sta_track_seen_on(struct hostapd_iface * iface,const u8 * addr,const char * ifname)1215325151a3SRui Paulo sta_track_seen_on(struct hostapd_iface *iface, const u8 *addr,
1216325151a3SRui Paulo const char *ifname)
1217325151a3SRui Paulo {
1218325151a3SRui Paulo struct hapd_interfaces *interfaces = iface->interfaces;
1219325151a3SRui Paulo size_t i, j;
1220325151a3SRui Paulo
1221325151a3SRui Paulo for (i = 0; i < interfaces->count; i++) {
1222325151a3SRui Paulo struct hostapd_data *hapd = NULL;
1223325151a3SRui Paulo
1224325151a3SRui Paulo iface = interfaces->iface[i];
1225325151a3SRui Paulo for (j = 0; j < iface->num_bss; j++) {
1226325151a3SRui Paulo hapd = iface->bss[j];
1227325151a3SRui Paulo if (os_strcmp(ifname, hapd->conf->iface) == 0)
1228325151a3SRui Paulo break;
1229325151a3SRui Paulo hapd = NULL;
1230325151a3SRui Paulo }
1231325151a3SRui Paulo
1232325151a3SRui Paulo if (hapd && sta_track_get(iface, addr))
1233325151a3SRui Paulo return hapd;
1234325151a3SRui Paulo }
1235325151a3SRui Paulo
1236325151a3SRui Paulo return NULL;
1237325151a3SRui Paulo }
1238325151a3SRui Paulo
1239325151a3SRui Paulo
1240780fb4a2SCy Schubert #ifdef CONFIG_TAXONOMY
sta_track_claim_taxonomy_info(struct hostapd_iface * iface,const u8 * addr,struct wpabuf ** probe_ie_taxonomy)1241780fb4a2SCy Schubert void sta_track_claim_taxonomy_info(struct hostapd_iface *iface, const u8 *addr,
1242780fb4a2SCy Schubert struct wpabuf **probe_ie_taxonomy)
1243780fb4a2SCy Schubert {
1244780fb4a2SCy Schubert struct hostapd_sta_info *info;
1245780fb4a2SCy Schubert
1246780fb4a2SCy Schubert info = sta_track_get(iface, addr);
1247780fb4a2SCy Schubert if (!info)
1248780fb4a2SCy Schubert return;
1249780fb4a2SCy Schubert
1250780fb4a2SCy Schubert wpabuf_free(*probe_ie_taxonomy);
1251780fb4a2SCy Schubert *probe_ie_taxonomy = info->probe_ie_taxonomy;
1252780fb4a2SCy Schubert info->probe_ie_taxonomy = NULL;
1253780fb4a2SCy Schubert }
1254780fb4a2SCy Schubert #endif /* CONFIG_TAXONOMY */
1255780fb4a2SCy Schubert
1256780fb4a2SCy Schubert
1257*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211BE
parse_ml_probe_req(const struct ieee80211_eht_ml * ml,size_t ml_len,int * mld_id,u16 * links)1258*a90b9d01SCy Schubert static bool parse_ml_probe_req(const struct ieee80211_eht_ml *ml, size_t ml_len,
1259*a90b9d01SCy Schubert int *mld_id, u16 *links)
1260*a90b9d01SCy Schubert {
1261*a90b9d01SCy Schubert u16 ml_control;
1262*a90b9d01SCy Schubert const struct element *sub;
1263*a90b9d01SCy Schubert const u8 *pos;
1264*a90b9d01SCy Schubert size_t len;
1265*a90b9d01SCy Schubert
1266*a90b9d01SCy Schubert *mld_id = -1;
1267*a90b9d01SCy Schubert *links = 0xffff;
1268*a90b9d01SCy Schubert
1269*a90b9d01SCy Schubert if (ml_len < sizeof(struct ieee80211_eht_ml))
1270*a90b9d01SCy Schubert return false;
1271*a90b9d01SCy Schubert
1272*a90b9d01SCy Schubert ml_control = le_to_host16(ml->ml_control);
1273*a90b9d01SCy Schubert if ((ml_control & MULTI_LINK_CONTROL_TYPE_MASK) !=
1274*a90b9d01SCy Schubert MULTI_LINK_CONTROL_TYPE_PROBE_REQ) {
1275*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "MLD: Not an ML probe req");
1276*a90b9d01SCy Schubert return false;
1277*a90b9d01SCy Schubert }
1278*a90b9d01SCy Schubert
1279*a90b9d01SCy Schubert if (sizeof(struct ieee80211_eht_ml) + 1 > ml_len) {
1280*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "MLD: ML probe req too short");
1281*a90b9d01SCy Schubert return false;
1282*a90b9d01SCy Schubert }
1283*a90b9d01SCy Schubert
1284*a90b9d01SCy Schubert pos = ml->variable;
1285*a90b9d01SCy Schubert len = pos[0];
1286*a90b9d01SCy Schubert if (len < 1 || sizeof(struct ieee80211_eht_ml) + len > ml_len) {
1287*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
1288*a90b9d01SCy Schubert "MLD: ML probe request with invalid length");
1289*a90b9d01SCy Schubert return false;
1290*a90b9d01SCy Schubert }
1291*a90b9d01SCy Schubert
1292*a90b9d01SCy Schubert if (ml_control & EHT_ML_PRES_BM_PROBE_REQ_AP_MLD_ID) {
1293*a90b9d01SCy Schubert if (len < 2) {
1294*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
1295*a90b9d01SCy Schubert "MLD: ML probe req too short for MLD ID");
1296*a90b9d01SCy Schubert return false;
1297*a90b9d01SCy Schubert }
1298*a90b9d01SCy Schubert
1299*a90b9d01SCy Schubert *mld_id = pos[1];
1300*a90b9d01SCy Schubert }
1301*a90b9d01SCy Schubert pos += len;
1302*a90b9d01SCy Schubert
1303*a90b9d01SCy Schubert /* Parse subelements (if there are any) */
1304*a90b9d01SCy Schubert len = ml_len - len - sizeof(struct ieee80211_eht_ml);
1305*a90b9d01SCy Schubert for_each_element_id(sub, 0, pos, len) {
1306*a90b9d01SCy Schubert const struct ieee80211_eht_per_sta_profile *sta;
1307*a90b9d01SCy Schubert u16 sta_control;
1308*a90b9d01SCy Schubert
1309*a90b9d01SCy Schubert if (*links == 0xffff)
1310*a90b9d01SCy Schubert *links = 0;
1311*a90b9d01SCy Schubert
1312*a90b9d01SCy Schubert if (sub->datalen <
1313*a90b9d01SCy Schubert sizeof(struct ieee80211_eht_per_sta_profile)) {
1314*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
1315*a90b9d01SCy Schubert "MLD: ML probe req %d too short for sta profile",
1316*a90b9d01SCy Schubert sub->datalen);
1317*a90b9d01SCy Schubert return false;
1318*a90b9d01SCy Schubert }
1319*a90b9d01SCy Schubert
1320*a90b9d01SCy Schubert sta = (struct ieee80211_eht_per_sta_profile *) sub->data;
1321*a90b9d01SCy Schubert
1322*a90b9d01SCy Schubert /*
1323*a90b9d01SCy Schubert * Extract the link ID, do not return whether a complete or
1324*a90b9d01SCy Schubert * partial profile was requested.
1325*a90b9d01SCy Schubert */
1326*a90b9d01SCy Schubert sta_control = le_to_host16(sta->sta_control);
1327*a90b9d01SCy Schubert *links |= BIT(sta_control & EHT_PER_STA_CTRL_LINK_ID_MSK);
1328*a90b9d01SCy Schubert }
1329*a90b9d01SCy Schubert
1330*a90b9d01SCy Schubert if (!for_each_element_completed(sub, pos, len)) {
1331*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
1332*a90b9d01SCy Schubert "MLD: ML probe req sub-elements parsing error");
1333*a90b9d01SCy Schubert return false;
1334*a90b9d01SCy Schubert }
1335*a90b9d01SCy Schubert
1336*a90b9d01SCy Schubert return true;
1337*a90b9d01SCy Schubert }
1338*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211BE */
1339*a90b9d01SCy Schubert
1340*a90b9d01SCy Schubert
handle_probe_req(struct hostapd_data * hapd,const struct ieee80211_mgmt * mgmt,size_t len,int ssi_signal)1341f05cddf9SRui Paulo void handle_probe_req(struct hostapd_data *hapd,
1342f05cddf9SRui Paulo const struct ieee80211_mgmt *mgmt, size_t len,
1343f05cddf9SRui Paulo int ssi_signal)
1344f05cddf9SRui Paulo {
1345f05cddf9SRui Paulo struct ieee802_11_elems elems;
1346f05cddf9SRui Paulo const u8 *ie;
1347f05cddf9SRui Paulo size_t ie_len;
1348*a90b9d01SCy Schubert size_t i;
1349f05cddf9SRui Paulo int noack;
1350f05cddf9SRui Paulo enum ssid_match_result res;
1351780fb4a2SCy Schubert int ret;
1352780fb4a2SCy Schubert u16 csa_offs[2];
1353780fb4a2SCy Schubert size_t csa_offs_len;
1354c1d255d3SCy Schubert struct radius_sta rad_info;
1355*a90b9d01SCy Schubert struct probe_resp_params params;
1356*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211BE
1357*a90b9d01SCy Schubert int mld_id;
1358*a90b9d01SCy Schubert u16 links;
1359*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211BE */
1360c1d255d3SCy Schubert
1361c1d255d3SCy Schubert if (hapd->iconf->rssi_ignore_probe_request && ssi_signal &&
1362c1d255d3SCy Schubert ssi_signal < hapd->iconf->rssi_ignore_probe_request)
1363c1d255d3SCy Schubert return;
1364f05cddf9SRui Paulo
1365780fb4a2SCy Schubert if (len < IEEE80211_HDRLEN)
1366f05cddf9SRui Paulo return;
1367780fb4a2SCy Schubert ie = ((const u8 *) mgmt) + IEEE80211_HDRLEN;
1368325151a3SRui Paulo if (hapd->iconf->track_sta_max_num)
136985732ac8SCy Schubert sta_track_add(hapd->iface, mgmt->sa, ssi_signal);
1370780fb4a2SCy Schubert ie_len = len - IEEE80211_HDRLEN;
1371f05cddf9SRui Paulo
1372c1d255d3SCy Schubert ret = hostapd_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len,
1373c1d255d3SCy Schubert &rad_info, 1);
137485732ac8SCy Schubert if (ret == HOSTAPD_ACL_REJECT) {
137585732ac8SCy Schubert wpa_msg(hapd->msg_ctx, MSG_DEBUG,
137685732ac8SCy Schubert "Ignore Probe Request frame from " MACSTR
137785732ac8SCy Schubert " due to ACL reject ", MAC2STR(mgmt->sa));
137885732ac8SCy Schubert return;
137985732ac8SCy Schubert }
138085732ac8SCy Schubert
1381f05cddf9SRui Paulo for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++)
1382f05cddf9SRui Paulo if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
1383f05cddf9SRui Paulo mgmt->sa, mgmt->da, mgmt->bssid,
1384f05cddf9SRui Paulo ie, ie_len, ssi_signal) > 0)
1385f05cddf9SRui Paulo return;
1386f05cddf9SRui Paulo
13874bc52338SCy Schubert if (!hapd->conf->send_probe_response)
1388f05cddf9SRui Paulo return;
1389f05cddf9SRui Paulo
1390f05cddf9SRui Paulo if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) {
1391f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "Could not parse ProbeReq from " MACSTR,
1392f05cddf9SRui Paulo MAC2STR(mgmt->sa));
1393f05cddf9SRui Paulo return;
1394f05cddf9SRui Paulo }
1395f05cddf9SRui Paulo
1396f05cddf9SRui Paulo if ((!elems.ssid || !elems.supp_rates)) {
1397f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "STA " MACSTR " sent probe request "
1398f05cddf9SRui Paulo "without SSID or supported rates element",
1399f05cddf9SRui Paulo MAC2STR(mgmt->sa));
1400f05cddf9SRui Paulo return;
1401f05cddf9SRui Paulo }
1402f05cddf9SRui Paulo
14035b9c547cSRui Paulo /*
14045b9c547cSRui Paulo * No need to reply if the Probe Request frame was sent on an adjacent
14055b9c547cSRui Paulo * channel. IEEE Std 802.11-2012 describes this as a requirement for an
14065b9c547cSRui Paulo * AP with dot11RadioMeasurementActivated set to true, but strictly
14075b9c547cSRui Paulo * speaking does not allow such ignoring of Probe Request frames if
14085b9c547cSRui Paulo * dot11RadioMeasurementActivated is false. Anyway, this can help reduce
14095b9c547cSRui Paulo * number of unnecessary Probe Response frames for cases where the STA
14105b9c547cSRui Paulo * is less likely to see them (Probe Request frame sent on a
14115b9c547cSRui Paulo * neighboring, but partially overlapping, channel).
14125b9c547cSRui Paulo */
1413325151a3SRui Paulo if (elems.ds_params &&
14145b9c547cSRui Paulo hapd->iface->current_mode &&
14155b9c547cSRui Paulo (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G ||
14165b9c547cSRui Paulo hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211B) &&
14175b9c547cSRui Paulo hapd->iconf->channel != elems.ds_params[0]) {
14185b9c547cSRui Paulo wpa_printf(MSG_DEBUG,
14195b9c547cSRui Paulo "Ignore Probe Request due to DS Params mismatch: chan=%u != ds.chan=%u",
14205b9c547cSRui Paulo hapd->iconf->channel, elems.ds_params[0]);
14215b9c547cSRui Paulo return;
14225b9c547cSRui Paulo }
14235b9c547cSRui Paulo
1424f05cddf9SRui Paulo #ifdef CONFIG_P2P
1425780fb4a2SCy Schubert if (hapd->p2p && hapd->p2p_group && elems.wps_ie) {
1426f05cddf9SRui Paulo struct wpabuf *wps;
1427f05cddf9SRui Paulo wps = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA);
1428f05cddf9SRui Paulo if (wps && !p2p_group_match_dev_type(hapd->p2p_group, wps)) {
1429f05cddf9SRui Paulo wpa_printf(MSG_MSGDUMP, "P2P: Ignore Probe Request "
1430f05cddf9SRui Paulo "due to mismatch with Requested Device "
1431f05cddf9SRui Paulo "Type");
1432f05cddf9SRui Paulo wpabuf_free(wps);
1433f05cddf9SRui Paulo return;
1434f05cddf9SRui Paulo }
1435f05cddf9SRui Paulo wpabuf_free(wps);
1436f05cddf9SRui Paulo }
1437f05cddf9SRui Paulo
1438780fb4a2SCy Schubert if (hapd->p2p && hapd->p2p_group && elems.p2p) {
1439f05cddf9SRui Paulo struct wpabuf *p2p;
1440f05cddf9SRui Paulo p2p = ieee802_11_vendor_ie_concat(ie, ie_len, P2P_IE_VENDOR_TYPE);
1441f05cddf9SRui Paulo if (p2p && !p2p_group_match_dev_id(hapd->p2p_group, p2p)) {
1442f05cddf9SRui Paulo wpa_printf(MSG_MSGDUMP, "P2P: Ignore Probe Request "
1443f05cddf9SRui Paulo "due to mismatch with Device ID");
1444f05cddf9SRui Paulo wpabuf_free(p2p);
1445f05cddf9SRui Paulo return;
1446f05cddf9SRui Paulo }
1447f05cddf9SRui Paulo wpabuf_free(p2p);
1448f05cddf9SRui Paulo }
1449f05cddf9SRui Paulo #endif /* CONFIG_P2P */
1450f05cddf9SRui Paulo
1451f05cddf9SRui Paulo if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0 &&
1452c1d255d3SCy Schubert elems.ssid_list_len == 0 && elems.short_ssid_list_len == 0) {
1453f05cddf9SRui Paulo wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for "
1454f05cddf9SRui Paulo "broadcast SSID ignored", MAC2STR(mgmt->sa));
1455f05cddf9SRui Paulo return;
1456f05cddf9SRui Paulo }
1457f05cddf9SRui Paulo
1458f05cddf9SRui Paulo #ifdef CONFIG_P2P
1459f05cddf9SRui Paulo if ((hapd->conf->p2p & P2P_GROUP_OWNER) &&
1460f05cddf9SRui Paulo elems.ssid_len == P2P_WILDCARD_SSID_LEN &&
1461f05cddf9SRui Paulo os_memcmp(elems.ssid, P2P_WILDCARD_SSID,
1462f05cddf9SRui Paulo P2P_WILDCARD_SSID_LEN) == 0) {
1463f05cddf9SRui Paulo /* Process P2P Wildcard SSID like Wildcard SSID */
1464f05cddf9SRui Paulo elems.ssid_len = 0;
1465f05cddf9SRui Paulo }
1466f05cddf9SRui Paulo #endif /* CONFIG_P2P */
1467f05cddf9SRui Paulo
1468780fb4a2SCy Schubert #ifdef CONFIG_TAXONOMY
1469780fb4a2SCy Schubert {
1470780fb4a2SCy Schubert struct sta_info *sta;
1471780fb4a2SCy Schubert struct hostapd_sta_info *info;
1472780fb4a2SCy Schubert
1473780fb4a2SCy Schubert if ((sta = ap_get_sta(hapd, mgmt->sa)) != NULL) {
1474780fb4a2SCy Schubert taxonomy_sta_info_probe_req(hapd, sta, ie, ie_len);
1475780fb4a2SCy Schubert } else if ((info = sta_track_get(hapd->iface,
1476780fb4a2SCy Schubert mgmt->sa)) != NULL) {
1477780fb4a2SCy Schubert taxonomy_hostapd_sta_info_probe_req(hapd, info,
1478780fb4a2SCy Schubert ie, ie_len);
1479780fb4a2SCy Schubert }
1480780fb4a2SCy Schubert }
1481780fb4a2SCy Schubert #endif /* CONFIG_TAXONOMY */
1482780fb4a2SCy Schubert
1483f05cddf9SRui Paulo res = ssid_match(hapd, elems.ssid, elems.ssid_len,
1484c1d255d3SCy Schubert elems.ssid_list, elems.ssid_list_len,
1485c1d255d3SCy Schubert elems.short_ssid_list, elems.short_ssid_list_len);
1486325151a3SRui Paulo if (res == NO_SSID_MATCH) {
1487f05cddf9SRui Paulo if (!(mgmt->da[0] & 0x01)) {
1488f05cddf9SRui Paulo wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
1489f05cddf9SRui Paulo " for foreign SSID '%s' (DA " MACSTR ")%s",
14905b9c547cSRui Paulo MAC2STR(mgmt->sa),
14915b9c547cSRui Paulo wpa_ssid_txt(elems.ssid, elems.ssid_len),
1492f05cddf9SRui Paulo MAC2STR(mgmt->da),
1493f05cddf9SRui Paulo elems.ssid_list ? " (SSID list)" : "");
1494f05cddf9SRui Paulo }
1495f05cddf9SRui Paulo return;
1496f05cddf9SRui Paulo }
1497f05cddf9SRui Paulo
1498c1d255d3SCy Schubert if (hapd->conf->ignore_broadcast_ssid && res == WILDCARD_SSID_MATCH) {
1499c1d255d3SCy Schubert wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for "
1500c1d255d3SCy Schubert "broadcast SSID ignored", MAC2STR(mgmt->sa));
1501c1d255d3SCy Schubert return;
1502c1d255d3SCy Schubert }
1503c1d255d3SCy Schubert
1504f05cddf9SRui Paulo #ifdef CONFIG_INTERWORKING
15055b9c547cSRui Paulo if (hapd->conf->interworking &&
15065b9c547cSRui Paulo elems.interworking && elems.interworking_len >= 1) {
1507f05cddf9SRui Paulo u8 ant = elems.interworking[0] & 0x0f;
1508f05cddf9SRui Paulo if (ant != INTERWORKING_ANT_WILDCARD &&
1509f05cddf9SRui Paulo ant != hapd->conf->access_network_type) {
1510f05cddf9SRui Paulo wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
1511f05cddf9SRui Paulo " for mismatching ANT %u ignored",
1512f05cddf9SRui Paulo MAC2STR(mgmt->sa), ant);
1513f05cddf9SRui Paulo return;
1514f05cddf9SRui Paulo }
1515f05cddf9SRui Paulo }
1516f05cddf9SRui Paulo
15175b9c547cSRui Paulo if (hapd->conf->interworking && elems.interworking &&
1518f05cddf9SRui Paulo (elems.interworking_len == 7 || elems.interworking_len == 9)) {
1519f05cddf9SRui Paulo const u8 *hessid;
1520f05cddf9SRui Paulo if (elems.interworking_len == 7)
1521f05cddf9SRui Paulo hessid = elems.interworking + 1;
1522f05cddf9SRui Paulo else
1523f05cddf9SRui Paulo hessid = elems.interworking + 1 + 2;
1524f05cddf9SRui Paulo if (!is_broadcast_ether_addr(hessid) &&
1525*a90b9d01SCy Schubert !ether_addr_equal(hessid, hapd->conf->hessid)) {
1526f05cddf9SRui Paulo wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
1527f05cddf9SRui Paulo " for mismatching HESSID " MACSTR
1528f05cddf9SRui Paulo " ignored",
1529f05cddf9SRui Paulo MAC2STR(mgmt->sa), MAC2STR(hessid));
1530f05cddf9SRui Paulo return;
1531f05cddf9SRui Paulo }
1532f05cddf9SRui Paulo }
1533f05cddf9SRui Paulo #endif /* CONFIG_INTERWORKING */
1534f05cddf9SRui Paulo
15355b9c547cSRui Paulo #ifdef CONFIG_P2P
15365b9c547cSRui Paulo if ((hapd->conf->p2p & P2P_GROUP_OWNER) &&
15375b9c547cSRui Paulo supp_rates_11b_only(&elems)) {
15385b9c547cSRui Paulo /* Indicates support for 11b rates only */
15395b9c547cSRui Paulo wpa_printf(MSG_EXCESSIVE, "P2P: Ignore Probe Request from "
15405b9c547cSRui Paulo MACSTR " with only 802.11b rates",
15415b9c547cSRui Paulo MAC2STR(mgmt->sa));
15425b9c547cSRui Paulo return;
15435b9c547cSRui Paulo }
15445b9c547cSRui Paulo #endif /* CONFIG_P2P */
15455b9c547cSRui Paulo
1546f05cddf9SRui Paulo /* TODO: verify that supp_rates contains at least one matching rate
1547f05cddf9SRui Paulo * with AP configuration */
1548f05cddf9SRui Paulo
1549325151a3SRui Paulo if (hapd->conf->no_probe_resp_if_seen_on &&
1550325151a3SRui Paulo is_multicast_ether_addr(mgmt->da) &&
1551325151a3SRui Paulo is_multicast_ether_addr(mgmt->bssid) &&
1552325151a3SRui Paulo sta_track_seen_on(hapd->iface, mgmt->sa,
1553325151a3SRui Paulo hapd->conf->no_probe_resp_if_seen_on)) {
1554325151a3SRui Paulo wpa_printf(MSG_MSGDUMP, "%s: Ignore Probe Request from " MACSTR
1555325151a3SRui Paulo " since STA has been seen on %s",
1556325151a3SRui Paulo hapd->conf->iface, MAC2STR(mgmt->sa),
1557325151a3SRui Paulo hapd->conf->no_probe_resp_if_seen_on);
1558325151a3SRui Paulo return;
1559325151a3SRui Paulo }
1560325151a3SRui Paulo
1561780fb4a2SCy Schubert if (hapd->conf->no_probe_resp_if_max_sta &&
1562780fb4a2SCy Schubert is_multicast_ether_addr(mgmt->da) &&
1563780fb4a2SCy Schubert is_multicast_ether_addr(mgmt->bssid) &&
1564780fb4a2SCy Schubert hapd->num_sta >= hapd->conf->max_num_sta &&
1565780fb4a2SCy Schubert !ap_get_sta(hapd, mgmt->sa)) {
1566780fb4a2SCy Schubert wpa_printf(MSG_MSGDUMP, "%s: Ignore Probe Request from " MACSTR
1567780fb4a2SCy Schubert " since no room for additional STA",
1568780fb4a2SCy Schubert hapd->conf->iface, MAC2STR(mgmt->sa));
1569780fb4a2SCy Schubert return;
1570780fb4a2SCy Schubert }
1571780fb4a2SCy Schubert
15725b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS
15735b9c547cSRui Paulo if (hapd->iconf->ignore_probe_probability > 0.0 &&
15745b9c547cSRui Paulo drand48() < hapd->iconf->ignore_probe_probability) {
15755b9c547cSRui Paulo wpa_printf(MSG_INFO,
15765b9c547cSRui Paulo "TESTING: ignoring probe request from " MACSTR,
15775b9c547cSRui Paulo MAC2STR(mgmt->sa));
15785b9c547cSRui Paulo return;
15795b9c547cSRui Paulo }
15805b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */
15815b9c547cSRui Paulo
1582*a90b9d01SCy Schubert /* Do not send Probe Response frame from a non-transmitting multiple
1583*a90b9d01SCy Schubert * BSSID profile unless the Probe Request frame is directed at that
1584*a90b9d01SCy Schubert * particular BSS. */
1585*a90b9d01SCy Schubert if (hapd != hostapd_mbssid_get_tx_bss(hapd) && res != EXACT_SSID_MATCH)
1586*a90b9d01SCy Schubert return;
1587*a90b9d01SCy Schubert
158885732ac8SCy Schubert wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, RX_PROBE_REQUEST "sa=" MACSTR
158985732ac8SCy Schubert " signal=%d", MAC2STR(mgmt->sa), ssi_signal);
159085732ac8SCy Schubert
1591*a90b9d01SCy Schubert os_memset(¶ms, 0, sizeof(params));
1592*a90b9d01SCy Schubert
1593*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211BE
1594*a90b9d01SCy Schubert if (hapd->conf->mld_ap && elems.probe_req_mle &&
1595*a90b9d01SCy Schubert parse_ml_probe_req((struct ieee80211_eht_ml *) elems.probe_req_mle,
1596*a90b9d01SCy Schubert elems.probe_req_mle_len, &mld_id, &links)) {
1597*a90b9d01SCy Schubert hostapd_fill_probe_resp_ml_params(hapd, ¶ms, mgmt,
1598*a90b9d01SCy Schubert mld_id, links);
1599*a90b9d01SCy Schubert }
1600*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211BE */
1601*a90b9d01SCy Schubert
1602*a90b9d01SCy Schubert params.req = mgmt;
1603*a90b9d01SCy Schubert params.is_p2p = !!elems.p2p;
1604*a90b9d01SCy Schubert params.known_bss = elems.mbssid_known_bss;
1605*a90b9d01SCy Schubert params.known_bss_len = elems.mbssid_known_bss_len;
1606*a90b9d01SCy Schubert params.is_ml_sta_info = false;
1607*a90b9d01SCy Schubert
1608*a90b9d01SCy Schubert hostapd_gen_probe_resp(hapd, ¶ms);
1609*a90b9d01SCy Schubert
1610*a90b9d01SCy Schubert hostapd_free_probe_resp_params(¶ms);
1611*a90b9d01SCy Schubert
1612*a90b9d01SCy Schubert if (!params.resp)
1613f05cddf9SRui Paulo return;
1614f05cddf9SRui Paulo
1615f05cddf9SRui Paulo /*
1616f05cddf9SRui Paulo * If this is a broadcast probe request, apply no ack policy to avoid
1617f05cddf9SRui Paulo * excessive retries.
1618f05cddf9SRui Paulo */
1619f05cddf9SRui Paulo noack = !!(res == WILDCARD_SSID_MATCH &&
1620f05cddf9SRui Paulo is_broadcast_ether_addr(mgmt->da));
1621f05cddf9SRui Paulo
1622780fb4a2SCy Schubert csa_offs_len = 0;
1623780fb4a2SCy Schubert if (hapd->csa_in_progress) {
1624*a90b9d01SCy Schubert if (params.csa_pos)
1625780fb4a2SCy Schubert csa_offs[csa_offs_len++] =
1626*a90b9d01SCy Schubert params.csa_pos - (u8 *) params.resp;
1627780fb4a2SCy Schubert
1628*a90b9d01SCy Schubert if (params.ecsa_pos)
1629780fb4a2SCy Schubert csa_offs[csa_offs_len++] =
1630*a90b9d01SCy Schubert params.ecsa_pos - (u8 *) params.resp;
1631780fb4a2SCy Schubert }
1632780fb4a2SCy Schubert
1633*a90b9d01SCy Schubert ret = hostapd_drv_send_mlme(hapd, params.resp, params.resp_len, noack,
1634780fb4a2SCy Schubert csa_offs_len ? csa_offs : NULL,
1635c1d255d3SCy Schubert csa_offs_len, 0);
1636780fb4a2SCy Schubert
1637780fb4a2SCy Schubert if (ret < 0)
16385b9c547cSRui Paulo wpa_printf(MSG_INFO, "handle_probe_req: send failed");
1639e28a4053SRui Paulo
1640*a90b9d01SCy Schubert os_free(params.resp);
1641e28a4053SRui Paulo
1642f05cddf9SRui Paulo wpa_printf(MSG_EXCESSIVE, "STA " MACSTR " sent probe request for %s "
1643e28a4053SRui Paulo "SSID", MAC2STR(mgmt->sa),
1644e28a4053SRui Paulo elems.ssid_len == 0 ? "broadcast" : "our");
1645e28a4053SRui Paulo }
1646e28a4053SRui Paulo
1647e28a4053SRui Paulo
hostapd_probe_resp_offloads(struct hostapd_data * hapd,size_t * resp_len)1648f05cddf9SRui Paulo static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd,
1649f05cddf9SRui Paulo size_t *resp_len)
1650f05cddf9SRui Paulo {
1651*a90b9d01SCy Schubert struct probe_resp_params params;
1652*a90b9d01SCy Schubert
1653f05cddf9SRui Paulo /* check probe response offloading caps and print warnings */
1654f05cddf9SRui Paulo if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD))
1655f05cddf9SRui Paulo return NULL;
1656f05cddf9SRui Paulo
1657f05cddf9SRui Paulo #ifdef CONFIG_WPS
1658f05cddf9SRui Paulo if (hapd->conf->wps_state && hapd->wps_probe_resp_ie &&
1659f05cddf9SRui Paulo (!(hapd->iface->probe_resp_offloads &
1660f05cddf9SRui Paulo (WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS |
1661f05cddf9SRui Paulo WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2))))
1662f05cddf9SRui Paulo wpa_printf(MSG_WARNING, "Device is trying to offload WPS "
1663f05cddf9SRui Paulo "Probe Response while not supporting this");
1664f05cddf9SRui Paulo #endif /* CONFIG_WPS */
1665f05cddf9SRui Paulo
1666f05cddf9SRui Paulo #ifdef CONFIG_P2P
1667f05cddf9SRui Paulo if ((hapd->conf->p2p & P2P_ENABLED) && hapd->p2p_probe_resp_ie &&
1668f05cddf9SRui Paulo !(hapd->iface->probe_resp_offloads &
1669f05cddf9SRui Paulo WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P))
1670f05cddf9SRui Paulo wpa_printf(MSG_WARNING, "Device is trying to offload P2P "
1671f05cddf9SRui Paulo "Probe Response while not supporting this");
1672f05cddf9SRui Paulo #endif /* CONFIG_P2P */
1673f05cddf9SRui Paulo
1674f05cddf9SRui Paulo if (hapd->conf->interworking &&
1675f05cddf9SRui Paulo !(hapd->iface->probe_resp_offloads &
1676f05cddf9SRui Paulo WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING))
1677f05cddf9SRui Paulo wpa_printf(MSG_WARNING, "Device is trying to offload "
1678f05cddf9SRui Paulo "Interworking Probe Response while not supporting "
1679f05cddf9SRui Paulo "this");
1680f05cddf9SRui Paulo
1681f05cddf9SRui Paulo /* Generate a Probe Response template for the non-P2P case */
1682*a90b9d01SCy Schubert os_memset(¶ms, 0, sizeof(params));
1683*a90b9d01SCy Schubert params.req = NULL;
1684*a90b9d01SCy Schubert params.is_p2p = false;
1685*a90b9d01SCy Schubert params.known_bss = NULL;
1686*a90b9d01SCy Schubert params.known_bss_len = 0;
1687*a90b9d01SCy Schubert params.is_ml_sta_info = false;
1688*a90b9d01SCy Schubert params.mld_ap = NULL;
1689*a90b9d01SCy Schubert params.mld_info = NULL;
1690*a90b9d01SCy Schubert
1691*a90b9d01SCy Schubert hostapd_gen_probe_resp(hapd, ¶ms);
1692*a90b9d01SCy Schubert *resp_len = params.resp_len;
1693*a90b9d01SCy Schubert if (!params.resp)
1694*a90b9d01SCy Schubert return NULL;
1695*a90b9d01SCy Schubert
1696*a90b9d01SCy Schubert /* TODO: Avoid passing these through struct hostapd_data */
1697*a90b9d01SCy Schubert if (params.csa_pos)
1698*a90b9d01SCy Schubert hapd->cs_c_off_proberesp = params.csa_pos - (u8 *) params.resp;
1699*a90b9d01SCy Schubert if (params.ecsa_pos)
1700*a90b9d01SCy Schubert hapd->cs_c_off_ecsa_proberesp = params.ecsa_pos -
1701*a90b9d01SCy Schubert (u8 *) params.resp;
1702*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211AX
1703*a90b9d01SCy Schubert if (params.cca_pos)
1704*a90b9d01SCy Schubert hapd->cca_c_off_proberesp = params.cca_pos - (u8 *) params.resp;
1705*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211AX */
1706*a90b9d01SCy Schubert
1707*a90b9d01SCy Schubert return (u8 *) params.resp;
1708f05cddf9SRui Paulo }
1709f05cddf9SRui Paulo
1710f05cddf9SRui Paulo #endif /* NEED_AP_MLME */
1711f05cddf9SRui Paulo
1712f05cddf9SRui Paulo
1713c1d255d3SCy Schubert #ifdef CONFIG_IEEE80211AX
1714c1d255d3SCy Schubert /* Unsolicited broadcast Probe Response transmission, 6 GHz only */
hostapd_unsol_bcast_probe_resp(struct hostapd_data * hapd,struct unsol_bcast_probe_resp * ubpr)1715*a90b9d01SCy Schubert u8 * hostapd_unsol_bcast_probe_resp(struct hostapd_data *hapd,
1716*a90b9d01SCy Schubert struct unsol_bcast_probe_resp *ubpr)
1717c1d255d3SCy Schubert {
1718*a90b9d01SCy Schubert struct probe_resp_params probe_params;
1719*a90b9d01SCy Schubert
1720c1d255d3SCy Schubert if (!is_6ghz_op_class(hapd->iconf->op_class))
1721c1d255d3SCy Schubert return NULL;
1722c1d255d3SCy Schubert
1723*a90b9d01SCy Schubert ubpr->unsol_bcast_probe_resp_interval =
1724c1d255d3SCy Schubert hapd->conf->unsol_bcast_probe_resp_interval;
1725c1d255d3SCy Schubert
1726*a90b9d01SCy Schubert os_memset(&probe_params, 0, sizeof(probe_params));
1727*a90b9d01SCy Schubert probe_params.req = NULL;
1728*a90b9d01SCy Schubert probe_params.is_p2p = false;
1729*a90b9d01SCy Schubert probe_params.known_bss = NULL;
1730*a90b9d01SCy Schubert probe_params.known_bss_len = 0;
1731*a90b9d01SCy Schubert probe_params.is_ml_sta_info = false;
1732*a90b9d01SCy Schubert probe_params.mld_ap = NULL;
1733*a90b9d01SCy Schubert probe_params.mld_info = NULL;
1734*a90b9d01SCy Schubert
1735*a90b9d01SCy Schubert hostapd_gen_probe_resp(hapd, &probe_params);
1736*a90b9d01SCy Schubert ubpr->unsol_bcast_probe_resp_tmpl_len = probe_params.resp_len;
1737*a90b9d01SCy Schubert return (u8 *) probe_params.resp;
1738c1d255d3SCy Schubert }
1739c1d255d3SCy Schubert #endif /* CONFIG_IEEE80211AX */
1740c1d255d3SCy Schubert
1741c1d255d3SCy Schubert
sta_track_del(struct hostapd_sta_info * info)1742780fb4a2SCy Schubert void sta_track_del(struct hostapd_sta_info *info)
1743780fb4a2SCy Schubert {
1744780fb4a2SCy Schubert #ifdef CONFIG_TAXONOMY
1745780fb4a2SCy Schubert wpabuf_free(info->probe_ie_taxonomy);
1746780fb4a2SCy Schubert info->probe_ie_taxonomy = NULL;
1747780fb4a2SCy Schubert #endif /* CONFIG_TAXONOMY */
1748780fb4a2SCy Schubert os_free(info);
1749780fb4a2SCy Schubert }
1750780fb4a2SCy Schubert
1751780fb4a2SCy Schubert
1752c1d255d3SCy Schubert #ifdef CONFIG_FILS
1753c1d255d3SCy Schubert
hostapd_gen_fils_discovery_phy_index(struct hostapd_data * hapd)1754*a90b9d01SCy Schubert static u16 hostapd_gen_fils_discovery_phy_index(struct hostapd_data *hapd)
1755*a90b9d01SCy Schubert {
1756*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211BE
1757*a90b9d01SCy Schubert if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be)
1758*a90b9d01SCy Schubert return FD_CAP_PHY_INDEX_EHT;
1759*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211BE */
1760*a90b9d01SCy Schubert
1761*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211AX
1762*a90b9d01SCy Schubert if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax)
1763*a90b9d01SCy Schubert return FD_CAP_PHY_INDEX_HE;
1764*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211AX */
1765*a90b9d01SCy Schubert
1766*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211AC
1767*a90b9d01SCy Schubert if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac)
1768*a90b9d01SCy Schubert return FD_CAP_PHY_INDEX_VHT;
1769*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211AC */
1770*a90b9d01SCy Schubert
1771*a90b9d01SCy Schubert if (hapd->iconf->ieee80211n && !hapd->conf->disable_11n)
1772*a90b9d01SCy Schubert return FD_CAP_PHY_INDEX_HT;
1773*a90b9d01SCy Schubert
1774*a90b9d01SCy Schubert return 0;
1775*a90b9d01SCy Schubert }
1776*a90b9d01SCy Schubert
1777*a90b9d01SCy Schubert
hostapd_gen_fils_discovery_nss(struct hostapd_hw_modes * mode,u16 phy_index,u8 he_mcs_nss_size)1778*a90b9d01SCy Schubert static u16 hostapd_gen_fils_discovery_nss(struct hostapd_hw_modes *mode,
1779*a90b9d01SCy Schubert u16 phy_index, u8 he_mcs_nss_size)
1780*a90b9d01SCy Schubert {
1781*a90b9d01SCy Schubert u16 nss = 0;
1782*a90b9d01SCy Schubert
1783*a90b9d01SCy Schubert if (!mode)
1784*a90b9d01SCy Schubert return 0;
1785*a90b9d01SCy Schubert
1786*a90b9d01SCy Schubert if (phy_index == FD_CAP_PHY_INDEX_HE) {
1787*a90b9d01SCy Schubert const u8 *he_mcs = mode->he_capab[IEEE80211_MODE_AP].mcs;
1788*a90b9d01SCy Schubert int i;
1789*a90b9d01SCy Schubert u16 mcs[6];
1790*a90b9d01SCy Schubert
1791*a90b9d01SCy Schubert os_memset(mcs, 0xff, 6 * sizeof(u16));
1792*a90b9d01SCy Schubert
1793*a90b9d01SCy Schubert if (he_mcs_nss_size == 4) {
1794*a90b9d01SCy Schubert mcs[0] = WPA_GET_LE16(&he_mcs[0]);
1795*a90b9d01SCy Schubert mcs[1] = WPA_GET_LE16(&he_mcs[2]);
1796*a90b9d01SCy Schubert }
1797*a90b9d01SCy Schubert
1798*a90b9d01SCy Schubert if (he_mcs_nss_size == 8) {
1799*a90b9d01SCy Schubert mcs[2] = WPA_GET_LE16(&he_mcs[4]);
1800*a90b9d01SCy Schubert mcs[3] = WPA_GET_LE16(&he_mcs[6]);
1801*a90b9d01SCy Schubert }
1802*a90b9d01SCy Schubert
1803*a90b9d01SCy Schubert if (he_mcs_nss_size == 12) {
1804*a90b9d01SCy Schubert mcs[4] = WPA_GET_LE16(&he_mcs[8]);
1805*a90b9d01SCy Schubert mcs[5] = WPA_GET_LE16(&he_mcs[10]);
1806*a90b9d01SCy Schubert }
1807*a90b9d01SCy Schubert
1808*a90b9d01SCy Schubert for (i = 0; i < HE_NSS_MAX_STREAMS; i++) {
1809*a90b9d01SCy Schubert u16 nss_mask = 0x3 << (i * 2);
1810*a90b9d01SCy Schubert
1811*a90b9d01SCy Schubert /*
1812*a90b9d01SCy Schubert * If Tx and/or Rx indicate support for a given NSS,
1813*a90b9d01SCy Schubert * count it towards the maximum NSS.
1814*a90b9d01SCy Schubert */
1815*a90b9d01SCy Schubert if (he_mcs_nss_size == 4 &&
1816*a90b9d01SCy Schubert (((mcs[0] & nss_mask) != nss_mask) ||
1817*a90b9d01SCy Schubert ((mcs[1] & nss_mask) != nss_mask))) {
1818*a90b9d01SCy Schubert nss++;
1819*a90b9d01SCy Schubert continue;
1820*a90b9d01SCy Schubert }
1821*a90b9d01SCy Schubert
1822*a90b9d01SCy Schubert if (he_mcs_nss_size == 8 &&
1823*a90b9d01SCy Schubert (((mcs[2] & nss_mask) != nss_mask) ||
1824*a90b9d01SCy Schubert ((mcs[3] & nss_mask) != nss_mask))) {
1825*a90b9d01SCy Schubert nss++;
1826*a90b9d01SCy Schubert continue;
1827*a90b9d01SCy Schubert }
1828*a90b9d01SCy Schubert
1829*a90b9d01SCy Schubert if (he_mcs_nss_size == 12 &&
1830*a90b9d01SCy Schubert (((mcs[4] & nss_mask) != nss_mask) ||
1831*a90b9d01SCy Schubert ((mcs[5] & nss_mask) != nss_mask))) {
1832*a90b9d01SCy Schubert nss++;
1833*a90b9d01SCy Schubert continue;
1834*a90b9d01SCy Schubert }
1835*a90b9d01SCy Schubert }
1836*a90b9d01SCy Schubert } else if (phy_index == FD_CAP_PHY_INDEX_EHT) {
1837*a90b9d01SCy Schubert u8 rx_nss, tx_nss, max_nss = 0, i;
1838*a90b9d01SCy Schubert u8 *mcs = mode->eht_capab[IEEE80211_MODE_AP].mcs;
1839*a90b9d01SCy Schubert
1840*a90b9d01SCy Schubert /*
1841*a90b9d01SCy Schubert * The Supported EHT-MCS And NSS Set field for the AP contains
1842*a90b9d01SCy Schubert * one to three EHT-MCS Map fields based on the supported
1843*a90b9d01SCy Schubert * bandwidth. Check the first byte (max NSS for Rx/Tx that
1844*a90b9d01SCy Schubert * supports EHT-MCS 0-9) for each bandwidth (<= 80,
1845*a90b9d01SCy Schubert * 160, 320) to find the maximum NSS. This assumes that
1846*a90b9d01SCy Schubert * the lowest MCS rates support the largest number of spatial
1847*a90b9d01SCy Schubert * streams. If values are different between Tx, Rx or the
1848*a90b9d01SCy Schubert * bandwidths, choose the highest value.
1849*a90b9d01SCy Schubert */
1850*a90b9d01SCy Schubert for (i = 0; i < 3; i++) {
1851*a90b9d01SCy Schubert rx_nss = mcs[3 * i] & 0x0F;
1852*a90b9d01SCy Schubert if (rx_nss > max_nss)
1853*a90b9d01SCy Schubert max_nss = rx_nss;
1854*a90b9d01SCy Schubert
1855*a90b9d01SCy Schubert tx_nss = (mcs[3 * i] & 0xF0) >> 4;
1856*a90b9d01SCy Schubert if (tx_nss > max_nss)
1857*a90b9d01SCy Schubert max_nss = tx_nss;
1858*a90b9d01SCy Schubert }
1859*a90b9d01SCy Schubert
1860*a90b9d01SCy Schubert nss = max_nss;
1861*a90b9d01SCy Schubert }
1862*a90b9d01SCy Schubert
1863*a90b9d01SCy Schubert if (nss > 4)
1864*a90b9d01SCy Schubert return FD_CAP_NSS_5_8 << FD_CAP_NSS_SHIFT;
1865*a90b9d01SCy Schubert if (nss)
1866*a90b9d01SCy Schubert return (nss - 1) << FD_CAP_NSS_SHIFT;
1867*a90b9d01SCy Schubert
1868*a90b9d01SCy Schubert return 0;
1869*a90b9d01SCy Schubert }
1870*a90b9d01SCy Schubert
1871*a90b9d01SCy Schubert
hostapd_fils_discovery_cap(struct hostapd_data * hapd)1872c1d255d3SCy Schubert static u16 hostapd_fils_discovery_cap(struct hostapd_data *hapd)
1873c1d255d3SCy Schubert {
1874*a90b9d01SCy Schubert u16 cap_info, phy_index;
1875*a90b9d01SCy Schubert u8 chwidth = FD_CAP_BSS_CHWIDTH_20, he_mcs_nss_size = 4;
1876c1d255d3SCy Schubert struct hostapd_hw_modes *mode = hapd->iface->current_mode;
1877c1d255d3SCy Schubert
1878c1d255d3SCy Schubert cap_info = FD_CAP_ESS;
1879c1d255d3SCy Schubert if (hapd->conf->wpa)
1880c1d255d3SCy Schubert cap_info |= FD_CAP_PRIVACY;
1881c1d255d3SCy Schubert
1882c1d255d3SCy Schubert if (is_6ghz_op_class(hapd->iconf->op_class)) {
1883c1d255d3SCy Schubert switch (hapd->iconf->op_class) {
1884*a90b9d01SCy Schubert case 137:
1885*a90b9d01SCy Schubert chwidth = FD_CAP_BSS_CHWIDTH_320;
1886*a90b9d01SCy Schubert break;
1887c1d255d3SCy Schubert case 135:
1888*a90b9d01SCy Schubert he_mcs_nss_size += 4;
1889c1d255d3SCy Schubert /* fallthrough */
1890c1d255d3SCy Schubert case 134:
1891*a90b9d01SCy Schubert he_mcs_nss_size += 4;
1892c1d255d3SCy Schubert chwidth = FD_CAP_BSS_CHWIDTH_160_80_80;
1893c1d255d3SCy Schubert break;
1894c1d255d3SCy Schubert case 133:
1895c1d255d3SCy Schubert chwidth = FD_CAP_BSS_CHWIDTH_80;
1896c1d255d3SCy Schubert break;
1897c1d255d3SCy Schubert case 132:
1898c1d255d3SCy Schubert chwidth = FD_CAP_BSS_CHWIDTH_40;
1899c1d255d3SCy Schubert break;
1900c1d255d3SCy Schubert }
1901c1d255d3SCy Schubert } else {
1902c1d255d3SCy Schubert switch (hostapd_get_oper_chwidth(hapd->iconf)) {
1903*a90b9d01SCy Schubert case CONF_OPER_CHWIDTH_80P80MHZ:
1904*a90b9d01SCy Schubert he_mcs_nss_size += 4;
1905c1d255d3SCy Schubert /* fallthrough */
1906*a90b9d01SCy Schubert case CONF_OPER_CHWIDTH_160MHZ:
1907*a90b9d01SCy Schubert he_mcs_nss_size += 4;
1908c1d255d3SCy Schubert chwidth = FD_CAP_BSS_CHWIDTH_160_80_80;
1909c1d255d3SCy Schubert break;
1910*a90b9d01SCy Schubert case CONF_OPER_CHWIDTH_80MHZ:
1911c1d255d3SCy Schubert chwidth = FD_CAP_BSS_CHWIDTH_80;
1912c1d255d3SCy Schubert break;
1913*a90b9d01SCy Schubert case CONF_OPER_CHWIDTH_USE_HT:
1914c1d255d3SCy Schubert if (hapd->iconf->secondary_channel)
1915c1d255d3SCy Schubert chwidth = FD_CAP_BSS_CHWIDTH_40;
1916c1d255d3SCy Schubert else
1917c1d255d3SCy Schubert chwidth = FD_CAP_BSS_CHWIDTH_20;
1918c1d255d3SCy Schubert break;
1919*a90b9d01SCy Schubert default:
1920*a90b9d01SCy Schubert break;
1921*a90b9d01SCy Schubert }
1922c1d255d3SCy Schubert }
1923c1d255d3SCy Schubert
1924*a90b9d01SCy Schubert phy_index = hostapd_gen_fils_discovery_phy_index(hapd);
1925c1d255d3SCy Schubert cap_info |= phy_index << FD_CAP_PHY_INDEX_SHIFT;
1926c1d255d3SCy Schubert cap_info |= chwidth << FD_CAP_BSS_CHWIDTH_SHIFT;
1927*a90b9d01SCy Schubert cap_info |= hostapd_gen_fils_discovery_nss(mode, phy_index,
1928*a90b9d01SCy Schubert he_mcs_nss_size);
1929c1d255d3SCy Schubert return cap_info;
1930c1d255d3SCy Schubert }
1931c1d255d3SCy Schubert
1932c1d255d3SCy Schubert
hostapd_gen_fils_discovery(struct hostapd_data * hapd,size_t * len)1933c1d255d3SCy Schubert static u8 * hostapd_gen_fils_discovery(struct hostapd_data *hapd, size_t *len)
1934c1d255d3SCy Schubert {
1935c1d255d3SCy Schubert struct ieee80211_mgmt *head;
1936c1d255d3SCy Schubert const u8 *mobility_domain;
1937c1d255d3SCy Schubert u8 *pos, *length_pos, buf[200];
1938c1d255d3SCy Schubert u16 ctl = 0;
1939c1d255d3SCy Schubert u8 fd_rsn_info[5];
1940c1d255d3SCy Schubert size_t total_len, buf_len;
1941c1d255d3SCy Schubert
1942c1d255d3SCy Schubert total_len = 24 + 2 + 12;
1943c1d255d3SCy Schubert
1944c1d255d3SCy Schubert /* FILS Discovery Frame Control */
1945c1d255d3SCy Schubert ctl = (sizeof(hapd->conf->ssid.short_ssid) - 1) |
1946c1d255d3SCy Schubert FD_FRAME_CTL_SHORT_SSID_PRESENT |
1947c1d255d3SCy Schubert FD_FRAME_CTL_LENGTH_PRESENT |
1948c1d255d3SCy Schubert FD_FRAME_CTL_CAP_PRESENT;
1949c1d255d3SCy Schubert total_len += 4 + 1 + 2;
1950c1d255d3SCy Schubert
1951*a90b9d01SCy Schubert /* Fill primary channel information for 6 GHz channels with over 20 MHz
1952*a90b9d01SCy Schubert * bandwidth, if the primary channel is not a PSC */
1953*a90b9d01SCy Schubert if (is_6ghz_op_class(hapd->iconf->op_class) &&
1954*a90b9d01SCy Schubert !is_6ghz_psc_frequency(ieee80211_chan_to_freq(
1955*a90b9d01SCy Schubert NULL, hapd->iconf->op_class,
1956*a90b9d01SCy Schubert hapd->iconf->channel)) &&
1957*a90b9d01SCy Schubert op_class_to_bandwidth(hapd->iconf->op_class) > 20) {
1958*a90b9d01SCy Schubert ctl |= FD_FRAME_CTL_PRI_CHAN_PRESENT;
1959*a90b9d01SCy Schubert total_len += 2;
1960*a90b9d01SCy Schubert }
1961*a90b9d01SCy Schubert
1962c1d255d3SCy Schubert /* Check for optional subfields and calculate length */
1963c1d255d3SCy Schubert if (wpa_auth_write_fd_rsn_info(hapd->wpa_auth, fd_rsn_info)) {
1964c1d255d3SCy Schubert ctl |= FD_FRAME_CTL_RSN_INFO_PRESENT;
1965c1d255d3SCy Schubert total_len += sizeof(fd_rsn_info);
1966c1d255d3SCy Schubert }
1967c1d255d3SCy Schubert
1968c1d255d3SCy Schubert mobility_domain = hostapd_wpa_ie(hapd, WLAN_EID_MOBILITY_DOMAIN);
1969c1d255d3SCy Schubert if (mobility_domain) {
1970c1d255d3SCy Schubert ctl |= FD_FRAME_CTL_MD_PRESENT;
1971c1d255d3SCy Schubert total_len += 3;
1972c1d255d3SCy Schubert }
1973c1d255d3SCy Schubert
1974*a90b9d01SCy Schubert total_len += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_ACTION, true);
19754b72b91aSCy Schubert
1976c1d255d3SCy Schubert pos = hostapd_eid_fils_indic(hapd, buf, 0);
1977c1d255d3SCy Schubert buf_len = pos - buf;
1978c1d255d3SCy Schubert total_len += buf_len;
1979c1d255d3SCy Schubert
1980*a90b9d01SCy Schubert /* he_elem_len() may return too large a value for FD frame, but that is
1981*a90b9d01SCy Schubert * fine here since this is used as the maximum length of the buffer. */
1982*a90b9d01SCy Schubert total_len += he_elem_len(hapd);
1983*a90b9d01SCy Schubert
1984c1d255d3SCy Schubert head = os_zalloc(total_len);
1985c1d255d3SCy Schubert if (!head)
1986c1d255d3SCy Schubert return NULL;
1987c1d255d3SCy Schubert
1988c1d255d3SCy Schubert head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
1989c1d255d3SCy Schubert WLAN_FC_STYPE_ACTION);
1990c1d255d3SCy Schubert os_memset(head->da, 0xff, ETH_ALEN);
1991c1d255d3SCy Schubert os_memcpy(head->sa, hapd->own_addr, ETH_ALEN);
1992c1d255d3SCy Schubert os_memcpy(head->bssid, hapd->own_addr, ETH_ALEN);
1993c1d255d3SCy Schubert
1994c1d255d3SCy Schubert head->u.action.category = WLAN_ACTION_PUBLIC;
1995c1d255d3SCy Schubert head->u.action.u.public_action.action = WLAN_PA_FILS_DISCOVERY;
1996c1d255d3SCy Schubert
1997c1d255d3SCy Schubert pos = &head->u.action.u.public_action.variable[0];
1998c1d255d3SCy Schubert
1999c1d255d3SCy Schubert /* FILS Discovery Information field */
2000c1d255d3SCy Schubert
2001c1d255d3SCy Schubert /* FILS Discovery Frame Control */
2002c1d255d3SCy Schubert WPA_PUT_LE16(pos, ctl);
2003c1d255d3SCy Schubert pos += 2;
2004c1d255d3SCy Schubert
2005c1d255d3SCy Schubert /* Hardware or low-level driver will fill in the Timestamp value */
2006c1d255d3SCy Schubert pos += 8;
2007c1d255d3SCy Schubert
2008c1d255d3SCy Schubert /* Beacon Interval */
2009c1d255d3SCy Schubert WPA_PUT_LE16(pos, hapd->iconf->beacon_int);
2010c1d255d3SCy Schubert pos += 2;
2011c1d255d3SCy Schubert
2012c1d255d3SCy Schubert /* Short SSID */
2013c1d255d3SCy Schubert WPA_PUT_LE32(pos, hapd->conf->ssid.short_ssid);
2014c1d255d3SCy Schubert pos += sizeof(hapd->conf->ssid.short_ssid);
2015c1d255d3SCy Schubert
2016c1d255d3SCy Schubert /* Store position of FILS discovery information element Length field */
2017c1d255d3SCy Schubert length_pos = pos++;
2018c1d255d3SCy Schubert
2019c1d255d3SCy Schubert /* FD Capability */
2020c1d255d3SCy Schubert WPA_PUT_LE16(pos, hostapd_fils_discovery_cap(hapd));
2021c1d255d3SCy Schubert pos += 2;
2022c1d255d3SCy Schubert
2023*a90b9d01SCy Schubert /* Operating Class and Primary Channel - if a 6 GHz chan is non PSC */
2024*a90b9d01SCy Schubert if (ctl & FD_FRAME_CTL_PRI_CHAN_PRESENT) {
2025*a90b9d01SCy Schubert *pos++ = hapd->iconf->op_class;
2026*a90b9d01SCy Schubert *pos++ = hapd->iconf->channel;
2027*a90b9d01SCy Schubert }
2028c1d255d3SCy Schubert
2029c1d255d3SCy Schubert /* AP Configuration Sequence Number - not present */
2030c1d255d3SCy Schubert
2031c1d255d3SCy Schubert /* Access Network Options - not present */
2032c1d255d3SCy Schubert
2033c1d255d3SCy Schubert /* FD RSN Information */
2034c1d255d3SCy Schubert if (ctl & FD_FRAME_CTL_RSN_INFO_PRESENT) {
2035c1d255d3SCy Schubert os_memcpy(pos, fd_rsn_info, sizeof(fd_rsn_info));
2036c1d255d3SCy Schubert pos += sizeof(fd_rsn_info);
2037c1d255d3SCy Schubert }
2038c1d255d3SCy Schubert
2039c1d255d3SCy Schubert /* Channel Center Frequency Segment 1 - not present */
2040c1d255d3SCy Schubert
2041c1d255d3SCy Schubert /* Mobility Domain */
2042c1d255d3SCy Schubert if (ctl & FD_FRAME_CTL_MD_PRESENT) {
2043c1d255d3SCy Schubert os_memcpy(pos, &mobility_domain[2], 3);
2044c1d255d3SCy Schubert pos += 3;
2045c1d255d3SCy Schubert }
2046c1d255d3SCy Schubert
2047c1d255d3SCy Schubert /* Fill in the Length field value */
2048c1d255d3SCy Schubert *length_pos = pos - (length_pos + 1);
2049c1d255d3SCy Schubert
2050*a90b9d01SCy Schubert pos = hostapd_eid_rnr(hapd, pos, WLAN_FC_STYPE_ACTION, true);
20514b72b91aSCy Schubert
2052c1d255d3SCy Schubert /* FILS Indication element */
2053c1d255d3SCy Schubert if (buf_len) {
2054c1d255d3SCy Schubert os_memcpy(pos, buf, buf_len);
2055c1d255d3SCy Schubert pos += buf_len;
2056c1d255d3SCy Schubert }
2057c1d255d3SCy Schubert
2058*a90b9d01SCy Schubert if (is_6ghz_op_class(hapd->iconf->op_class))
2059*a90b9d01SCy Schubert pos = hostapd_eid_txpower_envelope(hapd, pos);
2060*a90b9d01SCy Schubert
2061c1d255d3SCy Schubert *len = pos - (u8 *) head;
2062c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "FILS Discovery frame template",
2063c1d255d3SCy Schubert head, pos - (u8 *) head);
2064c1d255d3SCy Schubert return (u8 *) head;
2065c1d255d3SCy Schubert }
2066c1d255d3SCy Schubert
2067c1d255d3SCy Schubert
2068c1d255d3SCy Schubert /* Configure FILS Discovery frame transmission parameters */
hostapd_fils_discovery(struct hostapd_data * hapd,struct wpa_driver_ap_params * params)2069c1d255d3SCy Schubert static u8 * hostapd_fils_discovery(struct hostapd_data *hapd,
2070c1d255d3SCy Schubert struct wpa_driver_ap_params *params)
2071c1d255d3SCy Schubert {
2072c1d255d3SCy Schubert params->fd_max_int = hapd->conf->fils_discovery_max_int;
2073c1d255d3SCy Schubert if (is_6ghz_op_class(hapd->iconf->op_class) &&
2074c1d255d3SCy Schubert params->fd_max_int > FD_MAX_INTERVAL_6GHZ)
2075c1d255d3SCy Schubert params->fd_max_int = FD_MAX_INTERVAL_6GHZ;
2076c1d255d3SCy Schubert
2077c1d255d3SCy Schubert params->fd_min_int = hapd->conf->fils_discovery_min_int;
2078c1d255d3SCy Schubert if (params->fd_min_int > params->fd_max_int)
2079c1d255d3SCy Schubert params->fd_min_int = params->fd_max_int;
2080c1d255d3SCy Schubert
2081c1d255d3SCy Schubert if (params->fd_max_int)
2082c1d255d3SCy Schubert return hostapd_gen_fils_discovery(hapd,
2083c1d255d3SCy Schubert ¶ms->fd_frame_tmpl_len);
2084c1d255d3SCy Schubert
2085c1d255d3SCy Schubert return NULL;
2086c1d255d3SCy Schubert }
2087c1d255d3SCy Schubert
2088c1d255d3SCy Schubert #endif /* CONFIG_FILS */
2089c1d255d3SCy Schubert
2090c1d255d3SCy Schubert
ieee802_11_build_ap_params(struct hostapd_data * hapd,struct wpa_driver_ap_params * params)20915b9c547cSRui Paulo int ieee802_11_build_ap_params(struct hostapd_data *hapd,
20925b9c547cSRui Paulo struct wpa_driver_ap_params *params)
2093e28a4053SRui Paulo {
2094f05cddf9SRui Paulo struct ieee80211_mgmt *head = NULL;
2095f05cddf9SRui Paulo u8 *tail = NULL;
2096f05cddf9SRui Paulo size_t head_len = 0, tail_len = 0;
2097f05cddf9SRui Paulo u8 *resp = NULL;
2098f05cddf9SRui Paulo size_t resp_len = 0;
2099f05cddf9SRui Paulo #ifdef NEED_AP_MLME
2100e28a4053SRui Paulo u16 capab_info;
2101c1d255d3SCy Schubert u8 *pos, *tailpos, *tailend, *csa_pos;
2102*a90b9d01SCy Schubert bool complete = false;
2103*a90b9d01SCy Schubert #endif /* NEED_AP_MLME */
2104e28a4053SRui Paulo
2105*a90b9d01SCy Schubert os_memset(params, 0, sizeof(*params));
2106*a90b9d01SCy Schubert
2107*a90b9d01SCy Schubert #ifdef NEED_AP_MLME
2108e28a4053SRui Paulo #define BEACON_HEAD_BUF_SIZE 256
2109e28a4053SRui Paulo #define BEACON_TAIL_BUF_SIZE 512
2110e28a4053SRui Paulo head = os_zalloc(BEACON_HEAD_BUF_SIZE);
2111e28a4053SRui Paulo tail_len = BEACON_TAIL_BUF_SIZE;
2112e28a4053SRui Paulo #ifdef CONFIG_WPS
2113e28a4053SRui Paulo if (hapd->conf->wps_state && hapd->wps_beacon_ie)
2114e28a4053SRui Paulo tail_len += wpabuf_len(hapd->wps_beacon_ie);
2115e28a4053SRui Paulo #endif /* CONFIG_WPS */
2116f05cddf9SRui Paulo #ifdef CONFIG_P2P
2117f05cddf9SRui Paulo if (hapd->p2p_beacon_ie)
2118f05cddf9SRui Paulo tail_len += wpabuf_len(hapd->p2p_beacon_ie);
2119f05cddf9SRui Paulo #endif /* CONFIG_P2P */
2120325151a3SRui Paulo #ifdef CONFIG_FST
2121325151a3SRui Paulo if (hapd->iface->fst_ies)
2122325151a3SRui Paulo tail_len += wpabuf_len(hapd->iface->fst_ies);
2123325151a3SRui Paulo #endif /* CONFIG_FST */
2124f05cddf9SRui Paulo if (hapd->conf->vendor_elements)
2125f05cddf9SRui Paulo tail_len += wpabuf_len(hapd->conf->vendor_elements);
21265b9c547cSRui Paulo
21275b9c547cSRui Paulo #ifdef CONFIG_IEEE80211AC
21285b9c547cSRui Paulo if (hapd->conf->vendor_vht) {
21295b9c547cSRui Paulo tail_len += 5 + 2 + sizeof(struct ieee80211_vht_capabilities) +
21305b9c547cSRui Paulo 2 + sizeof(struct ieee80211_vht_operation);
21315b9c547cSRui Paulo }
21325b9c547cSRui Paulo #endif /* CONFIG_IEEE80211AC */
21335b9c547cSRui Paulo
2134*a90b9d01SCy Schubert tail_len += he_elem_len(hapd);
213585732ac8SCy Schubert
2136*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211BE
2137*a90b9d01SCy Schubert if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
2138*a90b9d01SCy Schubert tail_len += hostapd_eid_eht_capab_len(hapd, IEEE80211_MODE_AP);
2139*a90b9d01SCy Schubert tail_len += 3 + sizeof(struct ieee80211_eht_operation);
2140*a90b9d01SCy Schubert if (hapd->iconf->punct_bitmap)
2141*a90b9d01SCy Schubert tail_len += EHT_OPER_DISABLED_SUBCHAN_BITMAP_SIZE;
2142*a90b9d01SCy Schubert
2143*a90b9d01SCy Schubert /*
2144*a90b9d01SCy Schubert * TODO: Multi-Link element has variable length and can be
2145*a90b9d01SCy Schubert * long based on the common info and number of per
2146*a90b9d01SCy Schubert * station profiles. For now use 256.
2147*a90b9d01SCy Schubert */
2148*a90b9d01SCy Schubert if (hapd->conf->mld_ap)
2149*a90b9d01SCy Schubert tail_len += 256;
2150*a90b9d01SCy Schubert }
2151*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211BE */
2152*a90b9d01SCy Schubert
2153*a90b9d01SCy Schubert if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED &&
2154*a90b9d01SCy Schubert hapd == hostapd_mbssid_get_tx_bss(hapd))
2155*a90b9d01SCy Schubert tail_len += 5; /* Multiple BSSID Configuration element */
2156*a90b9d01SCy Schubert tail_len += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_BEACON, true);
2157780fb4a2SCy Schubert tail_len += hostapd_mbo_ie_len(hapd);
215885732ac8SCy Schubert tail_len += hostapd_eid_owe_trans_len(hapd);
2159c1d255d3SCy Schubert tail_len += hostapd_eid_dpp_cc_len(hapd);
2160780fb4a2SCy Schubert
2161e28a4053SRui Paulo tailpos = tail = os_malloc(tail_len);
2162e28a4053SRui Paulo if (head == NULL || tail == NULL) {
2163e28a4053SRui Paulo wpa_printf(MSG_ERROR, "Failed to set beacon data");
2164e28a4053SRui Paulo os_free(head);
2165e28a4053SRui Paulo os_free(tail);
21665b9c547cSRui Paulo return -1;
2167e28a4053SRui Paulo }
2168c1d255d3SCy Schubert tailend = tail + tail_len;
2169e28a4053SRui Paulo
2170e28a4053SRui Paulo head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
2171e28a4053SRui Paulo WLAN_FC_STYPE_BEACON);
2172e28a4053SRui Paulo head->duration = host_to_le16(0);
2173e28a4053SRui Paulo os_memset(head->da, 0xff, ETH_ALEN);
2174e28a4053SRui Paulo
2175e28a4053SRui Paulo os_memcpy(head->sa, hapd->own_addr, ETH_ALEN);
2176e28a4053SRui Paulo os_memcpy(head->bssid, hapd->own_addr, ETH_ALEN);
2177e28a4053SRui Paulo head->u.beacon.beacon_int =
2178e28a4053SRui Paulo host_to_le16(hapd->iconf->beacon_int);
2179e28a4053SRui Paulo
2180e28a4053SRui Paulo /* hardware or low-level driver will setup seq_ctrl and timestamp */
2181325151a3SRui Paulo capab_info = hostapd_own_capab_info(hapd);
2182e28a4053SRui Paulo head->u.beacon.capab_info = host_to_le16(capab_info);
2183e28a4053SRui Paulo pos = &head->u.beacon.variable[0];
2184e28a4053SRui Paulo
2185e28a4053SRui Paulo /* SSID */
2186e28a4053SRui Paulo *pos++ = WLAN_EID_SSID;
2187e28a4053SRui Paulo if (hapd->conf->ignore_broadcast_ssid == 2) {
2188e28a4053SRui Paulo /* clear the data, but keep the correct length of the SSID */
2189e28a4053SRui Paulo *pos++ = hapd->conf->ssid.ssid_len;
2190e28a4053SRui Paulo os_memset(pos, 0, hapd->conf->ssid.ssid_len);
2191e28a4053SRui Paulo pos += hapd->conf->ssid.ssid_len;
2192e28a4053SRui Paulo } else if (hapd->conf->ignore_broadcast_ssid) {
2193e28a4053SRui Paulo *pos++ = 0; /* empty SSID */
2194e28a4053SRui Paulo } else {
2195e28a4053SRui Paulo *pos++ = hapd->conf->ssid.ssid_len;
2196e28a4053SRui Paulo os_memcpy(pos, hapd->conf->ssid.ssid,
2197e28a4053SRui Paulo hapd->conf->ssid.ssid_len);
2198e28a4053SRui Paulo pos += hapd->conf->ssid.ssid_len;
2199e28a4053SRui Paulo }
2200e28a4053SRui Paulo
2201e28a4053SRui Paulo /* Supported rates */
2202e28a4053SRui Paulo pos = hostapd_eid_supp_rates(hapd, pos);
2203e28a4053SRui Paulo
2204e28a4053SRui Paulo /* DS Params */
2205e28a4053SRui Paulo pos = hostapd_eid_ds_params(hapd, pos);
2206e28a4053SRui Paulo
2207e28a4053SRui Paulo head_len = pos - (u8 *) head;
2208e28a4053SRui Paulo
2209c1d255d3SCy Schubert tailpos = hostapd_eid_country(hapd, tailpos, tailend - tailpos);
2210e28a4053SRui Paulo
22115b9c547cSRui Paulo /* Power Constraint element */
22125b9c547cSRui Paulo tailpos = hostapd_eid_pwr_constraint(hapd, tailpos);
22135b9c547cSRui Paulo
2214780fb4a2SCy Schubert /* CSA IE */
2215780fb4a2SCy Schubert csa_pos = hostapd_eid_csa(hapd, tailpos);
2216780fb4a2SCy Schubert if (csa_pos != tailpos)
2217780fb4a2SCy Schubert hapd->cs_c_off_beacon = csa_pos - tail - 1;
2218780fb4a2SCy Schubert tailpos = csa_pos;
2219780fb4a2SCy Schubert
2220e28a4053SRui Paulo /* ERP Information element */
2221e28a4053SRui Paulo tailpos = hostapd_eid_erp_info(hapd, tailpos);
2222e28a4053SRui Paulo
2223e28a4053SRui Paulo /* Extended supported rates */
2224e28a4053SRui Paulo tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos);
2225e28a4053SRui Paulo
2226c1d255d3SCy Schubert tailpos = hostapd_get_rsne(hapd, tailpos, tailend - tailpos);
2227c1d255d3SCy Schubert tailpos = hostapd_eid_bss_load(hapd, tailpos, tailend - tailpos);
22285b9c547cSRui Paulo tailpos = hostapd_eid_rm_enabled_capab(hapd, tailpos,
2229c1d255d3SCy Schubert tailend - tailpos);
2230c1d255d3SCy Schubert tailpos = hostapd_get_mde(hapd, tailpos, tailend - tailpos);
22315b9c547cSRui Paulo
2232780fb4a2SCy Schubert /* eCSA IE */
2233780fb4a2SCy Schubert csa_pos = hostapd_eid_ecsa(hapd, tailpos);
2234780fb4a2SCy Schubert if (csa_pos != tailpos)
2235780fb4a2SCy Schubert hapd->cs_c_off_ecsa_beacon = csa_pos - tail - 1;
2236780fb4a2SCy Schubert tailpos = csa_pos;
2237780fb4a2SCy Schubert
2238780fb4a2SCy Schubert tailpos = hostapd_eid_supported_op_classes(hapd, tailpos);
2239e28a4053SRui Paulo tailpos = hostapd_eid_ht_capabilities(hapd, tailpos);
2240e28a4053SRui Paulo tailpos = hostapd_eid_ht_operation(hapd, tailpos);
2241e28a4053SRui Paulo
2242*a90b9d01SCy Schubert if (hapd->iconf->mbssid && hapd->iconf->num_bss > 1) {
2243*a90b9d01SCy Schubert if (ieee802_11_build_ap_params_mbssid(hapd, params)) {
2244*a90b9d01SCy Schubert os_free(head);
2245*a90b9d01SCy Schubert os_free(tail);
2246*a90b9d01SCy Schubert wpa_printf(MSG_ERROR,
2247*a90b9d01SCy Schubert "MBSSID: Failed to set beacon data");
2248*a90b9d01SCy Schubert return -1;
2249*a90b9d01SCy Schubert }
2250*a90b9d01SCy Schubert complete = hapd->iconf->mbssid == MBSSID_ENABLED ||
2251*a90b9d01SCy Schubert (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED &&
2252*a90b9d01SCy Schubert params->mbssid_elem_count == 1);
2253*a90b9d01SCy Schubert }
2254*a90b9d01SCy Schubert
2255*a90b9d01SCy Schubert tailpos = hostapd_eid_ext_capab(hapd, tailpos, complete);
2256f05cddf9SRui Paulo
2257f05cddf9SRui Paulo /*
2258f05cddf9SRui Paulo * TODO: Time Advertisement element should only be included in some
2259f05cddf9SRui Paulo * DTIM Beacon frames.
2260f05cddf9SRui Paulo */
2261f05cddf9SRui Paulo tailpos = hostapd_eid_time_adv(hapd, tailpos);
2262f05cddf9SRui Paulo
2263f05cddf9SRui Paulo tailpos = hostapd_eid_interworking(hapd, tailpos);
2264f05cddf9SRui Paulo tailpos = hostapd_eid_adv_proto(hapd, tailpos);
2265f05cddf9SRui Paulo tailpos = hostapd_eid_roaming_consortium(hapd, tailpos);
2266325151a3SRui Paulo
2267325151a3SRui Paulo #ifdef CONFIG_FST
2268325151a3SRui Paulo if (hapd->iface->fst_ies) {
2269325151a3SRui Paulo os_memcpy(tailpos, wpabuf_head(hapd->iface->fst_ies),
2270325151a3SRui Paulo wpabuf_len(hapd->iface->fst_ies));
2271325151a3SRui Paulo tailpos += wpabuf_len(hapd->iface->fst_ies);
2272325151a3SRui Paulo }
2273325151a3SRui Paulo #endif /* CONFIG_FST */
2274325151a3SRui Paulo
2275f05cddf9SRui Paulo #ifdef CONFIG_IEEE80211AC
2276c1d255d3SCy Schubert if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac &&
2277c1d255d3SCy Schubert !is_6ghz_op_class(hapd->iconf->op_class)) {
2278780fb4a2SCy Schubert tailpos = hostapd_eid_vht_capabilities(hapd, tailpos, 0);
2279f05cddf9SRui Paulo tailpos = hostapd_eid_vht_operation(hapd, tailpos);
2280780fb4a2SCy Schubert tailpos = hostapd_eid_txpower_envelope(hapd, tailpos);
22815b9c547cSRui Paulo }
228285732ac8SCy Schubert #endif /* CONFIG_IEEE80211AC */
228385732ac8SCy Schubert
2284c1d255d3SCy Schubert #ifdef CONFIG_IEEE80211AX
2285c1d255d3SCy Schubert if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax &&
2286c1d255d3SCy Schubert is_6ghz_op_class(hapd->iconf->op_class))
2287c1d255d3SCy Schubert tailpos = hostapd_eid_txpower_envelope(hapd, tailpos);
2288c1d255d3SCy Schubert #endif /* CONFIG_IEEE80211AX */
2289c1d255d3SCy Schubert
2290c1d255d3SCy Schubert tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos);
2291c1d255d3SCy Schubert
2292*a90b9d01SCy Schubert tailpos = hostapd_eid_rnr(hapd, tailpos, WLAN_FC_STYPE_BEACON, true);
229385732ac8SCy Schubert tailpos = hostapd_eid_fils_indic(hapd, tailpos, 0);
2294c1d255d3SCy Schubert tailpos = hostapd_get_rsnxe(hapd, tailpos, tailend - tailpos);
2295*a90b9d01SCy Schubert tailpos = hostapd_eid_mbssid_config(hapd, tailpos,
2296*a90b9d01SCy Schubert params->mbssid_elem_count);
229785732ac8SCy Schubert
229885732ac8SCy Schubert #ifdef CONFIG_IEEE80211AX
2299c1d255d3SCy Schubert if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
2300*a90b9d01SCy Schubert u8 *cca_pos;
2301*a90b9d01SCy Schubert
2302206b73d0SCy Schubert tailpos = hostapd_eid_he_capab(hapd, tailpos,
2303206b73d0SCy Schubert IEEE80211_MODE_AP);
230485732ac8SCy Schubert tailpos = hostapd_eid_he_operation(hapd, tailpos);
2305*a90b9d01SCy Schubert
2306*a90b9d01SCy Schubert /* BSS Color Change Announcement element */
2307*a90b9d01SCy Schubert cca_pos = hostapd_eid_cca(hapd, tailpos);
2308*a90b9d01SCy Schubert if (cca_pos != tailpos)
2309*a90b9d01SCy Schubert hapd->cca_c_off_beacon = cca_pos - tail - 2;
2310*a90b9d01SCy Schubert tailpos = cca_pos;
2311*a90b9d01SCy Schubert
2312206b73d0SCy Schubert tailpos = hostapd_eid_spatial_reuse(hapd, tailpos);
2313c1d255d3SCy Schubert tailpos = hostapd_eid_he_mu_edca_parameter_set(hapd, tailpos);
2314c1d255d3SCy Schubert tailpos = hostapd_eid_he_6ghz_band_cap(hapd, tailpos);
231585732ac8SCy Schubert }
231685732ac8SCy Schubert #endif /* CONFIG_IEEE80211AX */
231785732ac8SCy Schubert
2318*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211BE
2319*a90b9d01SCy Schubert if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
2320*a90b9d01SCy Schubert if (hapd->conf->mld_ap)
2321*a90b9d01SCy Schubert tailpos = hostapd_eid_eht_ml_beacon(hapd, NULL,
2322*a90b9d01SCy Schubert tailpos, false);
2323*a90b9d01SCy Schubert tailpos = hostapd_eid_eht_capab(hapd, tailpos,
2324*a90b9d01SCy Schubert IEEE80211_MODE_AP);
2325*a90b9d01SCy Schubert tailpos = hostapd_eid_eht_operation(hapd, tailpos);
2326*a90b9d01SCy Schubert }
2327*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211BE */
2328*a90b9d01SCy Schubert
232985732ac8SCy Schubert #ifdef CONFIG_IEEE80211AC
23305b9c547cSRui Paulo if (hapd->conf->vendor_vht)
23315b9c547cSRui Paulo tailpos = hostapd_eid_vendor_vht(hapd, tailpos);
2332f05cddf9SRui Paulo #endif /* CONFIG_IEEE80211AC */
2333f05cddf9SRui Paulo
2334c1d255d3SCy Schubert /* WPA / OSEN */
2335c1d255d3SCy Schubert tailpos = hostapd_get_wpa_ie(hapd, tailpos, tailend - tailpos);
2336c1d255d3SCy Schubert tailpos = hostapd_get_osen_ie(hapd, tailpos, tailend - tailpos);
233785732ac8SCy Schubert
2338e28a4053SRui Paulo /* Wi-Fi Alliance WMM */
2339e28a4053SRui Paulo tailpos = hostapd_eid_wmm(hapd, tailpos);
2340e28a4053SRui Paulo
2341e28a4053SRui Paulo #ifdef CONFIG_WPS
2342e28a4053SRui Paulo if (hapd->conf->wps_state && hapd->wps_beacon_ie) {
2343e28a4053SRui Paulo os_memcpy(tailpos, wpabuf_head(hapd->wps_beacon_ie),
2344e28a4053SRui Paulo wpabuf_len(hapd->wps_beacon_ie));
2345e28a4053SRui Paulo tailpos += wpabuf_len(hapd->wps_beacon_ie);
2346e28a4053SRui Paulo }
2347e28a4053SRui Paulo #endif /* CONFIG_WPS */
2348e28a4053SRui Paulo
2349f05cddf9SRui Paulo #ifdef CONFIG_P2P
2350f05cddf9SRui Paulo if ((hapd->conf->p2p & P2P_ENABLED) && hapd->p2p_beacon_ie) {
2351f05cddf9SRui Paulo os_memcpy(tailpos, wpabuf_head(hapd->p2p_beacon_ie),
2352f05cddf9SRui Paulo wpabuf_len(hapd->p2p_beacon_ie));
2353f05cddf9SRui Paulo tailpos += wpabuf_len(hapd->p2p_beacon_ie);
2354f05cddf9SRui Paulo }
2355f05cddf9SRui Paulo #endif /* CONFIG_P2P */
2356f05cddf9SRui Paulo #ifdef CONFIG_P2P_MANAGER
2357f05cddf9SRui Paulo if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) ==
2358f05cddf9SRui Paulo P2P_MANAGE)
2359f05cddf9SRui Paulo tailpos = hostapd_eid_p2p_manage(hapd, tailpos);
2360f05cddf9SRui Paulo #endif /* CONFIG_P2P_MANAGER */
2361f05cddf9SRui Paulo
2362f05cddf9SRui Paulo #ifdef CONFIG_HS20
2363f05cddf9SRui Paulo tailpos = hostapd_eid_hs20_indication(hapd, tailpos);
2364f05cddf9SRui Paulo #endif /* CONFIG_HS20 */
2365f05cddf9SRui Paulo
2366780fb4a2SCy Schubert tailpos = hostapd_eid_mbo(hapd, tailpos, tail + tail_len - tailpos);
236785732ac8SCy Schubert tailpos = hostapd_eid_owe_trans(hapd, tailpos,
236885732ac8SCy Schubert tail + tail_len - tailpos);
2369c1d255d3SCy Schubert tailpos = hostapd_eid_dpp_cc(hapd, tailpos, tail + tail_len - tailpos);
2370780fb4a2SCy Schubert
2371f05cddf9SRui Paulo if (hapd->conf->vendor_elements) {
2372f05cddf9SRui Paulo os_memcpy(tailpos, wpabuf_head(hapd->conf->vendor_elements),
2373f05cddf9SRui Paulo wpabuf_len(hapd->conf->vendor_elements));
2374f05cddf9SRui Paulo tailpos += wpabuf_len(hapd->conf->vendor_elements);
2375f05cddf9SRui Paulo }
2376f05cddf9SRui Paulo
2377e28a4053SRui Paulo tail_len = tailpos > tail ? tailpos - tail : 0;
2378e28a4053SRui Paulo
2379f05cddf9SRui Paulo resp = hostapd_probe_resp_offloads(hapd, &resp_len);
2380f05cddf9SRui Paulo #endif /* NEED_AP_MLME */
2381f05cddf9SRui Paulo
2382*a90b9d01SCy Schubert /* If key management offload is enabled, configure PSK to the driver. */
2383*a90b9d01SCy Schubert if (wpa_key_mgmt_wpa_psk_no_sae(hapd->conf->wpa_key_mgmt) &&
2384*a90b9d01SCy Schubert (hapd->iface->drv_flags2 &
2385*a90b9d01SCy Schubert WPA_DRIVER_FLAGS2_4WAY_HANDSHAKE_AP_PSK)) {
2386*a90b9d01SCy Schubert if (hapd->conf->ssid.wpa_psk && hapd->conf->ssid.wpa_psk_set) {
2387*a90b9d01SCy Schubert os_memcpy(params->psk, hapd->conf->ssid.wpa_psk->psk,
2388*a90b9d01SCy Schubert PMK_LEN);
2389*a90b9d01SCy Schubert params->psk_len = PMK_LEN;
2390*a90b9d01SCy Schubert } else if (hapd->conf->ssid.wpa_passphrase &&
2391*a90b9d01SCy Schubert pbkdf2_sha1(hapd->conf->ssid.wpa_passphrase,
2392*a90b9d01SCy Schubert hapd->conf->ssid.ssid,
2393*a90b9d01SCy Schubert hapd->conf->ssid.ssid_len, 4096,
2394*a90b9d01SCy Schubert params->psk, PMK_LEN) == 0) {
2395*a90b9d01SCy Schubert params->psk_len = PMK_LEN;
2396*a90b9d01SCy Schubert }
2397*a90b9d01SCy Schubert }
2398*a90b9d01SCy Schubert
2399*a90b9d01SCy Schubert #ifdef CONFIG_SAE
2400*a90b9d01SCy Schubert /* If SAE offload is enabled, provide password to lower layer for
2401*a90b9d01SCy Schubert * SAE authentication and PMK generation.
2402*a90b9d01SCy Schubert */
2403*a90b9d01SCy Schubert if (wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
2404*a90b9d01SCy Schubert (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP)) {
2405*a90b9d01SCy Schubert if (hostapd_sae_pk_in_use(hapd->conf)) {
2406*a90b9d01SCy Schubert wpa_printf(MSG_ERROR,
2407*a90b9d01SCy Schubert "SAE PK not supported with SAE offload");
2408*a90b9d01SCy Schubert return -1;
2409*a90b9d01SCy Schubert }
2410*a90b9d01SCy Schubert
2411*a90b9d01SCy Schubert if (hostapd_sae_pw_id_in_use(hapd->conf)) {
2412*a90b9d01SCy Schubert wpa_printf(MSG_ERROR,
2413*a90b9d01SCy Schubert "SAE Password Identifiers not supported with SAE offload");
2414*a90b9d01SCy Schubert return -1;
2415*a90b9d01SCy Schubert }
2416*a90b9d01SCy Schubert
2417*a90b9d01SCy Schubert params->sae_password = sae_get_password(hapd, NULL, NULL, NULL,
2418*a90b9d01SCy Schubert NULL, NULL);
2419*a90b9d01SCy Schubert if (!params->sae_password) {
2420*a90b9d01SCy Schubert wpa_printf(MSG_ERROR, "SAE password not configured for offload");
2421*a90b9d01SCy Schubert return -1;
2422*a90b9d01SCy Schubert }
2423*a90b9d01SCy Schubert }
2424*a90b9d01SCy Schubert #endif /* CONFIG_SAE */
2425*a90b9d01SCy Schubert
24265b9c547cSRui Paulo params->head = (u8 *) head;
24275b9c547cSRui Paulo params->head_len = head_len;
24285b9c547cSRui Paulo params->tail = tail;
24295b9c547cSRui Paulo params->tail_len = tail_len;
24305b9c547cSRui Paulo params->proberesp = resp;
24315b9c547cSRui Paulo params->proberesp_len = resp_len;
24325b9c547cSRui Paulo params->dtim_period = hapd->conf->dtim_period;
24335b9c547cSRui Paulo params->beacon_int = hapd->iconf->beacon_int;
24345b9c547cSRui Paulo params->basic_rates = hapd->iface->basic_rates;
243585732ac8SCy Schubert params->beacon_rate = hapd->iconf->beacon_rate;
243685732ac8SCy Schubert params->rate_type = hapd->iconf->rate_type;
24375b9c547cSRui Paulo params->ssid = hapd->conf->ssid.ssid;
24385b9c547cSRui Paulo params->ssid_len = hapd->conf->ssid.ssid_len;
2439325151a3SRui Paulo if ((hapd->conf->wpa & (WPA_PROTO_WPA | WPA_PROTO_RSN)) ==
2440325151a3SRui Paulo (WPA_PROTO_WPA | WPA_PROTO_RSN))
24415b9c547cSRui Paulo params->pairwise_ciphers = hapd->conf->wpa_pairwise |
24425b9c547cSRui Paulo hapd->conf->rsn_pairwise;
2443325151a3SRui Paulo else if (hapd->conf->wpa & WPA_PROTO_RSN)
2444325151a3SRui Paulo params->pairwise_ciphers = hapd->conf->rsn_pairwise;
2445325151a3SRui Paulo else if (hapd->conf->wpa & WPA_PROTO_WPA)
2446325151a3SRui Paulo params->pairwise_ciphers = hapd->conf->wpa_pairwise;
24475b9c547cSRui Paulo params->group_cipher = hapd->conf->wpa_group;
24485b9c547cSRui Paulo params->key_mgmt_suites = hapd->conf->wpa_key_mgmt;
24495b9c547cSRui Paulo params->auth_algs = hapd->conf->auth_algs;
24505b9c547cSRui Paulo params->wpa_version = hapd->conf->wpa;
2451c1d255d3SCy Schubert params->privacy = hapd->conf->wpa;
2452c1d255d3SCy Schubert #ifdef CONFIG_WEP
2453c1d255d3SCy Schubert params->privacy |= hapd->conf->ssid.wep.keys_set ||
2454f05cddf9SRui Paulo (hapd->conf->ieee802_1x &&
2455f05cddf9SRui Paulo (hapd->conf->default_wep_key_len ||
2456f05cddf9SRui Paulo hapd->conf->individual_wep_key_len));
2457c1d255d3SCy Schubert #endif /* CONFIG_WEP */
2458f05cddf9SRui Paulo switch (hapd->conf->ignore_broadcast_ssid) {
2459f05cddf9SRui Paulo case 0:
24605b9c547cSRui Paulo params->hide_ssid = NO_SSID_HIDING;
2461f05cddf9SRui Paulo break;
2462f05cddf9SRui Paulo case 1:
24635b9c547cSRui Paulo params->hide_ssid = HIDDEN_SSID_ZERO_LEN;
2464f05cddf9SRui Paulo break;
2465f05cddf9SRui Paulo case 2:
24665b9c547cSRui Paulo params->hide_ssid = HIDDEN_SSID_ZERO_CONTENTS;
2467f05cddf9SRui Paulo break;
2468f05cddf9SRui Paulo }
24695b9c547cSRui Paulo params->isolate = hapd->conf->isolate;
2470f05cddf9SRui Paulo #ifdef NEED_AP_MLME
24715b9c547cSRui Paulo params->cts_protect = !!(ieee802_11_erp_info(hapd) &
2472f05cddf9SRui Paulo ERP_INFO_USE_PROTECTION);
24735b9c547cSRui Paulo params->preamble = hapd->iface->num_sta_no_short_preamble == 0 &&
2474f05cddf9SRui Paulo hapd->iconf->preamble == SHORT_PREAMBLE;
2475f05cddf9SRui Paulo if (hapd->iface->current_mode &&
2476f05cddf9SRui Paulo hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
24775b9c547cSRui Paulo params->short_slot_time =
2478f05cddf9SRui Paulo hapd->iface->num_sta_no_short_slot_time > 0 ? 0 : 1;
2479f05cddf9SRui Paulo else
24805b9c547cSRui Paulo params->short_slot_time = -1;
2481f05cddf9SRui Paulo if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n)
24825b9c547cSRui Paulo params->ht_opmode = -1;
2483f05cddf9SRui Paulo else
24845b9c547cSRui Paulo params->ht_opmode = hapd->iface->ht_op_mode;
2485f05cddf9SRui Paulo #endif /* NEED_AP_MLME */
24865b9c547cSRui Paulo params->interworking = hapd->conf->interworking;
2487f05cddf9SRui Paulo if (hapd->conf->interworking &&
2488f05cddf9SRui Paulo !is_zero_ether_addr(hapd->conf->hessid))
24895b9c547cSRui Paulo params->hessid = hapd->conf->hessid;
24905b9c547cSRui Paulo params->access_network_type = hapd->conf->access_network_type;
24915b9c547cSRui Paulo params->ap_max_inactivity = hapd->conf->ap_max_inactivity;
24925b9c547cSRui Paulo #ifdef CONFIG_P2P
24935b9c547cSRui Paulo params->p2p_go_ctwindow = hapd->iconf->p2p_go_ctwindow;
24945b9c547cSRui Paulo #endif /* CONFIG_P2P */
2495f05cddf9SRui Paulo #ifdef CONFIG_HS20
24965b9c547cSRui Paulo params->disable_dgaf = hapd->conf->disable_dgaf;
24975b9c547cSRui Paulo if (hapd->conf->osen) {
24985b9c547cSRui Paulo params->privacy = 1;
24995b9c547cSRui Paulo params->osen = 1;
25005b9c547cSRui Paulo }
2501f05cddf9SRui Paulo #endif /* CONFIG_HS20 */
250285732ac8SCy Schubert params->multicast_to_unicast = hapd->conf->multicast_to_unicast;
2503780fb4a2SCy Schubert params->pbss = hapd->conf->pbss;
25044bc52338SCy Schubert
25054bc52338SCy Schubert if (hapd->conf->ftm_responder) {
25064bc52338SCy Schubert if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_FTM_RESPONDER) {
25074bc52338SCy Schubert params->ftm_responder = 1;
25084bc52338SCy Schubert params->lci = hapd->iface->conf->lci;
25094bc52338SCy Schubert params->civic = hapd->iface->conf->civic;
25104bc52338SCy Schubert } else {
25114bc52338SCy Schubert wpa_printf(MSG_WARNING,
25124bc52338SCy Schubert "Not configuring FTM responder as the driver doesn't advertise support for it");
25134bc52338SCy Schubert }
25144bc52338SCy Schubert }
25154bc52338SCy Schubert
2516*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211BE
2517*a90b9d01SCy Schubert if (hapd->conf->mld_ap && hapd->iconf->ieee80211be &&
2518*a90b9d01SCy Schubert !hapd->conf->disable_11be) {
2519*a90b9d01SCy Schubert params->mld_ap = true;
2520*a90b9d01SCy Schubert params->mld_link_id = hapd->mld_link_id;
2521*a90b9d01SCy Schubert }
2522*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211BE */
2523*a90b9d01SCy Schubert
25245b9c547cSRui Paulo return 0;
2525e28a4053SRui Paulo }
2526e28a4053SRui Paulo
2527e28a4053SRui Paulo
ieee802_11_free_ap_params(struct wpa_driver_ap_params * params)25285b9c547cSRui Paulo void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params)
25295b9c547cSRui Paulo {
25305b9c547cSRui Paulo os_free(params->tail);
25315b9c547cSRui Paulo params->tail = NULL;
25325b9c547cSRui Paulo os_free(params->head);
25335b9c547cSRui Paulo params->head = NULL;
25345b9c547cSRui Paulo os_free(params->proberesp);
25355b9c547cSRui Paulo params->proberesp = NULL;
2536*a90b9d01SCy Schubert os_free(params->mbssid_elem);
2537*a90b9d01SCy Schubert params->mbssid_elem = NULL;
2538*a90b9d01SCy Schubert os_free(params->mbssid_elem_offset);
2539*a90b9d01SCy Schubert params->mbssid_elem_offset = NULL;
2540*a90b9d01SCy Schubert os_free(params->rnr_elem);
2541*a90b9d01SCy Schubert params->rnr_elem = NULL;
2542*a90b9d01SCy Schubert os_free(params->rnr_elem_offset);
2543*a90b9d01SCy Schubert params->rnr_elem_offset = NULL;
2544c1d255d3SCy Schubert #ifdef CONFIG_FILS
2545c1d255d3SCy Schubert os_free(params->fd_frame_tmpl);
2546c1d255d3SCy Schubert params->fd_frame_tmpl = NULL;
2547c1d255d3SCy Schubert #endif /* CONFIG_FILS */
2548c1d255d3SCy Schubert #ifdef CONFIG_IEEE80211AX
2549*a90b9d01SCy Schubert os_free(params->ubpr.unsol_bcast_probe_resp_tmpl);
2550*a90b9d01SCy Schubert params->ubpr.unsol_bcast_probe_resp_tmpl = NULL;
2551c1d255d3SCy Schubert #endif /* CONFIG_IEEE80211AX */
2552*a90b9d01SCy Schubert os_free(params->allowed_freqs);
2553*a90b9d01SCy Schubert params->allowed_freqs = NULL;
25545b9c547cSRui Paulo }
25555b9c547cSRui Paulo
25565b9c547cSRui Paulo
__ieee802_11_set_beacon(struct hostapd_data * hapd)25574b72b91aSCy Schubert static int __ieee802_11_set_beacon(struct hostapd_data *hapd)
25585b9c547cSRui Paulo {
25595b9c547cSRui Paulo struct wpa_driver_ap_params params;
25605b9c547cSRui Paulo struct hostapd_freq_params freq;
25615b9c547cSRui Paulo struct hostapd_iface *iface = hapd->iface;
25625b9c547cSRui Paulo struct hostapd_config *iconf = iface->conf;
2563206b73d0SCy Schubert struct hostapd_hw_modes *cmode = iface->current_mode;
25645b9c547cSRui Paulo struct wpabuf *beacon, *proberesp, *assocresp;
2565*a90b9d01SCy Schubert bool twt_he_responder = false;
2566*a90b9d01SCy Schubert int res, ret = -1, i;
2567*a90b9d01SCy Schubert struct hostapd_hw_modes *mode;
25685b9c547cSRui Paulo
2569c1d255d3SCy Schubert if (!hapd->drv_priv) {
2570c1d255d3SCy Schubert wpa_printf(MSG_ERROR, "Interface is disabled");
2571c1d255d3SCy Schubert return -1;
2572c1d255d3SCy Schubert }
2573c1d255d3SCy Schubert
25745b9c547cSRui Paulo if (hapd->csa_in_progress) {
25755b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Cannot set beacons during CSA period");
25765b9c547cSRui Paulo return -1;
25775b9c547cSRui Paulo }
25785b9c547cSRui Paulo
25795b9c547cSRui Paulo hapd->beacon_set_done = 1;
25805b9c547cSRui Paulo
25815b9c547cSRui Paulo if (ieee802_11_build_ap_params(hapd, ¶ms) < 0)
25825b9c547cSRui Paulo return -1;
25835b9c547cSRui Paulo
25845b9c547cSRui Paulo if (hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp) <
25855b9c547cSRui Paulo 0)
25865b9c547cSRui Paulo goto fail;
25875b9c547cSRui Paulo
25885b9c547cSRui Paulo params.beacon_ies = beacon;
25895b9c547cSRui Paulo params.proberesp_ies = proberesp;
25905b9c547cSRui Paulo params.assocresp_ies = assocresp;
25915b9c547cSRui Paulo params.reenable = hapd->reenable_beacon;
2592c1d255d3SCy Schubert #ifdef CONFIG_IEEE80211AX
2593c1d255d3SCy Schubert params.he_spr_ctrl = hapd->iface->conf->spr.sr_control;
2594c1d255d3SCy Schubert params.he_spr_non_srg_obss_pd_max_offset =
2595c1d255d3SCy Schubert hapd->iface->conf->spr.non_srg_obss_pd_max_offset;
2596c1d255d3SCy Schubert params.he_spr_srg_obss_pd_min_offset =
2597c1d255d3SCy Schubert hapd->iface->conf->spr.srg_obss_pd_min_offset;
2598c1d255d3SCy Schubert params.he_spr_srg_obss_pd_max_offset =
2599c1d255d3SCy Schubert hapd->iface->conf->spr.srg_obss_pd_max_offset;
2600c1d255d3SCy Schubert os_memcpy(params.he_spr_bss_color_bitmap,
2601c1d255d3SCy Schubert hapd->iface->conf->spr.srg_bss_color_bitmap, 8);
2602c1d255d3SCy Schubert os_memcpy(params.he_spr_partial_bssid_bitmap,
2603c1d255d3SCy Schubert hapd->iface->conf->spr.srg_partial_bssid_bitmap, 8);
2604c1d255d3SCy Schubert params.he_bss_color_disabled =
2605c1d255d3SCy Schubert hapd->iface->conf->he_op.he_bss_color_disabled;
2606c1d255d3SCy Schubert params.he_bss_color_partial =
2607c1d255d3SCy Schubert hapd->iface->conf->he_op.he_bss_color_partial;
2608c1d255d3SCy Schubert params.he_bss_color = hapd->iface->conf->he_op.he_bss_color;
2609*a90b9d01SCy Schubert twt_he_responder = hostapd_get_he_twt_responder(hapd,
2610c1d255d3SCy Schubert IEEE80211_MODE_AP);
2611*a90b9d01SCy Schubert params.ubpr.unsol_bcast_probe_resp_tmpl =
2612*a90b9d01SCy Schubert hostapd_unsol_bcast_probe_resp(hapd, ¶ms.ubpr);
2613c1d255d3SCy Schubert #endif /* CONFIG_IEEE80211AX */
2614*a90b9d01SCy Schubert params.twt_responder =
2615*a90b9d01SCy Schubert twt_he_responder || hostapd_get_ht_vht_twt_responder(hapd);
26165b9c547cSRui Paulo hapd->reenable_beacon = 0;
2617c1d255d3SCy Schubert #ifdef CONFIG_SAE
2618c1d255d3SCy Schubert params.sae_pwe = hapd->conf->sae_pwe;
2619c1d255d3SCy Schubert #endif /* CONFIG_SAE */
2620c1d255d3SCy Schubert
2621c1d255d3SCy Schubert #ifdef CONFIG_FILS
2622c1d255d3SCy Schubert params.fd_frame_tmpl = hostapd_fils_discovery(hapd, ¶ms);
2623c1d255d3SCy Schubert #endif /* CONFIG_FILS */
26245b9c547cSRui Paulo
2625*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211BE
2626*a90b9d01SCy Schubert params.punct_bitmap = iconf->punct_bitmap;
2627*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211BE */
2628*a90b9d01SCy Schubert
2629206b73d0SCy Schubert if (cmode &&
26305b9c547cSRui Paulo hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq,
2631c1d255d3SCy Schubert iconf->channel, iconf->enable_edmg,
2632c1d255d3SCy Schubert iconf->edmg_channel, iconf->ieee80211n,
2633206b73d0SCy Schubert iconf->ieee80211ac, iconf->ieee80211ax,
2634*a90b9d01SCy Schubert iconf->ieee80211be,
26355b9c547cSRui Paulo iconf->secondary_channel,
2636206b73d0SCy Schubert hostapd_get_oper_chwidth(iconf),
2637206b73d0SCy Schubert hostapd_get_oper_centr_freq_seg0_idx(iconf),
2638206b73d0SCy Schubert hostapd_get_oper_centr_freq_seg1_idx(iconf),
2639206b73d0SCy Schubert cmode->vht_capab,
2640*a90b9d01SCy Schubert &cmode->he_capab[IEEE80211_MODE_AP],
2641*a90b9d01SCy Schubert &cmode->eht_capab[IEEE80211_MODE_AP],
2642*a90b9d01SCy Schubert hostapd_get_punct_bitmap(hapd)) == 0) {
2643*a90b9d01SCy Schubert freq.link_id = -1;
2644*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211BE
2645*a90b9d01SCy Schubert if (hapd->conf->mld_ap)
2646*a90b9d01SCy Schubert freq.link_id = hapd->mld_link_id;
2647*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211BE */
26485b9c547cSRui Paulo params.freq = &freq;
2649*a90b9d01SCy Schubert }
2650*a90b9d01SCy Schubert
2651*a90b9d01SCy Schubert for (i = 0; i < hapd->iface->num_hw_features; i++) {
2652*a90b9d01SCy Schubert mode = &hapd->iface->hw_features[i];
2653*a90b9d01SCy Schubert
2654*a90b9d01SCy Schubert if (iconf->hw_mode != HOSTAPD_MODE_IEEE80211ANY &&
2655*a90b9d01SCy Schubert iconf->hw_mode != mode->mode)
2656*a90b9d01SCy Schubert continue;
2657*a90b9d01SCy Schubert
2658*a90b9d01SCy Schubert hostapd_get_hw_mode_any_channels(hapd, mode,
2659*a90b9d01SCy Schubert !(iconf->acs_freq_list.num ||
2660*a90b9d01SCy Schubert iconf->acs_ch_list.num),
2661*a90b9d01SCy Schubert true, ¶ms.allowed_freqs);
2662*a90b9d01SCy Schubert }
26635b9c547cSRui Paulo
26645b9c547cSRui Paulo res = hostapd_drv_set_ap(hapd, ¶ms);
26655b9c547cSRui Paulo hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
26665b9c547cSRui Paulo if (res)
26675b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Failed to set beacon parameters");
26685b9c547cSRui Paulo else
26695b9c547cSRui Paulo ret = 0;
26705b9c547cSRui Paulo fail:
26715b9c547cSRui Paulo ieee802_11_free_ap_params(¶ms);
26725b9c547cSRui Paulo return ret;
26735b9c547cSRui Paulo }
26745b9c547cSRui Paulo
26755b9c547cSRui Paulo
ieee802_11_set_beacon_per_bss_only(struct hostapd_data * hapd)2676*a90b9d01SCy Schubert void ieee802_11_set_beacon_per_bss_only(struct hostapd_data *hapd)
2677*a90b9d01SCy Schubert {
2678*a90b9d01SCy Schubert __ieee802_11_set_beacon(hapd);
2679*a90b9d01SCy Schubert }
2680*a90b9d01SCy Schubert
2681*a90b9d01SCy Schubert
ieee802_11_set_beacon(struct hostapd_data * hapd)26824b72b91aSCy Schubert int ieee802_11_set_beacon(struct hostapd_data *hapd)
26834b72b91aSCy Schubert {
26844b72b91aSCy Schubert struct hostapd_iface *iface = hapd->iface;
26854b72b91aSCy Schubert int ret;
26864b72b91aSCy Schubert size_t i, j;
2687*a90b9d01SCy Schubert bool is_6g, hapd_mld = false;
26884b72b91aSCy Schubert
26894b72b91aSCy Schubert ret = __ieee802_11_set_beacon(hapd);
26904b72b91aSCy Schubert if (ret != 0)
26914b72b91aSCy Schubert return ret;
26924b72b91aSCy Schubert
26934b72b91aSCy Schubert if (!iface->interfaces || iface->interfaces->count <= 1)
26944b72b91aSCy Schubert return 0;
26954b72b91aSCy Schubert
2696*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211BE
2697*a90b9d01SCy Schubert hapd_mld = hapd->conf->mld_ap;
2698*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211BE */
2699*a90b9d01SCy Schubert
2700*a90b9d01SCy Schubert /* Update Beacon frames in case of 6 GHz colocation or AP MLD */
27014b72b91aSCy Schubert is_6g = is_6ghz_op_class(iface->conf->op_class);
27024b72b91aSCy Schubert for (j = 0; j < iface->interfaces->count; j++) {
2703*a90b9d01SCy Schubert struct hostapd_iface *other;
2704*a90b9d01SCy Schubert bool other_iface_6g;
27054b72b91aSCy Schubert
2706*a90b9d01SCy Schubert other = iface->interfaces->iface[j];
2707*a90b9d01SCy Schubert if (other == iface || !other || !other->conf)
27084b72b91aSCy Schubert continue;
27094b72b91aSCy Schubert
2710*a90b9d01SCy Schubert other_iface_6g = is_6ghz_op_class(other->conf->op_class);
2711*a90b9d01SCy Schubert
2712*a90b9d01SCy Schubert if (is_6g == other_iface_6g && !hapd_mld)
27134b72b91aSCy Schubert continue;
27144b72b91aSCy Schubert
2715*a90b9d01SCy Schubert for (i = 0; i < other->num_bss; i++) {
2716*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211BE
2717*a90b9d01SCy Schubert if (is_6g == other_iface_6g &&
2718*a90b9d01SCy Schubert !(hapd_mld && other->bss[i]->conf->mld_ap &&
2719*a90b9d01SCy Schubert hostapd_is_ml_partner(hapd, other->bss[i])))
2720*a90b9d01SCy Schubert continue;
2721*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211BE */
2722*a90b9d01SCy Schubert
2723*a90b9d01SCy Schubert if (other->bss[i] && other->bss[i]->started)
2724*a90b9d01SCy Schubert __ieee802_11_set_beacon(other->bss[i]);
27254b72b91aSCy Schubert }
27264b72b91aSCy Schubert }
27274b72b91aSCy Schubert
27284b72b91aSCy Schubert return 0;
27294b72b91aSCy Schubert }
27304b72b91aSCy Schubert
27314b72b91aSCy Schubert
ieee802_11_set_beacons(struct hostapd_iface * iface)27325b9c547cSRui Paulo int ieee802_11_set_beacons(struct hostapd_iface *iface)
2733e28a4053SRui Paulo {
2734e28a4053SRui Paulo size_t i;
27355b9c547cSRui Paulo int ret = 0;
27365b9c547cSRui Paulo
27375b9c547cSRui Paulo for (i = 0; i < iface->num_bss; i++) {
27385b9c547cSRui Paulo if (iface->bss[i]->started &&
27395b9c547cSRui Paulo ieee802_11_set_beacon(iface->bss[i]) < 0)
27405b9c547cSRui Paulo ret = -1;
27415b9c547cSRui Paulo }
27425b9c547cSRui Paulo
27435b9c547cSRui Paulo return ret;
2744e28a4053SRui Paulo }
2745e28a4053SRui Paulo
2746f05cddf9SRui Paulo
2747f05cddf9SRui Paulo /* only update beacons if started */
ieee802_11_update_beacons(struct hostapd_iface * iface)27485b9c547cSRui Paulo int ieee802_11_update_beacons(struct hostapd_iface *iface)
2749f05cddf9SRui Paulo {
2750f05cddf9SRui Paulo size_t i;
27515b9c547cSRui Paulo int ret = 0;
27525b9c547cSRui Paulo
27535b9c547cSRui Paulo for (i = 0; i < iface->num_bss; i++) {
27545b9c547cSRui Paulo if (iface->bss[i]->beacon_set_done && iface->bss[i]->started &&
27555b9c547cSRui Paulo ieee802_11_set_beacon(iface->bss[i]) < 0)
27565b9c547cSRui Paulo ret = -1;
27575b9c547cSRui Paulo }
27585b9c547cSRui Paulo
27595b9c547cSRui Paulo return ret;
2760f05cddf9SRui Paulo }
2761f05cddf9SRui Paulo
2762e28a4053SRui Paulo #endif /* CONFIG_NATIVE_WINDOWS */
2763