blob: 77742f441d8459deaa328cd73156eede4aed9a18 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * hostapd / Initialization and configuration
Hai Shalom021b0b52019-04-10 11:17:58 -07003 * Copyright (c) 2002-2019, 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"
10
11#include "utils/common.h"
12#include "utils/eloop.h"
13#include "common/ieee802_11_defs.h"
Dmitry Shmidtcce06662013-11-04 18:44:24 -080014#include "common/wpa_ctrl.h"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080015#include "common/hw_features_common.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070016#include "radius/radius_client.h"
Dmitry Shmidt04949592012-07-19 12:16:46 -070017#include "radius/radius_das.h"
Dmitry Shmidt50b691d2014-05-21 14:01:45 -070018#include "eap_server/tncs.h"
Dmitry Shmidt2f74e362015-01-21 13:19:05 -080019#include "eapol_auth/eapol_auth_sm.h"
20#include "eapol_auth/eapol_auth_sm_i.h"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080021#include "fst/fst.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070022#include "hostapd.h"
23#include "authsrv.h"
24#include "sta_info.h"
25#include "accounting.h"
26#include "ap_list.h"
27#include "beacon.h"
28#include "iapp.h"
29#include "ieee802_1x.h"
30#include "ieee802_11_auth.h"
31#include "vlan_init.h"
32#include "wpa_auth.h"
33#include "wps_hostapd.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070034#include "dpp_hostapd.h"
35#include "gas_query_ap.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070036#include "hw_features.h"
37#include "wpa_auth_glue.h"
38#include "ap_drv_ops.h"
39#include "ap_config.h"
40#include "p2p_hostapd.h"
Dmitry Shmidt04949592012-07-19 12:16:46 -070041#include "gas_serv.h"
Dmitry Shmidt051af732013-10-22 13:52:46 -070042#include "dfs.h"
Dmitry Shmidt7832adb2014-04-29 10:53:02 -070043#include "ieee802_11.h"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080044#include "bss_load.h"
45#include "x_snoop.h"
46#include "dhcp_snoop.h"
47#include "ndisc_snoop.h"
Dmitry Shmidt849734c2016-05-27 09:59:01 -070048#include "neighbor_db.h"
49#include "rrm.h"
Dmitry Shmidtebd93af2017-02-21 13:40:44 -080050#include "fils_hlp.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070051#include "acs.h"
Roshan Pius3a1667e2018-07-03 15:17:14 -070052#include "hs20.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070053
54
Dmitry Shmidt04949592012-07-19 12:16:46 -070055static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070056static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd);
Dmitry Shmidtc55524a2011-07-07 11:18:38 -070057static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd);
Dmitry Shmidtcce06662013-11-04 18:44:24 -080058static int setup_interface2(struct hostapd_iface *iface);
59static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx);
Roshan Pius3a1667e2018-07-03 15:17:14 -070060static void hostapd_interface_setup_failure_handler(void *eloop_ctx,
61 void *timeout_ctx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070062
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070063
Dmitry Shmidt04949592012-07-19 12:16:46 -070064int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
65 int (*cb)(struct hostapd_iface *iface,
66 void *ctx), void *ctx)
67{
68 size_t i;
69 int ret;
70
71 for (i = 0; i < interfaces->count; i++) {
72 ret = cb(interfaces->iface[i], ctx);
73 if (ret)
74 return ret;
75 }
76
77 return 0;
78}
79
80
Hai Shalomce48b4a2018-09-05 11:41:35 -070081void hostapd_reconfig_encryption(struct hostapd_data *hapd)
82{
83 if (hapd->wpa_auth)
84 return;
85
86 hostapd_set_privacy(hapd, 0);
87 hostapd_setup_encryption(hapd->conf->iface, hapd);
88}
89
90
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070091static void hostapd_reload_bss(struct hostapd_data *hapd)
92{
Dmitry Shmidtcce06662013-11-04 18:44:24 -080093 struct hostapd_ssid *ssid;
94
Dmitry Shmidt29333592017-01-09 12:27:11 -080095 if (!hapd->started)
96 return;
97
Roshan Pius3a1667e2018-07-03 15:17:14 -070098 if (hapd->conf->wmm_enabled < 0)
99 hapd->conf->wmm_enabled = hapd->iconf->ieee80211n;
100
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700101#ifndef CONFIG_NO_RADIUS
102 radius_client_reconfig(hapd->radius, hapd->conf->radius);
103#endif /* CONFIG_NO_RADIUS */
104
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800105 ssid = &hapd->conf->ssid;
106 if (!ssid->wpa_psk_set && ssid->wpa_psk && !ssid->wpa_psk->next &&
107 ssid->wpa_passphrase_set && ssid->wpa_passphrase) {
108 /*
109 * Force PSK to be derived again since SSID or passphrase may
110 * have changed.
111 */
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800112 hostapd_config_clear_wpa_psk(&hapd->conf->ssid.wpa_psk);
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800113 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700114 if (hostapd_setup_wpa_psk(hapd->conf)) {
115 wpa_printf(MSG_ERROR, "Failed to re-configure WPA PSK "
116 "after reloading configuration");
117 }
118
119 if (hapd->conf->ieee802_1x || hapd->conf->wpa)
120 hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 1);
121 else
122 hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0);
123
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800124 if ((hapd->conf->wpa || hapd->conf->osen) && hapd->wpa_auth == NULL) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700125 hostapd_setup_wpa(hapd);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800126 if (hapd->wpa_auth)
127 wpa_init_keys(hapd->wpa_auth);
128 } else if (hapd->conf->wpa) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700129 const u8 *wpa_ie;
130 size_t wpa_ie_len;
131 hostapd_reconfig_wpa(hapd);
132 wpa_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &wpa_ie_len);
133 if (hostapd_set_generic_elem(hapd, wpa_ie, wpa_ie_len))
134 wpa_printf(MSG_ERROR, "Failed to configure WPA IE for "
135 "the kernel driver.");
136 } else if (hapd->wpa_auth) {
137 wpa_deinit(hapd->wpa_auth);
138 hapd->wpa_auth = NULL;
139 hostapd_set_privacy(hapd, 0);
140 hostapd_setup_encryption(hapd->conf->iface, hapd);
141 hostapd_set_generic_elem(hapd, (u8 *) "", 0);
142 }
143
144 ieee802_11_set_beacon(hapd);
145 hostapd_update_wps(hapd);
146
147 if (hapd->conf->ssid.ssid_set &&
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700148 hostapd_set_ssid(hapd, hapd->conf->ssid.ssid,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700149 hapd->conf->ssid.ssid_len)) {
150 wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver");
151 /* try to continue */
152 }
153 wpa_printf(MSG_DEBUG, "Reconfigured interface %s", hapd->conf->iface);
154}
155
156
Dmitry Shmidt444d5672013-04-01 13:08:44 -0700157static void hostapd_clear_old(struct hostapd_iface *iface)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700158{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700159 size_t j;
160
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700161 /*
162 * Deauthenticate all stations since the new configuration may not
163 * allow them to use the BSS anymore.
164 */
165 for (j = 0; j < iface->num_bss; j++) {
Dmitry Shmidt04949592012-07-19 12:16:46 -0700166 hostapd_flush_old_stations(iface->bss[j],
167 WLAN_REASON_PREV_AUTH_NOT_VALID);
Dmitry Shmidtc55524a2011-07-07 11:18:38 -0700168 hostapd_broadcast_wep_clear(iface->bss[j]);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700169
170#ifndef CONFIG_NO_RADIUS
171 /* TODO: update dynamic data based on changed configuration
172 * items (e.g., open/close sockets, etc.) */
173 radius_client_flush(iface->bss[j]->radius, 0);
174#endif /* CONFIG_NO_RADIUS */
175 }
Dmitry Shmidt444d5672013-04-01 13:08:44 -0700176}
177
178
Hai Shalom74f70d42019-02-11 14:42:39 -0800179static int hostapd_iface_conf_changed(struct hostapd_config *newconf,
180 struct hostapd_config *oldconf)
181{
182 size_t i;
183
184 if (newconf->num_bss != oldconf->num_bss)
185 return 1;
186
187 for (i = 0; i < newconf->num_bss; i++) {
188 if (os_strcmp(newconf->bss[i]->iface,
189 oldconf->bss[i]->iface) != 0)
190 return 1;
191 }
192
193 return 0;
194}
195
196
Dmitry Shmidt444d5672013-04-01 13:08:44 -0700197int hostapd_reload_config(struct hostapd_iface *iface)
198{
Hai Shalom74f70d42019-02-11 14:42:39 -0800199 struct hapd_interfaces *interfaces = iface->interfaces;
Dmitry Shmidt444d5672013-04-01 13:08:44 -0700200 struct hostapd_data *hapd = iface->bss[0];
201 struct hostapd_config *newconf, *oldconf;
202 size_t j;
203
204 if (iface->config_fname == NULL) {
205 /* Only in-memory config in use - assume it has been updated */
206 hostapd_clear_old(iface);
207 for (j = 0; j < iface->num_bss; j++)
208 hostapd_reload_bss(iface->bss[j]);
209 return 0;
210 }
211
212 if (iface->interfaces == NULL ||
213 iface->interfaces->config_read_cb == NULL)
214 return -1;
215 newconf = iface->interfaces->config_read_cb(iface->config_fname);
216 if (newconf == NULL)
217 return -1;
218
219 hostapd_clear_old(iface);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700220
221 oldconf = hapd->iconf;
Hai Shalom74f70d42019-02-11 14:42:39 -0800222 if (hostapd_iface_conf_changed(newconf, oldconf)) {
223 char *fname;
224 int res;
225
226 wpa_printf(MSG_DEBUG,
227 "Configuration changes include interface/BSS modification - force full disable+enable sequence");
228 fname = os_strdup(iface->config_fname);
229 if (!fname) {
230 hostapd_config_free(newconf);
231 return -1;
232 }
233 hostapd_remove_iface(interfaces, hapd->conf->iface);
234 iface = hostapd_init(interfaces, fname);
235 os_free(fname);
236 hostapd_config_free(newconf);
237 if (!iface) {
238 wpa_printf(MSG_ERROR,
239 "Failed to initialize interface on config reload");
240 return -1;
241 }
242 iface->interfaces = interfaces;
243 interfaces->iface[interfaces->count] = iface;
244 interfaces->count++;
245 res = hostapd_enable_iface(iface);
246 if (res < 0)
247 wpa_printf(MSG_ERROR,
248 "Failed to enable interface on config reload");
249 return res;
250 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700251 iface->conf = newconf;
252
253 for (j = 0; j < iface->num_bss; j++) {
254 hapd = iface->bss[j];
255 hapd->iconf = newconf;
Dmitry Shmidtd11f0192014-03-24 12:09:47 -0700256 hapd->iconf->channel = oldconf->channel;
Dmitry Shmidtdda10c22015-03-24 16:05:01 -0700257 hapd->iconf->acs = oldconf->acs;
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -0700258 hapd->iconf->secondary_channel = oldconf->secondary_channel;
Dmitry Shmidtd11f0192014-03-24 12:09:47 -0700259 hapd->iconf->ieee80211n = oldconf->ieee80211n;
260 hapd->iconf->ieee80211ac = oldconf->ieee80211ac;
261 hapd->iconf->ht_capab = oldconf->ht_capab;
262 hapd->iconf->vht_capab = oldconf->vht_capab;
263 hapd->iconf->vht_oper_chwidth = oldconf->vht_oper_chwidth;
264 hapd->iconf->vht_oper_centr_freq_seg0_idx =
265 oldconf->vht_oper_centr_freq_seg0_idx;
266 hapd->iconf->vht_oper_centr_freq_seg1_idx =
267 oldconf->vht_oper_centr_freq_seg1_idx;
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800268 hapd->conf = newconf->bss[j];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700269 hostapd_reload_bss(hapd);
270 }
271
272 hostapd_config_free(oldconf);
273
274
275 return 0;
276}
277
278
279static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -0700280 const char *ifname)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700281{
282 int i;
283
Dmitry Shmidt29333592017-01-09 12:27:11 -0800284 if (!ifname || !hapd->drv_priv)
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -0700285 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700286 for (i = 0; i < NUM_WEP_KEYS; i++) {
287 if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i,
288 0, NULL, 0, NULL, 0)) {
289 wpa_printf(MSG_DEBUG, "Failed to clear default "
290 "encryption keys (ifname=%s keyidx=%d)",
291 ifname, i);
292 }
293 }
294#ifdef CONFIG_IEEE80211W
295 if (hapd->conf->ieee80211w) {
296 for (i = NUM_WEP_KEYS; i < NUM_WEP_KEYS + 2; i++) {
297 if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE,
298 NULL, i, 0, NULL,
299 0, NULL, 0)) {
300 wpa_printf(MSG_DEBUG, "Failed to clear "
301 "default mgmt encryption keys "
302 "(ifname=%s keyidx=%d)", ifname, i);
303 }
304 }
305 }
306#endif /* CONFIG_IEEE80211W */
307}
308
309
310static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd)
311{
312 hostapd_broadcast_key_clear_iface(hapd, hapd->conf->iface);
313 return 0;
314}
315
316
317static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
318{
319 int errors = 0, idx;
320 struct hostapd_ssid *ssid = &hapd->conf->ssid;
321
322 idx = ssid->wep.idx;
323 if (ssid->wep.default_len &&
324 hostapd_drv_set_key(hapd->conf->iface,
325 hapd, WPA_ALG_WEP, broadcast_ether_addr, idx,
326 1, NULL, 0, ssid->wep.key[idx],
327 ssid->wep.len[idx])) {
328 wpa_printf(MSG_WARNING, "Could not set WEP encryption.");
329 errors++;
330 }
331
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700332 return errors;
333}
334
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700335
Dmitry Shmidt04949592012-07-19 12:16:46 -0700336static void hostapd_free_hapd_data(struct hostapd_data *hapd)
337{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800338 os_free(hapd->probereq_cb);
339 hapd->probereq_cb = NULL;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800340 hapd->num_probereq_cb = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800341
342#ifdef CONFIG_P2P
343 wpabuf_free(hapd->p2p_beacon_ie);
344 hapd->p2p_beacon_ie = NULL;
345 wpabuf_free(hapd->p2p_probe_resp_ie);
346 hapd->p2p_probe_resp_ie = NULL;
347#endif /* CONFIG_P2P */
348
Dmitry Shmidtfa3fc4a2013-11-21 13:34:38 -0800349 if (!hapd->started) {
350 wpa_printf(MSG_ERROR, "%s: Interface %s wasn't started",
Hai Shalom021b0b52019-04-10 11:17:58 -0700351 __func__, hapd->conf ? hapd->conf->iface : "N/A");
Dmitry Shmidtfa3fc4a2013-11-21 13:34:38 -0800352 return;
353 }
354 hapd->started = 0;
355
Dmitry Shmidt54605472013-11-08 11:10:19 -0800356 wpa_printf(MSG_DEBUG, "%s(%s)", __func__, hapd->conf->iface);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700357 iapp_deinit(hapd->iapp);
358 hapd->iapp = NULL;
359 accounting_deinit(hapd);
360 hostapd_deinit_wpa(hapd);
361 vlan_deinit(hapd);
362 hostapd_acl_deinit(hapd);
363#ifndef CONFIG_NO_RADIUS
364 radius_client_deinit(hapd->radius);
365 hapd->radius = NULL;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700366 radius_das_deinit(hapd->radius_das);
367 hapd->radius_das = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700368#endif /* CONFIG_NO_RADIUS */
369
370 hostapd_deinit_wps(hapd);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700371#ifdef CONFIG_DPP
372 hostapd_dpp_deinit(hapd);
373 gas_query_ap_deinit(hapd->gas);
374#endif /* CONFIG_DPP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700375
376 authsrv_deinit(hapd);
377
Dmitry Shmidt71757432014-06-02 13:50:35 -0700378 if (hapd->interface_added) {
379 hapd->interface_added = 0;
380 if (hostapd_if_remove(hapd, WPA_IF_AP_BSS, hapd->conf->iface)) {
381 wpa_printf(MSG_WARNING,
382 "Failed to remove BSS interface %s",
383 hapd->conf->iface);
384 hapd->interface_added = 1;
385 } else {
386 /*
387 * Since this was a dynamically added interface, the
388 * driver wrapper may have removed its internal instance
389 * and hapd->drv_priv is not valid anymore.
390 */
391 hapd->drv_priv = NULL;
392 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700393 }
394
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800395 wpabuf_free(hapd->time_adv);
Dmitry Shmidt04949592012-07-19 12:16:46 -0700396
397#ifdef CONFIG_INTERWORKING
398 gas_serv_deinit(hapd);
399#endif /* CONFIG_INTERWORKING */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800400
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800401 bss_load_update_deinit(hapd);
402 ndisc_snoop_deinit(hapd);
403 dhcp_snoop_deinit(hapd);
404 x_snoop_deinit(hapd);
405
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800406#ifdef CONFIG_SQLITE
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700407 bin_clear_free(hapd->tmp_eap_user.identity,
408 hapd->tmp_eap_user.identity_len);
409 bin_clear_free(hapd->tmp_eap_user.password,
410 hapd->tmp_eap_user.password_len);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800411#endif /* CONFIG_SQLITE */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800412
413#ifdef CONFIG_MESH
414 wpabuf_free(hapd->mesh_pending_auth);
415 hapd->mesh_pending_auth = NULL;
416#endif /* CONFIG_MESH */
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700417
418 hostapd_clean_rrm(hapd);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -0800419 fils_hlp_deinit(hapd);
Hai Shalom021b0b52019-04-10 11:17:58 -0700420
421#ifdef CONFIG_SAE
422 {
423 struct hostapd_sae_commit_queue *q;
424
425 while ((q = dl_list_first(&hapd->sae_commit_queue,
426 struct hostapd_sae_commit_queue,
427 list))) {
428 dl_list_del(&q->list);
429 os_free(q);
430 }
431 }
432 eloop_cancel_timeout(auth_sae_process_commit, hapd, NULL);
433#endif /* CONFIG_SAE */
Dmitry Shmidt04949592012-07-19 12:16:46 -0700434}
435
436
437/**
438 * hostapd_cleanup - Per-BSS cleanup (deinitialization)
439 * @hapd: Pointer to BSS data
440 *
441 * This function is used to free all per-BSS data structures and resources.
Dmitry Shmidt54605472013-11-08 11:10:19 -0800442 * Most of the modules that are initialized in hostapd_setup_bss() are
443 * deinitialized here.
Dmitry Shmidt04949592012-07-19 12:16:46 -0700444 */
445static void hostapd_cleanup(struct hostapd_data *hapd)
446{
Dmitry Shmidt54605472013-11-08 11:10:19 -0800447 wpa_printf(MSG_DEBUG, "%s(hapd=%p (%s))", __func__, hapd,
Hai Shalom021b0b52019-04-10 11:17:58 -0700448 hapd->conf ? hapd->conf->iface : "N/A");
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700449 if (hapd->iface->interfaces &&
Dmitry Shmidt29333592017-01-09 12:27:11 -0800450 hapd->iface->interfaces->ctrl_iface_deinit) {
451 wpa_msg(hapd->msg_ctx, MSG_INFO, WPA_EVENT_TERMINATING);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700452 hapd->iface->interfaces->ctrl_iface_deinit(hapd);
Dmitry Shmidt29333592017-01-09 12:27:11 -0800453 }
Dmitry Shmidt04949592012-07-19 12:16:46 -0700454 hostapd_free_hapd_data(hapd);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700455}
456
457
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800458static void sta_track_deinit(struct hostapd_iface *iface)
459{
460 struct hostapd_sta_info *info;
461
462 if (!iface->num_sta_seen)
463 return;
464
465 while ((info = dl_list_first(&iface->sta_seen, struct hostapd_sta_info,
466 list))) {
467 dl_list_del(&info->list);
468 iface->num_sta_seen--;
Dmitry Shmidtaca489e2016-09-28 15:44:14 -0700469 sta_track_del(info);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800470 }
471}
472
473
Dmitry Shmidt04949592012-07-19 12:16:46 -0700474static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
475{
Dmitry Shmidt54605472013-11-08 11:10:19 -0800476 wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800477#ifdef CONFIG_IEEE80211N
478#ifdef NEED_AP_MLME
479 hostapd_stop_setup_timers(iface);
480#endif /* NEED_AP_MLME */
481#endif /* CONFIG_IEEE80211N */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700482 if (iface->current_mode)
483 acs_cleanup(iface);
Dmitry Shmidt04949592012-07-19 12:16:46 -0700484 hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
485 iface->hw_features = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700486 iface->current_mode = NULL;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700487 os_free(iface->current_rates);
488 iface->current_rates = NULL;
489 os_free(iface->basic_rates);
490 iface->basic_rates = NULL;
491 ap_list_deinit(iface);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800492 sta_track_deinit(iface);
Dmitry Shmidt04949592012-07-19 12:16:46 -0700493}
494
495
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700496/**
497 * hostapd_cleanup_iface - Complete per-interface cleanup
498 * @iface: Pointer to interface data
499 *
500 * This function is called after per-BSS data structures are deinitialized
501 * with hostapd_cleanup().
502 */
503static void hostapd_cleanup_iface(struct hostapd_iface *iface)
504{
Dmitry Shmidt54605472013-11-08 11:10:19 -0800505 wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800506 eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700507 eloop_cancel_timeout(hostapd_interface_setup_failure_handler, iface,
508 NULL);
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800509
Dmitry Shmidt04949592012-07-19 12:16:46 -0700510 hostapd_cleanup_iface_partial(iface);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700511 hostapd_config_free(iface->conf);
512 iface->conf = NULL;
513
514 os_free(iface->config_fname);
515 os_free(iface->bss);
Dmitry Shmidt54605472013-11-08 11:10:19 -0800516 wpa_printf(MSG_DEBUG, "%s: free iface=%p", __func__, iface);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700517 os_free(iface);
518}
519
520
Dmitry Shmidt04949592012-07-19 12:16:46 -0700521static void hostapd_clear_wep(struct hostapd_data *hapd)
522{
Hai Shalom021b0b52019-04-10 11:17:58 -0700523 if (hapd->drv_priv && !hapd->iface->driver_ap_teardown && hapd->conf) {
Dmitry Shmidt04949592012-07-19 12:16:46 -0700524 hostapd_set_privacy(hapd, 0);
525 hostapd_broadcast_wep_clear(hapd);
526 }
527}
528
529
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700530static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd)
531{
532 int i;
533
534 hostapd_broadcast_wep_set(hapd);
535
536 if (hapd->conf->ssid.wep.default_len) {
537 hostapd_set_privacy(hapd, 1);
538 return 0;
539 }
540
Jouni Malinen75ecf522011-06-27 15:19:46 -0700541 /*
542 * When IEEE 802.1X is not enabled, the driver may need to know how to
543 * set authentication algorithms for static WEP.
544 */
545 hostapd_drv_set_authmode(hapd, hapd->conf->auth_algs);
546
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700547 for (i = 0; i < 4; i++) {
548 if (hapd->conf->ssid.wep.key[i] &&
549 hostapd_drv_set_key(iface, hapd, WPA_ALG_WEP, NULL, i,
550 i == hapd->conf->ssid.wep.idx, NULL, 0,
551 hapd->conf->ssid.wep.key[i],
552 hapd->conf->ssid.wep.len[i])) {
553 wpa_printf(MSG_WARNING, "Could not set WEP "
554 "encryption.");
555 return -1;
556 }
557 if (hapd->conf->ssid.wep.key[i] &&
558 i == hapd->conf->ssid.wep.idx)
559 hostapd_set_privacy(hapd, 1);
560 }
561
562 return 0;
563}
564
565
Dmitry Shmidt04949592012-07-19 12:16:46 -0700566static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700567{
568 int ret = 0;
569 u8 addr[ETH_ALEN];
570
571 if (hostapd_drv_none(hapd) || hapd->drv_priv == NULL)
572 return 0;
573
Dmitry Shmidta38abf92014-03-06 13:38:44 -0800574 if (!hapd->iface->driver_ap_teardown) {
575 wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
576 "Flushing old station entries");
577
578 if (hostapd_flush(hapd)) {
579 wpa_msg(hapd->msg_ctx, MSG_WARNING,
580 "Could not connect to kernel driver");
581 ret = -1;
582 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700583 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700584 if (hapd->conf && hapd->conf->broadcast_deauth) {
585 wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
586 "Deauthenticate all stations");
587 os_memset(addr, 0xff, ETH_ALEN);
588 hostapd_drv_sta_deauth(hapd, addr, reason);
589 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700590 hostapd_free_stas(hapd);
591
592 return ret;
593}
594
595
Dmitry Shmidt71757432014-06-02 13:50:35 -0700596static void hostapd_bss_deinit_no_free(struct hostapd_data *hapd)
597{
598 hostapd_free_stas(hapd);
599 hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
600 hostapd_clear_wep(hapd);
601}
602
603
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700604/**
605 * hostapd_validate_bssid_configuration - Validate BSSID configuration
606 * @iface: Pointer to interface data
607 * Returns: 0 on success, -1 on failure
608 *
609 * This function is used to validate that the configured BSSIDs are valid.
610 */
611static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface)
612{
613 u8 mask[ETH_ALEN] = { 0 };
614 struct hostapd_data *hapd = iface->bss[0];
615 unsigned int i = iface->conf->num_bss, bits = 0, j;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700616 int auto_addr = 0;
617
618 if (hostapd_drv_none(hapd))
619 return 0;
620
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -0800621 if (iface->conf->use_driver_iface_addr)
622 return 0;
623
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700624 /* Generate BSSID mask that is large enough to cover the BSSIDs. */
625
626 /* Determine the bits necessary to cover the number of BSSIDs. */
627 for (i--; i; i >>= 1)
628 bits++;
629
630 /* Determine the bits necessary to any configured BSSIDs,
631 if they are higher than the number of BSSIDs. */
632 for (j = 0; j < iface->conf->num_bss; j++) {
Dmitry Shmidt9c175262016-03-03 10:20:07 -0800633 if (is_zero_ether_addr(iface->conf->bss[j]->bssid)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700634 if (j)
635 auto_addr++;
636 continue;
637 }
638
639 for (i = 0; i < ETH_ALEN; i++) {
640 mask[i] |=
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800641 iface->conf->bss[j]->bssid[i] ^
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700642 hapd->own_addr[i];
643 }
644 }
645
646 if (!auto_addr)
647 goto skip_mask_ext;
648
649 for (i = 0; i < ETH_ALEN && mask[i] == 0; i++)
650 ;
651 j = 0;
652 if (i < ETH_ALEN) {
653 j = (5 - i) * 8;
654
655 while (mask[i] != 0) {
656 mask[i] >>= 1;
657 j++;
658 }
659 }
660
661 if (bits < j)
662 bits = j;
663
664 if (bits > 40) {
665 wpa_printf(MSG_ERROR, "Too many bits in the BSSID mask (%u)",
666 bits);
667 return -1;
668 }
669
670 os_memset(mask, 0xff, ETH_ALEN);
671 j = bits / 8;
672 for (i = 5; i > 5 - j; i--)
673 mask[i] = 0;
674 j = bits % 8;
Hai Shalom021b0b52019-04-10 11:17:58 -0700675 while (j) {
676 j--;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700677 mask[i] <<= 1;
Hai Shalom021b0b52019-04-10 11:17:58 -0700678 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700679
680skip_mask_ext:
681 wpa_printf(MSG_DEBUG, "BSS count %lu, BSSID mask " MACSTR " (%d bits)",
682 (unsigned long) iface->conf->num_bss, MAC2STR(mask), bits);
683
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700684 if (!auto_addr)
685 return 0;
686
687 for (i = 0; i < ETH_ALEN; i++) {
688 if ((hapd->own_addr[i] & mask[i]) != hapd->own_addr[i]) {
689 wpa_printf(MSG_ERROR, "Invalid BSSID mask " MACSTR
690 " for start address " MACSTR ".",
691 MAC2STR(mask), MAC2STR(hapd->own_addr));
692 wpa_printf(MSG_ERROR, "Start address must be the "
693 "first address in the block (i.e., addr "
694 "AND mask == addr).");
695 return -1;
696 }
697 }
698
699 return 0;
700}
701
702
703static int mac_in_conf(struct hostapd_config *conf, const void *a)
704{
705 size_t i;
706
707 for (i = 0; i < conf->num_bss; i++) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800708 if (hostapd_mac_comp(conf->bss[i]->bssid, a) == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700709 return 1;
710 }
711 }
712
713 return 0;
714}
715
716
Dmitry Shmidt04949592012-07-19 12:16:46 -0700717#ifndef CONFIG_NO_RADIUS
718
719static int hostapd_das_nas_mismatch(struct hostapd_data *hapd,
720 struct radius_das_attrs *attr)
721{
Dmitry Shmidt13ca8d82014-02-20 10:18:40 -0800722 if (attr->nas_identifier &&
723 (!hapd->conf->nas_identifier ||
724 os_strlen(hapd->conf->nas_identifier) !=
725 attr->nas_identifier_len ||
726 os_memcmp(hapd->conf->nas_identifier, attr->nas_identifier,
727 attr->nas_identifier_len) != 0)) {
728 wpa_printf(MSG_DEBUG, "RADIUS DAS: NAS-Identifier mismatch");
729 return 1;
730 }
731
732 if (attr->nas_ip_addr &&
733 (hapd->conf->own_ip_addr.af != AF_INET ||
734 os_memcmp(&hapd->conf->own_ip_addr.u.v4, attr->nas_ip_addr, 4) !=
735 0)) {
736 wpa_printf(MSG_DEBUG, "RADIUS DAS: NAS-IP-Address mismatch");
737 return 1;
738 }
739
740#ifdef CONFIG_IPV6
741 if (attr->nas_ipv6_addr &&
742 (hapd->conf->own_ip_addr.af != AF_INET6 ||
743 os_memcmp(&hapd->conf->own_ip_addr.u.v6, attr->nas_ipv6_addr, 16)
744 != 0)) {
745 wpa_printf(MSG_DEBUG, "RADIUS DAS: NAS-IPv6-Address mismatch");
746 return 1;
747 }
748#endif /* CONFIG_IPV6 */
749
Dmitry Shmidt04949592012-07-19 12:16:46 -0700750 return 0;
751}
752
753
754static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800755 struct radius_das_attrs *attr,
756 int *multi)
Dmitry Shmidt04949592012-07-19 12:16:46 -0700757{
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800758 struct sta_info *selected, *sta;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700759 char buf[128];
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800760 int num_attr = 0;
761 int count;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700762
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800763 *multi = 0;
764
765 for (sta = hapd->sta_list; sta; sta = sta->next)
766 sta->radius_das_match = 1;
767
768 if (attr->sta_addr) {
769 num_attr++;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700770 sta = ap_get_sta(hapd, attr->sta_addr);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800771 if (!sta) {
772 wpa_printf(MSG_DEBUG,
773 "RADIUS DAS: No Calling-Station-Id match");
774 return NULL;
775 }
Dmitry Shmidt04949592012-07-19 12:16:46 -0700776
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800777 selected = sta;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700778 for (sta = hapd->sta_list; sta; sta = sta->next) {
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800779 if (sta != selected)
780 sta->radius_das_match = 0;
781 }
782 wpa_printf(MSG_DEBUG, "RADIUS DAS: Calling-Station-Id match");
783 }
784
785 if (attr->acct_session_id) {
786 num_attr++;
Dmitry Shmidtb97e4282016-02-08 10:16:07 -0800787 if (attr->acct_session_id_len != 16) {
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800788 wpa_printf(MSG_DEBUG,
789 "RADIUS DAS: Acct-Session-Id cannot match");
790 return NULL;
791 }
792 count = 0;
793
794 for (sta = hapd->sta_list; sta; sta = sta->next) {
795 if (!sta->radius_das_match)
796 continue;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800797 os_snprintf(buf, sizeof(buf), "%016llX",
798 (unsigned long long) sta->acct_session_id);
Dmitry Shmidtb97e4282016-02-08 10:16:07 -0800799 if (os_memcmp(attr->acct_session_id, buf, 16) != 0)
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800800 sta->radius_das_match = 0;
801 else
802 count++;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700803 }
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800804
805 if (count == 0) {
806 wpa_printf(MSG_DEBUG,
807 "RADIUS DAS: No matches remaining after Acct-Session-Id check");
808 return NULL;
809 }
810 wpa_printf(MSG_DEBUG, "RADIUS DAS: Acct-Session-Id match");
Dmitry Shmidt04949592012-07-19 12:16:46 -0700811 }
812
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800813 if (attr->acct_multi_session_id) {
814 num_attr++;
Dmitry Shmidtb97e4282016-02-08 10:16:07 -0800815 if (attr->acct_multi_session_id_len != 16) {
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800816 wpa_printf(MSG_DEBUG,
817 "RADIUS DAS: Acct-Multi-Session-Id cannot match");
818 return NULL;
819 }
820 count = 0;
821
822 for (sta = hapd->sta_list; sta; sta = sta->next) {
823 if (!sta->radius_das_match)
824 continue;
825 if (!sta->eapol_sm ||
Dmitry Shmidtb97e4282016-02-08 10:16:07 -0800826 !sta->eapol_sm->acct_multi_session_id) {
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800827 sta->radius_das_match = 0;
828 continue;
829 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800830 os_snprintf(buf, sizeof(buf), "%016llX",
831 (unsigned long long)
Dmitry Shmidtb97e4282016-02-08 10:16:07 -0800832 sta->eapol_sm->acct_multi_session_id);
833 if (os_memcmp(attr->acct_multi_session_id, buf, 16) !=
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800834 0)
835 sta->radius_das_match = 0;
836 else
837 count++;
838 }
839
840 if (count == 0) {
841 wpa_printf(MSG_DEBUG,
842 "RADIUS DAS: No matches remaining after Acct-Multi-Session-Id check");
843 return NULL;
844 }
845 wpa_printf(MSG_DEBUG,
846 "RADIUS DAS: Acct-Multi-Session-Id match");
847 }
848
849 if (attr->cui) {
850 num_attr++;
851 count = 0;
852
Dmitry Shmidt04949592012-07-19 12:16:46 -0700853 for (sta = hapd->sta_list; sta; sta = sta->next) {
854 struct wpabuf *cui;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800855
856 if (!sta->radius_das_match)
857 continue;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700858 cui = ieee802_1x_get_radius_cui(sta->eapol_sm);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800859 if (!cui || wpabuf_len(cui) != attr->cui_len ||
Dmitry Shmidt04949592012-07-19 12:16:46 -0700860 os_memcmp(wpabuf_head(cui), attr->cui,
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800861 attr->cui_len) != 0)
862 sta->radius_das_match = 0;
863 else
864 count++;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700865 }
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800866
867 if (count == 0) {
868 wpa_printf(MSG_DEBUG,
869 "RADIUS DAS: No matches remaining after Chargeable-User-Identity check");
870 return NULL;
871 }
872 wpa_printf(MSG_DEBUG,
873 "RADIUS DAS: Chargeable-User-Identity match");
Dmitry Shmidt04949592012-07-19 12:16:46 -0700874 }
875
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800876 if (attr->user_name) {
877 num_attr++;
878 count = 0;
879
Dmitry Shmidt04949592012-07-19 12:16:46 -0700880 for (sta = hapd->sta_list; sta; sta = sta->next) {
881 u8 *identity;
882 size_t identity_len;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800883
884 if (!sta->radius_das_match)
885 continue;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700886 identity = ieee802_1x_get_identity(sta->eapol_sm,
887 &identity_len);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800888 if (!identity ||
889 identity_len != attr->user_name_len ||
Dmitry Shmidt04949592012-07-19 12:16:46 -0700890 os_memcmp(identity, attr->user_name, identity_len)
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800891 != 0)
892 sta->radius_das_match = 0;
893 else
894 count++;
895 }
896
897 if (count == 0) {
898 wpa_printf(MSG_DEBUG,
899 "RADIUS DAS: No matches remaining after User-Name check");
900 return NULL;
901 }
902 wpa_printf(MSG_DEBUG,
903 "RADIUS DAS: User-Name match");
904 }
905
906 if (num_attr == 0) {
907 /*
908 * In theory, we could match all current associations, but it
909 * seems safer to just reject requests that do not include any
910 * session identification attributes.
911 */
912 wpa_printf(MSG_DEBUG,
913 "RADIUS DAS: No session identification attributes included");
914 return NULL;
915 }
916
917 selected = NULL;
918 for (sta = hapd->sta_list; sta; sta = sta->next) {
919 if (sta->radius_das_match) {
920 if (selected) {
921 *multi = 1;
922 return NULL;
923 }
924 selected = sta;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700925 }
926 }
927
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800928 return selected;
929}
930
931
932static int hostapd_das_disconnect_pmksa(struct hostapd_data *hapd,
933 struct radius_das_attrs *attr)
934{
935 if (!hapd->wpa_auth)
936 return -1;
937 return wpa_auth_radius_das_disconnect_pmksa(hapd->wpa_auth, attr);
Dmitry Shmidt04949592012-07-19 12:16:46 -0700938}
939
940
941static enum radius_das_res
942hostapd_das_disconnect(void *ctx, struct radius_das_attrs *attr)
943{
944 struct hostapd_data *hapd = ctx;
945 struct sta_info *sta;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800946 int multi;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700947
948 if (hostapd_das_nas_mismatch(hapd, attr))
949 return RADIUS_DAS_NAS_MISMATCH;
950
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800951 sta = hostapd_das_find_sta(hapd, attr, &multi);
952 if (sta == NULL) {
953 if (multi) {
954 wpa_printf(MSG_DEBUG,
955 "RADIUS DAS: Multiple sessions match - not supported");
956 return RADIUS_DAS_MULTI_SESSION_MATCH;
957 }
958 if (hostapd_das_disconnect_pmksa(hapd, attr) == 0) {
959 wpa_printf(MSG_DEBUG,
960 "RADIUS DAS: PMKSA cache entry matched");
961 return RADIUS_DAS_SUCCESS;
962 }
963 wpa_printf(MSG_DEBUG, "RADIUS DAS: No matching session found");
Dmitry Shmidt04949592012-07-19 12:16:46 -0700964 return RADIUS_DAS_SESSION_NOT_FOUND;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800965 }
Dmitry Shmidt04949592012-07-19 12:16:46 -0700966
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800967 wpa_printf(MSG_DEBUG, "RADIUS DAS: Found a matching session " MACSTR
968 " - disconnecting", MAC2STR(sta->addr));
Dmitry Shmidt13ca8d82014-02-20 10:18:40 -0800969 wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
970
Dmitry Shmidt04949592012-07-19 12:16:46 -0700971 hostapd_drv_sta_deauth(hapd, sta->addr,
972 WLAN_REASON_PREV_AUTH_NOT_VALID);
973 ap_sta_deauthenticate(hapd, sta, WLAN_REASON_PREV_AUTH_NOT_VALID);
974
975 return RADIUS_DAS_SUCCESS;
976}
977
Roshan Pius3a1667e2018-07-03 15:17:14 -0700978
979#ifdef CONFIG_HS20
980static enum radius_das_res
981hostapd_das_coa(void *ctx, struct radius_das_attrs *attr)
982{
983 struct hostapd_data *hapd = ctx;
984 struct sta_info *sta;
985 int multi;
986
987 if (hostapd_das_nas_mismatch(hapd, attr))
988 return RADIUS_DAS_NAS_MISMATCH;
989
990 sta = hostapd_das_find_sta(hapd, attr, &multi);
991 if (!sta) {
992 if (multi) {
993 wpa_printf(MSG_DEBUG,
994 "RADIUS DAS: Multiple sessions match - not supported");
995 return RADIUS_DAS_MULTI_SESSION_MATCH;
996 }
997 wpa_printf(MSG_DEBUG, "RADIUS DAS: No matching session found");
998 return RADIUS_DAS_SESSION_NOT_FOUND;
999 }
1000
1001 wpa_printf(MSG_DEBUG, "RADIUS DAS: Found a matching session " MACSTR
1002 " - CoA", MAC2STR(sta->addr));
1003
1004 if (attr->hs20_t_c_filtering) {
1005 if (attr->hs20_t_c_filtering[0] & BIT(0)) {
1006 wpa_printf(MSG_DEBUG,
1007 "HS 2.0: Unexpected Terms and Conditions filtering required in CoA-Request");
1008 return RADIUS_DAS_COA_FAILED;
1009 }
1010
1011 hs20_t_c_filtering(hapd, sta, 0);
1012 }
1013
1014 return RADIUS_DAS_SUCCESS;
1015}
1016#else /* CONFIG_HS20 */
1017#define hostapd_das_coa NULL
1018#endif /* CONFIG_HS20 */
1019
Dmitry Shmidt04949592012-07-19 12:16:46 -07001020#endif /* CONFIG_NO_RADIUS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001021
1022
1023/**
1024 * hostapd_setup_bss - Per-BSS setup (initialization)
1025 * @hapd: Pointer to BSS data
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001026 * @first: Whether this BSS is the first BSS of an interface; -1 = not first,
1027 * but interface may exist
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001028 *
1029 * This function is used to initialize all per-BSS data structures and
1030 * resources. This gets called in a loop for each BSS when an interface is
1031 * initialized. Most of the modules that are initialized here will be
1032 * deinitialized in hostapd_cleanup().
1033 */
1034static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
1035{
1036 struct hostapd_bss_config *conf = hapd->conf;
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07001037 u8 ssid[SSID_MAX_LEN + 1];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001038 int ssid_len, set_ssid;
1039 char force_ifname[IFNAMSIZ];
1040 u8 if_addr[ETH_ALEN];
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001041 int flush_old_stations = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001042
Dmitry Shmidt54605472013-11-08 11:10:19 -08001043 wpa_printf(MSG_DEBUG, "%s(hapd=%p (%s), first=%d)",
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001044 __func__, hapd, conf->iface, first);
Dmitry Shmidt54605472013-11-08 11:10:19 -08001045
Dmitry Shmidt50b691d2014-05-21 14:01:45 -07001046#ifdef EAP_SERVER_TNC
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001047 if (conf->tnc && tncs_global_init() < 0) {
Dmitry Shmidt50b691d2014-05-21 14:01:45 -07001048 wpa_printf(MSG_ERROR, "Failed to initialize TNCS");
1049 return -1;
1050 }
1051#endif /* EAP_SERVER_TNC */
1052
Dmitry Shmidt54605472013-11-08 11:10:19 -08001053 if (hapd->started) {
1054 wpa_printf(MSG_ERROR, "%s: Interface %s was already started",
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001055 __func__, conf->iface);
Dmitry Shmidt54605472013-11-08 11:10:19 -08001056 return -1;
1057 }
1058 hapd->started = 1;
1059
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001060 if (!first || first == -1) {
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08001061 u8 *addr = hapd->own_addr;
1062
1063 if (!is_zero_ether_addr(conf->bssid)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001064 /* Allocate the configured BSSID. */
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001065 os_memcpy(hapd->own_addr, conf->bssid, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001066
1067 if (hostapd_mac_comp(hapd->own_addr,
1068 hapd->iface->bss[0]->own_addr) ==
1069 0) {
1070 wpa_printf(MSG_ERROR, "BSS '%s' may not have "
1071 "BSSID set to the MAC address of "
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001072 "the radio", conf->iface);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001073 return -1;
1074 }
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08001075 } else if (hapd->iconf->use_driver_iface_addr) {
1076 addr = NULL;
1077 } else {
1078 /* Allocate the next available BSSID. */
1079 do {
1080 inc_byte_array(hapd->own_addr, ETH_ALEN);
1081 } while (mac_in_conf(hapd->iconf, hapd->own_addr));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001082 }
1083
Dmitry Shmidt54605472013-11-08 11:10:19 -08001084 hapd->interface_added = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001085 if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS,
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08001086 conf->iface, addr, hapd,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001087 &hapd->drv_priv, force_ifname, if_addr,
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001088 conf->bridge[0] ? conf->bridge : NULL,
1089 first == -1)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001090 wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID="
1091 MACSTR ")", MAC2STR(hapd->own_addr));
Dmitry Shmidt3cf6f792013-12-18 13:12:19 -08001092 hapd->interface_added = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001093 return -1;
1094 }
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08001095
1096 if (!addr)
1097 os_memcpy(hapd->own_addr, if_addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001098 }
1099
1100 if (conf->wmm_enabled < 0)
1101 conf->wmm_enabled = hapd->iconf->ieee80211n;
1102
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001103#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt9c175262016-03-03 10:20:07 -08001104 if (is_zero_ether_addr(conf->r1_key_holder))
1105 os_memcpy(conf->r1_key_holder, hapd->own_addr, ETH_ALEN);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001106#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt9c175262016-03-03 10:20:07 -08001107
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001108#ifdef CONFIG_MESH
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001109 if ((hapd->conf->mesh & MESH_ENABLED) && hapd->iface->mconf == NULL)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001110 flush_old_stations = 0;
1111#endif /* CONFIG_MESH */
1112
1113 if (flush_old_stations)
1114 hostapd_flush_old_stations(hapd,
1115 WLAN_REASON_PREV_AUTH_NOT_VALID);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001116 hostapd_set_privacy(hapd, 0);
1117
1118 hostapd_broadcast_wep_clear(hapd);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001119 if (hostapd_setup_encryption(conf->iface, hapd))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001120 return -1;
1121
1122 /*
1123 * Fetch the SSID from the system and use it or,
1124 * if one was specified in the config file, verify they
1125 * match.
1126 */
1127 ssid_len = hostapd_get_ssid(hapd, ssid, sizeof(ssid));
1128 if (ssid_len < 0) {
1129 wpa_printf(MSG_ERROR, "Could not read SSID from system");
1130 return -1;
1131 }
1132 if (conf->ssid.ssid_set) {
1133 /*
1134 * If SSID is specified in the config file and it differs
1135 * from what is being used then force installation of the
1136 * new SSID.
1137 */
1138 set_ssid = (conf->ssid.ssid_len != (size_t) ssid_len ||
1139 os_memcmp(conf->ssid.ssid, ssid, ssid_len) != 0);
1140 } else {
1141 /*
1142 * No SSID in the config file; just use the one we got
1143 * from the system.
1144 */
1145 set_ssid = 0;
1146 conf->ssid.ssid_len = ssid_len;
1147 os_memcpy(conf->ssid.ssid, ssid, conf->ssid.ssid_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001148 }
1149
1150 if (!hostapd_drv_none(hapd)) {
1151 wpa_printf(MSG_ERROR, "Using interface %s with hwaddr " MACSTR
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001152 " and ssid \"%s\"",
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001153 conf->iface, MAC2STR(hapd->own_addr),
1154 wpa_ssid_txt(conf->ssid.ssid, conf->ssid.ssid_len));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001155 }
1156
1157 if (hostapd_setup_wpa_psk(conf)) {
1158 wpa_printf(MSG_ERROR, "WPA-PSK setup failed.");
1159 return -1;
1160 }
1161
1162 /* Set SSID for the kernel driver (to be used in beacon and probe
1163 * response frames) */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001164 if (set_ssid && hostapd_set_ssid(hapd, conf->ssid.ssid,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001165 conf->ssid.ssid_len)) {
1166 wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver");
1167 return -1;
1168 }
1169
Dmitry Shmidt818ea482014-03-10 13:15:21 -07001170 if (wpa_debug_level <= MSG_MSGDUMP)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001171 conf->radius->msg_dumps = 1;
1172#ifndef CONFIG_NO_RADIUS
1173 hapd->radius = radius_client_init(hapd, conf->radius);
1174 if (hapd->radius == NULL) {
1175 wpa_printf(MSG_ERROR, "RADIUS client initialization failed.");
1176 return -1;
1177 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07001178
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001179 if (conf->radius_das_port) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07001180 struct radius_das_conf das_conf;
1181 os_memset(&das_conf, 0, sizeof(das_conf));
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001182 das_conf.port = conf->radius_das_port;
1183 das_conf.shared_secret = conf->radius_das_shared_secret;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001184 das_conf.shared_secret_len =
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001185 conf->radius_das_shared_secret_len;
1186 das_conf.client_addr = &conf->radius_das_client_addr;
1187 das_conf.time_window = conf->radius_das_time_window;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001188 das_conf.require_event_timestamp =
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001189 conf->radius_das_require_event_timestamp;
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07001190 das_conf.require_message_authenticator =
1191 conf->radius_das_require_message_authenticator;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001192 das_conf.ctx = hapd;
1193 das_conf.disconnect = hostapd_das_disconnect;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001194 das_conf.coa = hostapd_das_coa;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001195 hapd->radius_das = radius_das_init(&das_conf);
1196 if (hapd->radius_das == NULL) {
1197 wpa_printf(MSG_ERROR, "RADIUS DAS initialization "
1198 "failed.");
1199 return -1;
1200 }
1201 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001202#endif /* CONFIG_NO_RADIUS */
1203
1204 if (hostapd_acl_init(hapd)) {
1205 wpa_printf(MSG_ERROR, "ACL initialization failed.");
1206 return -1;
1207 }
1208 if (hostapd_init_wps(hapd, conf))
1209 return -1;
1210
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001211#ifdef CONFIG_DPP
1212 hapd->gas = gas_query_ap_init(hapd, hapd->msg_ctx);
1213 if (!hapd->gas)
1214 return -1;
1215 if (hostapd_dpp_init(hapd))
1216 return -1;
1217#endif /* CONFIG_DPP */
1218
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001219 if (authsrv_init(hapd) < 0)
1220 return -1;
1221
1222 if (ieee802_1x_init(hapd)) {
1223 wpa_printf(MSG_ERROR, "IEEE 802.1X initialization failed.");
1224 return -1;
1225 }
1226
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001227 if ((conf->wpa || conf->osen) && hostapd_setup_wpa(hapd))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001228 return -1;
1229
1230 if (accounting_init(hapd)) {
1231 wpa_printf(MSG_ERROR, "Accounting initialization failed.");
1232 return -1;
1233 }
1234
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001235 if (conf->ieee802_11f &&
1236 (hapd->iapp = iapp_init(hapd, conf->iapp_iface)) == NULL) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001237 wpa_printf(MSG_ERROR, "IEEE 802.11F (IAPP) initialization "
1238 "failed.");
1239 return -1;
1240 }
1241
Dmitry Shmidt04949592012-07-19 12:16:46 -07001242#ifdef CONFIG_INTERWORKING
1243 if (gas_serv_init(hapd)) {
1244 wpa_printf(MSG_ERROR, "GAS server initialization failed");
1245 return -1;
1246 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07001247
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001248 if (conf->qos_map_set_len &&
1249 hostapd_drv_set_qos_map(hapd, conf->qos_map_set,
1250 conf->qos_map_set_len)) {
1251 wpa_printf(MSG_ERROR, "Failed to initialize QoS Map");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001252 return -1;
1253 }
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001254#endif /* CONFIG_INTERWORKING */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001255
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001256 if (conf->bss_load_update_period && bss_load_update_init(hapd)) {
1257 wpa_printf(MSG_ERROR, "BSS Load initialization failed");
1258 return -1;
1259 }
1260
1261 if (conf->proxy_arp) {
1262 if (x_snoop_init(hapd)) {
1263 wpa_printf(MSG_ERROR,
1264 "Generic snooping infrastructure initialization failed");
1265 return -1;
1266 }
1267
1268 if (dhcp_snoop_init(hapd)) {
1269 wpa_printf(MSG_ERROR,
1270 "DHCP snooping initialization failed");
1271 return -1;
1272 }
1273
1274 if (ndisc_snoop_init(hapd)) {
1275 wpa_printf(MSG_ERROR,
1276 "Neighbor Discovery snooping initialization failed");
1277 return -1;
1278 }
1279 }
1280
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001281 if (!hostapd_drv_none(hapd) && vlan_init(hapd)) {
1282 wpa_printf(MSG_ERROR, "VLAN initialization failed.");
1283 return -1;
1284 }
1285
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001286 if (!conf->start_disabled && ieee802_11_set_beacon(hapd) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001287 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001288
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001289 if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0)
1290 return -1;
1291
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001292 if (hapd->driver && hapd->driver->set_operstate)
1293 hapd->driver->set_operstate(hapd->drv_priv, 1);
1294
1295 return 0;
1296}
1297
1298
1299static void hostapd_tx_queue_params(struct hostapd_iface *iface)
1300{
1301 struct hostapd_data *hapd = iface->bss[0];
1302 int i;
1303 struct hostapd_tx_queue_params *p;
1304
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001305#ifdef CONFIG_MESH
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001306 if ((hapd->conf->mesh & MESH_ENABLED) && iface->mconf == NULL)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001307 return;
1308#endif /* CONFIG_MESH */
1309
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001310 for (i = 0; i < NUM_TX_QUEUES; i++) {
1311 p = &iface->conf->tx_queue[i];
1312
1313 if (hostapd_set_tx_queue_params(hapd, i, p->aifs, p->cwmin,
1314 p->cwmax, p->burst)) {
1315 wpa_printf(MSG_DEBUG, "Failed to set TX queue "
1316 "parameters for queue %d.", i);
1317 /* Continue anyway */
1318 }
1319 }
1320}
1321
1322
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07001323static int hostapd_set_acl_list(struct hostapd_data *hapd,
1324 struct mac_acl_entry *mac_acl,
1325 int n_entries, u8 accept_acl)
1326{
1327 struct hostapd_acl_params *acl_params;
1328 int i, err;
1329
1330 acl_params = os_zalloc(sizeof(*acl_params) +
1331 (n_entries * sizeof(acl_params->mac_acl[0])));
1332 if (!acl_params)
1333 return -ENOMEM;
1334
1335 for (i = 0; i < n_entries; i++)
1336 os_memcpy(acl_params->mac_acl[i].addr, mac_acl[i].addr,
1337 ETH_ALEN);
1338
1339 acl_params->acl_policy = accept_acl;
1340 acl_params->num_mac_acl = n_entries;
1341
1342 err = hostapd_drv_set_acl(hapd, acl_params);
1343
1344 os_free(acl_params);
1345
1346 return err;
1347}
1348
1349
1350static void hostapd_set_acl(struct hostapd_data *hapd)
1351{
1352 struct hostapd_config *conf = hapd->iconf;
1353 int err;
1354 u8 accept_acl;
1355
1356 if (hapd->iface->drv_max_acl_mac_addrs == 0)
1357 return;
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07001358
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001359 if (conf->bss[0]->macaddr_acl == DENY_UNLESS_ACCEPTED) {
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07001360 accept_acl = 1;
1361 err = hostapd_set_acl_list(hapd, conf->bss[0]->accept_mac,
1362 conf->bss[0]->num_accept_mac,
1363 accept_acl);
1364 if (err) {
1365 wpa_printf(MSG_DEBUG, "Failed to set accept acl");
1366 return;
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07001367 }
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001368 } else if (conf->bss[0]->macaddr_acl == ACCEPT_UNLESS_DENIED) {
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07001369 accept_acl = 0;
1370 err = hostapd_set_acl_list(hapd, conf->bss[0]->deny_mac,
1371 conf->bss[0]->num_deny_mac,
1372 accept_acl);
1373 if (err) {
1374 wpa_printf(MSG_DEBUG, "Failed to set deny acl");
1375 return;
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07001376 }
1377 }
1378}
1379
1380
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001381static int start_ctrl_iface_bss(struct hostapd_data *hapd)
1382{
1383 if (!hapd->iface->interfaces ||
1384 !hapd->iface->interfaces->ctrl_iface_init)
1385 return 0;
1386
1387 if (hapd->iface->interfaces->ctrl_iface_init(hapd)) {
1388 wpa_printf(MSG_ERROR,
1389 "Failed to setup control interface for %s",
1390 hapd->conf->iface);
1391 return -1;
1392 }
1393
1394 return 0;
1395}
1396
1397
1398static int start_ctrl_iface(struct hostapd_iface *iface)
1399{
1400 size_t i;
1401
1402 if (!iface->interfaces || !iface->interfaces->ctrl_iface_init)
1403 return 0;
1404
1405 for (i = 0; i < iface->num_bss; i++) {
1406 struct hostapd_data *hapd = iface->bss[i];
1407 if (iface->interfaces->ctrl_iface_init(hapd)) {
1408 wpa_printf(MSG_ERROR,
1409 "Failed to setup control interface for %s",
1410 hapd->conf->iface);
1411 return -1;
1412 }
1413 }
1414
1415 return 0;
1416}
1417
1418
1419static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx)
1420{
1421 struct hostapd_iface *iface = eloop_ctx;
1422
1423 if (!iface->wait_channel_update) {
1424 wpa_printf(MSG_INFO, "Channel list update timeout, but interface was not waiting for it");
1425 return;
1426 }
1427
1428 /*
1429 * It is possible that the existing channel list is acceptable, so try
1430 * to proceed.
1431 */
1432 wpa_printf(MSG_DEBUG, "Channel list update timeout - try to continue anyway");
1433 setup_interface2(iface);
1434}
1435
1436
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001437void hostapd_channel_list_updated(struct hostapd_iface *iface, int initiator)
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001438{
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001439 if (!iface->wait_channel_update || initiator != REGDOM_SET_BY_USER)
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001440 return;
1441
1442 wpa_printf(MSG_DEBUG, "Channel list updated - continue setup");
1443 eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
1444 setup_interface2(iface);
1445}
1446
1447
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001448static int setup_interface(struct hostapd_iface *iface)
1449{
1450 struct hostapd_data *hapd = iface->bss[0];
1451 size_t i;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001452
Dmitry Shmidta38abf92014-03-06 13:38:44 -08001453 /*
1454 * It is possible that setup_interface() is called after the interface
1455 * was disabled etc., in which case driver_ap_teardown is possibly set
1456 * to 1. Clear it here so any other key/station deletion, which is not
1457 * part of a teardown flow, would also call the relevant driver
1458 * callbacks.
1459 */
1460 iface->driver_ap_teardown = 0;
1461
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001462 if (!iface->phy[0]) {
1463 const char *phy = hostapd_drv_get_radio_name(hapd);
1464 if (phy) {
1465 wpa_printf(MSG_DEBUG, "phy: %s", phy);
1466 os_strlcpy(iface->phy, phy, sizeof(iface->phy));
1467 }
1468 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001469
1470 /*
1471 * Make sure that all BSSes get configured with a pointer to the same
1472 * driver interface.
1473 */
1474 for (i = 1; i < iface->num_bss; i++) {
1475 iface->bss[i]->driver = hapd->driver;
1476 iface->bss[i]->drv_priv = hapd->drv_priv;
1477 }
1478
1479 if (hostapd_validate_bssid_configuration(iface))
1480 return -1;
1481
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001482 /*
1483 * Initialize control interfaces early to allow external monitoring of
1484 * channel setup operations that may take considerable amount of time
1485 * especially for DFS cases.
1486 */
1487 if (start_ctrl_iface(iface))
1488 return -1;
1489
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001490 if (hapd->iconf->country[0] && hapd->iconf->country[1]) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001491 char country[4], previous_country[4];
1492
1493 hostapd_set_state(iface, HAPD_IFACE_COUNTRY_UPDATE);
1494 if (hostapd_get_country(hapd, previous_country) < 0)
1495 previous_country[0] = '\0';
1496
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001497 os_memcpy(country, hapd->iconf->country, 3);
1498 country[3] = '\0';
1499 if (hostapd_set_country(hapd, country) < 0) {
1500 wpa_printf(MSG_ERROR, "Failed to set country code");
1501 return -1;
1502 }
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001503
1504 wpa_printf(MSG_DEBUG, "Previous country code %s, new country code %s",
1505 previous_country, country);
1506
1507 if (os_strncmp(previous_country, country, 2) != 0) {
1508 wpa_printf(MSG_DEBUG, "Continue interface setup after channel list update");
1509 iface->wait_channel_update = 1;
Dmitry Shmidt97672262014-02-03 13:02:54 -08001510 eloop_register_timeout(5, 0,
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001511 channel_list_update_timeout,
1512 iface, NULL);
1513 return 0;
1514 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001515 }
1516
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001517 return setup_interface2(iface);
1518}
1519
1520
1521static int setup_interface2(struct hostapd_iface *iface)
1522{
1523 iface->wait_channel_update = 0;
1524
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001525 if (hostapd_get_hw_features(iface)) {
1526 /* Not all drivers support this yet, so continue without hw
1527 * feature data. */
1528 } else {
1529 int ret = hostapd_select_hw_mode(iface);
1530 if (ret < 0) {
1531 wpa_printf(MSG_ERROR, "Could not select hw_mode and "
1532 "channel. (%d)", ret);
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07001533 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001534 }
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07001535 if (ret == 1) {
1536 wpa_printf(MSG_DEBUG, "Interface initialization will be completed in a callback (ACS)");
1537 return 0;
1538 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001539 ret = hostapd_check_ht_capab(iface);
1540 if (ret < 0)
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07001541 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001542 if (ret == 1) {
1543 wpa_printf(MSG_DEBUG, "Interface initialization will "
1544 "be completed in a callback");
1545 return 0;
1546 }
Dmitry Shmidt051af732013-10-22 13:52:46 -07001547
1548 if (iface->conf->ieee80211h)
1549 wpa_printf(MSG_DEBUG, "DFS support is enabled");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001550 }
1551 return hostapd_setup_interface_complete(iface, 0);
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07001552
1553fail:
1554 hostapd_set_state(iface, HAPD_IFACE_DISABLED);
1555 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
1556 if (iface->interfaces && iface->interfaces->terminate_on_error)
1557 eloop_terminate();
1558 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001559}
1560
1561
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001562#ifdef CONFIG_FST
1563
1564static const u8 * fst_hostapd_get_bssid_cb(void *ctx)
1565{
1566 struct hostapd_data *hapd = ctx;
1567
1568 return hapd->own_addr;
1569}
1570
1571
1572static void fst_hostapd_get_channel_info_cb(void *ctx,
1573 enum hostapd_hw_mode *hw_mode,
1574 u8 *channel)
1575{
1576 struct hostapd_data *hapd = ctx;
1577
1578 *hw_mode = ieee80211_freq_to_chan(hapd->iface->freq, channel);
1579}
1580
1581
1582static void fst_hostapd_set_ies_cb(void *ctx, const struct wpabuf *fst_ies)
1583{
1584 struct hostapd_data *hapd = ctx;
1585
1586 if (hapd->iface->fst_ies != fst_ies) {
1587 hapd->iface->fst_ies = fst_ies;
1588 if (ieee802_11_set_beacon(hapd))
1589 wpa_printf(MSG_WARNING, "FST: Cannot set beacon");
1590 }
1591}
1592
1593
1594static int fst_hostapd_send_action_cb(void *ctx, const u8 *da,
1595 struct wpabuf *buf)
1596{
1597 struct hostapd_data *hapd = ctx;
1598
1599 return hostapd_drv_send_action(hapd, hapd->iface->freq, 0, da,
1600 wpabuf_head(buf), wpabuf_len(buf));
1601}
1602
1603
1604static const struct wpabuf * fst_hostapd_get_mb_ie_cb(void *ctx, const u8 *addr)
1605{
1606 struct hostapd_data *hapd = ctx;
1607 struct sta_info *sta = ap_get_sta(hapd, addr);
1608
1609 return sta ? sta->mb_ies : NULL;
1610}
1611
1612
1613static void fst_hostapd_update_mb_ie_cb(void *ctx, const u8 *addr,
1614 const u8 *buf, size_t size)
1615{
1616 struct hostapd_data *hapd = ctx;
1617 struct sta_info *sta = ap_get_sta(hapd, addr);
1618
1619 if (sta) {
1620 struct mb_ies_info info;
1621
1622 if (!mb_ies_info_by_ies(&info, buf, size)) {
1623 wpabuf_free(sta->mb_ies);
1624 sta->mb_ies = mb_ies_by_info(&info);
1625 }
1626 }
1627}
1628
1629
1630static const u8 * fst_hostapd_get_sta(struct fst_get_peer_ctx **get_ctx,
1631 Boolean mb_only)
1632{
1633 struct sta_info *s = (struct sta_info *) *get_ctx;
1634
1635 if (mb_only) {
1636 for (; s && !s->mb_ies; s = s->next)
1637 ;
1638 }
1639
1640 if (s) {
1641 *get_ctx = (struct fst_get_peer_ctx *) s->next;
1642
1643 return s->addr;
1644 }
1645
1646 *get_ctx = NULL;
1647 return NULL;
1648}
1649
1650
1651static const u8 * fst_hostapd_get_peer_first(void *ctx,
1652 struct fst_get_peer_ctx **get_ctx,
1653 Boolean mb_only)
1654{
1655 struct hostapd_data *hapd = ctx;
1656
1657 *get_ctx = (struct fst_get_peer_ctx *) hapd->sta_list;
1658
1659 return fst_hostapd_get_sta(get_ctx, mb_only);
1660}
1661
1662
1663static const u8 * fst_hostapd_get_peer_next(void *ctx,
1664 struct fst_get_peer_ctx **get_ctx,
1665 Boolean mb_only)
1666{
1667 return fst_hostapd_get_sta(get_ctx, mb_only);
1668}
1669
1670
1671void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd,
1672 struct fst_wpa_obj *iface_obj)
1673{
1674 iface_obj->ctx = hapd;
1675 iface_obj->get_bssid = fst_hostapd_get_bssid_cb;
1676 iface_obj->get_channel_info = fst_hostapd_get_channel_info_cb;
1677 iface_obj->set_ies = fst_hostapd_set_ies_cb;
1678 iface_obj->send_action = fst_hostapd_send_action_cb;
1679 iface_obj->get_mb_ie = fst_hostapd_get_mb_ie_cb;
1680 iface_obj->update_mb_ie = fst_hostapd_update_mb_ie_cb;
1681 iface_obj->get_peer_first = fst_hostapd_get_peer_first;
1682 iface_obj->get_peer_next = fst_hostapd_get_peer_next;
1683}
1684
1685#endif /* CONFIG_FST */
1686
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001687#ifdef CONFIG_OWE
1688
1689static int hostapd_owe_iface_iter(struct hostapd_iface *iface, void *ctx)
1690{
1691 struct hostapd_data *hapd = ctx;
1692 size_t i;
1693
1694 for (i = 0; i < iface->num_bss; i++) {
1695 struct hostapd_data *bss = iface->bss[i];
1696
1697 if (os_strcmp(hapd->conf->owe_transition_ifname,
1698 bss->conf->iface) != 0)
1699 continue;
1700
1701 wpa_printf(MSG_DEBUG,
1702 "OWE: ifname=%s found transition mode ifname=%s BSSID "
1703 MACSTR " SSID %s",
1704 hapd->conf->iface, bss->conf->iface,
1705 MAC2STR(bss->own_addr),
1706 wpa_ssid_txt(bss->conf->ssid.ssid,
1707 bss->conf->ssid.ssid_len));
1708 if (!bss->conf->ssid.ssid_set || !bss->conf->ssid.ssid_len ||
1709 is_zero_ether_addr(bss->own_addr))
1710 continue;
1711
1712 os_memcpy(hapd->conf->owe_transition_bssid, bss->own_addr,
1713 ETH_ALEN);
1714 os_memcpy(hapd->conf->owe_transition_ssid,
1715 bss->conf->ssid.ssid, bss->conf->ssid.ssid_len);
1716 hapd->conf->owe_transition_ssid_len = bss->conf->ssid.ssid_len;
1717 wpa_printf(MSG_DEBUG,
1718 "OWE: Copied transition mode information");
1719 return 1;
1720 }
1721
1722 return 0;
1723}
1724
1725
1726int hostapd_owe_trans_get_info(struct hostapd_data *hapd)
1727{
1728 if (hapd->conf->owe_transition_ssid_len > 0 &&
1729 !is_zero_ether_addr(hapd->conf->owe_transition_bssid))
1730 return 0;
1731
1732 /* Find transition mode SSID/BSSID information from a BSS operated by
1733 * this hostapd instance. */
1734 if (!hapd->iface->interfaces ||
1735 !hapd->iface->interfaces->for_each_interface)
1736 return hostapd_owe_iface_iter(hapd->iface, hapd);
1737 else
1738 return hapd->iface->interfaces->for_each_interface(
1739 hapd->iface->interfaces, hostapd_owe_iface_iter, hapd);
1740}
1741
1742
1743static int hostapd_owe_iface_iter2(struct hostapd_iface *iface, void *ctx)
1744{
1745 size_t i;
1746
1747 for (i = 0; i < iface->num_bss; i++) {
1748 struct hostapd_data *bss = iface->bss[i];
1749 int res;
1750
1751 if (!bss->conf->owe_transition_ifname[0])
1752 continue;
1753 res = hostapd_owe_trans_get_info(bss);
1754 if (res == 0)
1755 continue;
1756 wpa_printf(MSG_DEBUG,
1757 "OWE: Matching transition mode interface enabled - update beacon data for %s",
1758 bss->conf->iface);
1759 ieee802_11_set_beacon(bss);
1760 }
1761
1762 return 0;
1763}
1764
1765#endif /* CONFIG_OWE */
1766
1767
1768static void hostapd_owe_update_trans(struct hostapd_iface *iface)
1769{
1770#ifdef CONFIG_OWE
1771 /* Check whether the enabled BSS can complete OWE transition mode
1772 * configuration for any pending interface. */
1773 if (!iface->interfaces ||
1774 !iface->interfaces->for_each_interface)
1775 hostapd_owe_iface_iter2(iface, NULL);
1776 else
1777 iface->interfaces->for_each_interface(
1778 iface->interfaces, hostapd_owe_iface_iter2, NULL);
1779#endif /* CONFIG_OWE */
1780}
1781
1782
Roshan Pius3a1667e2018-07-03 15:17:14 -07001783static void hostapd_interface_setup_failure_handler(void *eloop_ctx,
1784 void *timeout_ctx)
1785{
1786 struct hostapd_iface *iface = eloop_ctx;
1787 struct hostapd_data *hapd;
1788
1789 if (iface->num_bss < 1 || !iface->bss || !iface->bss[0])
1790 return;
1791 hapd = iface->bss[0];
1792 if (hapd->setup_complete_cb)
1793 hapd->setup_complete_cb(hapd->setup_complete_cb_ctx);
1794}
1795
1796
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001797static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
1798 int err)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001799{
1800 struct hostapd_data *hapd = iface->bss[0];
1801 size_t j;
1802 u8 *prev_addr;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001803 int delay_apply_cfg = 0;
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08001804 int res_dfs_offload = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001805
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07001806 if (err)
1807 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001808
1809 wpa_printf(MSG_DEBUG, "Completing interface initialization");
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001810 if (iface->conf->channel) {
Dmitry Shmidt051af732013-10-22 13:52:46 -07001811#ifdef NEED_AP_MLME
1812 int res;
1813#endif /* NEED_AP_MLME */
1814
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001815 iface->freq = hostapd_hw_get_freq(hapd, iface->conf->channel);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001816 wpa_printf(MSG_DEBUG, "Mode: %s Channel: %d "
1817 "Frequency: %d MHz",
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001818 hostapd_hw_mode_txt(iface->conf->hw_mode),
1819 iface->conf->channel, iface->freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001820
Dmitry Shmidt051af732013-10-22 13:52:46 -07001821#ifdef NEED_AP_MLME
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001822 /* Handle DFS only if it is not offloaded to the driver */
1823 if (!(iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)) {
1824 /* Check DFS */
1825 res = hostapd_handle_dfs(iface);
1826 if (res <= 0) {
1827 if (res < 0)
1828 goto fail;
1829 return res;
1830 }
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08001831 } else {
1832 /* If DFS is offloaded to the driver */
1833 res_dfs_offload = hostapd_handle_dfs_offload(iface);
1834 if (res_dfs_offload <= 0) {
1835 if (res_dfs_offload < 0)
1836 goto fail;
1837 } else {
1838 wpa_printf(MSG_DEBUG,
1839 "Proceed with AP/channel setup");
1840 /*
1841 * If this is a DFS channel, move to completing
1842 * AP setup.
1843 */
1844 if (res_dfs_offload == 1)
1845 goto dfs_offload;
1846 /* Otherwise fall through. */
1847 }
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07001848 }
Dmitry Shmidt051af732013-10-22 13:52:46 -07001849#endif /* NEED_AP_MLME */
1850
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001851#ifdef CONFIG_MESH
1852 if (iface->mconf != NULL) {
1853 wpa_printf(MSG_DEBUG,
1854 "%s: Mesh configuration will be applied while joining the mesh network",
1855 iface->bss[0]->conf->iface);
1856 delay_apply_cfg = 1;
1857 }
1858#endif /* CONFIG_MESH */
1859
1860 if (!delay_apply_cfg &&
1861 hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001862 hapd->iconf->channel,
1863 hapd->iconf->ieee80211n,
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001864 hapd->iconf->ieee80211ac,
1865 hapd->iconf->secondary_channel,
1866 hapd->iconf->vht_oper_chwidth,
1867 hapd->iconf->vht_oper_centr_freq_seg0_idx,
1868 hapd->iconf->vht_oper_centr_freq_seg1_idx)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001869 wpa_printf(MSG_ERROR, "Could not set channel for "
1870 "kernel driver");
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07001871 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001872 }
1873 }
1874
1875 if (iface->current_mode) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001876 if (hostapd_prepare_rates(iface, iface->current_mode)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001877 wpa_printf(MSG_ERROR, "Failed to prepare rates "
1878 "table.");
1879 hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
1880 HOSTAPD_LEVEL_WARNING,
1881 "Failed to prepare rates table.");
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07001882 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001883 }
1884 }
1885
Hai Shalom021b0b52019-04-10 11:17:58 -07001886 if (hapd->iconf->rts_threshold >= -1 &&
1887 hostapd_set_rts(hapd, hapd->iconf->rts_threshold) &&
1888 hapd->iconf->rts_threshold >= -1) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001889 wpa_printf(MSG_ERROR, "Could not set RTS threshold for "
1890 "kernel driver");
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07001891 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001892 }
1893
Hai Shalom021b0b52019-04-10 11:17:58 -07001894 if (hapd->iconf->fragm_threshold >= -1 &&
1895 hostapd_set_frag(hapd, hapd->iconf->fragm_threshold) &&
1896 hapd->iconf->fragm_threshold != -1) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001897 wpa_printf(MSG_ERROR, "Could not set fragmentation threshold "
1898 "for kernel driver");
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07001899 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001900 }
1901
1902 prev_addr = hapd->own_addr;
1903
1904 for (j = 0; j < iface->num_bss; j++) {
1905 hapd = iface->bss[j];
1906 if (j)
1907 os_memcpy(hapd->own_addr, prev_addr, ETH_ALEN);
Dmitry Shmidt71757432014-06-02 13:50:35 -07001908 if (hostapd_setup_bss(hapd, j == 0)) {
Hai Shalom021b0b52019-04-10 11:17:58 -07001909 for (;;) {
Dmitry Shmidt71757432014-06-02 13:50:35 -07001910 hapd = iface->bss[j];
1911 hostapd_bss_deinit_no_free(hapd);
1912 hostapd_free_hapd_data(hapd);
Hai Shalom021b0b52019-04-10 11:17:58 -07001913 if (j == 0)
1914 break;
1915 j--;
1916 }
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07001917 goto fail;
Dmitry Shmidt71757432014-06-02 13:50:35 -07001918 }
Dmitry Shmidt9c175262016-03-03 10:20:07 -08001919 if (is_zero_ether_addr(hapd->conf->bssid))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001920 prev_addr = hapd->own_addr;
1921 }
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001922 hapd = iface->bss[0];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001923
1924 hostapd_tx_queue_params(iface);
1925
1926 ap_list_init(iface);
1927
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07001928 hostapd_set_acl(hapd);
1929
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001930 if (hostapd_driver_commit(hapd) < 0) {
1931 wpa_printf(MSG_ERROR, "%s: Failed to commit driver "
1932 "configuration", __func__);
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07001933 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001934 }
1935
Jouni Malinen87fd2792011-05-16 18:35:42 +03001936 /*
1937 * WPS UPnP module can be initialized only when the "upnp_iface" is up.
1938 * If "interface" and "upnp_iface" are the same (e.g., non-bridge
1939 * mode), the interface is up only after driver_commit, so initialize
1940 * WPS after driver_commit.
1941 */
1942 for (j = 0; j < iface->num_bss; j++) {
1943 if (hostapd_init_wps_complete(iface->bss[j]))
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07001944 goto fail;
Jouni Malinen87fd2792011-05-16 18:35:42 +03001945 }
1946
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08001947 if ((iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
1948 !res_dfs_offload) {
1949 /*
1950 * If freq is DFS, and DFS is offloaded to the driver, then wait
1951 * for CAC to complete.
1952 */
1953 wpa_printf(MSG_DEBUG, "%s: Wait for CAC to complete", __func__);
1954 return res_dfs_offload;
1955 }
1956
1957#ifdef NEED_AP_MLME
1958dfs_offload:
1959#endif /* NEED_AP_MLME */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001960
1961#ifdef CONFIG_FST
1962 if (hapd->iconf->fst_cfg.group_id[0]) {
1963 struct fst_wpa_obj iface_obj;
1964
1965 fst_hostapd_fill_iface_obj(hapd, &iface_obj);
1966 iface->fst = fst_attach(hapd->conf->iface, hapd->own_addr,
1967 &iface_obj, &hapd->iconf->fst_cfg);
1968 if (!iface->fst) {
1969 wpa_printf(MSG_ERROR, "Could not attach to FST %s",
1970 hapd->iconf->fst_cfg.group_id);
1971 goto fail;
1972 }
1973 }
1974#endif /* CONFIG_FST */
1975
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001976 hostapd_set_state(iface, HAPD_IFACE_ENABLED);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001977 hostapd_owe_update_trans(iface);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001978 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_ENABLED);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001979 if (hapd->setup_complete_cb)
1980 hapd->setup_complete_cb(hapd->setup_complete_cb_ctx);
1981
1982 wpa_printf(MSG_DEBUG, "%s: Setup of interface done.",
1983 iface->bss[0]->conf->iface);
Dmitry Shmidtb96dad42013-11-05 10:07:29 -08001984 if (iface->interfaces && iface->interfaces->terminate_on_error > 0)
1985 iface->interfaces->terminate_on_error--;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001986
Dmitry Shmidt849734c2016-05-27 09:59:01 -07001987 for (j = 0; j < iface->num_bss; j++)
Hai Shalom74f70d42019-02-11 14:42:39 -08001988 hostapd_neighbor_set_own_report(iface->bss[j]);
Dmitry Shmidt849734c2016-05-27 09:59:01 -07001989
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001990 return 0;
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07001991
1992fail:
1993 wpa_printf(MSG_ERROR, "Interface initialization failed");
1994 hostapd_set_state(iface, HAPD_IFACE_DISABLED);
1995 wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001996#ifdef CONFIG_FST
1997 if (iface->fst) {
1998 fst_detach(iface->fst);
1999 iface->fst = NULL;
2000 }
2001#endif /* CONFIG_FST */
Roshan Pius3a1667e2018-07-03 15:17:14 -07002002
2003 if (iface->interfaces && iface->interfaces->terminate_on_error) {
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07002004 eloop_terminate();
Roshan Pius3a1667e2018-07-03 15:17:14 -07002005 } else if (hapd->setup_complete_cb) {
2006 /*
2007 * Calling hapd->setup_complete_cb directly may cause iface
2008 * deinitialization which may be accessed later by the caller.
2009 */
2010 eloop_register_timeout(0, 0,
2011 hostapd_interface_setup_failure_handler,
2012 iface, NULL);
2013 }
2014
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07002015 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002016}
2017
2018
2019/**
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002020 * hostapd_setup_interface_complete - Complete interface setup
2021 *
2022 * This function is called when previous steps in the interface setup has been
2023 * completed. This can also start operations, e.g., DFS, that will require
2024 * additional processing before interface is ready to be enabled. Such
2025 * operations will call this function from eloop callbacks when finished.
2026 */
2027int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
2028{
2029 struct hapd_interfaces *interfaces = iface->interfaces;
2030 struct hostapd_data *hapd = iface->bss[0];
2031 unsigned int i;
2032 int not_ready_in_sync_ifaces = 0;
2033
2034 if (!iface->need_to_start_in_sync)
2035 return hostapd_setup_interface_complete_sync(iface, err);
2036
2037 if (err) {
2038 wpa_printf(MSG_ERROR, "Interface initialization failed");
2039 hostapd_set_state(iface, HAPD_IFACE_DISABLED);
2040 iface->need_to_start_in_sync = 0;
2041 wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
2042 if (interfaces && interfaces->terminate_on_error)
2043 eloop_terminate();
2044 return -1;
2045 }
2046
2047 if (iface->ready_to_start_in_sync) {
2048 /* Already in ready and waiting. should never happpen */
2049 return 0;
2050 }
2051
2052 for (i = 0; i < interfaces->count; i++) {
2053 if (interfaces->iface[i]->need_to_start_in_sync &&
2054 !interfaces->iface[i]->ready_to_start_in_sync)
2055 not_ready_in_sync_ifaces++;
2056 }
2057
2058 /*
2059 * Check if this is the last interface, if yes then start all the other
2060 * waiting interfaces. If not, add this interface to the waiting list.
2061 */
2062 if (not_ready_in_sync_ifaces > 1 && iface->state == HAPD_IFACE_DFS) {
2063 /*
2064 * If this interface went through CAC, do not synchronize, just
2065 * start immediately.
2066 */
2067 iface->need_to_start_in_sync = 0;
2068 wpa_printf(MSG_INFO,
2069 "%s: Finished CAC - bypass sync and start interface",
2070 iface->bss[0]->conf->iface);
2071 return hostapd_setup_interface_complete_sync(iface, err);
2072 }
2073
2074 if (not_ready_in_sync_ifaces > 1) {
2075 /* need to wait as there are other interfaces still coming up */
2076 iface->ready_to_start_in_sync = 1;
2077 wpa_printf(MSG_INFO,
2078 "%s: Interface waiting to sync with other interfaces",
2079 iface->bss[0]->conf->iface);
2080 return 0;
2081 }
2082
2083 wpa_printf(MSG_INFO,
2084 "%s: Last interface to sync - starting all interfaces",
2085 iface->bss[0]->conf->iface);
2086 iface->need_to_start_in_sync = 0;
2087 hostapd_setup_interface_complete_sync(iface, err);
2088 for (i = 0; i < interfaces->count; i++) {
2089 if (interfaces->iface[i]->need_to_start_in_sync &&
2090 interfaces->iface[i]->ready_to_start_in_sync) {
2091 hostapd_setup_interface_complete_sync(
2092 interfaces->iface[i], 0);
2093 /* Only once the interfaces are sync started */
2094 interfaces->iface[i]->need_to_start_in_sync = 0;
2095 }
2096 }
2097
2098 return 0;
2099}
2100
2101
2102/**
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002103 * hostapd_setup_interface - Setup of an interface
2104 * @iface: Pointer to interface data.
2105 * Returns: 0 on success, -1 on failure
2106 *
2107 * Initializes the driver interface, validates the configuration,
2108 * and sets driver parameters based on the configuration.
2109 * Flushes old stations, sets the channel, encryption,
2110 * beacons, and WDS links based on the configuration.
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002111 *
2112 * If interface setup requires more time, e.g., to perform HT co-ex scans, ACS,
2113 * or DFS operations, this function returns 0 before such operations have been
2114 * completed. The pending operations are registered into eloop and will be
2115 * completed from eloop callbacks. Those callbacks end up calling
2116 * hostapd_setup_interface_complete() once setup has been completed.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002117 */
2118int hostapd_setup_interface(struct hostapd_iface *iface)
2119{
2120 int ret;
2121
2122 ret = setup_interface(iface);
2123 if (ret) {
2124 wpa_printf(MSG_ERROR, "%s: Unable to setup interface.",
2125 iface->bss[0]->conf->iface);
2126 return -1;
2127 }
2128
2129 return 0;
2130}
2131
2132
2133/**
2134 * hostapd_alloc_bss_data - Allocate and initialize per-BSS data
2135 * @hapd_iface: Pointer to interface data
2136 * @conf: Pointer to per-interface configuration
2137 * @bss: Pointer to per-BSS configuration for this BSS
2138 * Returns: Pointer to allocated BSS data
2139 *
2140 * This function is used to allocate per-BSS data structure. This data will be
2141 * freed after hostapd_cleanup() is called for it during interface
2142 * deinitialization.
2143 */
2144struct hostapd_data *
2145hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
2146 struct hostapd_config *conf,
2147 struct hostapd_bss_config *bss)
2148{
2149 struct hostapd_data *hapd;
2150
2151 hapd = os_zalloc(sizeof(*hapd));
2152 if (hapd == NULL)
2153 return NULL;
2154
2155 hapd->new_assoc_sta_cb = hostapd_new_assoc_sta;
2156 hapd->iconf = conf;
2157 hapd->conf = bss;
2158 hapd->iface = hapd_iface;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002159 if (conf)
2160 hapd->driver = conf->driver;
Dmitry Shmidt04949592012-07-19 12:16:46 -07002161 hapd->ctrl_sock = -1;
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08002162 dl_list_init(&hapd->ctrl_dst);
Dmitry Shmidt7d175302016-09-06 13:11:34 -07002163 dl_list_init(&hapd->nr_db);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002164 hapd->dhcp_sock = -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002165#ifdef CONFIG_IEEE80211R_AP
2166 dl_list_init(&hapd->l2_queue);
2167 dl_list_init(&hapd->l2_oui_queue);
2168#endif /* CONFIG_IEEE80211R_AP */
Hai Shalom021b0b52019-04-10 11:17:58 -07002169#ifdef CONFIG_SAE
2170 dl_list_init(&hapd->sae_commit_queue);
2171#endif /* CONFIG_SAE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002172
2173 return hapd;
2174}
2175
2176
Dmitry Shmidt54605472013-11-08 11:10:19 -08002177static void hostapd_bss_deinit(struct hostapd_data *hapd)
2178{
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07002179 if (!hapd)
2180 return;
Dmitry Shmidt54605472013-11-08 11:10:19 -08002181 wpa_printf(MSG_DEBUG, "%s: deinit bss %s", __func__,
Hai Shalom021b0b52019-04-10 11:17:58 -07002182 hapd->conf ? hapd->conf->iface : "N/A");
Dmitry Shmidt71757432014-06-02 13:50:35 -07002183 hostapd_bss_deinit_no_free(hapd);
Dmitry Shmidtf73259c2015-03-17 11:00:54 -07002184 wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
Dmitry Shmidt54605472013-11-08 11:10:19 -08002185 hostapd_cleanup(hapd);
2186}
2187
2188
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002189void hostapd_interface_deinit(struct hostapd_iface *iface)
2190{
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002191 int j;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002192
Dmitry Shmidt54605472013-11-08 11:10:19 -08002193 wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002194 if (iface == NULL)
2195 return;
2196
Dmitry Shmidtf73259c2015-03-17 11:00:54 -07002197 hostapd_set_state(iface, HAPD_IFACE_DISABLED);
2198
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002199 eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
2200 iface->wait_channel_update = 0;
2201
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002202#ifdef CONFIG_FST
2203 if (iface->fst) {
2204 fst_detach(iface->fst);
2205 iface->fst = NULL;
2206 }
2207#endif /* CONFIG_FST */
2208
Hai Shalom021b0b52019-04-10 11:17:58 -07002209 for (j = (int) iface->num_bss - 1; j >= 0; j--) {
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07002210 if (!iface->bss)
2211 break;
Dmitry Shmidt54605472013-11-08 11:10:19 -08002212 hostapd_bss_deinit(iface->bss[j]);
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07002213 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07002214
2215#ifdef CONFIG_IEEE80211N
2216#ifdef NEED_AP_MLME
2217 hostapd_stop_setup_timers(iface);
2218 eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL);
2219#endif /* NEED_AP_MLME */
2220#endif /* CONFIG_IEEE80211N */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002221}
2222
2223
2224void hostapd_interface_free(struct hostapd_iface *iface)
2225{
2226 size_t j;
Dmitry Shmidt54605472013-11-08 11:10:19 -08002227 wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
2228 for (j = 0; j < iface->num_bss; j++) {
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07002229 if (!iface->bss)
2230 break;
Dmitry Shmidt54605472013-11-08 11:10:19 -08002231 wpa_printf(MSG_DEBUG, "%s: free hapd %p",
2232 __func__, iface->bss[j]);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002233 os_free(iface->bss[j]);
Dmitry Shmidt54605472013-11-08 11:10:19 -08002234 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002235 hostapd_cleanup_iface(iface);
2236}
2237
2238
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07002239struct hostapd_iface * hostapd_alloc_iface(void)
2240{
2241 struct hostapd_iface *hapd_iface;
2242
2243 hapd_iface = os_zalloc(sizeof(*hapd_iface));
2244 if (!hapd_iface)
2245 return NULL;
2246
2247 dl_list_init(&hapd_iface->sta_seen);
2248
2249 return hapd_iface;
2250}
2251
2252
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002253/**
2254 * hostapd_init - Allocate and initialize per-interface data
2255 * @config_file: Path to the configuration file
2256 * Returns: Pointer to the allocated interface data or %NULL on failure
2257 *
2258 * This function is used to allocate main data structures for per-interface
2259 * data. The allocated data buffer will be freed by calling
2260 * hostapd_cleanup_iface().
2261 */
2262struct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces,
2263 const char *config_file)
2264{
2265 struct hostapd_iface *hapd_iface = NULL;
2266 struct hostapd_config *conf = NULL;
2267 struct hostapd_data *hapd;
2268 size_t i;
2269
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07002270 hapd_iface = hostapd_alloc_iface();
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002271 if (hapd_iface == NULL)
2272 goto fail;
2273
2274 hapd_iface->config_fname = os_strdup(config_file);
2275 if (hapd_iface->config_fname == NULL)
2276 goto fail;
2277
2278 conf = interfaces->config_read_cb(hapd_iface->config_fname);
2279 if (conf == NULL)
2280 goto fail;
2281 hapd_iface->conf = conf;
2282
2283 hapd_iface->num_bss = conf->num_bss;
2284 hapd_iface->bss = os_calloc(conf->num_bss,
2285 sizeof(struct hostapd_data *));
2286 if (hapd_iface->bss == NULL)
2287 goto fail;
2288
2289 for (i = 0; i < conf->num_bss; i++) {
2290 hapd = hapd_iface->bss[i] =
2291 hostapd_alloc_bss_data(hapd_iface, conf,
2292 conf->bss[i]);
2293 if (hapd == NULL)
2294 goto fail;
2295 hapd->msg_ctx = hapd;
2296 }
2297
2298 return hapd_iface;
2299
2300fail:
2301 wpa_printf(MSG_ERROR, "Failed to set up interface with %s",
2302 config_file);
2303 if (conf)
2304 hostapd_config_free(conf);
2305 if (hapd_iface) {
2306 os_free(hapd_iface->config_fname);
2307 os_free(hapd_iface->bss);
Dmitry Shmidt54605472013-11-08 11:10:19 -08002308 wpa_printf(MSG_DEBUG, "%s: free iface %p",
2309 __func__, hapd_iface);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002310 os_free(hapd_iface);
2311 }
2312 return NULL;
2313}
2314
2315
2316static int ifname_in_use(struct hapd_interfaces *interfaces, const char *ifname)
2317{
2318 size_t i, j;
2319
2320 for (i = 0; i < interfaces->count; i++) {
2321 struct hostapd_iface *iface = interfaces->iface[i];
2322 for (j = 0; j < iface->num_bss; j++) {
2323 struct hostapd_data *hapd = iface->bss[j];
2324 if (os_strcmp(ifname, hapd->conf->iface) == 0)
2325 return 1;
2326 }
2327 }
2328
2329 return 0;
2330}
2331
2332
2333/**
2334 * hostapd_interface_init_bss - Read configuration file and init BSS data
2335 *
2336 * This function is used to parse configuration file for a BSS. This BSS is
2337 * added to an existing interface sharing the same radio (if any) or a new
2338 * interface is created if this is the first interface on a radio. This
2339 * allocate memory for the BSS. No actual driver operations are started.
2340 *
2341 * This is similar to hostapd_interface_init(), but for a case where the
2342 * configuration is used to add a single BSS instead of all BSSes for a radio.
2343 */
2344struct hostapd_iface *
2345hostapd_interface_init_bss(struct hapd_interfaces *interfaces, const char *phy,
2346 const char *config_fname, int debug)
2347{
2348 struct hostapd_iface *new_iface = NULL, *iface = NULL;
2349 struct hostapd_data *hapd;
2350 int k;
2351 size_t i, bss_idx;
2352
2353 if (!phy || !*phy)
2354 return NULL;
2355
2356 for (i = 0; i < interfaces->count; i++) {
2357 if (os_strcmp(interfaces->iface[i]->phy, phy) == 0) {
2358 iface = interfaces->iface[i];
2359 break;
2360 }
2361 }
2362
2363 wpa_printf(MSG_INFO, "Configuration file: %s (phy %s)%s",
2364 config_fname, phy, iface ? "" : " --> new PHY");
2365 if (iface) {
2366 struct hostapd_config *conf;
2367 struct hostapd_bss_config **tmp_conf;
2368 struct hostapd_data **tmp_bss;
2369 struct hostapd_bss_config *bss;
2370 const char *ifname;
2371
2372 /* Add new BSS to existing iface */
2373 conf = interfaces->config_read_cb(config_fname);
2374 if (conf == NULL)
2375 return NULL;
2376 if (conf->num_bss > 1) {
2377 wpa_printf(MSG_ERROR, "Multiple BSSes specified in BSS-config");
2378 hostapd_config_free(conf);
2379 return NULL;
2380 }
2381
2382 ifname = conf->bss[0]->iface;
2383 if (ifname[0] != '\0' && ifname_in_use(interfaces, ifname)) {
2384 wpa_printf(MSG_ERROR,
2385 "Interface name %s already in use", ifname);
2386 hostapd_config_free(conf);
2387 return NULL;
2388 }
2389
2390 tmp_conf = os_realloc_array(
2391 iface->conf->bss, iface->conf->num_bss + 1,
2392 sizeof(struct hostapd_bss_config *));
2393 tmp_bss = os_realloc_array(iface->bss, iface->num_bss + 1,
2394 sizeof(struct hostapd_data *));
2395 if (tmp_bss)
2396 iface->bss = tmp_bss;
2397 if (tmp_conf) {
2398 iface->conf->bss = tmp_conf;
2399 iface->conf->last_bss = tmp_conf[0];
2400 }
2401 if (tmp_bss == NULL || tmp_conf == NULL) {
2402 hostapd_config_free(conf);
2403 return NULL;
2404 }
2405 bss = iface->conf->bss[iface->conf->num_bss] = conf->bss[0];
2406 iface->conf->num_bss++;
2407
2408 hapd = hostapd_alloc_bss_data(iface, iface->conf, bss);
2409 if (hapd == NULL) {
2410 iface->conf->num_bss--;
2411 hostapd_config_free(conf);
2412 return NULL;
2413 }
2414 iface->conf->last_bss = bss;
2415 iface->bss[iface->num_bss] = hapd;
2416 hapd->msg_ctx = hapd;
2417
2418 bss_idx = iface->num_bss++;
2419 conf->num_bss--;
2420 conf->bss[0] = NULL;
2421 hostapd_config_free(conf);
2422 } else {
2423 /* Add a new iface with the first BSS */
2424 new_iface = iface = hostapd_init(interfaces, config_fname);
2425 if (!iface)
2426 return NULL;
2427 os_strlcpy(iface->phy, phy, sizeof(iface->phy));
2428 iface->interfaces = interfaces;
2429 bss_idx = 0;
2430 }
2431
2432 for (k = 0; k < debug; k++) {
2433 if (iface->bss[bss_idx]->conf->logger_stdout_level > 0)
2434 iface->bss[bss_idx]->conf->logger_stdout_level--;
2435 }
2436
2437 if (iface->conf->bss[bss_idx]->iface[0] == '\0' &&
2438 !hostapd_drv_none(iface->bss[bss_idx])) {
2439 wpa_printf(MSG_ERROR, "Interface name not specified in %s",
2440 config_fname);
2441 if (new_iface)
2442 hostapd_interface_deinit_free(new_iface);
2443 return NULL;
2444 }
2445
2446 return iface;
2447}
2448
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002449
2450void hostapd_interface_deinit_free(struct hostapd_iface *iface)
2451{
2452 const struct wpa_driver_ops *driver;
2453 void *drv_priv;
Dmitry Shmidt54605472013-11-08 11:10:19 -08002454
2455 wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002456 if (iface == NULL)
2457 return;
Dmitry Shmidt54605472013-11-08 11:10:19 -08002458 wpa_printf(MSG_DEBUG, "%s: num_bss=%u conf->num_bss=%u",
2459 __func__, (unsigned int) iface->num_bss,
2460 (unsigned int) iface->conf->num_bss);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002461 driver = iface->bss[0]->driver;
2462 drv_priv = iface->bss[0]->drv_priv;
2463 hostapd_interface_deinit(iface);
Dmitry Shmidt54605472013-11-08 11:10:19 -08002464 wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit",
2465 __func__, driver, drv_priv);
Dmitry Shmidt71757432014-06-02 13:50:35 -07002466 if (driver && driver->hapd_deinit && drv_priv) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002467 driver->hapd_deinit(drv_priv);
Dmitry Shmidt71757432014-06-02 13:50:35 -07002468 iface->bss[0]->drv_priv = NULL;
2469 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002470 hostapd_interface_free(iface);
2471}
2472
2473
Dmitry Shmidt15907092014-03-25 10:42:57 -07002474static void hostapd_deinit_driver(const struct wpa_driver_ops *driver,
2475 void *drv_priv,
2476 struct hostapd_iface *hapd_iface)
2477{
2478 size_t j;
2479
2480 wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit",
2481 __func__, driver, drv_priv);
2482 if (driver && driver->hapd_deinit && drv_priv) {
2483 driver->hapd_deinit(drv_priv);
2484 for (j = 0; j < hapd_iface->num_bss; j++) {
2485 wpa_printf(MSG_DEBUG, "%s:bss[%d]->drv_priv=%p",
2486 __func__, (int) j,
2487 hapd_iface->bss[j]->drv_priv);
2488 if (hapd_iface->bss[j]->drv_priv == drv_priv)
2489 hapd_iface->bss[j]->drv_priv = NULL;
2490 }
2491 }
2492}
2493
2494
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002495int hostapd_enable_iface(struct hostapd_iface *hapd_iface)
2496{
Dmitry Shmidt71757432014-06-02 13:50:35 -07002497 size_t j;
2498
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002499 if (hapd_iface->bss[0]->drv_priv != NULL) {
2500 wpa_printf(MSG_ERROR, "Interface %s already enabled",
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002501 hapd_iface->conf->bss[0]->iface);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002502 return -1;
2503 }
2504
2505 wpa_printf(MSG_DEBUG, "Enable interface %s",
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002506 hapd_iface->conf->bss[0]->iface);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002507
Dmitry Shmidt71757432014-06-02 13:50:35 -07002508 for (j = 0; j < hapd_iface->num_bss; j++)
2509 hostapd_set_security_params(hapd_iface->conf->bss[j], 1);
Dmitry Shmidt344abd32014-01-14 13:17:00 -08002510 if (hostapd_config_check(hapd_iface->conf, 1) < 0) {
2511 wpa_printf(MSG_INFO, "Invalid configuration - cannot enable");
2512 return -1;
2513 }
2514
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002515 if (hapd_iface->interfaces == NULL ||
2516 hapd_iface->interfaces->driver_init == NULL ||
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002517 hapd_iface->interfaces->driver_init(hapd_iface))
2518 return -1;
2519
2520 if (hostapd_setup_interface(hapd_iface)) {
Dmitry Shmidt15907092014-03-25 10:42:57 -07002521 hostapd_deinit_driver(hapd_iface->bss[0]->driver,
2522 hapd_iface->bss[0]->drv_priv,
2523 hapd_iface);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002524 return -1;
2525 }
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002526
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002527 return 0;
2528}
2529
2530
2531int hostapd_reload_iface(struct hostapd_iface *hapd_iface)
2532{
2533 size_t j;
2534
2535 wpa_printf(MSG_DEBUG, "Reload interface %s",
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002536 hapd_iface->conf->bss[0]->iface);
2537 for (j = 0; j < hapd_iface->num_bss; j++)
Dmitry Shmidt71757432014-06-02 13:50:35 -07002538 hostapd_set_security_params(hapd_iface->conf->bss[j], 1);
Dmitry Shmidt344abd32014-01-14 13:17:00 -08002539 if (hostapd_config_check(hapd_iface->conf, 1) < 0) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002540 wpa_printf(MSG_ERROR, "Updated configuration is invalid");
2541 return -1;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002542 }
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002543 hostapd_clear_old(hapd_iface);
2544 for (j = 0; j < hapd_iface->num_bss; j++)
2545 hostapd_reload_bss(hapd_iface->bss[j]);
2546
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002547 return 0;
2548}
2549
2550
2551int hostapd_disable_iface(struct hostapd_iface *hapd_iface)
2552{
2553 size_t j;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002554 const struct wpa_driver_ops *driver;
2555 void *drv_priv;
2556
2557 if (hapd_iface == NULL)
2558 return -1;
Dmitry Shmidt71757432014-06-02 13:50:35 -07002559
2560 if (hapd_iface->bss[0]->drv_priv == NULL) {
2561 wpa_printf(MSG_INFO, "Interface %s already disabled",
2562 hapd_iface->conf->bss[0]->iface);
2563 return -1;
2564 }
2565
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002566 wpa_msg(hapd_iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002567 driver = hapd_iface->bss[0]->driver;
2568 drv_priv = hapd_iface->bss[0]->drv_priv;
2569
Dmitry Shmidta38abf92014-03-06 13:38:44 -08002570 hapd_iface->driver_ap_teardown =
2571 !!(hapd_iface->drv_flags &
2572 WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
2573
Hai Shalom39ba6fc2019-01-22 12:40:38 -08002574#ifdef NEED_AP_MLME
2575 for (j = 0; j < hapd_iface->num_bss; j++)
2576 hostapd_cleanup_cs_params(hapd_iface->bss[j]);
2577#endif /* NEED_AP_MLME */
2578
Dmitry Shmidta38abf92014-03-06 13:38:44 -08002579 /* same as hostapd_interface_deinit without deinitializing ctrl-iface */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002580 for (j = 0; j < hapd_iface->num_bss; j++) {
2581 struct hostapd_data *hapd = hapd_iface->bss[j];
Dmitry Shmidt71757432014-06-02 13:50:35 -07002582 hostapd_bss_deinit_no_free(hapd);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002583 hostapd_free_hapd_data(hapd);
2584 }
2585
Dmitry Shmidt15907092014-03-25 10:42:57 -07002586 hostapd_deinit_driver(driver, drv_priv, hapd_iface);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002587
2588 /* From hostapd_cleanup_iface: These were initialized in
2589 * hostapd_setup_interface and hostapd_setup_interface_complete
2590 */
2591 hostapd_cleanup_iface_partial(hapd_iface);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002592
Dmitry Shmidt56052862013-10-04 10:23:25 -07002593 wpa_printf(MSG_DEBUG, "Interface %s disabled",
2594 hapd_iface->bss[0]->conf->iface);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002595 hostapd_set_state(hapd_iface, HAPD_IFACE_DISABLED);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002596 return 0;
2597}
2598
2599
2600static struct hostapd_iface *
2601hostapd_iface_alloc(struct hapd_interfaces *interfaces)
2602{
2603 struct hostapd_iface **iface, *hapd_iface;
2604
2605 iface = os_realloc_array(interfaces->iface, interfaces->count + 1,
2606 sizeof(struct hostapd_iface *));
2607 if (iface == NULL)
2608 return NULL;
2609 interfaces->iface = iface;
2610 hapd_iface = interfaces->iface[interfaces->count] =
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07002611 hostapd_alloc_iface();
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002612 if (hapd_iface == NULL) {
2613 wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for "
2614 "the interface", __func__);
2615 return NULL;
2616 }
2617 interfaces->count++;
2618 hapd_iface->interfaces = interfaces;
2619
2620 return hapd_iface;
2621}
2622
2623
2624static struct hostapd_config *
2625hostapd_config_alloc(struct hapd_interfaces *interfaces, const char *ifname,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002626 const char *ctrl_iface, const char *driver)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002627{
2628 struct hostapd_bss_config *bss;
2629 struct hostapd_config *conf;
2630
2631 /* Allocates memory for bss and conf */
2632 conf = hostapd_config_defaults();
2633 if (conf == NULL) {
2634 wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for "
2635 "configuration", __func__);
Hai Shalom74f70d42019-02-11 14:42:39 -08002636 return NULL;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002637 }
2638
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002639 if (driver) {
2640 int j;
2641
2642 for (j = 0; wpa_drivers[j]; j++) {
2643 if (os_strcmp(driver, wpa_drivers[j]->name) == 0) {
2644 conf->driver = wpa_drivers[j];
2645 goto skip;
2646 }
2647 }
2648
2649 wpa_printf(MSG_ERROR,
2650 "Invalid/unknown driver '%s' - registering the default driver",
2651 driver);
2652 }
2653
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002654 conf->driver = wpa_drivers[0];
2655 if (conf->driver == NULL) {
2656 wpa_printf(MSG_ERROR, "No driver wrappers registered!");
2657 hostapd_config_free(conf);
2658 return NULL;
2659 }
2660
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002661skip:
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002662 bss = conf->last_bss = conf->bss[0];
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002663
2664 os_strlcpy(bss->iface, ifname, sizeof(bss->iface));
2665 bss->ctrl_interface = os_strdup(ctrl_iface);
2666 if (bss->ctrl_interface == NULL) {
2667 hostapd_config_free(conf);
2668 return NULL;
2669 }
2670
2671 /* Reading configuration file skipped, will be done in SET!
2672 * From reading the configuration till the end has to be done in
2673 * SET
2674 */
2675 return conf;
2676}
2677
2678
Dmitry Shmidtff787d52015-01-12 13:01:47 -08002679static int hostapd_data_alloc(struct hostapd_iface *hapd_iface,
2680 struct hostapd_config *conf)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002681{
2682 size_t i;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002683 struct hostapd_data *hapd;
2684
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002685 hapd_iface->bss = os_calloc(conf->num_bss,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002686 sizeof(struct hostapd_data *));
2687 if (hapd_iface->bss == NULL)
Dmitry Shmidtff787d52015-01-12 13:01:47 -08002688 return -1;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002689
2690 for (i = 0; i < conf->num_bss; i++) {
2691 hapd = hapd_iface->bss[i] =
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002692 hostapd_alloc_bss_data(hapd_iface, conf, conf->bss[i]);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08002693 if (hapd == NULL) {
2694 while (i > 0) {
2695 i--;
2696 os_free(hapd_iface->bss[i]);
2697 hapd_iface->bss[i] = NULL;
2698 }
2699 os_free(hapd_iface->bss);
2700 hapd_iface->bss = NULL;
2701 return -1;
2702 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002703 hapd->msg_ctx = hapd;
2704 }
2705
Dmitry Shmidtff787d52015-01-12 13:01:47 -08002706 hapd_iface->conf = conf;
2707 hapd_iface->num_bss = conf->num_bss;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002708
Dmitry Shmidtff787d52015-01-12 13:01:47 -08002709 return 0;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002710}
2711
2712
2713int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf)
2714{
2715 struct hostapd_config *conf = NULL;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002716 struct hostapd_iface *hapd_iface = NULL, *new_iface = NULL;
2717 struct hostapd_data *hapd;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002718 char *ptr;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002719 size_t i, j;
2720 const char *conf_file = NULL, *phy_name = NULL;
2721
2722 if (os_strncmp(buf, "bss_config=", 11) == 0) {
2723 char *pos;
2724 phy_name = buf + 11;
2725 pos = os_strchr(phy_name, ':');
2726 if (!pos)
2727 return -1;
2728 *pos++ = '\0';
2729 conf_file = pos;
2730 if (!os_strlen(conf_file))
2731 return -1;
2732
2733 hapd_iface = hostapd_interface_init_bss(interfaces, phy_name,
2734 conf_file, 0);
2735 if (!hapd_iface)
2736 return -1;
2737 for (j = 0; j < interfaces->count; j++) {
2738 if (interfaces->iface[j] == hapd_iface)
2739 break;
2740 }
2741 if (j == interfaces->count) {
2742 struct hostapd_iface **tmp;
2743 tmp = os_realloc_array(interfaces->iface,
2744 interfaces->count + 1,
2745 sizeof(struct hostapd_iface *));
2746 if (!tmp) {
2747 hostapd_interface_deinit_free(hapd_iface);
2748 return -1;
2749 }
2750 interfaces->iface = tmp;
2751 interfaces->iface[interfaces->count++] = hapd_iface;
2752 new_iface = hapd_iface;
2753 }
2754
2755 if (new_iface) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -08002756 if (interfaces->driver_init(hapd_iface))
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002757 goto fail;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002758
2759 if (hostapd_setup_interface(hapd_iface)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002760 hostapd_deinit_driver(
2761 hapd_iface->bss[0]->driver,
2762 hapd_iface->bss[0]->drv_priv,
2763 hapd_iface);
2764 goto fail;
2765 }
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002766 } else {
2767 /* Assign new BSS with bss[0]'s driver info */
2768 hapd = hapd_iface->bss[hapd_iface->num_bss - 1];
2769 hapd->driver = hapd_iface->bss[0]->driver;
2770 hapd->drv_priv = hapd_iface->bss[0]->drv_priv;
2771 os_memcpy(hapd->own_addr, hapd_iface->bss[0]->own_addr,
2772 ETH_ALEN);
2773
2774 if (start_ctrl_iface_bss(hapd) < 0 ||
Dmitry Shmidt54605472013-11-08 11:10:19 -08002775 (hapd_iface->state == HAPD_IFACE_ENABLED &&
2776 hostapd_setup_bss(hapd, -1))) {
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07002777 hostapd_cleanup(hapd);
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002778 hapd_iface->bss[hapd_iface->num_bss - 1] = NULL;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002779 hapd_iface->conf->num_bss--;
2780 hapd_iface->num_bss--;
Dmitry Shmidt54605472013-11-08 11:10:19 -08002781 wpa_printf(MSG_DEBUG, "%s: free hapd %p %s",
2782 __func__, hapd, hapd->conf->iface);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08002783 hostapd_config_free_bss(hapd->conf);
2784 hapd->conf = NULL;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002785 os_free(hapd);
2786 return -1;
2787 }
2788 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002789 hostapd_owe_update_trans(hapd_iface);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002790 return 0;
2791 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002792
2793 ptr = os_strchr(buf, ' ');
2794 if (ptr == NULL)
2795 return -1;
2796 *ptr++ = '\0';
2797
Dmitry Shmidt56052862013-10-04 10:23:25 -07002798 if (os_strncmp(ptr, "config=", 7) == 0)
2799 conf_file = ptr + 7;
2800
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002801 for (i = 0; i < interfaces->count; i++) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002802 if (!os_strcmp(interfaces->iface[i]->conf->bss[0]->iface,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002803 buf)) {
2804 wpa_printf(MSG_INFO, "Cannot add interface - it "
2805 "already exists");
2806 return -1;
2807 }
2808 }
2809
2810 hapd_iface = hostapd_iface_alloc(interfaces);
2811 if (hapd_iface == NULL) {
2812 wpa_printf(MSG_ERROR, "%s: Failed to allocate memory "
2813 "for interface", __func__);
2814 goto fail;
2815 }
Dmitry Shmidtff787d52015-01-12 13:01:47 -08002816 new_iface = hapd_iface;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002817
Dmitry Shmidt56052862013-10-04 10:23:25 -07002818 if (conf_file && interfaces->config_read_cb) {
2819 conf = interfaces->config_read_cb(conf_file);
2820 if (conf && conf->bss)
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002821 os_strlcpy(conf->bss[0]->iface, buf,
2822 sizeof(conf->bss[0]->iface));
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002823 } else {
2824 char *driver = os_strchr(ptr, ' ');
2825
2826 if (driver)
2827 *driver++ = '\0';
2828 conf = hostapd_config_alloc(interfaces, buf, ptr, driver);
2829 }
2830
Dmitry Shmidt56052862013-10-04 10:23:25 -07002831 if (conf == NULL || conf->bss == NULL) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002832 wpa_printf(MSG_ERROR, "%s: Failed to allocate memory "
2833 "for configuration", __func__);
2834 goto fail;
2835 }
2836
Dmitry Shmidtff787d52015-01-12 13:01:47 -08002837 if (hostapd_data_alloc(hapd_iface, conf) < 0) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002838 wpa_printf(MSG_ERROR, "%s: Failed to allocate memory "
2839 "for hostapd", __func__);
2840 goto fail;
2841 }
Dmitry Shmidtff787d52015-01-12 13:01:47 -08002842 conf = NULL;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002843
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002844 if (start_ctrl_iface(hapd_iface) < 0)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002845 goto fail;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002846
Dmitry Shmidtff787d52015-01-12 13:01:47 -08002847 wpa_printf(MSG_INFO, "Add interface '%s'",
2848 hapd_iface->conf->bss[0]->iface);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002849
2850 return 0;
2851
2852fail:
2853 if (conf)
2854 hostapd_config_free(conf);
2855 if (hapd_iface) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002856 if (hapd_iface->bss) {
Dmitry Shmidt54605472013-11-08 11:10:19 -08002857 for (i = 0; i < hapd_iface->num_bss; i++) {
2858 hapd = hapd_iface->bss[i];
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002859 if (!hapd)
2860 continue;
2861 if (hapd_iface->interfaces &&
Dmitry Shmidt54605472013-11-08 11:10:19 -08002862 hapd_iface->interfaces->ctrl_iface_deinit)
2863 hapd_iface->interfaces->
2864 ctrl_iface_deinit(hapd);
2865 wpa_printf(MSG_DEBUG, "%s: free hapd %p (%s)",
2866 __func__, hapd_iface->bss[i],
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002867 hapd->conf->iface);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002868 hostapd_cleanup(hapd);
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002869 os_free(hapd);
2870 hapd_iface->bss[i] = NULL;
Dmitry Shmidt54605472013-11-08 11:10:19 -08002871 }
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002872 os_free(hapd_iface->bss);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002873 hapd_iface->bss = NULL;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002874 }
Dmitry Shmidtff787d52015-01-12 13:01:47 -08002875 if (new_iface) {
2876 interfaces->count--;
2877 interfaces->iface[interfaces->count] = NULL;
2878 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002879 hostapd_cleanup_iface(hapd_iface);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002880 }
2881 return -1;
2882}
2883
2884
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002885static int hostapd_remove_bss(struct hostapd_iface *iface, unsigned int idx)
2886{
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002887 size_t i;
2888
Dmitry Shmidt54605472013-11-08 11:10:19 -08002889 wpa_printf(MSG_INFO, "Remove BSS '%s'", iface->conf->bss[idx]->iface);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002890
Dmitry Shmidt54605472013-11-08 11:10:19 -08002891 /* Remove hostapd_data only if it has already been initialized */
2892 if (idx < iface->num_bss) {
2893 struct hostapd_data *hapd = iface->bss[idx];
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002894
Dmitry Shmidt54605472013-11-08 11:10:19 -08002895 hostapd_bss_deinit(hapd);
2896 wpa_printf(MSG_DEBUG, "%s: free hapd %p (%s)",
2897 __func__, hapd, hapd->conf->iface);
2898 hostapd_config_free_bss(hapd->conf);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08002899 hapd->conf = NULL;
Dmitry Shmidt54605472013-11-08 11:10:19 -08002900 os_free(hapd);
2901
2902 iface->num_bss--;
2903
2904 for (i = idx; i < iface->num_bss; i++)
2905 iface->bss[i] = iface->bss[i + 1];
2906 } else {
2907 hostapd_config_free_bss(iface->conf->bss[idx]);
2908 iface->conf->bss[idx] = NULL;
2909 }
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002910
2911 iface->conf->num_bss--;
Dmitry Shmidt54605472013-11-08 11:10:19 -08002912 for (i = idx; i < iface->conf->num_bss; i++)
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002913 iface->conf->bss[i] = iface->conf->bss[i + 1];
2914
2915 return 0;
2916}
2917
2918
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002919int hostapd_remove_iface(struct hapd_interfaces *interfaces, char *buf)
2920{
2921 struct hostapd_iface *hapd_iface;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002922 size_t i, j, k = 0;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002923
2924 for (i = 0; i < interfaces->count; i++) {
2925 hapd_iface = interfaces->iface[i];
2926 if (hapd_iface == NULL)
2927 return -1;
Dmitry Shmidt54605472013-11-08 11:10:19 -08002928 if (!os_strcmp(hapd_iface->conf->bss[0]->iface, buf)) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002929 wpa_printf(MSG_INFO, "Remove interface '%s'", buf);
Dmitry Shmidta38abf92014-03-06 13:38:44 -08002930 hapd_iface->driver_ap_teardown =
2931 !!(hapd_iface->drv_flags &
2932 WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
2933
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002934 hostapd_interface_deinit_free(hapd_iface);
2935 k = i;
2936 while (k < (interfaces->count - 1)) {
2937 interfaces->iface[k] =
2938 interfaces->iface[k + 1];
2939 k++;
2940 }
2941 interfaces->count--;
2942 return 0;
2943 }
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002944
2945 for (j = 0; j < hapd_iface->conf->num_bss; j++) {
Dmitry Shmidta38abf92014-03-06 13:38:44 -08002946 if (!os_strcmp(hapd_iface->conf->bss[j]->iface, buf)) {
2947 hapd_iface->driver_ap_teardown =
2948 !(hapd_iface->drv_flags &
2949 WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002950 return hostapd_remove_bss(hapd_iface, j);
Dmitry Shmidta38abf92014-03-06 13:38:44 -08002951 }
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002952 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002953 }
2954 return -1;
2955}
2956
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002957
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002958/**
2959 * hostapd_new_assoc_sta - Notify that a new station associated with the AP
2960 * @hapd: Pointer to BSS data
2961 * @sta: Pointer to the associated STA data
2962 * @reassoc: 1 to indicate this was a re-association; 0 = first association
2963 *
2964 * This function will be called whenever a station associates with the AP. It
2965 * can be called from ieee802_11.c for drivers that export MLME to hostapd and
2966 * from drv_callbacks.c based on driver events for drivers that take care of
2967 * management frames (IEEE 802.11 authentication and association) internally.
2968 */
2969void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
2970 int reassoc)
2971{
2972 if (hapd->tkip_countermeasures) {
2973 hostapd_drv_sta_deauth(hapd, sta->addr,
2974 WLAN_REASON_MICHAEL_MIC_FAILURE);
2975 return;
2976 }
2977
2978 hostapd_prune_associations(hapd, sta->addr);
Dmitry Shmidt1d6bf422016-01-19 15:51:35 -08002979 ap_sta_clear_disconnect_timeouts(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002980
2981 /* IEEE 802.11F (IAPP) */
2982 if (hapd->conf->ieee802_11f)
2983 iapp_new_station(hapd->iapp, sta);
2984
2985#ifdef CONFIG_P2P
2986 if (sta->p2p_ie == NULL && !sta->no_p2p_set) {
2987 sta->no_p2p_set = 1;
2988 hapd->num_sta_no_p2p++;
2989 if (hapd->num_sta_no_p2p == 1)
2990 hostapd_p2p_non_p2p_sta_connected(hapd);
2991 }
2992#endif /* CONFIG_P2P */
2993
2994 /* Start accounting here, if IEEE 802.1X and WPA are not used.
2995 * IEEE 802.1X/WPA code will start accounting after the station has
2996 * been authorized. */
Dmitry Shmidt2ac5f602014-03-07 10:08:21 -08002997 if (!hapd->conf->ieee802_1x && !hapd->conf->wpa && !hapd->conf->osen) {
2998 ap_sta_set_authorized(hapd, sta, 1);
Dmitry Shmidt04f534e2013-12-09 15:50:16 -08002999 os_get_reltime(&sta->connected_time);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003000 accounting_sta_start(hapd, sta);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003001 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003002
3003 /* Start IEEE 802.1X authentication process for new stations */
3004 ieee802_1x_new_station(hapd, sta);
3005 if (reassoc) {
3006 if (sta->auth_alg != WLAN_AUTH_FT &&
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003007 sta->auth_alg != WLAN_AUTH_FILS_SK &&
3008 sta->auth_alg != WLAN_AUTH_FILS_SK_PFS &&
3009 sta->auth_alg != WLAN_AUTH_FILS_PK &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003010 !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)))
3011 wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH);
3012 } else
3013 wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm);
Dmitry Shmidt04949592012-07-19 12:16:46 -07003014
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08003015 if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED) {
3016 if (eloop_cancel_timeout(ap_handle_timer, hapd, sta) > 0) {
3017 wpa_printf(MSG_DEBUG,
3018 "%s: %s: canceled wired ap_handle_timer timeout for "
3019 MACSTR,
3020 hapd->conf->iface, __func__,
3021 MAC2STR(sta->addr));
3022 }
3023 } else if (!(hapd->iface->drv_flags &
3024 WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
Dmitry Shmidt1d6bf422016-01-19 15:51:35 -08003025 wpa_printf(MSG_DEBUG,
3026 "%s: %s: reschedule ap_handle_timer timeout for "
3027 MACSTR " (%d seconds - ap_max_inactivity)",
3028 hapd->conf->iface, __func__, MAC2STR(sta->addr),
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08003029 hapd->conf->ap_max_inactivity);
3030 eloop_cancel_timeout(ap_handle_timer, hapd, sta);
3031 eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
3032 ap_handle_timer, hapd, sta);
3033 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003034}
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003035
3036
3037const char * hostapd_state_text(enum hostapd_iface_state s)
3038{
3039 switch (s) {
3040 case HAPD_IFACE_UNINITIALIZED:
3041 return "UNINITIALIZED";
3042 case HAPD_IFACE_DISABLED:
3043 return "DISABLED";
3044 case HAPD_IFACE_COUNTRY_UPDATE:
3045 return "COUNTRY_UPDATE";
3046 case HAPD_IFACE_ACS:
3047 return "ACS";
3048 case HAPD_IFACE_HT_SCAN:
3049 return "HT_SCAN";
3050 case HAPD_IFACE_DFS:
3051 return "DFS";
3052 case HAPD_IFACE_ENABLED:
3053 return "ENABLED";
3054 }
3055
3056 return "UNKNOWN";
3057}
3058
3059
3060void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s)
3061{
3062 wpa_printf(MSG_INFO, "%s: interface state %s->%s",
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07003063 iface->conf ? iface->conf->bss[0]->iface : "N/A",
3064 hostapd_state_text(iface->state), hostapd_state_text(s));
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003065 iface->state = s;
3066}
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003067
3068
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003069int hostapd_csa_in_progress(struct hostapd_iface *iface)
3070{
3071 unsigned int i;
3072
3073 for (i = 0; i < iface->num_bss; i++)
3074 if (iface->bss[i]->csa_in_progress)
3075 return 1;
3076 return 0;
3077}
3078
3079
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003080#ifdef NEED_AP_MLME
3081
3082static void free_beacon_data(struct beacon_data *beacon)
3083{
3084 os_free(beacon->head);
3085 beacon->head = NULL;
3086 os_free(beacon->tail);
3087 beacon->tail = NULL;
3088 os_free(beacon->probe_resp);
3089 beacon->probe_resp = NULL;
3090 os_free(beacon->beacon_ies);
3091 beacon->beacon_ies = NULL;
3092 os_free(beacon->proberesp_ies);
3093 beacon->proberesp_ies = NULL;
3094 os_free(beacon->assocresp_ies);
3095 beacon->assocresp_ies = NULL;
3096}
3097
3098
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07003099static int hostapd_build_beacon_data(struct hostapd_data *hapd,
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003100 struct beacon_data *beacon)
3101{
3102 struct wpabuf *beacon_extra, *proberesp_extra, *assocresp_extra;
3103 struct wpa_driver_ap_params params;
3104 int ret;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003105
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08003106 os_memset(beacon, 0, sizeof(*beacon));
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003107 ret = ieee802_11_build_ap_params(hapd, &params);
3108 if (ret < 0)
3109 return ret;
3110
3111 ret = hostapd_build_ap_extra_ies(hapd, &beacon_extra,
3112 &proberesp_extra,
3113 &assocresp_extra);
3114 if (ret)
3115 goto free_ap_params;
3116
3117 ret = -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003118 beacon->head = os_memdup(params.head, params.head_len);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003119 if (!beacon->head)
3120 goto free_ap_extra_ies;
3121
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003122 beacon->head_len = params.head_len;
3123
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003124 beacon->tail = os_memdup(params.tail, params.tail_len);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003125 if (!beacon->tail)
3126 goto free_beacon;
3127
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003128 beacon->tail_len = params.tail_len;
3129
3130 if (params.proberesp != NULL) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003131 beacon->probe_resp = os_memdup(params.proberesp,
3132 params.proberesp_len);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003133 if (!beacon->probe_resp)
3134 goto free_beacon;
3135
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003136 beacon->probe_resp_len = params.proberesp_len;
3137 }
3138
3139 /* copy the extra ies */
3140 if (beacon_extra) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003141 beacon->beacon_ies = os_memdup(beacon_extra->buf,
3142 wpabuf_len(beacon_extra));
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003143 if (!beacon->beacon_ies)
3144 goto free_beacon;
3145
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003146 beacon->beacon_ies_len = wpabuf_len(beacon_extra);
3147 }
3148
3149 if (proberesp_extra) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003150 beacon->proberesp_ies = os_memdup(proberesp_extra->buf,
3151 wpabuf_len(proberesp_extra));
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003152 if (!beacon->proberesp_ies)
3153 goto free_beacon;
3154
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003155 beacon->proberesp_ies_len = wpabuf_len(proberesp_extra);
3156 }
3157
3158 if (assocresp_extra) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003159 beacon->assocresp_ies = os_memdup(assocresp_extra->buf,
3160 wpabuf_len(assocresp_extra));
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003161 if (!beacon->assocresp_ies)
3162 goto free_beacon;
3163
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003164 beacon->assocresp_ies_len = wpabuf_len(assocresp_extra);
3165 }
3166
3167 ret = 0;
3168free_beacon:
3169 /* if the function fails, the caller should not free beacon data */
3170 if (ret)
3171 free_beacon_data(beacon);
3172
3173free_ap_extra_ies:
3174 hostapd_free_ap_extra_ies(hapd, beacon_extra, proberesp_extra,
3175 assocresp_extra);
3176free_ap_params:
3177 ieee802_11_free_ap_params(&params);
3178 return ret;
3179}
3180
3181
3182/*
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003183 * TODO: This flow currently supports only changing channel and width within
3184 * the same hw_mode. Any other changes to MAC parameters or provided settings
3185 * are not supported.
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003186 */
3187static int hostapd_change_config_freq(struct hostapd_data *hapd,
3188 struct hostapd_config *conf,
3189 struct hostapd_freq_params *params,
3190 struct hostapd_freq_params *old_params)
3191{
3192 int channel;
3193
3194 if (!params->channel) {
3195 /* check if the new channel is supported by hw */
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07003196 params->channel = hostapd_hw_get_channel(hapd, params->freq);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003197 }
3198
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07003199 channel = params->channel;
3200 if (!channel)
3201 return -1;
3202
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003203 /* if a pointer to old_params is provided we save previous state */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003204 if (old_params &&
3205 hostapd_set_freq_params(old_params, conf->hw_mode,
3206 hostapd_hw_get_freq(hapd, conf->channel),
3207 conf->channel, conf->ieee80211n,
3208 conf->ieee80211ac,
3209 conf->secondary_channel,
3210 conf->vht_oper_chwidth,
3211 conf->vht_oper_centr_freq_seg0_idx,
3212 conf->vht_oper_centr_freq_seg1_idx,
3213 conf->vht_capab))
3214 return -1;
3215
3216 switch (params->bandwidth) {
3217 case 0:
3218 case 20:
3219 case 40:
3220 conf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT;
3221 break;
3222 case 80:
3223 if (params->center_freq2)
3224 conf->vht_oper_chwidth = VHT_CHANWIDTH_80P80MHZ;
3225 else
3226 conf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ;
3227 break;
3228 case 160:
3229 conf->vht_oper_chwidth = VHT_CHANWIDTH_160MHZ;
3230 break;
3231 default:
3232 return -1;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003233 }
3234
3235 conf->channel = channel;
3236 conf->ieee80211n = params->ht_enabled;
3237 conf->secondary_channel = params->sec_channel_offset;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003238 ieee80211_freq_to_chan(params->center_freq1,
3239 &conf->vht_oper_centr_freq_seg0_idx);
3240 ieee80211_freq_to_chan(params->center_freq2,
3241 &conf->vht_oper_centr_freq_seg1_idx);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003242
3243 /* TODO: maybe call here hostapd_config_check here? */
3244
3245 return 0;
3246}
3247
3248
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07003249static int hostapd_fill_csa_settings(struct hostapd_data *hapd,
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003250 struct csa_settings *settings)
3251{
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07003252 struct hostapd_iface *iface = hapd->iface;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003253 struct hostapd_freq_params old_freq;
3254 int ret;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003255 u8 chan, vht_bandwidth;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003256
3257 os_memset(&old_freq, 0, sizeof(old_freq));
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07003258 if (!iface || !iface->freq || hapd->csa_in_progress)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003259 return -1;
3260
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003261 switch (settings->freq_params.bandwidth) {
3262 case 80:
3263 if (settings->freq_params.center_freq2)
3264 vht_bandwidth = VHT_CHANWIDTH_80P80MHZ;
3265 else
3266 vht_bandwidth = VHT_CHANWIDTH_80MHZ;
3267 break;
3268 case 160:
3269 vht_bandwidth = VHT_CHANWIDTH_160MHZ;
3270 break;
3271 default:
3272 vht_bandwidth = VHT_CHANWIDTH_USE_HT;
3273 break;
3274 }
3275
3276 if (ieee80211_freq_to_channel_ext(
3277 settings->freq_params.freq,
3278 settings->freq_params.sec_channel_offset,
3279 vht_bandwidth,
3280 &hapd->iface->cs_oper_class,
3281 &chan) == NUM_HOSTAPD_MODES) {
3282 wpa_printf(MSG_DEBUG,
3283 "invalid frequency for channel switch (freq=%d, sec_channel_offset=%d, vht_enabled=%d)",
3284 settings->freq_params.freq,
3285 settings->freq_params.sec_channel_offset,
3286 settings->freq_params.vht_enabled);
3287 return -1;
3288 }
3289
3290 settings->freq_params.channel = chan;
3291
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003292 ret = hostapd_change_config_freq(iface->bss[0], iface->conf,
3293 &settings->freq_params,
3294 &old_freq);
3295 if (ret)
3296 return ret;
3297
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07003298 ret = hostapd_build_beacon_data(hapd, &settings->beacon_after);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003299
3300 /* change back the configuration */
3301 hostapd_change_config_freq(iface->bss[0], iface->conf,
3302 &old_freq, NULL);
3303
3304 if (ret)
3305 return ret;
3306
3307 /* set channel switch parameters for csa ie */
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07003308 hapd->cs_freq_params = settings->freq_params;
3309 hapd->cs_count = settings->cs_count;
3310 hapd->cs_block_tx = settings->block_tx;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003311
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07003312 ret = hostapd_build_beacon_data(hapd, &settings->beacon_csa);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003313 if (ret) {
3314 free_beacon_data(&settings->beacon_after);
3315 return ret;
3316 }
3317
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003318 settings->counter_offset_beacon[0] = hapd->cs_c_off_beacon;
3319 settings->counter_offset_presp[0] = hapd->cs_c_off_proberesp;
3320 settings->counter_offset_beacon[1] = hapd->cs_c_off_ecsa_beacon;
3321 settings->counter_offset_presp[1] = hapd->cs_c_off_ecsa_proberesp;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003322
3323 return 0;
3324}
3325
3326
3327void hostapd_cleanup_cs_params(struct hostapd_data *hapd)
3328{
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07003329 os_memset(&hapd->cs_freq_params, 0, sizeof(hapd->cs_freq_params));
3330 hapd->cs_count = 0;
3331 hapd->cs_block_tx = 0;
3332 hapd->cs_c_off_beacon = 0;
3333 hapd->cs_c_off_proberesp = 0;
3334 hapd->csa_in_progress = 0;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003335 hapd->cs_c_off_ecsa_beacon = 0;
3336 hapd->cs_c_off_ecsa_proberesp = 0;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003337}
3338
3339
Roshan Pius3a1667e2018-07-03 15:17:14 -07003340void hostapd_chan_switch_vht_config(struct hostapd_data *hapd, int vht_enabled)
3341{
3342 if (vht_enabled)
3343 hapd->iconf->ch_switch_vht_config |= CH_SWITCH_VHT_ENABLED;
3344 else
3345 hapd->iconf->ch_switch_vht_config |= CH_SWITCH_VHT_DISABLED;
3346
3347 hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
3348 HOSTAPD_LEVEL_INFO, "CHAN_SWITCH VHT CONFIG 0x%x",
3349 hapd->iconf->ch_switch_vht_config);
3350}
3351
3352
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003353int hostapd_switch_channel(struct hostapd_data *hapd,
3354 struct csa_settings *settings)
3355{
3356 int ret;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003357
3358 if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA)) {
3359 wpa_printf(MSG_INFO, "CSA is not supported");
3360 return -1;
3361 }
3362
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07003363 ret = hostapd_fill_csa_settings(hapd, settings);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003364 if (ret)
3365 return ret;
3366
3367 ret = hostapd_drv_switch_channel(hapd, settings);
3368 free_beacon_data(&settings->beacon_csa);
3369 free_beacon_data(&settings->beacon_after);
3370
3371 if (ret) {
3372 /* if we failed, clean cs parameters */
3373 hostapd_cleanup_cs_params(hapd);
3374 return ret;
3375 }
3376
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07003377 hapd->csa_in_progress = 1;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003378 return 0;
3379}
3380
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07003381
3382void
3383hostapd_switch_channel_fallback(struct hostapd_iface *iface,
3384 const struct hostapd_freq_params *freq_params)
3385{
3386 int vht_seg0_idx = 0, vht_seg1_idx = 0, vht_bw = VHT_CHANWIDTH_USE_HT;
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07003387
3388 wpa_printf(MSG_DEBUG, "Restarting all CSA-related BSSes");
3389
3390 if (freq_params->center_freq1)
3391 vht_seg0_idx = 36 + (freq_params->center_freq1 - 5180) / 5;
3392 if (freq_params->center_freq2)
3393 vht_seg1_idx = 36 + (freq_params->center_freq2 - 5180) / 5;
3394
3395 switch (freq_params->bandwidth) {
3396 case 0:
3397 case 20:
3398 case 40:
3399 vht_bw = VHT_CHANWIDTH_USE_HT;
3400 break;
3401 case 80:
3402 if (freq_params->center_freq2)
3403 vht_bw = VHT_CHANWIDTH_80P80MHZ;
3404 else
3405 vht_bw = VHT_CHANWIDTH_80MHZ;
3406 break;
3407 case 160:
3408 vht_bw = VHT_CHANWIDTH_160MHZ;
3409 break;
3410 default:
3411 wpa_printf(MSG_WARNING, "Unknown CSA bandwidth: %d",
3412 freq_params->bandwidth);
3413 break;
3414 }
3415
3416 iface->freq = freq_params->freq;
3417 iface->conf->channel = freq_params->channel;
3418 iface->conf->secondary_channel = freq_params->sec_channel_offset;
3419 iface->conf->vht_oper_centr_freq_seg0_idx = vht_seg0_idx;
3420 iface->conf->vht_oper_centr_freq_seg1_idx = vht_seg1_idx;
3421 iface->conf->vht_oper_chwidth = vht_bw;
3422 iface->conf->ieee80211n = freq_params->ht_enabled;
3423 iface->conf->ieee80211ac = freq_params->vht_enabled;
3424
3425 /*
3426 * cs_params must not be cleared earlier because the freq_params
3427 * argument may actually point to one of these.
Hai Shalom39ba6fc2019-01-22 12:40:38 -08003428 * These params will be cleared during interface disable below.
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07003429 */
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07003430 hostapd_disable_iface(iface);
3431 hostapd_enable_iface(iface);
3432}
3433
Dmitry Shmidte4663042016-04-04 10:07:49 -07003434#endif /* NEED_AP_MLME */
3435
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003436
3437struct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces,
3438 const char *ifname)
3439{
3440 size_t i, j;
3441
3442 for (i = 0; i < interfaces->count; i++) {
3443 struct hostapd_iface *iface = interfaces->iface[i];
3444
3445 for (j = 0; j < iface->num_bss; j++) {
3446 struct hostapd_data *hapd = iface->bss[j];
3447
3448 if (os_strcmp(ifname, hapd->conf->iface) == 0)
3449 return hapd;
3450 }
3451 }
3452
3453 return NULL;
3454}
3455
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003456
3457void hostapd_periodic_iface(struct hostapd_iface *iface)
3458{
3459 size_t i;
3460
3461 ap_list_timer(iface);
3462
3463 for (i = 0; i < iface->num_bss; i++) {
3464 struct hostapd_data *hapd = iface->bss[i];
3465
3466 if (!hapd->started)
3467 continue;
3468
3469#ifndef CONFIG_NO_RADIUS
3470 hostapd_acl_expire(hapd);
3471#endif /* CONFIG_NO_RADIUS */
3472 }
3473}