1214503Srpaulo/*
2214503Srpaulo * hostapd / Configuration file parser
3252726Srpaulo * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
4214503Srpaulo *
5252726Srpaulo * This software may be distributed under the terms of the BSD license.
6252726Srpaulo * See README for more details.
7214503Srpaulo */
8214503Srpaulo
9214503Srpaulo#include "utils/includes.h"
10214503Srpaulo#ifndef CONFIG_NATIVE_WINDOWS
11214503Srpaulo#include <grp.h>
12214503Srpaulo#endif /* CONFIG_NATIVE_WINDOWS */
13214503Srpaulo
14214503Srpaulo#include "utils/common.h"
15214503Srpaulo#include "utils/uuid.h"
16214503Srpaulo#include "common/ieee802_11_defs.h"
17214503Srpaulo#include "drivers/driver.h"
18214503Srpaulo#include "eap_server/eap.h"
19214503Srpaulo#include "radius/radius_client.h"
20214503Srpaulo#include "ap/wpa_auth.h"
21214503Srpaulo#include "ap/ap_config.h"
22214503Srpaulo#include "config_file.h"
23214503Srpaulo
24214503Srpaulo
25214503Srpauloextern struct wpa_driver_ops *wpa_drivers[];
26214503Srpaulo
27214503Srpaulo
28214503Srpaulo#ifndef CONFIG_NO_VLAN
29214503Srpaulostatic int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
30214503Srpaulo					 const char *fname)
31214503Srpaulo{
32214503Srpaulo	FILE *f;
33214503Srpaulo	char buf[128], *pos, *pos2;
34214503Srpaulo	int line = 0, vlan_id;
35214503Srpaulo	struct hostapd_vlan *vlan;
36214503Srpaulo
37214503Srpaulo	f = fopen(fname, "r");
38214503Srpaulo	if (!f) {
39214503Srpaulo		wpa_printf(MSG_ERROR, "VLAN file '%s' not readable.", fname);
40214503Srpaulo		return -1;
41214503Srpaulo	}
42214503Srpaulo
43214503Srpaulo	while (fgets(buf, sizeof(buf), f)) {
44214503Srpaulo		line++;
45214503Srpaulo
46214503Srpaulo		if (buf[0] == '#')
47214503Srpaulo			continue;
48214503Srpaulo		pos = buf;
49214503Srpaulo		while (*pos != '\0') {
50214503Srpaulo			if (*pos == '\n') {
51214503Srpaulo				*pos = '\0';
52214503Srpaulo				break;
53214503Srpaulo			}
54214503Srpaulo			pos++;
55214503Srpaulo		}
56214503Srpaulo		if (buf[0] == '\0')
57214503Srpaulo			continue;
58214503Srpaulo
59214503Srpaulo		if (buf[0] == '*') {
60214503Srpaulo			vlan_id = VLAN_ID_WILDCARD;
61214503Srpaulo			pos = buf + 1;
62214503Srpaulo		} else {
63214503Srpaulo			vlan_id = strtol(buf, &pos, 10);
64214503Srpaulo			if (buf == pos || vlan_id < 1 ||
65214503Srpaulo			    vlan_id > MAX_VLAN_ID) {
66214503Srpaulo				wpa_printf(MSG_ERROR, "Invalid VLAN ID at "
67214503Srpaulo					   "line %d in '%s'", line, fname);
68214503Srpaulo				fclose(f);
69214503Srpaulo				return -1;
70214503Srpaulo			}
71214503Srpaulo		}
72214503Srpaulo
73214503Srpaulo		while (*pos == ' ' || *pos == '\t')
74214503Srpaulo			pos++;
75214503Srpaulo		pos2 = pos;
76214503Srpaulo		while (*pos2 != ' ' && *pos2 != '\t' && *pos2 != '\0')
77214503Srpaulo			pos2++;
78214503Srpaulo		*pos2 = '\0';
79214503Srpaulo		if (*pos == '\0' || os_strlen(pos) > IFNAMSIZ) {
80214503Srpaulo			wpa_printf(MSG_ERROR, "Invalid VLAN ifname at line %d "
81214503Srpaulo				   "in '%s'", line, fname);
82214503Srpaulo			fclose(f);
83214503Srpaulo			return -1;
84214503Srpaulo		}
85214503Srpaulo
86214503Srpaulo		vlan = os_malloc(sizeof(*vlan));
87214503Srpaulo		if (vlan == NULL) {
88214503Srpaulo			wpa_printf(MSG_ERROR, "Out of memory while reading "
89214503Srpaulo				   "VLAN interfaces from '%s'", fname);
90214503Srpaulo			fclose(f);
91214503Srpaulo			return -1;
92214503Srpaulo		}
93214503Srpaulo
94214503Srpaulo		os_memset(vlan, 0, sizeof(*vlan));
95214503Srpaulo		vlan->vlan_id = vlan_id;
96214503Srpaulo		os_strlcpy(vlan->ifname, pos, sizeof(vlan->ifname));
97214503Srpaulo		if (bss->vlan_tail)
98214503Srpaulo			bss->vlan_tail->next = vlan;
99214503Srpaulo		else
100214503Srpaulo			bss->vlan = vlan;
101214503Srpaulo		bss->vlan_tail = vlan;
102214503Srpaulo	}
103214503Srpaulo
104214503Srpaulo	fclose(f);
105214503Srpaulo
106214503Srpaulo	return 0;
107214503Srpaulo}
108214503Srpaulo#endif /* CONFIG_NO_VLAN */
109214503Srpaulo
110214503Srpaulo
111214503Srpaulostatic int hostapd_acl_comp(const void *a, const void *b)
112214503Srpaulo{
113214503Srpaulo	const struct mac_acl_entry *aa = a;
114214503Srpaulo	const struct mac_acl_entry *bb = b;
115214503Srpaulo	return os_memcmp(aa->addr, bb->addr, sizeof(macaddr));
116214503Srpaulo}
117214503Srpaulo
118214503Srpaulo
119214503Srpaulostatic int hostapd_config_read_maclist(const char *fname,
120214503Srpaulo				       struct mac_acl_entry **acl, int *num)
121214503Srpaulo{
122214503Srpaulo	FILE *f;
123214503Srpaulo	char buf[128], *pos;
124214503Srpaulo	int line = 0;
125214503Srpaulo	u8 addr[ETH_ALEN];
126214503Srpaulo	struct mac_acl_entry *newacl;
127214503Srpaulo	int vlan_id;
128214503Srpaulo
129214503Srpaulo	if (!fname)
130214503Srpaulo		return 0;
131214503Srpaulo
132214503Srpaulo	f = fopen(fname, "r");
133214503Srpaulo	if (!f) {
134214503Srpaulo		wpa_printf(MSG_ERROR, "MAC list file '%s' not found.", fname);
135214503Srpaulo		return -1;
136214503Srpaulo	}
137214503Srpaulo
138214503Srpaulo	while (fgets(buf, sizeof(buf), f)) {
139214503Srpaulo		line++;
140214503Srpaulo
141214503Srpaulo		if (buf[0] == '#')
142214503Srpaulo			continue;
143214503Srpaulo		pos = buf;
144214503Srpaulo		while (*pos != '\0') {
145214503Srpaulo			if (*pos == '\n') {
146214503Srpaulo				*pos = '\0';
147214503Srpaulo				break;
148214503Srpaulo			}
149214503Srpaulo			pos++;
150214503Srpaulo		}
151214503Srpaulo		if (buf[0] == '\0')
152214503Srpaulo			continue;
153214503Srpaulo
154214503Srpaulo		if (hwaddr_aton(buf, addr)) {
155214503Srpaulo			wpa_printf(MSG_ERROR, "Invalid MAC address '%s' at "
156214503Srpaulo				   "line %d in '%s'", buf, line, fname);
157214503Srpaulo			fclose(f);
158214503Srpaulo			return -1;
159214503Srpaulo		}
160214503Srpaulo
161214503Srpaulo		vlan_id = 0;
162214503Srpaulo		pos = buf;
163214503Srpaulo		while (*pos != '\0' && *pos != ' ' && *pos != '\t')
164214503Srpaulo			pos++;
165214503Srpaulo		while (*pos == ' ' || *pos == '\t')
166214503Srpaulo			pos++;
167214503Srpaulo		if (*pos != '\0')
168214503Srpaulo			vlan_id = atoi(pos);
169214503Srpaulo
170252726Srpaulo		newacl = os_realloc_array(*acl, *num + 1, sizeof(**acl));
171214503Srpaulo		if (newacl == NULL) {
172214503Srpaulo			wpa_printf(MSG_ERROR, "MAC list reallocation failed");
173214503Srpaulo			fclose(f);
174214503Srpaulo			return -1;
175214503Srpaulo		}
176214503Srpaulo
177214503Srpaulo		*acl = newacl;
178214503Srpaulo		os_memcpy((*acl)[*num].addr, addr, ETH_ALEN);
179214503Srpaulo		(*acl)[*num].vlan_id = vlan_id;
180214503Srpaulo		(*num)++;
181214503Srpaulo	}
182214503Srpaulo
183214503Srpaulo	fclose(f);
184214503Srpaulo
185214503Srpaulo	qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp);
186214503Srpaulo
187214503Srpaulo	return 0;
188214503Srpaulo}
189214503Srpaulo
190214503Srpaulo
191214503Srpaulo#ifdef EAP_SERVER
192214503Srpaulostatic int hostapd_config_read_eap_user(const char *fname,
193214503Srpaulo					struct hostapd_bss_config *conf)
194214503Srpaulo{
195214503Srpaulo	FILE *f;
196214503Srpaulo	char buf[512], *pos, *start, *pos2;
197214503Srpaulo	int line = 0, ret = 0, num_methods;
198214503Srpaulo	struct hostapd_eap_user *user, *tail = NULL;
199214503Srpaulo
200214503Srpaulo	if (!fname)
201214503Srpaulo		return 0;
202214503Srpaulo
203252726Srpaulo	if (os_strncmp(fname, "sqlite:", 7) == 0) {
204252726Srpaulo		os_free(conf->eap_user_sqlite);
205252726Srpaulo		conf->eap_user_sqlite = os_strdup(fname + 7);
206252726Srpaulo		return 0;
207252726Srpaulo	}
208252726Srpaulo
209214503Srpaulo	f = fopen(fname, "r");
210214503Srpaulo	if (!f) {
211214503Srpaulo		wpa_printf(MSG_ERROR, "EAP user file '%s' not found.", fname);
212214503Srpaulo		return -1;
213214503Srpaulo	}
214214503Srpaulo
215214503Srpaulo	/* Lines: "user" METHOD,METHOD2 "password" (password optional) */
216214503Srpaulo	while (fgets(buf, sizeof(buf), f)) {
217214503Srpaulo		line++;
218214503Srpaulo
219214503Srpaulo		if (buf[0] == '#')
220214503Srpaulo			continue;
221214503Srpaulo		pos = buf;
222214503Srpaulo		while (*pos != '\0') {
223214503Srpaulo			if (*pos == '\n') {
224214503Srpaulo				*pos = '\0';
225214503Srpaulo				break;
226214503Srpaulo			}
227214503Srpaulo			pos++;
228214503Srpaulo		}
229214503Srpaulo		if (buf[0] == '\0')
230214503Srpaulo			continue;
231214503Srpaulo
232214503Srpaulo		user = NULL;
233214503Srpaulo
234214503Srpaulo		if (buf[0] != '"' && buf[0] != '*') {
235214503Srpaulo			wpa_printf(MSG_ERROR, "Invalid EAP identity (no \" in "
236214503Srpaulo				   "start) on line %d in '%s'", line, fname);
237214503Srpaulo			goto failed;
238214503Srpaulo		}
239214503Srpaulo
240214503Srpaulo		user = os_zalloc(sizeof(*user));
241214503Srpaulo		if (user == NULL) {
242214503Srpaulo			wpa_printf(MSG_ERROR, "EAP user allocation failed");
243214503Srpaulo			goto failed;
244214503Srpaulo		}
245214503Srpaulo		user->force_version = -1;
246214503Srpaulo
247214503Srpaulo		if (buf[0] == '*') {
248214503Srpaulo			pos = buf;
249214503Srpaulo		} else {
250214503Srpaulo			pos = buf + 1;
251214503Srpaulo			start = pos;
252214503Srpaulo			while (*pos != '"' && *pos != '\0')
253214503Srpaulo				pos++;
254214503Srpaulo			if (*pos == '\0') {
255214503Srpaulo				wpa_printf(MSG_ERROR, "Invalid EAP identity "
256214503Srpaulo					   "(no \" in end) on line %d in '%s'",
257214503Srpaulo					   line, fname);
258214503Srpaulo				goto failed;
259214503Srpaulo			}
260214503Srpaulo
261214503Srpaulo			user->identity = os_malloc(pos - start);
262214503Srpaulo			if (user->identity == NULL) {
263214503Srpaulo				wpa_printf(MSG_ERROR, "Failed to allocate "
264214503Srpaulo					   "memory for EAP identity");
265214503Srpaulo				goto failed;
266214503Srpaulo			}
267214503Srpaulo			os_memcpy(user->identity, start, pos - start);
268214503Srpaulo			user->identity_len = pos - start;
269214503Srpaulo
270214503Srpaulo			if (pos[0] == '"' && pos[1] == '*') {
271214503Srpaulo				user->wildcard_prefix = 1;
272214503Srpaulo				pos++;
273214503Srpaulo			}
274214503Srpaulo		}
275214503Srpaulo		pos++;
276214503Srpaulo		while (*pos == ' ' || *pos == '\t')
277214503Srpaulo			pos++;
278214503Srpaulo
279214503Srpaulo		if (*pos == '\0') {
280214503Srpaulo			wpa_printf(MSG_ERROR, "No EAP method on line %d in "
281214503Srpaulo				   "'%s'", line, fname);
282214503Srpaulo			goto failed;
283214503Srpaulo		}
284214503Srpaulo
285214503Srpaulo		start = pos;
286214503Srpaulo		while (*pos != ' ' && *pos != '\t' && *pos != '\0')
287214503Srpaulo			pos++;
288214503Srpaulo		if (*pos == '\0') {
289214503Srpaulo			pos = NULL;
290214503Srpaulo		} else {
291214503Srpaulo			*pos = '\0';
292214503Srpaulo			pos++;
293214503Srpaulo		}
294214503Srpaulo		num_methods = 0;
295214503Srpaulo		while (*start) {
296214503Srpaulo			char *pos3 = os_strchr(start, ',');
297214503Srpaulo			if (pos3) {
298214503Srpaulo				*pos3++ = '\0';
299214503Srpaulo			}
300214503Srpaulo			user->methods[num_methods].method =
301214503Srpaulo				eap_server_get_type(
302214503Srpaulo					start,
303214503Srpaulo					&user->methods[num_methods].vendor);
304214503Srpaulo			if (user->methods[num_methods].vendor ==
305214503Srpaulo			    EAP_VENDOR_IETF &&
306214503Srpaulo			    user->methods[num_methods].method == EAP_TYPE_NONE)
307214503Srpaulo			{
308214503Srpaulo				if (os_strcmp(start, "TTLS-PAP") == 0) {
309214503Srpaulo					user->ttls_auth |= EAP_TTLS_AUTH_PAP;
310214503Srpaulo					goto skip_eap;
311214503Srpaulo				}
312214503Srpaulo				if (os_strcmp(start, "TTLS-CHAP") == 0) {
313214503Srpaulo					user->ttls_auth |= EAP_TTLS_AUTH_CHAP;
314214503Srpaulo					goto skip_eap;
315214503Srpaulo				}
316214503Srpaulo				if (os_strcmp(start, "TTLS-MSCHAP") == 0) {
317214503Srpaulo					user->ttls_auth |=
318214503Srpaulo						EAP_TTLS_AUTH_MSCHAP;
319214503Srpaulo					goto skip_eap;
320214503Srpaulo				}
321214503Srpaulo				if (os_strcmp(start, "TTLS-MSCHAPV2") == 0) {
322214503Srpaulo					user->ttls_auth |=
323214503Srpaulo						EAP_TTLS_AUTH_MSCHAPV2;
324214503Srpaulo					goto skip_eap;
325214503Srpaulo				}
326214503Srpaulo				wpa_printf(MSG_ERROR, "Unsupported EAP type "
327214503Srpaulo					   "'%s' on line %d in '%s'",
328214503Srpaulo					   start, line, fname);
329214503Srpaulo				goto failed;
330214503Srpaulo			}
331214503Srpaulo
332214503Srpaulo			num_methods++;
333252726Srpaulo			if (num_methods >= EAP_MAX_METHODS)
334214503Srpaulo				break;
335214503Srpaulo		skip_eap:
336214503Srpaulo			if (pos3 == NULL)
337214503Srpaulo				break;
338214503Srpaulo			start = pos3;
339214503Srpaulo		}
340214503Srpaulo		if (num_methods == 0 && user->ttls_auth == 0) {
341214503Srpaulo			wpa_printf(MSG_ERROR, "No EAP types configured on "
342214503Srpaulo				   "line %d in '%s'", line, fname);
343214503Srpaulo			goto failed;
344214503Srpaulo		}
345214503Srpaulo
346214503Srpaulo		if (pos == NULL)
347214503Srpaulo			goto done;
348214503Srpaulo
349214503Srpaulo		while (*pos == ' ' || *pos == '\t')
350214503Srpaulo			pos++;
351214503Srpaulo		if (*pos == '\0')
352214503Srpaulo			goto done;
353214503Srpaulo
354214503Srpaulo		if (os_strncmp(pos, "[ver=0]", 7) == 0) {
355214503Srpaulo			user->force_version = 0;
356214503Srpaulo			goto done;
357214503Srpaulo		}
358214503Srpaulo
359214503Srpaulo		if (os_strncmp(pos, "[ver=1]", 7) == 0) {
360214503Srpaulo			user->force_version = 1;
361214503Srpaulo			goto done;
362214503Srpaulo		}
363214503Srpaulo
364214503Srpaulo		if (os_strncmp(pos, "[2]", 3) == 0) {
365214503Srpaulo			user->phase2 = 1;
366214503Srpaulo			goto done;
367214503Srpaulo		}
368214503Srpaulo
369214503Srpaulo		if (*pos == '"') {
370214503Srpaulo			pos++;
371214503Srpaulo			start = pos;
372214503Srpaulo			while (*pos != '"' && *pos != '\0')
373214503Srpaulo				pos++;
374214503Srpaulo			if (*pos == '\0') {
375214503Srpaulo				wpa_printf(MSG_ERROR, "Invalid EAP password "
376214503Srpaulo					   "(no \" in end) on line %d in '%s'",
377214503Srpaulo					   line, fname);
378214503Srpaulo				goto failed;
379214503Srpaulo			}
380214503Srpaulo
381214503Srpaulo			user->password = os_malloc(pos - start);
382214503Srpaulo			if (user->password == NULL) {
383214503Srpaulo				wpa_printf(MSG_ERROR, "Failed to allocate "
384214503Srpaulo					   "memory for EAP password");
385214503Srpaulo				goto failed;
386214503Srpaulo			}
387214503Srpaulo			os_memcpy(user->password, start, pos - start);
388214503Srpaulo			user->password_len = pos - start;
389214503Srpaulo
390214503Srpaulo			pos++;
391214503Srpaulo		} else if (os_strncmp(pos, "hash:", 5) == 0) {
392214503Srpaulo			pos += 5;
393214503Srpaulo			pos2 = pos;
394214503Srpaulo			while (*pos2 != '\0' && *pos2 != ' ' &&
395214503Srpaulo			       *pos2 != '\t' && *pos2 != '#')
396214503Srpaulo				pos2++;
397214503Srpaulo			if (pos2 - pos != 32) {
398214503Srpaulo				wpa_printf(MSG_ERROR, "Invalid password hash "
399214503Srpaulo					   "on line %d in '%s'", line, fname);
400214503Srpaulo				goto failed;
401214503Srpaulo			}
402214503Srpaulo			user->password = os_malloc(16);
403214503Srpaulo			if (user->password == NULL) {
404214503Srpaulo				wpa_printf(MSG_ERROR, "Failed to allocate "
405214503Srpaulo					   "memory for EAP password hash");
406214503Srpaulo				goto failed;
407214503Srpaulo			}
408214503Srpaulo			if (hexstr2bin(pos, user->password, 16) < 0) {
409214503Srpaulo				wpa_printf(MSG_ERROR, "Invalid hash password "
410214503Srpaulo					   "on line %d in '%s'", line, fname);
411214503Srpaulo				goto failed;
412214503Srpaulo			}
413214503Srpaulo			user->password_len = 16;
414214503Srpaulo			user->password_hash = 1;
415214503Srpaulo			pos = pos2;
416214503Srpaulo		} else {
417214503Srpaulo			pos2 = pos;
418214503Srpaulo			while (*pos2 != '\0' && *pos2 != ' ' &&
419214503Srpaulo			       *pos2 != '\t' && *pos2 != '#')
420214503Srpaulo				pos2++;
421214503Srpaulo			if ((pos2 - pos) & 1) {
422214503Srpaulo				wpa_printf(MSG_ERROR, "Invalid hex password "
423214503Srpaulo					   "on line %d in '%s'", line, fname);
424214503Srpaulo				goto failed;
425214503Srpaulo			}
426214503Srpaulo			user->password = os_malloc((pos2 - pos) / 2);
427214503Srpaulo			if (user->password == NULL) {
428214503Srpaulo				wpa_printf(MSG_ERROR, "Failed to allocate "
429214503Srpaulo					   "memory for EAP password");
430214503Srpaulo				goto failed;
431214503Srpaulo			}
432214503Srpaulo			if (hexstr2bin(pos, user->password,
433214503Srpaulo				       (pos2 - pos) / 2) < 0) {
434214503Srpaulo				wpa_printf(MSG_ERROR, "Invalid hex password "
435214503Srpaulo					   "on line %d in '%s'", line, fname);
436214503Srpaulo				goto failed;
437214503Srpaulo			}
438214503Srpaulo			user->password_len = (pos2 - pos) / 2;
439214503Srpaulo			pos = pos2;
440214503Srpaulo		}
441214503Srpaulo
442214503Srpaulo		while (*pos == ' ' || *pos == '\t')
443214503Srpaulo			pos++;
444214503Srpaulo		if (os_strncmp(pos, "[2]", 3) == 0) {
445214503Srpaulo			user->phase2 = 1;
446214503Srpaulo		}
447214503Srpaulo
448214503Srpaulo	done:
449214503Srpaulo		if (tail == NULL) {
450214503Srpaulo			tail = conf->eap_user = user;
451214503Srpaulo		} else {
452214503Srpaulo			tail->next = user;
453214503Srpaulo			tail = user;
454214503Srpaulo		}
455214503Srpaulo		continue;
456214503Srpaulo
457214503Srpaulo	failed:
458214503Srpaulo		if (user) {
459214503Srpaulo			os_free(user->password);
460214503Srpaulo			os_free(user->identity);
461214503Srpaulo			os_free(user);
462214503Srpaulo		}
463214503Srpaulo		ret = -1;
464214503Srpaulo		break;
465214503Srpaulo	}
466214503Srpaulo
467214503Srpaulo	fclose(f);
468214503Srpaulo
469214503Srpaulo	return ret;
470214503Srpaulo}
471214503Srpaulo#endif /* EAP_SERVER */
472214503Srpaulo
473214503Srpaulo
474214503Srpaulo#ifndef CONFIG_NO_RADIUS
475214503Srpaulostatic int
476214503Srpaulohostapd_config_read_radius_addr(struct hostapd_radius_server **server,
477214503Srpaulo				int *num_server, const char *val, int def_port,
478214503Srpaulo				struct hostapd_radius_server **curr_serv)
479214503Srpaulo{
480214503Srpaulo	struct hostapd_radius_server *nserv;
481214503Srpaulo	int ret;
482214503Srpaulo	static int server_index = 1;
483214503Srpaulo
484252726Srpaulo	nserv = os_realloc_array(*server, *num_server + 1, sizeof(*nserv));
485214503Srpaulo	if (nserv == NULL)
486214503Srpaulo		return -1;
487214503Srpaulo
488214503Srpaulo	*server = nserv;
489214503Srpaulo	nserv = &nserv[*num_server];
490214503Srpaulo	(*num_server)++;
491214503Srpaulo	(*curr_serv) = nserv;
492214503Srpaulo
493214503Srpaulo	os_memset(nserv, 0, sizeof(*nserv));
494214503Srpaulo	nserv->port = def_port;
495214503Srpaulo	ret = hostapd_parse_ip_addr(val, &nserv->addr);
496214503Srpaulo	nserv->index = server_index++;
497214503Srpaulo
498214503Srpaulo	return ret;
499214503Srpaulo}
500252726Srpaulo
501252726Srpaulo
502252726Srpaulostatic struct hostapd_radius_attr *
503252726Srpaulohostapd_parse_radius_attr(const char *value)
504252726Srpaulo{
505252726Srpaulo	const char *pos;
506252726Srpaulo	char syntax;
507252726Srpaulo	struct hostapd_radius_attr *attr;
508252726Srpaulo	size_t len;
509252726Srpaulo
510252726Srpaulo	attr = os_zalloc(sizeof(*attr));
511252726Srpaulo	if (attr == NULL)
512252726Srpaulo		return NULL;
513252726Srpaulo
514252726Srpaulo	attr->type = atoi(value);
515252726Srpaulo
516252726Srpaulo	pos = os_strchr(value, ':');
517252726Srpaulo	if (pos == NULL) {
518252726Srpaulo		attr->val = wpabuf_alloc(1);
519252726Srpaulo		if (attr->val == NULL) {
520252726Srpaulo			os_free(attr);
521252726Srpaulo			return NULL;
522252726Srpaulo		}
523252726Srpaulo		wpabuf_put_u8(attr->val, 0);
524252726Srpaulo		return attr;
525252726Srpaulo	}
526252726Srpaulo
527252726Srpaulo	pos++;
528252726Srpaulo	if (pos[0] == '\0' || pos[1] != ':') {
529252726Srpaulo		os_free(attr);
530252726Srpaulo		return NULL;
531252726Srpaulo	}
532252726Srpaulo	syntax = *pos++;
533252726Srpaulo	pos++;
534252726Srpaulo
535252726Srpaulo	switch (syntax) {
536252726Srpaulo	case 's':
537252726Srpaulo		attr->val = wpabuf_alloc_copy(pos, os_strlen(pos));
538252726Srpaulo		break;
539252726Srpaulo	case 'x':
540252726Srpaulo		len = os_strlen(pos);
541252726Srpaulo		if (len & 1)
542252726Srpaulo			break;
543252726Srpaulo		len /= 2;
544252726Srpaulo		attr->val = wpabuf_alloc(len);
545252726Srpaulo		if (attr->val == NULL)
546252726Srpaulo			break;
547252726Srpaulo		if (hexstr2bin(pos, wpabuf_put(attr->val, len), len) < 0) {
548252726Srpaulo			wpabuf_free(attr->val);
549252726Srpaulo			os_free(attr);
550252726Srpaulo			return NULL;
551252726Srpaulo		}
552252726Srpaulo		break;
553252726Srpaulo	case 'd':
554252726Srpaulo		attr->val = wpabuf_alloc(4);
555252726Srpaulo		if (attr->val)
556252726Srpaulo			wpabuf_put_be32(attr->val, atoi(pos));
557252726Srpaulo		break;
558252726Srpaulo	default:
559252726Srpaulo		os_free(attr);
560252726Srpaulo		return NULL;
561252726Srpaulo	}
562252726Srpaulo
563252726Srpaulo	if (attr->val == NULL) {
564252726Srpaulo		os_free(attr);
565252726Srpaulo		return NULL;
566252726Srpaulo	}
567252726Srpaulo
568252726Srpaulo	return attr;
569252726Srpaulo}
570252726Srpaulo
571252726Srpaulo
572252726Srpaulostatic int hostapd_parse_das_client(struct hostapd_bss_config *bss,
573252726Srpaulo				    const char *val)
574252726Srpaulo{
575252726Srpaulo	char *secret;
576252726Srpaulo
577252726Srpaulo	secret = os_strchr(val, ' ');
578252726Srpaulo	if (secret == NULL)
579252726Srpaulo		return -1;
580252726Srpaulo
581252726Srpaulo	secret++;
582252726Srpaulo
583252726Srpaulo	if (hostapd_parse_ip_addr(val, &bss->radius_das_client_addr))
584252726Srpaulo		return -1;
585252726Srpaulo
586252726Srpaulo	os_free(bss->radius_das_shared_secret);
587252726Srpaulo	bss->radius_das_shared_secret = (u8 *) os_strdup(secret);
588252726Srpaulo	if (bss->radius_das_shared_secret == NULL)
589252726Srpaulo		return -1;
590252726Srpaulo	bss->radius_das_shared_secret_len = os_strlen(secret);
591252726Srpaulo
592252726Srpaulo	return 0;
593252726Srpaulo}
594214503Srpaulo#endif /* CONFIG_NO_RADIUS */
595214503Srpaulo
596214503Srpaulo
597214503Srpaulostatic int hostapd_config_parse_key_mgmt(int line, const char *value)
598214503Srpaulo{
599214503Srpaulo	int val = 0, last;
600214503Srpaulo	char *start, *end, *buf;
601214503Srpaulo
602214503Srpaulo	buf = os_strdup(value);
603214503Srpaulo	if (buf == NULL)
604214503Srpaulo		return -1;
605214503Srpaulo	start = buf;
606214503Srpaulo
607214503Srpaulo	while (*start != '\0') {
608214503Srpaulo		while (*start == ' ' || *start == '\t')
609214503Srpaulo			start++;
610214503Srpaulo		if (*start == '\0')
611214503Srpaulo			break;
612214503Srpaulo		end = start;
613214503Srpaulo		while (*end != ' ' && *end != '\t' && *end != '\0')
614214503Srpaulo			end++;
615214503Srpaulo		last = *end == '\0';
616214503Srpaulo		*end = '\0';
617214503Srpaulo		if (os_strcmp(start, "WPA-PSK") == 0)
618214503Srpaulo			val |= WPA_KEY_MGMT_PSK;
619214503Srpaulo		else if (os_strcmp(start, "WPA-EAP") == 0)
620214503Srpaulo			val |= WPA_KEY_MGMT_IEEE8021X;
621214503Srpaulo#ifdef CONFIG_IEEE80211R
622214503Srpaulo		else if (os_strcmp(start, "FT-PSK") == 0)
623214503Srpaulo			val |= WPA_KEY_MGMT_FT_PSK;
624214503Srpaulo		else if (os_strcmp(start, "FT-EAP") == 0)
625214503Srpaulo			val |= WPA_KEY_MGMT_FT_IEEE8021X;
626214503Srpaulo#endif /* CONFIG_IEEE80211R */
627214503Srpaulo#ifdef CONFIG_IEEE80211W
628214503Srpaulo		else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
629214503Srpaulo			val |= WPA_KEY_MGMT_PSK_SHA256;
630214503Srpaulo		else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
631214503Srpaulo			val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
632214503Srpaulo#endif /* CONFIG_IEEE80211W */
633252726Srpaulo#ifdef CONFIG_SAE
634252726Srpaulo		else if (os_strcmp(start, "SAE") == 0)
635252726Srpaulo			val |= WPA_KEY_MGMT_SAE;
636252726Srpaulo		else if (os_strcmp(start, "FT-SAE") == 0)
637252726Srpaulo			val |= WPA_KEY_MGMT_FT_SAE;
638252726Srpaulo#endif /* CONFIG_SAE */
639214503Srpaulo		else {
640214503Srpaulo			wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
641214503Srpaulo				   line, start);
642214503Srpaulo			os_free(buf);
643214503Srpaulo			return -1;
644214503Srpaulo		}
645214503Srpaulo
646214503Srpaulo		if (last)
647214503Srpaulo			break;
648214503Srpaulo		start = end + 1;
649214503Srpaulo	}
650214503Srpaulo
651214503Srpaulo	os_free(buf);
652214503Srpaulo	if (val == 0) {
653214503Srpaulo		wpa_printf(MSG_ERROR, "Line %d: no key_mgmt values "
654214503Srpaulo			   "configured.", line);
655214503Srpaulo		return -1;
656214503Srpaulo	}
657214503Srpaulo
658214503Srpaulo	return val;
659214503Srpaulo}
660214503Srpaulo
661214503Srpaulo
662214503Srpaulostatic int hostapd_config_parse_cipher(int line, const char *value)
663214503Srpaulo{
664214503Srpaulo	int val = 0, last;
665214503Srpaulo	char *start, *end, *buf;
666214503Srpaulo
667214503Srpaulo	buf = os_strdup(value);
668214503Srpaulo	if (buf == NULL)
669214503Srpaulo		return -1;
670214503Srpaulo	start = buf;
671214503Srpaulo
672214503Srpaulo	while (*start != '\0') {
673214503Srpaulo		while (*start == ' ' || *start == '\t')
674214503Srpaulo			start++;
675214503Srpaulo		if (*start == '\0')
676214503Srpaulo			break;
677214503Srpaulo		end = start;
678214503Srpaulo		while (*end != ' ' && *end != '\t' && *end != '\0')
679214503Srpaulo			end++;
680214503Srpaulo		last = *end == '\0';
681214503Srpaulo		*end = '\0';
682214503Srpaulo		if (os_strcmp(start, "CCMP") == 0)
683214503Srpaulo			val |= WPA_CIPHER_CCMP;
684252726Srpaulo		else if (os_strcmp(start, "GCMP") == 0)
685252726Srpaulo			val |= WPA_CIPHER_GCMP;
686214503Srpaulo		else if (os_strcmp(start, "TKIP") == 0)
687214503Srpaulo			val |= WPA_CIPHER_TKIP;
688214503Srpaulo		else if (os_strcmp(start, "WEP104") == 0)
689214503Srpaulo			val |= WPA_CIPHER_WEP104;
690214503Srpaulo		else if (os_strcmp(start, "WEP40") == 0)
691214503Srpaulo			val |= WPA_CIPHER_WEP40;
692214503Srpaulo		else if (os_strcmp(start, "NONE") == 0)
693214503Srpaulo			val |= WPA_CIPHER_NONE;
694214503Srpaulo		else {
695214503Srpaulo			wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
696214503Srpaulo				   line, start);
697214503Srpaulo			os_free(buf);
698214503Srpaulo			return -1;
699214503Srpaulo		}
700214503Srpaulo
701214503Srpaulo		if (last)
702214503Srpaulo			break;
703214503Srpaulo		start = end + 1;
704214503Srpaulo	}
705214503Srpaulo	os_free(buf);
706214503Srpaulo
707214503Srpaulo	if (val == 0) {
708214503Srpaulo		wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.",
709214503Srpaulo			   line);
710214503Srpaulo		return -1;
711214503Srpaulo	}
712214503Srpaulo	return val;
713214503Srpaulo}
714214503Srpaulo
715214503Srpaulo
716214503Srpaulostatic int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
717214503Srpaulo				   char *val)
718214503Srpaulo{
719214503Srpaulo	size_t len = os_strlen(val);
720214503Srpaulo
721214503Srpaulo	if (keyidx < 0 || keyidx > 3 || wep->key[keyidx] != NULL)
722214503Srpaulo		return -1;
723214503Srpaulo
724214503Srpaulo	if (val[0] == '"') {
725214503Srpaulo		if (len < 2 || val[len - 1] != '"')
726214503Srpaulo			return -1;
727214503Srpaulo		len -= 2;
728214503Srpaulo		wep->key[keyidx] = os_malloc(len);
729214503Srpaulo		if (wep->key[keyidx] == NULL)
730214503Srpaulo			return -1;
731214503Srpaulo		os_memcpy(wep->key[keyidx], val + 1, len);
732214503Srpaulo		wep->len[keyidx] = len;
733214503Srpaulo	} else {
734214503Srpaulo		if (len & 1)
735214503Srpaulo			return -1;
736214503Srpaulo		len /= 2;
737214503Srpaulo		wep->key[keyidx] = os_malloc(len);
738214503Srpaulo		if (wep->key[keyidx] == NULL)
739214503Srpaulo			return -1;
740214503Srpaulo		wep->len[keyidx] = len;
741214503Srpaulo		if (hexstr2bin(val, wep->key[keyidx], len) < 0)
742214503Srpaulo			return -1;
743214503Srpaulo	}
744214503Srpaulo
745214503Srpaulo	wep->keys_set++;
746214503Srpaulo
747214503Srpaulo	return 0;
748214503Srpaulo}
749214503Srpaulo
750214503Srpaulo
751214503Srpaulostatic int hostapd_parse_rates(int **rate_list, char *val)
752214503Srpaulo{
753214503Srpaulo	int *list;
754214503Srpaulo	int count;
755214503Srpaulo	char *pos, *end;
756214503Srpaulo
757214503Srpaulo	os_free(*rate_list);
758214503Srpaulo	*rate_list = NULL;
759214503Srpaulo
760214503Srpaulo	pos = val;
761214503Srpaulo	count = 0;
762214503Srpaulo	while (*pos != '\0') {
763214503Srpaulo		if (*pos == ' ')
764214503Srpaulo			count++;
765214503Srpaulo		pos++;
766214503Srpaulo	}
767214503Srpaulo
768214503Srpaulo	list = os_malloc(sizeof(int) * (count + 2));
769214503Srpaulo	if (list == NULL)
770214503Srpaulo		return -1;
771214503Srpaulo	pos = val;
772214503Srpaulo	count = 0;
773214503Srpaulo	while (*pos != '\0') {
774214503Srpaulo		end = os_strchr(pos, ' ');
775214503Srpaulo		if (end)
776214503Srpaulo			*end = '\0';
777214503Srpaulo
778214503Srpaulo		list[count++] = atoi(pos);
779214503Srpaulo		if (!end)
780214503Srpaulo			break;
781214503Srpaulo		pos = end + 1;
782214503Srpaulo	}
783214503Srpaulo	list[count] = -1;
784214503Srpaulo
785214503Srpaulo	*rate_list = list;
786214503Srpaulo	return 0;
787214503Srpaulo}
788214503Srpaulo
789214503Srpaulo
790214503Srpaulostatic int hostapd_config_bss(struct hostapd_config *conf, const char *ifname)
791214503Srpaulo{
792214503Srpaulo	struct hostapd_bss_config *bss;
793214503Srpaulo
794214503Srpaulo	if (*ifname == '\0')
795214503Srpaulo		return -1;
796214503Srpaulo
797252726Srpaulo	bss = os_realloc_array(conf->bss, conf->num_bss + 1,
798252726Srpaulo			       sizeof(struct hostapd_bss_config));
799214503Srpaulo	if (bss == NULL) {
800214503Srpaulo		wpa_printf(MSG_ERROR, "Failed to allocate memory for "
801214503Srpaulo			   "multi-BSS entry");
802214503Srpaulo		return -1;
803214503Srpaulo	}
804214503Srpaulo	conf->bss = bss;
805214503Srpaulo
806214503Srpaulo	bss = &(conf->bss[conf->num_bss]);
807214503Srpaulo	os_memset(bss, 0, sizeof(*bss));
808214503Srpaulo	bss->radius = os_zalloc(sizeof(*bss->radius));
809214503Srpaulo	if (bss->radius == NULL) {
810214503Srpaulo		wpa_printf(MSG_ERROR, "Failed to allocate memory for "
811214503Srpaulo			   "multi-BSS RADIUS data");
812214503Srpaulo		return -1;
813214503Srpaulo	}
814214503Srpaulo
815214503Srpaulo	conf->num_bss++;
816214503Srpaulo	conf->last_bss = bss;
817214503Srpaulo
818214503Srpaulo	hostapd_config_defaults_bss(bss);
819214503Srpaulo	os_strlcpy(bss->iface, ifname, sizeof(bss->iface));
820214503Srpaulo	os_memcpy(bss->ssid.vlan, bss->iface, IFNAMSIZ + 1);
821214503Srpaulo
822214503Srpaulo	return 0;
823214503Srpaulo}
824214503Srpaulo
825214503Srpaulo
826214503Srpaulo/* convert floats with one decimal place to value*10 int, i.e.,
827214503Srpaulo * "1.5" will return 15 */
828214503Srpaulostatic int hostapd_config_read_int10(const char *value)
829214503Srpaulo{
830214503Srpaulo	int i, d;
831214503Srpaulo	char *pos;
832214503Srpaulo
833214503Srpaulo	i = atoi(value);
834214503Srpaulo	pos = os_strchr(value, '.');
835214503Srpaulo	d = 0;
836214503Srpaulo	if (pos) {
837214503Srpaulo		pos++;
838214503Srpaulo		if (*pos >= '0' && *pos <= '9')
839214503Srpaulo			d = *pos - '0';
840214503Srpaulo	}
841214503Srpaulo
842214503Srpaulo	return i * 10 + d;
843214503Srpaulo}
844214503Srpaulo
845214503Srpaulo
846214503Srpaulostatic int valid_cw(int cw)
847214503Srpaulo{
848214503Srpaulo	return (cw == 1 || cw == 3 || cw == 7 || cw == 15 || cw == 31 ||
849214503Srpaulo		cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023);
850214503Srpaulo}
851214503Srpaulo
852214503Srpaulo
853214503Srpauloenum {
854214503Srpaulo	IEEE80211_TX_QUEUE_DATA0 = 0, /* used for EDCA AC_VO data */
855214503Srpaulo	IEEE80211_TX_QUEUE_DATA1 = 1, /* used for EDCA AC_VI data */
856214503Srpaulo	IEEE80211_TX_QUEUE_DATA2 = 2, /* used for EDCA AC_BE data */
857252726Srpaulo	IEEE80211_TX_QUEUE_DATA3 = 3 /* used for EDCA AC_BK data */
858214503Srpaulo};
859214503Srpaulo
860214503Srpaulostatic int hostapd_config_tx_queue(struct hostapd_config *conf, char *name,
861214503Srpaulo				   char *val)
862214503Srpaulo{
863214503Srpaulo	int num;
864214503Srpaulo	char *pos;
865214503Srpaulo	struct hostapd_tx_queue_params *queue;
866214503Srpaulo
867214503Srpaulo	/* skip 'tx_queue_' prefix */
868214503Srpaulo	pos = name + 9;
869214503Srpaulo	if (os_strncmp(pos, "data", 4) == 0 &&
870214503Srpaulo	    pos[4] >= '0' && pos[4] <= '9' && pos[5] == '_') {
871214503Srpaulo		num = pos[4] - '0';
872214503Srpaulo		pos += 6;
873252726Srpaulo	} else if (os_strncmp(pos, "after_beacon_", 13) == 0 ||
874252726Srpaulo		   os_strncmp(pos, "beacon_", 7) == 0) {
875252726Srpaulo		wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
876252726Srpaulo		return 0;
877214503Srpaulo	} else {
878214503Srpaulo		wpa_printf(MSG_ERROR, "Unknown tx_queue name '%s'", pos);
879214503Srpaulo		return -1;
880214503Srpaulo	}
881214503Srpaulo
882252726Srpaulo	if (num >= NUM_TX_QUEUES) {
883252726Srpaulo		/* for backwards compatibility, do not trigger failure */
884252726Srpaulo		wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
885252726Srpaulo		return 0;
886252726Srpaulo	}
887252726Srpaulo
888214503Srpaulo	queue = &conf->tx_queue[num];
889214503Srpaulo
890214503Srpaulo	if (os_strcmp(pos, "aifs") == 0) {
891214503Srpaulo		queue->aifs = atoi(val);
892214503Srpaulo		if (queue->aifs < 0 || queue->aifs > 255) {
893214503Srpaulo			wpa_printf(MSG_ERROR, "Invalid AIFS value %d",
894214503Srpaulo				   queue->aifs);
895214503Srpaulo			return -1;
896214503Srpaulo		}
897214503Srpaulo	} else if (os_strcmp(pos, "cwmin") == 0) {
898214503Srpaulo		queue->cwmin = atoi(val);
899214503Srpaulo		if (!valid_cw(queue->cwmin)) {
900214503Srpaulo			wpa_printf(MSG_ERROR, "Invalid cwMin value %d",
901214503Srpaulo				   queue->cwmin);
902214503Srpaulo			return -1;
903214503Srpaulo		}
904214503Srpaulo	} else if (os_strcmp(pos, "cwmax") == 0) {
905214503Srpaulo		queue->cwmax = atoi(val);
906214503Srpaulo		if (!valid_cw(queue->cwmax)) {
907214503Srpaulo			wpa_printf(MSG_ERROR, "Invalid cwMax value %d",
908214503Srpaulo				   queue->cwmax);
909214503Srpaulo			return -1;
910214503Srpaulo		}
911214503Srpaulo	} else if (os_strcmp(pos, "burst") == 0) {
912214503Srpaulo		queue->burst = hostapd_config_read_int10(val);
913214503Srpaulo	} else {
914214503Srpaulo		wpa_printf(MSG_ERROR, "Unknown tx_queue field '%s'", pos);
915214503Srpaulo		return -1;
916214503Srpaulo	}
917214503Srpaulo
918214503Srpaulo	return 0;
919214503Srpaulo}
920214503Srpaulo
921214503Srpaulo
922214503Srpaulo#ifdef CONFIG_IEEE80211R
923214503Srpaulostatic int add_r0kh(struct hostapd_bss_config *bss, char *value)
924214503Srpaulo{
925214503Srpaulo	struct ft_remote_r0kh *r0kh;
926214503Srpaulo	char *pos, *next;
927214503Srpaulo
928214503Srpaulo	r0kh = os_zalloc(sizeof(*r0kh));
929214503Srpaulo	if (r0kh == NULL)
930214503Srpaulo		return -1;
931214503Srpaulo
932214503Srpaulo	/* 02:01:02:03:04:05 a.example.com 000102030405060708090a0b0c0d0e0f */
933214503Srpaulo	pos = value;
934214503Srpaulo	next = os_strchr(pos, ' ');
935214503Srpaulo	if (next)
936214503Srpaulo		*next++ = '\0';
937214503Srpaulo	if (next == NULL || hwaddr_aton(pos, r0kh->addr)) {
938214503Srpaulo		wpa_printf(MSG_ERROR, "Invalid R0KH MAC address: '%s'", pos);
939214503Srpaulo		os_free(r0kh);
940214503Srpaulo		return -1;
941214503Srpaulo	}
942214503Srpaulo
943214503Srpaulo	pos = next;
944214503Srpaulo	next = os_strchr(pos, ' ');
945214503Srpaulo	if (next)
946214503Srpaulo		*next++ = '\0';
947214503Srpaulo	if (next == NULL || next - pos > FT_R0KH_ID_MAX_LEN) {
948214503Srpaulo		wpa_printf(MSG_ERROR, "Invalid R0KH-ID: '%s'", pos);
949214503Srpaulo		os_free(r0kh);
950214503Srpaulo		return -1;
951214503Srpaulo	}
952214503Srpaulo	r0kh->id_len = next - pos - 1;
953214503Srpaulo	os_memcpy(r0kh->id, pos, r0kh->id_len);
954214503Srpaulo
955214503Srpaulo	pos = next;
956214503Srpaulo	if (hexstr2bin(pos, r0kh->key, sizeof(r0kh->key))) {
957214503Srpaulo		wpa_printf(MSG_ERROR, "Invalid R0KH key: '%s'", pos);
958214503Srpaulo		os_free(r0kh);
959214503Srpaulo		return -1;
960214503Srpaulo	}
961214503Srpaulo
962214503Srpaulo	r0kh->next = bss->r0kh_list;
963214503Srpaulo	bss->r0kh_list = r0kh;
964214503Srpaulo
965214503Srpaulo	return 0;
966214503Srpaulo}
967214503Srpaulo
968214503Srpaulo
969214503Srpaulostatic int add_r1kh(struct hostapd_bss_config *bss, char *value)
970214503Srpaulo{
971214503Srpaulo	struct ft_remote_r1kh *r1kh;
972214503Srpaulo	char *pos, *next;
973214503Srpaulo
974214503Srpaulo	r1kh = os_zalloc(sizeof(*r1kh));
975214503Srpaulo	if (r1kh == NULL)
976214503Srpaulo		return -1;
977214503Srpaulo
978214503Srpaulo	/* 02:01:02:03:04:05 02:01:02:03:04:05
979214503Srpaulo	 * 000102030405060708090a0b0c0d0e0f */
980214503Srpaulo	pos = value;
981214503Srpaulo	next = os_strchr(pos, ' ');
982214503Srpaulo	if (next)
983214503Srpaulo		*next++ = '\0';
984214503Srpaulo	if (next == NULL || hwaddr_aton(pos, r1kh->addr)) {
985214503Srpaulo		wpa_printf(MSG_ERROR, "Invalid R1KH MAC address: '%s'", pos);
986214503Srpaulo		os_free(r1kh);
987214503Srpaulo		return -1;
988214503Srpaulo	}
989214503Srpaulo
990214503Srpaulo	pos = next;
991214503Srpaulo	next = os_strchr(pos, ' ');
992214503Srpaulo	if (next)
993214503Srpaulo		*next++ = '\0';
994214503Srpaulo	if (next == NULL || hwaddr_aton(pos, r1kh->id)) {
995214503Srpaulo		wpa_printf(MSG_ERROR, "Invalid R1KH-ID: '%s'", pos);
996214503Srpaulo		os_free(r1kh);
997214503Srpaulo		return -1;
998214503Srpaulo	}
999214503Srpaulo
1000214503Srpaulo	pos = next;
1001214503Srpaulo	if (hexstr2bin(pos, r1kh->key, sizeof(r1kh->key))) {
1002214503Srpaulo		wpa_printf(MSG_ERROR, "Invalid R1KH key: '%s'", pos);
1003214503Srpaulo		os_free(r1kh);
1004214503Srpaulo		return -1;
1005214503Srpaulo	}
1006214503Srpaulo
1007214503Srpaulo	r1kh->next = bss->r1kh_list;
1008214503Srpaulo	bss->r1kh_list = r1kh;
1009214503Srpaulo
1010214503Srpaulo	return 0;
1011214503Srpaulo}
1012214503Srpaulo#endif /* CONFIG_IEEE80211R */
1013214503Srpaulo
1014214503Srpaulo
1015214503Srpaulo#ifdef CONFIG_IEEE80211N
1016214503Srpaulostatic int hostapd_config_ht_capab(struct hostapd_config *conf,
1017214503Srpaulo				   const char *capab)
1018214503Srpaulo{
1019214503Srpaulo	if (os_strstr(capab, "[LDPC]"))
1020214503Srpaulo		conf->ht_capab |= HT_CAP_INFO_LDPC_CODING_CAP;
1021214503Srpaulo	if (os_strstr(capab, "[HT40-]")) {
1022214503Srpaulo		conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
1023214503Srpaulo		conf->secondary_channel = -1;
1024214503Srpaulo	}
1025214503Srpaulo	if (os_strstr(capab, "[HT40+]")) {
1026214503Srpaulo		conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
1027214503Srpaulo		conf->secondary_channel = 1;
1028214503Srpaulo	}
1029214503Srpaulo	if (os_strstr(capab, "[SMPS-STATIC]")) {
1030214503Srpaulo		conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK;
1031214503Srpaulo		conf->ht_capab |= HT_CAP_INFO_SMPS_STATIC;
1032214503Srpaulo	}
1033214503Srpaulo	if (os_strstr(capab, "[SMPS-DYNAMIC]")) {
1034214503Srpaulo		conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK;
1035214503Srpaulo		conf->ht_capab |= HT_CAP_INFO_SMPS_DYNAMIC;
1036214503Srpaulo	}
1037214503Srpaulo	if (os_strstr(capab, "[GF]"))
1038214503Srpaulo		conf->ht_capab |= HT_CAP_INFO_GREEN_FIELD;
1039214503Srpaulo	if (os_strstr(capab, "[SHORT-GI-20]"))
1040214503Srpaulo		conf->ht_capab |= HT_CAP_INFO_SHORT_GI20MHZ;
1041214503Srpaulo	if (os_strstr(capab, "[SHORT-GI-40]"))
1042214503Srpaulo		conf->ht_capab |= HT_CAP_INFO_SHORT_GI40MHZ;
1043214503Srpaulo	if (os_strstr(capab, "[TX-STBC]"))
1044214503Srpaulo		conf->ht_capab |= HT_CAP_INFO_TX_STBC;
1045214503Srpaulo	if (os_strstr(capab, "[RX-STBC1]")) {
1046214503Srpaulo		conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK;
1047214503Srpaulo		conf->ht_capab |= HT_CAP_INFO_RX_STBC_1;
1048214503Srpaulo	}
1049214503Srpaulo	if (os_strstr(capab, "[RX-STBC12]")) {
1050214503Srpaulo		conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK;
1051214503Srpaulo		conf->ht_capab |= HT_CAP_INFO_RX_STBC_12;
1052214503Srpaulo	}
1053214503Srpaulo	if (os_strstr(capab, "[RX-STBC123]")) {
1054214503Srpaulo		conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK;
1055214503Srpaulo		conf->ht_capab |= HT_CAP_INFO_RX_STBC_123;
1056214503Srpaulo	}
1057214503Srpaulo	if (os_strstr(capab, "[DELAYED-BA]"))
1058214503Srpaulo		conf->ht_capab |= HT_CAP_INFO_DELAYED_BA;
1059214503Srpaulo	if (os_strstr(capab, "[MAX-AMSDU-7935]"))
1060214503Srpaulo		conf->ht_capab |= HT_CAP_INFO_MAX_AMSDU_SIZE;
1061214503Srpaulo	if (os_strstr(capab, "[DSSS_CCK-40]"))
1062214503Srpaulo		conf->ht_capab |= HT_CAP_INFO_DSSS_CCK40MHZ;
1063214503Srpaulo	if (os_strstr(capab, "[PSMP]"))
1064214503Srpaulo		conf->ht_capab |= HT_CAP_INFO_PSMP_SUPP;
1065214503Srpaulo	if (os_strstr(capab, "[LSIG-TXOP-PROT]"))
1066214503Srpaulo		conf->ht_capab |= HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT;
1067214503Srpaulo
1068214503Srpaulo	return 0;
1069214503Srpaulo}
1070214503Srpaulo#endif /* CONFIG_IEEE80211N */
1071214503Srpaulo
1072214503Srpaulo
1073252726Srpaulo#ifdef CONFIG_IEEE80211AC
1074252726Srpaulostatic int hostapd_config_vht_capab(struct hostapd_config *conf,
1075252726Srpaulo				    const char *capab)
1076252726Srpaulo{
1077252726Srpaulo	if (os_strstr(capab, "[MAX-MPDU-7991]"))
1078252726Srpaulo		conf->vht_capab |= VHT_CAP_MAX_MPDU_LENGTH_7991;
1079252726Srpaulo	if (os_strstr(capab, "[MAX-MPDU-11454]"))
1080252726Srpaulo		conf->vht_capab |= VHT_CAP_MAX_MPDU_LENGTH_11454;
1081252726Srpaulo	if (os_strstr(capab, "[VHT160]"))
1082252726Srpaulo		conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
1083252726Srpaulo	if (os_strstr(capab, "[VHT160-80PLUS80]"))
1084252726Srpaulo		conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
1085252726Srpaulo	if (os_strstr(capab, "[VHT160-80PLUS80]"))
1086252726Srpaulo		conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
1087252726Srpaulo	if (os_strstr(capab, "[RXLDPC]"))
1088252726Srpaulo		conf->vht_capab |= VHT_CAP_RXLDPC;
1089252726Srpaulo	if (os_strstr(capab, "[SHORT-GI-80]"))
1090252726Srpaulo		conf->vht_capab |= VHT_CAP_SHORT_GI_80;
1091252726Srpaulo	if (os_strstr(capab, "[SHORT-GI-160]"))
1092252726Srpaulo		conf->vht_capab |= VHT_CAP_SHORT_GI_160;
1093252726Srpaulo	if (os_strstr(capab, "[TX-STBC-2BY1]"))
1094252726Srpaulo		conf->vht_capab |= VHT_CAP_TXSTBC;
1095252726Srpaulo	if (os_strstr(capab, "[RX-STBC-1]"))
1096252726Srpaulo		conf->vht_capab |= VHT_CAP_RXSTBC_1;
1097252726Srpaulo	if (os_strstr(capab, "[RX-STBC-12]"))
1098252726Srpaulo		conf->vht_capab |= VHT_CAP_RXSTBC_2;
1099252726Srpaulo	if (os_strstr(capab, "[RX-STBC-123]"))
1100252726Srpaulo		conf->vht_capab |= VHT_CAP_RXSTBC_3;
1101252726Srpaulo	if (os_strstr(capab, "[RX-STBC-1234]"))
1102252726Srpaulo		conf->vht_capab |= VHT_CAP_RXSTBC_4;
1103252726Srpaulo	if (os_strstr(capab, "[SU-BEAMFORMER]"))
1104252726Srpaulo		conf->vht_capab |= VHT_CAP_MU_BEAMFORMER_CAPABLE;
1105252726Srpaulo	if (os_strstr(capab, "[SU-BEAMFORMEE]"))
1106252726Srpaulo		conf->vht_capab |= VHT_CAP_MU_BEAMFORMEE_CAPABLE;
1107252726Srpaulo	if (os_strstr(capab, "[BF-ANTENNA-2]") &&
1108252726Srpaulo	    (conf->vht_capab & VHT_CAP_MU_BEAMFORMER_CAPABLE))
1109252726Srpaulo		conf->vht_capab |= VHT_CAP_BEAMFORMER_ANTENNAS_MAX;
1110252726Srpaulo	if (os_strstr(capab, "[SOUNDING-DIMENSION-2]") &&
1111252726Srpaulo	    (conf->vht_capab & VHT_CAP_MU_BEAMFORMER_CAPABLE))
1112252726Srpaulo		conf->vht_capab |= VHT_CAP_SOUNDING_DIMENTION_MAX;
1113252726Srpaulo	if (os_strstr(capab, "[MU-BEAMFORMER]"))
1114252726Srpaulo		conf->vht_capab |= VHT_CAP_MU_BEAMFORMER_CAPABLE;
1115252726Srpaulo	if (os_strstr(capab, "[MU-BEAMFORMEE]"))
1116252726Srpaulo		conf->vht_capab |= VHT_CAP_MU_BEAMFORMEE_CAPABLE;
1117252726Srpaulo	if (os_strstr(capab, "[VHT-TXOP-PS]"))
1118252726Srpaulo		conf->vht_capab |= VHT_CAP_VHT_TXOP_PS;
1119252726Srpaulo	if (os_strstr(capab, "[HTC-VHT]"))
1120252726Srpaulo		conf->vht_capab |= VHT_CAP_HTC_VHT;
1121252726Srpaulo	if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP0]"))
1122252726Srpaulo		conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT;
1123252726Srpaulo	if (os_strstr(capab, "[VHT-LINK-ADAPT2]") &&
1124252726Srpaulo	    (conf->vht_capab & VHT_CAP_HTC_VHT))
1125252726Srpaulo		conf->vht_capab |= VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB;
1126252726Srpaulo	if (os_strstr(capab, "[VHT-LINK-ADAPT3]") &&
1127252726Srpaulo	    (conf->vht_capab & VHT_CAP_HTC_VHT))
1128252726Srpaulo		conf->vht_capab |= VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
1129252726Srpaulo	if (os_strstr(capab, "[RX-ANTENNA-PATTERN]"))
1130252726Srpaulo		conf->vht_capab |= VHT_CAP_RX_ANTENNA_PATTERN;
1131252726Srpaulo	if (os_strstr(capab, "[TX-ANTENNA-PATTERN]"))
1132252726Srpaulo		conf->vht_capab |= VHT_CAP_TX_ANTENNA_PATTERN;
1133252726Srpaulo	return 0;
1134252726Srpaulo}
1135252726Srpaulo#endif /* CONFIG_IEEE80211AC */
1136252726Srpaulo
1137252726Srpaulo
1138214503Srpaulostatic int hostapd_config_check_bss(struct hostapd_bss_config *bss,
1139214503Srpaulo				    struct hostapd_config *conf)
1140214503Srpaulo{
1141214503Srpaulo	if (bss->ieee802_1x && !bss->eap_server &&
1142214503Srpaulo	    !bss->radius->auth_servers) {
1143214503Srpaulo		wpa_printf(MSG_ERROR, "Invalid IEEE 802.1X configuration (no "
1144214503Srpaulo			   "EAP authenticator configured).");
1145214503Srpaulo		return -1;
1146214503Srpaulo	}
1147214503Srpaulo
1148252726Srpaulo	if (bss->wpa && bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
1149252726Srpaulo	    bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
1150252726Srpaulo		wpa_printf(MSG_ERROR, "WPA-PSK using RADIUS enabled, but no "
1151252726Srpaulo			   "RADIUS checking (macaddr_acl=2) enabled.");
1152252726Srpaulo		return -1;
1153252726Srpaulo	}
1154252726Srpaulo
1155214503Srpaulo	if (bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
1156214503Srpaulo	    bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL &&
1157252726Srpaulo	    bss->ssid.wpa_psk_file == NULL &&
1158252726Srpaulo	    (bss->wpa_psk_radius != PSK_RADIUS_REQUIRED ||
1159252726Srpaulo	     bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH)) {
1160214503Srpaulo		wpa_printf(MSG_ERROR, "WPA-PSK enabled, but PSK or passphrase "
1161214503Srpaulo			   "is not configured.");
1162214503Srpaulo		return -1;
1163214503Srpaulo	}
1164214503Srpaulo
1165214503Srpaulo	if (hostapd_mac_comp_empty(bss->bssid) != 0) {
1166214503Srpaulo		size_t i;
1167214503Srpaulo
1168214503Srpaulo		for (i = 0; i < conf->num_bss; i++) {
1169214503Srpaulo			if ((&conf->bss[i] != bss) &&
1170214503Srpaulo			    (hostapd_mac_comp(conf->bss[i].bssid,
1171214503Srpaulo					      bss->bssid) == 0)) {
1172214503Srpaulo				wpa_printf(MSG_ERROR, "Duplicate BSSID " MACSTR
1173214503Srpaulo					   " on interface '%s' and '%s'.",
1174214503Srpaulo					   MAC2STR(bss->bssid),
1175214503Srpaulo					   conf->bss[i].iface, bss->iface);
1176214503Srpaulo				return -1;
1177214503Srpaulo			}
1178214503Srpaulo		}
1179214503Srpaulo	}
1180214503Srpaulo
1181214503Srpaulo#ifdef CONFIG_IEEE80211R
1182252726Srpaulo	if (wpa_key_mgmt_ft(bss->wpa_key_mgmt) &&
1183214503Srpaulo	    (bss->nas_identifier == NULL ||
1184214503Srpaulo	     os_strlen(bss->nas_identifier) < 1 ||
1185214503Srpaulo	     os_strlen(bss->nas_identifier) > FT_R0KH_ID_MAX_LEN)) {
1186214503Srpaulo		wpa_printf(MSG_ERROR, "FT (IEEE 802.11r) requires "
1187214503Srpaulo			   "nas_identifier to be configured as a 1..48 octet "
1188214503Srpaulo			   "string");
1189214503Srpaulo		return -1;
1190214503Srpaulo	}
1191214503Srpaulo#endif /* CONFIG_IEEE80211R */
1192214503Srpaulo
1193214503Srpaulo#ifdef CONFIG_IEEE80211N
1194252726Srpaulo	if (conf->ieee80211n && conf->hw_mode == HOSTAPD_MODE_IEEE80211B) {
1195252726Srpaulo		bss->disable_11n = 1;
1196252726Srpaulo		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) in 11b mode is not "
1197252726Srpaulo			   "allowed, disabling HT capabilites");
1198252726Srpaulo	}
1199252726Srpaulo
1200252726Srpaulo	if (conf->ieee80211n &&
1201252726Srpaulo	    bss->ssid.security_policy == SECURITY_STATIC_WEP) {
1202252726Srpaulo		bss->disable_11n = 1;
1203252726Srpaulo		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WEP is not "
1204252726Srpaulo			   "allowed, disabling HT capabilities");
1205252726Srpaulo	}
1206252726Srpaulo
1207214503Srpaulo	if (conf->ieee80211n && bss->wpa &&
1208214503Srpaulo	    !(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
1209252726Srpaulo	    !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP))) {
1210252726Srpaulo		bss->disable_11n = 1;
1211214503Srpaulo		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 "
1212252726Srpaulo			   "requires CCMP/GCMP to be enabled, disabling HT "
1213252726Srpaulo			   "capabilities");
1214214503Srpaulo	}
1215214503Srpaulo#endif /* CONFIG_IEEE80211N */
1216214503Srpaulo
1217252726Srpaulo#ifdef CONFIG_WPS2
1218252726Srpaulo	if (bss->wps_state && bss->ignore_broadcast_ssid) {
1219252726Srpaulo		wpa_printf(MSG_INFO, "WPS: ignore_broadcast_ssid "
1220252726Srpaulo			   "configuration forced WPS to be disabled");
1221252726Srpaulo		bss->wps_state = 0;
1222252726Srpaulo	}
1223252726Srpaulo
1224252726Srpaulo	if (bss->wps_state && bss->ssid.wep.keys_set && bss->wpa == 0) {
1225252726Srpaulo		wpa_printf(MSG_INFO, "WPS: WEP configuration forced WPS to be "
1226252726Srpaulo			   "disabled");
1227252726Srpaulo		bss->wps_state = 0;
1228252726Srpaulo	}
1229252726Srpaulo
1230252726Srpaulo	if (bss->wps_state && bss->wpa &&
1231252726Srpaulo	    (!(bss->wpa & 2) ||
1232252726Srpaulo	     !(bss->rsn_pairwise & WPA_CIPHER_CCMP))) {
1233252726Srpaulo		wpa_printf(MSG_INFO, "WPS: WPA/TKIP configuration without "
1234252726Srpaulo			   "WPA2/CCMP forced WPS to be disabled");
1235252726Srpaulo		bss->wps_state = 0;
1236252726Srpaulo	}
1237252726Srpaulo#endif /* CONFIG_WPS2 */
1238252726Srpaulo
1239252726Srpaulo#ifdef CONFIG_HS20
1240252726Srpaulo	if (bss->hs20 &&
1241252726Srpaulo	    (!(bss->wpa & 2) ||
1242252726Srpaulo	     !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)))) {
1243252726Srpaulo		wpa_printf(MSG_ERROR, "HS 2.0: WPA2-Enterprise/CCMP "
1244252726Srpaulo			   "configuration is required for Hotspot 2.0 "
1245252726Srpaulo			   "functionality");
1246252726Srpaulo		return -1;
1247252726Srpaulo	}
1248252726Srpaulo#endif /* CONFIG_HS20 */
1249252726Srpaulo
1250214503Srpaulo	return 0;
1251214503Srpaulo}
1252214503Srpaulo
1253214503Srpaulo
1254214503Srpaulostatic int hostapd_config_check(struct hostapd_config *conf)
1255214503Srpaulo{
1256214503Srpaulo	size_t i;
1257214503Srpaulo
1258214503Srpaulo	if (conf->ieee80211d && (!conf->country[0] || !conf->country[1])) {
1259214503Srpaulo		wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11d without "
1260214503Srpaulo			   "setting the country_code");
1261214503Srpaulo		return -1;
1262214503Srpaulo	}
1263214503Srpaulo
1264214503Srpaulo	for (i = 0; i < conf->num_bss; i++) {
1265214503Srpaulo		if (hostapd_config_check_bss(&conf->bss[i], conf))
1266214503Srpaulo			return -1;
1267214503Srpaulo	}
1268214503Srpaulo
1269214503Srpaulo	return 0;
1270214503Srpaulo}
1271214503Srpaulo
1272214503Srpaulo
1273252726Srpaulo#ifdef CONFIG_INTERWORKING
1274252726Srpaulostatic int parse_roaming_consortium(struct hostapd_bss_config *bss, char *pos,
1275252726Srpaulo				    int line)
1276214503Srpaulo{
1277252726Srpaulo	size_t len = os_strlen(pos);
1278252726Srpaulo	u8 oi[MAX_ROAMING_CONSORTIUM_LEN];
1279214503Srpaulo
1280252726Srpaulo	struct hostapd_roaming_consortium *rc;
1281252726Srpaulo
1282252726Srpaulo	if ((len & 1) || len < 2 * 3 || len / 2 > MAX_ROAMING_CONSORTIUM_LEN ||
1283252726Srpaulo	    hexstr2bin(pos, oi, len / 2)) {
1284252726Srpaulo		wpa_printf(MSG_ERROR, "Line %d: invalid roaming_consortium "
1285252726Srpaulo			   "'%s'", line, pos);
1286252726Srpaulo		return -1;
1287214503Srpaulo	}
1288252726Srpaulo	len /= 2;
1289214503Srpaulo
1290252726Srpaulo	rc = os_realloc_array(bss->roaming_consortium,
1291252726Srpaulo			      bss->roaming_consortium_count + 1,
1292252726Srpaulo			      sizeof(struct hostapd_roaming_consortium));
1293252726Srpaulo	if (rc == NULL)
1294252726Srpaulo		return -1;
1295252726Srpaulo
1296252726Srpaulo	os_memcpy(rc[bss->roaming_consortium_count].oi, oi, len);
1297252726Srpaulo	rc[bss->roaming_consortium_count].len = len;
1298252726Srpaulo
1299252726Srpaulo	bss->roaming_consortium = rc;
1300252726Srpaulo	bss->roaming_consortium_count++;
1301252726Srpaulo
1302252726Srpaulo	return 0;
1303252726Srpaulo}
1304252726Srpaulo
1305252726Srpaulo
1306252726Srpaulostatic int parse_lang_string(struct hostapd_lang_string **array,
1307252726Srpaulo			     unsigned int *count, char *pos)
1308252726Srpaulo{
1309252726Srpaulo	char *sep;
1310252726Srpaulo	size_t clen, nlen;
1311252726Srpaulo	struct hostapd_lang_string *ls;
1312252726Srpaulo
1313252726Srpaulo	sep = os_strchr(pos, ':');
1314252726Srpaulo	if (sep == NULL)
1315252726Srpaulo		return -1;
1316252726Srpaulo	*sep++ = '\0';
1317252726Srpaulo
1318252726Srpaulo	clen = os_strlen(pos);
1319252726Srpaulo	if (clen < 2)
1320252726Srpaulo		return -1;
1321252726Srpaulo	nlen = os_strlen(sep);
1322252726Srpaulo	if (nlen > 252)
1323252726Srpaulo		return -1;
1324252726Srpaulo
1325252726Srpaulo	ls = os_realloc_array(*array, *count + 1,
1326252726Srpaulo			      sizeof(struct hostapd_lang_string));
1327252726Srpaulo	if (ls == NULL)
1328252726Srpaulo		return -1;
1329252726Srpaulo
1330252726Srpaulo	*array = ls;
1331252726Srpaulo	ls = &(*array)[*count];
1332252726Srpaulo	(*count)++;
1333252726Srpaulo
1334252726Srpaulo	os_memset(ls->lang, 0, sizeof(ls->lang));
1335252726Srpaulo	os_memcpy(ls->lang, pos, clen);
1336252726Srpaulo	ls->name_len = nlen;
1337252726Srpaulo	os_memcpy(ls->name, sep, nlen);
1338252726Srpaulo
1339252726Srpaulo	return 0;
1340252726Srpaulo}
1341252726Srpaulo
1342252726Srpaulo
1343252726Srpaulostatic int parse_venue_name(struct hostapd_bss_config *bss, char *pos,
1344252726Srpaulo			    int line)
1345252726Srpaulo{
1346252726Srpaulo	if (parse_lang_string(&bss->venue_name, &bss->venue_name_count, pos)) {
1347252726Srpaulo		wpa_printf(MSG_ERROR, "Line %d: Invalid venue_name '%s'",
1348252726Srpaulo			   line, pos);
1349252726Srpaulo		return -1;
1350214503Srpaulo	}
1351252726Srpaulo	return 0;
1352252726Srpaulo}
1353214503Srpaulo
1354252726Srpaulo
1355252726Srpaulostatic int parse_3gpp_cell_net(struct hostapd_bss_config *bss, char *buf,
1356252726Srpaulo			       int line)
1357252726Srpaulo{
1358252726Srpaulo	size_t count;
1359252726Srpaulo	char *pos;
1360252726Srpaulo	u8 *info = NULL, *ipos;
1361252726Srpaulo
1362252726Srpaulo	/* format: <MCC1,MNC1>[;<MCC2,MNC2>][;...] */
1363252726Srpaulo
1364252726Srpaulo	count = 1;
1365252726Srpaulo	for (pos = buf; *pos; pos++) {
1366252726Srpaulo		if ((*pos < '0' && *pos > '9') && *pos != ';' && *pos != ',')
1367252726Srpaulo			goto fail;
1368252726Srpaulo		if (*pos == ';')
1369252726Srpaulo			count++;
1370214503Srpaulo	}
1371252726Srpaulo	if (1 + count * 3 > 0x7f)
1372252726Srpaulo		goto fail;
1373214503Srpaulo
1374252726Srpaulo	info = os_zalloc(2 + 3 + count * 3);
1375252726Srpaulo	if (info == NULL)
1376252726Srpaulo		return -1;
1377214503Srpaulo
1378252726Srpaulo	ipos = info;
1379252726Srpaulo	*ipos++ = 0; /* GUD - Version 1 */
1380252726Srpaulo	*ipos++ = 3 + count * 3; /* User Data Header Length (UDHL) */
1381252726Srpaulo	*ipos++ = 0; /* PLMN List IEI */
1382252726Srpaulo	/* ext(b8) | Length of PLMN List value contents(b7..1) */
1383252726Srpaulo	*ipos++ = 1 + count * 3;
1384252726Srpaulo	*ipos++ = count; /* Number of PLMNs */
1385214503Srpaulo
1386252726Srpaulo	pos = buf;
1387252726Srpaulo	while (pos && *pos) {
1388252726Srpaulo		char *mcc, *mnc;
1389252726Srpaulo		size_t mnc_len;
1390252726Srpaulo
1391252726Srpaulo		mcc = pos;
1392252726Srpaulo		mnc = os_strchr(pos, ',');
1393252726Srpaulo		if (mnc == NULL)
1394252726Srpaulo			goto fail;
1395252726Srpaulo		*mnc++ = '\0';
1396252726Srpaulo		pos = os_strchr(mnc, ';');
1397252726Srpaulo		if (pos)
1398252726Srpaulo			*pos++ = '\0';
1399252726Srpaulo
1400252726Srpaulo		mnc_len = os_strlen(mnc);
1401252726Srpaulo		if (os_strlen(mcc) != 3 || (mnc_len != 2 && mnc_len != 3))
1402252726Srpaulo			goto fail;
1403252726Srpaulo
1404252726Srpaulo		/* BC coded MCC,MNC */
1405252726Srpaulo		/* MCC digit 2 | MCC digit 1 */
1406252726Srpaulo		*ipos++ = ((mcc[1] - '0') << 4) | (mcc[0] - '0');
1407252726Srpaulo		/* MNC digit 3 | MCC digit 3 */
1408252726Srpaulo		*ipos++ = (((mnc_len == 2) ? 0xf0 : ((mnc[2] - '0') << 4))) |
1409252726Srpaulo			(mcc[2] - '0');
1410252726Srpaulo		/* MNC digit 2 | MNC digit 1 */
1411252726Srpaulo		*ipos++ = ((mnc[1] - '0') << 4) | (mnc[0] - '0');
1412252726Srpaulo	}
1413252726Srpaulo
1414252726Srpaulo	os_free(bss->anqp_3gpp_cell_net);
1415252726Srpaulo	bss->anqp_3gpp_cell_net = info;
1416252726Srpaulo	bss->anqp_3gpp_cell_net_len = 2 + 3 + 3 * count;
1417252726Srpaulo	wpa_hexdump(MSG_MSGDUMP, "3GPP Cellular Network information",
1418252726Srpaulo		    bss->anqp_3gpp_cell_net, bss->anqp_3gpp_cell_net_len);
1419252726Srpaulo
1420252726Srpaulo	return 0;
1421252726Srpaulo
1422252726Srpaulofail:
1423252726Srpaulo	wpa_printf(MSG_ERROR, "Line %d: Invalid anqp_3gpp_cell_net: %s",
1424252726Srpaulo		   line, buf);
1425252726Srpaulo	os_free(info);
1426252726Srpaulo	return -1;
1427252726Srpaulo}
1428252726Srpaulo
1429252726Srpaulo
1430252726Srpaulostatic int parse_nai_realm(struct hostapd_bss_config *bss, char *buf, int line)
1431252726Srpaulo{
1432252726Srpaulo	struct hostapd_nai_realm_data *realm;
1433252726Srpaulo	size_t i, j, len;
1434252726Srpaulo	int *offsets;
1435252726Srpaulo	char *pos, *end, *rpos;
1436252726Srpaulo
1437252726Srpaulo	offsets = os_calloc(bss->nai_realm_count * MAX_NAI_REALMS,
1438252726Srpaulo			    sizeof(int));
1439252726Srpaulo	if (offsets == NULL)
1440252726Srpaulo		return -1;
1441252726Srpaulo
1442252726Srpaulo	for (i = 0; i < bss->nai_realm_count; i++) {
1443252726Srpaulo		realm = &bss->nai_realm_data[i];
1444252726Srpaulo		for (j = 0; j < MAX_NAI_REALMS; j++) {
1445252726Srpaulo			offsets[i * MAX_NAI_REALMS + j] =
1446252726Srpaulo				realm->realm[j] ?
1447252726Srpaulo				realm->realm[j] - realm->realm_buf : -1;
1448252726Srpaulo		}
1449252726Srpaulo	}
1450252726Srpaulo
1451252726Srpaulo	realm = os_realloc_array(bss->nai_realm_data, bss->nai_realm_count + 1,
1452252726Srpaulo				 sizeof(struct hostapd_nai_realm_data));
1453252726Srpaulo	if (realm == NULL) {
1454252726Srpaulo		os_free(offsets);
1455252726Srpaulo		return -1;
1456252726Srpaulo	}
1457252726Srpaulo	bss->nai_realm_data = realm;
1458252726Srpaulo
1459252726Srpaulo	/* patch the pointers after realloc */
1460252726Srpaulo	for (i = 0; i < bss->nai_realm_count; i++) {
1461252726Srpaulo		realm = &bss->nai_realm_data[i];
1462252726Srpaulo		for (j = 0; j < MAX_NAI_REALMS; j++) {
1463252726Srpaulo			int offs = offsets[i * MAX_NAI_REALMS + j];
1464252726Srpaulo			if (offs >= 0)
1465252726Srpaulo				realm->realm[j] = realm->realm_buf + offs;
1466252726Srpaulo			else
1467252726Srpaulo				realm->realm[j] = NULL;
1468252726Srpaulo		}
1469252726Srpaulo	}
1470252726Srpaulo	os_free(offsets);
1471252726Srpaulo
1472252726Srpaulo	realm = &bss->nai_realm_data[bss->nai_realm_count];
1473252726Srpaulo	os_memset(realm, 0, sizeof(*realm));
1474252726Srpaulo
1475252726Srpaulo	pos = buf;
1476252726Srpaulo	realm->encoding = atoi(pos);
1477252726Srpaulo	pos = os_strchr(pos, ',');
1478252726Srpaulo	if (pos == NULL)
1479252726Srpaulo		goto fail;
1480252726Srpaulo	pos++;
1481252726Srpaulo
1482252726Srpaulo	end = os_strchr(pos, ',');
1483252726Srpaulo	if (end) {
1484252726Srpaulo		len = end - pos;
1485252726Srpaulo		*end = '\0';
1486252726Srpaulo	} else {
1487252726Srpaulo		len = os_strlen(pos);
1488252726Srpaulo	}
1489252726Srpaulo
1490252726Srpaulo	if (len > MAX_NAI_REALMLEN) {
1491252726Srpaulo		wpa_printf(MSG_ERROR, "Too long a realm string (%d > max %d "
1492252726Srpaulo			   "characters)", (int) len, MAX_NAI_REALMLEN);
1493252726Srpaulo		goto fail;
1494252726Srpaulo	}
1495252726Srpaulo	os_memcpy(realm->realm_buf, pos, len);
1496252726Srpaulo
1497252726Srpaulo	if (end)
1498252726Srpaulo		pos = end + 1;
1499252726Srpaulo	else
1500252726Srpaulo		pos = NULL;
1501252726Srpaulo
1502252726Srpaulo	while (pos && *pos) {
1503252726Srpaulo		struct hostapd_nai_realm_eap *eap;
1504252726Srpaulo
1505252726Srpaulo		if (realm->eap_method_count >= MAX_NAI_EAP_METHODS) {
1506252726Srpaulo			wpa_printf(MSG_ERROR, "Too many EAP methods");
1507252726Srpaulo			goto fail;
1508252726Srpaulo		}
1509252726Srpaulo
1510252726Srpaulo		eap = &realm->eap_method[realm->eap_method_count];
1511252726Srpaulo		realm->eap_method_count++;
1512252726Srpaulo
1513252726Srpaulo		end = os_strchr(pos, ',');
1514252726Srpaulo		if (end == NULL)
1515252726Srpaulo			end = pos + os_strlen(pos);
1516252726Srpaulo
1517252726Srpaulo		eap->eap_method = atoi(pos);
1518252726Srpaulo		for (;;) {
1519252726Srpaulo			pos = os_strchr(pos, '[');
1520252726Srpaulo			if (pos == NULL || pos > end)
1521214503Srpaulo				break;
1522252726Srpaulo			pos++;
1523252726Srpaulo			if (eap->num_auths >= MAX_NAI_AUTH_TYPES) {
1524252726Srpaulo				wpa_printf(MSG_ERROR, "Too many auth params");
1525252726Srpaulo				goto fail;
1526214503Srpaulo			}
1527252726Srpaulo			eap->auth_id[eap->num_auths] = atoi(pos);
1528252726Srpaulo			pos = os_strchr(pos, ':');
1529252726Srpaulo			if (pos == NULL || pos > end)
1530252726Srpaulo				goto fail;
1531214503Srpaulo			pos++;
1532252726Srpaulo			eap->auth_val[eap->num_auths] = atoi(pos);
1533252726Srpaulo			pos = os_strchr(pos, ']');
1534252726Srpaulo			if (pos == NULL || pos > end)
1535252726Srpaulo				goto fail;
1536252726Srpaulo			pos++;
1537252726Srpaulo			eap->num_auths++;
1538214503Srpaulo		}
1539214503Srpaulo
1540252726Srpaulo		if (*end != ',')
1541252726Srpaulo			break;
1542252726Srpaulo
1543252726Srpaulo		pos = end + 1;
1544252726Srpaulo	}
1545252726Srpaulo
1546252726Srpaulo	/* Split realm list into null terminated realms */
1547252726Srpaulo	rpos = realm->realm_buf;
1548252726Srpaulo	i = 0;
1549252726Srpaulo	while (*rpos) {
1550252726Srpaulo		if (i >= MAX_NAI_REALMS) {
1551252726Srpaulo			wpa_printf(MSG_ERROR, "Too many realms");
1552252726Srpaulo			goto fail;
1553214503Srpaulo		}
1554252726Srpaulo		realm->realm[i++] = rpos;
1555252726Srpaulo		rpos = os_strchr(rpos, ';');
1556252726Srpaulo		if (rpos == NULL)
1557252726Srpaulo			break;
1558252726Srpaulo		*rpos++ = '\0';
1559252726Srpaulo	}
1560214503Srpaulo
1561252726Srpaulo	bss->nai_realm_count++;
1562252726Srpaulo
1563252726Srpaulo	return 0;
1564252726Srpaulo
1565252726Srpaulofail:
1566252726Srpaulo	wpa_printf(MSG_ERROR, "Line %d: invalid nai_realm '%s'", line, buf);
1567252726Srpaulo	return -1;
1568252726Srpaulo}
1569252726Srpaulo
1570252726Srpaulo#endif /* CONFIG_INTERWORKING */
1571252726Srpaulo
1572252726Srpaulo
1573252726Srpaulo#ifdef CONFIG_HS20
1574252726Srpaulostatic int hs20_parse_conn_capab(struct hostapd_bss_config *bss, char *buf,
1575252726Srpaulo				 int line)
1576252726Srpaulo{
1577252726Srpaulo	u8 *conn_cap;
1578252726Srpaulo	char *pos;
1579252726Srpaulo
1580252726Srpaulo	if (bss->hs20_connection_capability_len >= 0xfff0)
1581252726Srpaulo		return -1;
1582252726Srpaulo
1583252726Srpaulo	conn_cap = os_realloc(bss->hs20_connection_capability,
1584252726Srpaulo			      bss->hs20_connection_capability_len + 4);
1585252726Srpaulo	if (conn_cap == NULL)
1586252726Srpaulo		return -1;
1587252726Srpaulo
1588252726Srpaulo	bss->hs20_connection_capability = conn_cap;
1589252726Srpaulo	conn_cap += bss->hs20_connection_capability_len;
1590252726Srpaulo	pos = buf;
1591252726Srpaulo	conn_cap[0] = atoi(pos);
1592252726Srpaulo	pos = os_strchr(pos, ':');
1593252726Srpaulo	if (pos == NULL)
1594252726Srpaulo		return -1;
1595252726Srpaulo	pos++;
1596252726Srpaulo	WPA_PUT_LE16(conn_cap + 1, atoi(pos));
1597252726Srpaulo	pos = os_strchr(pos, ':');
1598252726Srpaulo	if (pos == NULL)
1599252726Srpaulo		return -1;
1600252726Srpaulo	pos++;
1601252726Srpaulo	conn_cap[3] = atoi(pos);
1602252726Srpaulo	bss->hs20_connection_capability_len += 4;
1603252726Srpaulo
1604252726Srpaulo	return 0;
1605252726Srpaulo}
1606252726Srpaulo
1607252726Srpaulo
1608252726Srpaulostatic int hs20_parse_wan_metrics(struct hostapd_bss_config *bss, char *buf,
1609252726Srpaulo				  int line)
1610252726Srpaulo{
1611252726Srpaulo	u8 *wan_metrics;
1612252726Srpaulo	char *pos;
1613252726Srpaulo
1614252726Srpaulo	/* <WAN Info>:<DL Speed>:<UL Speed>:<DL Load>:<UL Load>:<LMD> */
1615252726Srpaulo
1616252726Srpaulo	wan_metrics = os_zalloc(13);
1617252726Srpaulo	if (wan_metrics == NULL)
1618252726Srpaulo		return -1;
1619252726Srpaulo
1620252726Srpaulo	pos = buf;
1621252726Srpaulo	/* WAN Info */
1622252726Srpaulo	if (hexstr2bin(pos, wan_metrics, 1) < 0)
1623252726Srpaulo		goto fail;
1624252726Srpaulo	pos += 2;
1625252726Srpaulo	if (*pos != ':')
1626252726Srpaulo		goto fail;
1627252726Srpaulo	pos++;
1628252726Srpaulo
1629252726Srpaulo	/* Downlink Speed */
1630252726Srpaulo	WPA_PUT_LE32(wan_metrics + 1, atoi(pos));
1631252726Srpaulo	pos = os_strchr(pos, ':');
1632252726Srpaulo	if (pos == NULL)
1633252726Srpaulo		goto fail;
1634252726Srpaulo	pos++;
1635252726Srpaulo
1636252726Srpaulo	/* Uplink Speed */
1637252726Srpaulo	WPA_PUT_LE32(wan_metrics + 5, atoi(pos));
1638252726Srpaulo	pos = os_strchr(pos, ':');
1639252726Srpaulo	if (pos == NULL)
1640252726Srpaulo		goto fail;
1641252726Srpaulo	pos++;
1642252726Srpaulo
1643252726Srpaulo	/* Downlink Load */
1644252726Srpaulo	wan_metrics[9] = atoi(pos);
1645252726Srpaulo	pos = os_strchr(pos, ':');
1646252726Srpaulo	if (pos == NULL)
1647252726Srpaulo		goto fail;
1648252726Srpaulo	pos++;
1649252726Srpaulo
1650252726Srpaulo	/* Uplink Load */
1651252726Srpaulo	wan_metrics[10] = atoi(pos);
1652252726Srpaulo	pos = os_strchr(pos, ':');
1653252726Srpaulo	if (pos == NULL)
1654252726Srpaulo		goto fail;
1655252726Srpaulo	pos++;
1656252726Srpaulo
1657252726Srpaulo	/* LMD */
1658252726Srpaulo	WPA_PUT_LE16(wan_metrics + 11, atoi(pos));
1659252726Srpaulo
1660252726Srpaulo	os_free(bss->hs20_wan_metrics);
1661252726Srpaulo	bss->hs20_wan_metrics = wan_metrics;
1662252726Srpaulo
1663252726Srpaulo	return 0;
1664252726Srpaulo
1665252726Srpaulofail:
1666252726Srpaulo	wpa_printf(MSG_ERROR, "Line %d: Invalid hs20_wan_metrics '%s'",
1667252726Srpaulo		   line, pos);
1668252726Srpaulo	os_free(wan_metrics);
1669252726Srpaulo	return -1;
1670252726Srpaulo}
1671252726Srpaulo
1672252726Srpaulo
1673252726Srpaulostatic int hs20_parse_oper_friendly_name(struct hostapd_bss_config *bss,
1674252726Srpaulo					 char *pos, int line)
1675252726Srpaulo{
1676252726Srpaulo	if (parse_lang_string(&bss->hs20_oper_friendly_name,
1677252726Srpaulo			      &bss->hs20_oper_friendly_name_count, pos)) {
1678252726Srpaulo		wpa_printf(MSG_ERROR, "Line %d: Invalid "
1679252726Srpaulo			   "hs20_oper_friendly_name '%s'", line, pos);
1680252726Srpaulo		return -1;
1681252726Srpaulo	}
1682252726Srpaulo	return 0;
1683252726Srpaulo}
1684252726Srpaulo#endif /* CONFIG_HS20 */
1685252726Srpaulo
1686252726Srpaulo
1687252726Srpaulo#ifdef CONFIG_WPS_NFC
1688252726Srpaulostatic struct wpabuf * hostapd_parse_bin(const char *buf)
1689252726Srpaulo{
1690252726Srpaulo	size_t len;
1691252726Srpaulo	struct wpabuf *ret;
1692252726Srpaulo
1693252726Srpaulo	len = os_strlen(buf);
1694252726Srpaulo	if (len & 0x01)
1695252726Srpaulo		return NULL;
1696252726Srpaulo	len /= 2;
1697252726Srpaulo
1698252726Srpaulo	ret = wpabuf_alloc(len);
1699252726Srpaulo	if (ret == NULL)
1700252726Srpaulo		return NULL;
1701252726Srpaulo
1702252726Srpaulo	if (hexstr2bin(buf, wpabuf_put(ret, len), len)) {
1703252726Srpaulo		wpabuf_free(ret);
1704252726Srpaulo		return NULL;
1705252726Srpaulo	}
1706252726Srpaulo
1707252726Srpaulo	return ret;
1708252726Srpaulo}
1709252726Srpaulo#endif /* CONFIG_WPS_NFC */
1710252726Srpaulo
1711252726Srpaulo
1712252726Srpaulostatic int hostapd_config_fill(struct hostapd_config *conf,
1713252726Srpaulo			       struct hostapd_bss_config *bss,
1714252726Srpaulo			       char *buf, char *pos, int line)
1715252726Srpaulo{
1716252726Srpaulo	int errors = 0;
1717252726Srpaulo
1718252726Srpaulo	{
1719214503Srpaulo		if (os_strcmp(buf, "interface") == 0) {
1720214503Srpaulo			os_strlcpy(conf->bss[0].iface, pos,
1721214503Srpaulo				   sizeof(conf->bss[0].iface));
1722214503Srpaulo		} else if (os_strcmp(buf, "bridge") == 0) {
1723214503Srpaulo			os_strlcpy(bss->bridge, pos, sizeof(bss->bridge));
1724252726Srpaulo		} else if (os_strcmp(buf, "wds_bridge") == 0) {
1725252726Srpaulo			os_strlcpy(bss->wds_bridge, pos,
1726252726Srpaulo				   sizeof(bss->wds_bridge));
1727214503Srpaulo		} else if (os_strcmp(buf, "driver") == 0) {
1728214503Srpaulo			int j;
1729214503Srpaulo			/* clear to get error below if setting is invalid */
1730214503Srpaulo			conf->driver = NULL;
1731214503Srpaulo			for (j = 0; wpa_drivers[j]; j++) {
1732214503Srpaulo				if (os_strcmp(pos, wpa_drivers[j]->name) == 0)
1733214503Srpaulo				{
1734214503Srpaulo					conf->driver = wpa_drivers[j];
1735214503Srpaulo					break;
1736214503Srpaulo				}
1737214503Srpaulo			}
1738214503Srpaulo			if (conf->driver == NULL) {
1739214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid/"
1740214503Srpaulo					   "unknown driver '%s'", line, pos);
1741214503Srpaulo				errors++;
1742214503Srpaulo			}
1743214503Srpaulo		} else if (os_strcmp(buf, "debug") == 0) {
1744214503Srpaulo			wpa_printf(MSG_DEBUG, "Line %d: DEPRECATED: 'debug' "
1745214503Srpaulo				   "configuration variable is not used "
1746214503Srpaulo				   "anymore", line);
1747214503Srpaulo		} else if (os_strcmp(buf, "logger_syslog_level") == 0) {
1748214503Srpaulo			bss->logger_syslog_level = atoi(pos);
1749214503Srpaulo		} else if (os_strcmp(buf, "logger_stdout_level") == 0) {
1750214503Srpaulo			bss->logger_stdout_level = atoi(pos);
1751214503Srpaulo		} else if (os_strcmp(buf, "logger_syslog") == 0) {
1752214503Srpaulo			bss->logger_syslog = atoi(pos);
1753214503Srpaulo		} else if (os_strcmp(buf, "logger_stdout") == 0) {
1754214503Srpaulo			bss->logger_stdout = atoi(pos);
1755214503Srpaulo		} else if (os_strcmp(buf, "dump_file") == 0) {
1756214503Srpaulo			bss->dump_log_name = os_strdup(pos);
1757214503Srpaulo		} else if (os_strcmp(buf, "ssid") == 0) {
1758214503Srpaulo			bss->ssid.ssid_len = os_strlen(pos);
1759214503Srpaulo			if (bss->ssid.ssid_len > HOSTAPD_MAX_SSID_LEN ||
1760214503Srpaulo			    bss->ssid.ssid_len < 1) {
1761214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid SSID "
1762214503Srpaulo					   "'%s'", line, pos);
1763214503Srpaulo				errors++;
1764214503Srpaulo			} else {
1765214503Srpaulo				os_memcpy(bss->ssid.ssid, pos,
1766214503Srpaulo					  bss->ssid.ssid_len);
1767214503Srpaulo				bss->ssid.ssid_set = 1;
1768214503Srpaulo			}
1769252726Srpaulo		} else if (os_strcmp(buf, "ssid2") == 0) {
1770252726Srpaulo			size_t slen;
1771252726Srpaulo			char *str = wpa_config_parse_string(pos, &slen);
1772252726Srpaulo			if (str == NULL || slen < 1 ||
1773252726Srpaulo				   slen > HOSTAPD_MAX_SSID_LEN) {
1774252726Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid SSID "
1775252726Srpaulo					   "'%s'", line, pos);
1776252726Srpaulo				errors++;
1777252726Srpaulo			} else {
1778252726Srpaulo				os_memcpy(bss->ssid.ssid, str, slen);
1779252726Srpaulo				bss->ssid.ssid_len = slen;
1780252726Srpaulo				bss->ssid.ssid_set = 1;
1781252726Srpaulo			}
1782252726Srpaulo			os_free(str);
1783252726Srpaulo		} else if (os_strcmp(buf, "utf8_ssid") == 0) {
1784252726Srpaulo			bss->ssid.utf8_ssid = atoi(pos) > 0;
1785214503Srpaulo		} else if (os_strcmp(buf, "macaddr_acl") == 0) {
1786214503Srpaulo			bss->macaddr_acl = atoi(pos);
1787214503Srpaulo			if (bss->macaddr_acl != ACCEPT_UNLESS_DENIED &&
1788214503Srpaulo			    bss->macaddr_acl != DENY_UNLESS_ACCEPTED &&
1789214503Srpaulo			    bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
1790214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: unknown "
1791214503Srpaulo					   "macaddr_acl %d",
1792214503Srpaulo					   line, bss->macaddr_acl);
1793214503Srpaulo			}
1794214503Srpaulo		} else if (os_strcmp(buf, "accept_mac_file") == 0) {
1795214503Srpaulo			if (hostapd_config_read_maclist(pos, &bss->accept_mac,
1796214503Srpaulo							&bss->num_accept_mac))
1797214503Srpaulo			{
1798214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: Failed to "
1799214503Srpaulo					   "read accept_mac_file '%s'",
1800214503Srpaulo					   line, pos);
1801214503Srpaulo				errors++;
1802214503Srpaulo			}
1803214503Srpaulo		} else if (os_strcmp(buf, "deny_mac_file") == 0) {
1804214503Srpaulo			if (hostapd_config_read_maclist(pos, &bss->deny_mac,
1805214503Srpaulo							&bss->num_deny_mac)) {
1806214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: Failed to "
1807214503Srpaulo					   "read deny_mac_file '%s'",
1808214503Srpaulo					   line, pos);
1809214503Srpaulo				errors++;
1810214503Srpaulo			}
1811214503Srpaulo		} else if (os_strcmp(buf, "wds_sta") == 0) {
1812214503Srpaulo			bss->wds_sta = atoi(pos);
1813252726Srpaulo		} else if (os_strcmp(buf, "ap_isolate") == 0) {
1814252726Srpaulo			bss->isolate = atoi(pos);
1815214503Srpaulo		} else if (os_strcmp(buf, "ap_max_inactivity") == 0) {
1816214503Srpaulo			bss->ap_max_inactivity = atoi(pos);
1817252726Srpaulo		} else if (os_strcmp(buf, "skip_inactivity_poll") == 0) {
1818252726Srpaulo			bss->skip_inactivity_poll = atoi(pos);
1819214503Srpaulo		} else if (os_strcmp(buf, "country_code") == 0) {
1820214503Srpaulo			os_memcpy(conf->country, pos, 2);
1821214503Srpaulo			/* FIX: make this configurable */
1822214503Srpaulo			conf->country[2] = ' ';
1823214503Srpaulo		} else if (os_strcmp(buf, "ieee80211d") == 0) {
1824214503Srpaulo			conf->ieee80211d = atoi(pos);
1825214503Srpaulo		} else if (os_strcmp(buf, "ieee8021x") == 0) {
1826214503Srpaulo			bss->ieee802_1x = atoi(pos);
1827214503Srpaulo		} else if (os_strcmp(buf, "eapol_version") == 0) {
1828214503Srpaulo			bss->eapol_version = atoi(pos);
1829214503Srpaulo			if (bss->eapol_version < 1 ||
1830214503Srpaulo			    bss->eapol_version > 2) {
1831214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid EAPOL "
1832214503Srpaulo					   "version (%d): '%s'.",
1833214503Srpaulo					   line, bss->eapol_version, pos);
1834214503Srpaulo				errors++;
1835214503Srpaulo			} else
1836214503Srpaulo				wpa_printf(MSG_DEBUG, "eapol_version=%d",
1837214503Srpaulo					   bss->eapol_version);
1838214503Srpaulo#ifdef EAP_SERVER
1839214503Srpaulo		} else if (os_strcmp(buf, "eap_authenticator") == 0) {
1840214503Srpaulo			bss->eap_server = atoi(pos);
1841214503Srpaulo			wpa_printf(MSG_ERROR, "Line %d: obsolete "
1842214503Srpaulo				   "eap_authenticator used; this has been "
1843214503Srpaulo				   "renamed to eap_server", line);
1844214503Srpaulo		} else if (os_strcmp(buf, "eap_server") == 0) {
1845214503Srpaulo			bss->eap_server = atoi(pos);
1846214503Srpaulo		} else if (os_strcmp(buf, "eap_user_file") == 0) {
1847214503Srpaulo			if (hostapd_config_read_eap_user(pos, bss))
1848214503Srpaulo				errors++;
1849214503Srpaulo		} else if (os_strcmp(buf, "ca_cert") == 0) {
1850214503Srpaulo			os_free(bss->ca_cert);
1851214503Srpaulo			bss->ca_cert = os_strdup(pos);
1852214503Srpaulo		} else if (os_strcmp(buf, "server_cert") == 0) {
1853214503Srpaulo			os_free(bss->server_cert);
1854214503Srpaulo			bss->server_cert = os_strdup(pos);
1855214503Srpaulo		} else if (os_strcmp(buf, "private_key") == 0) {
1856214503Srpaulo			os_free(bss->private_key);
1857214503Srpaulo			bss->private_key = os_strdup(pos);
1858214503Srpaulo		} else if (os_strcmp(buf, "private_key_passwd") == 0) {
1859214503Srpaulo			os_free(bss->private_key_passwd);
1860214503Srpaulo			bss->private_key_passwd = os_strdup(pos);
1861214503Srpaulo		} else if (os_strcmp(buf, "check_crl") == 0) {
1862214503Srpaulo			bss->check_crl = atoi(pos);
1863214503Srpaulo		} else if (os_strcmp(buf, "dh_file") == 0) {
1864214503Srpaulo			os_free(bss->dh_file);
1865214503Srpaulo			bss->dh_file = os_strdup(pos);
1866252726Srpaulo		} else if (os_strcmp(buf, "fragment_size") == 0) {
1867252726Srpaulo			bss->fragment_size = atoi(pos);
1868214503Srpaulo#ifdef EAP_SERVER_FAST
1869214503Srpaulo		} else if (os_strcmp(buf, "pac_opaque_encr_key") == 0) {
1870214503Srpaulo			os_free(bss->pac_opaque_encr_key);
1871214503Srpaulo			bss->pac_opaque_encr_key = os_malloc(16);
1872214503Srpaulo			if (bss->pac_opaque_encr_key == NULL) {
1873214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: No memory for "
1874214503Srpaulo					   "pac_opaque_encr_key", line);
1875214503Srpaulo				errors++;
1876214503Srpaulo			} else if (hexstr2bin(pos, bss->pac_opaque_encr_key,
1877214503Srpaulo					      16)) {
1878214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: Invalid "
1879214503Srpaulo					   "pac_opaque_encr_key", line);
1880214503Srpaulo				errors++;
1881214503Srpaulo			}
1882214503Srpaulo		} else if (os_strcmp(buf, "eap_fast_a_id") == 0) {
1883214503Srpaulo			size_t idlen = os_strlen(pos);
1884214503Srpaulo			if (idlen & 1) {
1885214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: Invalid "
1886214503Srpaulo					   "eap_fast_a_id", line);
1887214503Srpaulo				errors++;
1888214503Srpaulo			} else {
1889214503Srpaulo				os_free(bss->eap_fast_a_id);
1890214503Srpaulo				bss->eap_fast_a_id = os_malloc(idlen / 2);
1891214503Srpaulo				if (bss->eap_fast_a_id == NULL ||
1892214503Srpaulo				    hexstr2bin(pos, bss->eap_fast_a_id,
1893214503Srpaulo					       idlen / 2)) {
1894214503Srpaulo					wpa_printf(MSG_ERROR, "Line %d: "
1895214503Srpaulo						   "Failed to parse "
1896214503Srpaulo						   "eap_fast_a_id", line);
1897214503Srpaulo					errors++;
1898214503Srpaulo				} else
1899214503Srpaulo					bss->eap_fast_a_id_len = idlen / 2;
1900214503Srpaulo			}
1901214503Srpaulo		} else if (os_strcmp(buf, "eap_fast_a_id_info") == 0) {
1902214503Srpaulo			os_free(bss->eap_fast_a_id_info);
1903214503Srpaulo			bss->eap_fast_a_id_info = os_strdup(pos);
1904214503Srpaulo		} else if (os_strcmp(buf, "eap_fast_prov") == 0) {
1905214503Srpaulo			bss->eap_fast_prov = atoi(pos);
1906214503Srpaulo		} else if (os_strcmp(buf, "pac_key_lifetime") == 0) {
1907214503Srpaulo			bss->pac_key_lifetime = atoi(pos);
1908214503Srpaulo		} else if (os_strcmp(buf, "pac_key_refresh_time") == 0) {
1909214503Srpaulo			bss->pac_key_refresh_time = atoi(pos);
1910214503Srpaulo#endif /* EAP_SERVER_FAST */
1911214503Srpaulo#ifdef EAP_SERVER_SIM
1912214503Srpaulo		} else if (os_strcmp(buf, "eap_sim_db") == 0) {
1913214503Srpaulo			os_free(bss->eap_sim_db);
1914214503Srpaulo			bss->eap_sim_db = os_strdup(pos);
1915214503Srpaulo		} else if (os_strcmp(buf, "eap_sim_aka_result_ind") == 0) {
1916214503Srpaulo			bss->eap_sim_aka_result_ind = atoi(pos);
1917214503Srpaulo#endif /* EAP_SERVER_SIM */
1918214503Srpaulo#ifdef EAP_SERVER_TNC
1919214503Srpaulo		} else if (os_strcmp(buf, "tnc") == 0) {
1920214503Srpaulo			bss->tnc = atoi(pos);
1921214503Srpaulo#endif /* EAP_SERVER_TNC */
1922252726Srpaulo#ifdef EAP_SERVER_PWD
1923252726Srpaulo		} else if (os_strcmp(buf, "pwd_group") == 0) {
1924252726Srpaulo			bss->pwd_group = atoi(pos);
1925252726Srpaulo#endif /* EAP_SERVER_PWD */
1926214503Srpaulo#endif /* EAP_SERVER */
1927214503Srpaulo		} else if (os_strcmp(buf, "eap_message") == 0) {
1928214503Srpaulo			char *term;
1929214503Srpaulo			bss->eap_req_id_text = os_strdup(pos);
1930214503Srpaulo			if (bss->eap_req_id_text == NULL) {
1931214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: Failed to "
1932214503Srpaulo					   "allocate memory for "
1933214503Srpaulo					   "eap_req_id_text", line);
1934214503Srpaulo				errors++;
1935252726Srpaulo				return errors;
1936214503Srpaulo			}
1937214503Srpaulo			bss->eap_req_id_text_len =
1938214503Srpaulo				os_strlen(bss->eap_req_id_text);
1939214503Srpaulo			term = os_strstr(bss->eap_req_id_text, "\\0");
1940214503Srpaulo			if (term) {
1941214503Srpaulo				*term++ = '\0';
1942214503Srpaulo				os_memmove(term, term + 1,
1943214503Srpaulo					   bss->eap_req_id_text_len -
1944214503Srpaulo					   (term - bss->eap_req_id_text) - 1);
1945214503Srpaulo				bss->eap_req_id_text_len--;
1946214503Srpaulo			}
1947214503Srpaulo		} else if (os_strcmp(buf, "wep_key_len_broadcast") == 0) {
1948214503Srpaulo			bss->default_wep_key_len = atoi(pos);
1949214503Srpaulo			if (bss->default_wep_key_len > 13) {
1950214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid WEP "
1951214503Srpaulo					   "key len %lu (= %lu bits)", line,
1952214503Srpaulo					   (unsigned long)
1953214503Srpaulo					   bss->default_wep_key_len,
1954214503Srpaulo					   (unsigned long)
1955214503Srpaulo					   bss->default_wep_key_len * 8);
1956214503Srpaulo				errors++;
1957214503Srpaulo			}
1958214503Srpaulo		} else if (os_strcmp(buf, "wep_key_len_unicast") == 0) {
1959214503Srpaulo			bss->individual_wep_key_len = atoi(pos);
1960214503Srpaulo			if (bss->individual_wep_key_len < 0 ||
1961214503Srpaulo			    bss->individual_wep_key_len > 13) {
1962214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid WEP "
1963214503Srpaulo					   "key len %d (= %d bits)", line,
1964214503Srpaulo					   bss->individual_wep_key_len,
1965214503Srpaulo					   bss->individual_wep_key_len * 8);
1966214503Srpaulo				errors++;
1967214503Srpaulo			}
1968214503Srpaulo		} else if (os_strcmp(buf, "wep_rekey_period") == 0) {
1969214503Srpaulo			bss->wep_rekeying_period = atoi(pos);
1970214503Srpaulo			if (bss->wep_rekeying_period < 0) {
1971214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid "
1972214503Srpaulo					   "period %d",
1973214503Srpaulo					   line, bss->wep_rekeying_period);
1974214503Srpaulo				errors++;
1975214503Srpaulo			}
1976214503Srpaulo		} else if (os_strcmp(buf, "eap_reauth_period") == 0) {
1977214503Srpaulo			bss->eap_reauth_period = atoi(pos);
1978214503Srpaulo			if (bss->eap_reauth_period < 0) {
1979214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid "
1980214503Srpaulo					   "period %d",
1981214503Srpaulo					   line, bss->eap_reauth_period);
1982214503Srpaulo				errors++;
1983214503Srpaulo			}
1984214503Srpaulo		} else if (os_strcmp(buf, "eapol_key_index_workaround") == 0) {
1985214503Srpaulo			bss->eapol_key_index_workaround = atoi(pos);
1986214503Srpaulo#ifdef CONFIG_IAPP
1987214503Srpaulo		} else if (os_strcmp(buf, "iapp_interface") == 0) {
1988214503Srpaulo			bss->ieee802_11f = 1;
1989214503Srpaulo			os_strlcpy(bss->iapp_iface, pos,
1990214503Srpaulo				   sizeof(bss->iapp_iface));
1991214503Srpaulo#endif /* CONFIG_IAPP */
1992214503Srpaulo		} else if (os_strcmp(buf, "own_ip_addr") == 0) {
1993214503Srpaulo			if (hostapd_parse_ip_addr(pos, &bss->own_ip_addr)) {
1994214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid IP "
1995214503Srpaulo					   "address '%s'", line, pos);
1996214503Srpaulo				errors++;
1997214503Srpaulo			}
1998214503Srpaulo		} else if (os_strcmp(buf, "nas_identifier") == 0) {
1999214503Srpaulo			bss->nas_identifier = os_strdup(pos);
2000214503Srpaulo#ifndef CONFIG_NO_RADIUS
2001214503Srpaulo		} else if (os_strcmp(buf, "auth_server_addr") == 0) {
2002214503Srpaulo			if (hostapd_config_read_radius_addr(
2003214503Srpaulo				    &bss->radius->auth_servers,
2004214503Srpaulo				    &bss->radius->num_auth_servers, pos, 1812,
2005214503Srpaulo				    &bss->radius->auth_server)) {
2006214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid IP "
2007214503Srpaulo					   "address '%s'", line, pos);
2008214503Srpaulo				errors++;
2009214503Srpaulo			}
2010214503Srpaulo		} else if (bss->radius->auth_server &&
2011214503Srpaulo			   os_strcmp(buf, "auth_server_port") == 0) {
2012214503Srpaulo			bss->radius->auth_server->port = atoi(pos);
2013214503Srpaulo		} else if (bss->radius->auth_server &&
2014214503Srpaulo			   os_strcmp(buf, "auth_server_shared_secret") == 0) {
2015214503Srpaulo			int len = os_strlen(pos);
2016214503Srpaulo			if (len == 0) {
2017214503Srpaulo				/* RFC 2865, Ch. 3 */
2018214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: empty shared "
2019214503Srpaulo					   "secret is not allowed.", line);
2020214503Srpaulo				errors++;
2021214503Srpaulo			}
2022214503Srpaulo			bss->radius->auth_server->shared_secret =
2023214503Srpaulo				(u8 *) os_strdup(pos);
2024214503Srpaulo			bss->radius->auth_server->shared_secret_len = len;
2025214503Srpaulo		} else if (os_strcmp(buf, "acct_server_addr") == 0) {
2026214503Srpaulo			if (hostapd_config_read_radius_addr(
2027214503Srpaulo				    &bss->radius->acct_servers,
2028214503Srpaulo				    &bss->radius->num_acct_servers, pos, 1813,
2029214503Srpaulo				    &bss->radius->acct_server)) {
2030214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid IP "
2031214503Srpaulo					   "address '%s'", line, pos);
2032214503Srpaulo				errors++;
2033214503Srpaulo			}
2034214503Srpaulo		} else if (bss->radius->acct_server &&
2035214503Srpaulo			   os_strcmp(buf, "acct_server_port") == 0) {
2036214503Srpaulo			bss->radius->acct_server->port = atoi(pos);
2037214503Srpaulo		} else if (bss->radius->acct_server &&
2038214503Srpaulo			   os_strcmp(buf, "acct_server_shared_secret") == 0) {
2039214503Srpaulo			int len = os_strlen(pos);
2040214503Srpaulo			if (len == 0) {
2041214503Srpaulo				/* RFC 2865, Ch. 3 */
2042214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: empty shared "
2043214503Srpaulo					   "secret is not allowed.", line);
2044214503Srpaulo				errors++;
2045214503Srpaulo			}
2046214503Srpaulo			bss->radius->acct_server->shared_secret =
2047214503Srpaulo				(u8 *) os_strdup(pos);
2048214503Srpaulo			bss->radius->acct_server->shared_secret_len = len;
2049214503Srpaulo		} else if (os_strcmp(buf, "radius_retry_primary_interval") ==
2050214503Srpaulo			   0) {
2051214503Srpaulo			bss->radius->retry_primary_interval = atoi(pos);
2052214503Srpaulo		} else if (os_strcmp(buf, "radius_acct_interim_interval") == 0)
2053214503Srpaulo		{
2054214503Srpaulo			bss->acct_interim_interval = atoi(pos);
2055252726Srpaulo		} else if (os_strcmp(buf, "radius_request_cui") == 0) {
2056252726Srpaulo			bss->radius_request_cui = atoi(pos);
2057252726Srpaulo		} else if (os_strcmp(buf, "radius_auth_req_attr") == 0) {
2058252726Srpaulo			struct hostapd_radius_attr *attr, *a;
2059252726Srpaulo			attr = hostapd_parse_radius_attr(pos);
2060252726Srpaulo			if (attr == NULL) {
2061252726Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid "
2062252726Srpaulo					   "radius_auth_req_attr", line);
2063252726Srpaulo				errors++;
2064252726Srpaulo			} else if (bss->radius_auth_req_attr == NULL) {
2065252726Srpaulo				bss->radius_auth_req_attr = attr;
2066252726Srpaulo			} else {
2067252726Srpaulo				a = bss->radius_auth_req_attr;
2068252726Srpaulo				while (a->next)
2069252726Srpaulo					a = a->next;
2070252726Srpaulo				a->next = attr;
2071252726Srpaulo			}
2072252726Srpaulo		} else if (os_strcmp(buf, "radius_acct_req_attr") == 0) {
2073252726Srpaulo			struct hostapd_radius_attr *attr, *a;
2074252726Srpaulo			attr = hostapd_parse_radius_attr(pos);
2075252726Srpaulo			if (attr == NULL) {
2076252726Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid "
2077252726Srpaulo					   "radius_acct_req_attr", line);
2078252726Srpaulo				errors++;
2079252726Srpaulo			} else if (bss->radius_acct_req_attr == NULL) {
2080252726Srpaulo				bss->radius_acct_req_attr = attr;
2081252726Srpaulo			} else {
2082252726Srpaulo				a = bss->radius_acct_req_attr;
2083252726Srpaulo				while (a->next)
2084252726Srpaulo					a = a->next;
2085252726Srpaulo				a->next = attr;
2086252726Srpaulo			}
2087252726Srpaulo		} else if (os_strcmp(buf, "radius_das_port") == 0) {
2088252726Srpaulo			bss->radius_das_port = atoi(pos);
2089252726Srpaulo		} else if (os_strcmp(buf, "radius_das_client") == 0) {
2090252726Srpaulo			if (hostapd_parse_das_client(bss, pos) < 0) {
2091252726Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid "
2092252726Srpaulo					   "DAS client", line);
2093252726Srpaulo				errors++;
2094252726Srpaulo			}
2095252726Srpaulo		} else if (os_strcmp(buf, "radius_das_time_window") == 0) {
2096252726Srpaulo			bss->radius_das_time_window = atoi(pos);
2097252726Srpaulo		} else if (os_strcmp(buf, "radius_das_require_event_timestamp")
2098252726Srpaulo			   == 0) {
2099252726Srpaulo			bss->radius_das_require_event_timestamp = atoi(pos);
2100214503Srpaulo#endif /* CONFIG_NO_RADIUS */
2101214503Srpaulo		} else if (os_strcmp(buf, "auth_algs") == 0) {
2102214503Srpaulo			bss->auth_algs = atoi(pos);
2103214503Srpaulo			if (bss->auth_algs == 0) {
2104214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: no "
2105214503Srpaulo					   "authentication algorithms allowed",
2106214503Srpaulo					   line);
2107214503Srpaulo				errors++;
2108214503Srpaulo			}
2109214503Srpaulo		} else if (os_strcmp(buf, "max_num_sta") == 0) {
2110214503Srpaulo			bss->max_num_sta = atoi(pos);
2111214503Srpaulo			if (bss->max_num_sta < 0 ||
2112214503Srpaulo			    bss->max_num_sta > MAX_STA_COUNT) {
2113214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: Invalid "
2114214503Srpaulo					   "max_num_sta=%d; allowed range "
2115214503Srpaulo					   "0..%d", line, bss->max_num_sta,
2116214503Srpaulo					   MAX_STA_COUNT);
2117214503Srpaulo				errors++;
2118214503Srpaulo			}
2119214503Srpaulo		} else if (os_strcmp(buf, "wpa") == 0) {
2120214503Srpaulo			bss->wpa = atoi(pos);
2121214503Srpaulo		} else if (os_strcmp(buf, "wpa_group_rekey") == 0) {
2122214503Srpaulo			bss->wpa_group_rekey = atoi(pos);
2123214503Srpaulo		} else if (os_strcmp(buf, "wpa_strict_rekey") == 0) {
2124214503Srpaulo			bss->wpa_strict_rekey = atoi(pos);
2125214503Srpaulo		} else if (os_strcmp(buf, "wpa_gmk_rekey") == 0) {
2126214503Srpaulo			bss->wpa_gmk_rekey = atoi(pos);
2127214503Srpaulo		} else if (os_strcmp(buf, "wpa_ptk_rekey") == 0) {
2128214503Srpaulo			bss->wpa_ptk_rekey = atoi(pos);
2129214503Srpaulo		} else if (os_strcmp(buf, "wpa_passphrase") == 0) {
2130214503Srpaulo			int len = os_strlen(pos);
2131214503Srpaulo			if (len < 8 || len > 63) {
2132214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid WPA "
2133214503Srpaulo					   "passphrase length %d (expected "
2134214503Srpaulo					   "8..63)", line, len);
2135214503Srpaulo				errors++;
2136214503Srpaulo			} else {
2137214503Srpaulo				os_free(bss->ssid.wpa_passphrase);
2138214503Srpaulo				bss->ssid.wpa_passphrase = os_strdup(pos);
2139252726Srpaulo				os_free(bss->ssid.wpa_psk);
2140252726Srpaulo				bss->ssid.wpa_psk = NULL;
2141214503Srpaulo			}
2142214503Srpaulo		} else if (os_strcmp(buf, "wpa_psk") == 0) {
2143214503Srpaulo			os_free(bss->ssid.wpa_psk);
2144214503Srpaulo			bss->ssid.wpa_psk =
2145214503Srpaulo				os_zalloc(sizeof(struct hostapd_wpa_psk));
2146214503Srpaulo			if (bss->ssid.wpa_psk == NULL)
2147214503Srpaulo				errors++;
2148214503Srpaulo			else if (hexstr2bin(pos, bss->ssid.wpa_psk->psk,
2149214503Srpaulo					    PMK_LEN) ||
2150214503Srpaulo				 pos[PMK_LEN * 2] != '\0') {
2151214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: Invalid PSK "
2152214503Srpaulo					   "'%s'.", line, pos);
2153214503Srpaulo				errors++;
2154214503Srpaulo			} else {
2155214503Srpaulo				bss->ssid.wpa_psk->group = 1;
2156252726Srpaulo				os_free(bss->ssid.wpa_passphrase);
2157252726Srpaulo				bss->ssid.wpa_passphrase = NULL;
2158214503Srpaulo			}
2159214503Srpaulo		} else if (os_strcmp(buf, "wpa_psk_file") == 0) {
2160214503Srpaulo			os_free(bss->ssid.wpa_psk_file);
2161214503Srpaulo			bss->ssid.wpa_psk_file = os_strdup(pos);
2162214503Srpaulo			if (!bss->ssid.wpa_psk_file) {
2163214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: allocation "
2164214503Srpaulo					   "failed", line);
2165214503Srpaulo				errors++;
2166214503Srpaulo			}
2167214503Srpaulo		} else if (os_strcmp(buf, "wpa_key_mgmt") == 0) {
2168214503Srpaulo			bss->wpa_key_mgmt =
2169214503Srpaulo				hostapd_config_parse_key_mgmt(line, pos);
2170214503Srpaulo			if (bss->wpa_key_mgmt == -1)
2171214503Srpaulo				errors++;
2172252726Srpaulo		} else if (os_strcmp(buf, "wpa_psk_radius") == 0) {
2173252726Srpaulo			bss->wpa_psk_radius = atoi(pos);
2174252726Srpaulo			if (bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
2175252726Srpaulo			    bss->wpa_psk_radius != PSK_RADIUS_ACCEPTED &&
2176252726Srpaulo			    bss->wpa_psk_radius != PSK_RADIUS_REQUIRED) {
2177252726Srpaulo				wpa_printf(MSG_ERROR, "Line %d: unknown "
2178252726Srpaulo					   "wpa_psk_radius %d",
2179252726Srpaulo					   line, bss->wpa_psk_radius);
2180252726Srpaulo				errors++;
2181252726Srpaulo			}
2182214503Srpaulo		} else if (os_strcmp(buf, "wpa_pairwise") == 0) {
2183214503Srpaulo			bss->wpa_pairwise =
2184214503Srpaulo				hostapd_config_parse_cipher(line, pos);
2185214503Srpaulo			if (bss->wpa_pairwise == -1 ||
2186214503Srpaulo			    bss->wpa_pairwise == 0)
2187214503Srpaulo				errors++;
2188214503Srpaulo			else if (bss->wpa_pairwise &
2189214503Srpaulo				 (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 |
2190214503Srpaulo				  WPA_CIPHER_WEP104)) {
2191214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: unsupported "
2192214503Srpaulo					   "pairwise cipher suite '%s'",
2193214503Srpaulo					   bss->wpa_pairwise, pos);
2194214503Srpaulo				errors++;
2195214503Srpaulo			}
2196214503Srpaulo		} else if (os_strcmp(buf, "rsn_pairwise") == 0) {
2197214503Srpaulo			bss->rsn_pairwise =
2198214503Srpaulo				hostapd_config_parse_cipher(line, pos);
2199214503Srpaulo			if (bss->rsn_pairwise == -1 ||
2200214503Srpaulo			    bss->rsn_pairwise == 0)
2201214503Srpaulo				errors++;
2202214503Srpaulo			else if (bss->rsn_pairwise &
2203214503Srpaulo				 (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 |
2204214503Srpaulo				  WPA_CIPHER_WEP104)) {
2205214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: unsupported "
2206214503Srpaulo					   "pairwise cipher suite '%s'",
2207214503Srpaulo					   bss->rsn_pairwise, pos);
2208214503Srpaulo				errors++;
2209214503Srpaulo			}
2210214503Srpaulo#ifdef CONFIG_RSN_PREAUTH
2211214503Srpaulo		} else if (os_strcmp(buf, "rsn_preauth") == 0) {
2212214503Srpaulo			bss->rsn_preauth = atoi(pos);
2213214503Srpaulo		} else if (os_strcmp(buf, "rsn_preauth_interfaces") == 0) {
2214214503Srpaulo			bss->rsn_preauth_interfaces = os_strdup(pos);
2215214503Srpaulo#endif /* CONFIG_RSN_PREAUTH */
2216214503Srpaulo#ifdef CONFIG_PEERKEY
2217214503Srpaulo		} else if (os_strcmp(buf, "peerkey") == 0) {
2218214503Srpaulo			bss->peerkey = atoi(pos);
2219214503Srpaulo#endif /* CONFIG_PEERKEY */
2220214503Srpaulo#ifdef CONFIG_IEEE80211R
2221214503Srpaulo		} else if (os_strcmp(buf, "mobility_domain") == 0) {
2222214503Srpaulo			if (os_strlen(pos) != 2 * MOBILITY_DOMAIN_ID_LEN ||
2223214503Srpaulo			    hexstr2bin(pos, bss->mobility_domain,
2224214503Srpaulo				       MOBILITY_DOMAIN_ID_LEN) != 0) {
2225214503Srpaulo				wpa_printf(MSG_DEBUG, "Line %d: Invalid "
2226214503Srpaulo					   "mobility_domain '%s'", line, pos);
2227214503Srpaulo				errors++;
2228252726Srpaulo				return errors;
2229214503Srpaulo			}
2230214503Srpaulo		} else if (os_strcmp(buf, "r1_key_holder") == 0) {
2231214503Srpaulo			if (os_strlen(pos) != 2 * FT_R1KH_ID_LEN ||
2232214503Srpaulo			    hexstr2bin(pos, bss->r1_key_holder,
2233214503Srpaulo				       FT_R1KH_ID_LEN) != 0) {
2234214503Srpaulo				wpa_printf(MSG_DEBUG, "Line %d: Invalid "
2235214503Srpaulo					   "r1_key_holder '%s'", line, pos);
2236214503Srpaulo				errors++;
2237252726Srpaulo				return errors;
2238214503Srpaulo			}
2239214503Srpaulo		} else if (os_strcmp(buf, "r0_key_lifetime") == 0) {
2240214503Srpaulo			bss->r0_key_lifetime = atoi(pos);
2241214503Srpaulo		} else if (os_strcmp(buf, "reassociation_deadline") == 0) {
2242214503Srpaulo			bss->reassociation_deadline = atoi(pos);
2243214503Srpaulo		} else if (os_strcmp(buf, "r0kh") == 0) {
2244214503Srpaulo			if (add_r0kh(bss, pos) < 0) {
2245214503Srpaulo				wpa_printf(MSG_DEBUG, "Line %d: Invalid "
2246214503Srpaulo					   "r0kh '%s'", line, pos);
2247214503Srpaulo				errors++;
2248252726Srpaulo				return errors;
2249214503Srpaulo			}
2250214503Srpaulo		} else if (os_strcmp(buf, "r1kh") == 0) {
2251214503Srpaulo			if (add_r1kh(bss, pos) < 0) {
2252214503Srpaulo				wpa_printf(MSG_DEBUG, "Line %d: Invalid "
2253214503Srpaulo					   "r1kh '%s'", line, pos);
2254214503Srpaulo				errors++;
2255252726Srpaulo				return errors;
2256214503Srpaulo			}
2257214503Srpaulo		} else if (os_strcmp(buf, "pmk_r1_push") == 0) {
2258214503Srpaulo			bss->pmk_r1_push = atoi(pos);
2259252726Srpaulo		} else if (os_strcmp(buf, "ft_over_ds") == 0) {
2260252726Srpaulo			bss->ft_over_ds = atoi(pos);
2261214503Srpaulo#endif /* CONFIG_IEEE80211R */
2262214503Srpaulo#ifndef CONFIG_NO_CTRL_IFACE
2263214503Srpaulo		} else if (os_strcmp(buf, "ctrl_interface") == 0) {
2264214503Srpaulo			os_free(bss->ctrl_interface);
2265214503Srpaulo			bss->ctrl_interface = os_strdup(pos);
2266214503Srpaulo		} else if (os_strcmp(buf, "ctrl_interface_group") == 0) {
2267214503Srpaulo#ifndef CONFIG_NATIVE_WINDOWS
2268214503Srpaulo			struct group *grp;
2269214503Srpaulo			char *endp;
2270214503Srpaulo			const char *group = pos;
2271214503Srpaulo
2272214503Srpaulo			grp = getgrnam(group);
2273214503Srpaulo			if (grp) {
2274214503Srpaulo				bss->ctrl_interface_gid = grp->gr_gid;
2275214503Srpaulo				bss->ctrl_interface_gid_set = 1;
2276214503Srpaulo				wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
2277214503Srpaulo					   " (from group name '%s')",
2278214503Srpaulo					   bss->ctrl_interface_gid, group);
2279252726Srpaulo				return errors;
2280214503Srpaulo			}
2281214503Srpaulo
2282214503Srpaulo			/* Group name not found - try to parse this as gid */
2283214503Srpaulo			bss->ctrl_interface_gid = strtol(group, &endp, 10);
2284214503Srpaulo			if (*group == '\0' || *endp != '\0') {
2285214503Srpaulo				wpa_printf(MSG_DEBUG, "Line %d: Invalid group "
2286214503Srpaulo					   "'%s'", line, group);
2287214503Srpaulo				errors++;
2288252726Srpaulo				return errors;
2289214503Srpaulo			}
2290214503Srpaulo			bss->ctrl_interface_gid_set = 1;
2291214503Srpaulo			wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
2292214503Srpaulo				   bss->ctrl_interface_gid);
2293214503Srpaulo#endif /* CONFIG_NATIVE_WINDOWS */
2294214503Srpaulo#endif /* CONFIG_NO_CTRL_IFACE */
2295214503Srpaulo#ifdef RADIUS_SERVER
2296214503Srpaulo		} else if (os_strcmp(buf, "radius_server_clients") == 0) {
2297214503Srpaulo			os_free(bss->radius_server_clients);
2298214503Srpaulo			bss->radius_server_clients = os_strdup(pos);
2299214503Srpaulo		} else if (os_strcmp(buf, "radius_server_auth_port") == 0) {
2300214503Srpaulo			bss->radius_server_auth_port = atoi(pos);
2301214503Srpaulo		} else if (os_strcmp(buf, "radius_server_ipv6") == 0) {
2302214503Srpaulo			bss->radius_server_ipv6 = atoi(pos);
2303214503Srpaulo#endif /* RADIUS_SERVER */
2304214503Srpaulo		} else if (os_strcmp(buf, "test_socket") == 0) {
2305214503Srpaulo			os_free(bss->test_socket);
2306214503Srpaulo			bss->test_socket = os_strdup(pos);
2307214503Srpaulo		} else if (os_strcmp(buf, "use_pae_group_addr") == 0) {
2308214503Srpaulo			bss->use_pae_group_addr = atoi(pos);
2309214503Srpaulo		} else if (os_strcmp(buf, "hw_mode") == 0) {
2310214503Srpaulo			if (os_strcmp(pos, "a") == 0)
2311214503Srpaulo				conf->hw_mode = HOSTAPD_MODE_IEEE80211A;
2312214503Srpaulo			else if (os_strcmp(pos, "b") == 0)
2313214503Srpaulo				conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
2314214503Srpaulo			else if (os_strcmp(pos, "g") == 0)
2315214503Srpaulo				conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
2316252726Srpaulo			else if (os_strcmp(pos, "ad") == 0)
2317252726Srpaulo				conf->hw_mode = HOSTAPD_MODE_IEEE80211AD;
2318214503Srpaulo			else {
2319214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: unknown "
2320214503Srpaulo					   "hw_mode '%s'", line, pos);
2321214503Srpaulo				errors++;
2322214503Srpaulo			}
2323252726Srpaulo		} else if (os_strcmp(buf, "wps_rf_bands") == 0) {
2324252726Srpaulo			if (os_strcmp(pos, "a") == 0)
2325252726Srpaulo				bss->wps_rf_bands = WPS_RF_50GHZ;
2326252726Srpaulo			else if (os_strcmp(pos, "g") == 0 ||
2327252726Srpaulo				 os_strcmp(pos, "b") == 0)
2328252726Srpaulo				bss->wps_rf_bands = WPS_RF_24GHZ;
2329252726Srpaulo			else if (os_strcmp(pos, "ag") == 0 ||
2330252726Srpaulo				 os_strcmp(pos, "ga") == 0)
2331252726Srpaulo				bss->wps_rf_bands =
2332252726Srpaulo					WPS_RF_24GHZ | WPS_RF_50GHZ;
2333252726Srpaulo			else {
2334252726Srpaulo				wpa_printf(MSG_ERROR, "Line %d: unknown "
2335252726Srpaulo					   "wps_rf_band '%s'", line, pos);
2336252726Srpaulo				errors++;
2337252726Srpaulo			}
2338214503Srpaulo		} else if (os_strcmp(buf, "channel") == 0) {
2339214503Srpaulo			conf->channel = atoi(pos);
2340214503Srpaulo		} else if (os_strcmp(buf, "beacon_int") == 0) {
2341214503Srpaulo			int val = atoi(pos);
2342214503Srpaulo			/* MIB defines range as 1..65535, but very small values
2343214503Srpaulo			 * cause problems with the current implementation.
2344214503Srpaulo			 * Since it is unlikely that this small numbers are
2345214503Srpaulo			 * useful in real life scenarios, do not allow beacon
2346214503Srpaulo			 * period to be set below 15 TU. */
2347214503Srpaulo			if (val < 15 || val > 65535) {
2348214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid "
2349214503Srpaulo					   "beacon_int %d (expected "
2350214503Srpaulo					   "15..65535)", line, val);
2351214503Srpaulo				errors++;
2352214503Srpaulo			} else
2353214503Srpaulo				conf->beacon_int = val;
2354214503Srpaulo		} else if (os_strcmp(buf, "dtim_period") == 0) {
2355214503Srpaulo			bss->dtim_period = atoi(pos);
2356214503Srpaulo			if (bss->dtim_period < 1 || bss->dtim_period > 255) {
2357214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid "
2358214503Srpaulo					   "dtim_period %d",
2359214503Srpaulo					   line, bss->dtim_period);
2360214503Srpaulo				errors++;
2361214503Srpaulo			}
2362214503Srpaulo		} else if (os_strcmp(buf, "rts_threshold") == 0) {
2363214503Srpaulo			conf->rts_threshold = atoi(pos);
2364214503Srpaulo			if (conf->rts_threshold < 0 ||
2365214503Srpaulo			    conf->rts_threshold > 2347) {
2366214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid "
2367214503Srpaulo					   "rts_threshold %d",
2368214503Srpaulo					   line, conf->rts_threshold);
2369214503Srpaulo				errors++;
2370214503Srpaulo			}
2371214503Srpaulo		} else if (os_strcmp(buf, "fragm_threshold") == 0) {
2372214503Srpaulo			conf->fragm_threshold = atoi(pos);
2373214503Srpaulo			if (conf->fragm_threshold < 256 ||
2374214503Srpaulo			    conf->fragm_threshold > 2346) {
2375214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid "
2376214503Srpaulo					   "fragm_threshold %d",
2377214503Srpaulo					   line, conf->fragm_threshold);
2378214503Srpaulo				errors++;
2379214503Srpaulo			}
2380214503Srpaulo		} else if (os_strcmp(buf, "send_probe_response") == 0) {
2381214503Srpaulo			int val = atoi(pos);
2382214503Srpaulo			if (val != 0 && val != 1) {
2383214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid "
2384214503Srpaulo					   "send_probe_response %d (expected "
2385214503Srpaulo					   "0 or 1)", line, val);
2386214503Srpaulo			} else
2387214503Srpaulo				conf->send_probe_response = val;
2388214503Srpaulo		} else if (os_strcmp(buf, "supported_rates") == 0) {
2389214503Srpaulo			if (hostapd_parse_rates(&conf->supported_rates, pos)) {
2390214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid rate "
2391214503Srpaulo					   "list", line);
2392214503Srpaulo				errors++;
2393214503Srpaulo			}
2394214503Srpaulo		} else if (os_strcmp(buf, "basic_rates") == 0) {
2395214503Srpaulo			if (hostapd_parse_rates(&conf->basic_rates, pos)) {
2396214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid rate "
2397214503Srpaulo					   "list", line);
2398214503Srpaulo				errors++;
2399214503Srpaulo			}
2400214503Srpaulo		} else if (os_strcmp(buf, "preamble") == 0) {
2401214503Srpaulo			if (atoi(pos))
2402214503Srpaulo				conf->preamble = SHORT_PREAMBLE;
2403214503Srpaulo			else
2404214503Srpaulo				conf->preamble = LONG_PREAMBLE;
2405214503Srpaulo		} else if (os_strcmp(buf, "ignore_broadcast_ssid") == 0) {
2406214503Srpaulo			bss->ignore_broadcast_ssid = atoi(pos);
2407214503Srpaulo		} else if (os_strcmp(buf, "wep_default_key") == 0) {
2408214503Srpaulo			bss->ssid.wep.idx = atoi(pos);
2409214503Srpaulo			if (bss->ssid.wep.idx > 3) {
2410214503Srpaulo				wpa_printf(MSG_ERROR, "Invalid "
2411214503Srpaulo					   "wep_default_key index %d",
2412214503Srpaulo					   bss->ssid.wep.idx);
2413214503Srpaulo				errors++;
2414214503Srpaulo			}
2415214503Srpaulo		} else if (os_strcmp(buf, "wep_key0") == 0 ||
2416214503Srpaulo			   os_strcmp(buf, "wep_key1") == 0 ||
2417214503Srpaulo			   os_strcmp(buf, "wep_key2") == 0 ||
2418214503Srpaulo			   os_strcmp(buf, "wep_key3") == 0) {
2419214503Srpaulo			if (hostapd_config_read_wep(&bss->ssid.wep,
2420214503Srpaulo						    buf[7] - '0', pos)) {
2421214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid WEP "
2422214503Srpaulo					   "key '%s'", line, buf);
2423214503Srpaulo				errors++;
2424214503Srpaulo			}
2425214503Srpaulo#ifndef CONFIG_NO_VLAN
2426214503Srpaulo		} else if (os_strcmp(buf, "dynamic_vlan") == 0) {
2427214503Srpaulo			bss->ssid.dynamic_vlan = atoi(pos);
2428214503Srpaulo		} else if (os_strcmp(buf, "vlan_file") == 0) {
2429214503Srpaulo			if (hostapd_config_read_vlan_file(bss, pos)) {
2430214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: failed to "
2431214503Srpaulo					   "read VLAN file '%s'", line, pos);
2432214503Srpaulo				errors++;
2433214503Srpaulo			}
2434252726Srpaulo		} else if (os_strcmp(buf, "vlan_naming") == 0) {
2435252726Srpaulo			bss->ssid.vlan_naming = atoi(pos);
2436252726Srpaulo			if (bss->ssid.vlan_naming >= DYNAMIC_VLAN_NAMING_END ||
2437252726Srpaulo			    bss->ssid.vlan_naming < 0) {
2438252726Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid "
2439252726Srpaulo					   "naming scheme %d", line,
2440252726Srpaulo                                           bss->ssid.vlan_naming);
2441252726Srpaulo				errors++;
2442252726Srpaulo                        }
2443214503Srpaulo#ifdef CONFIG_FULL_DYNAMIC_VLAN
2444214503Srpaulo		} else if (os_strcmp(buf, "vlan_tagged_interface") == 0) {
2445214503Srpaulo			bss->ssid.vlan_tagged_interface = os_strdup(pos);
2446214503Srpaulo#endif /* CONFIG_FULL_DYNAMIC_VLAN */
2447214503Srpaulo#endif /* CONFIG_NO_VLAN */
2448214503Srpaulo		} else if (os_strcmp(buf, "ap_table_max_size") == 0) {
2449214503Srpaulo			conf->ap_table_max_size = atoi(pos);
2450214503Srpaulo		} else if (os_strcmp(buf, "ap_table_expiration_time") == 0) {
2451214503Srpaulo			conf->ap_table_expiration_time = atoi(pos);
2452214503Srpaulo		} else if (os_strncmp(buf, "tx_queue_", 9) == 0) {
2453214503Srpaulo			if (hostapd_config_tx_queue(conf, buf, pos)) {
2454214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid TX "
2455214503Srpaulo					   "queue item", line);
2456214503Srpaulo				errors++;
2457214503Srpaulo			}
2458214503Srpaulo		} else if (os_strcmp(buf, "wme_enabled") == 0 ||
2459214503Srpaulo			   os_strcmp(buf, "wmm_enabled") == 0) {
2460214503Srpaulo			bss->wmm_enabled = atoi(pos);
2461214503Srpaulo		} else if (os_strcmp(buf, "uapsd_advertisement_enabled") == 0) {
2462214503Srpaulo			bss->wmm_uapsd = atoi(pos);
2463214503Srpaulo		} else if (os_strncmp(buf, "wme_ac_", 7) == 0 ||
2464214503Srpaulo			   os_strncmp(buf, "wmm_ac_", 7) == 0) {
2465252726Srpaulo			if (hostapd_config_wmm_ac(conf->wmm_ac_params, buf,
2466252726Srpaulo						  pos)) {
2467214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid WMM "
2468214503Srpaulo					   "ac item", line);
2469214503Srpaulo				errors++;
2470214503Srpaulo			}
2471214503Srpaulo		} else if (os_strcmp(buf, "bss") == 0) {
2472214503Srpaulo			if (hostapd_config_bss(conf, pos)) {
2473214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid bss "
2474214503Srpaulo					   "item", line);
2475214503Srpaulo				errors++;
2476214503Srpaulo			}
2477214503Srpaulo		} else if (os_strcmp(buf, "bssid") == 0) {
2478214503Srpaulo			if (hwaddr_aton(pos, bss->bssid)) {
2479214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid bssid "
2480214503Srpaulo					   "item", line);
2481214503Srpaulo				errors++;
2482214503Srpaulo			}
2483214503Srpaulo#ifdef CONFIG_IEEE80211W
2484214503Srpaulo		} else if (os_strcmp(buf, "ieee80211w") == 0) {
2485214503Srpaulo			bss->ieee80211w = atoi(pos);
2486214503Srpaulo		} else if (os_strcmp(buf, "assoc_sa_query_max_timeout") == 0) {
2487214503Srpaulo			bss->assoc_sa_query_max_timeout = atoi(pos);
2488214503Srpaulo			if (bss->assoc_sa_query_max_timeout == 0) {
2489214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid "
2490214503Srpaulo					   "assoc_sa_query_max_timeout", line);
2491214503Srpaulo				errors++;
2492214503Srpaulo			}
2493214503Srpaulo		} else if (os_strcmp(buf, "assoc_sa_query_retry_timeout") == 0)
2494214503Srpaulo		{
2495214503Srpaulo			bss->assoc_sa_query_retry_timeout = atoi(pos);
2496214503Srpaulo			if (bss->assoc_sa_query_retry_timeout == 0) {
2497214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid "
2498214503Srpaulo					   "assoc_sa_query_retry_timeout",
2499214503Srpaulo					   line);
2500214503Srpaulo				errors++;
2501214503Srpaulo			}
2502214503Srpaulo#endif /* CONFIG_IEEE80211W */
2503214503Srpaulo#ifdef CONFIG_IEEE80211N
2504214503Srpaulo		} else if (os_strcmp(buf, "ieee80211n") == 0) {
2505214503Srpaulo			conf->ieee80211n = atoi(pos);
2506214503Srpaulo		} else if (os_strcmp(buf, "ht_capab") == 0) {
2507214503Srpaulo			if (hostapd_config_ht_capab(conf, pos) < 0) {
2508214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid "
2509214503Srpaulo					   "ht_capab", line);
2510214503Srpaulo				errors++;
2511214503Srpaulo			}
2512252726Srpaulo		} else if (os_strcmp(buf, "require_ht") == 0) {
2513252726Srpaulo			conf->require_ht = atoi(pos);
2514214503Srpaulo#endif /* CONFIG_IEEE80211N */
2515252726Srpaulo#ifdef CONFIG_IEEE80211AC
2516252726Srpaulo		} else if (os_strcmp(buf, "ieee80211ac") == 0) {
2517252726Srpaulo			conf->ieee80211ac = atoi(pos);
2518252726Srpaulo		} else if (os_strcmp(buf, "vht_capab") == 0) {
2519252726Srpaulo			if (hostapd_config_vht_capab(conf, pos) < 0) {
2520252726Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid "
2521252726Srpaulo					   "vht_capab", line);
2522252726Srpaulo				errors++;
2523252726Srpaulo			}
2524252726Srpaulo		} else if (os_strcmp(buf, "require_vht") == 0) {
2525252726Srpaulo			conf->require_vht = atoi(pos);
2526252726Srpaulo		} else if (os_strcmp(buf, "vht_oper_chwidth") == 0) {
2527252726Srpaulo			conf->vht_oper_chwidth = atoi(pos);
2528252726Srpaulo		} else if (os_strcmp(buf, "vht_oper_centr_freq_seg0_idx") == 0)
2529252726Srpaulo		{
2530252726Srpaulo			conf->vht_oper_centr_freq_seg0_idx = atoi(pos);
2531252726Srpaulo		} else if (os_strcmp(buf, "vht_oper_centr_freq_seg1_idx") == 0)
2532252726Srpaulo		{
2533252726Srpaulo			conf->vht_oper_centr_freq_seg1_idx = atoi(pos);
2534252726Srpaulo#endif /* CONFIG_IEEE80211AC */
2535214503Srpaulo		} else if (os_strcmp(buf, "max_listen_interval") == 0) {
2536214503Srpaulo			bss->max_listen_interval = atoi(pos);
2537252726Srpaulo		} else if (os_strcmp(buf, "disable_pmksa_caching") == 0) {
2538252726Srpaulo			bss->disable_pmksa_caching = atoi(pos);
2539214503Srpaulo		} else if (os_strcmp(buf, "okc") == 0) {
2540214503Srpaulo			bss->okc = atoi(pos);
2541214503Srpaulo#ifdef CONFIG_WPS
2542214503Srpaulo		} else if (os_strcmp(buf, "wps_state") == 0) {
2543214503Srpaulo			bss->wps_state = atoi(pos);
2544214503Srpaulo			if (bss->wps_state < 0 || bss->wps_state > 2) {
2545214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid "
2546214503Srpaulo					   "wps_state", line);
2547214503Srpaulo				errors++;
2548214503Srpaulo			}
2549214503Srpaulo		} else if (os_strcmp(buf, "ap_setup_locked") == 0) {
2550214503Srpaulo			bss->ap_setup_locked = atoi(pos);
2551214503Srpaulo		} else if (os_strcmp(buf, "uuid") == 0) {
2552214503Srpaulo			if (uuid_str2bin(pos, bss->uuid)) {
2553214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid UUID",
2554214503Srpaulo					   line);
2555214503Srpaulo				errors++;
2556214503Srpaulo			}
2557214503Srpaulo		} else if (os_strcmp(buf, "wps_pin_requests") == 0) {
2558214503Srpaulo			os_free(bss->wps_pin_requests);
2559214503Srpaulo			bss->wps_pin_requests = os_strdup(pos);
2560214503Srpaulo		} else if (os_strcmp(buf, "device_name") == 0) {
2561214503Srpaulo			if (os_strlen(pos) > 32) {
2562214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: Too long "
2563214503Srpaulo					   "device_name", line);
2564214503Srpaulo				errors++;
2565214503Srpaulo			}
2566214503Srpaulo			os_free(bss->device_name);
2567214503Srpaulo			bss->device_name = os_strdup(pos);
2568214503Srpaulo		} else if (os_strcmp(buf, "manufacturer") == 0) {
2569214503Srpaulo			if (os_strlen(pos) > 64) {
2570214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: Too long "
2571214503Srpaulo					   "manufacturer", line);
2572214503Srpaulo				errors++;
2573214503Srpaulo			}
2574214503Srpaulo			os_free(bss->manufacturer);
2575214503Srpaulo			bss->manufacturer = os_strdup(pos);
2576214503Srpaulo		} else if (os_strcmp(buf, "model_name") == 0) {
2577214503Srpaulo			if (os_strlen(pos) > 32) {
2578214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: Too long "
2579214503Srpaulo					   "model_name", line);
2580214503Srpaulo				errors++;
2581214503Srpaulo			}
2582214503Srpaulo			os_free(bss->model_name);
2583214503Srpaulo			bss->model_name = os_strdup(pos);
2584214503Srpaulo		} else if (os_strcmp(buf, "model_number") == 0) {
2585214503Srpaulo			if (os_strlen(pos) > 32) {
2586214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: Too long "
2587214503Srpaulo					   "model_number", line);
2588214503Srpaulo				errors++;
2589214503Srpaulo			}
2590214503Srpaulo			os_free(bss->model_number);
2591214503Srpaulo			bss->model_number = os_strdup(pos);
2592214503Srpaulo		} else if (os_strcmp(buf, "serial_number") == 0) {
2593214503Srpaulo			if (os_strlen(pos) > 32) {
2594214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: Too long "
2595214503Srpaulo					   "serial_number", line);
2596214503Srpaulo				errors++;
2597214503Srpaulo			}
2598214503Srpaulo			os_free(bss->serial_number);
2599214503Srpaulo			bss->serial_number = os_strdup(pos);
2600214503Srpaulo		} else if (os_strcmp(buf, "device_type") == 0) {
2601252726Srpaulo			if (wps_dev_type_str2bin(pos, bss->device_type))
2602252726Srpaulo				errors++;
2603214503Srpaulo		} else if (os_strcmp(buf, "config_methods") == 0) {
2604214503Srpaulo			os_free(bss->config_methods);
2605214503Srpaulo			bss->config_methods = os_strdup(pos);
2606214503Srpaulo		} else if (os_strcmp(buf, "os_version") == 0) {
2607214503Srpaulo			if (hexstr2bin(pos, bss->os_version, 4)) {
2608214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid "
2609214503Srpaulo					   "os_version", line);
2610214503Srpaulo				errors++;
2611214503Srpaulo			}
2612214503Srpaulo		} else if (os_strcmp(buf, "ap_pin") == 0) {
2613214503Srpaulo			os_free(bss->ap_pin);
2614214503Srpaulo			bss->ap_pin = os_strdup(pos);
2615214503Srpaulo		} else if (os_strcmp(buf, "skip_cred_build") == 0) {
2616214503Srpaulo			bss->skip_cred_build = atoi(pos);
2617214503Srpaulo		} else if (os_strcmp(buf, "extra_cred") == 0) {
2618214503Srpaulo			os_free(bss->extra_cred);
2619214503Srpaulo			bss->extra_cred =
2620214503Srpaulo				(u8 *) os_readfile(pos, &bss->extra_cred_len);
2621214503Srpaulo			if (bss->extra_cred == NULL) {
2622214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: could not "
2623214503Srpaulo					   "read Credentials from '%s'",
2624214503Srpaulo					   line, pos);
2625214503Srpaulo				errors++;
2626214503Srpaulo			}
2627214503Srpaulo		} else if (os_strcmp(buf, "wps_cred_processing") == 0) {
2628214503Srpaulo			bss->wps_cred_processing = atoi(pos);
2629214503Srpaulo		} else if (os_strcmp(buf, "ap_settings") == 0) {
2630214503Srpaulo			os_free(bss->ap_settings);
2631214503Srpaulo			bss->ap_settings =
2632214503Srpaulo				(u8 *) os_readfile(pos, &bss->ap_settings_len);
2633214503Srpaulo			if (bss->ap_settings == NULL) {
2634214503Srpaulo				wpa_printf(MSG_ERROR, "Line %d: could not "
2635214503Srpaulo					   "read AP Settings from '%s'",
2636214503Srpaulo					   line, pos);
2637214503Srpaulo				errors++;
2638214503Srpaulo			}
2639214503Srpaulo		} else if (os_strcmp(buf, "upnp_iface") == 0) {
2640214503Srpaulo			bss->upnp_iface = os_strdup(pos);
2641214503Srpaulo		} else if (os_strcmp(buf, "friendly_name") == 0) {
2642214503Srpaulo			os_free(bss->friendly_name);
2643214503Srpaulo			bss->friendly_name = os_strdup(pos);
2644214503Srpaulo		} else if (os_strcmp(buf, "manufacturer_url") == 0) {
2645214503Srpaulo			os_free(bss->manufacturer_url);
2646214503Srpaulo			bss->manufacturer_url = os_strdup(pos);
2647214503Srpaulo		} else if (os_strcmp(buf, "model_description") == 0) {
2648214503Srpaulo			os_free(bss->model_description);
2649214503Srpaulo			bss->model_description = os_strdup(pos);
2650214503Srpaulo		} else if (os_strcmp(buf, "model_url") == 0) {
2651214503Srpaulo			os_free(bss->model_url);
2652214503Srpaulo			bss->model_url = os_strdup(pos);
2653214503Srpaulo		} else if (os_strcmp(buf, "upc") == 0) {
2654214503Srpaulo			os_free(bss->upc);
2655214503Srpaulo			bss->upc = os_strdup(pos);
2656252726Srpaulo		} else if (os_strcmp(buf, "pbc_in_m1") == 0) {
2657252726Srpaulo			bss->pbc_in_m1 = atoi(pos);
2658252726Srpaulo#ifdef CONFIG_WPS_NFC
2659252726Srpaulo		} else if (os_strcmp(buf, "wps_nfc_dev_pw_id") == 0) {
2660252726Srpaulo			bss->wps_nfc_dev_pw_id = atoi(pos);
2661252726Srpaulo			if (bss->wps_nfc_dev_pw_id < 0x10 ||
2662252726Srpaulo			    bss->wps_nfc_dev_pw_id > 0xffff) {
2663252726Srpaulo				wpa_printf(MSG_ERROR, "Line %d: Invalid "
2664252726Srpaulo					   "wps_nfc_dev_pw_id value", line);
2665252726Srpaulo				errors++;
2666252726Srpaulo			}
2667252726Srpaulo		} else if (os_strcmp(buf, "wps_nfc_dh_pubkey") == 0) {
2668252726Srpaulo			wpabuf_free(bss->wps_nfc_dh_pubkey);
2669252726Srpaulo			bss->wps_nfc_dh_pubkey = hostapd_parse_bin(pos);
2670252726Srpaulo		} else if (os_strcmp(buf, "wps_nfc_dh_privkey") == 0) {
2671252726Srpaulo			wpabuf_free(bss->wps_nfc_dh_privkey);
2672252726Srpaulo			bss->wps_nfc_dh_privkey = hostapd_parse_bin(pos);
2673252726Srpaulo		} else if (os_strcmp(buf, "wps_nfc_dev_pw") == 0) {
2674252726Srpaulo			wpabuf_free(bss->wps_nfc_dev_pw);
2675252726Srpaulo			bss->wps_nfc_dev_pw = hostapd_parse_bin(pos);
2676252726Srpaulo#endif /* CONFIG_WPS_NFC */
2677214503Srpaulo#endif /* CONFIG_WPS */
2678252726Srpaulo#ifdef CONFIG_P2P_MANAGER
2679252726Srpaulo		} else if (os_strcmp(buf, "manage_p2p") == 0) {
2680252726Srpaulo			int manage = atoi(pos);
2681252726Srpaulo			if (manage)
2682252726Srpaulo				bss->p2p |= P2P_MANAGE;
2683252726Srpaulo			else
2684252726Srpaulo				bss->p2p &= ~P2P_MANAGE;
2685252726Srpaulo		} else if (os_strcmp(buf, "allow_cross_connection") == 0) {
2686252726Srpaulo			if (atoi(pos))
2687252726Srpaulo				bss->p2p |= P2P_ALLOW_CROSS_CONNECTION;
2688252726Srpaulo			else
2689252726Srpaulo				bss->p2p &= ~P2P_ALLOW_CROSS_CONNECTION;
2690252726Srpaulo#endif /* CONFIG_P2P_MANAGER */
2691252726Srpaulo		} else if (os_strcmp(buf, "disassoc_low_ack") == 0) {
2692252726Srpaulo			bss->disassoc_low_ack = atoi(pos);
2693252726Srpaulo		} else if (os_strcmp(buf, "tdls_prohibit") == 0) {
2694252726Srpaulo			int val = atoi(pos);
2695252726Srpaulo			if (val)
2696252726Srpaulo				bss->tdls |= TDLS_PROHIBIT;
2697252726Srpaulo			else
2698252726Srpaulo				bss->tdls &= ~TDLS_PROHIBIT;
2699252726Srpaulo		} else if (os_strcmp(buf, "tdls_prohibit_chan_switch") == 0) {
2700252726Srpaulo			int val = atoi(pos);
2701252726Srpaulo			if (val)
2702252726Srpaulo				bss->tdls |= TDLS_PROHIBIT_CHAN_SWITCH;
2703252726Srpaulo			else
2704252726Srpaulo				bss->tdls &= ~TDLS_PROHIBIT_CHAN_SWITCH;
2705252726Srpaulo#ifdef CONFIG_RSN_TESTING
2706252726Srpaulo		} else if (os_strcmp(buf, "rsn_testing") == 0) {
2707252726Srpaulo			extern int rsn_testing;
2708252726Srpaulo			rsn_testing = atoi(pos);
2709252726Srpaulo#endif /* CONFIG_RSN_TESTING */
2710252726Srpaulo		} else if (os_strcmp(buf, "time_advertisement") == 0) {
2711252726Srpaulo			bss->time_advertisement = atoi(pos);
2712252726Srpaulo		} else if (os_strcmp(buf, "time_zone") == 0) {
2713252726Srpaulo			size_t tz_len = os_strlen(pos);
2714252726Srpaulo			if (tz_len < 4 || tz_len > 255) {
2715252726Srpaulo				wpa_printf(MSG_DEBUG, "Line %d: invalid "
2716252726Srpaulo					   "time_zone", line);
2717252726Srpaulo				errors++;
2718252726Srpaulo				return errors;
2719252726Srpaulo			}
2720252726Srpaulo			os_free(bss->time_zone);
2721252726Srpaulo			bss->time_zone = os_strdup(pos);
2722252726Srpaulo			if (bss->time_zone == NULL)
2723252726Srpaulo				errors++;
2724252726Srpaulo#ifdef CONFIG_WNM
2725252726Srpaulo		} else if (os_strcmp(buf, "wnm_sleep_mode") == 0) {
2726252726Srpaulo			bss->wnm_sleep_mode = atoi(pos);
2727252726Srpaulo		} else if (os_strcmp(buf, "bss_transition") == 0) {
2728252726Srpaulo			bss->bss_transition = atoi(pos);
2729252726Srpaulo#endif /* CONFIG_WNM */
2730252726Srpaulo#ifdef CONFIG_INTERWORKING
2731252726Srpaulo		} else if (os_strcmp(buf, "interworking") == 0) {
2732252726Srpaulo			bss->interworking = atoi(pos);
2733252726Srpaulo		} else if (os_strcmp(buf, "access_network_type") == 0) {
2734252726Srpaulo			bss->access_network_type = atoi(pos);
2735252726Srpaulo			if (bss->access_network_type < 0 ||
2736252726Srpaulo			    bss->access_network_type > 15) {
2737252726Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid "
2738252726Srpaulo					   "access_network_type", line);
2739252726Srpaulo				errors++;
2740252726Srpaulo			}
2741252726Srpaulo		} else if (os_strcmp(buf, "internet") == 0) {
2742252726Srpaulo			bss->internet = atoi(pos);
2743252726Srpaulo		} else if (os_strcmp(buf, "asra") == 0) {
2744252726Srpaulo			bss->asra = atoi(pos);
2745252726Srpaulo		} else if (os_strcmp(buf, "esr") == 0) {
2746252726Srpaulo			bss->esr = atoi(pos);
2747252726Srpaulo		} else if (os_strcmp(buf, "uesa") == 0) {
2748252726Srpaulo			bss->uesa = atoi(pos);
2749252726Srpaulo		} else if (os_strcmp(buf, "venue_group") == 0) {
2750252726Srpaulo			bss->venue_group = atoi(pos);
2751252726Srpaulo			bss->venue_info_set = 1;
2752252726Srpaulo		} else if (os_strcmp(buf, "venue_type") == 0) {
2753252726Srpaulo			bss->venue_type = atoi(pos);
2754252726Srpaulo			bss->venue_info_set = 1;
2755252726Srpaulo		} else if (os_strcmp(buf, "hessid") == 0) {
2756252726Srpaulo			if (hwaddr_aton(pos, bss->hessid)) {
2757252726Srpaulo				wpa_printf(MSG_ERROR, "Line %d: invalid "
2758252726Srpaulo					   "hessid", line);
2759252726Srpaulo				errors++;
2760252726Srpaulo			}
2761252726Srpaulo		} else if (os_strcmp(buf, "roaming_consortium") == 0) {
2762252726Srpaulo			if (parse_roaming_consortium(bss, pos, line) < 0)
2763252726Srpaulo				errors++;
2764252726Srpaulo		} else if (os_strcmp(buf, "venue_name") == 0) {
2765252726Srpaulo			if (parse_venue_name(bss, pos, line) < 0)
2766252726Srpaulo				errors++;
2767252726Srpaulo		} else if (os_strcmp(buf, "network_auth_type") == 0) {
2768252726Srpaulo			u8 auth_type;
2769252726Srpaulo			u16 redirect_url_len;
2770252726Srpaulo			if (hexstr2bin(pos, &auth_type, 1)) {
2771252726Srpaulo				wpa_printf(MSG_ERROR, "Line %d: Invalid "
2772252726Srpaulo					   "network_auth_type '%s'",
2773252726Srpaulo					   line, pos);
2774252726Srpaulo				errors++;
2775252726Srpaulo				return errors;
2776252726Srpaulo			}
2777252726Srpaulo			if (auth_type == 0 || auth_type == 2)
2778252726Srpaulo				redirect_url_len = os_strlen(pos + 2);
2779252726Srpaulo			else
2780252726Srpaulo				redirect_url_len = 0;
2781252726Srpaulo			os_free(bss->network_auth_type);
2782252726Srpaulo			bss->network_auth_type =
2783252726Srpaulo				os_malloc(redirect_url_len + 3 + 1);
2784252726Srpaulo			if (bss->network_auth_type == NULL) {
2785252726Srpaulo				errors++;
2786252726Srpaulo				return errors;
2787252726Srpaulo			}
2788252726Srpaulo			*bss->network_auth_type = auth_type;
2789252726Srpaulo			WPA_PUT_LE16(bss->network_auth_type + 1,
2790252726Srpaulo				     redirect_url_len);
2791252726Srpaulo			if (redirect_url_len)
2792252726Srpaulo				os_memcpy(bss->network_auth_type + 3,
2793252726Srpaulo					  pos + 2, redirect_url_len);
2794252726Srpaulo			bss->network_auth_type_len = 3 + redirect_url_len;
2795252726Srpaulo		} else if (os_strcmp(buf, "ipaddr_type_availability") == 0) {
2796252726Srpaulo			if (hexstr2bin(pos, &bss->ipaddr_type_availability, 1))
2797252726Srpaulo			{
2798252726Srpaulo				wpa_printf(MSG_ERROR, "Line %d: Invalid "
2799252726Srpaulo					   "ipaddr_type_availability '%s'",
2800252726Srpaulo					   line, pos);
2801252726Srpaulo				bss->ipaddr_type_configured = 0;
2802252726Srpaulo				errors++;
2803252726Srpaulo				return errors;
2804252726Srpaulo			}
2805252726Srpaulo			bss->ipaddr_type_configured = 1;
2806252726Srpaulo		} else if (os_strcmp(buf, "domain_name") == 0) {
2807252726Srpaulo			int j, num_domains, domain_len, domain_list_len = 0;
2808252726Srpaulo			char *tok_start, *tok_prev;
2809252726Srpaulo			u8 *domain_list, *domain_ptr;
2810252726Srpaulo
2811252726Srpaulo			domain_list_len = os_strlen(pos) + 1;
2812252726Srpaulo			domain_list = os_malloc(domain_list_len);
2813252726Srpaulo			if (domain_list == NULL) {
2814252726Srpaulo				errors++;
2815252726Srpaulo				return errors;
2816252726Srpaulo			}
2817252726Srpaulo
2818252726Srpaulo			domain_ptr = domain_list;
2819252726Srpaulo			tok_prev = pos;
2820252726Srpaulo			num_domains = 1;
2821252726Srpaulo			while ((tok_prev = os_strchr(tok_prev, ','))) {
2822252726Srpaulo				num_domains++;
2823252726Srpaulo				tok_prev++;
2824252726Srpaulo			}
2825252726Srpaulo			tok_prev = pos;
2826252726Srpaulo			for (j = 0; j < num_domains; j++) {
2827252726Srpaulo				tok_start = os_strchr(tok_prev, ',');
2828252726Srpaulo				if (tok_start) {
2829252726Srpaulo					domain_len = tok_start - tok_prev;
2830252726Srpaulo					*domain_ptr = domain_len;
2831252726Srpaulo					os_memcpy(domain_ptr + 1, tok_prev,
2832252726Srpaulo						  domain_len);
2833252726Srpaulo					domain_ptr += domain_len + 1;
2834252726Srpaulo					tok_prev = ++tok_start;
2835252726Srpaulo				} else {
2836252726Srpaulo					domain_len = os_strlen(tok_prev);
2837252726Srpaulo					*domain_ptr = domain_len;
2838252726Srpaulo					os_memcpy(domain_ptr + 1, tok_prev,
2839252726Srpaulo						  domain_len);
2840252726Srpaulo					domain_ptr += domain_len + 1;
2841252726Srpaulo				}
2842252726Srpaulo			}
2843252726Srpaulo
2844252726Srpaulo			os_free(bss->domain_name);
2845252726Srpaulo			bss->domain_name = domain_list;
2846252726Srpaulo			bss->domain_name_len = domain_list_len;
2847252726Srpaulo		} else if (os_strcmp(buf, "anqp_3gpp_cell_net") == 0) {
2848252726Srpaulo			if (parse_3gpp_cell_net(bss, pos, line) < 0)
2849252726Srpaulo				errors++;
2850252726Srpaulo		} else if (os_strcmp(buf, "nai_realm") == 0) {
2851252726Srpaulo			if (parse_nai_realm(bss, pos, line) < 0)
2852252726Srpaulo				errors++;
2853252726Srpaulo		} else if (os_strcmp(buf, "gas_frag_limit") == 0) {
2854252726Srpaulo			bss->gas_frag_limit = atoi(pos);
2855252726Srpaulo		} else if (os_strcmp(buf, "gas_comeback_delay") == 0) {
2856252726Srpaulo			bss->gas_comeback_delay = atoi(pos);
2857252726Srpaulo#endif /* CONFIG_INTERWORKING */
2858252726Srpaulo#ifdef CONFIG_RADIUS_TEST
2859252726Srpaulo		} else if (os_strcmp(buf, "dump_msk_file") == 0) {
2860252726Srpaulo			os_free(bss->dump_msk_file);
2861252726Srpaulo			bss->dump_msk_file = os_strdup(pos);
2862252726Srpaulo#endif /* CONFIG_RADIUS_TEST */
2863252726Srpaulo#ifdef CONFIG_HS20
2864252726Srpaulo		} else if (os_strcmp(buf, "hs20") == 0) {
2865252726Srpaulo			bss->hs20 = atoi(pos);
2866252726Srpaulo		} else if (os_strcmp(buf, "disable_dgaf") == 0) {
2867252726Srpaulo			bss->disable_dgaf = atoi(pos);
2868252726Srpaulo		} else if (os_strcmp(buf, "hs20_oper_friendly_name") == 0) {
2869252726Srpaulo			if (hs20_parse_oper_friendly_name(bss, pos, line) < 0)
2870252726Srpaulo				errors++;
2871252726Srpaulo		} else if (os_strcmp(buf, "hs20_wan_metrics") == 0) {
2872252726Srpaulo			if (hs20_parse_wan_metrics(bss, pos, line) < 0) {
2873252726Srpaulo				errors++;
2874252726Srpaulo				return errors;
2875252726Srpaulo			}
2876252726Srpaulo		} else if (os_strcmp(buf, "hs20_conn_capab") == 0) {
2877252726Srpaulo			if (hs20_parse_conn_capab(bss, pos, line) < 0) {
2878252726Srpaulo				errors++;
2879252726Srpaulo				return errors;
2880252726Srpaulo			}
2881252726Srpaulo		} else if (os_strcmp(buf, "hs20_operating_class") == 0) {
2882252726Srpaulo			u8 *oper_class;
2883252726Srpaulo			size_t oper_class_len;
2884252726Srpaulo			oper_class_len = os_strlen(pos);
2885252726Srpaulo			if (oper_class_len < 2 || (oper_class_len & 0x01)) {
2886252726Srpaulo				wpa_printf(MSG_ERROR, "Line %d: Invalid "
2887252726Srpaulo					   "hs20_operating_class '%s'",
2888252726Srpaulo					   line, pos);
2889252726Srpaulo				errors++;
2890252726Srpaulo				return errors;
2891252726Srpaulo			}
2892252726Srpaulo			oper_class_len /= 2;
2893252726Srpaulo			oper_class = os_malloc(oper_class_len);
2894252726Srpaulo			if (oper_class == NULL) {
2895252726Srpaulo				errors++;
2896252726Srpaulo				return errors;
2897252726Srpaulo			}
2898252726Srpaulo			if (hexstr2bin(pos, oper_class, oper_class_len)) {
2899252726Srpaulo				wpa_printf(MSG_ERROR, "Line %d: Invalid "
2900252726Srpaulo					   "hs20_operating_class '%s'",
2901252726Srpaulo					   line, pos);
2902252726Srpaulo				os_free(oper_class);
2903252726Srpaulo				errors++;
2904252726Srpaulo				return errors;
2905252726Srpaulo			}
2906252726Srpaulo			os_free(bss->hs20_operating_class);
2907252726Srpaulo			bss->hs20_operating_class = oper_class;
2908252726Srpaulo			bss->hs20_operating_class_len = oper_class_len;
2909252726Srpaulo#endif /* CONFIG_HS20 */
2910252726Srpaulo		} else if (os_strcmp(buf, "vendor_elements") == 0) {
2911252726Srpaulo			struct wpabuf *elems;
2912252726Srpaulo			size_t len = os_strlen(pos);
2913252726Srpaulo			if (len & 0x01) {
2914252726Srpaulo				wpa_printf(MSG_ERROR, "Line %d: Invalid "
2915252726Srpaulo					   "vendor_elements '%s'", line, pos);
2916252726Srpaulo				return 1;
2917252726Srpaulo			}
2918252726Srpaulo			len /= 2;
2919252726Srpaulo			if (len == 0) {
2920252726Srpaulo				wpabuf_free(bss->vendor_elements);
2921252726Srpaulo				bss->vendor_elements = NULL;
2922252726Srpaulo				return 0;
2923252726Srpaulo			}
2924252726Srpaulo
2925252726Srpaulo			elems = wpabuf_alloc(len);
2926252726Srpaulo			if (elems == NULL)
2927252726Srpaulo				return 1;
2928252726Srpaulo
2929252726Srpaulo			if (hexstr2bin(pos, wpabuf_put(elems, len), len)) {
2930252726Srpaulo				wpabuf_free(elems);
2931252726Srpaulo				wpa_printf(MSG_ERROR, "Line %d: Invalid "
2932252726Srpaulo					   "vendor_elements '%s'", line, pos);
2933252726Srpaulo				return 1;
2934252726Srpaulo			}
2935252726Srpaulo
2936252726Srpaulo			wpabuf_free(bss->vendor_elements);
2937252726Srpaulo			bss->vendor_elements = elems;
2938214503Srpaulo		} else {
2939214503Srpaulo			wpa_printf(MSG_ERROR, "Line %d: unknown configuration "
2940214503Srpaulo				   "item '%s'", line, buf);
2941214503Srpaulo			errors++;
2942214503Srpaulo		}
2943214503Srpaulo	}
2944214503Srpaulo
2945252726Srpaulo	return errors;
2946252726Srpaulo}
2947214503Srpaulo
2948214503Srpaulo
2949252726Srpaulostatic void hostapd_set_security_params(struct hostapd_bss_config *bss)
2950252726Srpaulo{
2951252726Srpaulo	int pairwise;
2952252726Srpaulo
2953252726Srpaulo	if (bss->individual_wep_key_len == 0) {
2954252726Srpaulo		/* individual keys are not use; can use key idx0 for
2955252726Srpaulo		 * broadcast keys */
2956252726Srpaulo		bss->broadcast_key_idx_min = 0;
2957252726Srpaulo	}
2958252726Srpaulo
2959252726Srpaulo	/* Select group cipher based on the enabled pairwise cipher
2960252726Srpaulo	 * suites */
2961252726Srpaulo	pairwise = 0;
2962252726Srpaulo	if (bss->wpa & 1)
2963252726Srpaulo		pairwise |= bss->wpa_pairwise;
2964252726Srpaulo	if (bss->wpa & 2) {
2965252726Srpaulo		if (bss->rsn_pairwise == 0)
2966252726Srpaulo			bss->rsn_pairwise = bss->wpa_pairwise;
2967252726Srpaulo		pairwise |= bss->rsn_pairwise;
2968252726Srpaulo	}
2969252726Srpaulo	if (pairwise & WPA_CIPHER_TKIP)
2970252726Srpaulo		bss->wpa_group = WPA_CIPHER_TKIP;
2971252726Srpaulo	else if ((pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) ==
2972252726Srpaulo		 WPA_CIPHER_GCMP)
2973252726Srpaulo		bss->wpa_group = WPA_CIPHER_GCMP;
2974252726Srpaulo	else
2975252726Srpaulo		bss->wpa_group = WPA_CIPHER_CCMP;
2976252726Srpaulo
2977252726Srpaulo	bss->radius->auth_server = bss->radius->auth_servers;
2978252726Srpaulo	bss->radius->acct_server = bss->radius->acct_servers;
2979252726Srpaulo
2980252726Srpaulo	if (bss->wpa && bss->ieee802_1x) {
2981252726Srpaulo		bss->ssid.security_policy = SECURITY_WPA;
2982252726Srpaulo	} else if (bss->wpa) {
2983252726Srpaulo		bss->ssid.security_policy = SECURITY_WPA_PSK;
2984252726Srpaulo	} else if (bss->ieee802_1x) {
2985252726Srpaulo		int cipher = WPA_CIPHER_NONE;
2986252726Srpaulo		bss->ssid.security_policy = SECURITY_IEEE_802_1X;
2987252726Srpaulo		bss->ssid.wep.default_len = bss->default_wep_key_len;
2988252726Srpaulo		if (bss->default_wep_key_len)
2989252726Srpaulo			cipher = bss->default_wep_key_len >= 13 ?
2990252726Srpaulo				WPA_CIPHER_WEP104 : WPA_CIPHER_WEP40;
2991252726Srpaulo		bss->wpa_group = cipher;
2992252726Srpaulo		bss->wpa_pairwise = cipher;
2993252726Srpaulo		bss->rsn_pairwise = cipher;
2994252726Srpaulo	} else if (bss->ssid.wep.keys_set) {
2995252726Srpaulo		int cipher = WPA_CIPHER_WEP40;
2996252726Srpaulo		if (bss->ssid.wep.len[0] >= 13)
2997252726Srpaulo			cipher = WPA_CIPHER_WEP104;
2998252726Srpaulo		bss->ssid.security_policy = SECURITY_STATIC_WEP;
2999252726Srpaulo		bss->wpa_group = cipher;
3000252726Srpaulo		bss->wpa_pairwise = cipher;
3001252726Srpaulo		bss->rsn_pairwise = cipher;
3002252726Srpaulo	} else {
3003252726Srpaulo		bss->ssid.security_policy = SECURITY_PLAINTEXT;
3004252726Srpaulo		bss->wpa_group = WPA_CIPHER_NONE;
3005252726Srpaulo		bss->wpa_pairwise = WPA_CIPHER_NONE;
3006252726Srpaulo		bss->rsn_pairwise = WPA_CIPHER_NONE;
3007252726Srpaulo	}
3008252726Srpaulo}
3009252726Srpaulo
3010252726Srpaulo
3011252726Srpaulo/**
3012252726Srpaulo * hostapd_config_read - Read and parse a configuration file
3013252726Srpaulo * @fname: Configuration file name (including path, if needed)
3014252726Srpaulo * Returns: Allocated configuration data structure
3015252726Srpaulo */
3016252726Srpaulostruct hostapd_config * hostapd_config_read(const char *fname)
3017252726Srpaulo{
3018252726Srpaulo	struct hostapd_config *conf;
3019252726Srpaulo	struct hostapd_bss_config *bss;
3020252726Srpaulo	FILE *f;
3021252726Srpaulo	char buf[512], *pos;
3022252726Srpaulo	int line = 0;
3023252726Srpaulo	int errors = 0;
3024252726Srpaulo	size_t i;
3025252726Srpaulo
3026252726Srpaulo	f = fopen(fname, "r");
3027252726Srpaulo	if (f == NULL) {
3028252726Srpaulo		wpa_printf(MSG_ERROR, "Could not open configuration file '%s' "
3029252726Srpaulo			   "for reading.", fname);
3030252726Srpaulo		return NULL;
3031252726Srpaulo	}
3032252726Srpaulo
3033252726Srpaulo	conf = hostapd_config_defaults();
3034252726Srpaulo	if (conf == NULL) {
3035252726Srpaulo		fclose(f);
3036252726Srpaulo		return NULL;
3037252726Srpaulo	}
3038252726Srpaulo
3039252726Srpaulo	/* set default driver based on configuration */
3040252726Srpaulo	conf->driver = wpa_drivers[0];
3041252726Srpaulo	if (conf->driver == NULL) {
3042252726Srpaulo		wpa_printf(MSG_ERROR, "No driver wrappers registered!");
3043252726Srpaulo		hostapd_config_free(conf);
3044252726Srpaulo		fclose(f);
3045252726Srpaulo		return NULL;
3046252726Srpaulo	}
3047252726Srpaulo
3048252726Srpaulo	bss = conf->last_bss = conf->bss;
3049252726Srpaulo
3050252726Srpaulo	while (fgets(buf, sizeof(buf), f)) {
3051252726Srpaulo		bss = conf->last_bss;
3052252726Srpaulo		line++;
3053252726Srpaulo
3054252726Srpaulo		if (buf[0] == '#')
3055252726Srpaulo			continue;
3056252726Srpaulo		pos = buf;
3057252726Srpaulo		while (*pos != '\0') {
3058252726Srpaulo			if (*pos == '\n') {
3059252726Srpaulo				*pos = '\0';
3060252726Srpaulo				break;
3061252726Srpaulo			}
3062252726Srpaulo			pos++;
3063214503Srpaulo		}
3064252726Srpaulo		if (buf[0] == '\0')
3065252726Srpaulo			continue;
3066214503Srpaulo
3067252726Srpaulo		pos = os_strchr(buf, '=');
3068252726Srpaulo		if (pos == NULL) {
3069252726Srpaulo			wpa_printf(MSG_ERROR, "Line %d: invalid line '%s'",
3070252726Srpaulo				   line, buf);
3071252726Srpaulo			errors++;
3072252726Srpaulo			continue;
3073214503Srpaulo		}
3074252726Srpaulo		*pos = '\0';
3075252726Srpaulo		pos++;
3076252726Srpaulo		errors += hostapd_config_fill(conf, bss, buf, pos, line);
3077252726Srpaulo	}
3078214503Srpaulo
3079252726Srpaulo	fclose(f);
3080214503Srpaulo
3081252726Srpaulo	for (i = 0; i < conf->num_bss; i++)
3082252726Srpaulo		hostapd_set_security_params(&conf->bss[i]);
3083214503Srpaulo
3084214503Srpaulo	if (hostapd_config_check(conf))
3085214503Srpaulo		errors++;
3086214503Srpaulo
3087252726Srpaulo#ifndef WPA_IGNORE_CONFIG_ERRORS
3088214503Srpaulo	if (errors) {
3089214503Srpaulo		wpa_printf(MSG_ERROR, "%d errors found in configuration file "
3090214503Srpaulo			   "'%s'", errors, fname);
3091214503Srpaulo		hostapd_config_free(conf);
3092214503Srpaulo		conf = NULL;
3093214503Srpaulo	}
3094252726Srpaulo#endif /* WPA_IGNORE_CONFIG_ERRORS */
3095214503Srpaulo
3096214503Srpaulo	return conf;
3097214503Srpaulo}
3098252726Srpaulo
3099252726Srpaulo
3100252726Srpauloint hostapd_set_iface(struct hostapd_config *conf,
3101252726Srpaulo		      struct hostapd_bss_config *bss, char *field, char *value)
3102252726Srpaulo{
3103252726Srpaulo	int errors;
3104252726Srpaulo	size_t i;
3105252726Srpaulo
3106252726Srpaulo	errors = hostapd_config_fill(conf, bss, field, value, 0);
3107252726Srpaulo	if (errors) {
3108252726Srpaulo		wpa_printf(MSG_INFO, "Failed to set configuration field '%s' "
3109252726Srpaulo			   "to value '%s'", field, value);
3110252726Srpaulo		return -1;
3111252726Srpaulo	}
3112252726Srpaulo
3113252726Srpaulo	for (i = 0; i < conf->num_bss; i++)
3114252726Srpaulo		hostapd_set_security_params(&conf->bss[i]);
3115252726Srpaulo
3116252726Srpaulo	if (hostapd_config_check(conf)) {
3117252726Srpaulo		wpa_printf(MSG_ERROR, "Configuration check failed");
3118252726Srpaulo		return -1;
3119252726Srpaulo	}
3120252726Srpaulo
3121252726Srpaulo	return 0;
3122252726Srpaulo}
3123