blob: 236381fe87ef55d841cf8013a6ecd83794a64bee [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * hostapd / Initialization and configuration
Hai Shaloma20dcd72022-02-04 13:43:00 -08003 * Copyright (c) 2002-2021, Jouni Malinen <j@w1.fi>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 */
8
9#include "utils/includes.h"
Hai Shalomc3565922019-10-28 11:58:20 -070010#ifdef CONFIG_SQLITE
11#include <sqlite3.h>
12#endif /* CONFIG_SQLITE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070013
14#include "utils/common.h"
15#include "utils/eloop.h"
Hai Shalomfdcde762020-04-02 11:19:20 -070016#include "utils/crc32.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070017#include "common/ieee802_11_defs.h"
Dmitry Shmidtcce06662013-11-04 18:44:24 -080018#include "common/wpa_ctrl.h"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080019#include "common/hw_features_common.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070020#include "radius/radius_client.h"
Dmitry Shmidt04949592012-07-19 12:16:46 -070021#include "radius/radius_das.h"
Dmitry Shmidt50b691d2014-05-21 14:01:45 -070022#include "eap_server/tncs.h"
Dmitry Shmidt2f74e362015-01-21 13:19:05 -080023#include "eapol_auth/eapol_auth_sm.h"
24#include "eapol_auth/eapol_auth_sm_i.h"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080025#include "fst/fst.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070026#include "hostapd.h"
27#include "authsrv.h"
28#include "sta_info.h"
29#include "accounting.h"
30#include "ap_list.h"
31#include "beacon.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070032#include "ieee802_1x.h"
33#include "ieee802_11_auth.h"
34#include "vlan_init.h"
35#include "wpa_auth.h"
36#include "wps_hostapd.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070037#include "dpp_hostapd.h"
38#include "gas_query_ap.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070039#include "hw_features.h"
40#include "wpa_auth_glue.h"
41#include "ap_drv_ops.h"
42#include "ap_config.h"
43#include "p2p_hostapd.h"
Dmitry Shmidt04949592012-07-19 12:16:46 -070044#include "gas_serv.h"
Dmitry Shmidt051af732013-10-22 13:52:46 -070045#include "dfs.h"
Dmitry Shmidt7832adb2014-04-29 10:53:02 -070046#include "ieee802_11.h"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080047#include "bss_load.h"
48#include "x_snoop.h"
49#include "dhcp_snoop.h"
50#include "ndisc_snoop.h"
Dmitry Shmidt849734c2016-05-27 09:59:01 -070051#include "neighbor_db.h"
52#include "rrm.h"
Dmitry Shmidtebd93af2017-02-21 13:40:44 -080053#include "fils_hlp.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070054#include "acs.h"
Roshan Pius3a1667e2018-07-03 15:17:14 -070055#include "hs20.h"
Hai Shalom81f62d82019-07-22 12:10:00 -070056#include "airtime_policy.h"
57#include "wpa_auth_kay.h"
Sunil Ravi2a14cf12023-11-21 00:54:38 +000058#include "hw_features.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070059
60
Dmitry Shmidt04949592012-07-19 12:16:46 -070061static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
Hai Shalomfdcde762020-04-02 11:19:20 -070062#ifdef CONFIG_WEP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070063static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd);
Dmitry Shmidtc55524a2011-07-07 11:18:38 -070064static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd);
Hai Shalomfdcde762020-04-02 11:19:20 -070065#endif /* CONFIG_WEP */
Dmitry Shmidtcce06662013-11-04 18:44:24 -080066static int setup_interface2(struct hostapd_iface *iface);
67static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx);
Roshan Pius3a1667e2018-07-03 15:17:14 -070068static void hostapd_interface_setup_failure_handler(void *eloop_ctx,
69 void *timeout_ctx);
Sunil Ravia04bd252022-05-02 22:54:18 -070070#ifdef CONFIG_IEEE80211AX
71static void hostapd_switch_color_timeout_handler(void *eloop_data,
72 void *user_ctx);
73#endif /* CONFIG_IEEE80211AX */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070074
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070075
Dmitry Shmidt04949592012-07-19 12:16:46 -070076int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
77 int (*cb)(struct hostapd_iface *iface,
78 void *ctx), void *ctx)
79{
80 size_t i;
81 int ret;
82
83 for (i = 0; i < interfaces->count; i++) {
Hai Shalom4fbc08f2020-05-18 12:37:00 -070084 if (!interfaces->iface[i])
85 continue;
Dmitry Shmidt04949592012-07-19 12:16:46 -070086 ret = cb(interfaces->iface[i], ctx);
87 if (ret)
88 return ret;
89 }
90
91 return 0;
92}
93
94
Sunil Ravi77d572f2023-01-17 23:58:31 +000095struct hostapd_data * hostapd_mbssid_get_tx_bss(struct hostapd_data *hapd)
96{
97 if (hapd->iconf->mbssid)
98 return hapd->iface->bss[0];
99
100 return hapd;
101}
102
103
104int hostapd_mbssid_get_bss_index(struct hostapd_data *hapd)
105{
106 if (hapd->iconf->mbssid) {
107 size_t i;
108
109 for (i = 1; i < hapd->iface->num_bss; i++)
110 if (hapd->iface->bss[i] == hapd)
111 return i;
112 }
113
114 return 0;
115}
116
117
Hai Shalomce48b4a2018-09-05 11:41:35 -0700118void hostapd_reconfig_encryption(struct hostapd_data *hapd)
119{
120 if (hapd->wpa_auth)
121 return;
122
123 hostapd_set_privacy(hapd, 0);
Hai Shalomfdcde762020-04-02 11:19:20 -0700124#ifdef CONFIG_WEP
Hai Shalomce48b4a2018-09-05 11:41:35 -0700125 hostapd_setup_encryption(hapd->conf->iface, hapd);
Hai Shalomfdcde762020-04-02 11:19:20 -0700126#endif /* CONFIG_WEP */
Hai Shalomce48b4a2018-09-05 11:41:35 -0700127}
128
129
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700130static void hostapd_reload_bss(struct hostapd_data *hapd)
131{
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800132 struct hostapd_ssid *ssid;
133
Dmitry Shmidt29333592017-01-09 12:27:11 -0800134 if (!hapd->started)
135 return;
136
Roshan Pius3a1667e2018-07-03 15:17:14 -0700137 if (hapd->conf->wmm_enabled < 0)
Hai Shaloma20dcd72022-02-04 13:43:00 -0800138 hapd->conf->wmm_enabled = hapd->iconf->ieee80211n |
139 hapd->iconf->ieee80211ax;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700140
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700141#ifndef CONFIG_NO_RADIUS
142 radius_client_reconfig(hapd->radius, hapd->conf->radius);
143#endif /* CONFIG_NO_RADIUS */
144
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800145 ssid = &hapd->conf->ssid;
146 if (!ssid->wpa_psk_set && ssid->wpa_psk && !ssid->wpa_psk->next &&
147 ssid->wpa_passphrase_set && ssid->wpa_passphrase) {
148 /*
149 * Force PSK to be derived again since SSID or passphrase may
150 * have changed.
151 */
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800152 hostapd_config_clear_wpa_psk(&hapd->conf->ssid.wpa_psk);
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800153 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700154 if (hostapd_setup_wpa_psk(hapd->conf)) {
155 wpa_printf(MSG_ERROR, "Failed to re-configure WPA PSK "
156 "after reloading configuration");
157 }
158
159 if (hapd->conf->ieee802_1x || hapd->conf->wpa)
160 hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 1);
161 else
162 hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0);
163
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800164 if ((hapd->conf->wpa || hapd->conf->osen) && hapd->wpa_auth == NULL) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700165 hostapd_setup_wpa(hapd);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800166 if (hapd->wpa_auth)
167 wpa_init_keys(hapd->wpa_auth);
168 } else if (hapd->conf->wpa) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700169 const u8 *wpa_ie;
170 size_t wpa_ie_len;
171 hostapd_reconfig_wpa(hapd);
172 wpa_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &wpa_ie_len);
173 if (hostapd_set_generic_elem(hapd, wpa_ie, wpa_ie_len))
174 wpa_printf(MSG_ERROR, "Failed to configure WPA IE for "
175 "the kernel driver.");
176 } else if (hapd->wpa_auth) {
177 wpa_deinit(hapd->wpa_auth);
178 hapd->wpa_auth = NULL;
179 hostapd_set_privacy(hapd, 0);
Hai Shalomfdcde762020-04-02 11:19:20 -0700180#ifdef CONFIG_WEP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700181 hostapd_setup_encryption(hapd->conf->iface, hapd);
Hai Shalomfdcde762020-04-02 11:19:20 -0700182#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700183 hostapd_set_generic_elem(hapd, (u8 *) "", 0);
184 }
185
186 ieee802_11_set_beacon(hapd);
187 hostapd_update_wps(hapd);
188
189 if (hapd->conf->ssid.ssid_set &&
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700190 hostapd_set_ssid(hapd, hapd->conf->ssid.ssid,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700191 hapd->conf->ssid.ssid_len)) {
192 wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver");
193 /* try to continue */
194 }
195 wpa_printf(MSG_DEBUG, "Reconfigured interface %s", hapd->conf->iface);
196}
197
198
Sunil Ravi77d572f2023-01-17 23:58:31 +0000199static void hostapd_clear_old_bss(struct hostapd_data *bss)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700200{
Sunil Ravi77d572f2023-01-17 23:58:31 +0000201 wpa_printf(MSG_DEBUG, "BSS %s changed - clear old state",
202 bss->conf->iface);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700203
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700204 /*
205 * Deauthenticate all stations since the new configuration may not
206 * allow them to use the BSS anymore.
207 */
Sunil Ravi77d572f2023-01-17 23:58:31 +0000208 hostapd_flush_old_stations(bss, WLAN_REASON_PREV_AUTH_NOT_VALID);
Hai Shalomfdcde762020-04-02 11:19:20 -0700209#ifdef CONFIG_WEP
Sunil Ravi77d572f2023-01-17 23:58:31 +0000210 hostapd_broadcast_wep_clear(bss);
Hai Shalomfdcde762020-04-02 11:19:20 -0700211#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700212
213#ifndef CONFIG_NO_RADIUS
Sunil Ravi77d572f2023-01-17 23:58:31 +0000214 /* TODO: update dynamic data based on changed configuration
215 * items (e.g., open/close sockets, etc.) */
216 radius_client_flush(bss->radius, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700217#endif /* CONFIG_NO_RADIUS */
Sunil Ravi77d572f2023-01-17 23:58:31 +0000218}
219
220
221static void hostapd_clear_old(struct hostapd_iface *iface)
222{
223 size_t j;
224
225 for (j = 0; j < iface->num_bss; j++)
226 hostapd_clear_old_bss(iface->bss[j]);
Dmitry Shmidt444d5672013-04-01 13:08:44 -0700227}
228
229
Hai Shalom74f70d42019-02-11 14:42:39 -0800230static int hostapd_iface_conf_changed(struct hostapd_config *newconf,
231 struct hostapd_config *oldconf)
232{
233 size_t i;
234
235 if (newconf->num_bss != oldconf->num_bss)
236 return 1;
237
238 for (i = 0; i < newconf->num_bss; i++) {
239 if (os_strcmp(newconf->bss[i]->iface,
240 oldconf->bss[i]->iface) != 0)
241 return 1;
242 }
243
244 return 0;
245}
246
247
Dmitry Shmidt444d5672013-04-01 13:08:44 -0700248int hostapd_reload_config(struct hostapd_iface *iface)
249{
Hai Shalom74f70d42019-02-11 14:42:39 -0800250 struct hapd_interfaces *interfaces = iface->interfaces;
Dmitry Shmidt444d5672013-04-01 13:08:44 -0700251 struct hostapd_data *hapd = iface->bss[0];
252 struct hostapd_config *newconf, *oldconf;
253 size_t j;
254
255 if (iface->config_fname == NULL) {
256 /* Only in-memory config in use - assume it has been updated */
257 hostapd_clear_old(iface);
258 for (j = 0; j < iface->num_bss; j++)
259 hostapd_reload_bss(iface->bss[j]);
260 return 0;
261 }
262
263 if (iface->interfaces == NULL ||
264 iface->interfaces->config_read_cb == NULL)
265 return -1;
266 newconf = iface->interfaces->config_read_cb(iface->config_fname);
267 if (newconf == NULL)
268 return -1;
269
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700270 oldconf = hapd->iconf;
Hai Shalom74f70d42019-02-11 14:42:39 -0800271 if (hostapd_iface_conf_changed(newconf, oldconf)) {
272 char *fname;
273 int res;
274
Sunil Ravi77d572f2023-01-17 23:58:31 +0000275 hostapd_clear_old(iface);
276
Hai Shalom74f70d42019-02-11 14:42:39 -0800277 wpa_printf(MSG_DEBUG,
278 "Configuration changes include interface/BSS modification - force full disable+enable sequence");
279 fname = os_strdup(iface->config_fname);
280 if (!fname) {
281 hostapd_config_free(newconf);
282 return -1;
283 }
284 hostapd_remove_iface(interfaces, hapd->conf->iface);
285 iface = hostapd_init(interfaces, fname);
286 os_free(fname);
287 hostapd_config_free(newconf);
288 if (!iface) {
289 wpa_printf(MSG_ERROR,
290 "Failed to initialize interface on config reload");
291 return -1;
292 }
293 iface->interfaces = interfaces;
294 interfaces->iface[interfaces->count] = iface;
295 interfaces->count++;
296 res = hostapd_enable_iface(iface);
297 if (res < 0)
298 wpa_printf(MSG_ERROR,
299 "Failed to enable interface on config reload");
300 return res;
301 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700302 iface->conf = newconf;
303
304 for (j = 0; j < iface->num_bss; j++) {
305 hapd = iface->bss[j];
Sunil Ravi77d572f2023-01-17 23:58:31 +0000306 if (!hapd->conf->config_id || !newconf->bss[j]->config_id ||
307 os_strcmp(hapd->conf->config_id,
308 newconf->bss[j]->config_id) != 0)
309 hostapd_clear_old_bss(hapd);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700310 hapd->iconf = newconf;
Dmitry Shmidtd11f0192014-03-24 12:09:47 -0700311 hapd->iconf->channel = oldconf->channel;
Dmitry Shmidtdda10c22015-03-24 16:05:01 -0700312 hapd->iconf->acs = oldconf->acs;
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -0700313 hapd->iconf->secondary_channel = oldconf->secondary_channel;
Dmitry Shmidtd11f0192014-03-24 12:09:47 -0700314 hapd->iconf->ieee80211n = oldconf->ieee80211n;
315 hapd->iconf->ieee80211ac = oldconf->ieee80211ac;
316 hapd->iconf->ht_capab = oldconf->ht_capab;
317 hapd->iconf->vht_capab = oldconf->vht_capab;
Hai Shalom81f62d82019-07-22 12:10:00 -0700318 hostapd_set_oper_chwidth(hapd->iconf,
319 hostapd_get_oper_chwidth(oldconf));
320 hostapd_set_oper_centr_freq_seg0_idx(
321 hapd->iconf,
322 hostapd_get_oper_centr_freq_seg0_idx(oldconf));
323 hostapd_set_oper_centr_freq_seg1_idx(
324 hapd->iconf,
325 hostapd_get_oper_centr_freq_seg1_idx(oldconf));
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800326 hapd->conf = newconf->bss[j];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700327 hostapd_reload_bss(hapd);
328 }
329
330 hostapd_config_free(oldconf);
331
332
333 return 0;
334}
335
336
Hai Shalomfdcde762020-04-02 11:19:20 -0700337#ifdef CONFIG_WEP
338
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700339static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -0700340 const char *ifname)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700341{
342 int i;
343
Dmitry Shmidt29333592017-01-09 12:27:11 -0800344 if (!ifname || !hapd->drv_priv)
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -0700345 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700346 for (i = 0; i < NUM_WEP_KEYS; i++) {
Hai Shalomfdcde762020-04-02 11:19:20 -0700347 if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i, 0,
348 0, NULL, 0, NULL, 0, KEY_FLAG_GROUP)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700349 wpa_printf(MSG_DEBUG, "Failed to clear default "
350 "encryption keys (ifname=%s keyidx=%d)",
351 ifname, i);
352 }
353 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700354 if (hapd->conf->ieee80211w) {
355 for (i = NUM_WEP_KEYS; i < NUM_WEP_KEYS + 2; i++) {
356 if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE,
Hai Shalomfdcde762020-04-02 11:19:20 -0700357 NULL, i, 0, 0, NULL,
358 0, NULL, 0, KEY_FLAG_GROUP)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700359 wpa_printf(MSG_DEBUG, "Failed to clear "
360 "default mgmt encryption keys "
361 "(ifname=%s keyidx=%d)", ifname, i);
362 }
363 }
364 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700365}
366
367
368static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd)
369{
370 hostapd_broadcast_key_clear_iface(hapd, hapd->conf->iface);
371 return 0;
372}
373
374
375static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
376{
377 int errors = 0, idx;
378 struct hostapd_ssid *ssid = &hapd->conf->ssid;
379
380 idx = ssid->wep.idx;
Hai Shalomfdcde762020-04-02 11:19:20 -0700381 if (ssid->wep.default_len && ssid->wep.key[idx] &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700382 hostapd_drv_set_key(hapd->conf->iface,
Hai Shalomfdcde762020-04-02 11:19:20 -0700383 hapd, WPA_ALG_WEP, broadcast_ether_addr, idx, 0,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700384 1, NULL, 0, ssid->wep.key[idx],
Hai Shalomfdcde762020-04-02 11:19:20 -0700385 ssid->wep.len[idx],
386 KEY_FLAG_GROUP_RX_TX_DEFAULT)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700387 wpa_printf(MSG_WARNING, "Could not set WEP encryption.");
388 errors++;
389 }
390
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700391 return errors;
392}
393
Hai Shalomfdcde762020-04-02 11:19:20 -0700394#endif /* CONFIG_WEP */
395
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700396
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000397static void hostapd_clear_drv_priv(struct hostapd_data *hapd)
398{
399 unsigned int i;
400
401 for (i = 0; i < hapd->iface->interfaces->count; i++) {
402 struct hostapd_iface *iface = hapd->iface->interfaces->iface[i];
403
404 if (hapd->iface == iface || !iface)
405 continue;
406
407 if (iface->bss && iface->bss[0] &&
408 iface->bss[0]->mld_first_bss == hapd)
409 iface->bss[0]->drv_priv = NULL;
410 }
411
412 hapd->drv_priv = NULL;
413}
414
415
Hai Shalom60840252021-02-19 19:02:11 -0800416void hostapd_free_hapd_data(struct hostapd_data *hapd)
Dmitry Shmidt04949592012-07-19 12:16:46 -0700417{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800418 os_free(hapd->probereq_cb);
419 hapd->probereq_cb = NULL;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800420 hapd->num_probereq_cb = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800421
422#ifdef CONFIG_P2P
423 wpabuf_free(hapd->p2p_beacon_ie);
424 hapd->p2p_beacon_ie = NULL;
425 wpabuf_free(hapd->p2p_probe_resp_ie);
426 hapd->p2p_probe_resp_ie = NULL;
427#endif /* CONFIG_P2P */
428
Dmitry Shmidtfa3fc4a2013-11-21 13:34:38 -0800429 if (!hapd->started) {
430 wpa_printf(MSG_ERROR, "%s: Interface %s wasn't started",
Hai Shalom021b0b52019-04-10 11:17:58 -0700431 __func__, hapd->conf ? hapd->conf->iface : "N/A");
Dmitry Shmidtfa3fc4a2013-11-21 13:34:38 -0800432 return;
433 }
434 hapd->started = 0;
Hai Shalom5f92bc92019-04-18 11:54:11 -0700435 hapd->beacon_set_done = 0;
Dmitry Shmidtfa3fc4a2013-11-21 13:34:38 -0800436
Dmitry Shmidt54605472013-11-08 11:10:19 -0800437 wpa_printf(MSG_DEBUG, "%s(%s)", __func__, hapd->conf->iface);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700438 accounting_deinit(hapd);
439 hostapd_deinit_wpa(hapd);
440 vlan_deinit(hapd);
441 hostapd_acl_deinit(hapd);
442#ifndef CONFIG_NO_RADIUS
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000443 if (!hapd->mld_first_bss) {
444 radius_client_deinit(hapd->radius);
445 radius_das_deinit(hapd->radius_das);
446 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700447 hapd->radius = NULL;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700448 hapd->radius_das = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700449#endif /* CONFIG_NO_RADIUS */
450
451 hostapd_deinit_wps(hapd);
Hai Shalom81f62d82019-07-22 12:10:00 -0700452 ieee802_1x_dealloc_kay_sm_hapd(hapd);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700453#ifdef CONFIG_DPP
454 hostapd_dpp_deinit(hapd);
455 gas_query_ap_deinit(hapd->gas);
Hai Shaloma20dcd72022-02-04 13:43:00 -0800456 hapd->gas = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700457#endif /* CONFIG_DPP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700458
459 authsrv_deinit(hapd);
460
Dmitry Shmidt71757432014-06-02 13:50:35 -0700461 if (hapd->interface_added) {
462 hapd->interface_added = 0;
463 if (hostapd_if_remove(hapd, WPA_IF_AP_BSS, hapd->conf->iface)) {
464 wpa_printf(MSG_WARNING,
465 "Failed to remove BSS interface %s",
466 hapd->conf->iface);
467 hapd->interface_added = 1;
468 } else {
469 /*
470 * Since this was a dynamically added interface, the
471 * driver wrapper may have removed its internal instance
472 * and hapd->drv_priv is not valid anymore.
473 */
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000474 hostapd_clear_drv_priv(hapd);
Dmitry Shmidt71757432014-06-02 13:50:35 -0700475 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700476 }
477
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800478 wpabuf_free(hapd->time_adv);
Hai Shaloma20dcd72022-02-04 13:43:00 -0800479 hapd->time_adv = NULL;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700480
481#ifdef CONFIG_INTERWORKING
482 gas_serv_deinit(hapd);
483#endif /* CONFIG_INTERWORKING */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800484
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800485 bss_load_update_deinit(hapd);
486 ndisc_snoop_deinit(hapd);
487 dhcp_snoop_deinit(hapd);
488 x_snoop_deinit(hapd);
489
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800490#ifdef CONFIG_SQLITE
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700491 bin_clear_free(hapd->tmp_eap_user.identity,
492 hapd->tmp_eap_user.identity_len);
493 bin_clear_free(hapd->tmp_eap_user.password,
494 hapd->tmp_eap_user.password_len);
Hai Shaloma20dcd72022-02-04 13:43:00 -0800495 os_memset(&hapd->tmp_eap_user, 0, sizeof(hapd->tmp_eap_user));
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800496#endif /* CONFIG_SQLITE */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800497
498#ifdef CONFIG_MESH
499 wpabuf_free(hapd->mesh_pending_auth);
500 hapd->mesh_pending_auth = NULL;
Hai Shalom60840252021-02-19 19:02:11 -0800501 /* handling setup failure is already done */
502 hapd->setup_complete_cb = NULL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800503#endif /* CONFIG_MESH */
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700504
505 hostapd_clean_rrm(hapd);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -0800506 fils_hlp_deinit(hapd);
Hai Shalom021b0b52019-04-10 11:17:58 -0700507
Hai Shalom899fcc72020-10-19 14:38:18 -0700508#ifdef CONFIG_OCV
509 eloop_cancel_timeout(hostapd_ocv_check_csa_sa_query, hapd, NULL);
510#endif /* CONFIG_OCV */
511
Hai Shalom021b0b52019-04-10 11:17:58 -0700512#ifdef CONFIG_SAE
513 {
514 struct hostapd_sae_commit_queue *q;
515
516 while ((q = dl_list_first(&hapd->sae_commit_queue,
517 struct hostapd_sae_commit_queue,
518 list))) {
519 dl_list_del(&q->list);
520 os_free(q);
521 }
522 }
523 eloop_cancel_timeout(auth_sae_process_commit, hapd, NULL);
524#endif /* CONFIG_SAE */
Sunil Ravia04bd252022-05-02 22:54:18 -0700525
526#ifdef CONFIG_IEEE80211AX
527 eloop_cancel_timeout(hostapd_switch_color_timeout_handler, hapd, NULL);
528#endif /* CONFIG_IEEE80211AX */
Dmitry Shmidt04949592012-07-19 12:16:46 -0700529}
530
531
532/**
533 * hostapd_cleanup - Per-BSS cleanup (deinitialization)
534 * @hapd: Pointer to BSS data
535 *
536 * This function is used to free all per-BSS data structures and resources.
Dmitry Shmidt54605472013-11-08 11:10:19 -0800537 * Most of the modules that are initialized in hostapd_setup_bss() are
538 * deinitialized here.
Dmitry Shmidt04949592012-07-19 12:16:46 -0700539 */
540static void hostapd_cleanup(struct hostapd_data *hapd)
541{
Dmitry Shmidt54605472013-11-08 11:10:19 -0800542 wpa_printf(MSG_DEBUG, "%s(hapd=%p (%s))", __func__, hapd,
Hai Shalom021b0b52019-04-10 11:17:58 -0700543 hapd->conf ? hapd->conf->iface : "N/A");
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700544 if (hapd->iface->interfaces &&
Dmitry Shmidt29333592017-01-09 12:27:11 -0800545 hapd->iface->interfaces->ctrl_iface_deinit) {
546 wpa_msg(hapd->msg_ctx, MSG_INFO, WPA_EVENT_TERMINATING);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700547 hapd->iface->interfaces->ctrl_iface_deinit(hapd);
Dmitry Shmidt29333592017-01-09 12:27:11 -0800548 }
Dmitry Shmidt04949592012-07-19 12:16:46 -0700549 hostapd_free_hapd_data(hapd);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700550}
551
552
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800553static void sta_track_deinit(struct hostapd_iface *iface)
554{
555 struct hostapd_sta_info *info;
556
557 if (!iface->num_sta_seen)
558 return;
559
560 while ((info = dl_list_first(&iface->sta_seen, struct hostapd_sta_info,
561 list))) {
562 dl_list_del(&info->list);
563 iface->num_sta_seen--;
Dmitry Shmidtaca489e2016-09-28 15:44:14 -0700564 sta_track_del(info);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800565 }
566}
567
568
Hai Shalom60840252021-02-19 19:02:11 -0800569void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
Dmitry Shmidt04949592012-07-19 12:16:46 -0700570{
Dmitry Shmidt54605472013-11-08 11:10:19 -0800571 wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800572#ifdef NEED_AP_MLME
573 hostapd_stop_setup_timers(iface);
574#endif /* NEED_AP_MLME */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700575 if (iface->current_mode)
576 acs_cleanup(iface);
Dmitry Shmidt04949592012-07-19 12:16:46 -0700577 hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
578 iface->hw_features = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700579 iface->current_mode = NULL;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700580 os_free(iface->current_rates);
581 iface->current_rates = NULL;
582 os_free(iface->basic_rates);
583 iface->basic_rates = NULL;
Sunil Ravi77d572f2023-01-17 23:58:31 +0000584 iface->cac_started = 0;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700585 ap_list_deinit(iface);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800586 sta_track_deinit(iface);
Hai Shalom81f62d82019-07-22 12:10:00 -0700587 airtime_policy_update_deinit(iface);
Dmitry Shmidt04949592012-07-19 12:16:46 -0700588}
589
590
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700591/**
592 * hostapd_cleanup_iface - Complete per-interface cleanup
593 * @iface: Pointer to interface data
594 *
595 * This function is called after per-BSS data structures are deinitialized
596 * with hostapd_cleanup().
597 */
598static void hostapd_cleanup_iface(struct hostapd_iface *iface)
599{
Dmitry Shmidt54605472013-11-08 11:10:19 -0800600 wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800601 eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700602 eloop_cancel_timeout(hostapd_interface_setup_failure_handler, iface,
603 NULL);
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800604
Dmitry Shmidt04949592012-07-19 12:16:46 -0700605 hostapd_cleanup_iface_partial(iface);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700606 hostapd_config_free(iface->conf);
607 iface->conf = NULL;
608
609 os_free(iface->config_fname);
610 os_free(iface->bss);
Dmitry Shmidt54605472013-11-08 11:10:19 -0800611 wpa_printf(MSG_DEBUG, "%s: free iface=%p", __func__, iface);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700612 os_free(iface);
613}
614
615
Hai Shalomfdcde762020-04-02 11:19:20 -0700616#ifdef CONFIG_WEP
617
Dmitry Shmidt04949592012-07-19 12:16:46 -0700618static void hostapd_clear_wep(struct hostapd_data *hapd)
619{
Hai Shalom021b0b52019-04-10 11:17:58 -0700620 if (hapd->drv_priv && !hapd->iface->driver_ap_teardown && hapd->conf) {
Dmitry Shmidt04949592012-07-19 12:16:46 -0700621 hostapd_set_privacy(hapd, 0);
622 hostapd_broadcast_wep_clear(hapd);
623 }
624}
625
626
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700627static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd)
628{
629 int i;
630
631 hostapd_broadcast_wep_set(hapd);
632
633 if (hapd->conf->ssid.wep.default_len) {
634 hostapd_set_privacy(hapd, 1);
635 return 0;
636 }
637
Jouni Malinen75ecf522011-06-27 15:19:46 -0700638 /*
639 * When IEEE 802.1X is not enabled, the driver may need to know how to
640 * set authentication algorithms for static WEP.
641 */
642 hostapd_drv_set_authmode(hapd, hapd->conf->auth_algs);
643
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700644 for (i = 0; i < 4; i++) {
645 if (hapd->conf->ssid.wep.key[i] &&
Hai Shalomfdcde762020-04-02 11:19:20 -0700646 hostapd_drv_set_key(iface, hapd, WPA_ALG_WEP, NULL, i, 0,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700647 i == hapd->conf->ssid.wep.idx, NULL, 0,
648 hapd->conf->ssid.wep.key[i],
Hai Shalomfdcde762020-04-02 11:19:20 -0700649 hapd->conf->ssid.wep.len[i],
650 i == hapd->conf->ssid.wep.idx ?
651 KEY_FLAG_GROUP_RX_TX_DEFAULT :
652 KEY_FLAG_GROUP_RX_TX)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700653 wpa_printf(MSG_WARNING, "Could not set WEP "
654 "encryption.");
655 return -1;
656 }
657 if (hapd->conf->ssid.wep.key[i] &&
658 i == hapd->conf->ssid.wep.idx)
659 hostapd_set_privacy(hapd, 1);
660 }
661
662 return 0;
663}
664
Hai Shalomfdcde762020-04-02 11:19:20 -0700665#endif /* CONFIG_WEP */
666
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700667
Dmitry Shmidt04949592012-07-19 12:16:46 -0700668static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700669{
670 int ret = 0;
671 u8 addr[ETH_ALEN];
672
673 if (hostapd_drv_none(hapd) || hapd->drv_priv == NULL)
674 return 0;
675
Dmitry Shmidta38abf92014-03-06 13:38:44 -0800676 if (!hapd->iface->driver_ap_teardown) {
677 wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
678 "Flushing old station entries");
679
680 if (hostapd_flush(hapd)) {
681 wpa_msg(hapd->msg_ctx, MSG_WARNING,
682 "Could not connect to kernel driver");
683 ret = -1;
684 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700685 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700686 if (hapd->conf && hapd->conf->broadcast_deauth) {
687 wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
688 "Deauthenticate all stations");
689 os_memset(addr, 0xff, ETH_ALEN);
690 hostapd_drv_sta_deauth(hapd, addr, reason);
691 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700692 hostapd_free_stas(hapd);
693
694 return ret;
695}
696
697
Hai Shalom60840252021-02-19 19:02:11 -0800698void hostapd_bss_deinit_no_free(struct hostapd_data *hapd)
Dmitry Shmidt71757432014-06-02 13:50:35 -0700699{
700 hostapd_free_stas(hapd);
701 hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
Hai Shalomfdcde762020-04-02 11:19:20 -0700702#ifdef CONFIG_WEP
Dmitry Shmidt71757432014-06-02 13:50:35 -0700703 hostapd_clear_wep(hapd);
Hai Shalomfdcde762020-04-02 11:19:20 -0700704#endif /* CONFIG_WEP */
Dmitry Shmidt71757432014-06-02 13:50:35 -0700705}
706
707
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700708/**
709 * hostapd_validate_bssid_configuration - Validate BSSID configuration
710 * @iface: Pointer to interface data
711 * Returns: 0 on success, -1 on failure
712 *
713 * This function is used to validate that the configured BSSIDs are valid.
714 */
715static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface)
716{
717 u8 mask[ETH_ALEN] = { 0 };
718 struct hostapd_data *hapd = iface->bss[0];
719 unsigned int i = iface->conf->num_bss, bits = 0, j;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700720 int auto_addr = 0;
721
722 if (hostapd_drv_none(hapd))
723 return 0;
724
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -0800725 if (iface->conf->use_driver_iface_addr)
726 return 0;
727
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700728 /* Generate BSSID mask that is large enough to cover the BSSIDs. */
729
730 /* Determine the bits necessary to cover the number of BSSIDs. */
731 for (i--; i; i >>= 1)
732 bits++;
733
734 /* Determine the bits necessary to any configured BSSIDs,
735 if they are higher than the number of BSSIDs. */
736 for (j = 0; j < iface->conf->num_bss; j++) {
Dmitry Shmidt9c175262016-03-03 10:20:07 -0800737 if (is_zero_ether_addr(iface->conf->bss[j]->bssid)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700738 if (j)
739 auto_addr++;
740 continue;
741 }
742
743 for (i = 0; i < ETH_ALEN; i++) {
744 mask[i] |=
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800745 iface->conf->bss[j]->bssid[i] ^
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700746 hapd->own_addr[i];
747 }
748 }
749
750 if (!auto_addr)
751 goto skip_mask_ext;
752
753 for (i = 0; i < ETH_ALEN && mask[i] == 0; i++)
754 ;
755 j = 0;
756 if (i < ETH_ALEN) {
757 j = (5 - i) * 8;
758
759 while (mask[i] != 0) {
760 mask[i] >>= 1;
761 j++;
762 }
763 }
764
765 if (bits < j)
766 bits = j;
767
768 if (bits > 40) {
769 wpa_printf(MSG_ERROR, "Too many bits in the BSSID mask (%u)",
770 bits);
771 return -1;
772 }
773
774 os_memset(mask, 0xff, ETH_ALEN);
775 j = bits / 8;
776 for (i = 5; i > 5 - j; i--)
777 mask[i] = 0;
778 j = bits % 8;
Hai Shalom021b0b52019-04-10 11:17:58 -0700779 while (j) {
780 j--;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700781 mask[i] <<= 1;
Hai Shalom021b0b52019-04-10 11:17:58 -0700782 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700783
784skip_mask_ext:
785 wpa_printf(MSG_DEBUG, "BSS count %lu, BSSID mask " MACSTR " (%d bits)",
786 (unsigned long) iface->conf->num_bss, MAC2STR(mask), bits);
787
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700788 if (!auto_addr)
789 return 0;
790
791 for (i = 0; i < ETH_ALEN; i++) {
792 if ((hapd->own_addr[i] & mask[i]) != hapd->own_addr[i]) {
793 wpa_printf(MSG_ERROR, "Invalid BSSID mask " MACSTR
794 " for start address " MACSTR ".",
795 MAC2STR(mask), MAC2STR(hapd->own_addr));
796 wpa_printf(MSG_ERROR, "Start address must be the "
797 "first address in the block (i.e., addr "
798 "AND mask == addr).");
799 return -1;
800 }
801 }
802
803 return 0;
804}
805
806
807static int mac_in_conf(struct hostapd_config *conf, const void *a)
808{
809 size_t i;
810
811 for (i = 0; i < conf->num_bss; i++) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800812 if (hostapd_mac_comp(conf->bss[i]->bssid, a) == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700813 return 1;
814 }
815 }
816
817 return 0;
818}
819
820
Dmitry Shmidt04949592012-07-19 12:16:46 -0700821#ifndef CONFIG_NO_RADIUS
822
823static int hostapd_das_nas_mismatch(struct hostapd_data *hapd,
824 struct radius_das_attrs *attr)
825{
Dmitry Shmidt13ca8d82014-02-20 10:18:40 -0800826 if (attr->nas_identifier &&
827 (!hapd->conf->nas_identifier ||
828 os_strlen(hapd->conf->nas_identifier) !=
829 attr->nas_identifier_len ||
830 os_memcmp(hapd->conf->nas_identifier, attr->nas_identifier,
831 attr->nas_identifier_len) != 0)) {
832 wpa_printf(MSG_DEBUG, "RADIUS DAS: NAS-Identifier mismatch");
833 return 1;
834 }
835
836 if (attr->nas_ip_addr &&
837 (hapd->conf->own_ip_addr.af != AF_INET ||
838 os_memcmp(&hapd->conf->own_ip_addr.u.v4, attr->nas_ip_addr, 4) !=
839 0)) {
840 wpa_printf(MSG_DEBUG, "RADIUS DAS: NAS-IP-Address mismatch");
841 return 1;
842 }
843
844#ifdef CONFIG_IPV6
845 if (attr->nas_ipv6_addr &&
846 (hapd->conf->own_ip_addr.af != AF_INET6 ||
847 os_memcmp(&hapd->conf->own_ip_addr.u.v6, attr->nas_ipv6_addr, 16)
848 != 0)) {
849 wpa_printf(MSG_DEBUG, "RADIUS DAS: NAS-IPv6-Address mismatch");
850 return 1;
851 }
852#endif /* CONFIG_IPV6 */
853
Dmitry Shmidt04949592012-07-19 12:16:46 -0700854 return 0;
855}
856
857
858static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800859 struct radius_das_attrs *attr,
860 int *multi)
Dmitry Shmidt04949592012-07-19 12:16:46 -0700861{
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800862 struct sta_info *selected, *sta;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700863 char buf[128];
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800864 int num_attr = 0;
865 int count;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700866
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800867 *multi = 0;
868
869 for (sta = hapd->sta_list; sta; sta = sta->next)
870 sta->radius_das_match = 1;
871
872 if (attr->sta_addr) {
873 num_attr++;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700874 sta = ap_get_sta(hapd, attr->sta_addr);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800875 if (!sta) {
876 wpa_printf(MSG_DEBUG,
877 "RADIUS DAS: No Calling-Station-Id match");
878 return NULL;
879 }
Dmitry Shmidt04949592012-07-19 12:16:46 -0700880
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800881 selected = sta;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700882 for (sta = hapd->sta_list; sta; sta = sta->next) {
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800883 if (sta != selected)
884 sta->radius_das_match = 0;
885 }
886 wpa_printf(MSG_DEBUG, "RADIUS DAS: Calling-Station-Id match");
887 }
888
889 if (attr->acct_session_id) {
890 num_attr++;
Dmitry Shmidtb97e4282016-02-08 10:16:07 -0800891 if (attr->acct_session_id_len != 16) {
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800892 wpa_printf(MSG_DEBUG,
893 "RADIUS DAS: Acct-Session-Id cannot match");
894 return NULL;
895 }
896 count = 0;
897
898 for (sta = hapd->sta_list; sta; sta = sta->next) {
899 if (!sta->radius_das_match)
900 continue;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800901 os_snprintf(buf, sizeof(buf), "%016llX",
902 (unsigned long long) sta->acct_session_id);
Dmitry Shmidtb97e4282016-02-08 10:16:07 -0800903 if (os_memcmp(attr->acct_session_id, buf, 16) != 0)
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800904 sta->radius_das_match = 0;
905 else
906 count++;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700907 }
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800908
909 if (count == 0) {
910 wpa_printf(MSG_DEBUG,
911 "RADIUS DAS: No matches remaining after Acct-Session-Id check");
912 return NULL;
913 }
914 wpa_printf(MSG_DEBUG, "RADIUS DAS: Acct-Session-Id match");
Dmitry Shmidt04949592012-07-19 12:16:46 -0700915 }
916
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800917 if (attr->acct_multi_session_id) {
918 num_attr++;
Dmitry Shmidtb97e4282016-02-08 10:16:07 -0800919 if (attr->acct_multi_session_id_len != 16) {
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800920 wpa_printf(MSG_DEBUG,
921 "RADIUS DAS: Acct-Multi-Session-Id cannot match");
922 return NULL;
923 }
924 count = 0;
925
926 for (sta = hapd->sta_list; sta; sta = sta->next) {
927 if (!sta->radius_das_match)
928 continue;
929 if (!sta->eapol_sm ||
Dmitry Shmidtb97e4282016-02-08 10:16:07 -0800930 !sta->eapol_sm->acct_multi_session_id) {
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800931 sta->radius_das_match = 0;
932 continue;
933 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800934 os_snprintf(buf, sizeof(buf), "%016llX",
935 (unsigned long long)
Dmitry Shmidtb97e4282016-02-08 10:16:07 -0800936 sta->eapol_sm->acct_multi_session_id);
937 if (os_memcmp(attr->acct_multi_session_id, buf, 16) !=
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800938 0)
939 sta->radius_das_match = 0;
940 else
941 count++;
942 }
943
944 if (count == 0) {
945 wpa_printf(MSG_DEBUG,
946 "RADIUS DAS: No matches remaining after Acct-Multi-Session-Id check");
947 return NULL;
948 }
949 wpa_printf(MSG_DEBUG,
950 "RADIUS DAS: Acct-Multi-Session-Id match");
951 }
952
953 if (attr->cui) {
954 num_attr++;
955 count = 0;
956
Dmitry Shmidt04949592012-07-19 12:16:46 -0700957 for (sta = hapd->sta_list; sta; sta = sta->next) {
958 struct wpabuf *cui;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800959
960 if (!sta->radius_das_match)
961 continue;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700962 cui = ieee802_1x_get_radius_cui(sta->eapol_sm);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800963 if (!cui || wpabuf_len(cui) != attr->cui_len ||
Dmitry Shmidt04949592012-07-19 12:16:46 -0700964 os_memcmp(wpabuf_head(cui), attr->cui,
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800965 attr->cui_len) != 0)
966 sta->radius_das_match = 0;
967 else
968 count++;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700969 }
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800970
971 if (count == 0) {
972 wpa_printf(MSG_DEBUG,
973 "RADIUS DAS: No matches remaining after Chargeable-User-Identity check");
974 return NULL;
975 }
976 wpa_printf(MSG_DEBUG,
977 "RADIUS DAS: Chargeable-User-Identity match");
Dmitry Shmidt04949592012-07-19 12:16:46 -0700978 }
979
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800980 if (attr->user_name) {
981 num_attr++;
982 count = 0;
983
Dmitry Shmidt04949592012-07-19 12:16:46 -0700984 for (sta = hapd->sta_list; sta; sta = sta->next) {
985 u8 *identity;
986 size_t identity_len;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800987
988 if (!sta->radius_das_match)
989 continue;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700990 identity = ieee802_1x_get_identity(sta->eapol_sm,
991 &identity_len);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800992 if (!identity ||
993 identity_len != attr->user_name_len ||
Dmitry Shmidt04949592012-07-19 12:16:46 -0700994 os_memcmp(identity, attr->user_name, identity_len)
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800995 != 0)
996 sta->radius_das_match = 0;
997 else
998 count++;
999 }
1000
1001 if (count == 0) {
1002 wpa_printf(MSG_DEBUG,
1003 "RADIUS DAS: No matches remaining after User-Name check");
1004 return NULL;
1005 }
1006 wpa_printf(MSG_DEBUG,
1007 "RADIUS DAS: User-Name match");
1008 }
1009
1010 if (num_attr == 0) {
1011 /*
1012 * In theory, we could match all current associations, but it
1013 * seems safer to just reject requests that do not include any
1014 * session identification attributes.
1015 */
1016 wpa_printf(MSG_DEBUG,
1017 "RADIUS DAS: No session identification attributes included");
1018 return NULL;
1019 }
1020
1021 selected = NULL;
1022 for (sta = hapd->sta_list; sta; sta = sta->next) {
1023 if (sta->radius_das_match) {
1024 if (selected) {
1025 *multi = 1;
1026 return NULL;
1027 }
1028 selected = sta;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001029 }
1030 }
1031
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08001032 return selected;
1033}
1034
1035
1036static int hostapd_das_disconnect_pmksa(struct hostapd_data *hapd,
1037 struct radius_das_attrs *attr)
1038{
1039 if (!hapd->wpa_auth)
1040 return -1;
1041 return wpa_auth_radius_das_disconnect_pmksa(hapd->wpa_auth, attr);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001042}
1043
1044
1045static enum radius_das_res
1046hostapd_das_disconnect(void *ctx, struct radius_das_attrs *attr)
1047{
1048 struct hostapd_data *hapd = ctx;
1049 struct sta_info *sta;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08001050 int multi;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001051
1052 if (hostapd_das_nas_mismatch(hapd, attr))
1053 return RADIUS_DAS_NAS_MISMATCH;
1054
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08001055 sta = hostapd_das_find_sta(hapd, attr, &multi);
1056 if (sta == NULL) {
1057 if (multi) {
1058 wpa_printf(MSG_DEBUG,
1059 "RADIUS DAS: Multiple sessions match - not supported");
1060 return RADIUS_DAS_MULTI_SESSION_MATCH;
1061 }
1062 if (hostapd_das_disconnect_pmksa(hapd, attr) == 0) {
1063 wpa_printf(MSG_DEBUG,
1064 "RADIUS DAS: PMKSA cache entry matched");
1065 return RADIUS_DAS_SUCCESS;
1066 }
1067 wpa_printf(MSG_DEBUG, "RADIUS DAS: No matching session found");
Dmitry Shmidt04949592012-07-19 12:16:46 -07001068 return RADIUS_DAS_SESSION_NOT_FOUND;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08001069 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07001070
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08001071 wpa_printf(MSG_DEBUG, "RADIUS DAS: Found a matching session " MACSTR
1072 " - disconnecting", MAC2STR(sta->addr));
Dmitry Shmidt13ca8d82014-02-20 10:18:40 -08001073 wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
1074
Dmitry Shmidt04949592012-07-19 12:16:46 -07001075 hostapd_drv_sta_deauth(hapd, sta->addr,
1076 WLAN_REASON_PREV_AUTH_NOT_VALID);
1077 ap_sta_deauthenticate(hapd, sta, WLAN_REASON_PREV_AUTH_NOT_VALID);
1078
1079 return RADIUS_DAS_SUCCESS;
1080}
1081
Roshan Pius3a1667e2018-07-03 15:17:14 -07001082
1083#ifdef CONFIG_HS20
1084static enum radius_das_res
1085hostapd_das_coa(void *ctx, struct radius_das_attrs *attr)
1086{
1087 struct hostapd_data *hapd = ctx;
1088 struct sta_info *sta;
1089 int multi;
1090
1091 if (hostapd_das_nas_mismatch(hapd, attr))
1092 return RADIUS_DAS_NAS_MISMATCH;
1093
1094 sta = hostapd_das_find_sta(hapd, attr, &multi);
1095 if (!sta) {
1096 if (multi) {
1097 wpa_printf(MSG_DEBUG,
1098 "RADIUS DAS: Multiple sessions match - not supported");
1099 return RADIUS_DAS_MULTI_SESSION_MATCH;
1100 }
1101 wpa_printf(MSG_DEBUG, "RADIUS DAS: No matching session found");
1102 return RADIUS_DAS_SESSION_NOT_FOUND;
1103 }
1104
1105 wpa_printf(MSG_DEBUG, "RADIUS DAS: Found a matching session " MACSTR
1106 " - CoA", MAC2STR(sta->addr));
1107
1108 if (attr->hs20_t_c_filtering) {
1109 if (attr->hs20_t_c_filtering[0] & BIT(0)) {
1110 wpa_printf(MSG_DEBUG,
1111 "HS 2.0: Unexpected Terms and Conditions filtering required in CoA-Request");
1112 return RADIUS_DAS_COA_FAILED;
1113 }
1114
1115 hs20_t_c_filtering(hapd, sta, 0);
1116 }
1117
1118 return RADIUS_DAS_SUCCESS;
1119}
1120#else /* CONFIG_HS20 */
1121#define hostapd_das_coa NULL
1122#endif /* CONFIG_HS20 */
1123
Hai Shalomc3565922019-10-28 11:58:20 -07001124
1125#ifdef CONFIG_SQLITE
1126
1127static int db_table_exists(sqlite3 *db, const char *name)
1128{
1129 char cmd[128];
1130
1131 os_snprintf(cmd, sizeof(cmd), "SELECT 1 FROM %s;", name);
1132 return sqlite3_exec(db, cmd, NULL, NULL, NULL) == SQLITE_OK;
1133}
1134
1135
1136static int db_table_create_radius_attributes(sqlite3 *db)
1137{
1138 char *err = NULL;
1139 const char *sql =
1140 "CREATE TABLE radius_attributes("
1141 " id INTEGER PRIMARY KEY,"
1142 " sta TEXT,"
1143 " reqtype TEXT,"
1144 " attr TEXT"
1145 ");"
1146 "CREATE INDEX idx_sta_reqtype ON radius_attributes(sta,reqtype);";
1147
1148 wpa_printf(MSG_DEBUG,
1149 "Adding database table for RADIUS attribute information");
1150 if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
1151 wpa_printf(MSG_ERROR, "SQLite error: %s", err);
1152 sqlite3_free(err);
1153 return -1;
1154 }
1155
1156 return 0;
1157}
1158
1159#endif /* CONFIG_SQLITE */
1160
Dmitry Shmidt04949592012-07-19 12:16:46 -07001161#endif /* CONFIG_NO_RADIUS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001162
1163
Sunil Ravi77d572f2023-01-17 23:58:31 +00001164static int hostapd_start_beacon(struct hostapd_data *hapd,
1165 bool flush_old_stations)
1166{
1167 struct hostapd_bss_config *conf = hapd->conf;
1168
1169 if (!conf->start_disabled && ieee802_11_set_beacon(hapd) < 0)
1170 return -1;
1171
1172 if (flush_old_stations && !conf->start_disabled &&
1173 conf->broadcast_deauth) {
1174 u8 addr[ETH_ALEN];
1175
1176 /* Should any previously associated STA not have noticed that
1177 * the AP had stopped and restarted, send one more
1178 * deauthentication notification now that the AP is ready to
1179 * operate. */
1180 wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
1181 "Deauthenticate all stations at BSS start");
1182 os_memset(addr, 0xff, ETH_ALEN);
1183 hostapd_drv_sta_deauth(hapd, addr,
1184 WLAN_REASON_PREV_AUTH_NOT_VALID);
1185 }
1186
1187 if (hapd->driver && hapd->driver->set_operstate)
1188 hapd->driver->set_operstate(hapd->drv_priv, 1);
1189
1190 return 0;
1191}
1192
1193
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001194/**
1195 * hostapd_setup_bss - Per-BSS setup (initialization)
1196 * @hapd: Pointer to BSS data
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001197 * @first: Whether this BSS is the first BSS of an interface; -1 = not first,
1198 * but interface may exist
Sunil Ravi77d572f2023-01-17 23:58:31 +00001199 * @start_beacon: Whether Beacon frame template should be configured and
1200 * transmission of Beaconf rames started at this time. This is used when
1201 * MBSSID element is enabled where the information regarding all BSSes
1202 * should be retrieved before configuring the Beacon frame template. The
1203 * calling functions are responsible for configuring the Beacon frame
1204 * explicitly if this is set to false.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001205 *
1206 * This function is used to initialize all per-BSS data structures and
1207 * resources. This gets called in a loop for each BSS when an interface is
1208 * initialized. Most of the modules that are initialized here will be
1209 * deinitialized in hostapd_cleanup().
1210 */
Sunil Ravi77d572f2023-01-17 23:58:31 +00001211static int hostapd_setup_bss(struct hostapd_data *hapd, int first,
1212 bool start_beacon)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001213{
1214 struct hostapd_bss_config *conf = hapd->conf;
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07001215 u8 ssid[SSID_MAX_LEN + 1];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001216 int ssid_len, set_ssid;
1217 char force_ifname[IFNAMSIZ];
1218 u8 if_addr[ETH_ALEN];
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001219 int flush_old_stations = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001220
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001221 if (hapd->mld_first_bss)
1222 wpa_printf(MSG_DEBUG,
1223 "MLD: %s: Setting non-first BSS", __func__);
1224
Dmitry Shmidt54605472013-11-08 11:10:19 -08001225 wpa_printf(MSG_DEBUG, "%s(hapd=%p (%s), first=%d)",
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001226 __func__, hapd, conf->iface, first);
Dmitry Shmidt54605472013-11-08 11:10:19 -08001227
Dmitry Shmidt50b691d2014-05-21 14:01:45 -07001228#ifdef EAP_SERVER_TNC
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001229 if (conf->tnc && tncs_global_init() < 0) {
Dmitry Shmidt50b691d2014-05-21 14:01:45 -07001230 wpa_printf(MSG_ERROR, "Failed to initialize TNCS");
1231 return -1;
1232 }
1233#endif /* EAP_SERVER_TNC */
1234
Dmitry Shmidt54605472013-11-08 11:10:19 -08001235 if (hapd->started) {
1236 wpa_printf(MSG_ERROR, "%s: Interface %s was already started",
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001237 __func__, conf->iface);
Dmitry Shmidt54605472013-11-08 11:10:19 -08001238 return -1;
1239 }
1240 hapd->started = 1;
1241
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001242 if (!first || first == -1) {
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08001243 u8 *addr = hapd->own_addr;
1244
1245 if (!is_zero_ether_addr(conf->bssid)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001246 /* Allocate the configured BSSID. */
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001247 os_memcpy(hapd->own_addr, conf->bssid, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001248
1249 if (hostapd_mac_comp(hapd->own_addr,
1250 hapd->iface->bss[0]->own_addr) ==
1251 0) {
1252 wpa_printf(MSG_ERROR, "BSS '%s' may not have "
1253 "BSSID set to the MAC address of "
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001254 "the radio", conf->iface);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001255 return -1;
1256 }
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08001257 } else if (hapd->iconf->use_driver_iface_addr) {
1258 addr = NULL;
1259 } else {
1260 /* Allocate the next available BSSID. */
1261 do {
1262 inc_byte_array(hapd->own_addr, ETH_ALEN);
1263 } while (mac_in_conf(hapd->iconf, hapd->own_addr));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001264 }
1265
Dmitry Shmidt54605472013-11-08 11:10:19 -08001266 hapd->interface_added = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001267 if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS,
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08001268 conf->iface, addr, hapd,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001269 &hapd->drv_priv, force_ifname, if_addr,
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001270 conf->bridge[0] ? conf->bridge : NULL,
1271 first == -1)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001272 wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID="
1273 MACSTR ")", MAC2STR(hapd->own_addr));
Dmitry Shmidt3cf6f792013-12-18 13:12:19 -08001274 hapd->interface_added = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001275 return -1;
1276 }
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08001277
1278 if (!addr)
1279 os_memcpy(hapd->own_addr, if_addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001280 }
1281
1282 if (conf->wmm_enabled < 0)
Hai Shaloma20dcd72022-02-04 13:43:00 -08001283 conf->wmm_enabled = hapd->iconf->ieee80211n |
1284 hapd->iconf->ieee80211ax;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001285
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001286#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt9c175262016-03-03 10:20:07 -08001287 if (is_zero_ether_addr(conf->r1_key_holder))
1288 os_memcpy(conf->r1_key_holder, hapd->own_addr, ETH_ALEN);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001289#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt9c175262016-03-03 10:20:07 -08001290
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001291#ifdef CONFIG_MESH
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001292 if ((hapd->conf->mesh & MESH_ENABLED) && hapd->iface->mconf == NULL)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001293 flush_old_stations = 0;
1294#endif /* CONFIG_MESH */
1295
1296 if (flush_old_stations)
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001297 hostapd_flush(hapd);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001298 hostapd_set_privacy(hapd, 0);
1299
Hai Shalomfdcde762020-04-02 11:19:20 -07001300#ifdef CONFIG_WEP
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001301 if (!hostapd_drv_nl80211(hapd))
1302 hostapd_broadcast_wep_clear(hapd);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001303 if (hostapd_setup_encryption(conf->iface, hapd))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001304 return -1;
Hai Shalomfdcde762020-04-02 11:19:20 -07001305#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001306
1307 /*
1308 * Fetch the SSID from the system and use it or,
1309 * if one was specified in the config file, verify they
1310 * match.
1311 */
1312 ssid_len = hostapd_get_ssid(hapd, ssid, sizeof(ssid));
1313 if (ssid_len < 0) {
1314 wpa_printf(MSG_ERROR, "Could not read SSID from system");
1315 return -1;
1316 }
1317 if (conf->ssid.ssid_set) {
1318 /*
1319 * If SSID is specified in the config file and it differs
1320 * from what is being used then force installation of the
1321 * new SSID.
1322 */
1323 set_ssid = (conf->ssid.ssid_len != (size_t) ssid_len ||
1324 os_memcmp(conf->ssid.ssid, ssid, ssid_len) != 0);
1325 } else {
1326 /*
1327 * No SSID in the config file; just use the one we got
1328 * from the system.
1329 */
1330 set_ssid = 0;
1331 conf->ssid.ssid_len = ssid_len;
1332 os_memcpy(conf->ssid.ssid, ssid, conf->ssid.ssid_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001333 }
1334
Hai Shalomfdcde762020-04-02 11:19:20 -07001335 /*
1336 * Short SSID calculation is identical to FCS and it is defined in
1337 * IEEE P802.11-REVmd/D3.0, 9.4.2.170.3 (Calculating the Short-SSID).
1338 */
Sunil Ravi89eba102022-09-13 21:04:37 -07001339 conf->ssid.short_ssid = ieee80211_crc32(conf->ssid.ssid,
1340 conf->ssid.ssid_len);
Hai Shalomfdcde762020-04-02 11:19:20 -07001341
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001342 if (!hostapd_drv_none(hapd)) {
Hai Shalomfdcde762020-04-02 11:19:20 -07001343 wpa_printf(MSG_DEBUG, "Using interface %s with hwaddr " MACSTR
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001344 " and ssid \"%s\"",
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001345 conf->iface, MAC2STR(hapd->own_addr),
1346 wpa_ssid_txt(conf->ssid.ssid, conf->ssid.ssid_len));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001347 }
1348
1349 if (hostapd_setup_wpa_psk(conf)) {
1350 wpa_printf(MSG_ERROR, "WPA-PSK setup failed.");
1351 return -1;
1352 }
1353
1354 /* Set SSID for the kernel driver (to be used in beacon and probe
1355 * response frames) */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001356 if (set_ssid && hostapd_set_ssid(hapd, conf->ssid.ssid,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001357 conf->ssid.ssid_len)) {
1358 wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver");
1359 return -1;
1360 }
1361
Dmitry Shmidt818ea482014-03-10 13:15:21 -07001362 if (wpa_debug_level <= MSG_MSGDUMP)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001363 conf->radius->msg_dumps = 1;
1364#ifndef CONFIG_NO_RADIUS
Hai Shalomc3565922019-10-28 11:58:20 -07001365
1366#ifdef CONFIG_SQLITE
1367 if (conf->radius_req_attr_sqlite) {
1368 if (sqlite3_open(conf->radius_req_attr_sqlite,
1369 &hapd->rad_attr_db)) {
1370 wpa_printf(MSG_ERROR, "Could not open SQLite file '%s'",
1371 conf->radius_req_attr_sqlite);
1372 return -1;
1373 }
1374
1375 wpa_printf(MSG_DEBUG, "Opening RADIUS attribute database: %s",
1376 conf->radius_req_attr_sqlite);
1377 if (!db_table_exists(hapd->rad_attr_db, "radius_attributes") &&
1378 db_table_create_radius_attributes(hapd->rad_attr_db) < 0)
1379 return -1;
1380 }
1381#endif /* CONFIG_SQLITE */
1382
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001383 if (!hapd->mld_first_bss) {
1384 hapd->radius = radius_client_init(hapd, conf->radius);
1385 if (!hapd->radius) {
1386 wpa_printf(MSG_ERROR,
1387 "RADIUS client initialization failed.");
Dmitry Shmidt04949592012-07-19 12:16:46 -07001388 return -1;
1389 }
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001390
1391 if (conf->radius_das_port) {
1392 struct radius_das_conf das_conf;
1393
1394 os_memset(&das_conf, 0, sizeof(das_conf));
1395 das_conf.port = conf->radius_das_port;
1396 das_conf.shared_secret = conf->radius_das_shared_secret;
1397 das_conf.shared_secret_len =
1398 conf->radius_das_shared_secret_len;
1399 das_conf.client_addr = &conf->radius_das_client_addr;
1400 das_conf.time_window = conf->radius_das_time_window;
1401 das_conf.require_event_timestamp =
1402 conf->radius_das_require_event_timestamp;
1403 das_conf.require_message_authenticator =
1404 conf->radius_das_require_message_authenticator;
1405 das_conf.ctx = hapd;
1406 das_conf.disconnect = hostapd_das_disconnect;
1407 das_conf.coa = hostapd_das_coa;
1408 hapd->radius_das = radius_das_init(&das_conf);
1409 if (!hapd->radius_das) {
1410 wpa_printf(MSG_ERROR,
1411 "RADIUS DAS initialization failed.");
1412 return -1;
1413 }
1414 }
1415 } else {
1416 wpa_printf(MSG_DEBUG,
1417 "MLD: Using RADIUS client of the first BSS");
1418 hapd->radius = hapd->mld_first_bss->radius;
1419 hapd->radius_das = hapd->mld_first_bss->radius_das;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001420 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001421#endif /* CONFIG_NO_RADIUS */
1422
1423 if (hostapd_acl_init(hapd)) {
1424 wpa_printf(MSG_ERROR, "ACL initialization failed.");
1425 return -1;
1426 }
1427 if (hostapd_init_wps(hapd, conf))
1428 return -1;
1429
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001430#ifdef CONFIG_DPP
1431 hapd->gas = gas_query_ap_init(hapd, hapd->msg_ctx);
1432 if (!hapd->gas)
1433 return -1;
1434 if (hostapd_dpp_init(hapd))
1435 return -1;
1436#endif /* CONFIG_DPP */
1437
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001438 if (authsrv_init(hapd) < 0)
1439 return -1;
1440
1441 if (ieee802_1x_init(hapd)) {
1442 wpa_printf(MSG_ERROR, "IEEE 802.1X initialization failed.");
1443 return -1;
1444 }
1445
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001446 if ((conf->wpa || conf->osen) && hostapd_setup_wpa(hapd))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001447 return -1;
1448
1449 if (accounting_init(hapd)) {
1450 wpa_printf(MSG_ERROR, "Accounting initialization failed.");
1451 return -1;
1452 }
1453
Dmitry Shmidt04949592012-07-19 12:16:46 -07001454#ifdef CONFIG_INTERWORKING
1455 if (gas_serv_init(hapd)) {
1456 wpa_printf(MSG_ERROR, "GAS server initialization failed");
1457 return -1;
1458 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07001459
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001460 if (conf->qos_map_set_len &&
1461 hostapd_drv_set_qos_map(hapd, conf->qos_map_set,
1462 conf->qos_map_set_len)) {
1463 wpa_printf(MSG_ERROR, "Failed to initialize QoS Map");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001464 return -1;
1465 }
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001466#endif /* CONFIG_INTERWORKING */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001467
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001468 if (conf->bss_load_update_period && bss_load_update_init(hapd)) {
1469 wpa_printf(MSG_ERROR, "BSS Load initialization failed");
1470 return -1;
1471 }
1472
Sunil Ravi036cec52023-03-29 11:35:17 -07001473 if (conf->bridge[0]) {
1474 /* Set explicitly configured bridge parameters that might have
1475 * been lost if the interface has been removed out of the
1476 * bridge. */
1477
1478 /* multicast to unicast on bridge ports */
1479 if (conf->bridge_multicast_to_unicast)
1480 hostapd_drv_br_port_set_attr(
1481 hapd, DRV_BR_PORT_ATTR_MCAST2UCAST, 1);
1482
1483 /* hairpin mode */
1484 if (conf->bridge_hairpin)
1485 hostapd_drv_br_port_set_attr(
1486 hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE, 1);
1487 }
1488
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001489 if (conf->proxy_arp) {
1490 if (x_snoop_init(hapd)) {
1491 wpa_printf(MSG_ERROR,
1492 "Generic snooping infrastructure initialization failed");
1493 return -1;
1494 }
1495
1496 if (dhcp_snoop_init(hapd)) {
1497 wpa_printf(MSG_ERROR,
1498 "DHCP snooping initialization failed");
1499 return -1;
1500 }
1501
1502 if (ndisc_snoop_init(hapd)) {
1503 wpa_printf(MSG_ERROR,
1504 "Neighbor Discovery snooping initialization failed");
1505 return -1;
1506 }
1507 }
1508
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001509 if (!hostapd_drv_none(hapd) && vlan_init(hapd)) {
1510 wpa_printf(MSG_ERROR, "VLAN initialization failed.");
1511 return -1;
1512 }
1513
Sunil Ravi640215c2023-06-28 23:08:09 +00001514 if (start_beacon && hostapd_start_beacon(hapd, flush_old_stations) < 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001515 return -1;
1516
Sunil Ravi640215c2023-06-28 23:08:09 +00001517 if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0)
1518 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001519
1520 return 0;
1521}
1522
1523
1524static void hostapd_tx_queue_params(struct hostapd_iface *iface)
1525{
1526 struct hostapd_data *hapd = iface->bss[0];
1527 int i;
1528 struct hostapd_tx_queue_params *p;
1529
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001530#ifdef CONFIG_MESH
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001531 if ((hapd->conf->mesh & MESH_ENABLED) && iface->mconf == NULL)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001532 return;
1533#endif /* CONFIG_MESH */
1534
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001535 for (i = 0; i < NUM_TX_QUEUES; i++) {
1536 p = &iface->conf->tx_queue[i];
1537
1538 if (hostapd_set_tx_queue_params(hapd, i, p->aifs, p->cwmin,
1539 p->cwmax, p->burst)) {
1540 wpa_printf(MSG_DEBUG, "Failed to set TX queue "
1541 "parameters for queue %d.", i);
1542 /* Continue anyway */
1543 }
1544 }
1545}
1546
1547
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07001548static int hostapd_set_acl_list(struct hostapd_data *hapd,
1549 struct mac_acl_entry *mac_acl,
1550 int n_entries, u8 accept_acl)
1551{
1552 struct hostapd_acl_params *acl_params;
1553 int i, err;
1554
1555 acl_params = os_zalloc(sizeof(*acl_params) +
1556 (n_entries * sizeof(acl_params->mac_acl[0])));
1557 if (!acl_params)
1558 return -ENOMEM;
1559
1560 for (i = 0; i < n_entries; i++)
1561 os_memcpy(acl_params->mac_acl[i].addr, mac_acl[i].addr,
1562 ETH_ALEN);
1563
1564 acl_params->acl_policy = accept_acl;
1565 acl_params->num_mac_acl = n_entries;
1566
1567 err = hostapd_drv_set_acl(hapd, acl_params);
1568
1569 os_free(acl_params);
1570
1571 return err;
1572}
1573
1574
Sunil Ravia04bd252022-05-02 22:54:18 -07001575int hostapd_set_acl(struct hostapd_data *hapd)
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07001576{
1577 struct hostapd_config *conf = hapd->iconf;
Sunil Ravia04bd252022-05-02 22:54:18 -07001578 int err = 0;
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07001579 u8 accept_acl;
1580
1581 if (hapd->iface->drv_max_acl_mac_addrs == 0)
Sunil Ravia04bd252022-05-02 22:54:18 -07001582 return 0;
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07001583
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001584 if (conf->bss[0]->macaddr_acl == DENY_UNLESS_ACCEPTED) {
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07001585 accept_acl = 1;
1586 err = hostapd_set_acl_list(hapd, conf->bss[0]->accept_mac,
1587 conf->bss[0]->num_accept_mac,
1588 accept_acl);
1589 if (err) {
1590 wpa_printf(MSG_DEBUG, "Failed to set accept acl");
Sunil Ravia04bd252022-05-02 22:54:18 -07001591 return -1;
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07001592 }
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001593 } else if (conf->bss[0]->macaddr_acl == ACCEPT_UNLESS_DENIED) {
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07001594 accept_acl = 0;
1595 err = hostapd_set_acl_list(hapd, conf->bss[0]->deny_mac,
1596 conf->bss[0]->num_deny_mac,
1597 accept_acl);
1598 if (err) {
1599 wpa_printf(MSG_DEBUG, "Failed to set deny acl");
Sunil Ravia04bd252022-05-02 22:54:18 -07001600 return -1;
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07001601 }
1602 }
Sunil Ravia04bd252022-05-02 22:54:18 -07001603 return err;
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07001604}
1605
1606
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001607static int start_ctrl_iface_bss(struct hostapd_data *hapd)
1608{
1609 if (!hapd->iface->interfaces ||
1610 !hapd->iface->interfaces->ctrl_iface_init)
1611 return 0;
1612
1613 if (hapd->iface->interfaces->ctrl_iface_init(hapd)) {
1614 wpa_printf(MSG_ERROR,
1615 "Failed to setup control interface for %s",
1616 hapd->conf->iface);
1617 return -1;
1618 }
1619
1620 return 0;
1621}
1622
1623
1624static int start_ctrl_iface(struct hostapd_iface *iface)
1625{
1626 size_t i;
1627
1628 if (!iface->interfaces || !iface->interfaces->ctrl_iface_init)
1629 return 0;
1630
1631 for (i = 0; i < iface->num_bss; i++) {
1632 struct hostapd_data *hapd = iface->bss[i];
1633 if (iface->interfaces->ctrl_iface_init(hapd)) {
1634 wpa_printf(MSG_ERROR,
1635 "Failed to setup control interface for %s",
1636 hapd->conf->iface);
1637 return -1;
1638 }
1639 }
1640
1641 return 0;
1642}
1643
1644
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001645/* When NO_IR flag is set and AP is stopped, clean up BSS parameters without
1646 * deinitializing the driver and the control interfaces. A subsequent
1647 * REG_CHANGE event can bring the AP back up.
1648 */
1649static void hostapd_no_ir_cleanup(struct hostapd_data *bss)
1650{
1651 hostapd_bss_deinit_no_free(bss);
1652 hostapd_free_hapd_data(bss);
1653 hostapd_cleanup_iface_partial(bss->iface);
1654}
1655
1656
1657static int hostapd_no_ir_channel_list_updated(struct hostapd_iface *iface,
1658 void *ctx)
1659{
1660 bool all_no_ir, is_6ghz;
1661 int i, j;
1662 struct hostapd_hw_modes *mode = NULL;
1663
1664 if (hostapd_get_hw_features(iface))
1665 return 0;
1666
1667 all_no_ir = true;
1668 is_6ghz = false;
1669
1670 for (i = 0; i < iface->num_hw_features; i++) {
1671 mode = &iface->hw_features[i];
1672
1673 if (mode->mode == iface->conf->hw_mode) {
1674 if (iface->freq > 0 &&
1675 !hw_mode_get_channel(mode, iface->freq, NULL)) {
1676 mode = NULL;
1677 continue;
1678 }
1679
1680 for (j = 0; j < mode->num_channels; j++) {
1681 if (!(mode->channels[j].flag &
1682 HOSTAPD_CHAN_NO_IR))
1683 all_no_ir = false;
1684
1685 if (is_6ghz_freq(mode->channels[j].freq))
1686 is_6ghz = true;
1687 }
1688 break;
1689 }
1690 }
1691
1692 if (!mode || !is_6ghz)
1693 return 0;
1694 iface->current_mode = mode;
1695
1696 if (iface->state == HAPD_IFACE_ENABLED) {
1697 if (!all_no_ir) {
1698 struct hostapd_channel_data *chan;
1699
1700 chan = hw_get_channel_freq(iface->current_mode->mode,
1701 iface->freq, NULL,
1702 iface->hw_features,
1703 iface->num_hw_features);
1704
1705 if (!chan) {
1706 wpa_printf(MSG_ERROR,
1707 "NO_IR: Could not derive chan from freq");
1708 return 0;
1709 }
1710
1711 if (!(chan->flag & HOSTAPD_CHAN_NO_IR))
1712 return 0;
1713 wpa_printf(MSG_DEBUG,
1714 "NO_IR: The current channel has NO_IR flag now, stop AP.");
1715 } else {
1716 wpa_printf(MSG_DEBUG,
1717 "NO_IR: All chan in new chanlist are NO_IR, stop AP.");
1718 }
1719
1720 hostapd_set_state(iface, HAPD_IFACE_NO_IR);
1721 iface->is_no_ir = true;
1722 hostapd_drv_stop_ap(iface->bss[0]);
1723 hostapd_no_ir_cleanup(iface->bss[0]);
1724 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_NO_IR);
1725 } else if (iface->state == HAPD_IFACE_NO_IR) {
1726 if (all_no_ir) {
1727 wpa_printf(MSG_DEBUG,
1728 "NO_IR: AP in NO_IR and all chan in the new chanlist are NO_IR. Ignore");
1729 return 0;
1730 }
1731
1732 if (!iface->conf->acs) {
1733 struct hostapd_channel_data *chan;
1734
1735 chan = hw_get_channel_freq(iface->current_mode->mode,
1736 iface->freq, NULL,
1737 iface->hw_features,
1738 iface->num_hw_features);
1739 if (!chan) {
1740 wpa_printf(MSG_ERROR,
1741 "NO_IR: Could not derive chan from freq");
1742 return 0;
1743 }
1744
1745 /* If the last operating channel is NO_IR, trigger ACS.
1746 */
1747 if (chan->flag & HOSTAPD_CHAN_NO_IR) {
1748 iface->freq = 0;
1749 iface->conf->channel = 0;
1750 if (acs_init(iface) != HOSTAPD_CHAN_ACS)
1751 wpa_printf(MSG_ERROR,
1752 "NO_IR: Could not start ACS");
1753 return 0;
1754 }
1755 }
1756
1757 setup_interface2(iface);
1758 }
1759
1760 return 0;
1761}
1762
1763
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001764static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx)
1765{
1766 struct hostapd_iface *iface = eloop_ctx;
1767
1768 if (!iface->wait_channel_update) {
1769 wpa_printf(MSG_INFO, "Channel list update timeout, but interface was not waiting for it");
1770 return;
1771 }
1772
1773 /*
1774 * It is possible that the existing channel list is acceptable, so try
1775 * to proceed.
1776 */
1777 wpa_printf(MSG_DEBUG, "Channel list update timeout - try to continue anyway");
1778 setup_interface2(iface);
1779}
1780
1781
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001782void hostapd_channel_list_updated(struct hostapd_iface *iface, int initiator)
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001783{
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001784 if (initiator == REGDOM_SET_BY_DRIVER) {
1785 hostapd_for_each_interface(iface->interfaces,
1786 hostapd_no_ir_channel_list_updated,
1787 NULL);
1788 return;
1789 }
1790
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001791 if (!iface->wait_channel_update || initiator != REGDOM_SET_BY_USER)
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001792 return;
1793
1794 wpa_printf(MSG_DEBUG, "Channel list updated - continue setup");
1795 eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
1796 setup_interface2(iface);
1797}
1798
1799
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001800static int setup_interface(struct hostapd_iface *iface)
1801{
1802 struct hostapd_data *hapd = iface->bss[0];
1803 size_t i;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001804
Dmitry Shmidta38abf92014-03-06 13:38:44 -08001805 /*
1806 * It is possible that setup_interface() is called after the interface
1807 * was disabled etc., in which case driver_ap_teardown is possibly set
1808 * to 1. Clear it here so any other key/station deletion, which is not
1809 * part of a teardown flow, would also call the relevant driver
1810 * callbacks.
1811 */
1812 iface->driver_ap_teardown = 0;
1813
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001814 if (!iface->phy[0]) {
1815 const char *phy = hostapd_drv_get_radio_name(hapd);
1816 if (phy) {
1817 wpa_printf(MSG_DEBUG, "phy: %s", phy);
1818 os_strlcpy(iface->phy, phy, sizeof(iface->phy));
1819 }
1820 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001821
1822 /*
1823 * Make sure that all BSSes get configured with a pointer to the same
1824 * driver interface.
1825 */
1826 for (i = 1; i < iface->num_bss; i++) {
1827 iface->bss[i]->driver = hapd->driver;
1828 iface->bss[i]->drv_priv = hapd->drv_priv;
1829 }
1830
1831 if (hostapd_validate_bssid_configuration(iface))
1832 return -1;
1833
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001834 /*
1835 * Initialize control interfaces early to allow external monitoring of
1836 * channel setup operations that may take considerable amount of time
1837 * especially for DFS cases.
1838 */
1839 if (start_ctrl_iface(iface))
1840 return -1;
1841
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001842 if (hapd->iconf->country[0] && hapd->iconf->country[1]) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001843 char country[4], previous_country[4];
1844
1845 hostapd_set_state(iface, HAPD_IFACE_COUNTRY_UPDATE);
1846 if (hostapd_get_country(hapd, previous_country) < 0)
1847 previous_country[0] = '\0';
1848
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001849 os_memcpy(country, hapd->iconf->country, 3);
1850 country[3] = '\0';
1851 if (hostapd_set_country(hapd, country) < 0) {
1852 wpa_printf(MSG_ERROR, "Failed to set country code");
1853 return -1;
1854 }
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001855
1856 wpa_printf(MSG_DEBUG, "Previous country code %s, new country code %s",
1857 previous_country, country);
1858
1859 if (os_strncmp(previous_country, country, 2) != 0) {
1860 wpa_printf(MSG_DEBUG, "Continue interface setup after channel list update");
1861 iface->wait_channel_update = 1;
Dmitry Shmidt97672262014-02-03 13:02:54 -08001862 eloop_register_timeout(5, 0,
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001863 channel_list_update_timeout,
1864 iface, NULL);
1865 return 0;
1866 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001867 }
1868
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001869 return setup_interface2(iface);
1870}
1871
1872
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001873static int configured_fixed_chan_to_freq(struct hostapd_iface *iface)
1874{
1875 int freq, i, j;
1876
1877 if (!iface->conf->channel)
1878 return 0;
1879 if (iface->conf->op_class) {
1880 freq = ieee80211_chan_to_freq(NULL, iface->conf->op_class,
1881 iface->conf->channel);
1882 if (freq < 0) {
1883 wpa_printf(MSG_INFO,
1884 "Could not convert op_class %u channel %u to operating frequency",
1885 iface->conf->op_class, iface->conf->channel);
1886 return -1;
1887 }
1888 iface->freq = freq;
1889 return 0;
1890 }
1891
1892 /* Old configurations using only 2.4/5/60 GHz bands may not specify the
1893 * op_class parameter. Select a matching channel from the configured
1894 * mode using the channel parameter for these cases.
1895 */
1896 for (j = 0; j < iface->num_hw_features; j++) {
1897 struct hostapd_hw_modes *mode = &iface->hw_features[j];
1898
1899 if (iface->conf->hw_mode != HOSTAPD_MODE_IEEE80211ANY &&
1900 iface->conf->hw_mode != mode->mode)
1901 continue;
1902 for (i = 0; i < mode->num_channels; i++) {
1903 struct hostapd_channel_data *chan = &mode->channels[i];
1904
1905 if (chan->chan == iface->conf->channel &&
1906 !is_6ghz_freq(chan->freq)) {
1907 iface->freq = chan->freq;
1908 return 0;
1909 }
1910 }
1911 }
1912
1913 wpa_printf(MSG_INFO, "Could not determine operating frequency");
1914 return -1;
1915}
1916
1917
Hai Shaloma20dcd72022-02-04 13:43:00 -08001918static void hostapd_set_6ghz_sec_chan(struct hostapd_iface *iface)
1919{
Sunil Ravi640215c2023-06-28 23:08:09 +00001920 int bw;
Hai Shaloma20dcd72022-02-04 13:43:00 -08001921
1922 if (!is_6ghz_op_class(iface->conf->op_class))
1923 return;
1924
Sunil Ravi640215c2023-06-28 23:08:09 +00001925 bw = op_class_to_bandwidth(iface->conf->op_class);
Hai Shaloma20dcd72022-02-04 13:43:00 -08001926 /* Assign the secondary channel if absent in config for
1927 * bandwidths > 20 MHz */
Sunil Ravi640215c2023-06-28 23:08:09 +00001928 if (bw >= 40 && !iface->conf->secondary_channel) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08001929 if (((iface->conf->channel - 1) / 4) % 2)
1930 iface->conf->secondary_channel = -1;
1931 else
1932 iface->conf->secondary_channel = 1;
1933 }
1934}
1935
1936
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001937static int setup_interface2(struct hostapd_iface *iface)
1938{
1939 iface->wait_channel_update = 0;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001940 iface->is_no_ir = false;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001941
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001942 if (hostapd_get_hw_features(iface)) {
1943 /* Not all drivers support this yet, so continue without hw
1944 * feature data. */
1945 } else {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001946 int ret;
1947
Sunil Ravi036cec52023-03-29 11:35:17 -07001948 if (iface->conf->acs) {
1949 iface->freq = 0;
1950 iface->conf->channel = 0;
1951 }
1952
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001953 ret = configured_fixed_chan_to_freq(iface);
1954 if (ret < 0)
1955 goto fail;
1956
1957 if (iface->conf->op_class) {
Sunil8cd6f4d2022-06-28 18:40:46 +00001958 enum oper_chan_width ch_width;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001959
1960 ch_width = op_class_to_ch_width(iface->conf->op_class);
1961 hostapd_set_oper_chwidth(iface->conf, ch_width);
Hai Shaloma20dcd72022-02-04 13:43:00 -08001962 hostapd_set_6ghz_sec_chan(iface);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001963 }
1964
1965 ret = hostapd_select_hw_mode(iface);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001966 if (ret < 0) {
1967 wpa_printf(MSG_ERROR, "Could not select hw_mode and "
1968 "channel. (%d)", ret);
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07001969 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001970 }
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07001971 if (ret == 1) {
1972 wpa_printf(MSG_DEBUG, "Interface initialization will be completed in a callback (ACS)");
1973 return 0;
1974 }
Hai Shalomc3565922019-10-28 11:58:20 -07001975 ret = hostapd_check_edmg_capab(iface);
1976 if (ret < 0)
1977 goto fail;
Hai Shalom60840252021-02-19 19:02:11 -08001978 ret = hostapd_check_he_6ghz_capab(iface);
1979 if (ret < 0)
1980 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001981 ret = hostapd_check_ht_capab(iface);
1982 if (ret < 0)
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07001983 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001984 if (ret == 1) {
1985 wpa_printf(MSG_DEBUG, "Interface initialization will "
1986 "be completed in a callback");
1987 return 0;
1988 }
Dmitry Shmidt051af732013-10-22 13:52:46 -07001989
1990 if (iface->conf->ieee80211h)
1991 wpa_printf(MSG_DEBUG, "DFS support is enabled");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001992 }
1993 return hostapd_setup_interface_complete(iface, 0);
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07001994
1995fail:
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001996 if (iface->is_no_ir) {
1997 /* If AP is in NO_IR state, it can be reenabled by the driver
1998 * regulatory update and EVENT_CHANNEL_LIST_CHANGED. */
1999 hostapd_set_state(iface, HAPD_IFACE_NO_IR);
2000 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_NO_IR);
2001 return 0;
2002 }
2003
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07002004 hostapd_set_state(iface, HAPD_IFACE_DISABLED);
2005 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
2006 if (iface->interfaces && iface->interfaces->terminate_on_error)
2007 eloop_terminate();
2008 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002009}
2010
2011
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002012#ifdef CONFIG_FST
2013
2014static const u8 * fst_hostapd_get_bssid_cb(void *ctx)
2015{
2016 struct hostapd_data *hapd = ctx;
2017
2018 return hapd->own_addr;
2019}
2020
2021
2022static void fst_hostapd_get_channel_info_cb(void *ctx,
2023 enum hostapd_hw_mode *hw_mode,
2024 u8 *channel)
2025{
2026 struct hostapd_data *hapd = ctx;
2027
2028 *hw_mode = ieee80211_freq_to_chan(hapd->iface->freq, channel);
2029}
2030
2031
Sunil8cd6f4d2022-06-28 18:40:46 +00002032static int fst_hostapd_get_hw_modes_cb(void *ctx,
2033 struct hostapd_hw_modes **modes)
2034{
2035 struct hostapd_data *hapd = ctx;
2036
2037 *modes = hapd->iface->hw_features;
2038 return hapd->iface->num_hw_features;
2039}
2040
2041
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002042static void fst_hostapd_set_ies_cb(void *ctx, const struct wpabuf *fst_ies)
2043{
2044 struct hostapd_data *hapd = ctx;
2045
2046 if (hapd->iface->fst_ies != fst_ies) {
2047 hapd->iface->fst_ies = fst_ies;
2048 if (ieee802_11_set_beacon(hapd))
2049 wpa_printf(MSG_WARNING, "FST: Cannot set beacon");
2050 }
2051}
2052
2053
2054static int fst_hostapd_send_action_cb(void *ctx, const u8 *da,
2055 struct wpabuf *buf)
2056{
2057 struct hostapd_data *hapd = ctx;
2058
2059 return hostapd_drv_send_action(hapd, hapd->iface->freq, 0, da,
2060 wpabuf_head(buf), wpabuf_len(buf));
2061}
2062
2063
2064static const struct wpabuf * fst_hostapd_get_mb_ie_cb(void *ctx, const u8 *addr)
2065{
2066 struct hostapd_data *hapd = ctx;
2067 struct sta_info *sta = ap_get_sta(hapd, addr);
2068
2069 return sta ? sta->mb_ies : NULL;
2070}
2071
2072
2073static void fst_hostapd_update_mb_ie_cb(void *ctx, const u8 *addr,
2074 const u8 *buf, size_t size)
2075{
2076 struct hostapd_data *hapd = ctx;
2077 struct sta_info *sta = ap_get_sta(hapd, addr);
2078
2079 if (sta) {
2080 struct mb_ies_info info;
2081
2082 if (!mb_ies_info_by_ies(&info, buf, size)) {
2083 wpabuf_free(sta->mb_ies);
2084 sta->mb_ies = mb_ies_by_info(&info);
2085 }
2086 }
2087}
2088
2089
2090static const u8 * fst_hostapd_get_sta(struct fst_get_peer_ctx **get_ctx,
Hai Shalome21d4e82020-04-29 16:34:06 -07002091 bool mb_only)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002092{
2093 struct sta_info *s = (struct sta_info *) *get_ctx;
2094
2095 if (mb_only) {
2096 for (; s && !s->mb_ies; s = s->next)
2097 ;
2098 }
2099
2100 if (s) {
2101 *get_ctx = (struct fst_get_peer_ctx *) s->next;
2102
2103 return s->addr;
2104 }
2105
2106 *get_ctx = NULL;
2107 return NULL;
2108}
2109
2110
2111static const u8 * fst_hostapd_get_peer_first(void *ctx,
2112 struct fst_get_peer_ctx **get_ctx,
Hai Shalome21d4e82020-04-29 16:34:06 -07002113 bool mb_only)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002114{
2115 struct hostapd_data *hapd = ctx;
2116
2117 *get_ctx = (struct fst_get_peer_ctx *) hapd->sta_list;
2118
2119 return fst_hostapd_get_sta(get_ctx, mb_only);
2120}
2121
2122
2123static const u8 * fst_hostapd_get_peer_next(void *ctx,
2124 struct fst_get_peer_ctx **get_ctx,
Hai Shalome21d4e82020-04-29 16:34:06 -07002125 bool mb_only)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002126{
2127 return fst_hostapd_get_sta(get_ctx, mb_only);
2128}
2129
2130
2131void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd,
2132 struct fst_wpa_obj *iface_obj)
2133{
Sunil8cd6f4d2022-06-28 18:40:46 +00002134 os_memset(iface_obj, 0, sizeof(*iface_obj));
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002135 iface_obj->ctx = hapd;
2136 iface_obj->get_bssid = fst_hostapd_get_bssid_cb;
2137 iface_obj->get_channel_info = fst_hostapd_get_channel_info_cb;
Sunil8cd6f4d2022-06-28 18:40:46 +00002138 iface_obj->get_hw_modes = fst_hostapd_get_hw_modes_cb;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002139 iface_obj->set_ies = fst_hostapd_set_ies_cb;
2140 iface_obj->send_action = fst_hostapd_send_action_cb;
2141 iface_obj->get_mb_ie = fst_hostapd_get_mb_ie_cb;
2142 iface_obj->update_mb_ie = fst_hostapd_update_mb_ie_cb;
2143 iface_obj->get_peer_first = fst_hostapd_get_peer_first;
2144 iface_obj->get_peer_next = fst_hostapd_get_peer_next;
2145}
2146
2147#endif /* CONFIG_FST */
2148
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002149#ifdef CONFIG_OWE
2150
2151static int hostapd_owe_iface_iter(struct hostapd_iface *iface, void *ctx)
2152{
2153 struct hostapd_data *hapd = ctx;
2154 size_t i;
2155
2156 for (i = 0; i < iface->num_bss; i++) {
2157 struct hostapd_data *bss = iface->bss[i];
2158
2159 if (os_strcmp(hapd->conf->owe_transition_ifname,
2160 bss->conf->iface) != 0)
2161 continue;
2162
2163 wpa_printf(MSG_DEBUG,
2164 "OWE: ifname=%s found transition mode ifname=%s BSSID "
2165 MACSTR " SSID %s",
2166 hapd->conf->iface, bss->conf->iface,
2167 MAC2STR(bss->own_addr),
2168 wpa_ssid_txt(bss->conf->ssid.ssid,
2169 bss->conf->ssid.ssid_len));
2170 if (!bss->conf->ssid.ssid_set || !bss->conf->ssid.ssid_len ||
2171 is_zero_ether_addr(bss->own_addr))
2172 continue;
2173
2174 os_memcpy(hapd->conf->owe_transition_bssid, bss->own_addr,
2175 ETH_ALEN);
2176 os_memcpy(hapd->conf->owe_transition_ssid,
2177 bss->conf->ssid.ssid, bss->conf->ssid.ssid_len);
2178 hapd->conf->owe_transition_ssid_len = bss->conf->ssid.ssid_len;
2179 wpa_printf(MSG_DEBUG,
2180 "OWE: Copied transition mode information");
2181 return 1;
2182 }
2183
2184 return 0;
2185}
2186
2187
2188int hostapd_owe_trans_get_info(struct hostapd_data *hapd)
2189{
2190 if (hapd->conf->owe_transition_ssid_len > 0 &&
2191 !is_zero_ether_addr(hapd->conf->owe_transition_bssid))
2192 return 0;
2193
2194 /* Find transition mode SSID/BSSID information from a BSS operated by
2195 * this hostapd instance. */
2196 if (!hapd->iface->interfaces ||
2197 !hapd->iface->interfaces->for_each_interface)
2198 return hostapd_owe_iface_iter(hapd->iface, hapd);
2199 else
2200 return hapd->iface->interfaces->for_each_interface(
2201 hapd->iface->interfaces, hostapd_owe_iface_iter, hapd);
2202}
2203
2204
2205static int hostapd_owe_iface_iter2(struct hostapd_iface *iface, void *ctx)
2206{
2207 size_t i;
2208
2209 for (i = 0; i < iface->num_bss; i++) {
2210 struct hostapd_data *bss = iface->bss[i];
2211 int res;
2212
2213 if (!bss->conf->owe_transition_ifname[0])
2214 continue;
Hai Shalom899fcc72020-10-19 14:38:18 -07002215 if (bss->iface->state != HAPD_IFACE_ENABLED) {
2216 wpa_printf(MSG_DEBUG,
2217 "OWE: Interface %s state %s - defer beacon update",
2218 bss->conf->iface,
2219 hostapd_state_text(bss->iface->state));
2220 continue;
2221 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002222 res = hostapd_owe_trans_get_info(bss);
2223 if (res == 0)
2224 continue;
2225 wpa_printf(MSG_DEBUG,
2226 "OWE: Matching transition mode interface enabled - update beacon data for %s",
2227 bss->conf->iface);
2228 ieee802_11_set_beacon(bss);
2229 }
2230
2231 return 0;
2232}
2233
2234#endif /* CONFIG_OWE */
2235
2236
2237static void hostapd_owe_update_trans(struct hostapd_iface *iface)
2238{
2239#ifdef CONFIG_OWE
2240 /* Check whether the enabled BSS can complete OWE transition mode
2241 * configuration for any pending interface. */
2242 if (!iface->interfaces ||
2243 !iface->interfaces->for_each_interface)
2244 hostapd_owe_iface_iter2(iface, NULL);
2245 else
2246 iface->interfaces->for_each_interface(
2247 iface->interfaces, hostapd_owe_iface_iter2, NULL);
2248#endif /* CONFIG_OWE */
2249}
2250
2251
Roshan Pius3a1667e2018-07-03 15:17:14 -07002252static void hostapd_interface_setup_failure_handler(void *eloop_ctx,
2253 void *timeout_ctx)
2254{
2255 struct hostapd_iface *iface = eloop_ctx;
2256 struct hostapd_data *hapd;
2257
2258 if (iface->num_bss < 1 || !iface->bss || !iface->bss[0])
2259 return;
2260 hapd = iface->bss[0];
2261 if (hapd->setup_complete_cb)
2262 hapd->setup_complete_cb(hapd->setup_complete_cb_ctx);
2263}
2264
2265
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002266static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
2267 int err)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002268{
2269 struct hostapd_data *hapd = iface->bss[0];
2270 size_t j;
2271 u8 *prev_addr;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002272 int delay_apply_cfg = 0;
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08002273 int res_dfs_offload = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002274
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07002275 if (err)
2276 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002277
2278 wpa_printf(MSG_DEBUG, "Completing interface initialization");
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002279 if (iface->freq) {
Dmitry Shmidt051af732013-10-22 13:52:46 -07002280#ifdef NEED_AP_MLME
2281 int res;
2282#endif /* NEED_AP_MLME */
2283
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002284 wpa_printf(MSG_DEBUG, "Mode: %s Channel: %d "
2285 "Frequency: %d MHz",
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002286 hostapd_hw_mode_txt(iface->conf->hw_mode),
2287 iface->conf->channel, iface->freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002288
Dmitry Shmidt051af732013-10-22 13:52:46 -07002289#ifdef NEED_AP_MLME
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002290 /* Handle DFS only if it is not offloaded to the driver */
2291 if (!(iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)) {
2292 /* Check DFS */
2293 res = hostapd_handle_dfs(iface);
2294 if (res <= 0) {
2295 if (res < 0)
2296 goto fail;
2297 return res;
2298 }
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08002299 } else {
2300 /* If DFS is offloaded to the driver */
2301 res_dfs_offload = hostapd_handle_dfs_offload(iface);
2302 if (res_dfs_offload <= 0) {
2303 if (res_dfs_offload < 0)
2304 goto fail;
2305 } else {
2306 wpa_printf(MSG_DEBUG,
2307 "Proceed with AP/channel setup");
2308 /*
2309 * If this is a DFS channel, move to completing
2310 * AP setup.
2311 */
2312 if (res_dfs_offload == 1)
2313 goto dfs_offload;
2314 /* Otherwise fall through. */
2315 }
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07002316 }
Dmitry Shmidt051af732013-10-22 13:52:46 -07002317#endif /* NEED_AP_MLME */
2318
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002319#ifdef CONFIG_MESH
2320 if (iface->mconf != NULL) {
2321 wpa_printf(MSG_DEBUG,
2322 "%s: Mesh configuration will be applied while joining the mesh network",
2323 iface->bss[0]->conf->iface);
2324 delay_apply_cfg = 1;
2325 }
2326#endif /* CONFIG_MESH */
2327
2328 if (!delay_apply_cfg &&
2329 hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002330 hapd->iconf->channel,
Hai Shalomc3565922019-10-28 11:58:20 -07002331 hapd->iconf->enable_edmg,
2332 hapd->iconf->edmg_channel,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002333 hapd->iconf->ieee80211n,
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002334 hapd->iconf->ieee80211ac,
Hai Shalom81f62d82019-07-22 12:10:00 -07002335 hapd->iconf->ieee80211ax,
Sunil Ravia04bd252022-05-02 22:54:18 -07002336 hapd->iconf->ieee80211be,
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002337 hapd->iconf->secondary_channel,
Hai Shalom81f62d82019-07-22 12:10:00 -07002338 hostapd_get_oper_chwidth(hapd->iconf),
2339 hostapd_get_oper_centr_freq_seg0_idx(
2340 hapd->iconf),
2341 hostapd_get_oper_centr_freq_seg1_idx(
2342 hapd->iconf))) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002343 wpa_printf(MSG_ERROR, "Could not set channel for "
2344 "kernel driver");
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07002345 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002346 }
2347 }
2348
2349 if (iface->current_mode) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002350 if (hostapd_prepare_rates(iface, iface->current_mode)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002351 wpa_printf(MSG_ERROR, "Failed to prepare rates "
2352 "table.");
2353 hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
2354 HOSTAPD_LEVEL_WARNING,
2355 "Failed to prepare rates table.");
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07002356 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002357 }
2358 }
2359
Hai Shalom021b0b52019-04-10 11:17:58 -07002360 if (hapd->iconf->rts_threshold >= -1 &&
2361 hostapd_set_rts(hapd, hapd->iconf->rts_threshold) &&
2362 hapd->iconf->rts_threshold >= -1) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002363 wpa_printf(MSG_ERROR, "Could not set RTS threshold for "
2364 "kernel driver");
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07002365 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002366 }
2367
Hai Shalom021b0b52019-04-10 11:17:58 -07002368 if (hapd->iconf->fragm_threshold >= -1 &&
2369 hostapd_set_frag(hapd, hapd->iconf->fragm_threshold) &&
2370 hapd->iconf->fragm_threshold != -1) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002371 wpa_printf(MSG_ERROR, "Could not set fragmentation threshold "
2372 "for kernel driver");
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07002373 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002374 }
2375
2376 prev_addr = hapd->own_addr;
2377
2378 for (j = 0; j < iface->num_bss; j++) {
2379 hapd = iface->bss[j];
2380 if (j)
2381 os_memcpy(hapd->own_addr, prev_addr, ETH_ALEN);
Sunil Ravi77d572f2023-01-17 23:58:31 +00002382 if (hostapd_setup_bss(hapd, j == 0, !iface->conf->mbssid)) {
Hai Shalom021b0b52019-04-10 11:17:58 -07002383 for (;;) {
Dmitry Shmidt71757432014-06-02 13:50:35 -07002384 hapd = iface->bss[j];
2385 hostapd_bss_deinit_no_free(hapd);
2386 hostapd_free_hapd_data(hapd);
Hai Shalom021b0b52019-04-10 11:17:58 -07002387 if (j == 0)
2388 break;
2389 j--;
2390 }
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07002391 goto fail;
Dmitry Shmidt71757432014-06-02 13:50:35 -07002392 }
Dmitry Shmidt9c175262016-03-03 10:20:07 -08002393 if (is_zero_ether_addr(hapd->conf->bssid))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002394 prev_addr = hapd->own_addr;
2395 }
Sunil Ravi77d572f2023-01-17 23:58:31 +00002396
2397 if (hapd->iconf->mbssid) {
2398 for (j = 0; hapd->iconf->mbssid && j < iface->num_bss; j++) {
2399 hapd = iface->bss[j];
2400 if (hostapd_start_beacon(hapd, true)) {
2401 for (;;) {
2402 hapd = iface->bss[j];
2403 hostapd_bss_deinit_no_free(hapd);
2404 hostapd_free_hapd_data(hapd);
2405 if (j == 0)
2406 break;
2407 j--;
2408 }
2409 goto fail;
2410 }
2411 }
2412 }
2413
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002414 hapd = iface->bss[0];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002415
2416 hostapd_tx_queue_params(iface);
2417
2418 ap_list_init(iface);
2419
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07002420 hostapd_set_acl(hapd);
2421
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002422 if (hostapd_driver_commit(hapd) < 0) {
2423 wpa_printf(MSG_ERROR, "%s: Failed to commit driver "
2424 "configuration", __func__);
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07002425 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002426 }
2427
Jouni Malinen87fd2792011-05-16 18:35:42 +03002428 /*
2429 * WPS UPnP module can be initialized only when the "upnp_iface" is up.
2430 * If "interface" and "upnp_iface" are the same (e.g., non-bridge
2431 * mode), the interface is up only after driver_commit, so initialize
2432 * WPS after driver_commit.
2433 */
2434 for (j = 0; j < iface->num_bss; j++) {
2435 if (hostapd_init_wps_complete(iface->bss[j]))
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07002436 goto fail;
Jouni Malinen87fd2792011-05-16 18:35:42 +03002437 }
2438
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08002439 if ((iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
2440 !res_dfs_offload) {
2441 /*
2442 * If freq is DFS, and DFS is offloaded to the driver, then wait
2443 * for CAC to complete.
2444 */
2445 wpa_printf(MSG_DEBUG, "%s: Wait for CAC to complete", __func__);
2446 return res_dfs_offload;
2447 }
2448
2449#ifdef NEED_AP_MLME
2450dfs_offload:
2451#endif /* NEED_AP_MLME */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002452
2453#ifdef CONFIG_FST
2454 if (hapd->iconf->fst_cfg.group_id[0]) {
2455 struct fst_wpa_obj iface_obj;
2456
2457 fst_hostapd_fill_iface_obj(hapd, &iface_obj);
2458 iface->fst = fst_attach(hapd->conf->iface, hapd->own_addr,
2459 &iface_obj, &hapd->iconf->fst_cfg);
2460 if (!iface->fst) {
2461 wpa_printf(MSG_ERROR, "Could not attach to FST %s",
2462 hapd->iconf->fst_cfg.group_id);
2463 goto fail;
2464 }
2465 }
2466#endif /* CONFIG_FST */
2467
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002468 hostapd_set_state(iface, HAPD_IFACE_ENABLED);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002469 hostapd_owe_update_trans(iface);
Hai Shalom81f62d82019-07-22 12:10:00 -07002470 airtime_policy_update_init(iface);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002471 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_ENABLED);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002472 if (hapd->setup_complete_cb)
2473 hapd->setup_complete_cb(hapd->setup_complete_cb_ctx);
2474
Hai Shalom60840252021-02-19 19:02:11 -08002475#ifdef CONFIG_MESH
2476 if (delay_apply_cfg && !iface->mconf) {
2477 wpa_printf(MSG_ERROR, "Error while completing mesh init");
2478 goto fail;
2479 }
2480#endif /* CONFIG_MESH */
2481
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002482 wpa_printf(MSG_DEBUG, "%s: Setup of interface done.",
2483 iface->bss[0]->conf->iface);
Dmitry Shmidtb96dad42013-11-05 10:07:29 -08002484 if (iface->interfaces && iface->interfaces->terminate_on_error > 0)
2485 iface->interfaces->terminate_on_error--;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002486
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002487 for (j = 0; j < iface->num_bss; j++)
Hai Shalom74f70d42019-02-11 14:42:39 -08002488 hostapd_neighbor_set_own_report(iface->bss[j]);
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002489
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002490 if (iface->interfaces && iface->interfaces->count > 1)
2491 ieee802_11_set_beacons(iface);
2492
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002493 return 0;
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07002494
2495fail:
2496 wpa_printf(MSG_ERROR, "Interface initialization failed");
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002497
2498 if (iface->is_no_ir) {
2499 hostapd_set_state(iface, HAPD_IFACE_NO_IR);
2500 wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_NO_IR);
2501 return 0;
2502 }
2503
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07002504 hostapd_set_state(iface, HAPD_IFACE_DISABLED);
2505 wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002506#ifdef CONFIG_FST
2507 if (iface->fst) {
2508 fst_detach(iface->fst);
2509 iface->fst = NULL;
2510 }
2511#endif /* CONFIG_FST */
Roshan Pius3a1667e2018-07-03 15:17:14 -07002512
2513 if (iface->interfaces && iface->interfaces->terminate_on_error) {
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07002514 eloop_terminate();
Roshan Pius3a1667e2018-07-03 15:17:14 -07002515 } else if (hapd->setup_complete_cb) {
2516 /*
2517 * Calling hapd->setup_complete_cb directly may cause iface
2518 * deinitialization which may be accessed later by the caller.
2519 */
2520 eloop_register_timeout(0, 0,
2521 hostapd_interface_setup_failure_handler,
2522 iface, NULL);
2523 }
2524
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07002525 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002526}
2527
2528
2529/**
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002530 * hostapd_setup_interface_complete - Complete interface setup
2531 *
2532 * This function is called when previous steps in the interface setup has been
2533 * completed. This can also start operations, e.g., DFS, that will require
2534 * additional processing before interface is ready to be enabled. Such
2535 * operations will call this function from eloop callbacks when finished.
2536 */
2537int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
2538{
2539 struct hapd_interfaces *interfaces = iface->interfaces;
2540 struct hostapd_data *hapd = iface->bss[0];
2541 unsigned int i;
2542 int not_ready_in_sync_ifaces = 0;
2543
2544 if (!iface->need_to_start_in_sync)
2545 return hostapd_setup_interface_complete_sync(iface, err);
2546
2547 if (err) {
2548 wpa_printf(MSG_ERROR, "Interface initialization failed");
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002549 iface->need_to_start_in_sync = 0;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002550
2551 if (iface->is_no_ir) {
2552 hostapd_set_state(iface, HAPD_IFACE_NO_IR);
2553 wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_NO_IR);
2554 return 0;
2555 }
2556
2557 hostapd_set_state(iface, HAPD_IFACE_DISABLED);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002558 wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
2559 if (interfaces && interfaces->terminate_on_error)
2560 eloop_terminate();
2561 return -1;
2562 }
2563
2564 if (iface->ready_to_start_in_sync) {
2565 /* Already in ready and waiting. should never happpen */
2566 return 0;
2567 }
2568
2569 for (i = 0; i < interfaces->count; i++) {
2570 if (interfaces->iface[i]->need_to_start_in_sync &&
2571 !interfaces->iface[i]->ready_to_start_in_sync)
2572 not_ready_in_sync_ifaces++;
2573 }
2574
2575 /*
2576 * Check if this is the last interface, if yes then start all the other
2577 * waiting interfaces. If not, add this interface to the waiting list.
2578 */
2579 if (not_ready_in_sync_ifaces > 1 && iface->state == HAPD_IFACE_DFS) {
2580 /*
2581 * If this interface went through CAC, do not synchronize, just
2582 * start immediately.
2583 */
2584 iface->need_to_start_in_sync = 0;
2585 wpa_printf(MSG_INFO,
2586 "%s: Finished CAC - bypass sync and start interface",
2587 iface->bss[0]->conf->iface);
2588 return hostapd_setup_interface_complete_sync(iface, err);
2589 }
2590
2591 if (not_ready_in_sync_ifaces > 1) {
2592 /* need to wait as there are other interfaces still coming up */
2593 iface->ready_to_start_in_sync = 1;
2594 wpa_printf(MSG_INFO,
2595 "%s: Interface waiting to sync with other interfaces",
2596 iface->bss[0]->conf->iface);
2597 return 0;
2598 }
2599
2600 wpa_printf(MSG_INFO,
2601 "%s: Last interface to sync - starting all interfaces",
2602 iface->bss[0]->conf->iface);
2603 iface->need_to_start_in_sync = 0;
2604 hostapd_setup_interface_complete_sync(iface, err);
2605 for (i = 0; i < interfaces->count; i++) {
2606 if (interfaces->iface[i]->need_to_start_in_sync &&
2607 interfaces->iface[i]->ready_to_start_in_sync) {
2608 hostapd_setup_interface_complete_sync(
2609 interfaces->iface[i], 0);
2610 /* Only once the interfaces are sync started */
2611 interfaces->iface[i]->need_to_start_in_sync = 0;
2612 }
2613 }
2614
2615 return 0;
2616}
2617
2618
2619/**
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002620 * hostapd_setup_interface - Setup of an interface
2621 * @iface: Pointer to interface data.
2622 * Returns: 0 on success, -1 on failure
2623 *
2624 * Initializes the driver interface, validates the configuration,
2625 * and sets driver parameters based on the configuration.
2626 * Flushes old stations, sets the channel, encryption,
2627 * beacons, and WDS links based on the configuration.
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002628 *
2629 * If interface setup requires more time, e.g., to perform HT co-ex scans, ACS,
2630 * or DFS operations, this function returns 0 before such operations have been
2631 * completed. The pending operations are registered into eloop and will be
2632 * completed from eloop callbacks. Those callbacks end up calling
2633 * hostapd_setup_interface_complete() once setup has been completed.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002634 */
2635int hostapd_setup_interface(struct hostapd_iface *iface)
2636{
2637 int ret;
2638
Hai Shaloma20dcd72022-02-04 13:43:00 -08002639 if (!iface->conf)
2640 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002641 ret = setup_interface(iface);
2642 if (ret) {
2643 wpa_printf(MSG_ERROR, "%s: Unable to setup interface.",
Hai Shaloma20dcd72022-02-04 13:43:00 -08002644 iface->conf->bss[0]->iface);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002645 return -1;
2646 }
2647
2648 return 0;
2649}
2650
2651
2652/**
2653 * hostapd_alloc_bss_data - Allocate and initialize per-BSS data
2654 * @hapd_iface: Pointer to interface data
2655 * @conf: Pointer to per-interface configuration
2656 * @bss: Pointer to per-BSS configuration for this BSS
2657 * Returns: Pointer to allocated BSS data
2658 *
2659 * This function is used to allocate per-BSS data structure. This data will be
2660 * freed after hostapd_cleanup() is called for it during interface
2661 * deinitialization.
2662 */
2663struct hostapd_data *
2664hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
2665 struct hostapd_config *conf,
2666 struct hostapd_bss_config *bss)
2667{
2668 struct hostapd_data *hapd;
2669
2670 hapd = os_zalloc(sizeof(*hapd));
2671 if (hapd == NULL)
2672 return NULL;
2673
2674 hapd->new_assoc_sta_cb = hostapd_new_assoc_sta;
2675 hapd->iconf = conf;
2676 hapd->conf = bss;
2677 hapd->iface = hapd_iface;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002678 if (conf)
2679 hapd->driver = conf->driver;
Dmitry Shmidt04949592012-07-19 12:16:46 -07002680 hapd->ctrl_sock = -1;
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08002681 dl_list_init(&hapd->ctrl_dst);
Dmitry Shmidt7d175302016-09-06 13:11:34 -07002682 dl_list_init(&hapd->nr_db);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002683 hapd->dhcp_sock = -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002684#ifdef CONFIG_IEEE80211R_AP
2685 dl_list_init(&hapd->l2_queue);
2686 dl_list_init(&hapd->l2_oui_queue);
2687#endif /* CONFIG_IEEE80211R_AP */
Hai Shalom021b0b52019-04-10 11:17:58 -07002688#ifdef CONFIG_SAE
2689 dl_list_init(&hapd->sae_commit_queue);
2690#endif /* CONFIG_SAE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002691
2692 return hapd;
2693}
2694
2695
Dmitry Shmidt54605472013-11-08 11:10:19 -08002696static void hostapd_bss_deinit(struct hostapd_data *hapd)
2697{
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07002698 if (!hapd)
2699 return;
Dmitry Shmidt54605472013-11-08 11:10:19 -08002700 wpa_printf(MSG_DEBUG, "%s: deinit bss %s", __func__,
Hai Shalom021b0b52019-04-10 11:17:58 -07002701 hapd->conf ? hapd->conf->iface : "N/A");
Dmitry Shmidt71757432014-06-02 13:50:35 -07002702 hostapd_bss_deinit_no_free(hapd);
Dmitry Shmidtf73259c2015-03-17 11:00:54 -07002703 wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
Hai Shalomc3565922019-10-28 11:58:20 -07002704#ifdef CONFIG_SQLITE
2705 if (hapd->rad_attr_db) {
2706 sqlite3_close(hapd->rad_attr_db);
2707 hapd->rad_attr_db = NULL;
2708 }
2709#endif /* CONFIG_SQLITE */
Dmitry Shmidt54605472013-11-08 11:10:19 -08002710 hostapd_cleanup(hapd);
2711}
2712
2713
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002714void hostapd_interface_deinit(struct hostapd_iface *iface)
2715{
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002716 int j;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002717
Dmitry Shmidt54605472013-11-08 11:10:19 -08002718 wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002719 if (iface == NULL)
2720 return;
2721
Dmitry Shmidtf73259c2015-03-17 11:00:54 -07002722 hostapd_set_state(iface, HAPD_IFACE_DISABLED);
2723
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002724 eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
2725 iface->wait_channel_update = 0;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002726 iface->is_no_ir = false;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002727
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002728#ifdef CONFIG_FST
2729 if (iface->fst) {
2730 fst_detach(iface->fst);
2731 iface->fst = NULL;
2732 }
2733#endif /* CONFIG_FST */
2734
Hai Shalom021b0b52019-04-10 11:17:58 -07002735 for (j = (int) iface->num_bss - 1; j >= 0; j--) {
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07002736 if (!iface->bss)
2737 break;
Dmitry Shmidt54605472013-11-08 11:10:19 -08002738 hostapd_bss_deinit(iface->bss[j]);
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07002739 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07002740
Roshan Pius3a1667e2018-07-03 15:17:14 -07002741#ifdef NEED_AP_MLME
2742 hostapd_stop_setup_timers(iface);
2743 eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL);
2744#endif /* NEED_AP_MLME */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002745}
2746
2747
2748void hostapd_interface_free(struct hostapd_iface *iface)
2749{
2750 size_t j;
Dmitry Shmidt54605472013-11-08 11:10:19 -08002751 wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
2752 for (j = 0; j < iface->num_bss; j++) {
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07002753 if (!iface->bss)
2754 break;
Dmitry Shmidt54605472013-11-08 11:10:19 -08002755 wpa_printf(MSG_DEBUG, "%s: free hapd %p",
2756 __func__, iface->bss[j]);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002757 os_free(iface->bss[j]);
Dmitry Shmidt54605472013-11-08 11:10:19 -08002758 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002759 hostapd_cleanup_iface(iface);
2760}
2761
2762
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07002763struct hostapd_iface * hostapd_alloc_iface(void)
2764{
2765 struct hostapd_iface *hapd_iface;
2766
2767 hapd_iface = os_zalloc(sizeof(*hapd_iface));
2768 if (!hapd_iface)
2769 return NULL;
2770
2771 dl_list_init(&hapd_iface->sta_seen);
2772
2773 return hapd_iface;
2774}
2775
2776
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002777/**
2778 * hostapd_init - Allocate and initialize per-interface data
2779 * @config_file: Path to the configuration file
2780 * Returns: Pointer to the allocated interface data or %NULL on failure
2781 *
2782 * This function is used to allocate main data structures for per-interface
2783 * data. The allocated data buffer will be freed by calling
2784 * hostapd_cleanup_iface().
2785 */
2786struct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces,
2787 const char *config_file)
2788{
2789 struct hostapd_iface *hapd_iface = NULL;
2790 struct hostapd_config *conf = NULL;
2791 struct hostapd_data *hapd;
2792 size_t i;
2793
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07002794 hapd_iface = hostapd_alloc_iface();
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002795 if (hapd_iface == NULL)
2796 goto fail;
2797
2798 hapd_iface->config_fname = os_strdup(config_file);
2799 if (hapd_iface->config_fname == NULL)
2800 goto fail;
2801
2802 conf = interfaces->config_read_cb(hapd_iface->config_fname);
2803 if (conf == NULL)
2804 goto fail;
2805 hapd_iface->conf = conf;
2806
2807 hapd_iface->num_bss = conf->num_bss;
2808 hapd_iface->bss = os_calloc(conf->num_bss,
2809 sizeof(struct hostapd_data *));
2810 if (hapd_iface->bss == NULL)
2811 goto fail;
2812
2813 for (i = 0; i < conf->num_bss; i++) {
2814 hapd = hapd_iface->bss[i] =
2815 hostapd_alloc_bss_data(hapd_iface, conf,
2816 conf->bss[i]);
2817 if (hapd == NULL)
2818 goto fail;
2819 hapd->msg_ctx = hapd;
2820 }
2821
2822 return hapd_iface;
2823
2824fail:
2825 wpa_printf(MSG_ERROR, "Failed to set up interface with %s",
2826 config_file);
2827 if (conf)
2828 hostapd_config_free(conf);
2829 if (hapd_iface) {
2830 os_free(hapd_iface->config_fname);
2831 os_free(hapd_iface->bss);
Dmitry Shmidt54605472013-11-08 11:10:19 -08002832 wpa_printf(MSG_DEBUG, "%s: free iface %p",
2833 __func__, hapd_iface);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002834 os_free(hapd_iface);
2835 }
2836 return NULL;
2837}
2838
2839
2840static int ifname_in_use(struct hapd_interfaces *interfaces, const char *ifname)
2841{
2842 size_t i, j;
2843
2844 for (i = 0; i < interfaces->count; i++) {
2845 struct hostapd_iface *iface = interfaces->iface[i];
2846 for (j = 0; j < iface->num_bss; j++) {
2847 struct hostapd_data *hapd = iface->bss[j];
2848 if (os_strcmp(ifname, hapd->conf->iface) == 0)
2849 return 1;
2850 }
2851 }
2852
2853 return 0;
2854}
2855
2856
2857/**
2858 * hostapd_interface_init_bss - Read configuration file and init BSS data
2859 *
2860 * This function is used to parse configuration file for a BSS. This BSS is
2861 * added to an existing interface sharing the same radio (if any) or a new
2862 * interface is created if this is the first interface on a radio. This
2863 * allocate memory for the BSS. No actual driver operations are started.
2864 *
2865 * This is similar to hostapd_interface_init(), but for a case where the
2866 * configuration is used to add a single BSS instead of all BSSes for a radio.
2867 */
2868struct hostapd_iface *
2869hostapd_interface_init_bss(struct hapd_interfaces *interfaces, const char *phy,
2870 const char *config_fname, int debug)
2871{
2872 struct hostapd_iface *new_iface = NULL, *iface = NULL;
2873 struct hostapd_data *hapd;
2874 int k;
2875 size_t i, bss_idx;
2876
2877 if (!phy || !*phy)
2878 return NULL;
2879
2880 for (i = 0; i < interfaces->count; i++) {
2881 if (os_strcmp(interfaces->iface[i]->phy, phy) == 0) {
2882 iface = interfaces->iface[i];
2883 break;
2884 }
2885 }
2886
2887 wpa_printf(MSG_INFO, "Configuration file: %s (phy %s)%s",
2888 config_fname, phy, iface ? "" : " --> new PHY");
2889 if (iface) {
2890 struct hostapd_config *conf;
2891 struct hostapd_bss_config **tmp_conf;
2892 struct hostapd_data **tmp_bss;
2893 struct hostapd_bss_config *bss;
2894 const char *ifname;
2895
2896 /* Add new BSS to existing iface */
2897 conf = interfaces->config_read_cb(config_fname);
2898 if (conf == NULL)
2899 return NULL;
2900 if (conf->num_bss > 1) {
2901 wpa_printf(MSG_ERROR, "Multiple BSSes specified in BSS-config");
2902 hostapd_config_free(conf);
2903 return NULL;
2904 }
2905
2906 ifname = conf->bss[0]->iface;
2907 if (ifname[0] != '\0' && ifname_in_use(interfaces, ifname)) {
2908 wpa_printf(MSG_ERROR,
2909 "Interface name %s already in use", ifname);
2910 hostapd_config_free(conf);
2911 return NULL;
2912 }
2913
2914 tmp_conf = os_realloc_array(
2915 iface->conf->bss, iface->conf->num_bss + 1,
2916 sizeof(struct hostapd_bss_config *));
2917 tmp_bss = os_realloc_array(iface->bss, iface->num_bss + 1,
2918 sizeof(struct hostapd_data *));
2919 if (tmp_bss)
2920 iface->bss = tmp_bss;
2921 if (tmp_conf) {
2922 iface->conf->bss = tmp_conf;
2923 iface->conf->last_bss = tmp_conf[0];
2924 }
2925 if (tmp_bss == NULL || tmp_conf == NULL) {
2926 hostapd_config_free(conf);
2927 return NULL;
2928 }
2929 bss = iface->conf->bss[iface->conf->num_bss] = conf->bss[0];
2930 iface->conf->num_bss++;
2931
2932 hapd = hostapd_alloc_bss_data(iface, iface->conf, bss);
2933 if (hapd == NULL) {
2934 iface->conf->num_bss--;
2935 hostapd_config_free(conf);
2936 return NULL;
2937 }
2938 iface->conf->last_bss = bss;
2939 iface->bss[iface->num_bss] = hapd;
2940 hapd->msg_ctx = hapd;
2941
2942 bss_idx = iface->num_bss++;
2943 conf->num_bss--;
2944 conf->bss[0] = NULL;
2945 hostapd_config_free(conf);
2946 } else {
2947 /* Add a new iface with the first BSS */
2948 new_iface = iface = hostapd_init(interfaces, config_fname);
2949 if (!iface)
2950 return NULL;
2951 os_strlcpy(iface->phy, phy, sizeof(iface->phy));
2952 iface->interfaces = interfaces;
2953 bss_idx = 0;
2954 }
2955
2956 for (k = 0; k < debug; k++) {
2957 if (iface->bss[bss_idx]->conf->logger_stdout_level > 0)
2958 iface->bss[bss_idx]->conf->logger_stdout_level--;
2959 }
2960
2961 if (iface->conf->bss[bss_idx]->iface[0] == '\0' &&
2962 !hostapd_drv_none(iface->bss[bss_idx])) {
2963 wpa_printf(MSG_ERROR, "Interface name not specified in %s",
2964 config_fname);
2965 if (new_iface)
2966 hostapd_interface_deinit_free(new_iface);
2967 return NULL;
2968 }
2969
2970 return iface;
2971}
2972
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002973
2974void hostapd_interface_deinit_free(struct hostapd_iface *iface)
2975{
2976 const struct wpa_driver_ops *driver;
2977 void *drv_priv;
Dmitry Shmidt54605472013-11-08 11:10:19 -08002978
2979 wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002980 if (iface == NULL)
2981 return;
Dmitry Shmidt54605472013-11-08 11:10:19 -08002982 wpa_printf(MSG_DEBUG, "%s: num_bss=%u conf->num_bss=%u",
2983 __func__, (unsigned int) iface->num_bss,
2984 (unsigned int) iface->conf->num_bss);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002985 driver = iface->bss[0]->driver;
2986 drv_priv = iface->bss[0]->drv_priv;
2987 hostapd_interface_deinit(iface);
Dmitry Shmidt54605472013-11-08 11:10:19 -08002988 wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit",
2989 __func__, driver, drv_priv);
Dmitry Shmidt71757432014-06-02 13:50:35 -07002990 if (driver && driver->hapd_deinit && drv_priv) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002991 if (!iface->bss[0]->mld_first_bss)
2992 driver->hapd_deinit(drv_priv);
2993 hostapd_clear_drv_priv(iface->bss[0]);
Dmitry Shmidt71757432014-06-02 13:50:35 -07002994 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002995 hostapd_interface_free(iface);
2996}
2997
2998
Dmitry Shmidt15907092014-03-25 10:42:57 -07002999static void hostapd_deinit_driver(const struct wpa_driver_ops *driver,
3000 void *drv_priv,
3001 struct hostapd_iface *hapd_iface)
3002{
3003 size_t j;
3004
3005 wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit",
3006 __func__, driver, drv_priv);
3007 if (driver && driver->hapd_deinit && drv_priv) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003008 if (!hapd_iface->bss[0]->mld_first_bss)
3009 driver->hapd_deinit(drv_priv);
Dmitry Shmidt15907092014-03-25 10:42:57 -07003010 for (j = 0; j < hapd_iface->num_bss; j++) {
3011 wpa_printf(MSG_DEBUG, "%s:bss[%d]->drv_priv=%p",
3012 __func__, (int) j,
3013 hapd_iface->bss[j]->drv_priv);
Hai Shalom1dc4d202019-04-29 16:22:27 -07003014 if (hapd_iface->bss[j]->drv_priv == drv_priv) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003015 hostapd_clear_drv_priv(hapd_iface->bss[j]);
Hai Shalom1dc4d202019-04-29 16:22:27 -07003016 hapd_iface->extended_capa = NULL;
3017 hapd_iface->extended_capa_mask = NULL;
3018 hapd_iface->extended_capa_len = 0;
3019 }
Dmitry Shmidt15907092014-03-25 10:42:57 -07003020 }
3021 }
3022}
3023
3024
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003025int hostapd_enable_iface(struct hostapd_iface *hapd_iface)
3026{
Dmitry Shmidt71757432014-06-02 13:50:35 -07003027 size_t j;
3028
Hai Shalom60840252021-02-19 19:02:11 -08003029 if (!hapd_iface)
3030 return -1;
3031
3032 if (hapd_iface->enable_iface_cb)
3033 return hapd_iface->enable_iface_cb(hapd_iface);
3034
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003035 if (hapd_iface->bss[0]->drv_priv != NULL) {
3036 wpa_printf(MSG_ERROR, "Interface %s already enabled",
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003037 hapd_iface->conf->bss[0]->iface);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003038 return -1;
3039 }
3040
3041 wpa_printf(MSG_DEBUG, "Enable interface %s",
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003042 hapd_iface->conf->bss[0]->iface);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003043
Dmitry Shmidt71757432014-06-02 13:50:35 -07003044 for (j = 0; j < hapd_iface->num_bss; j++)
3045 hostapd_set_security_params(hapd_iface->conf->bss[j], 1);
Dmitry Shmidt344abd32014-01-14 13:17:00 -08003046 if (hostapd_config_check(hapd_iface->conf, 1) < 0) {
3047 wpa_printf(MSG_INFO, "Invalid configuration - cannot enable");
3048 return -1;
3049 }
3050
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003051 if (hapd_iface->interfaces == NULL ||
3052 hapd_iface->interfaces->driver_init == NULL ||
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003053 hapd_iface->interfaces->driver_init(hapd_iface))
3054 return -1;
3055
3056 if (hostapd_setup_interface(hapd_iface)) {
Dmitry Shmidt15907092014-03-25 10:42:57 -07003057 hostapd_deinit_driver(hapd_iface->bss[0]->driver,
3058 hapd_iface->bss[0]->drv_priv,
3059 hapd_iface);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003060 return -1;
3061 }
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003062
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003063 return 0;
3064}
3065
3066
3067int hostapd_reload_iface(struct hostapd_iface *hapd_iface)
3068{
3069 size_t j;
3070
3071 wpa_printf(MSG_DEBUG, "Reload interface %s",
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003072 hapd_iface->conf->bss[0]->iface);
3073 for (j = 0; j < hapd_iface->num_bss; j++)
Dmitry Shmidt71757432014-06-02 13:50:35 -07003074 hostapd_set_security_params(hapd_iface->conf->bss[j], 1);
Dmitry Shmidt344abd32014-01-14 13:17:00 -08003075 if (hostapd_config_check(hapd_iface->conf, 1) < 0) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003076 wpa_printf(MSG_ERROR, "Updated configuration is invalid");
3077 return -1;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003078 }
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003079 hostapd_clear_old(hapd_iface);
3080 for (j = 0; j < hapd_iface->num_bss; j++)
3081 hostapd_reload_bss(hapd_iface->bss[j]);
3082
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003083 return 0;
3084}
3085
3086
Sunil Ravi77d572f2023-01-17 23:58:31 +00003087int hostapd_reload_bss_only(struct hostapd_data *bss)
3088{
3089
3090 wpa_printf(MSG_DEBUG, "Reload BSS %s", bss->conf->iface);
3091 hostapd_set_security_params(bss->conf, 1);
3092 if (hostapd_config_check(bss->iconf, 1) < 0) {
3093 wpa_printf(MSG_ERROR, "Updated BSS configuration is invalid");
3094 return -1;
3095 }
3096 hostapd_clear_old_bss(bss);
3097 hostapd_reload_bss(bss);
3098 return 0;
3099}
3100
3101
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003102int hostapd_disable_iface(struct hostapd_iface *hapd_iface)
3103{
3104 size_t j;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003105 const struct wpa_driver_ops *driver;
3106 void *drv_priv;
3107
3108 if (hapd_iface == NULL)
3109 return -1;
Dmitry Shmidt71757432014-06-02 13:50:35 -07003110
Hai Shalom60840252021-02-19 19:02:11 -08003111 if (hapd_iface->disable_iface_cb)
3112 return hapd_iface->disable_iface_cb(hapd_iface);
3113
Dmitry Shmidt71757432014-06-02 13:50:35 -07003114 if (hapd_iface->bss[0]->drv_priv == NULL) {
3115 wpa_printf(MSG_INFO, "Interface %s already disabled",
3116 hapd_iface->conf->bss[0]->iface);
3117 return -1;
3118 }
3119
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003120 wpa_msg(hapd_iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003121 driver = hapd_iface->bss[0]->driver;
3122 drv_priv = hapd_iface->bss[0]->drv_priv;
3123
Dmitry Shmidta38abf92014-03-06 13:38:44 -08003124 hapd_iface->driver_ap_teardown =
3125 !!(hapd_iface->drv_flags &
3126 WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
3127
Hai Shalom39ba6fc2019-01-22 12:40:38 -08003128#ifdef NEED_AP_MLME
3129 for (j = 0; j < hapd_iface->num_bss; j++)
3130 hostapd_cleanup_cs_params(hapd_iface->bss[j]);
3131#endif /* NEED_AP_MLME */
3132
Dmitry Shmidta38abf92014-03-06 13:38:44 -08003133 /* same as hostapd_interface_deinit without deinitializing ctrl-iface */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003134 for (j = 0; j < hapd_iface->num_bss; j++) {
3135 struct hostapd_data *hapd = hapd_iface->bss[j];
Dmitry Shmidt71757432014-06-02 13:50:35 -07003136 hostapd_bss_deinit_no_free(hapd);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003137 hostapd_free_hapd_data(hapd);
3138 }
3139
Dmitry Shmidt15907092014-03-25 10:42:57 -07003140 hostapd_deinit_driver(driver, drv_priv, hapd_iface);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003141
3142 /* From hostapd_cleanup_iface: These were initialized in
3143 * hostapd_setup_interface and hostapd_setup_interface_complete
3144 */
3145 hostapd_cleanup_iface_partial(hapd_iface);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003146
Dmitry Shmidt56052862013-10-04 10:23:25 -07003147 wpa_printf(MSG_DEBUG, "Interface %s disabled",
3148 hapd_iface->bss[0]->conf->iface);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003149 hostapd_set_state(hapd_iface, HAPD_IFACE_DISABLED);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003150 return 0;
3151}
3152
3153
3154static struct hostapd_iface *
3155hostapd_iface_alloc(struct hapd_interfaces *interfaces)
3156{
3157 struct hostapd_iface **iface, *hapd_iface;
3158
3159 iface = os_realloc_array(interfaces->iface, interfaces->count + 1,
3160 sizeof(struct hostapd_iface *));
3161 if (iface == NULL)
3162 return NULL;
3163 interfaces->iface = iface;
3164 hapd_iface = interfaces->iface[interfaces->count] =
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07003165 hostapd_alloc_iface();
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003166 if (hapd_iface == NULL) {
3167 wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for "
3168 "the interface", __func__);
3169 return NULL;
3170 }
3171 interfaces->count++;
3172 hapd_iface->interfaces = interfaces;
3173
3174 return hapd_iface;
3175}
3176
3177
3178static struct hostapd_config *
3179hostapd_config_alloc(struct hapd_interfaces *interfaces, const char *ifname,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003180 const char *ctrl_iface, const char *driver)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003181{
3182 struct hostapd_bss_config *bss;
3183 struct hostapd_config *conf;
3184
3185 /* Allocates memory for bss and conf */
3186 conf = hostapd_config_defaults();
3187 if (conf == NULL) {
3188 wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for "
3189 "configuration", __func__);
Hai Shalom74f70d42019-02-11 14:42:39 -08003190 return NULL;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003191 }
3192
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003193 if (driver) {
3194 int j;
3195
3196 for (j = 0; wpa_drivers[j]; j++) {
3197 if (os_strcmp(driver, wpa_drivers[j]->name) == 0) {
3198 conf->driver = wpa_drivers[j];
3199 goto skip;
3200 }
3201 }
3202
3203 wpa_printf(MSG_ERROR,
3204 "Invalid/unknown driver '%s' - registering the default driver",
3205 driver);
3206 }
3207
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003208 conf->driver = wpa_drivers[0];
3209 if (conf->driver == NULL) {
3210 wpa_printf(MSG_ERROR, "No driver wrappers registered!");
3211 hostapd_config_free(conf);
3212 return NULL;
3213 }
3214
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003215skip:
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003216 bss = conf->last_bss = conf->bss[0];
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003217
3218 os_strlcpy(bss->iface, ifname, sizeof(bss->iface));
3219 bss->ctrl_interface = os_strdup(ctrl_iface);
3220 if (bss->ctrl_interface == NULL) {
3221 hostapd_config_free(conf);
3222 return NULL;
3223 }
3224
3225 /* Reading configuration file skipped, will be done in SET!
3226 * From reading the configuration till the end has to be done in
3227 * SET
3228 */
3229 return conf;
3230}
3231
3232
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003233static int hostapd_data_alloc(struct hostapd_iface *hapd_iface,
3234 struct hostapd_config *conf)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003235{
3236 size_t i;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003237 struct hostapd_data *hapd;
3238
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003239 hapd_iface->bss = os_calloc(conf->num_bss,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003240 sizeof(struct hostapd_data *));
3241 if (hapd_iface->bss == NULL)
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003242 return -1;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003243
3244 for (i = 0; i < conf->num_bss; i++) {
3245 hapd = hapd_iface->bss[i] =
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003246 hostapd_alloc_bss_data(hapd_iface, conf, conf->bss[i]);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003247 if (hapd == NULL) {
3248 while (i > 0) {
3249 i--;
3250 os_free(hapd_iface->bss[i]);
3251 hapd_iface->bss[i] = NULL;
3252 }
3253 os_free(hapd_iface->bss);
3254 hapd_iface->bss = NULL;
3255 return -1;
3256 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003257 hapd->msg_ctx = hapd;
3258 }
3259
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003260 hapd_iface->conf = conf;
3261 hapd_iface->num_bss = conf->num_bss;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003262
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003263 return 0;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003264}
3265
3266
3267int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf)
3268{
3269 struct hostapd_config *conf = NULL;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003270 struct hostapd_iface *hapd_iface = NULL, *new_iface = NULL;
3271 struct hostapd_data *hapd;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003272 char *ptr;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003273 size_t i, j;
3274 const char *conf_file = NULL, *phy_name = NULL;
3275
3276 if (os_strncmp(buf, "bss_config=", 11) == 0) {
3277 char *pos;
3278 phy_name = buf + 11;
3279 pos = os_strchr(phy_name, ':');
3280 if (!pos)
3281 return -1;
3282 *pos++ = '\0';
3283 conf_file = pos;
3284 if (!os_strlen(conf_file))
3285 return -1;
3286
3287 hapd_iface = hostapd_interface_init_bss(interfaces, phy_name,
3288 conf_file, 0);
3289 if (!hapd_iface)
3290 return -1;
3291 for (j = 0; j < interfaces->count; j++) {
3292 if (interfaces->iface[j] == hapd_iface)
3293 break;
3294 }
3295 if (j == interfaces->count) {
3296 struct hostapd_iface **tmp;
3297 tmp = os_realloc_array(interfaces->iface,
3298 interfaces->count + 1,
3299 sizeof(struct hostapd_iface *));
3300 if (!tmp) {
3301 hostapd_interface_deinit_free(hapd_iface);
3302 return -1;
3303 }
3304 interfaces->iface = tmp;
3305 interfaces->iface[interfaces->count++] = hapd_iface;
3306 new_iface = hapd_iface;
3307 }
3308
3309 if (new_iface) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003310 if (interfaces->driver_init(hapd_iface))
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003311 goto fail;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003312
3313 if (hostapd_setup_interface(hapd_iface)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003314 hostapd_deinit_driver(
3315 hapd_iface->bss[0]->driver,
3316 hapd_iface->bss[0]->drv_priv,
3317 hapd_iface);
3318 goto fail;
3319 }
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003320 } else {
3321 /* Assign new BSS with bss[0]'s driver info */
3322 hapd = hapd_iface->bss[hapd_iface->num_bss - 1];
3323 hapd->driver = hapd_iface->bss[0]->driver;
3324 hapd->drv_priv = hapd_iface->bss[0]->drv_priv;
3325 os_memcpy(hapd->own_addr, hapd_iface->bss[0]->own_addr,
3326 ETH_ALEN);
3327
3328 if (start_ctrl_iface_bss(hapd) < 0 ||
Dmitry Shmidt54605472013-11-08 11:10:19 -08003329 (hapd_iface->state == HAPD_IFACE_ENABLED &&
Sunil Ravi77d572f2023-01-17 23:58:31 +00003330 hostapd_setup_bss(hapd, -1, true))) {
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07003331 hostapd_cleanup(hapd);
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003332 hapd_iface->bss[hapd_iface->num_bss - 1] = NULL;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003333 hapd_iface->conf->num_bss--;
3334 hapd_iface->num_bss--;
Dmitry Shmidt54605472013-11-08 11:10:19 -08003335 wpa_printf(MSG_DEBUG, "%s: free hapd %p %s",
3336 __func__, hapd, hapd->conf->iface);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003337 hostapd_config_free_bss(hapd->conf);
3338 hapd->conf = NULL;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003339 os_free(hapd);
3340 return -1;
3341 }
3342 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003343 hostapd_owe_update_trans(hapd_iface);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003344 return 0;
3345 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003346
3347 ptr = os_strchr(buf, ' ');
3348 if (ptr == NULL)
3349 return -1;
3350 *ptr++ = '\0';
3351
Dmitry Shmidt56052862013-10-04 10:23:25 -07003352 if (os_strncmp(ptr, "config=", 7) == 0)
3353 conf_file = ptr + 7;
3354
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003355 for (i = 0; i < interfaces->count; i++) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003356 bool mld_ap = false;
3357
3358#ifdef CONFIG_IEEE80211BE
3359 mld_ap = interfaces->iface[i]->conf->bss[0]->mld_ap;
3360#endif /* CONFIG_IEEE80211BE */
3361
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003362 if (!os_strcmp(interfaces->iface[i]->conf->bss[0]->iface,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003363 buf) && !mld_ap) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003364 wpa_printf(MSG_INFO, "Cannot add interface - it "
3365 "already exists");
3366 return -1;
3367 }
3368 }
3369
3370 hapd_iface = hostapd_iface_alloc(interfaces);
3371 if (hapd_iface == NULL) {
3372 wpa_printf(MSG_ERROR, "%s: Failed to allocate memory "
3373 "for interface", __func__);
3374 goto fail;
3375 }
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003376 new_iface = hapd_iface;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003377
Dmitry Shmidt56052862013-10-04 10:23:25 -07003378 if (conf_file && interfaces->config_read_cb) {
3379 conf = interfaces->config_read_cb(conf_file);
3380 if (conf && conf->bss)
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003381 os_strlcpy(conf->bss[0]->iface, buf,
3382 sizeof(conf->bss[0]->iface));
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003383 } else {
3384 char *driver = os_strchr(ptr, ' ');
3385
3386 if (driver)
3387 *driver++ = '\0';
3388 conf = hostapd_config_alloc(interfaces, buf, ptr, driver);
3389 }
3390
Dmitry Shmidt56052862013-10-04 10:23:25 -07003391 if (conf == NULL || conf->bss == NULL) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003392 wpa_printf(MSG_ERROR, "%s: Failed to allocate memory "
3393 "for configuration", __func__);
3394 goto fail;
3395 }
3396
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003397 if (hostapd_data_alloc(hapd_iface, conf) < 0) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003398 wpa_printf(MSG_ERROR, "%s: Failed to allocate memory "
3399 "for hostapd", __func__);
3400 goto fail;
3401 }
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003402 conf = NULL;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003403
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003404 if (start_ctrl_iface(hapd_iface) < 0)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003405 goto fail;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003406
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003407 wpa_printf(MSG_INFO, "Add interface '%s'",
3408 hapd_iface->conf->bss[0]->iface);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003409
3410 return 0;
3411
3412fail:
3413 if (conf)
3414 hostapd_config_free(conf);
3415 if (hapd_iface) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003416 if (hapd_iface->bss) {
Dmitry Shmidt54605472013-11-08 11:10:19 -08003417 for (i = 0; i < hapd_iface->num_bss; i++) {
3418 hapd = hapd_iface->bss[i];
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003419 if (!hapd)
3420 continue;
3421 if (hapd_iface->interfaces &&
Dmitry Shmidt54605472013-11-08 11:10:19 -08003422 hapd_iface->interfaces->ctrl_iface_deinit)
3423 hapd_iface->interfaces->
3424 ctrl_iface_deinit(hapd);
3425 wpa_printf(MSG_DEBUG, "%s: free hapd %p (%s)",
3426 __func__, hapd_iface->bss[i],
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003427 hapd->conf->iface);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003428 hostapd_cleanup(hapd);
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003429 os_free(hapd);
3430 hapd_iface->bss[i] = NULL;
Dmitry Shmidt54605472013-11-08 11:10:19 -08003431 }
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003432 os_free(hapd_iface->bss);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003433 hapd_iface->bss = NULL;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003434 }
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003435 if (new_iface) {
3436 interfaces->count--;
3437 interfaces->iface[interfaces->count] = NULL;
3438 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003439 hostapd_cleanup_iface(hapd_iface);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003440 }
3441 return -1;
3442}
3443
3444
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003445static int hostapd_remove_bss(struct hostapd_iface *iface, unsigned int idx)
3446{
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003447 size_t i;
3448
Dmitry Shmidt54605472013-11-08 11:10:19 -08003449 wpa_printf(MSG_INFO, "Remove BSS '%s'", iface->conf->bss[idx]->iface);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003450
Dmitry Shmidt54605472013-11-08 11:10:19 -08003451 /* Remove hostapd_data only if it has already been initialized */
3452 if (idx < iface->num_bss) {
3453 struct hostapd_data *hapd = iface->bss[idx];
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003454
Dmitry Shmidt54605472013-11-08 11:10:19 -08003455 hostapd_bss_deinit(hapd);
3456 wpa_printf(MSG_DEBUG, "%s: free hapd %p (%s)",
3457 __func__, hapd, hapd->conf->iface);
3458 hostapd_config_free_bss(hapd->conf);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003459 hapd->conf = NULL;
Dmitry Shmidt54605472013-11-08 11:10:19 -08003460 os_free(hapd);
3461
3462 iface->num_bss--;
3463
3464 for (i = idx; i < iface->num_bss; i++)
3465 iface->bss[i] = iface->bss[i + 1];
3466 } else {
3467 hostapd_config_free_bss(iface->conf->bss[idx]);
3468 iface->conf->bss[idx] = NULL;
3469 }
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003470
3471 iface->conf->num_bss--;
Dmitry Shmidt54605472013-11-08 11:10:19 -08003472 for (i = idx; i < iface->conf->num_bss; i++)
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003473 iface->conf->bss[i] = iface->conf->bss[i + 1];
3474
3475 return 0;
3476}
3477
3478
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003479int hostapd_remove_iface(struct hapd_interfaces *interfaces, char *buf)
3480{
3481 struct hostapd_iface *hapd_iface;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003482 size_t i, j, k = 0;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003483
3484 for (i = 0; i < interfaces->count; i++) {
3485 hapd_iface = interfaces->iface[i];
3486 if (hapd_iface == NULL)
3487 return -1;
Dmitry Shmidt54605472013-11-08 11:10:19 -08003488 if (!os_strcmp(hapd_iface->conf->bss[0]->iface, buf)) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003489 wpa_printf(MSG_INFO, "Remove interface '%s'", buf);
Dmitry Shmidta38abf92014-03-06 13:38:44 -08003490 hapd_iface->driver_ap_teardown =
3491 !!(hapd_iface->drv_flags &
3492 WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
3493
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003494 hostapd_interface_deinit_free(hapd_iface);
3495 k = i;
3496 while (k < (interfaces->count - 1)) {
3497 interfaces->iface[k] =
3498 interfaces->iface[k + 1];
3499 k++;
3500 }
3501 interfaces->count--;
3502 return 0;
3503 }
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003504
3505 for (j = 0; j < hapd_iface->conf->num_bss; j++) {
Dmitry Shmidta38abf92014-03-06 13:38:44 -08003506 if (!os_strcmp(hapd_iface->conf->bss[j]->iface, buf)) {
3507 hapd_iface->driver_ap_teardown =
3508 !(hapd_iface->drv_flags &
3509 WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003510 return hostapd_remove_bss(hapd_iface, j);
Dmitry Shmidta38abf92014-03-06 13:38:44 -08003511 }
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003512 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003513 }
3514 return -1;
3515}
3516
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003517
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003518/**
3519 * hostapd_new_assoc_sta - Notify that a new station associated with the AP
3520 * @hapd: Pointer to BSS data
3521 * @sta: Pointer to the associated STA data
3522 * @reassoc: 1 to indicate this was a re-association; 0 = first association
3523 *
3524 * This function will be called whenever a station associates with the AP. It
3525 * can be called from ieee802_11.c for drivers that export MLME to hostapd and
3526 * from drv_callbacks.c based on driver events for drivers that take care of
3527 * management frames (IEEE 802.11 authentication and association) internally.
3528 */
3529void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
3530 int reassoc)
3531{
3532 if (hapd->tkip_countermeasures) {
3533 hostapd_drv_sta_deauth(hapd, sta->addr,
3534 WLAN_REASON_MICHAEL_MIC_FAILURE);
3535 return;
3536 }
3537
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003538#ifdef CONFIG_IEEE80211BE
3539 if (hapd->conf->mld_ap && sta->mld_info.mld_sta &&
3540 sta->mld_assoc_link_id != hapd->mld_link_id)
3541 return;
3542#endif /* CONFIG_IEEE80211BE */
3543
Dmitry Shmidt1d6bf422016-01-19 15:51:35 -08003544 ap_sta_clear_disconnect_timeouts(hapd, sta);
Hai Shalom899fcc72020-10-19 14:38:18 -07003545 sta->post_csa_sa_query = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003546
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003547#ifdef CONFIG_P2P
3548 if (sta->p2p_ie == NULL && !sta->no_p2p_set) {
3549 sta->no_p2p_set = 1;
3550 hapd->num_sta_no_p2p++;
3551 if (hapd->num_sta_no_p2p == 1)
3552 hostapd_p2p_non_p2p_sta_connected(hapd);
3553 }
3554#endif /* CONFIG_P2P */
3555
Hai Shalom81f62d82019-07-22 12:10:00 -07003556 airtime_policy_new_sta(hapd, sta);
3557
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003558 /* Start accounting here, if IEEE 802.1X and WPA are not used.
3559 * IEEE 802.1X/WPA code will start accounting after the station has
3560 * been authorized. */
Dmitry Shmidt2ac5f602014-03-07 10:08:21 -08003561 if (!hapd->conf->ieee802_1x && !hapd->conf->wpa && !hapd->conf->osen) {
3562 ap_sta_set_authorized(hapd, sta, 1);
Dmitry Shmidt04f534e2013-12-09 15:50:16 -08003563 os_get_reltime(&sta->connected_time);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003564 accounting_sta_start(hapd, sta);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003565 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003566
3567 /* Start IEEE 802.1X authentication process for new stations */
3568 ieee802_1x_new_station(hapd, sta);
3569 if (reassoc) {
3570 if (sta->auth_alg != WLAN_AUTH_FT &&
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003571 sta->auth_alg != WLAN_AUTH_FILS_SK &&
3572 sta->auth_alg != WLAN_AUTH_FILS_SK_PFS &&
3573 sta->auth_alg != WLAN_AUTH_FILS_PK &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003574 !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)))
3575 wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003576 } else if (!(hapd->iface->drv_flags2 &
3577 WPA_DRIVER_FLAGS2_4WAY_HANDSHAKE_AP_PSK)) {
3578 /* The 4-way handshake offloaded case will have this handled
3579 * based on the port authorized event. */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003580 wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003581 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07003582
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08003583 if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED) {
3584 if (eloop_cancel_timeout(ap_handle_timer, hapd, sta) > 0) {
3585 wpa_printf(MSG_DEBUG,
3586 "%s: %s: canceled wired ap_handle_timer timeout for "
3587 MACSTR,
3588 hapd->conf->iface, __func__,
3589 MAC2STR(sta->addr));
3590 }
3591 } else if (!(hapd->iface->drv_flags &
3592 WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
Dmitry Shmidt1d6bf422016-01-19 15:51:35 -08003593 wpa_printf(MSG_DEBUG,
3594 "%s: %s: reschedule ap_handle_timer timeout for "
3595 MACSTR " (%d seconds - ap_max_inactivity)",
3596 hapd->conf->iface, __func__, MAC2STR(sta->addr),
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08003597 hapd->conf->ap_max_inactivity);
3598 eloop_cancel_timeout(ap_handle_timer, hapd, sta);
3599 eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
3600 ap_handle_timer, hapd, sta);
3601 }
Hai Shalom81f62d82019-07-22 12:10:00 -07003602
3603#ifdef CONFIG_MACSEC
3604 if (hapd->conf->wpa_key_mgmt == WPA_KEY_MGMT_NONE &&
3605 hapd->conf->mka_psk_set)
3606 ieee802_1x_create_preshared_mka_hapd(hapd, sta);
3607 else
3608 ieee802_1x_alloc_kay_sm_hapd(hapd, sta);
3609#endif /* CONFIG_MACSEC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003610}
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003611
3612
3613const char * hostapd_state_text(enum hostapd_iface_state s)
3614{
3615 switch (s) {
3616 case HAPD_IFACE_UNINITIALIZED:
3617 return "UNINITIALIZED";
3618 case HAPD_IFACE_DISABLED:
3619 return "DISABLED";
3620 case HAPD_IFACE_COUNTRY_UPDATE:
3621 return "COUNTRY_UPDATE";
3622 case HAPD_IFACE_ACS:
3623 return "ACS";
3624 case HAPD_IFACE_HT_SCAN:
3625 return "HT_SCAN";
3626 case HAPD_IFACE_DFS:
3627 return "DFS";
3628 case HAPD_IFACE_ENABLED:
3629 return "ENABLED";
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003630 case HAPD_IFACE_NO_IR:
3631 return "NO_IR";
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003632 }
3633
3634 return "UNKNOWN";
3635}
3636
3637
3638void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s)
3639{
3640 wpa_printf(MSG_INFO, "%s: interface state %s->%s",
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07003641 iface->conf ? iface->conf->bss[0]->iface : "N/A",
3642 hostapd_state_text(iface->state), hostapd_state_text(s));
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003643 iface->state = s;
3644}
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003645
3646
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003647int hostapd_csa_in_progress(struct hostapd_iface *iface)
3648{
3649 unsigned int i;
3650
3651 for (i = 0; i < iface->num_bss; i++)
3652 if (iface->bss[i]->csa_in_progress)
3653 return 1;
3654 return 0;
3655}
3656
3657
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003658#ifdef NEED_AP_MLME
3659
3660static void free_beacon_data(struct beacon_data *beacon)
3661{
3662 os_free(beacon->head);
3663 beacon->head = NULL;
3664 os_free(beacon->tail);
3665 beacon->tail = NULL;
3666 os_free(beacon->probe_resp);
3667 beacon->probe_resp = NULL;
3668 os_free(beacon->beacon_ies);
3669 beacon->beacon_ies = NULL;
3670 os_free(beacon->proberesp_ies);
3671 beacon->proberesp_ies = NULL;
3672 os_free(beacon->assocresp_ies);
3673 beacon->assocresp_ies = NULL;
3674}
3675
3676
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07003677static int hostapd_build_beacon_data(struct hostapd_data *hapd,
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003678 struct beacon_data *beacon)
3679{
3680 struct wpabuf *beacon_extra, *proberesp_extra, *assocresp_extra;
3681 struct wpa_driver_ap_params params;
3682 int ret;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003683
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08003684 os_memset(beacon, 0, sizeof(*beacon));
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003685 ret = ieee802_11_build_ap_params(hapd, &params);
3686 if (ret < 0)
3687 return ret;
3688
3689 ret = hostapd_build_ap_extra_ies(hapd, &beacon_extra,
3690 &proberesp_extra,
3691 &assocresp_extra);
3692 if (ret)
3693 goto free_ap_params;
3694
3695 ret = -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003696 beacon->head = os_memdup(params.head, params.head_len);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003697 if (!beacon->head)
3698 goto free_ap_extra_ies;
3699
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003700 beacon->head_len = params.head_len;
3701
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003702 beacon->tail = os_memdup(params.tail, params.tail_len);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003703 if (!beacon->tail)
3704 goto free_beacon;
3705
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003706 beacon->tail_len = params.tail_len;
3707
3708 if (params.proberesp != NULL) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003709 beacon->probe_resp = os_memdup(params.proberesp,
3710 params.proberesp_len);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003711 if (!beacon->probe_resp)
3712 goto free_beacon;
3713
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003714 beacon->probe_resp_len = params.proberesp_len;
3715 }
3716
3717 /* copy the extra ies */
3718 if (beacon_extra) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003719 beacon->beacon_ies = os_memdup(beacon_extra->buf,
3720 wpabuf_len(beacon_extra));
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003721 if (!beacon->beacon_ies)
3722 goto free_beacon;
3723
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003724 beacon->beacon_ies_len = wpabuf_len(beacon_extra);
3725 }
3726
3727 if (proberesp_extra) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003728 beacon->proberesp_ies = os_memdup(proberesp_extra->buf,
3729 wpabuf_len(proberesp_extra));
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003730 if (!beacon->proberesp_ies)
3731 goto free_beacon;
3732
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003733 beacon->proberesp_ies_len = wpabuf_len(proberesp_extra);
3734 }
3735
3736 if (assocresp_extra) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003737 beacon->assocresp_ies = os_memdup(assocresp_extra->buf,
3738 wpabuf_len(assocresp_extra));
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003739 if (!beacon->assocresp_ies)
3740 goto free_beacon;
3741
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003742 beacon->assocresp_ies_len = wpabuf_len(assocresp_extra);
3743 }
3744
3745 ret = 0;
3746free_beacon:
3747 /* if the function fails, the caller should not free beacon data */
3748 if (ret)
3749 free_beacon_data(beacon);
3750
3751free_ap_extra_ies:
3752 hostapd_free_ap_extra_ies(hapd, beacon_extra, proberesp_extra,
3753 assocresp_extra);
3754free_ap_params:
3755 ieee802_11_free_ap_params(&params);
3756 return ret;
3757}
3758
3759
3760/*
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003761 * TODO: This flow currently supports only changing channel and width within
3762 * the same hw_mode. Any other changes to MAC parameters or provided settings
3763 * are not supported.
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003764 */
3765static int hostapd_change_config_freq(struct hostapd_data *hapd,
3766 struct hostapd_config *conf,
3767 struct hostapd_freq_params *params,
3768 struct hostapd_freq_params *old_params)
3769{
3770 int channel;
Hai Shalom81f62d82019-07-22 12:10:00 -07003771 u8 seg0, seg1;
3772 struct hostapd_hw_modes *mode;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003773
3774 if (!params->channel) {
3775 /* check if the new channel is supported by hw */
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07003776 params->channel = hostapd_hw_get_channel(hapd, params->freq);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003777 }
3778
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07003779 channel = params->channel;
3780 if (!channel)
3781 return -1;
3782
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003783 hostapd_determine_mode(hapd->iface);
Hai Shalom81f62d82019-07-22 12:10:00 -07003784 mode = hapd->iface->current_mode;
3785
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003786 /* if a pointer to old_params is provided we save previous state */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003787 if (old_params &&
3788 hostapd_set_freq_params(old_params, conf->hw_mode,
3789 hostapd_hw_get_freq(hapd, conf->channel),
Hai Shalomc3565922019-10-28 11:58:20 -07003790 conf->channel, conf->enable_edmg,
3791 conf->edmg_channel, conf->ieee80211n,
Hai Shalom81f62d82019-07-22 12:10:00 -07003792 conf->ieee80211ac, conf->ieee80211ax,
Sunil Ravia04bd252022-05-02 22:54:18 -07003793 conf->ieee80211be, conf->secondary_channel,
Hai Shalom81f62d82019-07-22 12:10:00 -07003794 hostapd_get_oper_chwidth(conf),
3795 hostapd_get_oper_centr_freq_seg0_idx(conf),
3796 hostapd_get_oper_centr_freq_seg1_idx(conf),
3797 conf->vht_capab,
3798 mode ? &mode->he_capab[IEEE80211_MODE_AP] :
Sunil Ravia04bd252022-05-02 22:54:18 -07003799 NULL,
3800 mode ? &mode->eht_capab[IEEE80211_MODE_AP] :
Hai Shalom81f62d82019-07-22 12:10:00 -07003801 NULL))
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003802 return -1;
3803
3804 switch (params->bandwidth) {
3805 case 0:
3806 case 20:
Hai Shaloma20dcd72022-02-04 13:43:00 -08003807 conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
3808 break;
3809 case 40:
3810 case 80:
3811 case 160:
Sunil Ravi640215c2023-06-28 23:08:09 +00003812 case 320:
Hai Shaloma20dcd72022-02-04 13:43:00 -08003813 conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
3814 break;
3815 default:
3816 return -1;
3817 }
3818
3819 switch (params->bandwidth) {
3820 case 0:
3821 case 20:
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003822 case 40:
Sunil8cd6f4d2022-06-28 18:40:46 +00003823 hostapd_set_oper_chwidth(conf, CONF_OPER_CHWIDTH_USE_HT);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003824 break;
3825 case 80:
3826 if (params->center_freq2)
Sunil8cd6f4d2022-06-28 18:40:46 +00003827 hostapd_set_oper_chwidth(conf,
3828 CONF_OPER_CHWIDTH_80P80MHZ);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003829 else
Sunil8cd6f4d2022-06-28 18:40:46 +00003830 hostapd_set_oper_chwidth(conf,
3831 CONF_OPER_CHWIDTH_80MHZ);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003832 break;
3833 case 160:
Sunil8cd6f4d2022-06-28 18:40:46 +00003834 hostapd_set_oper_chwidth(conf, CONF_OPER_CHWIDTH_160MHZ);
3835 break;
3836 case 320:
3837 hostapd_set_oper_chwidth(conf, CONF_OPER_CHWIDTH_320MHZ);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003838 break;
3839 default:
3840 return -1;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003841 }
3842
3843 conf->channel = channel;
3844 conf->ieee80211n = params->ht_enabled;
Hai Shaloma20dcd72022-02-04 13:43:00 -08003845 conf->ieee80211ac = params->vht_enabled;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003846 conf->secondary_channel = params->sec_channel_offset;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003847 ieee80211_freq_to_chan(params->center_freq1,
Hai Shalom81f62d82019-07-22 12:10:00 -07003848 &seg0);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003849 ieee80211_freq_to_chan(params->center_freq2,
Hai Shalom81f62d82019-07-22 12:10:00 -07003850 &seg1);
3851 hostapd_set_oper_centr_freq_seg0_idx(conf, seg0);
3852 hostapd_set_oper_centr_freq_seg1_idx(conf, seg1);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003853
3854 /* TODO: maybe call here hostapd_config_check here? */
3855
3856 return 0;
3857}
3858
3859
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07003860static int hostapd_fill_csa_settings(struct hostapd_data *hapd,
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003861 struct csa_settings *settings)
3862{
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07003863 struct hostapd_iface *iface = hapd->iface;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003864 struct hostapd_freq_params old_freq;
3865 int ret;
Sunil Ravi036cec52023-03-29 11:35:17 -07003866#ifdef CONFIG_IEEE80211BE
3867 u16 old_punct_bitmap;
3868#endif /* CONFIG_IEEE80211BE */
Hai Shalom81f62d82019-07-22 12:10:00 -07003869 u8 chan, bandwidth;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003870
3871 os_memset(&old_freq, 0, sizeof(old_freq));
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07003872 if (!iface || !iface->freq || hapd->csa_in_progress)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003873 return -1;
3874
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003875 switch (settings->freq_params.bandwidth) {
3876 case 80:
3877 if (settings->freq_params.center_freq2)
Sunil8cd6f4d2022-06-28 18:40:46 +00003878 bandwidth = CONF_OPER_CHWIDTH_80P80MHZ;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003879 else
Sunil8cd6f4d2022-06-28 18:40:46 +00003880 bandwidth = CONF_OPER_CHWIDTH_80MHZ;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003881 break;
3882 case 160:
Sunil8cd6f4d2022-06-28 18:40:46 +00003883 bandwidth = CONF_OPER_CHWIDTH_160MHZ;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003884 break;
Sunil Ravi640215c2023-06-28 23:08:09 +00003885 case 320:
3886 bandwidth = CONF_OPER_CHWIDTH_320MHZ;
3887 break;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003888 default:
Sunil8cd6f4d2022-06-28 18:40:46 +00003889 bandwidth = CONF_OPER_CHWIDTH_USE_HT;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003890 break;
3891 }
3892
3893 if (ieee80211_freq_to_channel_ext(
3894 settings->freq_params.freq,
3895 settings->freq_params.sec_channel_offset,
Hai Shalom81f62d82019-07-22 12:10:00 -07003896 bandwidth,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003897 &hapd->iface->cs_oper_class,
3898 &chan) == NUM_HOSTAPD_MODES) {
3899 wpa_printf(MSG_DEBUG,
Sunil Ravia04bd252022-05-02 22:54:18 -07003900 "invalid frequency for channel switch (freq=%d, sec_channel_offset=%d, vht_enabled=%d, he_enabled=%d, eht_enabled=%d)",
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003901 settings->freq_params.freq,
3902 settings->freq_params.sec_channel_offset,
Hai Shalom81f62d82019-07-22 12:10:00 -07003903 settings->freq_params.vht_enabled,
Sunil Ravia04bd252022-05-02 22:54:18 -07003904 settings->freq_params.he_enabled,
3905 settings->freq_params.eht_enabled);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003906 return -1;
3907 }
3908
3909 settings->freq_params.channel = chan;
3910
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003911 ret = hostapd_change_config_freq(iface->bss[0], iface->conf,
3912 &settings->freq_params,
3913 &old_freq);
3914 if (ret)
3915 return ret;
3916
Sunil Ravi036cec52023-03-29 11:35:17 -07003917#ifdef CONFIG_IEEE80211BE
3918 old_punct_bitmap = iface->conf->punct_bitmap;
3919 iface->conf->punct_bitmap = settings->punct_bitmap;
3920#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07003921 ret = hostapd_build_beacon_data(hapd, &settings->beacon_after);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003922
3923 /* change back the configuration */
Sunil Ravi036cec52023-03-29 11:35:17 -07003924#ifdef CONFIG_IEEE80211BE
3925 iface->conf->punct_bitmap = old_punct_bitmap;
3926#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003927 hostapd_change_config_freq(iface->bss[0], iface->conf,
3928 &old_freq, NULL);
3929
3930 if (ret)
3931 return ret;
3932
3933 /* set channel switch parameters for csa ie */
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07003934 hapd->cs_freq_params = settings->freq_params;
3935 hapd->cs_count = settings->cs_count;
3936 hapd->cs_block_tx = settings->block_tx;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003937
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07003938 ret = hostapd_build_beacon_data(hapd, &settings->beacon_csa);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003939 if (ret) {
3940 free_beacon_data(&settings->beacon_after);
3941 return ret;
3942 }
3943
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003944 settings->counter_offset_beacon[0] = hapd->cs_c_off_beacon;
3945 settings->counter_offset_presp[0] = hapd->cs_c_off_proberesp;
3946 settings->counter_offset_beacon[1] = hapd->cs_c_off_ecsa_beacon;
3947 settings->counter_offset_presp[1] = hapd->cs_c_off_ecsa_proberesp;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003948
3949 return 0;
3950}
3951
3952
3953void hostapd_cleanup_cs_params(struct hostapd_data *hapd)
3954{
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07003955 os_memset(&hapd->cs_freq_params, 0, sizeof(hapd->cs_freq_params));
3956 hapd->cs_count = 0;
3957 hapd->cs_block_tx = 0;
3958 hapd->cs_c_off_beacon = 0;
3959 hapd->cs_c_off_proberesp = 0;
3960 hapd->csa_in_progress = 0;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003961 hapd->cs_c_off_ecsa_beacon = 0;
3962 hapd->cs_c_off_ecsa_proberesp = 0;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003963}
3964
3965
Hai Shalom60840252021-02-19 19:02:11 -08003966void hostapd_chan_switch_config(struct hostapd_data *hapd,
3967 struct hostapd_freq_params *freq_params)
Roshan Pius3a1667e2018-07-03 15:17:14 -07003968{
Sunil Ravia04bd252022-05-02 22:54:18 -07003969 if (freq_params->eht_enabled)
3970 hapd->iconf->ch_switch_eht_config |= CH_SWITCH_EHT_ENABLED;
3971 else
3972 hapd->iconf->ch_switch_eht_config |= CH_SWITCH_EHT_DISABLED;
3973
Hai Shalom60840252021-02-19 19:02:11 -08003974 if (freq_params->he_enabled)
3975 hapd->iconf->ch_switch_he_config |= CH_SWITCH_HE_ENABLED;
3976 else
3977 hapd->iconf->ch_switch_he_config |= CH_SWITCH_HE_DISABLED;
3978
3979 if (freq_params->vht_enabled)
Roshan Pius3a1667e2018-07-03 15:17:14 -07003980 hapd->iconf->ch_switch_vht_config |= CH_SWITCH_VHT_ENABLED;
3981 else
3982 hapd->iconf->ch_switch_vht_config |= CH_SWITCH_VHT_DISABLED;
3983
3984 hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
Hai Shalom60840252021-02-19 19:02:11 -08003985 HOSTAPD_LEVEL_INFO,
Sunil Ravia04bd252022-05-02 22:54:18 -07003986 "CHAN_SWITCH EHT config 0x%x HE config 0x%x VHT config 0x%x",
3987 hapd->iconf->ch_switch_eht_config,
Hai Shalom60840252021-02-19 19:02:11 -08003988 hapd->iconf->ch_switch_he_config,
Roshan Pius3a1667e2018-07-03 15:17:14 -07003989 hapd->iconf->ch_switch_vht_config);
3990}
3991
3992
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003993int hostapd_switch_channel(struct hostapd_data *hapd,
3994 struct csa_settings *settings)
3995{
3996 int ret;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003997
3998 if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA)) {
3999 wpa_printf(MSG_INFO, "CSA is not supported");
4000 return -1;
4001 }
4002
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07004003 ret = hostapd_fill_csa_settings(hapd, settings);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08004004 if (ret)
4005 return ret;
4006
4007 ret = hostapd_drv_switch_channel(hapd, settings);
4008 free_beacon_data(&settings->beacon_csa);
4009 free_beacon_data(&settings->beacon_after);
4010
4011 if (ret) {
4012 /* if we failed, clean cs parameters */
4013 hostapd_cleanup_cs_params(hapd);
4014 return ret;
4015 }
4016
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07004017 hapd->csa_in_progress = 1;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08004018 return 0;
4019}
4020
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07004021
4022void
4023hostapd_switch_channel_fallback(struct hostapd_iface *iface,
4024 const struct hostapd_freq_params *freq_params)
4025{
Sunil8cd6f4d2022-06-28 18:40:46 +00004026 int seg0_idx = 0, seg1_idx = 0;
4027 enum oper_chan_width bw = CONF_OPER_CHWIDTH_USE_HT;
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07004028
4029 wpa_printf(MSG_DEBUG, "Restarting all CSA-related BSSes");
4030
4031 if (freq_params->center_freq1)
Hai Shalom81f62d82019-07-22 12:10:00 -07004032 seg0_idx = 36 + (freq_params->center_freq1 - 5180) / 5;
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07004033 if (freq_params->center_freq2)
Hai Shalom81f62d82019-07-22 12:10:00 -07004034 seg1_idx = 36 + (freq_params->center_freq2 - 5180) / 5;
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07004035
4036 switch (freq_params->bandwidth) {
4037 case 0:
4038 case 20:
4039 case 40:
Sunil8cd6f4d2022-06-28 18:40:46 +00004040 bw = CONF_OPER_CHWIDTH_USE_HT;
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07004041 break;
4042 case 80:
4043 if (freq_params->center_freq2)
Sunil8cd6f4d2022-06-28 18:40:46 +00004044 bw = CONF_OPER_CHWIDTH_80P80MHZ;
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07004045 else
Sunil8cd6f4d2022-06-28 18:40:46 +00004046 bw = CONF_OPER_CHWIDTH_80MHZ;
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07004047 break;
4048 case 160:
Sunil8cd6f4d2022-06-28 18:40:46 +00004049 bw = CONF_OPER_CHWIDTH_160MHZ;
4050 break;
4051 case 320:
4052 bw = CONF_OPER_CHWIDTH_320MHZ;
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07004053 break;
4054 default:
4055 wpa_printf(MSG_WARNING, "Unknown CSA bandwidth: %d",
4056 freq_params->bandwidth);
4057 break;
4058 }
4059
4060 iface->freq = freq_params->freq;
4061 iface->conf->channel = freq_params->channel;
4062 iface->conf->secondary_channel = freq_params->sec_channel_offset;
Hai Shalom81f62d82019-07-22 12:10:00 -07004063 hostapd_set_oper_centr_freq_seg0_idx(iface->conf, seg0_idx);
4064 hostapd_set_oper_centr_freq_seg1_idx(iface->conf, seg1_idx);
4065 hostapd_set_oper_chwidth(iface->conf, bw);
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07004066 iface->conf->ieee80211n = freq_params->ht_enabled;
4067 iface->conf->ieee80211ac = freq_params->vht_enabled;
Hai Shalom81f62d82019-07-22 12:10:00 -07004068 iface->conf->ieee80211ax = freq_params->he_enabled;
Sunil Ravia04bd252022-05-02 22:54:18 -07004069 iface->conf->ieee80211be = freq_params->eht_enabled;
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07004070
4071 /*
4072 * cs_params must not be cleared earlier because the freq_params
4073 * argument may actually point to one of these.
Hai Shalom39ba6fc2019-01-22 12:40:38 -08004074 * These params will be cleared during interface disable below.
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07004075 */
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07004076 hostapd_disable_iface(iface);
4077 hostapd_enable_iface(iface);
4078}
4079
Sunil Ravia04bd252022-05-02 22:54:18 -07004080
4081#ifdef CONFIG_IEEE80211AX
4082
4083void hostapd_cleanup_cca_params(struct hostapd_data *hapd)
4084{
4085 hapd->cca_count = 0;
4086 hapd->cca_color = 0;
4087 hapd->cca_c_off_beacon = 0;
4088 hapd->cca_c_off_proberesp = 0;
4089 hapd->cca_in_progress = false;
4090}
4091
4092
4093static int hostapd_fill_cca_settings(struct hostapd_data *hapd,
4094 struct cca_settings *settings)
4095{
4096 struct hostapd_iface *iface = hapd->iface;
4097 u8 old_color;
4098 int ret;
4099
4100 if (!iface || iface->conf->he_op.he_bss_color_disabled)
4101 return -1;
4102
4103 old_color = iface->conf->he_op.he_bss_color;
4104 iface->conf->he_op.he_bss_color = hapd->cca_color;
4105 ret = hostapd_build_beacon_data(hapd, &settings->beacon_after);
4106 if (ret)
4107 return ret;
4108
4109 iface->conf->he_op.he_bss_color = old_color;
4110
4111 settings->cca_count = hapd->cca_count;
4112 settings->cca_color = hapd->cca_color,
4113 hapd->cca_in_progress = true;
4114
4115 ret = hostapd_build_beacon_data(hapd, &settings->beacon_cca);
4116 if (ret) {
4117 free_beacon_data(&settings->beacon_after);
4118 return ret;
4119 }
4120
4121 settings->counter_offset_beacon = hapd->cca_c_off_beacon;
4122 settings->counter_offset_presp = hapd->cca_c_off_proberesp;
4123
4124 return 0;
4125}
4126
4127
4128static void hostapd_switch_color_timeout_handler(void *eloop_data,
4129 void *user_ctx)
4130{
4131 struct hostapd_data *hapd = (struct hostapd_data *) eloop_data;
4132 os_time_t delta_t;
4133 unsigned int b;
4134 int i, r;
4135
4136 /* CCA can be triggered once the handler constantly receives
4137 * color collision events to for at least
4138 * DOT11BSS_COLOR_COLLISION_AP_PERIOD (50 s by default). */
4139 delta_t = hapd->last_color_collision.sec -
4140 hapd->first_color_collision.sec;
4141 if (delta_t < DOT11BSS_COLOR_COLLISION_AP_PERIOD)
4142 return;
4143
4144 r = os_random() % HE_OPERATION_BSS_COLOR_MAX;
4145 for (i = 0; i < HE_OPERATION_BSS_COLOR_MAX; i++) {
Sunil8cd6f4d2022-06-28 18:40:46 +00004146 if (r && !(hapd->color_collision_bitmap & (1ULL << r)))
Sunil Ravia04bd252022-05-02 22:54:18 -07004147 break;
4148
4149 r = (r + 1) % HE_OPERATION_BSS_COLOR_MAX;
4150 }
4151
4152 if (i == HE_OPERATION_BSS_COLOR_MAX) {
4153 /* There are no free colors so turn BSS coloring off */
4154 wpa_printf(MSG_INFO,
4155 "No free colors left, turning off BSS coloring");
4156 hapd->iface->conf->he_op.he_bss_color_disabled = 1;
4157 hapd->iface->conf->he_op.he_bss_color = os_random() % 63 + 1;
4158 for (b = 0; b < hapd->iface->num_bss; b++)
4159 ieee802_11_set_beacon(hapd->iface->bss[b]);
4160 return;
4161 }
4162
4163 for (b = 0; b < hapd->iface->num_bss; b++) {
4164 struct hostapd_data *bss = hapd->iface->bss[b];
4165 struct cca_settings settings;
4166 int ret;
4167
4168 hostapd_cleanup_cca_params(bss);
4169 bss->cca_color = r;
4170 bss->cca_count = 10;
4171
4172 if (hostapd_fill_cca_settings(bss, &settings)) {
4173 hostapd_cleanup_cca_params(bss);
4174 continue;
4175 }
4176
4177 ret = hostapd_drv_switch_color(bss, &settings);
4178 if (ret)
4179 hostapd_cleanup_cca_params(bss);
4180
4181 free_beacon_data(&settings.beacon_cca);
4182 free_beacon_data(&settings.beacon_after);
4183 }
4184}
4185
4186
4187void hostapd_switch_color(struct hostapd_data *hapd, u64 bitmap)
4188{
4189 struct os_reltime now;
4190
4191 if (hapd->cca_in_progress)
4192 return;
4193
4194 if (os_get_reltime(&now))
4195 return;
4196
4197 hapd->color_collision_bitmap = bitmap;
4198 hapd->last_color_collision = now;
4199
4200 if (eloop_is_timeout_registered(hostapd_switch_color_timeout_handler,
4201 hapd, NULL))
4202 return;
4203
4204 hapd->first_color_collision = now;
4205 /* 10 s window as margin for persistent color collision reporting */
4206 eloop_register_timeout(DOT11BSS_COLOR_COLLISION_AP_PERIOD + 10, 0,
4207 hostapd_switch_color_timeout_handler,
4208 hapd, NULL);
4209}
4210
4211#endif /* CONFIG_IEEE80211AX */
4212
Dmitry Shmidte4663042016-04-04 10:07:49 -07004213#endif /* NEED_AP_MLME */
4214
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004215
4216struct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces,
4217 const char *ifname)
4218{
4219 size_t i, j;
4220
4221 for (i = 0; i < interfaces->count; i++) {
4222 struct hostapd_iface *iface = interfaces->iface[i];
4223
4224 for (j = 0; j < iface->num_bss; j++) {
4225 struct hostapd_data *hapd = iface->bss[j];
4226
4227 if (os_strcmp(ifname, hapd->conf->iface) == 0)
4228 return hapd;
4229 }
4230 }
4231
4232 return NULL;
4233}
4234
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004235
4236void hostapd_periodic_iface(struct hostapd_iface *iface)
4237{
4238 size_t i;
4239
4240 ap_list_timer(iface);
4241
4242 for (i = 0; i < iface->num_bss; i++) {
4243 struct hostapd_data *hapd = iface->bss[i];
4244
4245 if (!hapd->started)
4246 continue;
4247
4248#ifndef CONFIG_NO_RADIUS
4249 hostapd_acl_expire(hapd);
4250#endif /* CONFIG_NO_RADIUS */
4251 }
4252}
Hai Shalom899fcc72020-10-19 14:38:18 -07004253
4254
4255#ifdef CONFIG_OCV
4256void hostapd_ocv_check_csa_sa_query(void *eloop_ctx, void *timeout_ctx)
4257{
4258 struct hostapd_data *hapd = eloop_ctx;
4259 struct sta_info *sta;
4260
4261 wpa_printf(MSG_DEBUG, "OCV: Post-CSA SA Query initiation check");
4262
4263 for (sta = hapd->sta_list; sta; sta = sta->next) {
4264 if (!sta->post_csa_sa_query)
4265 continue;
4266
4267 wpa_printf(MSG_DEBUG, "OCV: OCVC STA " MACSTR
4268 " did not start SA Query after CSA - disconnect",
4269 MAC2STR(sta->addr));
4270 ap_sta_disconnect(hapd, sta, sta->addr,
4271 WLAN_REASON_PREV_AUTH_NOT_VALID);
4272 }
4273}
4274#endif /* CONFIG_OCV */
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004275
4276
4277#ifdef CONFIG_IEEE80211BE
4278struct hostapd_data * hostapd_mld_get_link_bss(struct hostapd_data *hapd,
4279 u8 link_id)
4280{
4281 unsigned int i;
4282
4283 for (i = 0; i < hapd->iface->interfaces->count; i++) {
4284 struct hostapd_iface *h = hapd->iface->interfaces->iface[i];
4285 struct hostapd_data *h_hapd = h->bss[0];
4286 struct hostapd_bss_config *hconf = h_hapd->conf;
4287
4288 if (!hconf->mld_ap || hconf->mld_id != hapd->conf->mld_id)
4289 continue;
4290
4291 if (h_hapd->mld_link_id == link_id)
4292 return h_hapd;
4293 }
4294
4295 return NULL;
4296}
4297#endif /* CONFIG_IEEE80211BE */