xref: /dflybsd-src/contrib/wpa_supplicant/src/ap/hostapd.c (revision 3a84a4273475ed07d0ab1c2dfeffdfedef35d9cd)
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, &params);
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(&params);
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