xref: /dflybsd-src/contrib/wpa_supplicant/src/ap/ap_config.c (revision 3ff40c12445a6f5918b9c6e9c7031bc0cb8786d1)
1*3ff40c12SJohn Marino /*
2*3ff40c12SJohn Marino  * hostapd / Configuration helper functions
3*3ff40c12SJohn Marino  * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
4*3ff40c12SJohn Marino  *
5*3ff40c12SJohn Marino  * This software may be distributed under the terms of the BSD license.
6*3ff40c12SJohn Marino  * See README for more details.
7*3ff40c12SJohn Marino  */
8*3ff40c12SJohn Marino 
9*3ff40c12SJohn Marino #include "utils/includes.h"
10*3ff40c12SJohn Marino 
11*3ff40c12SJohn Marino #include "utils/common.h"
12*3ff40c12SJohn Marino #include "crypto/sha1.h"
13*3ff40c12SJohn Marino #include "radius/radius_client.h"
14*3ff40c12SJohn Marino #include "common/ieee802_11_defs.h"
15*3ff40c12SJohn Marino #include "common/eapol_common.h"
16*3ff40c12SJohn Marino #include "eap_common/eap_wsc_common.h"
17*3ff40c12SJohn Marino #include "eap_server/eap.h"
18*3ff40c12SJohn Marino #include "wpa_auth.h"
19*3ff40c12SJohn Marino #include "sta_info.h"
20*3ff40c12SJohn Marino #include "ap_config.h"
21*3ff40c12SJohn Marino 
22*3ff40c12SJohn Marino 
23*3ff40c12SJohn Marino static void hostapd_config_free_vlan(struct hostapd_bss_config *bss)
24*3ff40c12SJohn Marino {
25*3ff40c12SJohn Marino 	struct hostapd_vlan *vlan, *prev;
26*3ff40c12SJohn Marino 
27*3ff40c12SJohn Marino 	vlan = bss->vlan;
28*3ff40c12SJohn Marino 	prev = NULL;
29*3ff40c12SJohn Marino 	while (vlan) {
30*3ff40c12SJohn Marino 		prev = vlan;
31*3ff40c12SJohn Marino 		vlan = vlan->next;
32*3ff40c12SJohn Marino 		os_free(prev);
33*3ff40c12SJohn Marino 	}
34*3ff40c12SJohn Marino 
35*3ff40c12SJohn Marino 	bss->vlan = NULL;
36*3ff40c12SJohn Marino }
37*3ff40c12SJohn Marino 
38*3ff40c12SJohn Marino 
39*3ff40c12SJohn Marino void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
40*3ff40c12SJohn Marino {
41*3ff40c12SJohn Marino 	bss->logger_syslog_level = HOSTAPD_LEVEL_INFO;
42*3ff40c12SJohn Marino 	bss->logger_stdout_level = HOSTAPD_LEVEL_INFO;
43*3ff40c12SJohn Marino 	bss->logger_syslog = (unsigned int) -1;
44*3ff40c12SJohn Marino 	bss->logger_stdout = (unsigned int) -1;
45*3ff40c12SJohn Marino 
46*3ff40c12SJohn Marino 	bss->auth_algs = WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED;
47*3ff40c12SJohn Marino 
48*3ff40c12SJohn Marino 	bss->wep_rekeying_period = 300;
49*3ff40c12SJohn Marino 	/* use key0 in individual key and key1 in broadcast key */
50*3ff40c12SJohn Marino 	bss->broadcast_key_idx_min = 1;
51*3ff40c12SJohn Marino 	bss->broadcast_key_idx_max = 2;
52*3ff40c12SJohn Marino 	bss->eap_reauth_period = 3600;
53*3ff40c12SJohn Marino 
54*3ff40c12SJohn Marino 	bss->wpa_group_rekey = 600;
55*3ff40c12SJohn Marino 	bss->wpa_gmk_rekey = 86400;
56*3ff40c12SJohn Marino 	bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
57*3ff40c12SJohn Marino 	bss->wpa_pairwise = WPA_CIPHER_TKIP;
58*3ff40c12SJohn Marino 	bss->wpa_group = WPA_CIPHER_TKIP;
59*3ff40c12SJohn Marino 	bss->rsn_pairwise = 0;
60*3ff40c12SJohn Marino 
61*3ff40c12SJohn Marino 	bss->max_num_sta = MAX_STA_COUNT;
62*3ff40c12SJohn Marino 
63*3ff40c12SJohn Marino 	bss->dtim_period = 2;
64*3ff40c12SJohn Marino 
65*3ff40c12SJohn Marino 	bss->radius_server_auth_port = 1812;
66*3ff40c12SJohn Marino 	bss->ap_max_inactivity = AP_MAX_INACTIVITY;
67*3ff40c12SJohn Marino 	bss->eapol_version = EAPOL_VERSION;
68*3ff40c12SJohn Marino 
69*3ff40c12SJohn Marino 	bss->max_listen_interval = 65535;
70*3ff40c12SJohn Marino 
71*3ff40c12SJohn Marino 	bss->pwd_group = 19; /* ECC: GF(p=256) */
72*3ff40c12SJohn Marino 
73*3ff40c12SJohn Marino #ifdef CONFIG_IEEE80211W
74*3ff40c12SJohn Marino 	bss->assoc_sa_query_max_timeout = 1000;
75*3ff40c12SJohn Marino 	bss->assoc_sa_query_retry_timeout = 201;
76*3ff40c12SJohn Marino #endif /* CONFIG_IEEE80211W */
77*3ff40c12SJohn Marino #ifdef EAP_SERVER_FAST
78*3ff40c12SJohn Marino 	 /* both anonymous and authenticated provisioning */
79*3ff40c12SJohn Marino 	bss->eap_fast_prov = 3;
80*3ff40c12SJohn Marino 	bss->pac_key_lifetime = 7 * 24 * 60 * 60;
81*3ff40c12SJohn Marino 	bss->pac_key_refresh_time = 1 * 24 * 60 * 60;
82*3ff40c12SJohn Marino #endif /* EAP_SERVER_FAST */
83*3ff40c12SJohn Marino 
84*3ff40c12SJohn Marino 	/* Set to -1 as defaults depends on HT in setup */
85*3ff40c12SJohn Marino 	bss->wmm_enabled = -1;
86*3ff40c12SJohn Marino 
87*3ff40c12SJohn Marino #ifdef CONFIG_IEEE80211R
88*3ff40c12SJohn Marino 	bss->ft_over_ds = 1;
89*3ff40c12SJohn Marino #endif /* CONFIG_IEEE80211R */
90*3ff40c12SJohn Marino 
91*3ff40c12SJohn Marino 	bss->radius_das_time_window = 300;
92*3ff40c12SJohn Marino 
93*3ff40c12SJohn Marino 	bss->sae_anti_clogging_threshold = 5;
94*3ff40c12SJohn Marino }
95*3ff40c12SJohn Marino 
96*3ff40c12SJohn Marino 
97*3ff40c12SJohn Marino struct hostapd_config * hostapd_config_defaults(void)
98*3ff40c12SJohn Marino {
99*3ff40c12SJohn Marino #define ecw2cw(ecw) ((1 << (ecw)) - 1)
100*3ff40c12SJohn Marino 
101*3ff40c12SJohn Marino 	struct hostapd_config *conf;
102*3ff40c12SJohn Marino 	struct hostapd_bss_config *bss;
103*3ff40c12SJohn Marino 	const int aCWmin = 4, aCWmax = 10;
104*3ff40c12SJohn Marino 	const struct hostapd_wmm_ac_params ac_bk =
105*3ff40c12SJohn Marino 		{ aCWmin, aCWmax, 7, 0, 0 }; /* background traffic */
106*3ff40c12SJohn Marino 	const struct hostapd_wmm_ac_params ac_be =
107*3ff40c12SJohn Marino 		{ aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */
108*3ff40c12SJohn Marino 	const struct hostapd_wmm_ac_params ac_vi = /* video traffic */
109*3ff40c12SJohn Marino 		{ aCWmin - 1, aCWmin, 2, 3000 / 32, 0 };
110*3ff40c12SJohn Marino 	const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */
111*3ff40c12SJohn Marino 		{ aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 0 };
112*3ff40c12SJohn Marino 	const struct hostapd_tx_queue_params txq_bk =
113*3ff40c12SJohn Marino 		{ 7, ecw2cw(aCWmin), ecw2cw(aCWmax), 0 };
114*3ff40c12SJohn Marino 	const struct hostapd_tx_queue_params txq_be =
115*3ff40c12SJohn Marino 		{ 3, ecw2cw(aCWmin), 4 * (ecw2cw(aCWmin) + 1) - 1, 0};
116*3ff40c12SJohn Marino 	const struct hostapd_tx_queue_params txq_vi =
117*3ff40c12SJohn Marino 		{ 1, (ecw2cw(aCWmin) + 1) / 2 - 1, ecw2cw(aCWmin), 30};
118*3ff40c12SJohn Marino 	const struct hostapd_tx_queue_params txq_vo =
119*3ff40c12SJohn Marino 		{ 1, (ecw2cw(aCWmin) + 1) / 4 - 1,
120*3ff40c12SJohn Marino 		  (ecw2cw(aCWmin) + 1) / 2 - 1, 15};
121*3ff40c12SJohn Marino 
122*3ff40c12SJohn Marino #undef ecw2cw
123*3ff40c12SJohn Marino 
124*3ff40c12SJohn Marino 	conf = os_zalloc(sizeof(*conf));
125*3ff40c12SJohn Marino 	bss = os_zalloc(sizeof(*bss));
126*3ff40c12SJohn Marino 	if (conf == NULL || bss == NULL) {
127*3ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Failed to allocate memory for "
128*3ff40c12SJohn Marino 			   "configuration data.");
129*3ff40c12SJohn Marino 		os_free(conf);
130*3ff40c12SJohn Marino 		os_free(bss);
131*3ff40c12SJohn Marino 		return NULL;
132*3ff40c12SJohn Marino 	}
133*3ff40c12SJohn Marino 	conf->bss = os_calloc(1, sizeof(struct hostapd_bss_config *));
134*3ff40c12SJohn Marino 	if (conf->bss == NULL) {
135*3ff40c12SJohn Marino 		os_free(conf);
136*3ff40c12SJohn Marino 		os_free(bss);
137*3ff40c12SJohn Marino 		return NULL;
138*3ff40c12SJohn Marino 	}
139*3ff40c12SJohn Marino 	conf->bss[0] = bss;
140*3ff40c12SJohn Marino 
141*3ff40c12SJohn Marino 	bss->radius = os_zalloc(sizeof(*bss->radius));
142*3ff40c12SJohn Marino 	if (bss->radius == NULL) {
143*3ff40c12SJohn Marino 		os_free(conf->bss);
144*3ff40c12SJohn Marino 		os_free(conf);
145*3ff40c12SJohn Marino 		os_free(bss);
146*3ff40c12SJohn Marino 		return NULL;
147*3ff40c12SJohn Marino 	}
148*3ff40c12SJohn Marino 
149*3ff40c12SJohn Marino 	hostapd_config_defaults_bss(bss);
150*3ff40c12SJohn Marino 
151*3ff40c12SJohn Marino 	conf->num_bss = 1;
152*3ff40c12SJohn Marino 
153*3ff40c12SJohn Marino 	conf->beacon_int = 100;
154*3ff40c12SJohn Marino 	conf->rts_threshold = -1; /* use driver default: 2347 */
155*3ff40c12SJohn Marino 	conf->fragm_threshold = -1; /* user driver default: 2346 */
156*3ff40c12SJohn Marino 	conf->send_probe_response = 1;
157*3ff40c12SJohn Marino 
158*3ff40c12SJohn Marino 	conf->wmm_ac_params[0] = ac_be;
159*3ff40c12SJohn Marino 	conf->wmm_ac_params[1] = ac_bk;
160*3ff40c12SJohn Marino 	conf->wmm_ac_params[2] = ac_vi;
161*3ff40c12SJohn Marino 	conf->wmm_ac_params[3] = ac_vo;
162*3ff40c12SJohn Marino 
163*3ff40c12SJohn Marino 	conf->tx_queue[0] = txq_vo;
164*3ff40c12SJohn Marino 	conf->tx_queue[1] = txq_vi;
165*3ff40c12SJohn Marino 	conf->tx_queue[2] = txq_be;
166*3ff40c12SJohn Marino 	conf->tx_queue[3] = txq_bk;
167*3ff40c12SJohn Marino 
168*3ff40c12SJohn Marino 	conf->ht_capab = HT_CAP_INFO_SMPS_DISABLED;
169*3ff40c12SJohn Marino 
170*3ff40c12SJohn Marino 	conf->ap_table_max_size = 255;
171*3ff40c12SJohn Marino 	conf->ap_table_expiration_time = 60;
172*3ff40c12SJohn Marino 
173*3ff40c12SJohn Marino #ifdef CONFIG_TESTING_OPTIONS
174*3ff40c12SJohn Marino 	conf->ignore_probe_probability = 0.0d;
175*3ff40c12SJohn Marino 	conf->ignore_auth_probability = 0.0d;
176*3ff40c12SJohn Marino 	conf->ignore_assoc_probability = 0.0d;
177*3ff40c12SJohn Marino 	conf->ignore_reassoc_probability = 0.0d;
178*3ff40c12SJohn Marino 	conf->corrupt_gtk_rekey_mic_probability = 0.0d;
179*3ff40c12SJohn Marino #endif /* CONFIG_TESTING_OPTIONS */
180*3ff40c12SJohn Marino 
181*3ff40c12SJohn Marino #ifdef CONFIG_ACS
182*3ff40c12SJohn Marino 	conf->acs_num_scans = 5;
183*3ff40c12SJohn Marino #endif /* CONFIG_ACS */
184*3ff40c12SJohn Marino 
185*3ff40c12SJohn Marino 	return conf;
186*3ff40c12SJohn Marino }
187*3ff40c12SJohn Marino 
188*3ff40c12SJohn Marino 
189*3ff40c12SJohn Marino int hostapd_mac_comp(const void *a, const void *b)
190*3ff40c12SJohn Marino {
191*3ff40c12SJohn Marino 	return os_memcmp(a, b, sizeof(macaddr));
192*3ff40c12SJohn Marino }
193*3ff40c12SJohn Marino 
194*3ff40c12SJohn Marino 
195*3ff40c12SJohn Marino int hostapd_mac_comp_empty(const void *a)
196*3ff40c12SJohn Marino {
197*3ff40c12SJohn Marino 	macaddr empty = { 0 };
198*3ff40c12SJohn Marino 	return os_memcmp(a, empty, sizeof(macaddr));
199*3ff40c12SJohn Marino }
200*3ff40c12SJohn Marino 
201*3ff40c12SJohn Marino 
202*3ff40c12SJohn Marino static int hostapd_config_read_wpa_psk(const char *fname,
203*3ff40c12SJohn Marino 				       struct hostapd_ssid *ssid)
204*3ff40c12SJohn Marino {
205*3ff40c12SJohn Marino 	FILE *f;
206*3ff40c12SJohn Marino 	char buf[128], *pos;
207*3ff40c12SJohn Marino 	int line = 0, ret = 0, len, ok;
208*3ff40c12SJohn Marino 	u8 addr[ETH_ALEN];
209*3ff40c12SJohn Marino 	struct hostapd_wpa_psk *psk;
210*3ff40c12SJohn Marino 
211*3ff40c12SJohn Marino 	if (!fname)
212*3ff40c12SJohn Marino 		return 0;
213*3ff40c12SJohn Marino 
214*3ff40c12SJohn Marino 	f = fopen(fname, "r");
215*3ff40c12SJohn Marino 	if (!f) {
216*3ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "WPA PSK file '%s' not found.", fname);
217*3ff40c12SJohn Marino 		return -1;
218*3ff40c12SJohn Marino 	}
219*3ff40c12SJohn Marino 
220*3ff40c12SJohn Marino 	while (fgets(buf, sizeof(buf), f)) {
221*3ff40c12SJohn Marino 		line++;
222*3ff40c12SJohn Marino 
223*3ff40c12SJohn Marino 		if (buf[0] == '#')
224*3ff40c12SJohn Marino 			continue;
225*3ff40c12SJohn Marino 		pos = buf;
226*3ff40c12SJohn Marino 		while (*pos != '\0') {
227*3ff40c12SJohn Marino 			if (*pos == '\n') {
228*3ff40c12SJohn Marino 				*pos = '\0';
229*3ff40c12SJohn Marino 				break;
230*3ff40c12SJohn Marino 			}
231*3ff40c12SJohn Marino 			pos++;
232*3ff40c12SJohn Marino 		}
233*3ff40c12SJohn Marino 		if (buf[0] == '\0')
234*3ff40c12SJohn Marino 			continue;
235*3ff40c12SJohn Marino 
236*3ff40c12SJohn Marino 		if (hwaddr_aton(buf, addr)) {
237*3ff40c12SJohn Marino 			wpa_printf(MSG_ERROR, "Invalid MAC address '%s' on "
238*3ff40c12SJohn Marino 				   "line %d in '%s'", buf, line, fname);
239*3ff40c12SJohn Marino 			ret = -1;
240*3ff40c12SJohn Marino 			break;
241*3ff40c12SJohn Marino 		}
242*3ff40c12SJohn Marino 
243*3ff40c12SJohn Marino 		psk = os_zalloc(sizeof(*psk));
244*3ff40c12SJohn Marino 		if (psk == NULL) {
245*3ff40c12SJohn Marino 			wpa_printf(MSG_ERROR, "WPA PSK allocation failed");
246*3ff40c12SJohn Marino 			ret = -1;
247*3ff40c12SJohn Marino 			break;
248*3ff40c12SJohn Marino 		}
249*3ff40c12SJohn Marino 		if (is_zero_ether_addr(addr))
250*3ff40c12SJohn Marino 			psk->group = 1;
251*3ff40c12SJohn Marino 		else
252*3ff40c12SJohn Marino 			os_memcpy(psk->addr, addr, ETH_ALEN);
253*3ff40c12SJohn Marino 
254*3ff40c12SJohn Marino 		pos = buf + 17;
255*3ff40c12SJohn Marino 		if (*pos == '\0') {
256*3ff40c12SJohn Marino 			wpa_printf(MSG_ERROR, "No PSK on line %d in '%s'",
257*3ff40c12SJohn Marino 				   line, fname);
258*3ff40c12SJohn Marino 			os_free(psk);
259*3ff40c12SJohn Marino 			ret = -1;
260*3ff40c12SJohn Marino 			break;
261*3ff40c12SJohn Marino 		}
262*3ff40c12SJohn Marino 		pos++;
263*3ff40c12SJohn Marino 
264*3ff40c12SJohn Marino 		ok = 0;
265*3ff40c12SJohn Marino 		len = os_strlen(pos);
266*3ff40c12SJohn Marino 		if (len == 64 && hexstr2bin(pos, psk->psk, PMK_LEN) == 0)
267*3ff40c12SJohn Marino 			ok = 1;
268*3ff40c12SJohn Marino 		else if (len >= 8 && len < 64) {
269*3ff40c12SJohn Marino 			pbkdf2_sha1(pos, ssid->ssid, ssid->ssid_len,
270*3ff40c12SJohn Marino 				    4096, psk->psk, PMK_LEN);
271*3ff40c12SJohn Marino 			ok = 1;
272*3ff40c12SJohn Marino 		}
273*3ff40c12SJohn Marino 		if (!ok) {
274*3ff40c12SJohn Marino 			wpa_printf(MSG_ERROR, "Invalid PSK '%s' on line %d in "
275*3ff40c12SJohn Marino 				   "'%s'", pos, line, fname);
276*3ff40c12SJohn Marino 			os_free(psk);
277*3ff40c12SJohn Marino 			ret = -1;
278*3ff40c12SJohn Marino 			break;
279*3ff40c12SJohn Marino 		}
280*3ff40c12SJohn Marino 
281*3ff40c12SJohn Marino 		psk->next = ssid->wpa_psk;
282*3ff40c12SJohn Marino 		ssid->wpa_psk = psk;
283*3ff40c12SJohn Marino 	}
284*3ff40c12SJohn Marino 
285*3ff40c12SJohn Marino 	fclose(f);
286*3ff40c12SJohn Marino 
287*3ff40c12SJohn Marino 	return ret;
288*3ff40c12SJohn Marino }
289*3ff40c12SJohn Marino 
290*3ff40c12SJohn Marino 
291*3ff40c12SJohn Marino static int hostapd_derive_psk(struct hostapd_ssid *ssid)
292*3ff40c12SJohn Marino {
293*3ff40c12SJohn Marino 	ssid->wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk));
294*3ff40c12SJohn Marino 	if (ssid->wpa_psk == NULL) {
295*3ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Unable to alloc space for PSK");
296*3ff40c12SJohn Marino 		return -1;
297*3ff40c12SJohn Marino 	}
298*3ff40c12SJohn Marino 	wpa_hexdump_ascii(MSG_DEBUG, "SSID",
299*3ff40c12SJohn Marino 			  (u8 *) ssid->ssid, ssid->ssid_len);
300*3ff40c12SJohn Marino 	wpa_hexdump_ascii_key(MSG_DEBUG, "PSK (ASCII passphrase)",
301*3ff40c12SJohn Marino 			      (u8 *) ssid->wpa_passphrase,
302*3ff40c12SJohn Marino 			      os_strlen(ssid->wpa_passphrase));
303*3ff40c12SJohn Marino 	pbkdf2_sha1(ssid->wpa_passphrase,
304*3ff40c12SJohn Marino 		    ssid->ssid, ssid->ssid_len,
305*3ff40c12SJohn Marino 		    4096, ssid->wpa_psk->psk, PMK_LEN);
306*3ff40c12SJohn Marino 	wpa_hexdump_key(MSG_DEBUG, "PSK (from passphrase)",
307*3ff40c12SJohn Marino 			ssid->wpa_psk->psk, PMK_LEN);
308*3ff40c12SJohn Marino 	return 0;
309*3ff40c12SJohn Marino }
310*3ff40c12SJohn Marino 
311*3ff40c12SJohn Marino 
312*3ff40c12SJohn Marino int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf)
313*3ff40c12SJohn Marino {
314*3ff40c12SJohn Marino 	struct hostapd_ssid *ssid = &conf->ssid;
315*3ff40c12SJohn Marino 
316*3ff40c12SJohn Marino 	if (ssid->wpa_passphrase != NULL) {
317*3ff40c12SJohn Marino 		if (ssid->wpa_psk != NULL) {
318*3ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "Using pre-configured WPA PSK "
319*3ff40c12SJohn Marino 				   "instead of passphrase");
320*3ff40c12SJohn Marino 		} else {
321*3ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "Deriving WPA PSK based on "
322*3ff40c12SJohn Marino 				   "passphrase");
323*3ff40c12SJohn Marino 			if (hostapd_derive_psk(ssid) < 0)
324*3ff40c12SJohn Marino 				return -1;
325*3ff40c12SJohn Marino 		}
326*3ff40c12SJohn Marino 		ssid->wpa_psk->group = 1;
327*3ff40c12SJohn Marino 	}
328*3ff40c12SJohn Marino 
329*3ff40c12SJohn Marino 	if (ssid->wpa_psk_file) {
330*3ff40c12SJohn Marino 		if (hostapd_config_read_wpa_psk(ssid->wpa_psk_file,
331*3ff40c12SJohn Marino 						&conf->ssid))
332*3ff40c12SJohn Marino 			return -1;
333*3ff40c12SJohn Marino 	}
334*3ff40c12SJohn Marino 
335*3ff40c12SJohn Marino 	return 0;
336*3ff40c12SJohn Marino }
337*3ff40c12SJohn Marino 
338*3ff40c12SJohn Marino 
339*3ff40c12SJohn Marino int hostapd_wep_key_cmp(struct hostapd_wep_keys *a, struct hostapd_wep_keys *b)
340*3ff40c12SJohn Marino {
341*3ff40c12SJohn Marino 	int i;
342*3ff40c12SJohn Marino 
343*3ff40c12SJohn Marino 	if (a->idx != b->idx || a->default_len != b->default_len)
344*3ff40c12SJohn Marino 		return 1;
345*3ff40c12SJohn Marino 	for (i = 0; i < NUM_WEP_KEYS; i++)
346*3ff40c12SJohn Marino 		if (a->len[i] != b->len[i] ||
347*3ff40c12SJohn Marino 		    os_memcmp(a->key[i], b->key[i], a->len[i]) != 0)
348*3ff40c12SJohn Marino 			return 1;
349*3ff40c12SJohn Marino 	return 0;
350*3ff40c12SJohn Marino }
351*3ff40c12SJohn Marino 
352*3ff40c12SJohn Marino 
353*3ff40c12SJohn Marino static void hostapd_config_free_radius(struct hostapd_radius_server *servers,
354*3ff40c12SJohn Marino 				       int num_servers)
355*3ff40c12SJohn Marino {
356*3ff40c12SJohn Marino 	int i;
357*3ff40c12SJohn Marino 
358*3ff40c12SJohn Marino 	for (i = 0; i < num_servers; i++) {
359*3ff40c12SJohn Marino 		os_free(servers[i].shared_secret);
360*3ff40c12SJohn Marino 	}
361*3ff40c12SJohn Marino 	os_free(servers);
362*3ff40c12SJohn Marino }
363*3ff40c12SJohn Marino 
364*3ff40c12SJohn Marino 
365*3ff40c12SJohn Marino struct hostapd_radius_attr *
366*3ff40c12SJohn Marino hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type)
367*3ff40c12SJohn Marino {
368*3ff40c12SJohn Marino 	for (; attr; attr = attr->next) {
369*3ff40c12SJohn Marino 		if (attr->type == type)
370*3ff40c12SJohn Marino 			return attr;
371*3ff40c12SJohn Marino 	}
372*3ff40c12SJohn Marino 	return NULL;
373*3ff40c12SJohn Marino }
374*3ff40c12SJohn Marino 
375*3ff40c12SJohn Marino 
376*3ff40c12SJohn Marino static void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr)
377*3ff40c12SJohn Marino {
378*3ff40c12SJohn Marino 	struct hostapd_radius_attr *prev;
379*3ff40c12SJohn Marino 
380*3ff40c12SJohn Marino 	while (attr) {
381*3ff40c12SJohn Marino 		prev = attr;
382*3ff40c12SJohn Marino 		attr = attr->next;
383*3ff40c12SJohn Marino 		wpabuf_free(prev->val);
384*3ff40c12SJohn Marino 		os_free(prev);
385*3ff40c12SJohn Marino 	}
386*3ff40c12SJohn Marino }
387*3ff40c12SJohn Marino 
388*3ff40c12SJohn Marino 
389*3ff40c12SJohn Marino static void hostapd_config_free_eap_user(struct hostapd_eap_user *user)
390*3ff40c12SJohn Marino {
391*3ff40c12SJohn Marino 	os_free(user->identity);
392*3ff40c12SJohn Marino 	os_free(user->password);
393*3ff40c12SJohn Marino 	os_free(user);
394*3ff40c12SJohn Marino }
395*3ff40c12SJohn Marino 
396*3ff40c12SJohn Marino 
397*3ff40c12SJohn Marino static void hostapd_config_free_wep(struct hostapd_wep_keys *keys)
398*3ff40c12SJohn Marino {
399*3ff40c12SJohn Marino 	int i;
400*3ff40c12SJohn Marino 	for (i = 0; i < NUM_WEP_KEYS; i++) {
401*3ff40c12SJohn Marino 		os_free(keys->key[i]);
402*3ff40c12SJohn Marino 		keys->key[i] = NULL;
403*3ff40c12SJohn Marino 	}
404*3ff40c12SJohn Marino }
405*3ff40c12SJohn Marino 
406*3ff40c12SJohn Marino 
407*3ff40c12SJohn Marino void hostapd_config_free_bss(struct hostapd_bss_config *conf)
408*3ff40c12SJohn Marino {
409*3ff40c12SJohn Marino 	struct hostapd_wpa_psk *psk, *prev;
410*3ff40c12SJohn Marino 	struct hostapd_eap_user *user, *prev_user;
411*3ff40c12SJohn Marino 
412*3ff40c12SJohn Marino 	if (conf == NULL)
413*3ff40c12SJohn Marino 		return;
414*3ff40c12SJohn Marino 
415*3ff40c12SJohn Marino 	psk = conf->ssid.wpa_psk;
416*3ff40c12SJohn Marino 	while (psk) {
417*3ff40c12SJohn Marino 		prev = psk;
418*3ff40c12SJohn Marino 		psk = psk->next;
419*3ff40c12SJohn Marino 		os_free(prev);
420*3ff40c12SJohn Marino 	}
421*3ff40c12SJohn Marino 
422*3ff40c12SJohn Marino 	os_free(conf->ssid.wpa_passphrase);
423*3ff40c12SJohn Marino 	os_free(conf->ssid.wpa_psk_file);
424*3ff40c12SJohn Marino 	hostapd_config_free_wep(&conf->ssid.wep);
425*3ff40c12SJohn Marino #ifdef CONFIG_FULL_DYNAMIC_VLAN
426*3ff40c12SJohn Marino 	os_free(conf->ssid.vlan_tagged_interface);
427*3ff40c12SJohn Marino #endif /* CONFIG_FULL_DYNAMIC_VLAN */
428*3ff40c12SJohn Marino 
429*3ff40c12SJohn Marino 	user = conf->eap_user;
430*3ff40c12SJohn Marino 	while (user) {
431*3ff40c12SJohn Marino 		prev_user = user;
432*3ff40c12SJohn Marino 		user = user->next;
433*3ff40c12SJohn Marino 		hostapd_config_free_eap_user(prev_user);
434*3ff40c12SJohn Marino 	}
435*3ff40c12SJohn Marino 	os_free(conf->eap_user_sqlite);
436*3ff40c12SJohn Marino 
437*3ff40c12SJohn Marino 	os_free(conf->eap_req_id_text);
438*3ff40c12SJohn Marino 	os_free(conf->accept_mac);
439*3ff40c12SJohn Marino 	os_free(conf->deny_mac);
440*3ff40c12SJohn Marino 	os_free(conf->nas_identifier);
441*3ff40c12SJohn Marino 	if (conf->radius) {
442*3ff40c12SJohn Marino 		hostapd_config_free_radius(conf->radius->auth_servers,
443*3ff40c12SJohn Marino 					   conf->radius->num_auth_servers);
444*3ff40c12SJohn Marino 		hostapd_config_free_radius(conf->radius->acct_servers,
445*3ff40c12SJohn Marino 					   conf->radius->num_acct_servers);
446*3ff40c12SJohn Marino 	}
447*3ff40c12SJohn Marino 	hostapd_config_free_radius_attr(conf->radius_auth_req_attr);
448*3ff40c12SJohn Marino 	hostapd_config_free_radius_attr(conf->radius_acct_req_attr);
449*3ff40c12SJohn Marino 	os_free(conf->rsn_preauth_interfaces);
450*3ff40c12SJohn Marino 	os_free(conf->ctrl_interface);
451*3ff40c12SJohn Marino 	os_free(conf->ca_cert);
452*3ff40c12SJohn Marino 	os_free(conf->server_cert);
453*3ff40c12SJohn Marino 	os_free(conf->private_key);
454*3ff40c12SJohn Marino 	os_free(conf->private_key_passwd);
455*3ff40c12SJohn Marino 	os_free(conf->ocsp_stapling_response);
456*3ff40c12SJohn Marino 	os_free(conf->dh_file);
457*3ff40c12SJohn Marino 	os_free(conf->pac_opaque_encr_key);
458*3ff40c12SJohn Marino 	os_free(conf->eap_fast_a_id);
459*3ff40c12SJohn Marino 	os_free(conf->eap_fast_a_id_info);
460*3ff40c12SJohn Marino 	os_free(conf->eap_sim_db);
461*3ff40c12SJohn Marino 	os_free(conf->radius_server_clients);
462*3ff40c12SJohn Marino 	os_free(conf->test_socket);
463*3ff40c12SJohn Marino 	os_free(conf->radius);
464*3ff40c12SJohn Marino 	os_free(conf->radius_das_shared_secret);
465*3ff40c12SJohn Marino 	hostapd_config_free_vlan(conf);
466*3ff40c12SJohn Marino 	os_free(conf->time_zone);
467*3ff40c12SJohn Marino 
468*3ff40c12SJohn Marino #ifdef CONFIG_IEEE80211R
469*3ff40c12SJohn Marino 	{
470*3ff40c12SJohn Marino 		struct ft_remote_r0kh *r0kh, *r0kh_prev;
471*3ff40c12SJohn Marino 		struct ft_remote_r1kh *r1kh, *r1kh_prev;
472*3ff40c12SJohn Marino 
473*3ff40c12SJohn Marino 		r0kh = conf->r0kh_list;
474*3ff40c12SJohn Marino 		conf->r0kh_list = NULL;
475*3ff40c12SJohn Marino 		while (r0kh) {
476*3ff40c12SJohn Marino 			r0kh_prev = r0kh;
477*3ff40c12SJohn Marino 			r0kh = r0kh->next;
478*3ff40c12SJohn Marino 			os_free(r0kh_prev);
479*3ff40c12SJohn Marino 		}
480*3ff40c12SJohn Marino 
481*3ff40c12SJohn Marino 		r1kh = conf->r1kh_list;
482*3ff40c12SJohn Marino 		conf->r1kh_list = NULL;
483*3ff40c12SJohn Marino 		while (r1kh) {
484*3ff40c12SJohn Marino 			r1kh_prev = r1kh;
485*3ff40c12SJohn Marino 			r1kh = r1kh->next;
486*3ff40c12SJohn Marino 			os_free(r1kh_prev);
487*3ff40c12SJohn Marino 		}
488*3ff40c12SJohn Marino 	}
489*3ff40c12SJohn Marino #endif /* CONFIG_IEEE80211R */
490*3ff40c12SJohn Marino 
491*3ff40c12SJohn Marino #ifdef CONFIG_WPS
492*3ff40c12SJohn Marino 	os_free(conf->wps_pin_requests);
493*3ff40c12SJohn Marino 	os_free(conf->device_name);
494*3ff40c12SJohn Marino 	os_free(conf->manufacturer);
495*3ff40c12SJohn Marino 	os_free(conf->model_name);
496*3ff40c12SJohn Marino 	os_free(conf->model_number);
497*3ff40c12SJohn Marino 	os_free(conf->serial_number);
498*3ff40c12SJohn Marino 	os_free(conf->config_methods);
499*3ff40c12SJohn Marino 	os_free(conf->ap_pin);
500*3ff40c12SJohn Marino 	os_free(conf->extra_cred);
501*3ff40c12SJohn Marino 	os_free(conf->ap_settings);
502*3ff40c12SJohn Marino 	os_free(conf->upnp_iface);
503*3ff40c12SJohn Marino 	os_free(conf->friendly_name);
504*3ff40c12SJohn Marino 	os_free(conf->manufacturer_url);
505*3ff40c12SJohn Marino 	os_free(conf->model_description);
506*3ff40c12SJohn Marino 	os_free(conf->model_url);
507*3ff40c12SJohn Marino 	os_free(conf->upc);
508*3ff40c12SJohn Marino 	wpabuf_free(conf->wps_nfc_dh_pubkey);
509*3ff40c12SJohn Marino 	wpabuf_free(conf->wps_nfc_dh_privkey);
510*3ff40c12SJohn Marino 	wpabuf_free(conf->wps_nfc_dev_pw);
511*3ff40c12SJohn Marino #endif /* CONFIG_WPS */
512*3ff40c12SJohn Marino 
513*3ff40c12SJohn Marino 	os_free(conf->roaming_consortium);
514*3ff40c12SJohn Marino 	os_free(conf->venue_name);
515*3ff40c12SJohn Marino 	os_free(conf->nai_realm_data);
516*3ff40c12SJohn Marino 	os_free(conf->network_auth_type);
517*3ff40c12SJohn Marino 	os_free(conf->anqp_3gpp_cell_net);
518*3ff40c12SJohn Marino 	os_free(conf->domain_name);
519*3ff40c12SJohn Marino 
520*3ff40c12SJohn Marino #ifdef CONFIG_RADIUS_TEST
521*3ff40c12SJohn Marino 	os_free(conf->dump_msk_file);
522*3ff40c12SJohn Marino #endif /* CONFIG_RADIUS_TEST */
523*3ff40c12SJohn Marino 
524*3ff40c12SJohn Marino #ifdef CONFIG_HS20
525*3ff40c12SJohn Marino 	os_free(conf->hs20_oper_friendly_name);
526*3ff40c12SJohn Marino 	os_free(conf->hs20_wan_metrics);
527*3ff40c12SJohn Marino 	os_free(conf->hs20_connection_capability);
528*3ff40c12SJohn Marino 	os_free(conf->hs20_operating_class);
529*3ff40c12SJohn Marino #endif /* CONFIG_HS20 */
530*3ff40c12SJohn Marino 
531*3ff40c12SJohn Marino 	wpabuf_free(conf->vendor_elements);
532*3ff40c12SJohn Marino 
533*3ff40c12SJohn Marino 	os_free(conf->sae_groups);
534*3ff40c12SJohn Marino 
535*3ff40c12SJohn Marino 	os_free(conf->server_id);
536*3ff40c12SJohn Marino 
537*3ff40c12SJohn Marino 	os_free(conf);
538*3ff40c12SJohn Marino }
539*3ff40c12SJohn Marino 
540*3ff40c12SJohn Marino 
541*3ff40c12SJohn Marino /**
542*3ff40c12SJohn Marino  * hostapd_config_free - Free hostapd configuration
543*3ff40c12SJohn Marino  * @conf: Configuration data from hostapd_config_read().
544*3ff40c12SJohn Marino  */
545*3ff40c12SJohn Marino void hostapd_config_free(struct hostapd_config *conf)
546*3ff40c12SJohn Marino {
547*3ff40c12SJohn Marino 	size_t i;
548*3ff40c12SJohn Marino 
549*3ff40c12SJohn Marino 	if (conf == NULL)
550*3ff40c12SJohn Marino 		return;
551*3ff40c12SJohn Marino 
552*3ff40c12SJohn Marino 	for (i = 0; i < conf->num_bss; i++)
553*3ff40c12SJohn Marino 		hostapd_config_free_bss(conf->bss[i]);
554*3ff40c12SJohn Marino 	os_free(conf->bss);
555*3ff40c12SJohn Marino 	os_free(conf->supported_rates);
556*3ff40c12SJohn Marino 	os_free(conf->basic_rates);
557*3ff40c12SJohn Marino 
558*3ff40c12SJohn Marino 	os_free(conf);
559*3ff40c12SJohn Marino }
560*3ff40c12SJohn Marino 
561*3ff40c12SJohn Marino 
562*3ff40c12SJohn Marino /**
563*3ff40c12SJohn Marino  * hostapd_maclist_found - Find a MAC address from a list
564*3ff40c12SJohn Marino  * @list: MAC address list
565*3ff40c12SJohn Marino  * @num_entries: Number of addresses in the list
566*3ff40c12SJohn Marino  * @addr: Address to search for
567*3ff40c12SJohn Marino  * @vlan_id: Buffer for returning VLAN ID or %NULL if not needed
568*3ff40c12SJohn Marino  * Returns: 1 if address is in the list or 0 if not.
569*3ff40c12SJohn Marino  *
570*3ff40c12SJohn Marino  * Perform a binary search for given MAC address from a pre-sorted list.
571*3ff40c12SJohn Marino  */
572*3ff40c12SJohn Marino int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,
573*3ff40c12SJohn Marino 			  const u8 *addr, int *vlan_id)
574*3ff40c12SJohn Marino {
575*3ff40c12SJohn Marino 	int start, end, middle, res;
576*3ff40c12SJohn Marino 
577*3ff40c12SJohn Marino 	start = 0;
578*3ff40c12SJohn Marino 	end = num_entries - 1;
579*3ff40c12SJohn Marino 
580*3ff40c12SJohn Marino 	while (start <= end) {
581*3ff40c12SJohn Marino 		middle = (start + end) / 2;
582*3ff40c12SJohn Marino 		res = os_memcmp(list[middle].addr, addr, ETH_ALEN);
583*3ff40c12SJohn Marino 		if (res == 0) {
584*3ff40c12SJohn Marino 			if (vlan_id)
585*3ff40c12SJohn Marino 				*vlan_id = list[middle].vlan_id;
586*3ff40c12SJohn Marino 			return 1;
587*3ff40c12SJohn Marino 		}
588*3ff40c12SJohn Marino 		if (res < 0)
589*3ff40c12SJohn Marino 			start = middle + 1;
590*3ff40c12SJohn Marino 		else
591*3ff40c12SJohn Marino 			end = middle - 1;
592*3ff40c12SJohn Marino 	}
593*3ff40c12SJohn Marino 
594*3ff40c12SJohn Marino 	return 0;
595*3ff40c12SJohn Marino }
596*3ff40c12SJohn Marino 
597*3ff40c12SJohn Marino 
598*3ff40c12SJohn Marino int hostapd_rate_found(int *list, int rate)
599*3ff40c12SJohn Marino {
600*3ff40c12SJohn Marino 	int i;
601*3ff40c12SJohn Marino 
602*3ff40c12SJohn Marino 	if (list == NULL)
603*3ff40c12SJohn Marino 		return 0;
604*3ff40c12SJohn Marino 
605*3ff40c12SJohn Marino 	for (i = 0; list[i] >= 0; i++)
606*3ff40c12SJohn Marino 		if (list[i] == rate)
607*3ff40c12SJohn Marino 			return 1;
608*3ff40c12SJohn Marino 
609*3ff40c12SJohn Marino 	return 0;
610*3ff40c12SJohn Marino }
611*3ff40c12SJohn Marino 
612*3ff40c12SJohn Marino 
613*3ff40c12SJohn Marino int hostapd_vlan_id_valid(struct hostapd_vlan *vlan, int vlan_id)
614*3ff40c12SJohn Marino {
615*3ff40c12SJohn Marino 	struct hostapd_vlan *v = vlan;
616*3ff40c12SJohn Marino 	while (v) {
617*3ff40c12SJohn Marino 		if (v->vlan_id == vlan_id || v->vlan_id == VLAN_ID_WILDCARD)
618*3ff40c12SJohn Marino 			return 1;
619*3ff40c12SJohn Marino 		v = v->next;
620*3ff40c12SJohn Marino 	}
621*3ff40c12SJohn Marino 	return 0;
622*3ff40c12SJohn Marino }
623*3ff40c12SJohn Marino 
624*3ff40c12SJohn Marino 
625*3ff40c12SJohn Marino const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id)
626*3ff40c12SJohn Marino {
627*3ff40c12SJohn Marino 	struct hostapd_vlan *v = vlan;
628*3ff40c12SJohn Marino 	while (v) {
629*3ff40c12SJohn Marino 		if (v->vlan_id == vlan_id)
630*3ff40c12SJohn Marino 			return v->ifname;
631*3ff40c12SJohn Marino 		v = v->next;
632*3ff40c12SJohn Marino 	}
633*3ff40c12SJohn Marino 	return NULL;
634*3ff40c12SJohn Marino }
635*3ff40c12SJohn Marino 
636*3ff40c12SJohn Marino 
637*3ff40c12SJohn Marino const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
638*3ff40c12SJohn Marino 			   const u8 *addr, const u8 *p2p_dev_addr,
639*3ff40c12SJohn Marino 			   const u8 *prev_psk)
640*3ff40c12SJohn Marino {
641*3ff40c12SJohn Marino 	struct hostapd_wpa_psk *psk;
642*3ff40c12SJohn Marino 	int next_ok = prev_psk == NULL;
643*3ff40c12SJohn Marino 
644*3ff40c12SJohn Marino 	if (p2p_dev_addr) {
645*3ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "Searching a PSK for " MACSTR
646*3ff40c12SJohn Marino 			   " p2p_dev_addr=" MACSTR " prev_psk=%p",
647*3ff40c12SJohn Marino 			   MAC2STR(addr), MAC2STR(p2p_dev_addr), prev_psk);
648*3ff40c12SJohn Marino 		if (!is_zero_ether_addr(p2p_dev_addr))
649*3ff40c12SJohn Marino 			addr = NULL; /* Use P2P Device Address for matching */
650*3ff40c12SJohn Marino 	} else {
651*3ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "Searching a PSK for " MACSTR
652*3ff40c12SJohn Marino 			   " prev_psk=%p",
653*3ff40c12SJohn Marino 			   MAC2STR(addr), prev_psk);
654*3ff40c12SJohn Marino 	}
655*3ff40c12SJohn Marino 
656*3ff40c12SJohn Marino 	for (psk = conf->ssid.wpa_psk; psk != NULL; psk = psk->next) {
657*3ff40c12SJohn Marino 		if (next_ok &&
658*3ff40c12SJohn Marino 		    (psk->group ||
659*3ff40c12SJohn Marino 		     (addr && os_memcmp(psk->addr, addr, ETH_ALEN) == 0) ||
660*3ff40c12SJohn Marino 		     (!addr && p2p_dev_addr &&
661*3ff40c12SJohn Marino 		      os_memcmp(psk->p2p_dev_addr, p2p_dev_addr, ETH_ALEN) ==
662*3ff40c12SJohn Marino 		      0)))
663*3ff40c12SJohn Marino 			return psk->psk;
664*3ff40c12SJohn Marino 
665*3ff40c12SJohn Marino 		if (psk->psk == prev_psk)
666*3ff40c12SJohn Marino 			next_ok = 1;
667*3ff40c12SJohn Marino 	}
668*3ff40c12SJohn Marino 
669*3ff40c12SJohn Marino 	return NULL;
670*3ff40c12SJohn Marino }
671*3ff40c12SJohn Marino 
672*3ff40c12SJohn Marino 
673*3ff40c12SJohn Marino static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
674*3ff40c12SJohn Marino 				    struct hostapd_config *conf,
675*3ff40c12SJohn Marino 				    int full_config)
676*3ff40c12SJohn Marino {
677*3ff40c12SJohn Marino 	if (full_config && bss->ieee802_1x && !bss->eap_server &&
678*3ff40c12SJohn Marino 	    !bss->radius->auth_servers) {
679*3ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Invalid IEEE 802.1X configuration (no "
680*3ff40c12SJohn Marino 			   "EAP authenticator configured).");
681*3ff40c12SJohn Marino 		return -1;
682*3ff40c12SJohn Marino 	}
683*3ff40c12SJohn Marino 
684*3ff40c12SJohn Marino 	if (bss->wpa) {
685*3ff40c12SJohn Marino 		int wep, i;
686*3ff40c12SJohn Marino 
687*3ff40c12SJohn Marino 		wep = bss->default_wep_key_len > 0 ||
688*3ff40c12SJohn Marino 		       bss->individual_wep_key_len > 0;
689*3ff40c12SJohn Marino 		for (i = 0; i < NUM_WEP_KEYS; i++) {
690*3ff40c12SJohn Marino 			if (bss->ssid.wep.keys_set) {
691*3ff40c12SJohn Marino 				wep = 1;
692*3ff40c12SJohn Marino 				break;
693*3ff40c12SJohn Marino 			}
694*3ff40c12SJohn Marino 		}
695*3ff40c12SJohn Marino 
696*3ff40c12SJohn Marino 		if (wep) {
697*3ff40c12SJohn Marino 			wpa_printf(MSG_ERROR, "WEP configuration in a WPA network is not supported");
698*3ff40c12SJohn Marino 			return -1;
699*3ff40c12SJohn Marino 		}
700*3ff40c12SJohn Marino 	}
701*3ff40c12SJohn Marino 
702*3ff40c12SJohn Marino 	if (full_config && bss->wpa &&
703*3ff40c12SJohn Marino 	    bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
704*3ff40c12SJohn Marino 	    bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
705*3ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "WPA-PSK using RADIUS enabled, but no "
706*3ff40c12SJohn Marino 			   "RADIUS checking (macaddr_acl=2) enabled.");
707*3ff40c12SJohn Marino 		return -1;
708*3ff40c12SJohn Marino 	}
709*3ff40c12SJohn Marino 
710*3ff40c12SJohn Marino 	if (full_config && bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
711*3ff40c12SJohn Marino 	    bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL &&
712*3ff40c12SJohn Marino 	    bss->ssid.wpa_psk_file == NULL &&
713*3ff40c12SJohn Marino 	    (bss->wpa_psk_radius != PSK_RADIUS_REQUIRED ||
714*3ff40c12SJohn Marino 	     bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH)) {
715*3ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "WPA-PSK enabled, but PSK or passphrase "
716*3ff40c12SJohn Marino 			   "is not configured.");
717*3ff40c12SJohn Marino 		return -1;
718*3ff40c12SJohn Marino 	}
719*3ff40c12SJohn Marino 
720*3ff40c12SJohn Marino 	if (full_config && hostapd_mac_comp_empty(bss->bssid) != 0) {
721*3ff40c12SJohn Marino 		size_t i;
722*3ff40c12SJohn Marino 
723*3ff40c12SJohn Marino 		for (i = 0; i < conf->num_bss; i++) {
724*3ff40c12SJohn Marino 			if (conf->bss[i] != bss &&
725*3ff40c12SJohn Marino 			    (hostapd_mac_comp(conf->bss[i]->bssid,
726*3ff40c12SJohn Marino 					      bss->bssid) == 0)) {
727*3ff40c12SJohn Marino 				wpa_printf(MSG_ERROR, "Duplicate BSSID " MACSTR
728*3ff40c12SJohn Marino 					   " on interface '%s' and '%s'.",
729*3ff40c12SJohn Marino 					   MAC2STR(bss->bssid),
730*3ff40c12SJohn Marino 					   conf->bss[i]->iface, bss->iface);
731*3ff40c12SJohn Marino 				return -1;
732*3ff40c12SJohn Marino 			}
733*3ff40c12SJohn Marino 		}
734*3ff40c12SJohn Marino 	}
735*3ff40c12SJohn Marino 
736*3ff40c12SJohn Marino #ifdef CONFIG_IEEE80211R
737*3ff40c12SJohn Marino 	if (full_config && wpa_key_mgmt_ft(bss->wpa_key_mgmt) &&
738*3ff40c12SJohn Marino 	    (bss->nas_identifier == NULL ||
739*3ff40c12SJohn Marino 	     os_strlen(bss->nas_identifier) < 1 ||
740*3ff40c12SJohn Marino 	     os_strlen(bss->nas_identifier) > FT_R0KH_ID_MAX_LEN)) {
741*3ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "FT (IEEE 802.11r) requires "
742*3ff40c12SJohn Marino 			   "nas_identifier to be configured as a 1..48 octet "
743*3ff40c12SJohn Marino 			   "string");
744*3ff40c12SJohn Marino 		return -1;
745*3ff40c12SJohn Marino 	}
746*3ff40c12SJohn Marino #endif /* CONFIG_IEEE80211R */
747*3ff40c12SJohn Marino 
748*3ff40c12SJohn Marino #ifdef CONFIG_IEEE80211N
749*3ff40c12SJohn Marino 	if (full_config && conf->ieee80211n &&
750*3ff40c12SJohn Marino 	    conf->hw_mode == HOSTAPD_MODE_IEEE80211B) {
751*3ff40c12SJohn Marino 		bss->disable_11n = 1;
752*3ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) in 11b mode is not "
753*3ff40c12SJohn Marino 			   "allowed, disabling HT capabilites");
754*3ff40c12SJohn Marino 	}
755*3ff40c12SJohn Marino 
756*3ff40c12SJohn Marino 	if (full_config && conf->ieee80211n &&
757*3ff40c12SJohn Marino 	    bss->ssid.security_policy == SECURITY_STATIC_WEP) {
758*3ff40c12SJohn Marino 		bss->disable_11n = 1;
759*3ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WEP is not "
760*3ff40c12SJohn Marino 			   "allowed, disabling HT capabilities");
761*3ff40c12SJohn Marino 	}
762*3ff40c12SJohn Marino 
763*3ff40c12SJohn Marino 	if (full_config && conf->ieee80211n && bss->wpa &&
764*3ff40c12SJohn Marino 	    !(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
765*3ff40c12SJohn Marino 	    !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
766*3ff40c12SJohn Marino 				   WPA_CIPHER_CCMP_256 | WPA_CIPHER_GCMP_256)))
767*3ff40c12SJohn Marino 	{
768*3ff40c12SJohn Marino 		bss->disable_11n = 1;
769*3ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 "
770*3ff40c12SJohn Marino 			   "requires CCMP/GCMP to be enabled, disabling HT "
771*3ff40c12SJohn Marino 			   "capabilities");
772*3ff40c12SJohn Marino 	}
773*3ff40c12SJohn Marino #endif /* CONFIG_IEEE80211N */
774*3ff40c12SJohn Marino 
775*3ff40c12SJohn Marino #ifdef CONFIG_WPS2
776*3ff40c12SJohn Marino 	if (full_config && bss->wps_state && bss->ignore_broadcast_ssid) {
777*3ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "WPS: ignore_broadcast_ssid "
778*3ff40c12SJohn Marino 			   "configuration forced WPS to be disabled");
779*3ff40c12SJohn Marino 		bss->wps_state = 0;
780*3ff40c12SJohn Marino 	}
781*3ff40c12SJohn Marino 
782*3ff40c12SJohn Marino 	if (full_config && bss->wps_state &&
783*3ff40c12SJohn Marino 	    bss->ssid.wep.keys_set && bss->wpa == 0) {
784*3ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "WPS: WEP configuration forced WPS to be "
785*3ff40c12SJohn Marino 			   "disabled");
786*3ff40c12SJohn Marino 		bss->wps_state = 0;
787*3ff40c12SJohn Marino 	}
788*3ff40c12SJohn Marino 
789*3ff40c12SJohn Marino 	if (full_config && bss->wps_state && bss->wpa &&
790*3ff40c12SJohn Marino 	    (!(bss->wpa & 2) ||
791*3ff40c12SJohn Marino 	     !(bss->rsn_pairwise & WPA_CIPHER_CCMP))) {
792*3ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "WPS: WPA/TKIP configuration without "
793*3ff40c12SJohn Marino 			   "WPA2/CCMP forced WPS to be disabled");
794*3ff40c12SJohn Marino 		bss->wps_state = 0;
795*3ff40c12SJohn Marino 	}
796*3ff40c12SJohn Marino #endif /* CONFIG_WPS2 */
797*3ff40c12SJohn Marino 
798*3ff40c12SJohn Marino #ifdef CONFIG_HS20
799*3ff40c12SJohn Marino 	if (full_config && bss->hs20 &&
800*3ff40c12SJohn Marino 	    (!(bss->wpa & 2) ||
801*3ff40c12SJohn Marino 	     !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
802*3ff40c12SJohn Marino 				    WPA_CIPHER_CCMP_256 |
803*3ff40c12SJohn Marino 				    WPA_CIPHER_GCMP_256)))) {
804*3ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "HS 2.0: WPA2-Enterprise/CCMP "
805*3ff40c12SJohn Marino 			   "configuration is required for Hotspot 2.0 "
806*3ff40c12SJohn Marino 			   "functionality");
807*3ff40c12SJohn Marino 		return -1;
808*3ff40c12SJohn Marino 	}
809*3ff40c12SJohn Marino #endif /* CONFIG_HS20 */
810*3ff40c12SJohn Marino 
811*3ff40c12SJohn Marino 	return 0;
812*3ff40c12SJohn Marino }
813*3ff40c12SJohn Marino 
814*3ff40c12SJohn Marino 
815*3ff40c12SJohn Marino int hostapd_config_check(struct hostapd_config *conf, int full_config)
816*3ff40c12SJohn Marino {
817*3ff40c12SJohn Marino 	size_t i;
818*3ff40c12SJohn Marino 
819*3ff40c12SJohn Marino 	if (full_config && conf->ieee80211d &&
820*3ff40c12SJohn Marino 	    (!conf->country[0] || !conf->country[1])) {
821*3ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11d without "
822*3ff40c12SJohn Marino 			   "setting the country_code");
823*3ff40c12SJohn Marino 		return -1;
824*3ff40c12SJohn Marino 	}
825*3ff40c12SJohn Marino 
826*3ff40c12SJohn Marino 	if (full_config && conf->ieee80211h && !conf->ieee80211d) {
827*3ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11h without "
828*3ff40c12SJohn Marino 			   "IEEE 802.11d enabled");
829*3ff40c12SJohn Marino 		return -1;
830*3ff40c12SJohn Marino 	}
831*3ff40c12SJohn Marino 
832*3ff40c12SJohn Marino 	for (i = 0; i < conf->num_bss; i++) {
833*3ff40c12SJohn Marino 		if (hostapd_config_check_bss(conf->bss[i], conf, full_config))
834*3ff40c12SJohn Marino 			return -1;
835*3ff40c12SJohn Marino 	}
836*3ff40c12SJohn Marino 
837*3ff40c12SJohn Marino 	return 0;
838*3ff40c12SJohn Marino }
839*3ff40c12SJohn Marino 
840*3ff40c12SJohn Marino 
841*3ff40c12SJohn Marino void hostapd_set_security_params(struct hostapd_bss_config *bss)
842*3ff40c12SJohn Marino {
843*3ff40c12SJohn Marino 	if (bss->individual_wep_key_len == 0) {
844*3ff40c12SJohn Marino 		/* individual keys are not use; can use key idx0 for
845*3ff40c12SJohn Marino 		 * broadcast keys */
846*3ff40c12SJohn Marino 		bss->broadcast_key_idx_min = 0;
847*3ff40c12SJohn Marino 	}
848*3ff40c12SJohn Marino 
849*3ff40c12SJohn Marino 	if ((bss->wpa & 2) && bss->rsn_pairwise == 0)
850*3ff40c12SJohn Marino 		bss->rsn_pairwise = bss->wpa_pairwise;
851*3ff40c12SJohn Marino 	bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa, bss->wpa_pairwise,
852*3ff40c12SJohn Marino 						    bss->rsn_pairwise);
853*3ff40c12SJohn Marino 
854*3ff40c12SJohn Marino 	bss->radius->auth_server = bss->radius->auth_servers;
855*3ff40c12SJohn Marino 	bss->radius->acct_server = bss->radius->acct_servers;
856*3ff40c12SJohn Marino 
857*3ff40c12SJohn Marino 	if (bss->wpa && bss->ieee802_1x) {
858*3ff40c12SJohn Marino 		bss->ssid.security_policy = SECURITY_WPA;
859*3ff40c12SJohn Marino 	} else if (bss->wpa) {
860*3ff40c12SJohn Marino 		bss->ssid.security_policy = SECURITY_WPA_PSK;
861*3ff40c12SJohn Marino 	} else if (bss->ieee802_1x) {
862*3ff40c12SJohn Marino 		int cipher = WPA_CIPHER_NONE;
863*3ff40c12SJohn Marino 		bss->ssid.security_policy = SECURITY_IEEE_802_1X;
864*3ff40c12SJohn Marino 		bss->ssid.wep.default_len = bss->default_wep_key_len;
865*3ff40c12SJohn Marino 		if (bss->default_wep_key_len)
866*3ff40c12SJohn Marino 			cipher = bss->default_wep_key_len >= 13 ?
867*3ff40c12SJohn Marino 				WPA_CIPHER_WEP104 : WPA_CIPHER_WEP40;
868*3ff40c12SJohn Marino 		bss->wpa_group = cipher;
869*3ff40c12SJohn Marino 		bss->wpa_pairwise = cipher;
870*3ff40c12SJohn Marino 		bss->rsn_pairwise = cipher;
871*3ff40c12SJohn Marino 	} else if (bss->ssid.wep.keys_set) {
872*3ff40c12SJohn Marino 		int cipher = WPA_CIPHER_WEP40;
873*3ff40c12SJohn Marino 		if (bss->ssid.wep.len[0] >= 13)
874*3ff40c12SJohn Marino 			cipher = WPA_CIPHER_WEP104;
875*3ff40c12SJohn Marino 		bss->ssid.security_policy = SECURITY_STATIC_WEP;
876*3ff40c12SJohn Marino 		bss->wpa_group = cipher;
877*3ff40c12SJohn Marino 		bss->wpa_pairwise = cipher;
878*3ff40c12SJohn Marino 		bss->rsn_pairwise = cipher;
879*3ff40c12SJohn Marino 	} else {
880*3ff40c12SJohn Marino 		bss->ssid.security_policy = SECURITY_PLAINTEXT;
881*3ff40c12SJohn Marino 		bss->wpa_group = WPA_CIPHER_NONE;
882*3ff40c12SJohn Marino 		bss->wpa_pairwise = WPA_CIPHER_NONE;
883*3ff40c12SJohn Marino 		bss->rsn_pairwise = WPA_CIPHER_NONE;
884*3ff40c12SJohn Marino 	}
885*3ff40c12SJohn Marino }
886