13ff40c12SJohn Marino /*
23ff40c12SJohn Marino * hostapd / Initialization and configuration
3*a1157835SDaniel Fojt * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
43ff40c12SJohn Marino *
53ff40c12SJohn Marino * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino * See README for more details.
73ff40c12SJohn Marino */
83ff40c12SJohn Marino
93ff40c12SJohn Marino #include "utils/includes.h"
10*a1157835SDaniel Fojt #ifdef CONFIG_SQLITE
11*a1157835SDaniel Fojt #include <sqlite3.h>
12*a1157835SDaniel Fojt #endif /* CONFIG_SQLITE */
133ff40c12SJohn Marino
143ff40c12SJohn Marino #include "utils/common.h"
153ff40c12SJohn Marino #include "utils/eloop.h"
163ff40c12SJohn Marino #include "common/ieee802_11_defs.h"
173ff40c12SJohn Marino #include "common/wpa_ctrl.h"
18*a1157835SDaniel Fojt #include "common/hw_features_common.h"
193ff40c12SJohn Marino #include "radius/radius_client.h"
203ff40c12SJohn Marino #include "radius/radius_das.h"
21*a1157835SDaniel Fojt #include "eap_server/tncs.h"
22*a1157835SDaniel Fojt #include "eapol_auth/eapol_auth_sm.h"
23*a1157835SDaniel Fojt #include "eapol_auth/eapol_auth_sm_i.h"
24*a1157835SDaniel Fojt #include "fst/fst.h"
253ff40c12SJohn Marino #include "hostapd.h"
263ff40c12SJohn Marino #include "authsrv.h"
273ff40c12SJohn Marino #include "sta_info.h"
283ff40c12SJohn Marino #include "accounting.h"
293ff40c12SJohn Marino #include "ap_list.h"
303ff40c12SJohn Marino #include "beacon.h"
313ff40c12SJohn Marino #include "iapp.h"
323ff40c12SJohn Marino #include "ieee802_1x.h"
333ff40c12SJohn Marino #include "ieee802_11_auth.h"
343ff40c12SJohn Marino #include "vlan_init.h"
353ff40c12SJohn Marino #include "wpa_auth.h"
363ff40c12SJohn Marino #include "wps_hostapd.h"
37*a1157835SDaniel Fojt #include "dpp_hostapd.h"
38*a1157835SDaniel Fojt #include "gas_query_ap.h"
393ff40c12SJohn Marino #include "hw_features.h"
403ff40c12SJohn Marino #include "wpa_auth_glue.h"
413ff40c12SJohn Marino #include "ap_drv_ops.h"
423ff40c12SJohn Marino #include "ap_config.h"
433ff40c12SJohn Marino #include "p2p_hostapd.h"
443ff40c12SJohn Marino #include "gas_serv.h"
453ff40c12SJohn Marino #include "dfs.h"
46*a1157835SDaniel Fojt #include "ieee802_11.h"
47*a1157835SDaniel Fojt #include "bss_load.h"
48*a1157835SDaniel Fojt #include "x_snoop.h"
49*a1157835SDaniel Fojt #include "dhcp_snoop.h"
50*a1157835SDaniel Fojt #include "ndisc_snoop.h"
51*a1157835SDaniel Fojt #include "neighbor_db.h"
52*a1157835SDaniel Fojt #include "rrm.h"
53*a1157835SDaniel Fojt #include "fils_hlp.h"
54*a1157835SDaniel Fojt #include "acs.h"
55*a1157835SDaniel Fojt #include "hs20.h"
56*a1157835SDaniel Fojt #include "airtime_policy.h"
57*a1157835SDaniel Fojt #include "wpa_auth_kay.h"
583ff40c12SJohn Marino
593ff40c12SJohn Marino
603ff40c12SJohn Marino static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
613ff40c12SJohn Marino static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd);
623ff40c12SJohn Marino static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd);
633ff40c12SJohn Marino static int setup_interface2(struct hostapd_iface *iface);
643ff40c12SJohn Marino static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx);
65*a1157835SDaniel Fojt static void hostapd_interface_setup_failure_handler(void *eloop_ctx,
66*a1157835SDaniel Fojt void *timeout_ctx);
673ff40c12SJohn Marino
683ff40c12SJohn Marino
hostapd_for_each_interface(struct hapd_interfaces * interfaces,int (* cb)(struct hostapd_iface * iface,void * ctx),void * ctx)693ff40c12SJohn Marino int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
703ff40c12SJohn Marino int (*cb)(struct hostapd_iface *iface,
713ff40c12SJohn Marino void *ctx), void *ctx)
723ff40c12SJohn Marino {
733ff40c12SJohn Marino size_t i;
743ff40c12SJohn Marino int ret;
753ff40c12SJohn Marino
763ff40c12SJohn Marino for (i = 0; i < interfaces->count; i++) {
773ff40c12SJohn Marino ret = cb(interfaces->iface[i], ctx);
783ff40c12SJohn Marino if (ret)
793ff40c12SJohn Marino return ret;
803ff40c12SJohn Marino }
813ff40c12SJohn Marino
823ff40c12SJohn Marino return 0;
833ff40c12SJohn Marino }
843ff40c12SJohn Marino
853ff40c12SJohn Marino
hostapd_reconfig_encryption(struct hostapd_data * hapd)86*a1157835SDaniel Fojt void hostapd_reconfig_encryption(struct hostapd_data *hapd)
87*a1157835SDaniel Fojt {
88*a1157835SDaniel Fojt if (hapd->wpa_auth)
89*a1157835SDaniel Fojt return;
90*a1157835SDaniel Fojt
91*a1157835SDaniel Fojt hostapd_set_privacy(hapd, 0);
92*a1157835SDaniel Fojt hostapd_setup_encryption(hapd->conf->iface, hapd);
93*a1157835SDaniel Fojt }
94*a1157835SDaniel Fojt
95*a1157835SDaniel Fojt
hostapd_reload_bss(struct hostapd_data * hapd)963ff40c12SJohn Marino static void hostapd_reload_bss(struct hostapd_data *hapd)
973ff40c12SJohn Marino {
983ff40c12SJohn Marino struct hostapd_ssid *ssid;
993ff40c12SJohn Marino
100*a1157835SDaniel Fojt if (!hapd->started)
101*a1157835SDaniel Fojt return;
102*a1157835SDaniel Fojt
103*a1157835SDaniel Fojt if (hapd->conf->wmm_enabled < 0)
104*a1157835SDaniel Fojt hapd->conf->wmm_enabled = hapd->iconf->ieee80211n;
105*a1157835SDaniel Fojt
1063ff40c12SJohn Marino #ifndef CONFIG_NO_RADIUS
1073ff40c12SJohn Marino radius_client_reconfig(hapd->radius, hapd->conf->radius);
1083ff40c12SJohn Marino #endif /* CONFIG_NO_RADIUS */
1093ff40c12SJohn Marino
1103ff40c12SJohn Marino ssid = &hapd->conf->ssid;
1113ff40c12SJohn Marino if (!ssid->wpa_psk_set && ssid->wpa_psk && !ssid->wpa_psk->next &&
1123ff40c12SJohn Marino ssid->wpa_passphrase_set && ssid->wpa_passphrase) {
1133ff40c12SJohn Marino /*
1143ff40c12SJohn Marino * Force PSK to be derived again since SSID or passphrase may
1153ff40c12SJohn Marino * have changed.
1163ff40c12SJohn Marino */
117*a1157835SDaniel Fojt hostapd_config_clear_wpa_psk(&hapd->conf->ssid.wpa_psk);
1183ff40c12SJohn Marino }
1193ff40c12SJohn Marino if (hostapd_setup_wpa_psk(hapd->conf)) {
1203ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Failed to re-configure WPA PSK "
1213ff40c12SJohn Marino "after reloading configuration");
1223ff40c12SJohn Marino }
1233ff40c12SJohn Marino
1243ff40c12SJohn Marino if (hapd->conf->ieee802_1x || hapd->conf->wpa)
1253ff40c12SJohn Marino hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 1);
1263ff40c12SJohn Marino else
1273ff40c12SJohn Marino hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0);
1283ff40c12SJohn Marino
129*a1157835SDaniel Fojt if ((hapd->conf->wpa || hapd->conf->osen) && hapd->wpa_auth == NULL) {
1303ff40c12SJohn Marino hostapd_setup_wpa(hapd);
1313ff40c12SJohn Marino if (hapd->wpa_auth)
1323ff40c12SJohn Marino wpa_init_keys(hapd->wpa_auth);
1333ff40c12SJohn Marino } else if (hapd->conf->wpa) {
1343ff40c12SJohn Marino const u8 *wpa_ie;
1353ff40c12SJohn Marino size_t wpa_ie_len;
1363ff40c12SJohn Marino hostapd_reconfig_wpa(hapd);
1373ff40c12SJohn Marino wpa_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &wpa_ie_len);
1383ff40c12SJohn Marino if (hostapd_set_generic_elem(hapd, wpa_ie, wpa_ie_len))
1393ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Failed to configure WPA IE for "
1403ff40c12SJohn Marino "the kernel driver.");
1413ff40c12SJohn Marino } else if (hapd->wpa_auth) {
1423ff40c12SJohn Marino wpa_deinit(hapd->wpa_auth);
1433ff40c12SJohn Marino hapd->wpa_auth = NULL;
1443ff40c12SJohn Marino hostapd_set_privacy(hapd, 0);
1453ff40c12SJohn Marino hostapd_setup_encryption(hapd->conf->iface, hapd);
1463ff40c12SJohn Marino hostapd_set_generic_elem(hapd, (u8 *) "", 0);
1473ff40c12SJohn Marino }
1483ff40c12SJohn Marino
1493ff40c12SJohn Marino ieee802_11_set_beacon(hapd);
1503ff40c12SJohn Marino hostapd_update_wps(hapd);
1513ff40c12SJohn Marino
1523ff40c12SJohn Marino if (hapd->conf->ssid.ssid_set &&
1533ff40c12SJohn Marino hostapd_set_ssid(hapd, hapd->conf->ssid.ssid,
1543ff40c12SJohn Marino hapd->conf->ssid.ssid_len)) {
1553ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver");
1563ff40c12SJohn Marino /* try to continue */
1573ff40c12SJohn Marino }
1583ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Reconfigured interface %s", hapd->conf->iface);
1593ff40c12SJohn Marino }
1603ff40c12SJohn Marino
1613ff40c12SJohn Marino
hostapd_clear_old(struct hostapd_iface * iface)1623ff40c12SJohn Marino static void hostapd_clear_old(struct hostapd_iface *iface)
1633ff40c12SJohn Marino {
1643ff40c12SJohn Marino size_t j;
1653ff40c12SJohn Marino
1663ff40c12SJohn Marino /*
1673ff40c12SJohn Marino * Deauthenticate all stations since the new configuration may not
1683ff40c12SJohn Marino * allow them to use the BSS anymore.
1693ff40c12SJohn Marino */
1703ff40c12SJohn Marino for (j = 0; j < iface->num_bss; j++) {
1713ff40c12SJohn Marino hostapd_flush_old_stations(iface->bss[j],
1723ff40c12SJohn Marino WLAN_REASON_PREV_AUTH_NOT_VALID);
1733ff40c12SJohn Marino hostapd_broadcast_wep_clear(iface->bss[j]);
1743ff40c12SJohn Marino
1753ff40c12SJohn Marino #ifndef CONFIG_NO_RADIUS
1763ff40c12SJohn Marino /* TODO: update dynamic data based on changed configuration
1773ff40c12SJohn Marino * items (e.g., open/close sockets, etc.) */
1783ff40c12SJohn Marino radius_client_flush(iface->bss[j]->radius, 0);
1793ff40c12SJohn Marino #endif /* CONFIG_NO_RADIUS */
1803ff40c12SJohn Marino }
1813ff40c12SJohn Marino }
1823ff40c12SJohn Marino
1833ff40c12SJohn Marino
hostapd_iface_conf_changed(struct hostapd_config * newconf,struct hostapd_config * oldconf)184*a1157835SDaniel Fojt static int hostapd_iface_conf_changed(struct hostapd_config *newconf,
185*a1157835SDaniel Fojt struct hostapd_config *oldconf)
186*a1157835SDaniel Fojt {
187*a1157835SDaniel Fojt size_t i;
188*a1157835SDaniel Fojt
189*a1157835SDaniel Fojt if (newconf->num_bss != oldconf->num_bss)
190*a1157835SDaniel Fojt return 1;
191*a1157835SDaniel Fojt
192*a1157835SDaniel Fojt for (i = 0; i < newconf->num_bss; i++) {
193*a1157835SDaniel Fojt if (os_strcmp(newconf->bss[i]->iface,
194*a1157835SDaniel Fojt oldconf->bss[i]->iface) != 0)
195*a1157835SDaniel Fojt return 1;
196*a1157835SDaniel Fojt }
197*a1157835SDaniel Fojt
198*a1157835SDaniel Fojt return 0;
199*a1157835SDaniel Fojt }
200*a1157835SDaniel Fojt
201*a1157835SDaniel Fojt
hostapd_reload_config(struct hostapd_iface * iface)2023ff40c12SJohn Marino int hostapd_reload_config(struct hostapd_iface *iface)
2033ff40c12SJohn Marino {
204*a1157835SDaniel Fojt struct hapd_interfaces *interfaces = iface->interfaces;
2053ff40c12SJohn Marino struct hostapd_data *hapd = iface->bss[0];
2063ff40c12SJohn Marino struct hostapd_config *newconf, *oldconf;
2073ff40c12SJohn Marino size_t j;
2083ff40c12SJohn Marino
2093ff40c12SJohn Marino if (iface->config_fname == NULL) {
2103ff40c12SJohn Marino /* Only in-memory config in use - assume it has been updated */
2113ff40c12SJohn Marino hostapd_clear_old(iface);
2123ff40c12SJohn Marino for (j = 0; j < iface->num_bss; j++)
2133ff40c12SJohn Marino hostapd_reload_bss(iface->bss[j]);
2143ff40c12SJohn Marino return 0;
2153ff40c12SJohn Marino }
2163ff40c12SJohn Marino
2173ff40c12SJohn Marino if (iface->interfaces == NULL ||
2183ff40c12SJohn Marino iface->interfaces->config_read_cb == NULL)
2193ff40c12SJohn Marino return -1;
2203ff40c12SJohn Marino newconf = iface->interfaces->config_read_cb(iface->config_fname);
2213ff40c12SJohn Marino if (newconf == NULL)
2223ff40c12SJohn Marino return -1;
2233ff40c12SJohn Marino
2243ff40c12SJohn Marino hostapd_clear_old(iface);
2253ff40c12SJohn Marino
2263ff40c12SJohn Marino oldconf = hapd->iconf;
227*a1157835SDaniel Fojt if (hostapd_iface_conf_changed(newconf, oldconf)) {
228*a1157835SDaniel Fojt char *fname;
229*a1157835SDaniel Fojt int res;
230*a1157835SDaniel Fojt
231*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
232*a1157835SDaniel Fojt "Configuration changes include interface/BSS modification - force full disable+enable sequence");
233*a1157835SDaniel Fojt fname = os_strdup(iface->config_fname);
234*a1157835SDaniel Fojt if (!fname) {
235*a1157835SDaniel Fojt hostapd_config_free(newconf);
236*a1157835SDaniel Fojt return -1;
237*a1157835SDaniel Fojt }
238*a1157835SDaniel Fojt hostapd_remove_iface(interfaces, hapd->conf->iface);
239*a1157835SDaniel Fojt iface = hostapd_init(interfaces, fname);
240*a1157835SDaniel Fojt os_free(fname);
241*a1157835SDaniel Fojt hostapd_config_free(newconf);
242*a1157835SDaniel Fojt if (!iface) {
243*a1157835SDaniel Fojt wpa_printf(MSG_ERROR,
244*a1157835SDaniel Fojt "Failed to initialize interface on config reload");
245*a1157835SDaniel Fojt return -1;
246*a1157835SDaniel Fojt }
247*a1157835SDaniel Fojt iface->interfaces = interfaces;
248*a1157835SDaniel Fojt interfaces->iface[interfaces->count] = iface;
249*a1157835SDaniel Fojt interfaces->count++;
250*a1157835SDaniel Fojt res = hostapd_enable_iface(iface);
251*a1157835SDaniel Fojt if (res < 0)
252*a1157835SDaniel Fojt wpa_printf(MSG_ERROR,
253*a1157835SDaniel Fojt "Failed to enable interface on config reload");
254*a1157835SDaniel Fojt return res;
255*a1157835SDaniel Fojt }
2563ff40c12SJohn Marino iface->conf = newconf;
2573ff40c12SJohn Marino
2583ff40c12SJohn Marino for (j = 0; j < iface->num_bss; j++) {
2593ff40c12SJohn Marino hapd = iface->bss[j];
2603ff40c12SJohn Marino hapd->iconf = newconf;
261*a1157835SDaniel Fojt hapd->iconf->channel = oldconf->channel;
262*a1157835SDaniel Fojt hapd->iconf->acs = oldconf->acs;
263*a1157835SDaniel Fojt hapd->iconf->secondary_channel = oldconf->secondary_channel;
264*a1157835SDaniel Fojt hapd->iconf->ieee80211n = oldconf->ieee80211n;
265*a1157835SDaniel Fojt hapd->iconf->ieee80211ac = oldconf->ieee80211ac;
266*a1157835SDaniel Fojt hapd->iconf->ht_capab = oldconf->ht_capab;
267*a1157835SDaniel Fojt hapd->iconf->vht_capab = oldconf->vht_capab;
268*a1157835SDaniel Fojt hostapd_set_oper_chwidth(hapd->iconf,
269*a1157835SDaniel Fojt hostapd_get_oper_chwidth(oldconf));
270*a1157835SDaniel Fojt hostapd_set_oper_centr_freq_seg0_idx(
271*a1157835SDaniel Fojt hapd->iconf,
272*a1157835SDaniel Fojt hostapd_get_oper_centr_freq_seg0_idx(oldconf));
273*a1157835SDaniel Fojt hostapd_set_oper_centr_freq_seg1_idx(
274*a1157835SDaniel Fojt hapd->iconf,
275*a1157835SDaniel Fojt hostapd_get_oper_centr_freq_seg1_idx(oldconf));
2763ff40c12SJohn Marino hapd->conf = newconf->bss[j];
2773ff40c12SJohn Marino hostapd_reload_bss(hapd);
2783ff40c12SJohn Marino }
2793ff40c12SJohn Marino
2803ff40c12SJohn Marino hostapd_config_free(oldconf);
2813ff40c12SJohn Marino
2823ff40c12SJohn Marino
2833ff40c12SJohn Marino return 0;
2843ff40c12SJohn Marino }
2853ff40c12SJohn Marino
2863ff40c12SJohn Marino
hostapd_broadcast_key_clear_iface(struct hostapd_data * hapd,const char * ifname)2873ff40c12SJohn Marino static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
288*a1157835SDaniel Fojt const char *ifname)
2893ff40c12SJohn Marino {
2903ff40c12SJohn Marino int i;
2913ff40c12SJohn Marino
292*a1157835SDaniel Fojt if (!ifname || !hapd->drv_priv)
293*a1157835SDaniel Fojt return;
2943ff40c12SJohn Marino for (i = 0; i < NUM_WEP_KEYS; i++) {
2953ff40c12SJohn Marino if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i,
2963ff40c12SJohn Marino 0, NULL, 0, NULL, 0)) {
2973ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Failed to clear default "
2983ff40c12SJohn Marino "encryption keys (ifname=%s keyidx=%d)",
2993ff40c12SJohn Marino ifname, i);
3003ff40c12SJohn Marino }
3013ff40c12SJohn Marino }
3023ff40c12SJohn Marino #ifdef CONFIG_IEEE80211W
3033ff40c12SJohn Marino if (hapd->conf->ieee80211w) {
3043ff40c12SJohn Marino for (i = NUM_WEP_KEYS; i < NUM_WEP_KEYS + 2; i++) {
3053ff40c12SJohn Marino if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE,
3063ff40c12SJohn Marino NULL, i, 0, NULL,
3073ff40c12SJohn Marino 0, NULL, 0)) {
3083ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Failed to clear "
3093ff40c12SJohn Marino "default mgmt encryption keys "
3103ff40c12SJohn Marino "(ifname=%s keyidx=%d)", ifname, i);
3113ff40c12SJohn Marino }
3123ff40c12SJohn Marino }
3133ff40c12SJohn Marino }
3143ff40c12SJohn Marino #endif /* CONFIG_IEEE80211W */
3153ff40c12SJohn Marino }
3163ff40c12SJohn Marino
3173ff40c12SJohn Marino
hostapd_broadcast_wep_clear(struct hostapd_data * hapd)3183ff40c12SJohn Marino static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd)
3193ff40c12SJohn Marino {
3203ff40c12SJohn Marino hostapd_broadcast_key_clear_iface(hapd, hapd->conf->iface);
3213ff40c12SJohn Marino return 0;
3223ff40c12SJohn Marino }
3233ff40c12SJohn Marino
3243ff40c12SJohn Marino
hostapd_broadcast_wep_set(struct hostapd_data * hapd)3253ff40c12SJohn Marino static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
3263ff40c12SJohn Marino {
3273ff40c12SJohn Marino int errors = 0, idx;
3283ff40c12SJohn Marino struct hostapd_ssid *ssid = &hapd->conf->ssid;
3293ff40c12SJohn Marino
3303ff40c12SJohn Marino idx = ssid->wep.idx;
3313ff40c12SJohn Marino if (ssid->wep.default_len &&
3323ff40c12SJohn Marino hostapd_drv_set_key(hapd->conf->iface,
3333ff40c12SJohn Marino hapd, WPA_ALG_WEP, broadcast_ether_addr, idx,
3343ff40c12SJohn Marino 1, NULL, 0, ssid->wep.key[idx],
3353ff40c12SJohn Marino ssid->wep.len[idx])) {
3363ff40c12SJohn Marino wpa_printf(MSG_WARNING, "Could not set WEP encryption.");
3373ff40c12SJohn Marino errors++;
3383ff40c12SJohn Marino }
3393ff40c12SJohn Marino
3403ff40c12SJohn Marino return errors;
3413ff40c12SJohn Marino }
3423ff40c12SJohn Marino
3433ff40c12SJohn Marino
hostapd_free_hapd_data(struct hostapd_data * hapd)3443ff40c12SJohn Marino static void hostapd_free_hapd_data(struct hostapd_data *hapd)
3453ff40c12SJohn Marino {
346*a1157835SDaniel Fojt os_free(hapd->probereq_cb);
347*a1157835SDaniel Fojt hapd->probereq_cb = NULL;
348*a1157835SDaniel Fojt hapd->num_probereq_cb = 0;
349*a1157835SDaniel Fojt
350*a1157835SDaniel Fojt #ifdef CONFIG_P2P
351*a1157835SDaniel Fojt wpabuf_free(hapd->p2p_beacon_ie);
352*a1157835SDaniel Fojt hapd->p2p_beacon_ie = NULL;
353*a1157835SDaniel Fojt wpabuf_free(hapd->p2p_probe_resp_ie);
354*a1157835SDaniel Fojt hapd->p2p_probe_resp_ie = NULL;
355*a1157835SDaniel Fojt #endif /* CONFIG_P2P */
356*a1157835SDaniel Fojt
3573ff40c12SJohn Marino if (!hapd->started) {
3583ff40c12SJohn Marino wpa_printf(MSG_ERROR, "%s: Interface %s wasn't started",
359*a1157835SDaniel Fojt __func__, hapd->conf ? hapd->conf->iface : "N/A");
3603ff40c12SJohn Marino return;
3613ff40c12SJohn Marino }
3623ff40c12SJohn Marino hapd->started = 0;
363*a1157835SDaniel Fojt hapd->beacon_set_done = 0;
3643ff40c12SJohn Marino
3653ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "%s(%s)", __func__, hapd->conf->iface);
3663ff40c12SJohn Marino iapp_deinit(hapd->iapp);
3673ff40c12SJohn Marino hapd->iapp = NULL;
3683ff40c12SJohn Marino accounting_deinit(hapd);
3693ff40c12SJohn Marino hostapd_deinit_wpa(hapd);
3703ff40c12SJohn Marino vlan_deinit(hapd);
3713ff40c12SJohn Marino hostapd_acl_deinit(hapd);
3723ff40c12SJohn Marino #ifndef CONFIG_NO_RADIUS
3733ff40c12SJohn Marino radius_client_deinit(hapd->radius);
3743ff40c12SJohn Marino hapd->radius = NULL;
3753ff40c12SJohn Marino radius_das_deinit(hapd->radius_das);
3763ff40c12SJohn Marino hapd->radius_das = NULL;
3773ff40c12SJohn Marino #endif /* CONFIG_NO_RADIUS */
3783ff40c12SJohn Marino
3793ff40c12SJohn Marino hostapd_deinit_wps(hapd);
380*a1157835SDaniel Fojt ieee802_1x_dealloc_kay_sm_hapd(hapd);
381*a1157835SDaniel Fojt #ifdef CONFIG_DPP
382*a1157835SDaniel Fojt hostapd_dpp_deinit(hapd);
383*a1157835SDaniel Fojt gas_query_ap_deinit(hapd->gas);
384*a1157835SDaniel Fojt #endif /* CONFIG_DPP */
3853ff40c12SJohn Marino
3863ff40c12SJohn Marino authsrv_deinit(hapd);
3873ff40c12SJohn Marino
388*a1157835SDaniel Fojt if (hapd->interface_added) {
389*a1157835SDaniel Fojt hapd->interface_added = 0;
390*a1157835SDaniel Fojt if (hostapd_if_remove(hapd, WPA_IF_AP_BSS, hapd->conf->iface)) {
391*a1157835SDaniel Fojt wpa_printf(MSG_WARNING,
392*a1157835SDaniel Fojt "Failed to remove BSS interface %s",
3933ff40c12SJohn Marino hapd->conf->iface);
394*a1157835SDaniel Fojt hapd->interface_added = 1;
395*a1157835SDaniel Fojt } else {
396*a1157835SDaniel Fojt /*
397*a1157835SDaniel Fojt * Since this was a dynamically added interface, the
398*a1157835SDaniel Fojt * driver wrapper may have removed its internal instance
399*a1157835SDaniel Fojt * and hapd->drv_priv is not valid anymore.
400*a1157835SDaniel Fojt */
401*a1157835SDaniel Fojt hapd->drv_priv = NULL;
4023ff40c12SJohn Marino }
403*a1157835SDaniel Fojt }
4043ff40c12SJohn Marino
4053ff40c12SJohn Marino wpabuf_free(hapd->time_adv);
4063ff40c12SJohn Marino
4073ff40c12SJohn Marino #ifdef CONFIG_INTERWORKING
4083ff40c12SJohn Marino gas_serv_deinit(hapd);
4093ff40c12SJohn Marino #endif /* CONFIG_INTERWORKING */
4103ff40c12SJohn Marino
411*a1157835SDaniel Fojt bss_load_update_deinit(hapd);
412*a1157835SDaniel Fojt ndisc_snoop_deinit(hapd);
413*a1157835SDaniel Fojt dhcp_snoop_deinit(hapd);
414*a1157835SDaniel Fojt x_snoop_deinit(hapd);
415*a1157835SDaniel Fojt
4163ff40c12SJohn Marino #ifdef CONFIG_SQLITE
417*a1157835SDaniel Fojt bin_clear_free(hapd->tmp_eap_user.identity,
418*a1157835SDaniel Fojt hapd->tmp_eap_user.identity_len);
419*a1157835SDaniel Fojt bin_clear_free(hapd->tmp_eap_user.password,
420*a1157835SDaniel Fojt hapd->tmp_eap_user.password_len);
4213ff40c12SJohn Marino #endif /* CONFIG_SQLITE */
422*a1157835SDaniel Fojt
423*a1157835SDaniel Fojt #ifdef CONFIG_MESH
424*a1157835SDaniel Fojt wpabuf_free(hapd->mesh_pending_auth);
425*a1157835SDaniel Fojt hapd->mesh_pending_auth = NULL;
426*a1157835SDaniel Fojt #endif /* CONFIG_MESH */
427*a1157835SDaniel Fojt
428*a1157835SDaniel Fojt hostapd_clean_rrm(hapd);
429*a1157835SDaniel Fojt fils_hlp_deinit(hapd);
430*a1157835SDaniel Fojt
431*a1157835SDaniel Fojt #ifdef CONFIG_SAE
432*a1157835SDaniel Fojt {
433*a1157835SDaniel Fojt struct hostapd_sae_commit_queue *q;
434*a1157835SDaniel Fojt
435*a1157835SDaniel Fojt while ((q = dl_list_first(&hapd->sae_commit_queue,
436*a1157835SDaniel Fojt struct hostapd_sae_commit_queue,
437*a1157835SDaniel Fojt list))) {
438*a1157835SDaniel Fojt dl_list_del(&q->list);
439*a1157835SDaniel Fojt os_free(q);
440*a1157835SDaniel Fojt }
441*a1157835SDaniel Fojt }
442*a1157835SDaniel Fojt eloop_cancel_timeout(auth_sae_process_commit, hapd, NULL);
443*a1157835SDaniel Fojt #endif /* CONFIG_SAE */
4443ff40c12SJohn Marino }
4453ff40c12SJohn Marino
4463ff40c12SJohn Marino
4473ff40c12SJohn Marino /**
4483ff40c12SJohn Marino * hostapd_cleanup - Per-BSS cleanup (deinitialization)
4493ff40c12SJohn Marino * @hapd: Pointer to BSS data
4503ff40c12SJohn Marino *
4513ff40c12SJohn Marino * This function is used to free all per-BSS data structures and resources.
4523ff40c12SJohn Marino * Most of the modules that are initialized in hostapd_setup_bss() are
4533ff40c12SJohn Marino * deinitialized here.
4543ff40c12SJohn Marino */
hostapd_cleanup(struct hostapd_data * hapd)4553ff40c12SJohn Marino static void hostapd_cleanup(struct hostapd_data *hapd)
4563ff40c12SJohn Marino {
4573ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "%s(hapd=%p (%s))", __func__, hapd,
458*a1157835SDaniel Fojt hapd->conf ? hapd->conf->iface : "N/A");
4593ff40c12SJohn Marino if (hapd->iface->interfaces &&
460*a1157835SDaniel Fojt hapd->iface->interfaces->ctrl_iface_deinit) {
461*a1157835SDaniel Fojt wpa_msg(hapd->msg_ctx, MSG_INFO, WPA_EVENT_TERMINATING);
4623ff40c12SJohn Marino hapd->iface->interfaces->ctrl_iface_deinit(hapd);
463*a1157835SDaniel Fojt }
4643ff40c12SJohn Marino hostapd_free_hapd_data(hapd);
4653ff40c12SJohn Marino }
4663ff40c12SJohn Marino
4673ff40c12SJohn Marino
sta_track_deinit(struct hostapd_iface * iface)468*a1157835SDaniel Fojt static void sta_track_deinit(struct hostapd_iface *iface)
469*a1157835SDaniel Fojt {
470*a1157835SDaniel Fojt struct hostapd_sta_info *info;
471*a1157835SDaniel Fojt
472*a1157835SDaniel Fojt if (!iface->num_sta_seen)
473*a1157835SDaniel Fojt return;
474*a1157835SDaniel Fojt
475*a1157835SDaniel Fojt while ((info = dl_list_first(&iface->sta_seen, struct hostapd_sta_info,
476*a1157835SDaniel Fojt list))) {
477*a1157835SDaniel Fojt dl_list_del(&info->list);
478*a1157835SDaniel Fojt iface->num_sta_seen--;
479*a1157835SDaniel Fojt sta_track_del(info);
480*a1157835SDaniel Fojt }
481*a1157835SDaniel Fojt }
482*a1157835SDaniel Fojt
483*a1157835SDaniel Fojt
hostapd_cleanup_iface_partial(struct hostapd_iface * iface)4843ff40c12SJohn Marino static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
4853ff40c12SJohn Marino {
4863ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
487*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211N
488*a1157835SDaniel Fojt #ifdef NEED_AP_MLME
489*a1157835SDaniel Fojt hostapd_stop_setup_timers(iface);
490*a1157835SDaniel Fojt #endif /* NEED_AP_MLME */
491*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211N */
492*a1157835SDaniel Fojt if (iface->current_mode)
493*a1157835SDaniel Fojt acs_cleanup(iface);
4943ff40c12SJohn Marino hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
4953ff40c12SJohn Marino iface->hw_features = NULL;
496*a1157835SDaniel Fojt iface->current_mode = NULL;
4973ff40c12SJohn Marino os_free(iface->current_rates);
4983ff40c12SJohn Marino iface->current_rates = NULL;
4993ff40c12SJohn Marino os_free(iface->basic_rates);
5003ff40c12SJohn Marino iface->basic_rates = NULL;
5013ff40c12SJohn Marino ap_list_deinit(iface);
502*a1157835SDaniel Fojt sta_track_deinit(iface);
503*a1157835SDaniel Fojt airtime_policy_update_deinit(iface);
5043ff40c12SJohn Marino }
5053ff40c12SJohn Marino
5063ff40c12SJohn Marino
5073ff40c12SJohn Marino /**
5083ff40c12SJohn Marino * hostapd_cleanup_iface - Complete per-interface cleanup
5093ff40c12SJohn Marino * @iface: Pointer to interface data
5103ff40c12SJohn Marino *
5113ff40c12SJohn Marino * This function is called after per-BSS data structures are deinitialized
5123ff40c12SJohn Marino * with hostapd_cleanup().
5133ff40c12SJohn Marino */
hostapd_cleanup_iface(struct hostapd_iface * iface)5143ff40c12SJohn Marino static void hostapd_cleanup_iface(struct hostapd_iface *iface)
5153ff40c12SJohn Marino {
5163ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
5173ff40c12SJohn Marino eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
518*a1157835SDaniel Fojt eloop_cancel_timeout(hostapd_interface_setup_failure_handler, iface,
519*a1157835SDaniel Fojt NULL);
5203ff40c12SJohn Marino
5213ff40c12SJohn Marino hostapd_cleanup_iface_partial(iface);
5223ff40c12SJohn Marino hostapd_config_free(iface->conf);
5233ff40c12SJohn Marino iface->conf = NULL;
5243ff40c12SJohn Marino
5253ff40c12SJohn Marino os_free(iface->config_fname);
5263ff40c12SJohn Marino os_free(iface->bss);
5273ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "%s: free iface=%p", __func__, iface);
5283ff40c12SJohn Marino os_free(iface);
5293ff40c12SJohn Marino }
5303ff40c12SJohn Marino
5313ff40c12SJohn Marino
hostapd_clear_wep(struct hostapd_data * hapd)5323ff40c12SJohn Marino static void hostapd_clear_wep(struct hostapd_data *hapd)
5333ff40c12SJohn Marino {
534*a1157835SDaniel Fojt if (hapd->drv_priv && !hapd->iface->driver_ap_teardown && hapd->conf) {
5353ff40c12SJohn Marino hostapd_set_privacy(hapd, 0);
5363ff40c12SJohn Marino hostapd_broadcast_wep_clear(hapd);
5373ff40c12SJohn Marino }
5383ff40c12SJohn Marino }
5393ff40c12SJohn Marino
5403ff40c12SJohn Marino
hostapd_setup_encryption(char * iface,struct hostapd_data * hapd)5413ff40c12SJohn Marino static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd)
5423ff40c12SJohn Marino {
5433ff40c12SJohn Marino int i;
5443ff40c12SJohn Marino
5453ff40c12SJohn Marino hostapd_broadcast_wep_set(hapd);
5463ff40c12SJohn Marino
5473ff40c12SJohn Marino if (hapd->conf->ssid.wep.default_len) {
5483ff40c12SJohn Marino hostapd_set_privacy(hapd, 1);
5493ff40c12SJohn Marino return 0;
5503ff40c12SJohn Marino }
5513ff40c12SJohn Marino
5523ff40c12SJohn Marino /*
5533ff40c12SJohn Marino * When IEEE 802.1X is not enabled, the driver may need to know how to
5543ff40c12SJohn Marino * set authentication algorithms for static WEP.
5553ff40c12SJohn Marino */
5563ff40c12SJohn Marino hostapd_drv_set_authmode(hapd, hapd->conf->auth_algs);
5573ff40c12SJohn Marino
5583ff40c12SJohn Marino for (i = 0; i < 4; i++) {
5593ff40c12SJohn Marino if (hapd->conf->ssid.wep.key[i] &&
5603ff40c12SJohn Marino hostapd_drv_set_key(iface, hapd, WPA_ALG_WEP, NULL, i,
5613ff40c12SJohn Marino i == hapd->conf->ssid.wep.idx, NULL, 0,
5623ff40c12SJohn Marino hapd->conf->ssid.wep.key[i],
5633ff40c12SJohn Marino hapd->conf->ssid.wep.len[i])) {
5643ff40c12SJohn Marino wpa_printf(MSG_WARNING, "Could not set WEP "
5653ff40c12SJohn Marino "encryption.");
5663ff40c12SJohn Marino return -1;
5673ff40c12SJohn Marino }
5683ff40c12SJohn Marino if (hapd->conf->ssid.wep.key[i] &&
5693ff40c12SJohn Marino i == hapd->conf->ssid.wep.idx)
5703ff40c12SJohn Marino hostapd_set_privacy(hapd, 1);
5713ff40c12SJohn Marino }
5723ff40c12SJohn Marino
5733ff40c12SJohn Marino return 0;
5743ff40c12SJohn Marino }
5753ff40c12SJohn Marino
5763ff40c12SJohn Marino
hostapd_flush_old_stations(struct hostapd_data * hapd,u16 reason)5773ff40c12SJohn Marino static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason)
5783ff40c12SJohn Marino {
5793ff40c12SJohn Marino int ret = 0;
5803ff40c12SJohn Marino u8 addr[ETH_ALEN];
5813ff40c12SJohn Marino
5823ff40c12SJohn Marino if (hostapd_drv_none(hapd) || hapd->drv_priv == NULL)
5833ff40c12SJohn Marino return 0;
5843ff40c12SJohn Marino
585*a1157835SDaniel Fojt if (!hapd->iface->driver_ap_teardown) {
586*a1157835SDaniel Fojt wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
587*a1157835SDaniel Fojt "Flushing old station entries");
588*a1157835SDaniel Fojt
5893ff40c12SJohn Marino if (hostapd_flush(hapd)) {
590*a1157835SDaniel Fojt wpa_msg(hapd->msg_ctx, MSG_WARNING,
591*a1157835SDaniel Fojt "Could not connect to kernel driver");
5923ff40c12SJohn Marino ret = -1;
5933ff40c12SJohn Marino }
594*a1157835SDaniel Fojt }
595*a1157835SDaniel Fojt if (hapd->conf && hapd->conf->broadcast_deauth) {
596*a1157835SDaniel Fojt wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
597*a1157835SDaniel Fojt "Deauthenticate all stations");
5983ff40c12SJohn Marino os_memset(addr, 0xff, ETH_ALEN);
5993ff40c12SJohn Marino hostapd_drv_sta_deauth(hapd, addr, reason);
600*a1157835SDaniel Fojt }
6013ff40c12SJohn Marino hostapd_free_stas(hapd);
6023ff40c12SJohn Marino
6033ff40c12SJohn Marino return ret;
6043ff40c12SJohn Marino }
6053ff40c12SJohn Marino
6063ff40c12SJohn Marino
hostapd_bss_deinit_no_free(struct hostapd_data * hapd)607*a1157835SDaniel Fojt static void hostapd_bss_deinit_no_free(struct hostapd_data *hapd)
608*a1157835SDaniel Fojt {
609*a1157835SDaniel Fojt hostapd_free_stas(hapd);
610*a1157835SDaniel Fojt hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
611*a1157835SDaniel Fojt hostapd_clear_wep(hapd);
612*a1157835SDaniel Fojt }
613*a1157835SDaniel Fojt
614*a1157835SDaniel Fojt
6153ff40c12SJohn Marino /**
6163ff40c12SJohn Marino * hostapd_validate_bssid_configuration - Validate BSSID configuration
6173ff40c12SJohn Marino * @iface: Pointer to interface data
6183ff40c12SJohn Marino * Returns: 0 on success, -1 on failure
6193ff40c12SJohn Marino *
6203ff40c12SJohn Marino * This function is used to validate that the configured BSSIDs are valid.
6213ff40c12SJohn Marino */
hostapd_validate_bssid_configuration(struct hostapd_iface * iface)6223ff40c12SJohn Marino static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface)
6233ff40c12SJohn Marino {
6243ff40c12SJohn Marino u8 mask[ETH_ALEN] = { 0 };
6253ff40c12SJohn Marino struct hostapd_data *hapd = iface->bss[0];
6263ff40c12SJohn Marino unsigned int i = iface->conf->num_bss, bits = 0, j;
6273ff40c12SJohn Marino int auto_addr = 0;
6283ff40c12SJohn Marino
6293ff40c12SJohn Marino if (hostapd_drv_none(hapd))
6303ff40c12SJohn Marino return 0;
6313ff40c12SJohn Marino
632*a1157835SDaniel Fojt if (iface->conf->use_driver_iface_addr)
633*a1157835SDaniel Fojt return 0;
634*a1157835SDaniel Fojt
6353ff40c12SJohn Marino /* Generate BSSID mask that is large enough to cover the BSSIDs. */
6363ff40c12SJohn Marino
6373ff40c12SJohn Marino /* Determine the bits necessary to cover the number of BSSIDs. */
6383ff40c12SJohn Marino for (i--; i; i >>= 1)
6393ff40c12SJohn Marino bits++;
6403ff40c12SJohn Marino
6413ff40c12SJohn Marino /* Determine the bits necessary to any configured BSSIDs,
6423ff40c12SJohn Marino if they are higher than the number of BSSIDs. */
6433ff40c12SJohn Marino for (j = 0; j < iface->conf->num_bss; j++) {
644*a1157835SDaniel Fojt if (is_zero_ether_addr(iface->conf->bss[j]->bssid)) {
6453ff40c12SJohn Marino if (j)
6463ff40c12SJohn Marino auto_addr++;
6473ff40c12SJohn Marino continue;
6483ff40c12SJohn Marino }
6493ff40c12SJohn Marino
6503ff40c12SJohn Marino for (i = 0; i < ETH_ALEN; i++) {
6513ff40c12SJohn Marino mask[i] |=
6523ff40c12SJohn Marino iface->conf->bss[j]->bssid[i] ^
6533ff40c12SJohn Marino hapd->own_addr[i];
6543ff40c12SJohn Marino }
6553ff40c12SJohn Marino }
6563ff40c12SJohn Marino
6573ff40c12SJohn Marino if (!auto_addr)
6583ff40c12SJohn Marino goto skip_mask_ext;
6593ff40c12SJohn Marino
6603ff40c12SJohn Marino for (i = 0; i < ETH_ALEN && mask[i] == 0; i++)
6613ff40c12SJohn Marino ;
6623ff40c12SJohn Marino j = 0;
6633ff40c12SJohn Marino if (i < ETH_ALEN) {
6643ff40c12SJohn Marino j = (5 - i) * 8;
6653ff40c12SJohn Marino
6663ff40c12SJohn Marino while (mask[i] != 0) {
6673ff40c12SJohn Marino mask[i] >>= 1;
6683ff40c12SJohn Marino j++;
6693ff40c12SJohn Marino }
6703ff40c12SJohn Marino }
6713ff40c12SJohn Marino
6723ff40c12SJohn Marino if (bits < j)
6733ff40c12SJohn Marino bits = j;
6743ff40c12SJohn Marino
6753ff40c12SJohn Marino if (bits > 40) {
6763ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Too many bits in the BSSID mask (%u)",
6773ff40c12SJohn Marino bits);
6783ff40c12SJohn Marino return -1;
6793ff40c12SJohn Marino }
6803ff40c12SJohn Marino
6813ff40c12SJohn Marino os_memset(mask, 0xff, ETH_ALEN);
6823ff40c12SJohn Marino j = bits / 8;
6833ff40c12SJohn Marino for (i = 5; i > 5 - j; i--)
6843ff40c12SJohn Marino mask[i] = 0;
6853ff40c12SJohn Marino j = bits % 8;
686*a1157835SDaniel Fojt while (j) {
687*a1157835SDaniel Fojt j--;
6883ff40c12SJohn Marino mask[i] <<= 1;
689*a1157835SDaniel Fojt }
6903ff40c12SJohn Marino
6913ff40c12SJohn Marino skip_mask_ext:
6923ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "BSS count %lu, BSSID mask " MACSTR " (%d bits)",
6933ff40c12SJohn Marino (unsigned long) iface->conf->num_bss, MAC2STR(mask), bits);
6943ff40c12SJohn Marino
6953ff40c12SJohn Marino if (!auto_addr)
6963ff40c12SJohn Marino return 0;
6973ff40c12SJohn Marino
6983ff40c12SJohn Marino for (i = 0; i < ETH_ALEN; i++) {
6993ff40c12SJohn Marino if ((hapd->own_addr[i] & mask[i]) != hapd->own_addr[i]) {
7003ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Invalid BSSID mask " MACSTR
7013ff40c12SJohn Marino " for start address " MACSTR ".",
7023ff40c12SJohn Marino MAC2STR(mask), MAC2STR(hapd->own_addr));
7033ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Start address must be the "
7043ff40c12SJohn Marino "first address in the block (i.e., addr "
7053ff40c12SJohn Marino "AND mask == addr).");
7063ff40c12SJohn Marino return -1;
7073ff40c12SJohn Marino }
7083ff40c12SJohn Marino }
7093ff40c12SJohn Marino
7103ff40c12SJohn Marino return 0;
7113ff40c12SJohn Marino }
7123ff40c12SJohn Marino
7133ff40c12SJohn Marino
mac_in_conf(struct hostapd_config * conf,const void * a)7143ff40c12SJohn Marino static int mac_in_conf(struct hostapd_config *conf, const void *a)
7153ff40c12SJohn Marino {
7163ff40c12SJohn Marino size_t i;
7173ff40c12SJohn Marino
7183ff40c12SJohn Marino for (i = 0; i < conf->num_bss; i++) {
7193ff40c12SJohn Marino if (hostapd_mac_comp(conf->bss[i]->bssid, a) == 0) {
7203ff40c12SJohn Marino return 1;
7213ff40c12SJohn Marino }
7223ff40c12SJohn Marino }
7233ff40c12SJohn Marino
7243ff40c12SJohn Marino return 0;
7253ff40c12SJohn Marino }
7263ff40c12SJohn Marino
7273ff40c12SJohn Marino
7283ff40c12SJohn Marino #ifndef CONFIG_NO_RADIUS
7293ff40c12SJohn Marino
hostapd_das_nas_mismatch(struct hostapd_data * hapd,struct radius_das_attrs * attr)7303ff40c12SJohn Marino static int hostapd_das_nas_mismatch(struct hostapd_data *hapd,
7313ff40c12SJohn Marino struct radius_das_attrs *attr)
7323ff40c12SJohn Marino {
733*a1157835SDaniel Fojt if (attr->nas_identifier &&
734*a1157835SDaniel Fojt (!hapd->conf->nas_identifier ||
735*a1157835SDaniel Fojt os_strlen(hapd->conf->nas_identifier) !=
736*a1157835SDaniel Fojt attr->nas_identifier_len ||
737*a1157835SDaniel Fojt os_memcmp(hapd->conf->nas_identifier, attr->nas_identifier,
738*a1157835SDaniel Fojt attr->nas_identifier_len) != 0)) {
739*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "RADIUS DAS: NAS-Identifier mismatch");
740*a1157835SDaniel Fojt return 1;
741*a1157835SDaniel Fojt }
742*a1157835SDaniel Fojt
743*a1157835SDaniel Fojt if (attr->nas_ip_addr &&
744*a1157835SDaniel Fojt (hapd->conf->own_ip_addr.af != AF_INET ||
745*a1157835SDaniel Fojt os_memcmp(&hapd->conf->own_ip_addr.u.v4, attr->nas_ip_addr, 4) !=
746*a1157835SDaniel Fojt 0)) {
747*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "RADIUS DAS: NAS-IP-Address mismatch");
748*a1157835SDaniel Fojt return 1;
749*a1157835SDaniel Fojt }
750*a1157835SDaniel Fojt
751*a1157835SDaniel Fojt #ifdef CONFIG_IPV6
752*a1157835SDaniel Fojt if (attr->nas_ipv6_addr &&
753*a1157835SDaniel Fojt (hapd->conf->own_ip_addr.af != AF_INET6 ||
754*a1157835SDaniel Fojt os_memcmp(&hapd->conf->own_ip_addr.u.v6, attr->nas_ipv6_addr, 16)
755*a1157835SDaniel Fojt != 0)) {
756*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "RADIUS DAS: NAS-IPv6-Address mismatch");
757*a1157835SDaniel Fojt return 1;
758*a1157835SDaniel Fojt }
759*a1157835SDaniel Fojt #endif /* CONFIG_IPV6 */
760*a1157835SDaniel Fojt
7613ff40c12SJohn Marino return 0;
7623ff40c12SJohn Marino }
7633ff40c12SJohn Marino
7643ff40c12SJohn Marino
hostapd_das_find_sta(struct hostapd_data * hapd,struct radius_das_attrs * attr,int * multi)7653ff40c12SJohn Marino static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,
766*a1157835SDaniel Fojt struct radius_das_attrs *attr,
767*a1157835SDaniel Fojt int *multi)
7683ff40c12SJohn Marino {
769*a1157835SDaniel Fojt struct sta_info *selected, *sta;
7703ff40c12SJohn Marino char buf[128];
771*a1157835SDaniel Fojt int num_attr = 0;
772*a1157835SDaniel Fojt int count;
7733ff40c12SJohn Marino
774*a1157835SDaniel Fojt *multi = 0;
775*a1157835SDaniel Fojt
776*a1157835SDaniel Fojt for (sta = hapd->sta_list; sta; sta = sta->next)
777*a1157835SDaniel Fojt sta->radius_das_match = 1;
778*a1157835SDaniel Fojt
779*a1157835SDaniel Fojt if (attr->sta_addr) {
780*a1157835SDaniel Fojt num_attr++;
7813ff40c12SJohn Marino sta = ap_get_sta(hapd, attr->sta_addr);
782*a1157835SDaniel Fojt if (!sta) {
783*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
784*a1157835SDaniel Fojt "RADIUS DAS: No Calling-Station-Id match");
785*a1157835SDaniel Fojt return NULL;
786*a1157835SDaniel Fojt }
7873ff40c12SJohn Marino
788*a1157835SDaniel Fojt selected = sta;
7893ff40c12SJohn Marino for (sta = hapd->sta_list; sta; sta = sta->next) {
790*a1157835SDaniel Fojt if (sta != selected)
791*a1157835SDaniel Fojt sta->radius_das_match = 0;
7923ff40c12SJohn Marino }
793*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "RADIUS DAS: Calling-Station-Id match");
7943ff40c12SJohn Marino }
7953ff40c12SJohn Marino
796*a1157835SDaniel Fojt if (attr->acct_session_id) {
797*a1157835SDaniel Fojt num_attr++;
798*a1157835SDaniel Fojt if (attr->acct_session_id_len != 16) {
799*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
800*a1157835SDaniel Fojt "RADIUS DAS: Acct-Session-Id cannot match");
801*a1157835SDaniel Fojt return NULL;
802*a1157835SDaniel Fojt }
803*a1157835SDaniel Fojt count = 0;
804*a1157835SDaniel Fojt
805*a1157835SDaniel Fojt for (sta = hapd->sta_list; sta; sta = sta->next) {
806*a1157835SDaniel Fojt if (!sta->radius_das_match)
807*a1157835SDaniel Fojt continue;
808*a1157835SDaniel Fojt os_snprintf(buf, sizeof(buf), "%016llX",
809*a1157835SDaniel Fojt (unsigned long long) sta->acct_session_id);
810*a1157835SDaniel Fojt if (os_memcmp(attr->acct_session_id, buf, 16) != 0)
811*a1157835SDaniel Fojt sta->radius_das_match = 0;
812*a1157835SDaniel Fojt else
813*a1157835SDaniel Fojt count++;
814*a1157835SDaniel Fojt }
815*a1157835SDaniel Fojt
816*a1157835SDaniel Fojt if (count == 0) {
817*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
818*a1157835SDaniel Fojt "RADIUS DAS: No matches remaining after Acct-Session-Id check");
819*a1157835SDaniel Fojt return NULL;
820*a1157835SDaniel Fojt }
821*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "RADIUS DAS: Acct-Session-Id match");
822*a1157835SDaniel Fojt }
823*a1157835SDaniel Fojt
824*a1157835SDaniel Fojt if (attr->acct_multi_session_id) {
825*a1157835SDaniel Fojt num_attr++;
826*a1157835SDaniel Fojt if (attr->acct_multi_session_id_len != 16) {
827*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
828*a1157835SDaniel Fojt "RADIUS DAS: Acct-Multi-Session-Id cannot match");
829*a1157835SDaniel Fojt return NULL;
830*a1157835SDaniel Fojt }
831*a1157835SDaniel Fojt count = 0;
832*a1157835SDaniel Fojt
833*a1157835SDaniel Fojt for (sta = hapd->sta_list; sta; sta = sta->next) {
834*a1157835SDaniel Fojt if (!sta->radius_das_match)
835*a1157835SDaniel Fojt continue;
836*a1157835SDaniel Fojt if (!sta->eapol_sm ||
837*a1157835SDaniel Fojt !sta->eapol_sm->acct_multi_session_id) {
838*a1157835SDaniel Fojt sta->radius_das_match = 0;
839*a1157835SDaniel Fojt continue;
840*a1157835SDaniel Fojt }
841*a1157835SDaniel Fojt os_snprintf(buf, sizeof(buf), "%016llX",
842*a1157835SDaniel Fojt (unsigned long long)
843*a1157835SDaniel Fojt sta->eapol_sm->acct_multi_session_id);
844*a1157835SDaniel Fojt if (os_memcmp(attr->acct_multi_session_id, buf, 16) !=
845*a1157835SDaniel Fojt 0)
846*a1157835SDaniel Fojt sta->radius_das_match = 0;
847*a1157835SDaniel Fojt else
848*a1157835SDaniel Fojt count++;
849*a1157835SDaniel Fojt }
850*a1157835SDaniel Fojt
851*a1157835SDaniel Fojt if (count == 0) {
852*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
853*a1157835SDaniel Fojt "RADIUS DAS: No matches remaining after Acct-Multi-Session-Id check");
854*a1157835SDaniel Fojt return NULL;
855*a1157835SDaniel Fojt }
856*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
857*a1157835SDaniel Fojt "RADIUS DAS: Acct-Multi-Session-Id match");
858*a1157835SDaniel Fojt }
859*a1157835SDaniel Fojt
860*a1157835SDaniel Fojt if (attr->cui) {
861*a1157835SDaniel Fojt num_attr++;
862*a1157835SDaniel Fojt count = 0;
863*a1157835SDaniel Fojt
8643ff40c12SJohn Marino for (sta = hapd->sta_list; sta; sta = sta->next) {
8653ff40c12SJohn Marino struct wpabuf *cui;
866*a1157835SDaniel Fojt
867*a1157835SDaniel Fojt if (!sta->radius_das_match)
868*a1157835SDaniel Fojt continue;
8693ff40c12SJohn Marino cui = ieee802_1x_get_radius_cui(sta->eapol_sm);
870*a1157835SDaniel Fojt if (!cui || wpabuf_len(cui) != attr->cui_len ||
8713ff40c12SJohn Marino os_memcmp(wpabuf_head(cui), attr->cui,
872*a1157835SDaniel Fojt attr->cui_len) != 0)
873*a1157835SDaniel Fojt sta->radius_das_match = 0;
874*a1157835SDaniel Fojt else
875*a1157835SDaniel Fojt count++;
8763ff40c12SJohn Marino }
8773ff40c12SJohn Marino
878*a1157835SDaniel Fojt if (count == 0) {
879*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
880*a1157835SDaniel Fojt "RADIUS DAS: No matches remaining after Chargeable-User-Identity check");
881*a1157835SDaniel Fojt return NULL;
882*a1157835SDaniel Fojt }
883*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
884*a1157835SDaniel Fojt "RADIUS DAS: Chargeable-User-Identity match");
885*a1157835SDaniel Fojt }
886*a1157835SDaniel Fojt
887*a1157835SDaniel Fojt if (attr->user_name) {
888*a1157835SDaniel Fojt num_attr++;
889*a1157835SDaniel Fojt count = 0;
890*a1157835SDaniel Fojt
8913ff40c12SJohn Marino for (sta = hapd->sta_list; sta; sta = sta->next) {
8923ff40c12SJohn Marino u8 *identity;
8933ff40c12SJohn Marino size_t identity_len;
894*a1157835SDaniel Fojt
895*a1157835SDaniel Fojt if (!sta->radius_das_match)
896*a1157835SDaniel Fojt continue;
8973ff40c12SJohn Marino identity = ieee802_1x_get_identity(sta->eapol_sm,
8983ff40c12SJohn Marino &identity_len);
899*a1157835SDaniel Fojt if (!identity ||
900*a1157835SDaniel Fojt identity_len != attr->user_name_len ||
9013ff40c12SJohn Marino os_memcmp(identity, attr->user_name, identity_len)
902*a1157835SDaniel Fojt != 0)
903*a1157835SDaniel Fojt sta->radius_das_match = 0;
904*a1157835SDaniel Fojt else
905*a1157835SDaniel Fojt count++;
906*a1157835SDaniel Fojt }
907*a1157835SDaniel Fojt
908*a1157835SDaniel Fojt if (count == 0) {
909*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
910*a1157835SDaniel Fojt "RADIUS DAS: No matches remaining after User-Name check");
911*a1157835SDaniel Fojt return NULL;
912*a1157835SDaniel Fojt }
913*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
914*a1157835SDaniel Fojt "RADIUS DAS: User-Name match");
915*a1157835SDaniel Fojt }
916*a1157835SDaniel Fojt
917*a1157835SDaniel Fojt if (num_attr == 0) {
918*a1157835SDaniel Fojt /*
919*a1157835SDaniel Fojt * In theory, we could match all current associations, but it
920*a1157835SDaniel Fojt * seems safer to just reject requests that do not include any
921*a1157835SDaniel Fojt * session identification attributes.
922*a1157835SDaniel Fojt */
923*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
924*a1157835SDaniel Fojt "RADIUS DAS: No session identification attributes included");
925*a1157835SDaniel Fojt return NULL;
926*a1157835SDaniel Fojt }
927*a1157835SDaniel Fojt
928*a1157835SDaniel Fojt selected = NULL;
929*a1157835SDaniel Fojt for (sta = hapd->sta_list; sta; sta = sta->next) {
930*a1157835SDaniel Fojt if (sta->radius_das_match) {
931*a1157835SDaniel Fojt if (selected) {
932*a1157835SDaniel Fojt *multi = 1;
933*a1157835SDaniel Fojt return NULL;
934*a1157835SDaniel Fojt }
935*a1157835SDaniel Fojt selected = sta;
9363ff40c12SJohn Marino }
9373ff40c12SJohn Marino }
9383ff40c12SJohn Marino
939*a1157835SDaniel Fojt return selected;
940*a1157835SDaniel Fojt }
941*a1157835SDaniel Fojt
942*a1157835SDaniel Fojt
hostapd_das_disconnect_pmksa(struct hostapd_data * hapd,struct radius_das_attrs * attr)943*a1157835SDaniel Fojt static int hostapd_das_disconnect_pmksa(struct hostapd_data *hapd,
944*a1157835SDaniel Fojt struct radius_das_attrs *attr)
945*a1157835SDaniel Fojt {
946*a1157835SDaniel Fojt if (!hapd->wpa_auth)
947*a1157835SDaniel Fojt return -1;
948*a1157835SDaniel Fojt return wpa_auth_radius_das_disconnect_pmksa(hapd->wpa_auth, attr);
9493ff40c12SJohn Marino }
9503ff40c12SJohn Marino
9513ff40c12SJohn Marino
9523ff40c12SJohn Marino static enum radius_das_res
hostapd_das_disconnect(void * ctx,struct radius_das_attrs * attr)9533ff40c12SJohn Marino hostapd_das_disconnect(void *ctx, struct radius_das_attrs *attr)
9543ff40c12SJohn Marino {
9553ff40c12SJohn Marino struct hostapd_data *hapd = ctx;
9563ff40c12SJohn Marino struct sta_info *sta;
957*a1157835SDaniel Fojt int multi;
9583ff40c12SJohn Marino
9593ff40c12SJohn Marino if (hostapd_das_nas_mismatch(hapd, attr))
9603ff40c12SJohn Marino return RADIUS_DAS_NAS_MISMATCH;
9613ff40c12SJohn Marino
962*a1157835SDaniel Fojt sta = hostapd_das_find_sta(hapd, attr, &multi);
963*a1157835SDaniel Fojt if (sta == NULL) {
964*a1157835SDaniel Fojt if (multi) {
965*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
966*a1157835SDaniel Fojt "RADIUS DAS: Multiple sessions match - not supported");
967*a1157835SDaniel Fojt return RADIUS_DAS_MULTI_SESSION_MATCH;
968*a1157835SDaniel Fojt }
969*a1157835SDaniel Fojt if (hostapd_das_disconnect_pmksa(hapd, attr) == 0) {
970*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
971*a1157835SDaniel Fojt "RADIUS DAS: PMKSA cache entry matched");
972*a1157835SDaniel Fojt return RADIUS_DAS_SUCCESS;
973*a1157835SDaniel Fojt }
974*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "RADIUS DAS: No matching session found");
9753ff40c12SJohn Marino return RADIUS_DAS_SESSION_NOT_FOUND;
976*a1157835SDaniel Fojt }
977*a1157835SDaniel Fojt
978*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "RADIUS DAS: Found a matching session " MACSTR
979*a1157835SDaniel Fojt " - disconnecting", MAC2STR(sta->addr));
980*a1157835SDaniel Fojt wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
9813ff40c12SJohn Marino
9823ff40c12SJohn Marino hostapd_drv_sta_deauth(hapd, sta->addr,
9833ff40c12SJohn Marino WLAN_REASON_PREV_AUTH_NOT_VALID);
9843ff40c12SJohn Marino ap_sta_deauthenticate(hapd, sta, WLAN_REASON_PREV_AUTH_NOT_VALID);
9853ff40c12SJohn Marino
9863ff40c12SJohn Marino return RADIUS_DAS_SUCCESS;
9873ff40c12SJohn Marino }
9883ff40c12SJohn Marino
989*a1157835SDaniel Fojt
990*a1157835SDaniel Fojt #ifdef CONFIG_HS20
991*a1157835SDaniel Fojt static enum radius_das_res
hostapd_das_coa(void * ctx,struct radius_das_attrs * attr)992*a1157835SDaniel Fojt hostapd_das_coa(void *ctx, struct radius_das_attrs *attr)
993*a1157835SDaniel Fojt {
994*a1157835SDaniel Fojt struct hostapd_data *hapd = ctx;
995*a1157835SDaniel Fojt struct sta_info *sta;
996*a1157835SDaniel Fojt int multi;
997*a1157835SDaniel Fojt
998*a1157835SDaniel Fojt if (hostapd_das_nas_mismatch(hapd, attr))
999*a1157835SDaniel Fojt return RADIUS_DAS_NAS_MISMATCH;
1000*a1157835SDaniel Fojt
1001*a1157835SDaniel Fojt sta = hostapd_das_find_sta(hapd, attr, &multi);
1002*a1157835SDaniel Fojt if (!sta) {
1003*a1157835SDaniel Fojt if (multi) {
1004*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
1005*a1157835SDaniel Fojt "RADIUS DAS: Multiple sessions match - not supported");
1006*a1157835SDaniel Fojt return RADIUS_DAS_MULTI_SESSION_MATCH;
1007*a1157835SDaniel Fojt }
1008*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "RADIUS DAS: No matching session found");
1009*a1157835SDaniel Fojt return RADIUS_DAS_SESSION_NOT_FOUND;
1010*a1157835SDaniel Fojt }
1011*a1157835SDaniel Fojt
1012*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "RADIUS DAS: Found a matching session " MACSTR
1013*a1157835SDaniel Fojt " - CoA", MAC2STR(sta->addr));
1014*a1157835SDaniel Fojt
1015*a1157835SDaniel Fojt if (attr->hs20_t_c_filtering) {
1016*a1157835SDaniel Fojt if (attr->hs20_t_c_filtering[0] & BIT(0)) {
1017*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
1018*a1157835SDaniel Fojt "HS 2.0: Unexpected Terms and Conditions filtering required in CoA-Request");
1019*a1157835SDaniel Fojt return RADIUS_DAS_COA_FAILED;
1020*a1157835SDaniel Fojt }
1021*a1157835SDaniel Fojt
1022*a1157835SDaniel Fojt hs20_t_c_filtering(hapd, sta, 0);
1023*a1157835SDaniel Fojt }
1024*a1157835SDaniel Fojt
1025*a1157835SDaniel Fojt return RADIUS_DAS_SUCCESS;
1026*a1157835SDaniel Fojt }
1027*a1157835SDaniel Fojt #else /* CONFIG_HS20 */
1028*a1157835SDaniel Fojt #define hostapd_das_coa NULL
1029*a1157835SDaniel Fojt #endif /* CONFIG_HS20 */
1030*a1157835SDaniel Fojt
1031*a1157835SDaniel Fojt
1032*a1157835SDaniel Fojt #ifdef CONFIG_SQLITE
1033*a1157835SDaniel Fojt
db_table_exists(sqlite3 * db,const char * name)1034*a1157835SDaniel Fojt static int db_table_exists(sqlite3 *db, const char *name)
1035*a1157835SDaniel Fojt {
1036*a1157835SDaniel Fojt char cmd[128];
1037*a1157835SDaniel Fojt
1038*a1157835SDaniel Fojt os_snprintf(cmd, sizeof(cmd), "SELECT 1 FROM %s;", name);
1039*a1157835SDaniel Fojt return sqlite3_exec(db, cmd, NULL, NULL, NULL) == SQLITE_OK;
1040*a1157835SDaniel Fojt }
1041*a1157835SDaniel Fojt
1042*a1157835SDaniel Fojt
db_table_create_radius_attributes(sqlite3 * db)1043*a1157835SDaniel Fojt static int db_table_create_radius_attributes(sqlite3 *db)
1044*a1157835SDaniel Fojt {
1045*a1157835SDaniel Fojt char *err = NULL;
1046*a1157835SDaniel Fojt const char *sql =
1047*a1157835SDaniel Fojt "CREATE TABLE radius_attributes("
1048*a1157835SDaniel Fojt " id INTEGER PRIMARY KEY,"
1049*a1157835SDaniel Fojt " sta TEXT,"
1050*a1157835SDaniel Fojt " reqtype TEXT,"
1051*a1157835SDaniel Fojt " attr TEXT"
1052*a1157835SDaniel Fojt ");"
1053*a1157835SDaniel Fojt "CREATE INDEX idx_sta_reqtype ON radius_attributes(sta,reqtype);";
1054*a1157835SDaniel Fojt
1055*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
1056*a1157835SDaniel Fojt "Adding database table for RADIUS attribute information");
1057*a1157835SDaniel Fojt if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
1058*a1157835SDaniel Fojt wpa_printf(MSG_ERROR, "SQLite error: %s", err);
1059*a1157835SDaniel Fojt sqlite3_free(err);
1060*a1157835SDaniel Fojt return -1;
1061*a1157835SDaniel Fojt }
1062*a1157835SDaniel Fojt
1063*a1157835SDaniel Fojt return 0;
1064*a1157835SDaniel Fojt }
1065*a1157835SDaniel Fojt
1066*a1157835SDaniel Fojt #endif /* CONFIG_SQLITE */
1067*a1157835SDaniel Fojt
10683ff40c12SJohn Marino #endif /* CONFIG_NO_RADIUS */
10693ff40c12SJohn Marino
10703ff40c12SJohn Marino
10713ff40c12SJohn Marino /**
10723ff40c12SJohn Marino * hostapd_setup_bss - Per-BSS setup (initialization)
10733ff40c12SJohn Marino * @hapd: Pointer to BSS data
10743ff40c12SJohn Marino * @first: Whether this BSS is the first BSS of an interface; -1 = not first,
10753ff40c12SJohn Marino * but interface may exist
10763ff40c12SJohn Marino *
10773ff40c12SJohn Marino * This function is used to initialize all per-BSS data structures and
10783ff40c12SJohn Marino * resources. This gets called in a loop for each BSS when an interface is
10793ff40c12SJohn Marino * initialized. Most of the modules that are initialized here will be
10803ff40c12SJohn Marino * deinitialized in hostapd_cleanup().
10813ff40c12SJohn Marino */
hostapd_setup_bss(struct hostapd_data * hapd,int first)10823ff40c12SJohn Marino static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
10833ff40c12SJohn Marino {
10843ff40c12SJohn Marino struct hostapd_bss_config *conf = hapd->conf;
1085*a1157835SDaniel Fojt u8 ssid[SSID_MAX_LEN + 1];
10863ff40c12SJohn Marino int ssid_len, set_ssid;
10873ff40c12SJohn Marino char force_ifname[IFNAMSIZ];
10883ff40c12SJohn Marino u8 if_addr[ETH_ALEN];
1089*a1157835SDaniel Fojt int flush_old_stations = 1;
10903ff40c12SJohn Marino
10913ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "%s(hapd=%p (%s), first=%d)",
1092*a1157835SDaniel Fojt __func__, hapd, conf->iface, first);
1093*a1157835SDaniel Fojt
1094*a1157835SDaniel Fojt #ifdef EAP_SERVER_TNC
1095*a1157835SDaniel Fojt if (conf->tnc && tncs_global_init() < 0) {
1096*a1157835SDaniel Fojt wpa_printf(MSG_ERROR, "Failed to initialize TNCS");
1097*a1157835SDaniel Fojt return -1;
1098*a1157835SDaniel Fojt }
1099*a1157835SDaniel Fojt #endif /* EAP_SERVER_TNC */
11003ff40c12SJohn Marino
11013ff40c12SJohn Marino if (hapd->started) {
11023ff40c12SJohn Marino wpa_printf(MSG_ERROR, "%s: Interface %s was already started",
1103*a1157835SDaniel Fojt __func__, conf->iface);
11043ff40c12SJohn Marino return -1;
11053ff40c12SJohn Marino }
11063ff40c12SJohn Marino hapd->started = 1;
11073ff40c12SJohn Marino
11083ff40c12SJohn Marino if (!first || first == -1) {
1109*a1157835SDaniel Fojt u8 *addr = hapd->own_addr;
1110*a1157835SDaniel Fojt
1111*a1157835SDaniel Fojt if (!is_zero_ether_addr(conf->bssid)) {
11123ff40c12SJohn Marino /* Allocate the configured BSSID. */
1113*a1157835SDaniel Fojt os_memcpy(hapd->own_addr, conf->bssid, ETH_ALEN);
11143ff40c12SJohn Marino
11153ff40c12SJohn Marino if (hostapd_mac_comp(hapd->own_addr,
11163ff40c12SJohn Marino hapd->iface->bss[0]->own_addr) ==
11173ff40c12SJohn Marino 0) {
11183ff40c12SJohn Marino wpa_printf(MSG_ERROR, "BSS '%s' may not have "
11193ff40c12SJohn Marino "BSSID set to the MAC address of "
1120*a1157835SDaniel Fojt "the radio", conf->iface);
11213ff40c12SJohn Marino return -1;
11223ff40c12SJohn Marino }
1123*a1157835SDaniel Fojt } else if (hapd->iconf->use_driver_iface_addr) {
1124*a1157835SDaniel Fojt addr = NULL;
1125*a1157835SDaniel Fojt } else {
1126*a1157835SDaniel Fojt /* Allocate the next available BSSID. */
1127*a1157835SDaniel Fojt do {
1128*a1157835SDaniel Fojt inc_byte_array(hapd->own_addr, ETH_ALEN);
1129*a1157835SDaniel Fojt } while (mac_in_conf(hapd->iconf, hapd->own_addr));
11303ff40c12SJohn Marino }
11313ff40c12SJohn Marino
11323ff40c12SJohn Marino hapd->interface_added = 1;
11333ff40c12SJohn Marino if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS,
1134*a1157835SDaniel Fojt conf->iface, addr, hapd,
11353ff40c12SJohn Marino &hapd->drv_priv, force_ifname, if_addr,
1136*a1157835SDaniel Fojt conf->bridge[0] ? conf->bridge : NULL,
1137*a1157835SDaniel Fojt first == -1)) {
11383ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID="
11393ff40c12SJohn Marino MACSTR ")", MAC2STR(hapd->own_addr));
11403ff40c12SJohn Marino hapd->interface_added = 0;
11413ff40c12SJohn Marino return -1;
11423ff40c12SJohn Marino }
1143*a1157835SDaniel Fojt
1144*a1157835SDaniel Fojt if (!addr)
1145*a1157835SDaniel Fojt os_memcpy(hapd->own_addr, if_addr, ETH_ALEN);
11463ff40c12SJohn Marino }
11473ff40c12SJohn Marino
11483ff40c12SJohn Marino if (conf->wmm_enabled < 0)
11493ff40c12SJohn Marino conf->wmm_enabled = hapd->iconf->ieee80211n;
11503ff40c12SJohn Marino
1151*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
1152*a1157835SDaniel Fojt if (is_zero_ether_addr(conf->r1_key_holder))
1153*a1157835SDaniel Fojt os_memcpy(conf->r1_key_holder, hapd->own_addr, ETH_ALEN);
1154*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
1155*a1157835SDaniel Fojt
1156*a1157835SDaniel Fojt #ifdef CONFIG_MESH
1157*a1157835SDaniel Fojt if ((hapd->conf->mesh & MESH_ENABLED) && hapd->iface->mconf == NULL)
1158*a1157835SDaniel Fojt flush_old_stations = 0;
1159*a1157835SDaniel Fojt #endif /* CONFIG_MESH */
1160*a1157835SDaniel Fojt
1161*a1157835SDaniel Fojt if (flush_old_stations)
1162*a1157835SDaniel Fojt hostapd_flush_old_stations(hapd,
1163*a1157835SDaniel Fojt WLAN_REASON_PREV_AUTH_NOT_VALID);
11643ff40c12SJohn Marino hostapd_set_privacy(hapd, 0);
11653ff40c12SJohn Marino
11663ff40c12SJohn Marino hostapd_broadcast_wep_clear(hapd);
1167*a1157835SDaniel Fojt if (hostapd_setup_encryption(conf->iface, hapd))
11683ff40c12SJohn Marino return -1;
11693ff40c12SJohn Marino
11703ff40c12SJohn Marino /*
11713ff40c12SJohn Marino * Fetch the SSID from the system and use it or,
11723ff40c12SJohn Marino * if one was specified in the config file, verify they
11733ff40c12SJohn Marino * match.
11743ff40c12SJohn Marino */
11753ff40c12SJohn Marino ssid_len = hostapd_get_ssid(hapd, ssid, sizeof(ssid));
11763ff40c12SJohn Marino if (ssid_len < 0) {
11773ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Could not read SSID from system");
11783ff40c12SJohn Marino return -1;
11793ff40c12SJohn Marino }
11803ff40c12SJohn Marino if (conf->ssid.ssid_set) {
11813ff40c12SJohn Marino /*
11823ff40c12SJohn Marino * If SSID is specified in the config file and it differs
11833ff40c12SJohn Marino * from what is being used then force installation of the
11843ff40c12SJohn Marino * new SSID.
11853ff40c12SJohn Marino */
11863ff40c12SJohn Marino set_ssid = (conf->ssid.ssid_len != (size_t) ssid_len ||
11873ff40c12SJohn Marino os_memcmp(conf->ssid.ssid, ssid, ssid_len) != 0);
11883ff40c12SJohn Marino } else {
11893ff40c12SJohn Marino /*
11903ff40c12SJohn Marino * No SSID in the config file; just use the one we got
11913ff40c12SJohn Marino * from the system.
11923ff40c12SJohn Marino */
11933ff40c12SJohn Marino set_ssid = 0;
11943ff40c12SJohn Marino conf->ssid.ssid_len = ssid_len;
11953ff40c12SJohn Marino os_memcpy(conf->ssid.ssid, ssid, conf->ssid.ssid_len);
11963ff40c12SJohn Marino }
11973ff40c12SJohn Marino
11983ff40c12SJohn Marino if (!hostapd_drv_none(hapd)) {
11993ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Using interface %s with hwaddr " MACSTR
12003ff40c12SJohn Marino " and ssid \"%s\"",
1201*a1157835SDaniel Fojt conf->iface, MAC2STR(hapd->own_addr),
1202*a1157835SDaniel Fojt wpa_ssid_txt(conf->ssid.ssid, conf->ssid.ssid_len));
12033ff40c12SJohn Marino }
12043ff40c12SJohn Marino
12053ff40c12SJohn Marino if (hostapd_setup_wpa_psk(conf)) {
12063ff40c12SJohn Marino wpa_printf(MSG_ERROR, "WPA-PSK setup failed.");
12073ff40c12SJohn Marino return -1;
12083ff40c12SJohn Marino }
12093ff40c12SJohn Marino
12103ff40c12SJohn Marino /* Set SSID for the kernel driver (to be used in beacon and probe
12113ff40c12SJohn Marino * response frames) */
12123ff40c12SJohn Marino if (set_ssid && hostapd_set_ssid(hapd, conf->ssid.ssid,
12133ff40c12SJohn Marino conf->ssid.ssid_len)) {
12143ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver");
12153ff40c12SJohn Marino return -1;
12163ff40c12SJohn Marino }
12173ff40c12SJohn Marino
1218*a1157835SDaniel Fojt if (wpa_debug_level <= MSG_MSGDUMP)
12193ff40c12SJohn Marino conf->radius->msg_dumps = 1;
12203ff40c12SJohn Marino #ifndef CONFIG_NO_RADIUS
1221*a1157835SDaniel Fojt
1222*a1157835SDaniel Fojt #ifdef CONFIG_SQLITE
1223*a1157835SDaniel Fojt if (conf->radius_req_attr_sqlite) {
1224*a1157835SDaniel Fojt if (sqlite3_open(conf->radius_req_attr_sqlite,
1225*a1157835SDaniel Fojt &hapd->rad_attr_db)) {
1226*a1157835SDaniel Fojt wpa_printf(MSG_ERROR, "Could not open SQLite file '%s'",
1227*a1157835SDaniel Fojt conf->radius_req_attr_sqlite);
1228*a1157835SDaniel Fojt return -1;
1229*a1157835SDaniel Fojt }
1230*a1157835SDaniel Fojt
1231*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "Opening RADIUS attribute database: %s",
1232*a1157835SDaniel Fojt conf->radius_req_attr_sqlite);
1233*a1157835SDaniel Fojt if (!db_table_exists(hapd->rad_attr_db, "radius_attributes") &&
1234*a1157835SDaniel Fojt db_table_create_radius_attributes(hapd->rad_attr_db) < 0)
1235*a1157835SDaniel Fojt return -1;
1236*a1157835SDaniel Fojt }
1237*a1157835SDaniel Fojt #endif /* CONFIG_SQLITE */
1238*a1157835SDaniel Fojt
12393ff40c12SJohn Marino hapd->radius = radius_client_init(hapd, conf->radius);
12403ff40c12SJohn Marino if (hapd->radius == NULL) {
12413ff40c12SJohn Marino wpa_printf(MSG_ERROR, "RADIUS client initialization failed.");
12423ff40c12SJohn Marino return -1;
12433ff40c12SJohn Marino }
12443ff40c12SJohn Marino
1245*a1157835SDaniel Fojt if (conf->radius_das_port) {
12463ff40c12SJohn Marino struct radius_das_conf das_conf;
12473ff40c12SJohn Marino os_memset(&das_conf, 0, sizeof(das_conf));
1248*a1157835SDaniel Fojt das_conf.port = conf->radius_das_port;
1249*a1157835SDaniel Fojt das_conf.shared_secret = conf->radius_das_shared_secret;
12503ff40c12SJohn Marino das_conf.shared_secret_len =
1251*a1157835SDaniel Fojt conf->radius_das_shared_secret_len;
1252*a1157835SDaniel Fojt das_conf.client_addr = &conf->radius_das_client_addr;
1253*a1157835SDaniel Fojt das_conf.time_window = conf->radius_das_time_window;
12543ff40c12SJohn Marino das_conf.require_event_timestamp =
1255*a1157835SDaniel Fojt conf->radius_das_require_event_timestamp;
1256*a1157835SDaniel Fojt das_conf.require_message_authenticator =
1257*a1157835SDaniel Fojt conf->radius_das_require_message_authenticator;
12583ff40c12SJohn Marino das_conf.ctx = hapd;
12593ff40c12SJohn Marino das_conf.disconnect = hostapd_das_disconnect;
1260*a1157835SDaniel Fojt das_conf.coa = hostapd_das_coa;
12613ff40c12SJohn Marino hapd->radius_das = radius_das_init(&das_conf);
12623ff40c12SJohn Marino if (hapd->radius_das == NULL) {
12633ff40c12SJohn Marino wpa_printf(MSG_ERROR, "RADIUS DAS initialization "
12643ff40c12SJohn Marino "failed.");
12653ff40c12SJohn Marino return -1;
12663ff40c12SJohn Marino }
12673ff40c12SJohn Marino }
12683ff40c12SJohn Marino #endif /* CONFIG_NO_RADIUS */
12693ff40c12SJohn Marino
12703ff40c12SJohn Marino if (hostapd_acl_init(hapd)) {
12713ff40c12SJohn Marino wpa_printf(MSG_ERROR, "ACL initialization failed.");
12723ff40c12SJohn Marino return -1;
12733ff40c12SJohn Marino }
12743ff40c12SJohn Marino if (hostapd_init_wps(hapd, conf))
12753ff40c12SJohn Marino return -1;
12763ff40c12SJohn Marino
1277*a1157835SDaniel Fojt #ifdef CONFIG_DPP
1278*a1157835SDaniel Fojt hapd->gas = gas_query_ap_init(hapd, hapd->msg_ctx);
1279*a1157835SDaniel Fojt if (!hapd->gas)
1280*a1157835SDaniel Fojt return -1;
1281*a1157835SDaniel Fojt if (hostapd_dpp_init(hapd))
1282*a1157835SDaniel Fojt return -1;
1283*a1157835SDaniel Fojt #endif /* CONFIG_DPP */
1284*a1157835SDaniel Fojt
12853ff40c12SJohn Marino if (authsrv_init(hapd) < 0)
12863ff40c12SJohn Marino return -1;
12873ff40c12SJohn Marino
12883ff40c12SJohn Marino if (ieee802_1x_init(hapd)) {
12893ff40c12SJohn Marino wpa_printf(MSG_ERROR, "IEEE 802.1X initialization failed.");
12903ff40c12SJohn Marino return -1;
12913ff40c12SJohn Marino }
12923ff40c12SJohn Marino
1293*a1157835SDaniel Fojt if ((conf->wpa || conf->osen) && hostapd_setup_wpa(hapd))
12943ff40c12SJohn Marino return -1;
12953ff40c12SJohn Marino
12963ff40c12SJohn Marino if (accounting_init(hapd)) {
12973ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Accounting initialization failed.");
12983ff40c12SJohn Marino return -1;
12993ff40c12SJohn Marino }
13003ff40c12SJohn Marino
1301*a1157835SDaniel Fojt if (conf->ieee802_11f &&
1302*a1157835SDaniel Fojt (hapd->iapp = iapp_init(hapd, conf->iapp_iface)) == NULL) {
13033ff40c12SJohn Marino wpa_printf(MSG_ERROR, "IEEE 802.11F (IAPP) initialization "
13043ff40c12SJohn Marino "failed.");
13053ff40c12SJohn Marino return -1;
13063ff40c12SJohn Marino }
13073ff40c12SJohn Marino
13083ff40c12SJohn Marino #ifdef CONFIG_INTERWORKING
13093ff40c12SJohn Marino if (gas_serv_init(hapd)) {
13103ff40c12SJohn Marino wpa_printf(MSG_ERROR, "GAS server initialization failed");
13113ff40c12SJohn Marino return -1;
13123ff40c12SJohn Marino }
13133ff40c12SJohn Marino
13143ff40c12SJohn Marino if (conf->qos_map_set_len &&
13153ff40c12SJohn Marino hostapd_drv_set_qos_map(hapd, conf->qos_map_set,
13163ff40c12SJohn Marino conf->qos_map_set_len)) {
13173ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Failed to initialize QoS Map");
13183ff40c12SJohn Marino return -1;
13193ff40c12SJohn Marino }
13203ff40c12SJohn Marino #endif /* CONFIG_INTERWORKING */
13213ff40c12SJohn Marino
1322*a1157835SDaniel Fojt if (conf->bss_load_update_period && bss_load_update_init(hapd)) {
1323*a1157835SDaniel Fojt wpa_printf(MSG_ERROR, "BSS Load initialization failed");
1324*a1157835SDaniel Fojt return -1;
1325*a1157835SDaniel Fojt }
1326*a1157835SDaniel Fojt
1327*a1157835SDaniel Fojt if (conf->proxy_arp) {
1328*a1157835SDaniel Fojt if (x_snoop_init(hapd)) {
1329*a1157835SDaniel Fojt wpa_printf(MSG_ERROR,
1330*a1157835SDaniel Fojt "Generic snooping infrastructure initialization failed");
1331*a1157835SDaniel Fojt return -1;
1332*a1157835SDaniel Fojt }
1333*a1157835SDaniel Fojt
1334*a1157835SDaniel Fojt if (dhcp_snoop_init(hapd)) {
1335*a1157835SDaniel Fojt wpa_printf(MSG_ERROR,
1336*a1157835SDaniel Fojt "DHCP snooping initialization failed");
1337*a1157835SDaniel Fojt return -1;
1338*a1157835SDaniel Fojt }
1339*a1157835SDaniel Fojt
1340*a1157835SDaniel Fojt if (ndisc_snoop_init(hapd)) {
1341*a1157835SDaniel Fojt wpa_printf(MSG_ERROR,
1342*a1157835SDaniel Fojt "Neighbor Discovery snooping initialization failed");
1343*a1157835SDaniel Fojt return -1;
1344*a1157835SDaniel Fojt }
1345*a1157835SDaniel Fojt }
1346*a1157835SDaniel Fojt
13473ff40c12SJohn Marino if (!hostapd_drv_none(hapd) && vlan_init(hapd)) {
13483ff40c12SJohn Marino wpa_printf(MSG_ERROR, "VLAN initialization failed.");
13493ff40c12SJohn Marino return -1;
13503ff40c12SJohn Marino }
13513ff40c12SJohn Marino
1352*a1157835SDaniel Fojt if (!conf->start_disabled && ieee802_11_set_beacon(hapd) < 0)
13533ff40c12SJohn Marino return -1;
13543ff40c12SJohn Marino
13553ff40c12SJohn Marino if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0)
13563ff40c12SJohn Marino return -1;
13573ff40c12SJohn Marino
13583ff40c12SJohn Marino if (hapd->driver && hapd->driver->set_operstate)
13593ff40c12SJohn Marino hapd->driver->set_operstate(hapd->drv_priv, 1);
13603ff40c12SJohn Marino
13613ff40c12SJohn Marino return 0;
13623ff40c12SJohn Marino }
13633ff40c12SJohn Marino
13643ff40c12SJohn Marino
hostapd_tx_queue_params(struct hostapd_iface * iface)13653ff40c12SJohn Marino static void hostapd_tx_queue_params(struct hostapd_iface *iface)
13663ff40c12SJohn Marino {
13673ff40c12SJohn Marino struct hostapd_data *hapd = iface->bss[0];
13683ff40c12SJohn Marino int i;
13693ff40c12SJohn Marino struct hostapd_tx_queue_params *p;
13703ff40c12SJohn Marino
1371*a1157835SDaniel Fojt #ifdef CONFIG_MESH
1372*a1157835SDaniel Fojt if ((hapd->conf->mesh & MESH_ENABLED) && iface->mconf == NULL)
1373*a1157835SDaniel Fojt return;
1374*a1157835SDaniel Fojt #endif /* CONFIG_MESH */
1375*a1157835SDaniel Fojt
13763ff40c12SJohn Marino for (i = 0; i < NUM_TX_QUEUES; i++) {
13773ff40c12SJohn Marino p = &iface->conf->tx_queue[i];
13783ff40c12SJohn Marino
13793ff40c12SJohn Marino if (hostapd_set_tx_queue_params(hapd, i, p->aifs, p->cwmin,
13803ff40c12SJohn Marino p->cwmax, p->burst)) {
13813ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Failed to set TX queue "
13823ff40c12SJohn Marino "parameters for queue %d.", i);
13833ff40c12SJohn Marino /* Continue anyway */
13843ff40c12SJohn Marino }
13853ff40c12SJohn Marino }
13863ff40c12SJohn Marino }
13873ff40c12SJohn Marino
13883ff40c12SJohn Marino
hostapd_set_acl_list(struct hostapd_data * hapd,struct mac_acl_entry * mac_acl,int n_entries,u8 accept_acl)13893ff40c12SJohn Marino static int hostapd_set_acl_list(struct hostapd_data *hapd,
13903ff40c12SJohn Marino struct mac_acl_entry *mac_acl,
13913ff40c12SJohn Marino int n_entries, u8 accept_acl)
13923ff40c12SJohn Marino {
13933ff40c12SJohn Marino struct hostapd_acl_params *acl_params;
13943ff40c12SJohn Marino int i, err;
13953ff40c12SJohn Marino
13963ff40c12SJohn Marino acl_params = os_zalloc(sizeof(*acl_params) +
13973ff40c12SJohn Marino (n_entries * sizeof(acl_params->mac_acl[0])));
13983ff40c12SJohn Marino if (!acl_params)
13993ff40c12SJohn Marino return -ENOMEM;
14003ff40c12SJohn Marino
14013ff40c12SJohn Marino for (i = 0; i < n_entries; i++)
14023ff40c12SJohn Marino os_memcpy(acl_params->mac_acl[i].addr, mac_acl[i].addr,
14033ff40c12SJohn Marino ETH_ALEN);
14043ff40c12SJohn Marino
14053ff40c12SJohn Marino acl_params->acl_policy = accept_acl;
14063ff40c12SJohn Marino acl_params->num_mac_acl = n_entries;
14073ff40c12SJohn Marino
14083ff40c12SJohn Marino err = hostapd_drv_set_acl(hapd, acl_params);
14093ff40c12SJohn Marino
14103ff40c12SJohn Marino os_free(acl_params);
14113ff40c12SJohn Marino
14123ff40c12SJohn Marino return err;
14133ff40c12SJohn Marino }
14143ff40c12SJohn Marino
14153ff40c12SJohn Marino
hostapd_set_acl(struct hostapd_data * hapd)14163ff40c12SJohn Marino static void hostapd_set_acl(struct hostapd_data *hapd)
14173ff40c12SJohn Marino {
14183ff40c12SJohn Marino struct hostapd_config *conf = hapd->iconf;
14193ff40c12SJohn Marino int err;
14203ff40c12SJohn Marino u8 accept_acl;
14213ff40c12SJohn Marino
14223ff40c12SJohn Marino if (hapd->iface->drv_max_acl_mac_addrs == 0)
14233ff40c12SJohn Marino return;
14243ff40c12SJohn Marino
14253ff40c12SJohn Marino if (conf->bss[0]->macaddr_acl == DENY_UNLESS_ACCEPTED) {
14263ff40c12SJohn Marino accept_acl = 1;
1427*a1157835SDaniel Fojt err = hostapd_set_acl_list(hapd, conf->bss[0]->accept_mac,
14283ff40c12SJohn Marino conf->bss[0]->num_accept_mac,
14293ff40c12SJohn Marino accept_acl);
14303ff40c12SJohn Marino if (err) {
14313ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Failed to set accept acl");
14323ff40c12SJohn Marino return;
14333ff40c12SJohn Marino }
14343ff40c12SJohn Marino } else if (conf->bss[0]->macaddr_acl == ACCEPT_UNLESS_DENIED) {
14353ff40c12SJohn Marino accept_acl = 0;
14363ff40c12SJohn Marino err = hostapd_set_acl_list(hapd, conf->bss[0]->deny_mac,
14373ff40c12SJohn Marino conf->bss[0]->num_deny_mac,
14383ff40c12SJohn Marino accept_acl);
14393ff40c12SJohn Marino if (err) {
14403ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Failed to set deny acl");
14413ff40c12SJohn Marino return;
14423ff40c12SJohn Marino }
14433ff40c12SJohn Marino }
14443ff40c12SJohn Marino }
14453ff40c12SJohn Marino
14463ff40c12SJohn Marino
start_ctrl_iface_bss(struct hostapd_data * hapd)14473ff40c12SJohn Marino static int start_ctrl_iface_bss(struct hostapd_data *hapd)
14483ff40c12SJohn Marino {
14493ff40c12SJohn Marino if (!hapd->iface->interfaces ||
14503ff40c12SJohn Marino !hapd->iface->interfaces->ctrl_iface_init)
14513ff40c12SJohn Marino return 0;
14523ff40c12SJohn Marino
14533ff40c12SJohn Marino if (hapd->iface->interfaces->ctrl_iface_init(hapd)) {
14543ff40c12SJohn Marino wpa_printf(MSG_ERROR,
14553ff40c12SJohn Marino "Failed to setup control interface for %s",
14563ff40c12SJohn Marino hapd->conf->iface);
14573ff40c12SJohn Marino return -1;
14583ff40c12SJohn Marino }
14593ff40c12SJohn Marino
14603ff40c12SJohn Marino return 0;
14613ff40c12SJohn Marino }
14623ff40c12SJohn Marino
14633ff40c12SJohn Marino
start_ctrl_iface(struct hostapd_iface * iface)14643ff40c12SJohn Marino static int start_ctrl_iface(struct hostapd_iface *iface)
14653ff40c12SJohn Marino {
14663ff40c12SJohn Marino size_t i;
14673ff40c12SJohn Marino
14683ff40c12SJohn Marino if (!iface->interfaces || !iface->interfaces->ctrl_iface_init)
14693ff40c12SJohn Marino return 0;
14703ff40c12SJohn Marino
14713ff40c12SJohn Marino for (i = 0; i < iface->num_bss; i++) {
14723ff40c12SJohn Marino struct hostapd_data *hapd = iface->bss[i];
14733ff40c12SJohn Marino if (iface->interfaces->ctrl_iface_init(hapd)) {
14743ff40c12SJohn Marino wpa_printf(MSG_ERROR,
14753ff40c12SJohn Marino "Failed to setup control interface for %s",
14763ff40c12SJohn Marino hapd->conf->iface);
14773ff40c12SJohn Marino return -1;
14783ff40c12SJohn Marino }
14793ff40c12SJohn Marino }
14803ff40c12SJohn Marino
14813ff40c12SJohn Marino return 0;
14823ff40c12SJohn Marino }
14833ff40c12SJohn Marino
14843ff40c12SJohn Marino
channel_list_update_timeout(void * eloop_ctx,void * timeout_ctx)14853ff40c12SJohn Marino static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx)
14863ff40c12SJohn Marino {
14873ff40c12SJohn Marino struct hostapd_iface *iface = eloop_ctx;
14883ff40c12SJohn Marino
14893ff40c12SJohn Marino if (!iface->wait_channel_update) {
14903ff40c12SJohn Marino wpa_printf(MSG_INFO, "Channel list update timeout, but interface was not waiting for it");
14913ff40c12SJohn Marino return;
14923ff40c12SJohn Marino }
14933ff40c12SJohn Marino
14943ff40c12SJohn Marino /*
14953ff40c12SJohn Marino * It is possible that the existing channel list is acceptable, so try
14963ff40c12SJohn Marino * to proceed.
14973ff40c12SJohn Marino */
14983ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Channel list update timeout - try to continue anyway");
14993ff40c12SJohn Marino setup_interface2(iface);
15003ff40c12SJohn Marino }
15013ff40c12SJohn Marino
15023ff40c12SJohn Marino
hostapd_channel_list_updated(struct hostapd_iface * iface,int initiator)15033ff40c12SJohn Marino void hostapd_channel_list_updated(struct hostapd_iface *iface, int initiator)
15043ff40c12SJohn Marino {
15053ff40c12SJohn Marino if (!iface->wait_channel_update || initiator != REGDOM_SET_BY_USER)
15063ff40c12SJohn Marino return;
15073ff40c12SJohn Marino
15083ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Channel list updated - continue setup");
15093ff40c12SJohn Marino eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
15103ff40c12SJohn Marino setup_interface2(iface);
15113ff40c12SJohn Marino }
15123ff40c12SJohn Marino
15133ff40c12SJohn Marino
setup_interface(struct hostapd_iface * iface)15143ff40c12SJohn Marino static int setup_interface(struct hostapd_iface *iface)
15153ff40c12SJohn Marino {
15163ff40c12SJohn Marino struct hostapd_data *hapd = iface->bss[0];
15173ff40c12SJohn Marino size_t i;
15183ff40c12SJohn Marino
1519*a1157835SDaniel Fojt /*
1520*a1157835SDaniel Fojt * It is possible that setup_interface() is called after the interface
1521*a1157835SDaniel Fojt * was disabled etc., in which case driver_ap_teardown is possibly set
1522*a1157835SDaniel Fojt * to 1. Clear it here so any other key/station deletion, which is not
1523*a1157835SDaniel Fojt * part of a teardown flow, would also call the relevant driver
1524*a1157835SDaniel Fojt * callbacks.
1525*a1157835SDaniel Fojt */
1526*a1157835SDaniel Fojt iface->driver_ap_teardown = 0;
1527*a1157835SDaniel Fojt
15283ff40c12SJohn Marino if (!iface->phy[0]) {
15293ff40c12SJohn Marino const char *phy = hostapd_drv_get_radio_name(hapd);
15303ff40c12SJohn Marino if (phy) {
15313ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "phy: %s", phy);
15323ff40c12SJohn Marino os_strlcpy(iface->phy, phy, sizeof(iface->phy));
15333ff40c12SJohn Marino }
15343ff40c12SJohn Marino }
15353ff40c12SJohn Marino
15363ff40c12SJohn Marino /*
15373ff40c12SJohn Marino * Make sure that all BSSes get configured with a pointer to the same
15383ff40c12SJohn Marino * driver interface.
15393ff40c12SJohn Marino */
15403ff40c12SJohn Marino for (i = 1; i < iface->num_bss; i++) {
15413ff40c12SJohn Marino iface->bss[i]->driver = hapd->driver;
15423ff40c12SJohn Marino iface->bss[i]->drv_priv = hapd->drv_priv;
15433ff40c12SJohn Marino }
15443ff40c12SJohn Marino
15453ff40c12SJohn Marino if (hostapd_validate_bssid_configuration(iface))
15463ff40c12SJohn Marino return -1;
15473ff40c12SJohn Marino
15483ff40c12SJohn Marino /*
15493ff40c12SJohn Marino * Initialize control interfaces early to allow external monitoring of
15503ff40c12SJohn Marino * channel setup operations that may take considerable amount of time
15513ff40c12SJohn Marino * especially for DFS cases.
15523ff40c12SJohn Marino */
15533ff40c12SJohn Marino if (start_ctrl_iface(iface))
15543ff40c12SJohn Marino return -1;
15553ff40c12SJohn Marino
15563ff40c12SJohn Marino if (hapd->iconf->country[0] && hapd->iconf->country[1]) {
15573ff40c12SJohn Marino char country[4], previous_country[4];
15583ff40c12SJohn Marino
15593ff40c12SJohn Marino hostapd_set_state(iface, HAPD_IFACE_COUNTRY_UPDATE);
15603ff40c12SJohn Marino if (hostapd_get_country(hapd, previous_country) < 0)
15613ff40c12SJohn Marino previous_country[0] = '\0';
15623ff40c12SJohn Marino
15633ff40c12SJohn Marino os_memcpy(country, hapd->iconf->country, 3);
15643ff40c12SJohn Marino country[3] = '\0';
15653ff40c12SJohn Marino if (hostapd_set_country(hapd, country) < 0) {
15663ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Failed to set country code");
15673ff40c12SJohn Marino return -1;
15683ff40c12SJohn Marino }
15693ff40c12SJohn Marino
15703ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Previous country code %s, new country code %s",
15713ff40c12SJohn Marino previous_country, country);
15723ff40c12SJohn Marino
15733ff40c12SJohn Marino if (os_strncmp(previous_country, country, 2) != 0) {
15743ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Continue interface setup after channel list update");
15753ff40c12SJohn Marino iface->wait_channel_update = 1;
15763ff40c12SJohn Marino eloop_register_timeout(5, 0,
15773ff40c12SJohn Marino channel_list_update_timeout,
15783ff40c12SJohn Marino iface, NULL);
15793ff40c12SJohn Marino return 0;
15803ff40c12SJohn Marino }
15813ff40c12SJohn Marino }
15823ff40c12SJohn Marino
15833ff40c12SJohn Marino return setup_interface2(iface);
15843ff40c12SJohn Marino }
15853ff40c12SJohn Marino
15863ff40c12SJohn Marino
setup_interface2(struct hostapd_iface * iface)15873ff40c12SJohn Marino static int setup_interface2(struct hostapd_iface *iface)
15883ff40c12SJohn Marino {
15893ff40c12SJohn Marino iface->wait_channel_update = 0;
15903ff40c12SJohn Marino
15913ff40c12SJohn Marino if (hostapd_get_hw_features(iface)) {
15923ff40c12SJohn Marino /* Not all drivers support this yet, so continue without hw
15933ff40c12SJohn Marino * feature data. */
15943ff40c12SJohn Marino } else {
15953ff40c12SJohn Marino int ret = hostapd_select_hw_mode(iface);
15963ff40c12SJohn Marino if (ret < 0) {
15973ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Could not select hw_mode and "
15983ff40c12SJohn Marino "channel. (%d)", ret);
1599*a1157835SDaniel Fojt goto fail;
16003ff40c12SJohn Marino }
16013ff40c12SJohn Marino if (ret == 1) {
16023ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Interface initialization will be completed in a callback (ACS)");
16033ff40c12SJohn Marino return 0;
16043ff40c12SJohn Marino }
16053ff40c12SJohn Marino ret = hostapd_check_ht_capab(iface);
16063ff40c12SJohn Marino if (ret < 0)
1607*a1157835SDaniel Fojt goto fail;
16083ff40c12SJohn Marino if (ret == 1) {
16093ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Interface initialization will "
16103ff40c12SJohn Marino "be completed in a callback");
16113ff40c12SJohn Marino return 0;
16123ff40c12SJohn Marino }
16133ff40c12SJohn Marino
16143ff40c12SJohn Marino if (iface->conf->ieee80211h)
16153ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "DFS support is enabled");
16163ff40c12SJohn Marino }
16173ff40c12SJohn Marino return hostapd_setup_interface_complete(iface, 0);
16183ff40c12SJohn Marino
1619*a1157835SDaniel Fojt fail:
16203ff40c12SJohn Marino hostapd_set_state(iface, HAPD_IFACE_DISABLED);
1621*a1157835SDaniel Fojt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
16223ff40c12SJohn Marino if (iface->interfaces && iface->interfaces->terminate_on_error)
16233ff40c12SJohn Marino eloop_terminate();
16243ff40c12SJohn Marino return -1;
16253ff40c12SJohn Marino }
16263ff40c12SJohn Marino
1627*a1157835SDaniel Fojt
1628*a1157835SDaniel Fojt #ifdef CONFIG_FST
1629*a1157835SDaniel Fojt
fst_hostapd_get_bssid_cb(void * ctx)1630*a1157835SDaniel Fojt static const u8 * fst_hostapd_get_bssid_cb(void *ctx)
1631*a1157835SDaniel Fojt {
1632*a1157835SDaniel Fojt struct hostapd_data *hapd = ctx;
1633*a1157835SDaniel Fojt
1634*a1157835SDaniel Fojt return hapd->own_addr;
1635*a1157835SDaniel Fojt }
1636*a1157835SDaniel Fojt
1637*a1157835SDaniel Fojt
fst_hostapd_get_channel_info_cb(void * ctx,enum hostapd_hw_mode * hw_mode,u8 * channel)1638*a1157835SDaniel Fojt static void fst_hostapd_get_channel_info_cb(void *ctx,
1639*a1157835SDaniel Fojt enum hostapd_hw_mode *hw_mode,
1640*a1157835SDaniel Fojt u8 *channel)
1641*a1157835SDaniel Fojt {
1642*a1157835SDaniel Fojt struct hostapd_data *hapd = ctx;
1643*a1157835SDaniel Fojt
1644*a1157835SDaniel Fojt *hw_mode = ieee80211_freq_to_chan(hapd->iface->freq, channel);
1645*a1157835SDaniel Fojt }
1646*a1157835SDaniel Fojt
1647*a1157835SDaniel Fojt
fst_hostapd_set_ies_cb(void * ctx,const struct wpabuf * fst_ies)1648*a1157835SDaniel Fojt static void fst_hostapd_set_ies_cb(void *ctx, const struct wpabuf *fst_ies)
1649*a1157835SDaniel Fojt {
1650*a1157835SDaniel Fojt struct hostapd_data *hapd = ctx;
1651*a1157835SDaniel Fojt
1652*a1157835SDaniel Fojt if (hapd->iface->fst_ies != fst_ies) {
1653*a1157835SDaniel Fojt hapd->iface->fst_ies = fst_ies;
1654*a1157835SDaniel Fojt if (ieee802_11_set_beacon(hapd))
1655*a1157835SDaniel Fojt wpa_printf(MSG_WARNING, "FST: Cannot set beacon");
1656*a1157835SDaniel Fojt }
1657*a1157835SDaniel Fojt }
1658*a1157835SDaniel Fojt
1659*a1157835SDaniel Fojt
fst_hostapd_send_action_cb(void * ctx,const u8 * da,struct wpabuf * buf)1660*a1157835SDaniel Fojt static int fst_hostapd_send_action_cb(void *ctx, const u8 *da,
1661*a1157835SDaniel Fojt struct wpabuf *buf)
1662*a1157835SDaniel Fojt {
1663*a1157835SDaniel Fojt struct hostapd_data *hapd = ctx;
1664*a1157835SDaniel Fojt
1665*a1157835SDaniel Fojt return hostapd_drv_send_action(hapd, hapd->iface->freq, 0, da,
1666*a1157835SDaniel Fojt wpabuf_head(buf), wpabuf_len(buf));
1667*a1157835SDaniel Fojt }
1668*a1157835SDaniel Fojt
1669*a1157835SDaniel Fojt
fst_hostapd_get_mb_ie_cb(void * ctx,const u8 * addr)1670*a1157835SDaniel Fojt static const struct wpabuf * fst_hostapd_get_mb_ie_cb(void *ctx, const u8 *addr)
1671*a1157835SDaniel Fojt {
1672*a1157835SDaniel Fojt struct hostapd_data *hapd = ctx;
1673*a1157835SDaniel Fojt struct sta_info *sta = ap_get_sta(hapd, addr);
1674*a1157835SDaniel Fojt
1675*a1157835SDaniel Fojt return sta ? sta->mb_ies : NULL;
1676*a1157835SDaniel Fojt }
1677*a1157835SDaniel Fojt
1678*a1157835SDaniel Fojt
fst_hostapd_update_mb_ie_cb(void * ctx,const u8 * addr,const u8 * buf,size_t size)1679*a1157835SDaniel Fojt static void fst_hostapd_update_mb_ie_cb(void *ctx, const u8 *addr,
1680*a1157835SDaniel Fojt const u8 *buf, size_t size)
1681*a1157835SDaniel Fojt {
1682*a1157835SDaniel Fojt struct hostapd_data *hapd = ctx;
1683*a1157835SDaniel Fojt struct sta_info *sta = ap_get_sta(hapd, addr);
1684*a1157835SDaniel Fojt
1685*a1157835SDaniel Fojt if (sta) {
1686*a1157835SDaniel Fojt struct mb_ies_info info;
1687*a1157835SDaniel Fojt
1688*a1157835SDaniel Fojt if (!mb_ies_info_by_ies(&info, buf, size)) {
1689*a1157835SDaniel Fojt wpabuf_free(sta->mb_ies);
1690*a1157835SDaniel Fojt sta->mb_ies = mb_ies_by_info(&info);
1691*a1157835SDaniel Fojt }
1692*a1157835SDaniel Fojt }
1693*a1157835SDaniel Fojt }
1694*a1157835SDaniel Fojt
1695*a1157835SDaniel Fojt
fst_hostapd_get_sta(struct fst_get_peer_ctx ** get_ctx,Boolean mb_only)1696*a1157835SDaniel Fojt static const u8 * fst_hostapd_get_sta(struct fst_get_peer_ctx **get_ctx,
1697*a1157835SDaniel Fojt Boolean mb_only)
1698*a1157835SDaniel Fojt {
1699*a1157835SDaniel Fojt struct sta_info *s = (struct sta_info *) *get_ctx;
1700*a1157835SDaniel Fojt
1701*a1157835SDaniel Fojt if (mb_only) {
1702*a1157835SDaniel Fojt for (; s && !s->mb_ies; s = s->next)
1703*a1157835SDaniel Fojt ;
1704*a1157835SDaniel Fojt }
1705*a1157835SDaniel Fojt
1706*a1157835SDaniel Fojt if (s) {
1707*a1157835SDaniel Fojt *get_ctx = (struct fst_get_peer_ctx *) s->next;
1708*a1157835SDaniel Fojt
1709*a1157835SDaniel Fojt return s->addr;
1710*a1157835SDaniel Fojt }
1711*a1157835SDaniel Fojt
1712*a1157835SDaniel Fojt *get_ctx = NULL;
1713*a1157835SDaniel Fojt return NULL;
1714*a1157835SDaniel Fojt }
1715*a1157835SDaniel Fojt
1716*a1157835SDaniel Fojt
fst_hostapd_get_peer_first(void * ctx,struct fst_get_peer_ctx ** get_ctx,Boolean mb_only)1717*a1157835SDaniel Fojt static const u8 * fst_hostapd_get_peer_first(void *ctx,
1718*a1157835SDaniel Fojt struct fst_get_peer_ctx **get_ctx,
1719*a1157835SDaniel Fojt Boolean mb_only)
1720*a1157835SDaniel Fojt {
1721*a1157835SDaniel Fojt struct hostapd_data *hapd = ctx;
1722*a1157835SDaniel Fojt
1723*a1157835SDaniel Fojt *get_ctx = (struct fst_get_peer_ctx *) hapd->sta_list;
1724*a1157835SDaniel Fojt
1725*a1157835SDaniel Fojt return fst_hostapd_get_sta(get_ctx, mb_only);
1726*a1157835SDaniel Fojt }
1727*a1157835SDaniel Fojt
1728*a1157835SDaniel Fojt
fst_hostapd_get_peer_next(void * ctx,struct fst_get_peer_ctx ** get_ctx,Boolean mb_only)1729*a1157835SDaniel Fojt static const u8 * fst_hostapd_get_peer_next(void *ctx,
1730*a1157835SDaniel Fojt struct fst_get_peer_ctx **get_ctx,
1731*a1157835SDaniel Fojt Boolean mb_only)
1732*a1157835SDaniel Fojt {
1733*a1157835SDaniel Fojt return fst_hostapd_get_sta(get_ctx, mb_only);
1734*a1157835SDaniel Fojt }
1735*a1157835SDaniel Fojt
1736*a1157835SDaniel Fojt
fst_hostapd_fill_iface_obj(struct hostapd_data * hapd,struct fst_wpa_obj * iface_obj)1737*a1157835SDaniel Fojt void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd,
1738*a1157835SDaniel Fojt struct fst_wpa_obj *iface_obj)
1739*a1157835SDaniel Fojt {
1740*a1157835SDaniel Fojt iface_obj->ctx = hapd;
1741*a1157835SDaniel Fojt iface_obj->get_bssid = fst_hostapd_get_bssid_cb;
1742*a1157835SDaniel Fojt iface_obj->get_channel_info = fst_hostapd_get_channel_info_cb;
1743*a1157835SDaniel Fojt iface_obj->set_ies = fst_hostapd_set_ies_cb;
1744*a1157835SDaniel Fojt iface_obj->send_action = fst_hostapd_send_action_cb;
1745*a1157835SDaniel Fojt iface_obj->get_mb_ie = fst_hostapd_get_mb_ie_cb;
1746*a1157835SDaniel Fojt iface_obj->update_mb_ie = fst_hostapd_update_mb_ie_cb;
1747*a1157835SDaniel Fojt iface_obj->get_peer_first = fst_hostapd_get_peer_first;
1748*a1157835SDaniel Fojt iface_obj->get_peer_next = fst_hostapd_get_peer_next;
1749*a1157835SDaniel Fojt }
1750*a1157835SDaniel Fojt
1751*a1157835SDaniel Fojt #endif /* CONFIG_FST */
1752*a1157835SDaniel Fojt
1753*a1157835SDaniel Fojt #ifdef CONFIG_OWE
1754*a1157835SDaniel Fojt
hostapd_owe_iface_iter(struct hostapd_iface * iface,void * ctx)1755*a1157835SDaniel Fojt static int hostapd_owe_iface_iter(struct hostapd_iface *iface, void *ctx)
1756*a1157835SDaniel Fojt {
1757*a1157835SDaniel Fojt struct hostapd_data *hapd = ctx;
1758*a1157835SDaniel Fojt size_t i;
1759*a1157835SDaniel Fojt
1760*a1157835SDaniel Fojt for (i = 0; i < iface->num_bss; i++) {
1761*a1157835SDaniel Fojt struct hostapd_data *bss = iface->bss[i];
1762*a1157835SDaniel Fojt
1763*a1157835SDaniel Fojt if (os_strcmp(hapd->conf->owe_transition_ifname,
1764*a1157835SDaniel Fojt bss->conf->iface) != 0)
1765*a1157835SDaniel Fojt continue;
1766*a1157835SDaniel Fojt
1767*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
1768*a1157835SDaniel Fojt "OWE: ifname=%s found transition mode ifname=%s BSSID "
1769*a1157835SDaniel Fojt MACSTR " SSID %s",
1770*a1157835SDaniel Fojt hapd->conf->iface, bss->conf->iface,
1771*a1157835SDaniel Fojt MAC2STR(bss->own_addr),
1772*a1157835SDaniel Fojt wpa_ssid_txt(bss->conf->ssid.ssid,
1773*a1157835SDaniel Fojt bss->conf->ssid.ssid_len));
1774*a1157835SDaniel Fojt if (!bss->conf->ssid.ssid_set || !bss->conf->ssid.ssid_len ||
1775*a1157835SDaniel Fojt is_zero_ether_addr(bss->own_addr))
1776*a1157835SDaniel Fojt continue;
1777*a1157835SDaniel Fojt
1778*a1157835SDaniel Fojt os_memcpy(hapd->conf->owe_transition_bssid, bss->own_addr,
1779*a1157835SDaniel Fojt ETH_ALEN);
1780*a1157835SDaniel Fojt os_memcpy(hapd->conf->owe_transition_ssid,
1781*a1157835SDaniel Fojt bss->conf->ssid.ssid, bss->conf->ssid.ssid_len);
1782*a1157835SDaniel Fojt hapd->conf->owe_transition_ssid_len = bss->conf->ssid.ssid_len;
1783*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
1784*a1157835SDaniel Fojt "OWE: Copied transition mode information");
1785*a1157835SDaniel Fojt return 1;
1786*a1157835SDaniel Fojt }
1787*a1157835SDaniel Fojt
1788*a1157835SDaniel Fojt return 0;
1789*a1157835SDaniel Fojt }
1790*a1157835SDaniel Fojt
1791*a1157835SDaniel Fojt
hostapd_owe_trans_get_info(struct hostapd_data * hapd)1792*a1157835SDaniel Fojt int hostapd_owe_trans_get_info(struct hostapd_data *hapd)
1793*a1157835SDaniel Fojt {
1794*a1157835SDaniel Fojt if (hapd->conf->owe_transition_ssid_len > 0 &&
1795*a1157835SDaniel Fojt !is_zero_ether_addr(hapd->conf->owe_transition_bssid))
1796*a1157835SDaniel Fojt return 0;
1797*a1157835SDaniel Fojt
1798*a1157835SDaniel Fojt /* Find transition mode SSID/BSSID information from a BSS operated by
1799*a1157835SDaniel Fojt * this hostapd instance. */
1800*a1157835SDaniel Fojt if (!hapd->iface->interfaces ||
1801*a1157835SDaniel Fojt !hapd->iface->interfaces->for_each_interface)
1802*a1157835SDaniel Fojt return hostapd_owe_iface_iter(hapd->iface, hapd);
1803*a1157835SDaniel Fojt else
1804*a1157835SDaniel Fojt return hapd->iface->interfaces->for_each_interface(
1805*a1157835SDaniel Fojt hapd->iface->interfaces, hostapd_owe_iface_iter, hapd);
1806*a1157835SDaniel Fojt }
1807*a1157835SDaniel Fojt
1808*a1157835SDaniel Fojt
hostapd_owe_iface_iter2(struct hostapd_iface * iface,void * ctx)1809*a1157835SDaniel Fojt static int hostapd_owe_iface_iter2(struct hostapd_iface *iface, void *ctx)
1810*a1157835SDaniel Fojt {
1811*a1157835SDaniel Fojt size_t i;
1812*a1157835SDaniel Fojt
1813*a1157835SDaniel Fojt for (i = 0; i < iface->num_bss; i++) {
1814*a1157835SDaniel Fojt struct hostapd_data *bss = iface->bss[i];
1815*a1157835SDaniel Fojt int res;
1816*a1157835SDaniel Fojt
1817*a1157835SDaniel Fojt if (!bss->conf->owe_transition_ifname[0])
1818*a1157835SDaniel Fojt continue;
1819*a1157835SDaniel Fojt res = hostapd_owe_trans_get_info(bss);
1820*a1157835SDaniel Fojt if (res == 0)
1821*a1157835SDaniel Fojt continue;
1822*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
1823*a1157835SDaniel Fojt "OWE: Matching transition mode interface enabled - update beacon data for %s",
1824*a1157835SDaniel Fojt bss->conf->iface);
1825*a1157835SDaniel Fojt ieee802_11_set_beacon(bss);
1826*a1157835SDaniel Fojt }
1827*a1157835SDaniel Fojt
1828*a1157835SDaniel Fojt return 0;
1829*a1157835SDaniel Fojt }
1830*a1157835SDaniel Fojt
1831*a1157835SDaniel Fojt #endif /* CONFIG_OWE */
1832*a1157835SDaniel Fojt
1833*a1157835SDaniel Fojt
hostapd_owe_update_trans(struct hostapd_iface * iface)1834*a1157835SDaniel Fojt static void hostapd_owe_update_trans(struct hostapd_iface *iface)
1835*a1157835SDaniel Fojt {
1836*a1157835SDaniel Fojt #ifdef CONFIG_OWE
1837*a1157835SDaniel Fojt /* Check whether the enabled BSS can complete OWE transition mode
1838*a1157835SDaniel Fojt * configuration for any pending interface. */
1839*a1157835SDaniel Fojt if (!iface->interfaces ||
1840*a1157835SDaniel Fojt !iface->interfaces->for_each_interface)
1841*a1157835SDaniel Fojt hostapd_owe_iface_iter2(iface, NULL);
1842*a1157835SDaniel Fojt else
1843*a1157835SDaniel Fojt iface->interfaces->for_each_interface(
1844*a1157835SDaniel Fojt iface->interfaces, hostapd_owe_iface_iter2, NULL);
1845*a1157835SDaniel Fojt #endif /* CONFIG_OWE */
1846*a1157835SDaniel Fojt }
1847*a1157835SDaniel Fojt
1848*a1157835SDaniel Fojt
hostapd_interface_setup_failure_handler(void * eloop_ctx,void * timeout_ctx)1849*a1157835SDaniel Fojt static void hostapd_interface_setup_failure_handler(void *eloop_ctx,
1850*a1157835SDaniel Fojt void *timeout_ctx)
1851*a1157835SDaniel Fojt {
1852*a1157835SDaniel Fojt struct hostapd_iface *iface = eloop_ctx;
1853*a1157835SDaniel Fojt struct hostapd_data *hapd;
1854*a1157835SDaniel Fojt
1855*a1157835SDaniel Fojt if (iface->num_bss < 1 || !iface->bss || !iface->bss[0])
1856*a1157835SDaniel Fojt return;
1857*a1157835SDaniel Fojt hapd = iface->bss[0];
1858*a1157835SDaniel Fojt if (hapd->setup_complete_cb)
1859*a1157835SDaniel Fojt hapd->setup_complete_cb(hapd->setup_complete_cb_ctx);
1860*a1157835SDaniel Fojt }
1861*a1157835SDaniel Fojt
1862*a1157835SDaniel Fojt
hostapd_setup_interface_complete_sync(struct hostapd_iface * iface,int err)1863*a1157835SDaniel Fojt static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
1864*a1157835SDaniel Fojt int err)
1865*a1157835SDaniel Fojt {
1866*a1157835SDaniel Fojt struct hostapd_data *hapd = iface->bss[0];
1867*a1157835SDaniel Fojt size_t j;
1868*a1157835SDaniel Fojt u8 *prev_addr;
1869*a1157835SDaniel Fojt int delay_apply_cfg = 0;
1870*a1157835SDaniel Fojt int res_dfs_offload = 0;
1871*a1157835SDaniel Fojt
1872*a1157835SDaniel Fojt if (err)
1873*a1157835SDaniel Fojt goto fail;
1874*a1157835SDaniel Fojt
18753ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Completing interface initialization");
18763ff40c12SJohn Marino if (iface->conf->channel) {
18773ff40c12SJohn Marino #ifdef NEED_AP_MLME
18783ff40c12SJohn Marino int res;
18793ff40c12SJohn Marino #endif /* NEED_AP_MLME */
18803ff40c12SJohn Marino
18813ff40c12SJohn Marino iface->freq = hostapd_hw_get_freq(hapd, iface->conf->channel);
18823ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Mode: %s Channel: %d "
18833ff40c12SJohn Marino "Frequency: %d MHz",
18843ff40c12SJohn Marino hostapd_hw_mode_txt(iface->conf->hw_mode),
18853ff40c12SJohn Marino iface->conf->channel, iface->freq);
18863ff40c12SJohn Marino
18873ff40c12SJohn Marino #ifdef NEED_AP_MLME
1888*a1157835SDaniel Fojt /* Handle DFS only if it is not offloaded to the driver */
1889*a1157835SDaniel Fojt if (!(iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)) {
18903ff40c12SJohn Marino /* Check DFS */
18913ff40c12SJohn Marino res = hostapd_handle_dfs(iface);
1892*a1157835SDaniel Fojt if (res <= 0) {
1893*a1157835SDaniel Fojt if (res < 0)
1894*a1157835SDaniel Fojt goto fail;
18953ff40c12SJohn Marino return res;
1896*a1157835SDaniel Fojt }
1897*a1157835SDaniel Fojt } else {
1898*a1157835SDaniel Fojt /* If DFS is offloaded to the driver */
1899*a1157835SDaniel Fojt res_dfs_offload = hostapd_handle_dfs_offload(iface);
1900*a1157835SDaniel Fojt if (res_dfs_offload <= 0) {
1901*a1157835SDaniel Fojt if (res_dfs_offload < 0)
1902*a1157835SDaniel Fojt goto fail;
1903*a1157835SDaniel Fojt } else {
1904*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
1905*a1157835SDaniel Fojt "Proceed with AP/channel setup");
1906*a1157835SDaniel Fojt /*
1907*a1157835SDaniel Fojt * If this is a DFS channel, move to completing
1908*a1157835SDaniel Fojt * AP setup.
1909*a1157835SDaniel Fojt */
1910*a1157835SDaniel Fojt if (res_dfs_offload == 1)
1911*a1157835SDaniel Fojt goto dfs_offload;
1912*a1157835SDaniel Fojt /* Otherwise fall through. */
1913*a1157835SDaniel Fojt }
1914*a1157835SDaniel Fojt }
19153ff40c12SJohn Marino #endif /* NEED_AP_MLME */
19163ff40c12SJohn Marino
1917*a1157835SDaniel Fojt #ifdef CONFIG_MESH
1918*a1157835SDaniel Fojt if (iface->mconf != NULL) {
1919*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
1920*a1157835SDaniel Fojt "%s: Mesh configuration will be applied while joining the mesh network",
1921*a1157835SDaniel Fojt iface->bss[0]->conf->iface);
1922*a1157835SDaniel Fojt delay_apply_cfg = 1;
1923*a1157835SDaniel Fojt }
1924*a1157835SDaniel Fojt #endif /* CONFIG_MESH */
1925*a1157835SDaniel Fojt
1926*a1157835SDaniel Fojt if (!delay_apply_cfg &&
1927*a1157835SDaniel Fojt hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
19283ff40c12SJohn Marino hapd->iconf->channel,
19293ff40c12SJohn Marino hapd->iconf->ieee80211n,
19303ff40c12SJohn Marino hapd->iconf->ieee80211ac,
1931*a1157835SDaniel Fojt hapd->iconf->ieee80211ax,
19323ff40c12SJohn Marino hapd->iconf->secondary_channel,
1933*a1157835SDaniel Fojt hostapd_get_oper_chwidth(hapd->iconf),
1934*a1157835SDaniel Fojt hostapd_get_oper_centr_freq_seg0_idx(
1935*a1157835SDaniel Fojt hapd->iconf),
1936*a1157835SDaniel Fojt hostapd_get_oper_centr_freq_seg1_idx(
1937*a1157835SDaniel Fojt hapd->iconf))) {
19383ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Could not set channel for "
19393ff40c12SJohn Marino "kernel driver");
1940*a1157835SDaniel Fojt goto fail;
19413ff40c12SJohn Marino }
19423ff40c12SJohn Marino }
19433ff40c12SJohn Marino
19443ff40c12SJohn Marino if (iface->current_mode) {
19453ff40c12SJohn Marino if (hostapd_prepare_rates(iface, iface->current_mode)) {
19463ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Failed to prepare rates "
19473ff40c12SJohn Marino "table.");
19483ff40c12SJohn Marino hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
19493ff40c12SJohn Marino HOSTAPD_LEVEL_WARNING,
19503ff40c12SJohn Marino "Failed to prepare rates table.");
1951*a1157835SDaniel Fojt goto fail;
19523ff40c12SJohn Marino }
19533ff40c12SJohn Marino }
19543ff40c12SJohn Marino
1955*a1157835SDaniel Fojt if (hapd->iconf->rts_threshold >= -1 &&
1956*a1157835SDaniel Fojt hostapd_set_rts(hapd, hapd->iconf->rts_threshold) &&
1957*a1157835SDaniel Fojt hapd->iconf->rts_threshold >= -1) {
19583ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Could not set RTS threshold for "
19593ff40c12SJohn Marino "kernel driver");
1960*a1157835SDaniel Fojt goto fail;
19613ff40c12SJohn Marino }
19623ff40c12SJohn Marino
1963*a1157835SDaniel Fojt if (hapd->iconf->fragm_threshold >= -1 &&
1964*a1157835SDaniel Fojt hostapd_set_frag(hapd, hapd->iconf->fragm_threshold) &&
1965*a1157835SDaniel Fojt hapd->iconf->fragm_threshold != -1) {
19663ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Could not set fragmentation threshold "
19673ff40c12SJohn Marino "for kernel driver");
1968*a1157835SDaniel Fojt goto fail;
19693ff40c12SJohn Marino }
19703ff40c12SJohn Marino
19713ff40c12SJohn Marino prev_addr = hapd->own_addr;
19723ff40c12SJohn Marino
19733ff40c12SJohn Marino for (j = 0; j < iface->num_bss; j++) {
19743ff40c12SJohn Marino hapd = iface->bss[j];
19753ff40c12SJohn Marino if (j)
19763ff40c12SJohn Marino os_memcpy(hapd->own_addr, prev_addr, ETH_ALEN);
1977*a1157835SDaniel Fojt if (hostapd_setup_bss(hapd, j == 0)) {
1978*a1157835SDaniel Fojt for (;;) {
1979*a1157835SDaniel Fojt hapd = iface->bss[j];
1980*a1157835SDaniel Fojt hostapd_bss_deinit_no_free(hapd);
1981*a1157835SDaniel Fojt hostapd_free_hapd_data(hapd);
1982*a1157835SDaniel Fojt if (j == 0)
1983*a1157835SDaniel Fojt break;
1984*a1157835SDaniel Fojt j--;
1985*a1157835SDaniel Fojt }
1986*a1157835SDaniel Fojt goto fail;
1987*a1157835SDaniel Fojt }
1988*a1157835SDaniel Fojt if (is_zero_ether_addr(hapd->conf->bssid))
19893ff40c12SJohn Marino prev_addr = hapd->own_addr;
19903ff40c12SJohn Marino }
19913ff40c12SJohn Marino hapd = iface->bss[0];
19923ff40c12SJohn Marino
19933ff40c12SJohn Marino hostapd_tx_queue_params(iface);
19943ff40c12SJohn Marino
19953ff40c12SJohn Marino ap_list_init(iface);
19963ff40c12SJohn Marino
19973ff40c12SJohn Marino hostapd_set_acl(hapd);
19983ff40c12SJohn Marino
19993ff40c12SJohn Marino if (hostapd_driver_commit(hapd) < 0) {
20003ff40c12SJohn Marino wpa_printf(MSG_ERROR, "%s: Failed to commit driver "
20013ff40c12SJohn Marino "configuration", __func__);
2002*a1157835SDaniel Fojt goto fail;
20033ff40c12SJohn Marino }
20043ff40c12SJohn Marino
20053ff40c12SJohn Marino /*
20063ff40c12SJohn Marino * WPS UPnP module can be initialized only when the "upnp_iface" is up.
20073ff40c12SJohn Marino * If "interface" and "upnp_iface" are the same (e.g., non-bridge
20083ff40c12SJohn Marino * mode), the interface is up only after driver_commit, so initialize
20093ff40c12SJohn Marino * WPS after driver_commit.
20103ff40c12SJohn Marino */
20113ff40c12SJohn Marino for (j = 0; j < iface->num_bss; j++) {
20123ff40c12SJohn Marino if (hostapd_init_wps_complete(iface->bss[j]))
2013*a1157835SDaniel Fojt goto fail;
20143ff40c12SJohn Marino }
20153ff40c12SJohn Marino
2016*a1157835SDaniel Fojt if ((iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
2017*a1157835SDaniel Fojt !res_dfs_offload) {
2018*a1157835SDaniel Fojt /*
2019*a1157835SDaniel Fojt * If freq is DFS, and DFS is offloaded to the driver, then wait
2020*a1157835SDaniel Fojt * for CAC to complete.
2021*a1157835SDaniel Fojt */
2022*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "%s: Wait for CAC to complete", __func__);
2023*a1157835SDaniel Fojt return res_dfs_offload;
2024*a1157835SDaniel Fojt }
2025*a1157835SDaniel Fojt
2026*a1157835SDaniel Fojt #ifdef NEED_AP_MLME
2027*a1157835SDaniel Fojt dfs_offload:
2028*a1157835SDaniel Fojt #endif /* NEED_AP_MLME */
2029*a1157835SDaniel Fojt
2030*a1157835SDaniel Fojt #ifdef CONFIG_FST
2031*a1157835SDaniel Fojt if (hapd->iconf->fst_cfg.group_id[0]) {
2032*a1157835SDaniel Fojt struct fst_wpa_obj iface_obj;
2033*a1157835SDaniel Fojt
2034*a1157835SDaniel Fojt fst_hostapd_fill_iface_obj(hapd, &iface_obj);
2035*a1157835SDaniel Fojt iface->fst = fst_attach(hapd->conf->iface, hapd->own_addr,
2036*a1157835SDaniel Fojt &iface_obj, &hapd->iconf->fst_cfg);
2037*a1157835SDaniel Fojt if (!iface->fst) {
2038*a1157835SDaniel Fojt wpa_printf(MSG_ERROR, "Could not attach to FST %s",
2039*a1157835SDaniel Fojt hapd->iconf->fst_cfg.group_id);
2040*a1157835SDaniel Fojt goto fail;
2041*a1157835SDaniel Fojt }
2042*a1157835SDaniel Fojt }
2043*a1157835SDaniel Fojt #endif /* CONFIG_FST */
2044*a1157835SDaniel Fojt
20453ff40c12SJohn Marino hostapd_set_state(iface, HAPD_IFACE_ENABLED);
2046*a1157835SDaniel Fojt hostapd_owe_update_trans(iface);
2047*a1157835SDaniel Fojt airtime_policy_update_init(iface);
20483ff40c12SJohn Marino wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_ENABLED);
20493ff40c12SJohn Marino if (hapd->setup_complete_cb)
20503ff40c12SJohn Marino hapd->setup_complete_cb(hapd->setup_complete_cb_ctx);
20513ff40c12SJohn Marino
20523ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "%s: Setup of interface done.",
20533ff40c12SJohn Marino iface->bss[0]->conf->iface);
20543ff40c12SJohn Marino if (iface->interfaces && iface->interfaces->terminate_on_error > 0)
20553ff40c12SJohn Marino iface->interfaces->terminate_on_error--;
20563ff40c12SJohn Marino
2057*a1157835SDaniel Fojt for (j = 0; j < iface->num_bss; j++)
2058*a1157835SDaniel Fojt hostapd_neighbor_set_own_report(iface->bss[j]);
2059*a1157835SDaniel Fojt
2060*a1157835SDaniel Fojt return 0;
2061*a1157835SDaniel Fojt
2062*a1157835SDaniel Fojt fail:
2063*a1157835SDaniel Fojt wpa_printf(MSG_ERROR, "Interface initialization failed");
2064*a1157835SDaniel Fojt hostapd_set_state(iface, HAPD_IFACE_DISABLED);
2065*a1157835SDaniel Fojt wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
2066*a1157835SDaniel Fojt #ifdef CONFIG_FST
2067*a1157835SDaniel Fojt if (iface->fst) {
2068*a1157835SDaniel Fojt fst_detach(iface->fst);
2069*a1157835SDaniel Fojt iface->fst = NULL;
2070*a1157835SDaniel Fojt }
2071*a1157835SDaniel Fojt #endif /* CONFIG_FST */
2072*a1157835SDaniel Fojt
2073*a1157835SDaniel Fojt if (iface->interfaces && iface->interfaces->terminate_on_error) {
2074*a1157835SDaniel Fojt eloop_terminate();
2075*a1157835SDaniel Fojt } else if (hapd->setup_complete_cb) {
2076*a1157835SDaniel Fojt /*
2077*a1157835SDaniel Fojt * Calling hapd->setup_complete_cb directly may cause iface
2078*a1157835SDaniel Fojt * deinitialization which may be accessed later by the caller.
2079*a1157835SDaniel Fojt */
2080*a1157835SDaniel Fojt eloop_register_timeout(0, 0,
2081*a1157835SDaniel Fojt hostapd_interface_setup_failure_handler,
2082*a1157835SDaniel Fojt iface, NULL);
2083*a1157835SDaniel Fojt }
2084*a1157835SDaniel Fojt
2085*a1157835SDaniel Fojt return -1;
2086*a1157835SDaniel Fojt }
2087*a1157835SDaniel Fojt
2088*a1157835SDaniel Fojt
2089*a1157835SDaniel Fojt /**
2090*a1157835SDaniel Fojt * hostapd_setup_interface_complete - Complete interface setup
2091*a1157835SDaniel Fojt *
2092*a1157835SDaniel Fojt * This function is called when previous steps in the interface setup has been
2093*a1157835SDaniel Fojt * completed. This can also start operations, e.g., DFS, that will require
2094*a1157835SDaniel Fojt * additional processing before interface is ready to be enabled. Such
2095*a1157835SDaniel Fojt * operations will call this function from eloop callbacks when finished.
2096*a1157835SDaniel Fojt */
hostapd_setup_interface_complete(struct hostapd_iface * iface,int err)2097*a1157835SDaniel Fojt int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
2098*a1157835SDaniel Fojt {
2099*a1157835SDaniel Fojt struct hapd_interfaces *interfaces = iface->interfaces;
2100*a1157835SDaniel Fojt struct hostapd_data *hapd = iface->bss[0];
2101*a1157835SDaniel Fojt unsigned int i;
2102*a1157835SDaniel Fojt int not_ready_in_sync_ifaces = 0;
2103*a1157835SDaniel Fojt
2104*a1157835SDaniel Fojt if (!iface->need_to_start_in_sync)
2105*a1157835SDaniel Fojt return hostapd_setup_interface_complete_sync(iface, err);
2106*a1157835SDaniel Fojt
2107*a1157835SDaniel Fojt if (err) {
2108*a1157835SDaniel Fojt wpa_printf(MSG_ERROR, "Interface initialization failed");
2109*a1157835SDaniel Fojt hostapd_set_state(iface, HAPD_IFACE_DISABLED);
2110*a1157835SDaniel Fojt iface->need_to_start_in_sync = 0;
2111*a1157835SDaniel Fojt wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
2112*a1157835SDaniel Fojt if (interfaces && interfaces->terminate_on_error)
2113*a1157835SDaniel Fojt eloop_terminate();
2114*a1157835SDaniel Fojt return -1;
2115*a1157835SDaniel Fojt }
2116*a1157835SDaniel Fojt
2117*a1157835SDaniel Fojt if (iface->ready_to_start_in_sync) {
2118*a1157835SDaniel Fojt /* Already in ready and waiting. should never happpen */
2119*a1157835SDaniel Fojt return 0;
2120*a1157835SDaniel Fojt }
2121*a1157835SDaniel Fojt
2122*a1157835SDaniel Fojt for (i = 0; i < interfaces->count; i++) {
2123*a1157835SDaniel Fojt if (interfaces->iface[i]->need_to_start_in_sync &&
2124*a1157835SDaniel Fojt !interfaces->iface[i]->ready_to_start_in_sync)
2125*a1157835SDaniel Fojt not_ready_in_sync_ifaces++;
2126*a1157835SDaniel Fojt }
2127*a1157835SDaniel Fojt
2128*a1157835SDaniel Fojt /*
2129*a1157835SDaniel Fojt * Check if this is the last interface, if yes then start all the other
2130*a1157835SDaniel Fojt * waiting interfaces. If not, add this interface to the waiting list.
2131*a1157835SDaniel Fojt */
2132*a1157835SDaniel Fojt if (not_ready_in_sync_ifaces > 1 && iface->state == HAPD_IFACE_DFS) {
2133*a1157835SDaniel Fojt /*
2134*a1157835SDaniel Fojt * If this interface went through CAC, do not synchronize, just
2135*a1157835SDaniel Fojt * start immediately.
2136*a1157835SDaniel Fojt */
2137*a1157835SDaniel Fojt iface->need_to_start_in_sync = 0;
2138*a1157835SDaniel Fojt wpa_printf(MSG_INFO,
2139*a1157835SDaniel Fojt "%s: Finished CAC - bypass sync and start interface",
2140*a1157835SDaniel Fojt iface->bss[0]->conf->iface);
2141*a1157835SDaniel Fojt return hostapd_setup_interface_complete_sync(iface, err);
2142*a1157835SDaniel Fojt }
2143*a1157835SDaniel Fojt
2144*a1157835SDaniel Fojt if (not_ready_in_sync_ifaces > 1) {
2145*a1157835SDaniel Fojt /* need to wait as there are other interfaces still coming up */
2146*a1157835SDaniel Fojt iface->ready_to_start_in_sync = 1;
2147*a1157835SDaniel Fojt wpa_printf(MSG_INFO,
2148*a1157835SDaniel Fojt "%s: Interface waiting to sync with other interfaces",
2149*a1157835SDaniel Fojt iface->bss[0]->conf->iface);
2150*a1157835SDaniel Fojt return 0;
2151*a1157835SDaniel Fojt }
2152*a1157835SDaniel Fojt
2153*a1157835SDaniel Fojt wpa_printf(MSG_INFO,
2154*a1157835SDaniel Fojt "%s: Last interface to sync - starting all interfaces",
2155*a1157835SDaniel Fojt iface->bss[0]->conf->iface);
2156*a1157835SDaniel Fojt iface->need_to_start_in_sync = 0;
2157*a1157835SDaniel Fojt hostapd_setup_interface_complete_sync(iface, err);
2158*a1157835SDaniel Fojt for (i = 0; i < interfaces->count; i++) {
2159*a1157835SDaniel Fojt if (interfaces->iface[i]->need_to_start_in_sync &&
2160*a1157835SDaniel Fojt interfaces->iface[i]->ready_to_start_in_sync) {
2161*a1157835SDaniel Fojt hostapd_setup_interface_complete_sync(
2162*a1157835SDaniel Fojt interfaces->iface[i], 0);
2163*a1157835SDaniel Fojt /* Only once the interfaces are sync started */
2164*a1157835SDaniel Fojt interfaces->iface[i]->need_to_start_in_sync = 0;
2165*a1157835SDaniel Fojt }
2166*a1157835SDaniel Fojt }
2167*a1157835SDaniel Fojt
21683ff40c12SJohn Marino return 0;
21693ff40c12SJohn Marino }
21703ff40c12SJohn Marino
21713ff40c12SJohn Marino
21723ff40c12SJohn Marino /**
21733ff40c12SJohn Marino * hostapd_setup_interface - Setup of an interface
21743ff40c12SJohn Marino * @iface: Pointer to interface data.
21753ff40c12SJohn Marino * Returns: 0 on success, -1 on failure
21763ff40c12SJohn Marino *
21773ff40c12SJohn Marino * Initializes the driver interface, validates the configuration,
21783ff40c12SJohn Marino * and sets driver parameters based on the configuration.
21793ff40c12SJohn Marino * Flushes old stations, sets the channel, encryption,
21803ff40c12SJohn Marino * beacons, and WDS links based on the configuration.
21813ff40c12SJohn Marino *
21823ff40c12SJohn Marino * If interface setup requires more time, e.g., to perform HT co-ex scans, ACS,
21833ff40c12SJohn Marino * or DFS operations, this function returns 0 before such operations have been
21843ff40c12SJohn Marino * completed. The pending operations are registered into eloop and will be
21853ff40c12SJohn Marino * completed from eloop callbacks. Those callbacks end up calling
21863ff40c12SJohn Marino * hostapd_setup_interface_complete() once setup has been completed.
21873ff40c12SJohn Marino */
hostapd_setup_interface(struct hostapd_iface * iface)21883ff40c12SJohn Marino int hostapd_setup_interface(struct hostapd_iface *iface)
21893ff40c12SJohn Marino {
21903ff40c12SJohn Marino int ret;
21913ff40c12SJohn Marino
21923ff40c12SJohn Marino ret = setup_interface(iface);
21933ff40c12SJohn Marino if (ret) {
21943ff40c12SJohn Marino wpa_printf(MSG_ERROR, "%s: Unable to setup interface.",
21953ff40c12SJohn Marino iface->bss[0]->conf->iface);
21963ff40c12SJohn Marino return -1;
21973ff40c12SJohn Marino }
21983ff40c12SJohn Marino
21993ff40c12SJohn Marino return 0;
22003ff40c12SJohn Marino }
22013ff40c12SJohn Marino
22023ff40c12SJohn Marino
22033ff40c12SJohn Marino /**
22043ff40c12SJohn Marino * hostapd_alloc_bss_data - Allocate and initialize per-BSS data
22053ff40c12SJohn Marino * @hapd_iface: Pointer to interface data
22063ff40c12SJohn Marino * @conf: Pointer to per-interface configuration
22073ff40c12SJohn Marino * @bss: Pointer to per-BSS configuration for this BSS
22083ff40c12SJohn Marino * Returns: Pointer to allocated BSS data
22093ff40c12SJohn Marino *
22103ff40c12SJohn Marino * This function is used to allocate per-BSS data structure. This data will be
22113ff40c12SJohn Marino * freed after hostapd_cleanup() is called for it during interface
22123ff40c12SJohn Marino * deinitialization.
22133ff40c12SJohn Marino */
22143ff40c12SJohn Marino struct hostapd_data *
hostapd_alloc_bss_data(struct hostapd_iface * hapd_iface,struct hostapd_config * conf,struct hostapd_bss_config * bss)22153ff40c12SJohn Marino hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
22163ff40c12SJohn Marino struct hostapd_config *conf,
22173ff40c12SJohn Marino struct hostapd_bss_config *bss)
22183ff40c12SJohn Marino {
22193ff40c12SJohn Marino struct hostapd_data *hapd;
22203ff40c12SJohn Marino
22213ff40c12SJohn Marino hapd = os_zalloc(sizeof(*hapd));
22223ff40c12SJohn Marino if (hapd == NULL)
22233ff40c12SJohn Marino return NULL;
22243ff40c12SJohn Marino
22253ff40c12SJohn Marino hapd->new_assoc_sta_cb = hostapd_new_assoc_sta;
22263ff40c12SJohn Marino hapd->iconf = conf;
22273ff40c12SJohn Marino hapd->conf = bss;
22283ff40c12SJohn Marino hapd->iface = hapd_iface;
2229*a1157835SDaniel Fojt if (conf)
2230*a1157835SDaniel Fojt hapd->driver = conf->driver;
22313ff40c12SJohn Marino hapd->ctrl_sock = -1;
2232*a1157835SDaniel Fojt dl_list_init(&hapd->ctrl_dst);
2233*a1157835SDaniel Fojt dl_list_init(&hapd->nr_db);
2234*a1157835SDaniel Fojt hapd->dhcp_sock = -1;
2235*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
2236*a1157835SDaniel Fojt dl_list_init(&hapd->l2_queue);
2237*a1157835SDaniel Fojt dl_list_init(&hapd->l2_oui_queue);
2238*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
2239*a1157835SDaniel Fojt #ifdef CONFIG_SAE
2240*a1157835SDaniel Fojt dl_list_init(&hapd->sae_commit_queue);
2241*a1157835SDaniel Fojt #endif /* CONFIG_SAE */
22423ff40c12SJohn Marino
22433ff40c12SJohn Marino return hapd;
22443ff40c12SJohn Marino }
22453ff40c12SJohn Marino
22463ff40c12SJohn Marino
hostapd_bss_deinit(struct hostapd_data * hapd)22473ff40c12SJohn Marino static void hostapd_bss_deinit(struct hostapd_data *hapd)
22483ff40c12SJohn Marino {
2249*a1157835SDaniel Fojt if (!hapd)
2250*a1157835SDaniel Fojt return;
22513ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "%s: deinit bss %s", __func__,
2252*a1157835SDaniel Fojt hapd->conf ? hapd->conf->iface : "N/A");
2253*a1157835SDaniel Fojt hostapd_bss_deinit_no_free(hapd);
2254*a1157835SDaniel Fojt wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
2255*a1157835SDaniel Fojt #ifdef CONFIG_SQLITE
2256*a1157835SDaniel Fojt if (hapd->rad_attr_db) {
2257*a1157835SDaniel Fojt sqlite3_close(hapd->rad_attr_db);
2258*a1157835SDaniel Fojt hapd->rad_attr_db = NULL;
2259*a1157835SDaniel Fojt }
2260*a1157835SDaniel Fojt #endif /* CONFIG_SQLITE */
22613ff40c12SJohn Marino hostapd_cleanup(hapd);
22623ff40c12SJohn Marino }
22633ff40c12SJohn Marino
22643ff40c12SJohn Marino
hostapd_interface_deinit(struct hostapd_iface * iface)22653ff40c12SJohn Marino void hostapd_interface_deinit(struct hostapd_iface *iface)
22663ff40c12SJohn Marino {
22673ff40c12SJohn Marino int j;
22683ff40c12SJohn Marino
22693ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
22703ff40c12SJohn Marino if (iface == NULL)
22713ff40c12SJohn Marino return;
22723ff40c12SJohn Marino
2273*a1157835SDaniel Fojt hostapd_set_state(iface, HAPD_IFACE_DISABLED);
2274*a1157835SDaniel Fojt
22753ff40c12SJohn Marino eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
22763ff40c12SJohn Marino iface->wait_channel_update = 0;
22773ff40c12SJohn Marino
2278*a1157835SDaniel Fojt #ifdef CONFIG_FST
2279*a1157835SDaniel Fojt if (iface->fst) {
2280*a1157835SDaniel Fojt fst_detach(iface->fst);
2281*a1157835SDaniel Fojt iface->fst = NULL;
2282*a1157835SDaniel Fojt }
2283*a1157835SDaniel Fojt #endif /* CONFIG_FST */
2284*a1157835SDaniel Fojt
2285*a1157835SDaniel Fojt for (j = (int) iface->num_bss - 1; j >= 0; j--) {
2286*a1157835SDaniel Fojt if (!iface->bss)
2287*a1157835SDaniel Fojt break;
22883ff40c12SJohn Marino hostapd_bss_deinit(iface->bss[j]);
22893ff40c12SJohn Marino }
22903ff40c12SJohn Marino
2291*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211N
2292*a1157835SDaniel Fojt #ifdef NEED_AP_MLME
2293*a1157835SDaniel Fojt hostapd_stop_setup_timers(iface);
2294*a1157835SDaniel Fojt eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL);
2295*a1157835SDaniel Fojt #endif /* NEED_AP_MLME */
2296*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211N */
2297*a1157835SDaniel Fojt }
2298*a1157835SDaniel Fojt
22993ff40c12SJohn Marino
hostapd_interface_free(struct hostapd_iface * iface)23003ff40c12SJohn Marino void hostapd_interface_free(struct hostapd_iface *iface)
23013ff40c12SJohn Marino {
23023ff40c12SJohn Marino size_t j;
23033ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
23043ff40c12SJohn Marino for (j = 0; j < iface->num_bss; j++) {
2305*a1157835SDaniel Fojt if (!iface->bss)
2306*a1157835SDaniel Fojt break;
23073ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "%s: free hapd %p",
23083ff40c12SJohn Marino __func__, iface->bss[j]);
23093ff40c12SJohn Marino os_free(iface->bss[j]);
23103ff40c12SJohn Marino }
23113ff40c12SJohn Marino hostapd_cleanup_iface(iface);
23123ff40c12SJohn Marino }
23133ff40c12SJohn Marino
23143ff40c12SJohn Marino
hostapd_alloc_iface(void)2315*a1157835SDaniel Fojt struct hostapd_iface * hostapd_alloc_iface(void)
2316*a1157835SDaniel Fojt {
2317*a1157835SDaniel Fojt struct hostapd_iface *hapd_iface;
2318*a1157835SDaniel Fojt
2319*a1157835SDaniel Fojt hapd_iface = os_zalloc(sizeof(*hapd_iface));
2320*a1157835SDaniel Fojt if (!hapd_iface)
2321*a1157835SDaniel Fojt return NULL;
2322*a1157835SDaniel Fojt
2323*a1157835SDaniel Fojt dl_list_init(&hapd_iface->sta_seen);
2324*a1157835SDaniel Fojt
2325*a1157835SDaniel Fojt return hapd_iface;
2326*a1157835SDaniel Fojt }
2327*a1157835SDaniel Fojt
2328*a1157835SDaniel Fojt
23293ff40c12SJohn Marino /**
23303ff40c12SJohn Marino * hostapd_init - Allocate and initialize per-interface data
23313ff40c12SJohn Marino * @config_file: Path to the configuration file
23323ff40c12SJohn Marino * Returns: Pointer to the allocated interface data or %NULL on failure
23333ff40c12SJohn Marino *
23343ff40c12SJohn Marino * This function is used to allocate main data structures for per-interface
23353ff40c12SJohn Marino * data. The allocated data buffer will be freed by calling
23363ff40c12SJohn Marino * hostapd_cleanup_iface().
23373ff40c12SJohn Marino */
hostapd_init(struct hapd_interfaces * interfaces,const char * config_file)23383ff40c12SJohn Marino struct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces,
23393ff40c12SJohn Marino const char *config_file)
23403ff40c12SJohn Marino {
23413ff40c12SJohn Marino struct hostapd_iface *hapd_iface = NULL;
23423ff40c12SJohn Marino struct hostapd_config *conf = NULL;
23433ff40c12SJohn Marino struct hostapd_data *hapd;
23443ff40c12SJohn Marino size_t i;
23453ff40c12SJohn Marino
2346*a1157835SDaniel Fojt hapd_iface = hostapd_alloc_iface();
23473ff40c12SJohn Marino if (hapd_iface == NULL)
23483ff40c12SJohn Marino goto fail;
23493ff40c12SJohn Marino
23503ff40c12SJohn Marino hapd_iface->config_fname = os_strdup(config_file);
23513ff40c12SJohn Marino if (hapd_iface->config_fname == NULL)
23523ff40c12SJohn Marino goto fail;
23533ff40c12SJohn Marino
23543ff40c12SJohn Marino conf = interfaces->config_read_cb(hapd_iface->config_fname);
23553ff40c12SJohn Marino if (conf == NULL)
23563ff40c12SJohn Marino goto fail;
23573ff40c12SJohn Marino hapd_iface->conf = conf;
23583ff40c12SJohn Marino
23593ff40c12SJohn Marino hapd_iface->num_bss = conf->num_bss;
23603ff40c12SJohn Marino hapd_iface->bss = os_calloc(conf->num_bss,
23613ff40c12SJohn Marino sizeof(struct hostapd_data *));
23623ff40c12SJohn Marino if (hapd_iface->bss == NULL)
23633ff40c12SJohn Marino goto fail;
23643ff40c12SJohn Marino
23653ff40c12SJohn Marino for (i = 0; i < conf->num_bss; i++) {
23663ff40c12SJohn Marino hapd = hapd_iface->bss[i] =
23673ff40c12SJohn Marino hostapd_alloc_bss_data(hapd_iface, conf,
23683ff40c12SJohn Marino conf->bss[i]);
23693ff40c12SJohn Marino if (hapd == NULL)
23703ff40c12SJohn Marino goto fail;
23713ff40c12SJohn Marino hapd->msg_ctx = hapd;
23723ff40c12SJohn Marino }
23733ff40c12SJohn Marino
23743ff40c12SJohn Marino return hapd_iface;
23753ff40c12SJohn Marino
23763ff40c12SJohn Marino fail:
23773ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Failed to set up interface with %s",
23783ff40c12SJohn Marino config_file);
23793ff40c12SJohn Marino if (conf)
23803ff40c12SJohn Marino hostapd_config_free(conf);
23813ff40c12SJohn Marino if (hapd_iface) {
23823ff40c12SJohn Marino os_free(hapd_iface->config_fname);
23833ff40c12SJohn Marino os_free(hapd_iface->bss);
23843ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "%s: free iface %p",
23853ff40c12SJohn Marino __func__, hapd_iface);
23863ff40c12SJohn Marino os_free(hapd_iface);
23873ff40c12SJohn Marino }
23883ff40c12SJohn Marino return NULL;
23893ff40c12SJohn Marino }
23903ff40c12SJohn Marino
23913ff40c12SJohn Marino
ifname_in_use(struct hapd_interfaces * interfaces,const char * ifname)23923ff40c12SJohn Marino static int ifname_in_use(struct hapd_interfaces *interfaces, const char *ifname)
23933ff40c12SJohn Marino {
23943ff40c12SJohn Marino size_t i, j;
23953ff40c12SJohn Marino
23963ff40c12SJohn Marino for (i = 0; i < interfaces->count; i++) {
23973ff40c12SJohn Marino struct hostapd_iface *iface = interfaces->iface[i];
23983ff40c12SJohn Marino for (j = 0; j < iface->num_bss; j++) {
23993ff40c12SJohn Marino struct hostapd_data *hapd = iface->bss[j];
24003ff40c12SJohn Marino if (os_strcmp(ifname, hapd->conf->iface) == 0)
24013ff40c12SJohn Marino return 1;
24023ff40c12SJohn Marino }
24033ff40c12SJohn Marino }
24043ff40c12SJohn Marino
24053ff40c12SJohn Marino return 0;
24063ff40c12SJohn Marino }
24073ff40c12SJohn Marino
24083ff40c12SJohn Marino
24093ff40c12SJohn Marino /**
24103ff40c12SJohn Marino * hostapd_interface_init_bss - Read configuration file and init BSS data
24113ff40c12SJohn Marino *
24123ff40c12SJohn Marino * This function is used to parse configuration file for a BSS. This BSS is
24133ff40c12SJohn Marino * added to an existing interface sharing the same radio (if any) or a new
24143ff40c12SJohn Marino * interface is created if this is the first interface on a radio. This
24153ff40c12SJohn Marino * allocate memory for the BSS. No actual driver operations are started.
24163ff40c12SJohn Marino *
24173ff40c12SJohn Marino * This is similar to hostapd_interface_init(), but for a case where the
24183ff40c12SJohn Marino * configuration is used to add a single BSS instead of all BSSes for a radio.
24193ff40c12SJohn Marino */
24203ff40c12SJohn Marino struct hostapd_iface *
hostapd_interface_init_bss(struct hapd_interfaces * interfaces,const char * phy,const char * config_fname,int debug)24213ff40c12SJohn Marino hostapd_interface_init_bss(struct hapd_interfaces *interfaces, const char *phy,
24223ff40c12SJohn Marino const char *config_fname, int debug)
24233ff40c12SJohn Marino {
24243ff40c12SJohn Marino struct hostapd_iface *new_iface = NULL, *iface = NULL;
24253ff40c12SJohn Marino struct hostapd_data *hapd;
24263ff40c12SJohn Marino int k;
24273ff40c12SJohn Marino size_t i, bss_idx;
24283ff40c12SJohn Marino
24293ff40c12SJohn Marino if (!phy || !*phy)
24303ff40c12SJohn Marino return NULL;
24313ff40c12SJohn Marino
24323ff40c12SJohn Marino for (i = 0; i < interfaces->count; i++) {
24333ff40c12SJohn Marino if (os_strcmp(interfaces->iface[i]->phy, phy) == 0) {
24343ff40c12SJohn Marino iface = interfaces->iface[i];
24353ff40c12SJohn Marino break;
24363ff40c12SJohn Marino }
24373ff40c12SJohn Marino }
24383ff40c12SJohn Marino
24393ff40c12SJohn Marino wpa_printf(MSG_INFO, "Configuration file: %s (phy %s)%s",
24403ff40c12SJohn Marino config_fname, phy, iface ? "" : " --> new PHY");
24413ff40c12SJohn Marino if (iface) {
24423ff40c12SJohn Marino struct hostapd_config *conf;
24433ff40c12SJohn Marino struct hostapd_bss_config **tmp_conf;
24443ff40c12SJohn Marino struct hostapd_data **tmp_bss;
24453ff40c12SJohn Marino struct hostapd_bss_config *bss;
24463ff40c12SJohn Marino const char *ifname;
24473ff40c12SJohn Marino
24483ff40c12SJohn Marino /* Add new BSS to existing iface */
24493ff40c12SJohn Marino conf = interfaces->config_read_cb(config_fname);
24503ff40c12SJohn Marino if (conf == NULL)
24513ff40c12SJohn Marino return NULL;
24523ff40c12SJohn Marino if (conf->num_bss > 1) {
24533ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Multiple BSSes specified in BSS-config");
24543ff40c12SJohn Marino hostapd_config_free(conf);
24553ff40c12SJohn Marino return NULL;
24563ff40c12SJohn Marino }
24573ff40c12SJohn Marino
24583ff40c12SJohn Marino ifname = conf->bss[0]->iface;
24593ff40c12SJohn Marino if (ifname[0] != '\0' && ifname_in_use(interfaces, ifname)) {
24603ff40c12SJohn Marino wpa_printf(MSG_ERROR,
24613ff40c12SJohn Marino "Interface name %s already in use", ifname);
24623ff40c12SJohn Marino hostapd_config_free(conf);
24633ff40c12SJohn Marino return NULL;
24643ff40c12SJohn Marino }
24653ff40c12SJohn Marino
24663ff40c12SJohn Marino tmp_conf = os_realloc_array(
24673ff40c12SJohn Marino iface->conf->bss, iface->conf->num_bss + 1,
24683ff40c12SJohn Marino sizeof(struct hostapd_bss_config *));
24693ff40c12SJohn Marino tmp_bss = os_realloc_array(iface->bss, iface->num_bss + 1,
24703ff40c12SJohn Marino sizeof(struct hostapd_data *));
24713ff40c12SJohn Marino if (tmp_bss)
24723ff40c12SJohn Marino iface->bss = tmp_bss;
24733ff40c12SJohn Marino if (tmp_conf) {
24743ff40c12SJohn Marino iface->conf->bss = tmp_conf;
24753ff40c12SJohn Marino iface->conf->last_bss = tmp_conf[0];
24763ff40c12SJohn Marino }
24773ff40c12SJohn Marino if (tmp_bss == NULL || tmp_conf == NULL) {
24783ff40c12SJohn Marino hostapd_config_free(conf);
24793ff40c12SJohn Marino return NULL;
24803ff40c12SJohn Marino }
24813ff40c12SJohn Marino bss = iface->conf->bss[iface->conf->num_bss] = conf->bss[0];
24823ff40c12SJohn Marino iface->conf->num_bss++;
24833ff40c12SJohn Marino
24843ff40c12SJohn Marino hapd = hostapd_alloc_bss_data(iface, iface->conf, bss);
24853ff40c12SJohn Marino if (hapd == NULL) {
24863ff40c12SJohn Marino iface->conf->num_bss--;
24873ff40c12SJohn Marino hostapd_config_free(conf);
24883ff40c12SJohn Marino return NULL;
24893ff40c12SJohn Marino }
24903ff40c12SJohn Marino iface->conf->last_bss = bss;
24913ff40c12SJohn Marino iface->bss[iface->num_bss] = hapd;
24923ff40c12SJohn Marino hapd->msg_ctx = hapd;
24933ff40c12SJohn Marino
24943ff40c12SJohn Marino bss_idx = iface->num_bss++;
24953ff40c12SJohn Marino conf->num_bss--;
24963ff40c12SJohn Marino conf->bss[0] = NULL;
24973ff40c12SJohn Marino hostapd_config_free(conf);
24983ff40c12SJohn Marino } else {
24993ff40c12SJohn Marino /* Add a new iface with the first BSS */
25003ff40c12SJohn Marino new_iface = iface = hostapd_init(interfaces, config_fname);
25013ff40c12SJohn Marino if (!iface)
25023ff40c12SJohn Marino return NULL;
25033ff40c12SJohn Marino os_strlcpy(iface->phy, phy, sizeof(iface->phy));
25043ff40c12SJohn Marino iface->interfaces = interfaces;
25053ff40c12SJohn Marino bss_idx = 0;
25063ff40c12SJohn Marino }
25073ff40c12SJohn Marino
25083ff40c12SJohn Marino for (k = 0; k < debug; k++) {
25093ff40c12SJohn Marino if (iface->bss[bss_idx]->conf->logger_stdout_level > 0)
25103ff40c12SJohn Marino iface->bss[bss_idx]->conf->logger_stdout_level--;
25113ff40c12SJohn Marino }
25123ff40c12SJohn Marino
25133ff40c12SJohn Marino if (iface->conf->bss[bss_idx]->iface[0] == '\0' &&
25143ff40c12SJohn Marino !hostapd_drv_none(iface->bss[bss_idx])) {
25153ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Interface name not specified in %s",
25163ff40c12SJohn Marino config_fname);
25173ff40c12SJohn Marino if (new_iface)
25183ff40c12SJohn Marino hostapd_interface_deinit_free(new_iface);
25193ff40c12SJohn Marino return NULL;
25203ff40c12SJohn Marino }
25213ff40c12SJohn Marino
25223ff40c12SJohn Marino return iface;
25233ff40c12SJohn Marino }
25243ff40c12SJohn Marino
25253ff40c12SJohn Marino
hostapd_interface_deinit_free(struct hostapd_iface * iface)25263ff40c12SJohn Marino void hostapd_interface_deinit_free(struct hostapd_iface *iface)
25273ff40c12SJohn Marino {
25283ff40c12SJohn Marino const struct wpa_driver_ops *driver;
25293ff40c12SJohn Marino void *drv_priv;
25303ff40c12SJohn Marino
25313ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
25323ff40c12SJohn Marino if (iface == NULL)
25333ff40c12SJohn Marino return;
25343ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "%s: num_bss=%u conf->num_bss=%u",
25353ff40c12SJohn Marino __func__, (unsigned int) iface->num_bss,
25363ff40c12SJohn Marino (unsigned int) iface->conf->num_bss);
25373ff40c12SJohn Marino driver = iface->bss[0]->driver;
25383ff40c12SJohn Marino drv_priv = iface->bss[0]->drv_priv;
25393ff40c12SJohn Marino hostapd_interface_deinit(iface);
25403ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit",
25413ff40c12SJohn Marino __func__, driver, drv_priv);
2542*a1157835SDaniel Fojt if (driver && driver->hapd_deinit && drv_priv) {
25433ff40c12SJohn Marino driver->hapd_deinit(drv_priv);
2544*a1157835SDaniel Fojt iface->bss[0]->drv_priv = NULL;
2545*a1157835SDaniel Fojt }
25463ff40c12SJohn Marino hostapd_interface_free(iface);
25473ff40c12SJohn Marino }
25483ff40c12SJohn Marino
25493ff40c12SJohn Marino
hostapd_deinit_driver(const struct wpa_driver_ops * driver,void * drv_priv,struct hostapd_iface * hapd_iface)2550*a1157835SDaniel Fojt static void hostapd_deinit_driver(const struct wpa_driver_ops *driver,
2551*a1157835SDaniel Fojt void *drv_priv,
2552*a1157835SDaniel Fojt struct hostapd_iface *hapd_iface)
2553*a1157835SDaniel Fojt {
2554*a1157835SDaniel Fojt size_t j;
2555*a1157835SDaniel Fojt
2556*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit",
2557*a1157835SDaniel Fojt __func__, driver, drv_priv);
2558*a1157835SDaniel Fojt if (driver && driver->hapd_deinit && drv_priv) {
2559*a1157835SDaniel Fojt driver->hapd_deinit(drv_priv);
2560*a1157835SDaniel Fojt for (j = 0; j < hapd_iface->num_bss; j++) {
2561*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "%s:bss[%d]->drv_priv=%p",
2562*a1157835SDaniel Fojt __func__, (int) j,
2563*a1157835SDaniel Fojt hapd_iface->bss[j]->drv_priv);
2564*a1157835SDaniel Fojt if (hapd_iface->bss[j]->drv_priv == drv_priv) {
2565*a1157835SDaniel Fojt hapd_iface->bss[j]->drv_priv = NULL;
2566*a1157835SDaniel Fojt hapd_iface->extended_capa = NULL;
2567*a1157835SDaniel Fojt hapd_iface->extended_capa_mask = NULL;
2568*a1157835SDaniel Fojt hapd_iface->extended_capa_len = 0;
2569*a1157835SDaniel Fojt }
2570*a1157835SDaniel Fojt }
2571*a1157835SDaniel Fojt }
2572*a1157835SDaniel Fojt }
2573*a1157835SDaniel Fojt
2574*a1157835SDaniel Fojt
hostapd_enable_iface(struct hostapd_iface * hapd_iface)25753ff40c12SJohn Marino int hostapd_enable_iface(struct hostapd_iface *hapd_iface)
25763ff40c12SJohn Marino {
2577*a1157835SDaniel Fojt size_t j;
2578*a1157835SDaniel Fojt
25793ff40c12SJohn Marino if (hapd_iface->bss[0]->drv_priv != NULL) {
25803ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Interface %s already enabled",
25813ff40c12SJohn Marino hapd_iface->conf->bss[0]->iface);
25823ff40c12SJohn Marino return -1;
25833ff40c12SJohn Marino }
25843ff40c12SJohn Marino
25853ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Enable interface %s",
25863ff40c12SJohn Marino hapd_iface->conf->bss[0]->iface);
25873ff40c12SJohn Marino
2588*a1157835SDaniel Fojt for (j = 0; j < hapd_iface->num_bss; j++)
2589*a1157835SDaniel Fojt hostapd_set_security_params(hapd_iface->conf->bss[j], 1);
25903ff40c12SJohn Marino if (hostapd_config_check(hapd_iface->conf, 1) < 0) {
25913ff40c12SJohn Marino wpa_printf(MSG_INFO, "Invalid configuration - cannot enable");
25923ff40c12SJohn Marino return -1;
25933ff40c12SJohn Marino }
25943ff40c12SJohn Marino
25953ff40c12SJohn Marino if (hapd_iface->interfaces == NULL ||
25963ff40c12SJohn Marino hapd_iface->interfaces->driver_init == NULL ||
25973ff40c12SJohn Marino hapd_iface->interfaces->driver_init(hapd_iface))
25983ff40c12SJohn Marino return -1;
25993ff40c12SJohn Marino
26003ff40c12SJohn Marino if (hostapd_setup_interface(hapd_iface)) {
2601*a1157835SDaniel Fojt hostapd_deinit_driver(hapd_iface->bss[0]->driver,
2602*a1157835SDaniel Fojt hapd_iface->bss[0]->drv_priv,
2603*a1157835SDaniel Fojt hapd_iface);
26043ff40c12SJohn Marino return -1;
26053ff40c12SJohn Marino }
26063ff40c12SJohn Marino
26073ff40c12SJohn Marino return 0;
26083ff40c12SJohn Marino }
26093ff40c12SJohn Marino
26103ff40c12SJohn Marino
hostapd_reload_iface(struct hostapd_iface * hapd_iface)26113ff40c12SJohn Marino int hostapd_reload_iface(struct hostapd_iface *hapd_iface)
26123ff40c12SJohn Marino {
26133ff40c12SJohn Marino size_t j;
26143ff40c12SJohn Marino
26153ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Reload interface %s",
26163ff40c12SJohn Marino hapd_iface->conf->bss[0]->iface);
26173ff40c12SJohn Marino for (j = 0; j < hapd_iface->num_bss; j++)
2618*a1157835SDaniel Fojt hostapd_set_security_params(hapd_iface->conf->bss[j], 1);
26193ff40c12SJohn Marino if (hostapd_config_check(hapd_iface->conf, 1) < 0) {
26203ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Updated configuration is invalid");
26213ff40c12SJohn Marino return -1;
26223ff40c12SJohn Marino }
26233ff40c12SJohn Marino hostapd_clear_old(hapd_iface);
26243ff40c12SJohn Marino for (j = 0; j < hapd_iface->num_bss; j++)
26253ff40c12SJohn Marino hostapd_reload_bss(hapd_iface->bss[j]);
26263ff40c12SJohn Marino
26273ff40c12SJohn Marino return 0;
26283ff40c12SJohn Marino }
26293ff40c12SJohn Marino
26303ff40c12SJohn Marino
hostapd_disable_iface(struct hostapd_iface * hapd_iface)26313ff40c12SJohn Marino int hostapd_disable_iface(struct hostapd_iface *hapd_iface)
26323ff40c12SJohn Marino {
26333ff40c12SJohn Marino size_t j;
26343ff40c12SJohn Marino const struct wpa_driver_ops *driver;
26353ff40c12SJohn Marino void *drv_priv;
26363ff40c12SJohn Marino
26373ff40c12SJohn Marino if (hapd_iface == NULL)
26383ff40c12SJohn Marino return -1;
2639*a1157835SDaniel Fojt
2640*a1157835SDaniel Fojt if (hapd_iface->bss[0]->drv_priv == NULL) {
2641*a1157835SDaniel Fojt wpa_printf(MSG_INFO, "Interface %s already disabled",
2642*a1157835SDaniel Fojt hapd_iface->conf->bss[0]->iface);
2643*a1157835SDaniel Fojt return -1;
2644*a1157835SDaniel Fojt }
2645*a1157835SDaniel Fojt
26463ff40c12SJohn Marino wpa_msg(hapd_iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
26473ff40c12SJohn Marino driver = hapd_iface->bss[0]->driver;
26483ff40c12SJohn Marino drv_priv = hapd_iface->bss[0]->drv_priv;
26493ff40c12SJohn Marino
2650*a1157835SDaniel Fojt hapd_iface->driver_ap_teardown =
2651*a1157835SDaniel Fojt !!(hapd_iface->drv_flags &
2652*a1157835SDaniel Fojt WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
2653*a1157835SDaniel Fojt
2654*a1157835SDaniel Fojt #ifdef NEED_AP_MLME
2655*a1157835SDaniel Fojt for (j = 0; j < hapd_iface->num_bss; j++)
2656*a1157835SDaniel Fojt hostapd_cleanup_cs_params(hapd_iface->bss[j]);
2657*a1157835SDaniel Fojt #endif /* NEED_AP_MLME */
2658*a1157835SDaniel Fojt
2659*a1157835SDaniel Fojt /* same as hostapd_interface_deinit without deinitializing ctrl-iface */
26603ff40c12SJohn Marino for (j = 0; j < hapd_iface->num_bss; j++) {
26613ff40c12SJohn Marino struct hostapd_data *hapd = hapd_iface->bss[j];
2662*a1157835SDaniel Fojt hostapd_bss_deinit_no_free(hapd);
26633ff40c12SJohn Marino hostapd_free_hapd_data(hapd);
26643ff40c12SJohn Marino }
26653ff40c12SJohn Marino
2666*a1157835SDaniel Fojt hostapd_deinit_driver(driver, drv_priv, hapd_iface);
26673ff40c12SJohn Marino
26683ff40c12SJohn Marino /* From hostapd_cleanup_iface: These were initialized in
26693ff40c12SJohn Marino * hostapd_setup_interface and hostapd_setup_interface_complete
26703ff40c12SJohn Marino */
26713ff40c12SJohn Marino hostapd_cleanup_iface_partial(hapd_iface);
26723ff40c12SJohn Marino
26733ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Interface %s disabled",
26743ff40c12SJohn Marino hapd_iface->bss[0]->conf->iface);
26753ff40c12SJohn Marino hostapd_set_state(hapd_iface, HAPD_IFACE_DISABLED);
26763ff40c12SJohn Marino return 0;
26773ff40c12SJohn Marino }
26783ff40c12SJohn Marino
26793ff40c12SJohn Marino
26803ff40c12SJohn Marino static struct hostapd_iface *
hostapd_iface_alloc(struct hapd_interfaces * interfaces)26813ff40c12SJohn Marino hostapd_iface_alloc(struct hapd_interfaces *interfaces)
26823ff40c12SJohn Marino {
26833ff40c12SJohn Marino struct hostapd_iface **iface, *hapd_iface;
26843ff40c12SJohn Marino
26853ff40c12SJohn Marino iface = os_realloc_array(interfaces->iface, interfaces->count + 1,
26863ff40c12SJohn Marino sizeof(struct hostapd_iface *));
26873ff40c12SJohn Marino if (iface == NULL)
26883ff40c12SJohn Marino return NULL;
26893ff40c12SJohn Marino interfaces->iface = iface;
26903ff40c12SJohn Marino hapd_iface = interfaces->iface[interfaces->count] =
2691*a1157835SDaniel Fojt hostapd_alloc_iface();
26923ff40c12SJohn Marino if (hapd_iface == NULL) {
26933ff40c12SJohn Marino wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for "
26943ff40c12SJohn Marino "the interface", __func__);
26953ff40c12SJohn Marino return NULL;
26963ff40c12SJohn Marino }
26973ff40c12SJohn Marino interfaces->count++;
26983ff40c12SJohn Marino hapd_iface->interfaces = interfaces;
26993ff40c12SJohn Marino
27003ff40c12SJohn Marino return hapd_iface;
27013ff40c12SJohn Marino }
27023ff40c12SJohn Marino
27033ff40c12SJohn Marino
27043ff40c12SJohn Marino static struct hostapd_config *
hostapd_config_alloc(struct hapd_interfaces * interfaces,const char * ifname,const char * ctrl_iface,const char * driver)27053ff40c12SJohn Marino hostapd_config_alloc(struct hapd_interfaces *interfaces, const char *ifname,
2706*a1157835SDaniel Fojt const char *ctrl_iface, const char *driver)
27073ff40c12SJohn Marino {
27083ff40c12SJohn Marino struct hostapd_bss_config *bss;
27093ff40c12SJohn Marino struct hostapd_config *conf;
27103ff40c12SJohn Marino
27113ff40c12SJohn Marino /* Allocates memory for bss and conf */
27123ff40c12SJohn Marino conf = hostapd_config_defaults();
27133ff40c12SJohn Marino if (conf == NULL) {
27143ff40c12SJohn Marino wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for "
27153ff40c12SJohn Marino "configuration", __func__);
27163ff40c12SJohn Marino return NULL;
27173ff40c12SJohn Marino }
27183ff40c12SJohn Marino
2719*a1157835SDaniel Fojt if (driver) {
2720*a1157835SDaniel Fojt int j;
2721*a1157835SDaniel Fojt
2722*a1157835SDaniel Fojt for (j = 0; wpa_drivers[j]; j++) {
2723*a1157835SDaniel Fojt if (os_strcmp(driver, wpa_drivers[j]->name) == 0) {
2724*a1157835SDaniel Fojt conf->driver = wpa_drivers[j];
2725*a1157835SDaniel Fojt goto skip;
2726*a1157835SDaniel Fojt }
2727*a1157835SDaniel Fojt }
2728*a1157835SDaniel Fojt
2729*a1157835SDaniel Fojt wpa_printf(MSG_ERROR,
2730*a1157835SDaniel Fojt "Invalid/unknown driver '%s' - registering the default driver",
2731*a1157835SDaniel Fojt driver);
2732*a1157835SDaniel Fojt }
2733*a1157835SDaniel Fojt
27343ff40c12SJohn Marino conf->driver = wpa_drivers[0];
27353ff40c12SJohn Marino if (conf->driver == NULL) {
27363ff40c12SJohn Marino wpa_printf(MSG_ERROR, "No driver wrappers registered!");
27373ff40c12SJohn Marino hostapd_config_free(conf);
27383ff40c12SJohn Marino return NULL;
27393ff40c12SJohn Marino }
27403ff40c12SJohn Marino
2741*a1157835SDaniel Fojt skip:
27423ff40c12SJohn Marino bss = conf->last_bss = conf->bss[0];
27433ff40c12SJohn Marino
27443ff40c12SJohn Marino os_strlcpy(bss->iface, ifname, sizeof(bss->iface));
27453ff40c12SJohn Marino bss->ctrl_interface = os_strdup(ctrl_iface);
27463ff40c12SJohn Marino if (bss->ctrl_interface == NULL) {
27473ff40c12SJohn Marino hostapd_config_free(conf);
27483ff40c12SJohn Marino return NULL;
27493ff40c12SJohn Marino }
27503ff40c12SJohn Marino
27513ff40c12SJohn Marino /* Reading configuration file skipped, will be done in SET!
27523ff40c12SJohn Marino * From reading the configuration till the end has to be done in
27533ff40c12SJohn Marino * SET
27543ff40c12SJohn Marino */
27553ff40c12SJohn Marino return conf;
27563ff40c12SJohn Marino }
27573ff40c12SJohn Marino
27583ff40c12SJohn Marino
hostapd_data_alloc(struct hostapd_iface * hapd_iface,struct hostapd_config * conf)2759*a1157835SDaniel Fojt static int hostapd_data_alloc(struct hostapd_iface *hapd_iface,
2760*a1157835SDaniel Fojt struct hostapd_config *conf)
27613ff40c12SJohn Marino {
27623ff40c12SJohn Marino size_t i;
27633ff40c12SJohn Marino struct hostapd_data *hapd;
27643ff40c12SJohn Marino
2765*a1157835SDaniel Fojt hapd_iface->bss = os_calloc(conf->num_bss,
27663ff40c12SJohn Marino sizeof(struct hostapd_data *));
27673ff40c12SJohn Marino if (hapd_iface->bss == NULL)
2768*a1157835SDaniel Fojt return -1;
27693ff40c12SJohn Marino
27703ff40c12SJohn Marino for (i = 0; i < conf->num_bss; i++) {
27713ff40c12SJohn Marino hapd = hapd_iface->bss[i] =
27723ff40c12SJohn Marino hostapd_alloc_bss_data(hapd_iface, conf, conf->bss[i]);
2773*a1157835SDaniel Fojt if (hapd == NULL) {
2774*a1157835SDaniel Fojt while (i > 0) {
2775*a1157835SDaniel Fojt i--;
2776*a1157835SDaniel Fojt os_free(hapd_iface->bss[i]);
2777*a1157835SDaniel Fojt hapd_iface->bss[i] = NULL;
2778*a1157835SDaniel Fojt }
2779*a1157835SDaniel Fojt os_free(hapd_iface->bss);
2780*a1157835SDaniel Fojt hapd_iface->bss = NULL;
2781*a1157835SDaniel Fojt return -1;
2782*a1157835SDaniel Fojt }
27833ff40c12SJohn Marino hapd->msg_ctx = hapd;
27843ff40c12SJohn Marino }
27853ff40c12SJohn Marino
2786*a1157835SDaniel Fojt hapd_iface->conf = conf;
2787*a1157835SDaniel Fojt hapd_iface->num_bss = conf->num_bss;
27883ff40c12SJohn Marino
2789*a1157835SDaniel Fojt return 0;
27903ff40c12SJohn Marino }
27913ff40c12SJohn Marino
27923ff40c12SJohn Marino
hostapd_add_iface(struct hapd_interfaces * interfaces,char * buf)27933ff40c12SJohn Marino int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf)
27943ff40c12SJohn Marino {
27953ff40c12SJohn Marino struct hostapd_config *conf = NULL;
27963ff40c12SJohn Marino struct hostapd_iface *hapd_iface = NULL, *new_iface = NULL;
27973ff40c12SJohn Marino struct hostapd_data *hapd;
27983ff40c12SJohn Marino char *ptr;
27993ff40c12SJohn Marino size_t i, j;
28003ff40c12SJohn Marino const char *conf_file = NULL, *phy_name = NULL;
28013ff40c12SJohn Marino
28023ff40c12SJohn Marino if (os_strncmp(buf, "bss_config=", 11) == 0) {
28033ff40c12SJohn Marino char *pos;
28043ff40c12SJohn Marino phy_name = buf + 11;
28053ff40c12SJohn Marino pos = os_strchr(phy_name, ':');
28063ff40c12SJohn Marino if (!pos)
28073ff40c12SJohn Marino return -1;
28083ff40c12SJohn Marino *pos++ = '\0';
28093ff40c12SJohn Marino conf_file = pos;
28103ff40c12SJohn Marino if (!os_strlen(conf_file))
28113ff40c12SJohn Marino return -1;
28123ff40c12SJohn Marino
28133ff40c12SJohn Marino hapd_iface = hostapd_interface_init_bss(interfaces, phy_name,
28143ff40c12SJohn Marino conf_file, 0);
28153ff40c12SJohn Marino if (!hapd_iface)
28163ff40c12SJohn Marino return -1;
28173ff40c12SJohn Marino for (j = 0; j < interfaces->count; j++) {
28183ff40c12SJohn Marino if (interfaces->iface[j] == hapd_iface)
28193ff40c12SJohn Marino break;
28203ff40c12SJohn Marino }
28213ff40c12SJohn Marino if (j == interfaces->count) {
28223ff40c12SJohn Marino struct hostapd_iface **tmp;
28233ff40c12SJohn Marino tmp = os_realloc_array(interfaces->iface,
28243ff40c12SJohn Marino interfaces->count + 1,
28253ff40c12SJohn Marino sizeof(struct hostapd_iface *));
28263ff40c12SJohn Marino if (!tmp) {
28273ff40c12SJohn Marino hostapd_interface_deinit_free(hapd_iface);
28283ff40c12SJohn Marino return -1;
28293ff40c12SJohn Marino }
28303ff40c12SJohn Marino interfaces->iface = tmp;
28313ff40c12SJohn Marino interfaces->iface[interfaces->count++] = hapd_iface;
28323ff40c12SJohn Marino new_iface = hapd_iface;
28333ff40c12SJohn Marino }
28343ff40c12SJohn Marino
28353ff40c12SJohn Marino if (new_iface) {
2836*a1157835SDaniel Fojt if (interfaces->driver_init(hapd_iface))
2837*a1157835SDaniel Fojt goto fail;
2838*a1157835SDaniel Fojt
2839*a1157835SDaniel Fojt if (hostapd_setup_interface(hapd_iface)) {
2840*a1157835SDaniel Fojt hostapd_deinit_driver(
2841*a1157835SDaniel Fojt hapd_iface->bss[0]->driver,
2842*a1157835SDaniel Fojt hapd_iface->bss[0]->drv_priv,
2843*a1157835SDaniel Fojt hapd_iface);
28443ff40c12SJohn Marino goto fail;
28453ff40c12SJohn Marino }
28463ff40c12SJohn Marino } else {
28473ff40c12SJohn Marino /* Assign new BSS with bss[0]'s driver info */
28483ff40c12SJohn Marino hapd = hapd_iface->bss[hapd_iface->num_bss - 1];
28493ff40c12SJohn Marino hapd->driver = hapd_iface->bss[0]->driver;
28503ff40c12SJohn Marino hapd->drv_priv = hapd_iface->bss[0]->drv_priv;
28513ff40c12SJohn Marino os_memcpy(hapd->own_addr, hapd_iface->bss[0]->own_addr,
28523ff40c12SJohn Marino ETH_ALEN);
28533ff40c12SJohn Marino
28543ff40c12SJohn Marino if (start_ctrl_iface_bss(hapd) < 0 ||
28553ff40c12SJohn Marino (hapd_iface->state == HAPD_IFACE_ENABLED &&
28563ff40c12SJohn Marino hostapd_setup_bss(hapd, -1))) {
2857*a1157835SDaniel Fojt hostapd_cleanup(hapd);
2858*a1157835SDaniel Fojt hapd_iface->bss[hapd_iface->num_bss - 1] = NULL;
28593ff40c12SJohn Marino hapd_iface->conf->num_bss--;
28603ff40c12SJohn Marino hapd_iface->num_bss--;
28613ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "%s: free hapd %p %s",
28623ff40c12SJohn Marino __func__, hapd, hapd->conf->iface);
2863*a1157835SDaniel Fojt hostapd_config_free_bss(hapd->conf);
2864*a1157835SDaniel Fojt hapd->conf = NULL;
28653ff40c12SJohn Marino os_free(hapd);
28663ff40c12SJohn Marino return -1;
28673ff40c12SJohn Marino }
28683ff40c12SJohn Marino }
2869*a1157835SDaniel Fojt hostapd_owe_update_trans(hapd_iface);
28703ff40c12SJohn Marino return 0;
28713ff40c12SJohn Marino }
28723ff40c12SJohn Marino
28733ff40c12SJohn Marino ptr = os_strchr(buf, ' ');
28743ff40c12SJohn Marino if (ptr == NULL)
28753ff40c12SJohn Marino return -1;
28763ff40c12SJohn Marino *ptr++ = '\0';
28773ff40c12SJohn Marino
28783ff40c12SJohn Marino if (os_strncmp(ptr, "config=", 7) == 0)
28793ff40c12SJohn Marino conf_file = ptr + 7;
28803ff40c12SJohn Marino
28813ff40c12SJohn Marino for (i = 0; i < interfaces->count; i++) {
28823ff40c12SJohn Marino if (!os_strcmp(interfaces->iface[i]->conf->bss[0]->iface,
28833ff40c12SJohn Marino buf)) {
28843ff40c12SJohn Marino wpa_printf(MSG_INFO, "Cannot add interface - it "
28853ff40c12SJohn Marino "already exists");
28863ff40c12SJohn Marino return -1;
28873ff40c12SJohn Marino }
28883ff40c12SJohn Marino }
28893ff40c12SJohn Marino
28903ff40c12SJohn Marino hapd_iface = hostapd_iface_alloc(interfaces);
28913ff40c12SJohn Marino if (hapd_iface == NULL) {
28923ff40c12SJohn Marino wpa_printf(MSG_ERROR, "%s: Failed to allocate memory "
28933ff40c12SJohn Marino "for interface", __func__);
28943ff40c12SJohn Marino goto fail;
28953ff40c12SJohn Marino }
2896*a1157835SDaniel Fojt new_iface = hapd_iface;
28973ff40c12SJohn Marino
28983ff40c12SJohn Marino if (conf_file && interfaces->config_read_cb) {
28993ff40c12SJohn Marino conf = interfaces->config_read_cb(conf_file);
29003ff40c12SJohn Marino if (conf && conf->bss)
29013ff40c12SJohn Marino os_strlcpy(conf->bss[0]->iface, buf,
29023ff40c12SJohn Marino sizeof(conf->bss[0]->iface));
2903*a1157835SDaniel Fojt } else {
2904*a1157835SDaniel Fojt char *driver = os_strchr(ptr, ' ');
2905*a1157835SDaniel Fojt
2906*a1157835SDaniel Fojt if (driver)
2907*a1157835SDaniel Fojt *driver++ = '\0';
2908*a1157835SDaniel Fojt conf = hostapd_config_alloc(interfaces, buf, ptr, driver);
2909*a1157835SDaniel Fojt }
2910*a1157835SDaniel Fojt
29113ff40c12SJohn Marino if (conf == NULL || conf->bss == NULL) {
29123ff40c12SJohn Marino wpa_printf(MSG_ERROR, "%s: Failed to allocate memory "
29133ff40c12SJohn Marino "for configuration", __func__);
29143ff40c12SJohn Marino goto fail;
29153ff40c12SJohn Marino }
29163ff40c12SJohn Marino
2917*a1157835SDaniel Fojt if (hostapd_data_alloc(hapd_iface, conf) < 0) {
29183ff40c12SJohn Marino wpa_printf(MSG_ERROR, "%s: Failed to allocate memory "
29193ff40c12SJohn Marino "for hostapd", __func__);
29203ff40c12SJohn Marino goto fail;
29213ff40c12SJohn Marino }
2922*a1157835SDaniel Fojt conf = NULL;
29233ff40c12SJohn Marino
29243ff40c12SJohn Marino if (start_ctrl_iface(hapd_iface) < 0)
29253ff40c12SJohn Marino goto fail;
29263ff40c12SJohn Marino
2927*a1157835SDaniel Fojt wpa_printf(MSG_INFO, "Add interface '%s'",
2928*a1157835SDaniel Fojt hapd_iface->conf->bss[0]->iface);
29293ff40c12SJohn Marino
29303ff40c12SJohn Marino return 0;
29313ff40c12SJohn Marino
29323ff40c12SJohn Marino fail:
29333ff40c12SJohn Marino if (conf)
29343ff40c12SJohn Marino hostapd_config_free(conf);
29353ff40c12SJohn Marino if (hapd_iface) {
29363ff40c12SJohn Marino if (hapd_iface->bss) {
29373ff40c12SJohn Marino for (i = 0; i < hapd_iface->num_bss; i++) {
29383ff40c12SJohn Marino hapd = hapd_iface->bss[i];
2939*a1157835SDaniel Fojt if (!hapd)
2940*a1157835SDaniel Fojt continue;
2941*a1157835SDaniel Fojt if (hapd_iface->interfaces &&
29423ff40c12SJohn Marino hapd_iface->interfaces->ctrl_iface_deinit)
29433ff40c12SJohn Marino hapd_iface->interfaces->
29443ff40c12SJohn Marino ctrl_iface_deinit(hapd);
29453ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "%s: free hapd %p (%s)",
29463ff40c12SJohn Marino __func__, hapd_iface->bss[i],
2947*a1157835SDaniel Fojt hapd->conf->iface);
2948*a1157835SDaniel Fojt hostapd_cleanup(hapd);
2949*a1157835SDaniel Fojt os_free(hapd);
2950*a1157835SDaniel Fojt hapd_iface->bss[i] = NULL;
29513ff40c12SJohn Marino }
29523ff40c12SJohn Marino os_free(hapd_iface->bss);
2953*a1157835SDaniel Fojt hapd_iface->bss = NULL;
29543ff40c12SJohn Marino }
2955*a1157835SDaniel Fojt if (new_iface) {
2956*a1157835SDaniel Fojt interfaces->count--;
2957*a1157835SDaniel Fojt interfaces->iface[interfaces->count] = NULL;
2958*a1157835SDaniel Fojt }
2959*a1157835SDaniel Fojt hostapd_cleanup_iface(hapd_iface);
29603ff40c12SJohn Marino }
29613ff40c12SJohn Marino return -1;
29623ff40c12SJohn Marino }
29633ff40c12SJohn Marino
29643ff40c12SJohn Marino
hostapd_remove_bss(struct hostapd_iface * iface,unsigned int idx)29653ff40c12SJohn Marino static int hostapd_remove_bss(struct hostapd_iface *iface, unsigned int idx)
29663ff40c12SJohn Marino {
29673ff40c12SJohn Marino size_t i;
29683ff40c12SJohn Marino
29693ff40c12SJohn Marino wpa_printf(MSG_INFO, "Remove BSS '%s'", iface->conf->bss[idx]->iface);
29703ff40c12SJohn Marino
29713ff40c12SJohn Marino /* Remove hostapd_data only if it has already been initialized */
29723ff40c12SJohn Marino if (idx < iface->num_bss) {
29733ff40c12SJohn Marino struct hostapd_data *hapd = iface->bss[idx];
29743ff40c12SJohn Marino
29753ff40c12SJohn Marino hostapd_bss_deinit(hapd);
29763ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "%s: free hapd %p (%s)",
29773ff40c12SJohn Marino __func__, hapd, hapd->conf->iface);
29783ff40c12SJohn Marino hostapd_config_free_bss(hapd->conf);
2979*a1157835SDaniel Fojt hapd->conf = NULL;
29803ff40c12SJohn Marino os_free(hapd);
29813ff40c12SJohn Marino
29823ff40c12SJohn Marino iface->num_bss--;
29833ff40c12SJohn Marino
29843ff40c12SJohn Marino for (i = idx; i < iface->num_bss; i++)
29853ff40c12SJohn Marino iface->bss[i] = iface->bss[i + 1];
29863ff40c12SJohn Marino } else {
29873ff40c12SJohn Marino hostapd_config_free_bss(iface->conf->bss[idx]);
29883ff40c12SJohn Marino iface->conf->bss[idx] = NULL;
29893ff40c12SJohn Marino }
29903ff40c12SJohn Marino
29913ff40c12SJohn Marino iface->conf->num_bss--;
29923ff40c12SJohn Marino for (i = idx; i < iface->conf->num_bss; i++)
29933ff40c12SJohn Marino iface->conf->bss[i] = iface->conf->bss[i + 1];
29943ff40c12SJohn Marino
29953ff40c12SJohn Marino return 0;
29963ff40c12SJohn Marino }
29973ff40c12SJohn Marino
29983ff40c12SJohn Marino
hostapd_remove_iface(struct hapd_interfaces * interfaces,char * buf)29993ff40c12SJohn Marino int hostapd_remove_iface(struct hapd_interfaces *interfaces, char *buf)
30003ff40c12SJohn Marino {
30013ff40c12SJohn Marino struct hostapd_iface *hapd_iface;
30023ff40c12SJohn Marino size_t i, j, k = 0;
30033ff40c12SJohn Marino
30043ff40c12SJohn Marino for (i = 0; i < interfaces->count; i++) {
30053ff40c12SJohn Marino hapd_iface = interfaces->iface[i];
30063ff40c12SJohn Marino if (hapd_iface == NULL)
30073ff40c12SJohn Marino return -1;
30083ff40c12SJohn Marino if (!os_strcmp(hapd_iface->conf->bss[0]->iface, buf)) {
30093ff40c12SJohn Marino wpa_printf(MSG_INFO, "Remove interface '%s'", buf);
3010*a1157835SDaniel Fojt hapd_iface->driver_ap_teardown =
3011*a1157835SDaniel Fojt !!(hapd_iface->drv_flags &
3012*a1157835SDaniel Fojt WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
3013*a1157835SDaniel Fojt
30143ff40c12SJohn Marino hostapd_interface_deinit_free(hapd_iface);
30153ff40c12SJohn Marino k = i;
30163ff40c12SJohn Marino while (k < (interfaces->count - 1)) {
30173ff40c12SJohn Marino interfaces->iface[k] =
30183ff40c12SJohn Marino interfaces->iface[k + 1];
30193ff40c12SJohn Marino k++;
30203ff40c12SJohn Marino }
30213ff40c12SJohn Marino interfaces->count--;
30223ff40c12SJohn Marino return 0;
30233ff40c12SJohn Marino }
30243ff40c12SJohn Marino
30253ff40c12SJohn Marino for (j = 0; j < hapd_iface->conf->num_bss; j++) {
3026*a1157835SDaniel Fojt if (!os_strcmp(hapd_iface->conf->bss[j]->iface, buf)) {
3027*a1157835SDaniel Fojt hapd_iface->driver_ap_teardown =
3028*a1157835SDaniel Fojt !(hapd_iface->drv_flags &
3029*a1157835SDaniel Fojt WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
30303ff40c12SJohn Marino return hostapd_remove_bss(hapd_iface, j);
30313ff40c12SJohn Marino }
30323ff40c12SJohn Marino }
3033*a1157835SDaniel Fojt }
30343ff40c12SJohn Marino return -1;
30353ff40c12SJohn Marino }
30363ff40c12SJohn Marino
30373ff40c12SJohn Marino
30383ff40c12SJohn Marino /**
30393ff40c12SJohn Marino * hostapd_new_assoc_sta - Notify that a new station associated with the AP
30403ff40c12SJohn Marino * @hapd: Pointer to BSS data
30413ff40c12SJohn Marino * @sta: Pointer to the associated STA data
30423ff40c12SJohn Marino * @reassoc: 1 to indicate this was a re-association; 0 = first association
30433ff40c12SJohn Marino *
30443ff40c12SJohn Marino * This function will be called whenever a station associates with the AP. It
30453ff40c12SJohn Marino * can be called from ieee802_11.c for drivers that export MLME to hostapd and
30463ff40c12SJohn Marino * from drv_callbacks.c based on driver events for drivers that take care of
30473ff40c12SJohn Marino * management frames (IEEE 802.11 authentication and association) internally.
30483ff40c12SJohn Marino */
hostapd_new_assoc_sta(struct hostapd_data * hapd,struct sta_info * sta,int reassoc)30493ff40c12SJohn Marino void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
30503ff40c12SJohn Marino int reassoc)
30513ff40c12SJohn Marino {
30523ff40c12SJohn Marino if (hapd->tkip_countermeasures) {
30533ff40c12SJohn Marino hostapd_drv_sta_deauth(hapd, sta->addr,
30543ff40c12SJohn Marino WLAN_REASON_MICHAEL_MIC_FAILURE);
30553ff40c12SJohn Marino return;
30563ff40c12SJohn Marino }
30573ff40c12SJohn Marino
30583ff40c12SJohn Marino hostapd_prune_associations(hapd, sta->addr);
3059*a1157835SDaniel Fojt ap_sta_clear_disconnect_timeouts(hapd, sta);
30603ff40c12SJohn Marino
30613ff40c12SJohn Marino /* IEEE 802.11F (IAPP) */
30623ff40c12SJohn Marino if (hapd->conf->ieee802_11f)
30633ff40c12SJohn Marino iapp_new_station(hapd->iapp, sta);
30643ff40c12SJohn Marino
30653ff40c12SJohn Marino #ifdef CONFIG_P2P
30663ff40c12SJohn Marino if (sta->p2p_ie == NULL && !sta->no_p2p_set) {
30673ff40c12SJohn Marino sta->no_p2p_set = 1;
30683ff40c12SJohn Marino hapd->num_sta_no_p2p++;
30693ff40c12SJohn Marino if (hapd->num_sta_no_p2p == 1)
30703ff40c12SJohn Marino hostapd_p2p_non_p2p_sta_connected(hapd);
30713ff40c12SJohn Marino }
30723ff40c12SJohn Marino #endif /* CONFIG_P2P */
30733ff40c12SJohn Marino
3074*a1157835SDaniel Fojt airtime_policy_new_sta(hapd, sta);
3075*a1157835SDaniel Fojt
30763ff40c12SJohn Marino /* Start accounting here, if IEEE 802.1X and WPA are not used.
30773ff40c12SJohn Marino * IEEE 802.1X/WPA code will start accounting after the station has
30783ff40c12SJohn Marino * been authorized. */
3079*a1157835SDaniel Fojt if (!hapd->conf->ieee802_1x && !hapd->conf->wpa && !hapd->conf->osen) {
3080*a1157835SDaniel Fojt ap_sta_set_authorized(hapd, sta, 1);
30813ff40c12SJohn Marino os_get_reltime(&sta->connected_time);
30823ff40c12SJohn Marino accounting_sta_start(hapd, sta);
30833ff40c12SJohn Marino }
30843ff40c12SJohn Marino
30853ff40c12SJohn Marino /* Start IEEE 802.1X authentication process for new stations */
30863ff40c12SJohn Marino ieee802_1x_new_station(hapd, sta);
30873ff40c12SJohn Marino if (reassoc) {
30883ff40c12SJohn Marino if (sta->auth_alg != WLAN_AUTH_FT &&
3089*a1157835SDaniel Fojt sta->auth_alg != WLAN_AUTH_FILS_SK &&
3090*a1157835SDaniel Fojt sta->auth_alg != WLAN_AUTH_FILS_SK_PFS &&
3091*a1157835SDaniel Fojt sta->auth_alg != WLAN_AUTH_FILS_PK &&
30923ff40c12SJohn Marino !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)))
30933ff40c12SJohn Marino wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH);
30943ff40c12SJohn Marino } else
30953ff40c12SJohn Marino wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm);
30963ff40c12SJohn Marino
3097*a1157835SDaniel Fojt if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED) {
3098*a1157835SDaniel Fojt if (eloop_cancel_timeout(ap_handle_timer, hapd, sta) > 0) {
3099*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
3100*a1157835SDaniel Fojt "%s: %s: canceled wired ap_handle_timer timeout for "
3101*a1157835SDaniel Fojt MACSTR,
3102*a1157835SDaniel Fojt hapd->conf->iface, __func__,
3103*a1157835SDaniel Fojt MAC2STR(sta->addr));
3104*a1157835SDaniel Fojt }
3105*a1157835SDaniel Fojt } else if (!(hapd->iface->drv_flags &
3106*a1157835SDaniel Fojt WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
3107*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
3108*a1157835SDaniel Fojt "%s: %s: reschedule ap_handle_timer timeout for "
3109*a1157835SDaniel Fojt MACSTR " (%d seconds - ap_max_inactivity)",
3110*a1157835SDaniel Fojt hapd->conf->iface, __func__, MAC2STR(sta->addr),
31113ff40c12SJohn Marino hapd->conf->ap_max_inactivity);
31123ff40c12SJohn Marino eloop_cancel_timeout(ap_handle_timer, hapd, sta);
31133ff40c12SJohn Marino eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
31143ff40c12SJohn Marino ap_handle_timer, hapd, sta);
31153ff40c12SJohn Marino }
3116*a1157835SDaniel Fojt
3117*a1157835SDaniel Fojt #ifdef CONFIG_MACSEC
3118*a1157835SDaniel Fojt if (hapd->conf->wpa_key_mgmt == WPA_KEY_MGMT_NONE &&
3119*a1157835SDaniel Fojt hapd->conf->mka_psk_set)
3120*a1157835SDaniel Fojt ieee802_1x_create_preshared_mka_hapd(hapd, sta);
3121*a1157835SDaniel Fojt else
3122*a1157835SDaniel Fojt ieee802_1x_alloc_kay_sm_hapd(hapd, sta);
3123*a1157835SDaniel Fojt #endif /* CONFIG_MACSEC */
31243ff40c12SJohn Marino }
31253ff40c12SJohn Marino
31263ff40c12SJohn Marino
hostapd_state_text(enum hostapd_iface_state s)31273ff40c12SJohn Marino const char * hostapd_state_text(enum hostapd_iface_state s)
31283ff40c12SJohn Marino {
31293ff40c12SJohn Marino switch (s) {
31303ff40c12SJohn Marino case HAPD_IFACE_UNINITIALIZED:
31313ff40c12SJohn Marino return "UNINITIALIZED";
31323ff40c12SJohn Marino case HAPD_IFACE_DISABLED:
31333ff40c12SJohn Marino return "DISABLED";
31343ff40c12SJohn Marino case HAPD_IFACE_COUNTRY_UPDATE:
31353ff40c12SJohn Marino return "COUNTRY_UPDATE";
31363ff40c12SJohn Marino case HAPD_IFACE_ACS:
31373ff40c12SJohn Marino return "ACS";
31383ff40c12SJohn Marino case HAPD_IFACE_HT_SCAN:
31393ff40c12SJohn Marino return "HT_SCAN";
31403ff40c12SJohn Marino case HAPD_IFACE_DFS:
31413ff40c12SJohn Marino return "DFS";
31423ff40c12SJohn Marino case HAPD_IFACE_ENABLED:
31433ff40c12SJohn Marino return "ENABLED";
31443ff40c12SJohn Marino }
31453ff40c12SJohn Marino
31463ff40c12SJohn Marino return "UNKNOWN";
31473ff40c12SJohn Marino }
31483ff40c12SJohn Marino
31493ff40c12SJohn Marino
hostapd_set_state(struct hostapd_iface * iface,enum hostapd_iface_state s)31503ff40c12SJohn Marino void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s)
31513ff40c12SJohn Marino {
31523ff40c12SJohn Marino wpa_printf(MSG_INFO, "%s: interface state %s->%s",
3153*a1157835SDaniel Fojt iface->conf ? iface->conf->bss[0]->iface : "N/A",
3154*a1157835SDaniel Fojt hostapd_state_text(iface->state), hostapd_state_text(s));
31553ff40c12SJohn Marino iface->state = s;
31563ff40c12SJohn Marino }
31573ff40c12SJohn Marino
31583ff40c12SJohn Marino
hostapd_csa_in_progress(struct hostapd_iface * iface)3159*a1157835SDaniel Fojt int hostapd_csa_in_progress(struct hostapd_iface *iface)
3160*a1157835SDaniel Fojt {
3161*a1157835SDaniel Fojt unsigned int i;
3162*a1157835SDaniel Fojt
3163*a1157835SDaniel Fojt for (i = 0; i < iface->num_bss; i++)
3164*a1157835SDaniel Fojt if (iface->bss[i]->csa_in_progress)
3165*a1157835SDaniel Fojt return 1;
3166*a1157835SDaniel Fojt return 0;
3167*a1157835SDaniel Fojt }
3168*a1157835SDaniel Fojt
3169*a1157835SDaniel Fojt
31703ff40c12SJohn Marino #ifdef NEED_AP_MLME
31713ff40c12SJohn Marino
free_beacon_data(struct beacon_data * beacon)31723ff40c12SJohn Marino static void free_beacon_data(struct beacon_data *beacon)
31733ff40c12SJohn Marino {
31743ff40c12SJohn Marino os_free(beacon->head);
31753ff40c12SJohn Marino beacon->head = NULL;
31763ff40c12SJohn Marino os_free(beacon->tail);
31773ff40c12SJohn Marino beacon->tail = NULL;
31783ff40c12SJohn Marino os_free(beacon->probe_resp);
31793ff40c12SJohn Marino beacon->probe_resp = NULL;
31803ff40c12SJohn Marino os_free(beacon->beacon_ies);
31813ff40c12SJohn Marino beacon->beacon_ies = NULL;
31823ff40c12SJohn Marino os_free(beacon->proberesp_ies);
31833ff40c12SJohn Marino beacon->proberesp_ies = NULL;
31843ff40c12SJohn Marino os_free(beacon->assocresp_ies);
31853ff40c12SJohn Marino beacon->assocresp_ies = NULL;
31863ff40c12SJohn Marino }
31873ff40c12SJohn Marino
31883ff40c12SJohn Marino
hostapd_build_beacon_data(struct hostapd_data * hapd,struct beacon_data * beacon)3189*a1157835SDaniel Fojt static int hostapd_build_beacon_data(struct hostapd_data *hapd,
31903ff40c12SJohn Marino struct beacon_data *beacon)
31913ff40c12SJohn Marino {
31923ff40c12SJohn Marino struct wpabuf *beacon_extra, *proberesp_extra, *assocresp_extra;
31933ff40c12SJohn Marino struct wpa_driver_ap_params params;
31943ff40c12SJohn Marino int ret;
31953ff40c12SJohn Marino
31963ff40c12SJohn Marino os_memset(beacon, 0, sizeof(*beacon));
31973ff40c12SJohn Marino ret = ieee802_11_build_ap_params(hapd, ¶ms);
31983ff40c12SJohn Marino if (ret < 0)
31993ff40c12SJohn Marino return ret;
32003ff40c12SJohn Marino
32013ff40c12SJohn Marino ret = hostapd_build_ap_extra_ies(hapd, &beacon_extra,
32023ff40c12SJohn Marino &proberesp_extra,
32033ff40c12SJohn Marino &assocresp_extra);
32043ff40c12SJohn Marino if (ret)
32053ff40c12SJohn Marino goto free_ap_params;
32063ff40c12SJohn Marino
32073ff40c12SJohn Marino ret = -1;
3208*a1157835SDaniel Fojt beacon->head = os_memdup(params.head, params.head_len);
32093ff40c12SJohn Marino if (!beacon->head)
32103ff40c12SJohn Marino goto free_ap_extra_ies;
32113ff40c12SJohn Marino
32123ff40c12SJohn Marino beacon->head_len = params.head_len;
32133ff40c12SJohn Marino
3214*a1157835SDaniel Fojt beacon->tail = os_memdup(params.tail, params.tail_len);
32153ff40c12SJohn Marino if (!beacon->tail)
32163ff40c12SJohn Marino goto free_beacon;
32173ff40c12SJohn Marino
32183ff40c12SJohn Marino beacon->tail_len = params.tail_len;
32193ff40c12SJohn Marino
32203ff40c12SJohn Marino if (params.proberesp != NULL) {
3221*a1157835SDaniel Fojt beacon->probe_resp = os_memdup(params.proberesp,
3222*a1157835SDaniel Fojt params.proberesp_len);
32233ff40c12SJohn Marino if (!beacon->probe_resp)
32243ff40c12SJohn Marino goto free_beacon;
32253ff40c12SJohn Marino
32263ff40c12SJohn Marino beacon->probe_resp_len = params.proberesp_len;
32273ff40c12SJohn Marino }
32283ff40c12SJohn Marino
32293ff40c12SJohn Marino /* copy the extra ies */
32303ff40c12SJohn Marino if (beacon_extra) {
3231*a1157835SDaniel Fojt beacon->beacon_ies = os_memdup(beacon_extra->buf,
3232*a1157835SDaniel Fojt wpabuf_len(beacon_extra));
32333ff40c12SJohn Marino if (!beacon->beacon_ies)
32343ff40c12SJohn Marino goto free_beacon;
32353ff40c12SJohn Marino
32363ff40c12SJohn Marino beacon->beacon_ies_len = wpabuf_len(beacon_extra);
32373ff40c12SJohn Marino }
32383ff40c12SJohn Marino
32393ff40c12SJohn Marino if (proberesp_extra) {
3240*a1157835SDaniel Fojt beacon->proberesp_ies = os_memdup(proberesp_extra->buf,
3241*a1157835SDaniel Fojt wpabuf_len(proberesp_extra));
32423ff40c12SJohn Marino if (!beacon->proberesp_ies)
32433ff40c12SJohn Marino goto free_beacon;
32443ff40c12SJohn Marino
32453ff40c12SJohn Marino beacon->proberesp_ies_len = wpabuf_len(proberesp_extra);
32463ff40c12SJohn Marino }
32473ff40c12SJohn Marino
32483ff40c12SJohn Marino if (assocresp_extra) {
3249*a1157835SDaniel Fojt beacon->assocresp_ies = os_memdup(assocresp_extra->buf,
3250*a1157835SDaniel Fojt wpabuf_len(assocresp_extra));
32513ff40c12SJohn Marino if (!beacon->assocresp_ies)
32523ff40c12SJohn Marino goto free_beacon;
32533ff40c12SJohn Marino
32543ff40c12SJohn Marino beacon->assocresp_ies_len = wpabuf_len(assocresp_extra);
32553ff40c12SJohn Marino }
32563ff40c12SJohn Marino
32573ff40c12SJohn Marino ret = 0;
32583ff40c12SJohn Marino free_beacon:
32593ff40c12SJohn Marino /* if the function fails, the caller should not free beacon data */
32603ff40c12SJohn Marino if (ret)
32613ff40c12SJohn Marino free_beacon_data(beacon);
32623ff40c12SJohn Marino
32633ff40c12SJohn Marino free_ap_extra_ies:
32643ff40c12SJohn Marino hostapd_free_ap_extra_ies(hapd, beacon_extra, proberesp_extra,
32653ff40c12SJohn Marino assocresp_extra);
32663ff40c12SJohn Marino free_ap_params:
32673ff40c12SJohn Marino ieee802_11_free_ap_params(¶ms);
32683ff40c12SJohn Marino return ret;
32693ff40c12SJohn Marino }
32703ff40c12SJohn Marino
32713ff40c12SJohn Marino
32723ff40c12SJohn Marino /*
3273*a1157835SDaniel Fojt * TODO: This flow currently supports only changing channel and width within
3274*a1157835SDaniel Fojt * the same hw_mode. Any other changes to MAC parameters or provided settings
3275*a1157835SDaniel Fojt * are not supported.
32763ff40c12SJohn Marino */
hostapd_change_config_freq(struct hostapd_data * hapd,struct hostapd_config * conf,struct hostapd_freq_params * params,struct hostapd_freq_params * old_params)32773ff40c12SJohn Marino static int hostapd_change_config_freq(struct hostapd_data *hapd,
32783ff40c12SJohn Marino struct hostapd_config *conf,
32793ff40c12SJohn Marino struct hostapd_freq_params *params,
32803ff40c12SJohn Marino struct hostapd_freq_params *old_params)
32813ff40c12SJohn Marino {
32823ff40c12SJohn Marino int channel;
3283*a1157835SDaniel Fojt u8 seg0, seg1;
3284*a1157835SDaniel Fojt struct hostapd_hw_modes *mode;
32853ff40c12SJohn Marino
32863ff40c12SJohn Marino if (!params->channel) {
32873ff40c12SJohn Marino /* check if the new channel is supported by hw */
3288*a1157835SDaniel Fojt params->channel = hostapd_hw_get_channel(hapd, params->freq);
32893ff40c12SJohn Marino }
32903ff40c12SJohn Marino
3291*a1157835SDaniel Fojt channel = params->channel;
3292*a1157835SDaniel Fojt if (!channel)
3293*a1157835SDaniel Fojt return -1;
3294*a1157835SDaniel Fojt
3295*a1157835SDaniel Fojt mode = hapd->iface->current_mode;
3296*a1157835SDaniel Fojt
32973ff40c12SJohn Marino /* if a pointer to old_params is provided we save previous state */
3298*a1157835SDaniel Fojt if (old_params &&
3299*a1157835SDaniel Fojt hostapd_set_freq_params(old_params, conf->hw_mode,
3300*a1157835SDaniel Fojt hostapd_hw_get_freq(hapd, conf->channel),
3301*a1157835SDaniel Fojt conf->channel, conf->ieee80211n,
3302*a1157835SDaniel Fojt conf->ieee80211ac, conf->ieee80211ax,
3303*a1157835SDaniel Fojt conf->secondary_channel,
3304*a1157835SDaniel Fojt hostapd_get_oper_chwidth(conf),
3305*a1157835SDaniel Fojt hostapd_get_oper_centr_freq_seg0_idx(conf),
3306*a1157835SDaniel Fojt hostapd_get_oper_centr_freq_seg1_idx(conf),
3307*a1157835SDaniel Fojt conf->vht_capab,
3308*a1157835SDaniel Fojt mode ? &mode->he_capab[IEEE80211_MODE_AP] :
3309*a1157835SDaniel Fojt NULL))
3310*a1157835SDaniel Fojt return -1;
3311*a1157835SDaniel Fojt
3312*a1157835SDaniel Fojt switch (params->bandwidth) {
3313*a1157835SDaniel Fojt case 0:
3314*a1157835SDaniel Fojt case 20:
3315*a1157835SDaniel Fojt case 40:
3316*a1157835SDaniel Fojt hostapd_set_oper_chwidth(conf, CHANWIDTH_USE_HT);
3317*a1157835SDaniel Fojt break;
3318*a1157835SDaniel Fojt case 80:
3319*a1157835SDaniel Fojt if (params->center_freq2)
3320*a1157835SDaniel Fojt hostapd_set_oper_chwidth(conf, CHANWIDTH_80P80MHZ);
3321*a1157835SDaniel Fojt else
3322*a1157835SDaniel Fojt hostapd_set_oper_chwidth(conf, CHANWIDTH_80MHZ);
3323*a1157835SDaniel Fojt break;
3324*a1157835SDaniel Fojt case 160:
3325*a1157835SDaniel Fojt hostapd_set_oper_chwidth(conf, CHANWIDTH_160MHZ);
3326*a1157835SDaniel Fojt break;
3327*a1157835SDaniel Fojt default:
3328*a1157835SDaniel Fojt return -1;
33293ff40c12SJohn Marino }
33303ff40c12SJohn Marino
33313ff40c12SJohn Marino conf->channel = channel;
33323ff40c12SJohn Marino conf->ieee80211n = params->ht_enabled;
33333ff40c12SJohn Marino conf->secondary_channel = params->sec_channel_offset;
3334*a1157835SDaniel Fojt ieee80211_freq_to_chan(params->center_freq1,
3335*a1157835SDaniel Fojt &seg0);
3336*a1157835SDaniel Fojt ieee80211_freq_to_chan(params->center_freq2,
3337*a1157835SDaniel Fojt &seg1);
3338*a1157835SDaniel Fojt hostapd_set_oper_centr_freq_seg0_idx(conf, seg0);
3339*a1157835SDaniel Fojt hostapd_set_oper_centr_freq_seg1_idx(conf, seg1);
33403ff40c12SJohn Marino
33413ff40c12SJohn Marino /* TODO: maybe call here hostapd_config_check here? */
33423ff40c12SJohn Marino
33433ff40c12SJohn Marino return 0;
33443ff40c12SJohn Marino }
33453ff40c12SJohn Marino
33463ff40c12SJohn Marino
hostapd_fill_csa_settings(struct hostapd_data * hapd,struct csa_settings * settings)3347*a1157835SDaniel Fojt static int hostapd_fill_csa_settings(struct hostapd_data *hapd,
33483ff40c12SJohn Marino struct csa_settings *settings)
33493ff40c12SJohn Marino {
3350*a1157835SDaniel Fojt struct hostapd_iface *iface = hapd->iface;
33513ff40c12SJohn Marino struct hostapd_freq_params old_freq;
33523ff40c12SJohn Marino int ret;
3353*a1157835SDaniel Fojt u8 chan, bandwidth;
33543ff40c12SJohn Marino
33553ff40c12SJohn Marino os_memset(&old_freq, 0, sizeof(old_freq));
3356*a1157835SDaniel Fojt if (!iface || !iface->freq || hapd->csa_in_progress)
33573ff40c12SJohn Marino return -1;
33583ff40c12SJohn Marino
3359*a1157835SDaniel Fojt switch (settings->freq_params.bandwidth) {
3360*a1157835SDaniel Fojt case 80:
3361*a1157835SDaniel Fojt if (settings->freq_params.center_freq2)
3362*a1157835SDaniel Fojt bandwidth = CHANWIDTH_80P80MHZ;
3363*a1157835SDaniel Fojt else
3364*a1157835SDaniel Fojt bandwidth = CHANWIDTH_80MHZ;
3365*a1157835SDaniel Fojt break;
3366*a1157835SDaniel Fojt case 160:
3367*a1157835SDaniel Fojt bandwidth = CHANWIDTH_160MHZ;
3368*a1157835SDaniel Fojt break;
3369*a1157835SDaniel Fojt default:
3370*a1157835SDaniel Fojt bandwidth = CHANWIDTH_USE_HT;
3371*a1157835SDaniel Fojt break;
3372*a1157835SDaniel Fojt }
3373*a1157835SDaniel Fojt
3374*a1157835SDaniel Fojt if (ieee80211_freq_to_channel_ext(
3375*a1157835SDaniel Fojt settings->freq_params.freq,
3376*a1157835SDaniel Fojt settings->freq_params.sec_channel_offset,
3377*a1157835SDaniel Fojt bandwidth,
3378*a1157835SDaniel Fojt &hapd->iface->cs_oper_class,
3379*a1157835SDaniel Fojt &chan) == NUM_HOSTAPD_MODES) {
3380*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
3381*a1157835SDaniel Fojt "invalid frequency for channel switch (freq=%d, sec_channel_offset=%d, vht_enabled=%d, he_enabled=%d)",
3382*a1157835SDaniel Fojt settings->freq_params.freq,
3383*a1157835SDaniel Fojt settings->freq_params.sec_channel_offset,
3384*a1157835SDaniel Fojt settings->freq_params.vht_enabled,
3385*a1157835SDaniel Fojt settings->freq_params.he_enabled);
3386*a1157835SDaniel Fojt return -1;
3387*a1157835SDaniel Fojt }
3388*a1157835SDaniel Fojt
3389*a1157835SDaniel Fojt settings->freq_params.channel = chan;
3390*a1157835SDaniel Fojt
33913ff40c12SJohn Marino ret = hostapd_change_config_freq(iface->bss[0], iface->conf,
33923ff40c12SJohn Marino &settings->freq_params,
33933ff40c12SJohn Marino &old_freq);
33943ff40c12SJohn Marino if (ret)
33953ff40c12SJohn Marino return ret;
33963ff40c12SJohn Marino
3397*a1157835SDaniel Fojt ret = hostapd_build_beacon_data(hapd, &settings->beacon_after);
33983ff40c12SJohn Marino
33993ff40c12SJohn Marino /* change back the configuration */
34003ff40c12SJohn Marino hostapd_change_config_freq(iface->bss[0], iface->conf,
34013ff40c12SJohn Marino &old_freq, NULL);
34023ff40c12SJohn Marino
34033ff40c12SJohn Marino if (ret)
34043ff40c12SJohn Marino return ret;
34053ff40c12SJohn Marino
34063ff40c12SJohn Marino /* set channel switch parameters for csa ie */
3407*a1157835SDaniel Fojt hapd->cs_freq_params = settings->freq_params;
3408*a1157835SDaniel Fojt hapd->cs_count = settings->cs_count;
3409*a1157835SDaniel Fojt hapd->cs_block_tx = settings->block_tx;
34103ff40c12SJohn Marino
3411*a1157835SDaniel Fojt ret = hostapd_build_beacon_data(hapd, &settings->beacon_csa);
34123ff40c12SJohn Marino if (ret) {
34133ff40c12SJohn Marino free_beacon_data(&settings->beacon_after);
34143ff40c12SJohn Marino return ret;
34153ff40c12SJohn Marino }
34163ff40c12SJohn Marino
3417*a1157835SDaniel Fojt settings->counter_offset_beacon[0] = hapd->cs_c_off_beacon;
3418*a1157835SDaniel Fojt settings->counter_offset_presp[0] = hapd->cs_c_off_proberesp;
3419*a1157835SDaniel Fojt settings->counter_offset_beacon[1] = hapd->cs_c_off_ecsa_beacon;
3420*a1157835SDaniel Fojt settings->counter_offset_presp[1] = hapd->cs_c_off_ecsa_proberesp;
34213ff40c12SJohn Marino
34223ff40c12SJohn Marino return 0;
34233ff40c12SJohn Marino }
34243ff40c12SJohn Marino
34253ff40c12SJohn Marino
hostapd_cleanup_cs_params(struct hostapd_data * hapd)34263ff40c12SJohn Marino void hostapd_cleanup_cs_params(struct hostapd_data *hapd)
34273ff40c12SJohn Marino {
3428*a1157835SDaniel Fojt os_memset(&hapd->cs_freq_params, 0, sizeof(hapd->cs_freq_params));
3429*a1157835SDaniel Fojt hapd->cs_count = 0;
3430*a1157835SDaniel Fojt hapd->cs_block_tx = 0;
3431*a1157835SDaniel Fojt hapd->cs_c_off_beacon = 0;
3432*a1157835SDaniel Fojt hapd->cs_c_off_proberesp = 0;
3433*a1157835SDaniel Fojt hapd->csa_in_progress = 0;
3434*a1157835SDaniel Fojt hapd->cs_c_off_ecsa_beacon = 0;
3435*a1157835SDaniel Fojt hapd->cs_c_off_ecsa_proberesp = 0;
3436*a1157835SDaniel Fojt }
3437*a1157835SDaniel Fojt
3438*a1157835SDaniel Fojt
hostapd_chan_switch_vht_config(struct hostapd_data * hapd,int vht_enabled)3439*a1157835SDaniel Fojt void hostapd_chan_switch_vht_config(struct hostapd_data *hapd, int vht_enabled)
3440*a1157835SDaniel Fojt {
3441*a1157835SDaniel Fojt if (vht_enabled)
3442*a1157835SDaniel Fojt hapd->iconf->ch_switch_vht_config |= CH_SWITCH_VHT_ENABLED;
3443*a1157835SDaniel Fojt else
3444*a1157835SDaniel Fojt hapd->iconf->ch_switch_vht_config |= CH_SWITCH_VHT_DISABLED;
3445*a1157835SDaniel Fojt
3446*a1157835SDaniel Fojt hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
3447*a1157835SDaniel Fojt HOSTAPD_LEVEL_INFO, "CHAN_SWITCH VHT CONFIG 0x%x",
3448*a1157835SDaniel Fojt hapd->iconf->ch_switch_vht_config);
34493ff40c12SJohn Marino }
34503ff40c12SJohn Marino
34513ff40c12SJohn Marino
hostapd_switch_channel(struct hostapd_data * hapd,struct csa_settings * settings)34523ff40c12SJohn Marino int hostapd_switch_channel(struct hostapd_data *hapd,
34533ff40c12SJohn Marino struct csa_settings *settings)
34543ff40c12SJohn Marino {
34553ff40c12SJohn Marino int ret;
3456*a1157835SDaniel Fojt
3457*a1157835SDaniel Fojt if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA)) {
3458*a1157835SDaniel Fojt wpa_printf(MSG_INFO, "CSA is not supported");
3459*a1157835SDaniel Fojt return -1;
3460*a1157835SDaniel Fojt }
3461*a1157835SDaniel Fojt
3462*a1157835SDaniel Fojt ret = hostapd_fill_csa_settings(hapd, settings);
34633ff40c12SJohn Marino if (ret)
34643ff40c12SJohn Marino return ret;
34653ff40c12SJohn Marino
34663ff40c12SJohn Marino ret = hostapd_drv_switch_channel(hapd, settings);
34673ff40c12SJohn Marino free_beacon_data(&settings->beacon_csa);
34683ff40c12SJohn Marino free_beacon_data(&settings->beacon_after);
34693ff40c12SJohn Marino
34703ff40c12SJohn Marino if (ret) {
34713ff40c12SJohn Marino /* if we failed, clean cs parameters */
34723ff40c12SJohn Marino hostapd_cleanup_cs_params(hapd);
34733ff40c12SJohn Marino return ret;
34743ff40c12SJohn Marino }
34753ff40c12SJohn Marino
3476*a1157835SDaniel Fojt hapd->csa_in_progress = 1;
34773ff40c12SJohn Marino return 0;
34783ff40c12SJohn Marino }
34793ff40c12SJohn Marino
3480*a1157835SDaniel Fojt
3481*a1157835SDaniel Fojt void
hostapd_switch_channel_fallback(struct hostapd_iface * iface,const struct hostapd_freq_params * freq_params)3482*a1157835SDaniel Fojt hostapd_switch_channel_fallback(struct hostapd_iface *iface,
3483*a1157835SDaniel Fojt const struct hostapd_freq_params *freq_params)
3484*a1157835SDaniel Fojt {
3485*a1157835SDaniel Fojt int seg0_idx = 0, seg1_idx = 0, bw = CHANWIDTH_USE_HT;
3486*a1157835SDaniel Fojt
3487*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "Restarting all CSA-related BSSes");
3488*a1157835SDaniel Fojt
3489*a1157835SDaniel Fojt if (freq_params->center_freq1)
3490*a1157835SDaniel Fojt seg0_idx = 36 + (freq_params->center_freq1 - 5180) / 5;
3491*a1157835SDaniel Fojt if (freq_params->center_freq2)
3492*a1157835SDaniel Fojt seg1_idx = 36 + (freq_params->center_freq2 - 5180) / 5;
3493*a1157835SDaniel Fojt
3494*a1157835SDaniel Fojt switch (freq_params->bandwidth) {
3495*a1157835SDaniel Fojt case 0:
3496*a1157835SDaniel Fojt case 20:
3497*a1157835SDaniel Fojt case 40:
3498*a1157835SDaniel Fojt bw = CHANWIDTH_USE_HT;
3499*a1157835SDaniel Fojt break;
3500*a1157835SDaniel Fojt case 80:
3501*a1157835SDaniel Fojt if (freq_params->center_freq2)
3502*a1157835SDaniel Fojt bw = CHANWIDTH_80P80MHZ;
3503*a1157835SDaniel Fojt else
3504*a1157835SDaniel Fojt bw = CHANWIDTH_80MHZ;
3505*a1157835SDaniel Fojt break;
3506*a1157835SDaniel Fojt case 160:
3507*a1157835SDaniel Fojt bw = CHANWIDTH_160MHZ;
3508*a1157835SDaniel Fojt break;
3509*a1157835SDaniel Fojt default:
3510*a1157835SDaniel Fojt wpa_printf(MSG_WARNING, "Unknown CSA bandwidth: %d",
3511*a1157835SDaniel Fojt freq_params->bandwidth);
3512*a1157835SDaniel Fojt break;
3513*a1157835SDaniel Fojt }
3514*a1157835SDaniel Fojt
3515*a1157835SDaniel Fojt iface->freq = freq_params->freq;
3516*a1157835SDaniel Fojt iface->conf->channel = freq_params->channel;
3517*a1157835SDaniel Fojt iface->conf->secondary_channel = freq_params->sec_channel_offset;
3518*a1157835SDaniel Fojt hostapd_set_oper_centr_freq_seg0_idx(iface->conf, seg0_idx);
3519*a1157835SDaniel Fojt hostapd_set_oper_centr_freq_seg1_idx(iface->conf, seg1_idx);
3520*a1157835SDaniel Fojt hostapd_set_oper_chwidth(iface->conf, bw);
3521*a1157835SDaniel Fojt iface->conf->ieee80211n = freq_params->ht_enabled;
3522*a1157835SDaniel Fojt iface->conf->ieee80211ac = freq_params->vht_enabled;
3523*a1157835SDaniel Fojt iface->conf->ieee80211ax = freq_params->he_enabled;
3524*a1157835SDaniel Fojt
3525*a1157835SDaniel Fojt /*
3526*a1157835SDaniel Fojt * cs_params must not be cleared earlier because the freq_params
3527*a1157835SDaniel Fojt * argument may actually point to one of these.
3528*a1157835SDaniel Fojt * These params will be cleared during interface disable below.
3529*a1157835SDaniel Fojt */
3530*a1157835SDaniel Fojt hostapd_disable_iface(iface);
3531*a1157835SDaniel Fojt hostapd_enable_iface(iface);
3532*a1157835SDaniel Fojt }
3533*a1157835SDaniel Fojt
35343ff40c12SJohn Marino #endif /* NEED_AP_MLME */
3535*a1157835SDaniel Fojt
3536*a1157835SDaniel Fojt
hostapd_get_iface(struct hapd_interfaces * interfaces,const char * ifname)3537*a1157835SDaniel Fojt struct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces,
3538*a1157835SDaniel Fojt const char *ifname)
3539*a1157835SDaniel Fojt {
3540*a1157835SDaniel Fojt size_t i, j;
3541*a1157835SDaniel Fojt
3542*a1157835SDaniel Fojt for (i = 0; i < interfaces->count; i++) {
3543*a1157835SDaniel Fojt struct hostapd_iface *iface = interfaces->iface[i];
3544*a1157835SDaniel Fojt
3545*a1157835SDaniel Fojt for (j = 0; j < iface->num_bss; j++) {
3546*a1157835SDaniel Fojt struct hostapd_data *hapd = iface->bss[j];
3547*a1157835SDaniel Fojt
3548*a1157835SDaniel Fojt if (os_strcmp(ifname, hapd->conf->iface) == 0)
3549*a1157835SDaniel Fojt return hapd;
3550*a1157835SDaniel Fojt }
3551*a1157835SDaniel Fojt }
3552*a1157835SDaniel Fojt
3553*a1157835SDaniel Fojt return NULL;
3554*a1157835SDaniel Fojt }
3555*a1157835SDaniel Fojt
3556*a1157835SDaniel Fojt
hostapd_periodic_iface(struct hostapd_iface * iface)3557*a1157835SDaniel Fojt void hostapd_periodic_iface(struct hostapd_iface *iface)
3558*a1157835SDaniel Fojt {
3559*a1157835SDaniel Fojt size_t i;
3560*a1157835SDaniel Fojt
3561*a1157835SDaniel Fojt ap_list_timer(iface);
3562*a1157835SDaniel Fojt
3563*a1157835SDaniel Fojt for (i = 0; i < iface->num_bss; i++) {
3564*a1157835SDaniel Fojt struct hostapd_data *hapd = iface->bss[i];
3565*a1157835SDaniel Fojt
3566*a1157835SDaniel Fojt if (!hapd->started)
3567*a1157835SDaniel Fojt continue;
3568*a1157835SDaniel Fojt
3569*a1157835SDaniel Fojt #ifndef CONFIG_NO_RADIUS
3570*a1157835SDaniel Fojt hostapd_acl_expire(hapd);
3571*a1157835SDaniel Fojt #endif /* CONFIG_NO_RADIUS */
3572*a1157835SDaniel Fojt }
3573*a1157835SDaniel Fojt }
3574