config_file.c revision bd14a57187b024f49f5b9ace55ef457d8d04650a
1/*
2 * hostapd / Configuration file parser
3 * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9#include "utils/includes.h"
10#ifndef CONFIG_NATIVE_WINDOWS
11#include <grp.h>
12#endif /* CONFIG_NATIVE_WINDOWS */
13
14#include "utils/common.h"
15#include "utils/uuid.h"
16#include "common/ieee802_11_defs.h"
17#include "drivers/driver.h"
18#include "eap_server/eap.h"
19#include "radius/radius_client.h"
20#include "ap/wpa_auth.h"
21#include "ap/ap_config.h"
22#include "config_file.h"
23
24
25#ifndef CONFIG_NO_VLAN
26static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
27					 const char *fname)
28{
29	FILE *f;
30	char buf[128], *pos, *pos2;
31	int line = 0, vlan_id;
32	struct hostapd_vlan *vlan;
33
34	f = fopen(fname, "r");
35	if (!f) {
36		wpa_printf(MSG_ERROR, "VLAN file '%s' not readable.", fname);
37		return -1;
38	}
39
40	while (fgets(buf, sizeof(buf), f)) {
41		line++;
42
43		if (buf[0] == '#')
44			continue;
45		pos = buf;
46		while (*pos != '\0') {
47			if (*pos == '\n') {
48				*pos = '\0';
49				break;
50			}
51			pos++;
52		}
53		if (buf[0] == '\0')
54			continue;
55
56		if (buf[0] == '*') {
57			vlan_id = VLAN_ID_WILDCARD;
58			pos = buf + 1;
59		} else {
60			vlan_id = strtol(buf, &pos, 10);
61			if (buf == pos || vlan_id < 1 ||
62			    vlan_id > MAX_VLAN_ID) {
63				wpa_printf(MSG_ERROR, "Invalid VLAN ID at "
64					   "line %d in '%s'", line, fname);
65				fclose(f);
66				return -1;
67			}
68		}
69
70		while (*pos == ' ' || *pos == '\t')
71			pos++;
72		pos2 = pos;
73		while (*pos2 != ' ' && *pos2 != '\t' && *pos2 != '\0')
74			pos2++;
75		*pos2 = '\0';
76		if (*pos == '\0' || os_strlen(pos) > IFNAMSIZ) {
77			wpa_printf(MSG_ERROR, "Invalid VLAN ifname at line %d "
78				   "in '%s'", line, fname);
79			fclose(f);
80			return -1;
81		}
82
83		vlan = os_zalloc(sizeof(*vlan));
84		if (vlan == NULL) {
85			wpa_printf(MSG_ERROR, "Out of memory while reading "
86				   "VLAN interfaces from '%s'", fname);
87			fclose(f);
88			return -1;
89		}
90
91		vlan->vlan_id = vlan_id;
92		os_strlcpy(vlan->ifname, pos, sizeof(vlan->ifname));
93		vlan->next = bss->vlan;
94		bss->vlan = vlan;
95	}
96
97	fclose(f);
98
99	return 0;
100}
101#endif /* CONFIG_NO_VLAN */
102
103
104static int hostapd_acl_comp(const void *a, const void *b)
105{
106	const struct mac_acl_entry *aa = a;
107	const struct mac_acl_entry *bb = b;
108	return os_memcmp(aa->addr, bb->addr, sizeof(macaddr));
109}
110
111
112static int hostapd_config_read_maclist(const char *fname,
113				       struct mac_acl_entry **acl, int *num)
114{
115	FILE *f;
116	char buf[128], *pos;
117	int line = 0;
118	u8 addr[ETH_ALEN];
119	struct mac_acl_entry *newacl;
120	int vlan_id;
121
122	if (!fname)
123		return 0;
124
125	f = fopen(fname, "r");
126	if (!f) {
127		wpa_printf(MSG_ERROR, "MAC list file '%s' not found.", fname);
128		return -1;
129	}
130
131	while (fgets(buf, sizeof(buf), f)) {
132		line++;
133
134		if (buf[0] == '#')
135			continue;
136		pos = buf;
137		while (*pos != '\0') {
138			if (*pos == '\n') {
139				*pos = '\0';
140				break;
141			}
142			pos++;
143		}
144		if (buf[0] == '\0')
145			continue;
146
147		if (hwaddr_aton(buf, addr)) {
148			wpa_printf(MSG_ERROR, "Invalid MAC address '%s' at "
149				   "line %d in '%s'", buf, line, fname);
150			fclose(f);
151			return -1;
152		}
153
154		vlan_id = 0;
155		pos = buf;
156		while (*pos != '\0' && *pos != ' ' && *pos != '\t')
157			pos++;
158		while (*pos == ' ' || *pos == '\t')
159			pos++;
160		if (*pos != '\0')
161			vlan_id = atoi(pos);
162
163		newacl = os_realloc_array(*acl, *num + 1, sizeof(**acl));
164		if (newacl == NULL) {
165			wpa_printf(MSG_ERROR, "MAC list reallocation failed");
166			fclose(f);
167			return -1;
168		}
169
170		*acl = newacl;
171		os_memcpy((*acl)[*num].addr, addr, ETH_ALEN);
172		(*acl)[*num].vlan_id = vlan_id;
173		(*num)++;
174	}
175
176	fclose(f);
177
178	qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp);
179
180	return 0;
181}
182
183
184#ifdef EAP_SERVER
185static int hostapd_config_read_eap_user(const char *fname,
186					struct hostapd_bss_config *conf)
187{
188	FILE *f;
189	char buf[512], *pos, *start, *pos2;
190	int line = 0, ret = 0, num_methods;
191	struct hostapd_eap_user *user, *tail = NULL;
192
193	if (!fname)
194		return 0;
195
196	if (os_strncmp(fname, "sqlite:", 7) == 0) {
197		os_free(conf->eap_user_sqlite);
198		conf->eap_user_sqlite = os_strdup(fname + 7);
199		return 0;
200	}
201
202	f = fopen(fname, "r");
203	if (!f) {
204		wpa_printf(MSG_ERROR, "EAP user file '%s' not found.", fname);
205		return -1;
206	}
207
208	/* Lines: "user" METHOD,METHOD2 "password" (password optional) */
209	while (fgets(buf, sizeof(buf), f)) {
210		line++;
211
212		if (buf[0] == '#')
213			continue;
214		pos = buf;
215		while (*pos != '\0') {
216			if (*pos == '\n') {
217				*pos = '\0';
218				break;
219			}
220			pos++;
221		}
222		if (buf[0] == '\0')
223			continue;
224
225		user = NULL;
226
227		if (buf[0] != '"' && buf[0] != '*') {
228			wpa_printf(MSG_ERROR, "Invalid EAP identity (no \" in "
229				   "start) on line %d in '%s'", line, fname);
230			goto failed;
231		}
232
233		user = os_zalloc(sizeof(*user));
234		if (user == NULL) {
235			wpa_printf(MSG_ERROR, "EAP user allocation failed");
236			goto failed;
237		}
238		user->force_version = -1;
239
240		if (buf[0] == '*') {
241			pos = buf;
242		} else {
243			pos = buf + 1;
244			start = pos;
245			while (*pos != '"' && *pos != '\0')
246				pos++;
247			if (*pos == '\0') {
248				wpa_printf(MSG_ERROR, "Invalid EAP identity "
249					   "(no \" in end) on line %d in '%s'",
250					   line, fname);
251				goto failed;
252			}
253
254			user->identity = os_malloc(pos - start);
255			if (user->identity == NULL) {
256				wpa_printf(MSG_ERROR, "Failed to allocate "
257					   "memory for EAP identity");
258				goto failed;
259			}
260			os_memcpy(user->identity, start, pos - start);
261			user->identity_len = pos - start;
262
263			if (pos[0] == '"' && pos[1] == '*') {
264				user->wildcard_prefix = 1;
265				pos++;
266			}
267		}
268		pos++;
269		while (*pos == ' ' || *pos == '\t')
270			pos++;
271
272		if (*pos == '\0') {
273			wpa_printf(MSG_ERROR, "No EAP method on line %d in "
274				   "'%s'", line, fname);
275			goto failed;
276		}
277
278		start = pos;
279		while (*pos != ' ' && *pos != '\t' && *pos != '\0')
280			pos++;
281		if (*pos == '\0') {
282			pos = NULL;
283		} else {
284			*pos = '\0';
285			pos++;
286		}
287		num_methods = 0;
288		while (*start) {
289			char *pos3 = os_strchr(start, ',');
290			if (pos3) {
291				*pos3++ = '\0';
292			}
293			user->methods[num_methods].method =
294				eap_server_get_type(
295					start,
296					&user->methods[num_methods].vendor);
297			if (user->methods[num_methods].vendor ==
298			    EAP_VENDOR_IETF &&
299			    user->methods[num_methods].method == EAP_TYPE_NONE)
300			{
301				if (os_strcmp(start, "TTLS-PAP") == 0) {
302					user->ttls_auth |= EAP_TTLS_AUTH_PAP;
303					goto skip_eap;
304				}
305				if (os_strcmp(start, "TTLS-CHAP") == 0) {
306					user->ttls_auth |= EAP_TTLS_AUTH_CHAP;
307					goto skip_eap;
308				}
309				if (os_strcmp(start, "TTLS-MSCHAP") == 0) {
310					user->ttls_auth |=
311						EAP_TTLS_AUTH_MSCHAP;
312					goto skip_eap;
313				}
314				if (os_strcmp(start, "TTLS-MSCHAPV2") == 0) {
315					user->ttls_auth |=
316						EAP_TTLS_AUTH_MSCHAPV2;
317					goto skip_eap;
318				}
319				wpa_printf(MSG_ERROR, "Unsupported EAP type "
320					   "'%s' on line %d in '%s'",
321					   start, line, fname);
322				goto failed;
323			}
324
325			num_methods++;
326			if (num_methods >= EAP_MAX_METHODS)
327				break;
328		skip_eap:
329			if (pos3 == NULL)
330				break;
331			start = pos3;
332		}
333		if (num_methods == 0 && user->ttls_auth == 0) {
334			wpa_printf(MSG_ERROR, "No EAP types configured on "
335				   "line %d in '%s'", line, fname);
336			goto failed;
337		}
338
339		if (pos == NULL)
340			goto done;
341
342		while (*pos == ' ' || *pos == '\t')
343			pos++;
344		if (*pos == '\0')
345			goto done;
346
347		if (os_strncmp(pos, "[ver=0]", 7) == 0) {
348			user->force_version = 0;
349			goto done;
350		}
351
352		if (os_strncmp(pos, "[ver=1]", 7) == 0) {
353			user->force_version = 1;
354			goto done;
355		}
356
357		if (os_strncmp(pos, "[2]", 3) == 0) {
358			user->phase2 = 1;
359			goto done;
360		}
361
362		if (*pos == '"') {
363			pos++;
364			start = pos;
365			while (*pos != '"' && *pos != '\0')
366				pos++;
367			if (*pos == '\0') {
368				wpa_printf(MSG_ERROR, "Invalid EAP password "
369					   "(no \" in end) on line %d in '%s'",
370					   line, fname);
371				goto failed;
372			}
373
374			user->password = os_malloc(pos - start);
375			if (user->password == NULL) {
376				wpa_printf(MSG_ERROR, "Failed to allocate "
377					   "memory for EAP password");
378				goto failed;
379			}
380			os_memcpy(user->password, start, pos - start);
381			user->password_len = pos - start;
382
383			pos++;
384		} else if (os_strncmp(pos, "hash:", 5) == 0) {
385			pos += 5;
386			pos2 = pos;
387			while (*pos2 != '\0' && *pos2 != ' ' &&
388			       *pos2 != '\t' && *pos2 != '#')
389				pos2++;
390			if (pos2 - pos != 32) {
391				wpa_printf(MSG_ERROR, "Invalid password hash "
392					   "on line %d in '%s'", line, fname);
393				goto failed;
394			}
395			user->password = os_malloc(16);
396			if (user->password == NULL) {
397				wpa_printf(MSG_ERROR, "Failed to allocate "
398					   "memory for EAP password hash");
399				goto failed;
400			}
401			if (hexstr2bin(pos, user->password, 16) < 0) {
402				wpa_printf(MSG_ERROR, "Invalid hash password "
403					   "on line %d in '%s'", line, fname);
404				goto failed;
405			}
406			user->password_len = 16;
407			user->password_hash = 1;
408			pos = pos2;
409		} else {
410			pos2 = pos;
411			while (*pos2 != '\0' && *pos2 != ' ' &&
412			       *pos2 != '\t' && *pos2 != '#')
413				pos2++;
414			if ((pos2 - pos) & 1) {
415				wpa_printf(MSG_ERROR, "Invalid hex password "
416					   "on line %d in '%s'", line, fname);
417				goto failed;
418			}
419			user->password = os_malloc((pos2 - pos) / 2);
420			if (user->password == NULL) {
421				wpa_printf(MSG_ERROR, "Failed to allocate "
422					   "memory for EAP password");
423				goto failed;
424			}
425			if (hexstr2bin(pos, user->password,
426				       (pos2 - pos) / 2) < 0) {
427				wpa_printf(MSG_ERROR, "Invalid hex password "
428					   "on line %d in '%s'", line, fname);
429				goto failed;
430			}
431			user->password_len = (pos2 - pos) / 2;
432			pos = pos2;
433		}
434
435		while (*pos == ' ' || *pos == '\t')
436			pos++;
437		if (os_strncmp(pos, "[2]", 3) == 0) {
438			user->phase2 = 1;
439		}
440
441	done:
442		if (tail == NULL) {
443			tail = conf->eap_user = user;
444		} else {
445			tail->next = user;
446			tail = user;
447		}
448		continue;
449
450	failed:
451		if (user) {
452			os_free(user->password);
453			os_free(user->identity);
454			os_free(user);
455		}
456		ret = -1;
457		break;
458	}
459
460	fclose(f);
461
462	return ret;
463}
464#endif /* EAP_SERVER */
465
466
467#ifndef CONFIG_NO_RADIUS
468static int
469hostapd_config_read_radius_addr(struct hostapd_radius_server **server,
470				int *num_server, const char *val, int def_port,
471				struct hostapd_radius_server **curr_serv)
472{
473	struct hostapd_radius_server *nserv;
474	int ret;
475	static int server_index = 1;
476
477	nserv = os_realloc_array(*server, *num_server + 1, sizeof(*nserv));
478	if (nserv == NULL)
479		return -1;
480
481	*server = nserv;
482	nserv = &nserv[*num_server];
483	(*num_server)++;
484	(*curr_serv) = nserv;
485
486	os_memset(nserv, 0, sizeof(*nserv));
487	nserv->port = def_port;
488	ret = hostapd_parse_ip_addr(val, &nserv->addr);
489	nserv->index = server_index++;
490
491	return ret;
492}
493
494
495static struct hostapd_radius_attr *
496hostapd_parse_radius_attr(const char *value)
497{
498	const char *pos;
499	char syntax;
500	struct hostapd_radius_attr *attr;
501	size_t len;
502
503	attr = os_zalloc(sizeof(*attr));
504	if (attr == NULL)
505		return NULL;
506
507	attr->type = atoi(value);
508
509	pos = os_strchr(value, ':');
510	if (pos == NULL) {
511		attr->val = wpabuf_alloc(1);
512		if (attr->val == NULL) {
513			os_free(attr);
514			return NULL;
515		}
516		wpabuf_put_u8(attr->val, 0);
517		return attr;
518	}
519
520	pos++;
521	if (pos[0] == '\0' || pos[1] != ':') {
522		os_free(attr);
523		return NULL;
524	}
525	syntax = *pos++;
526	pos++;
527
528	switch (syntax) {
529	case 's':
530		attr->val = wpabuf_alloc_copy(pos, os_strlen(pos));
531		break;
532	case 'x':
533		len = os_strlen(pos);
534		if (len & 1)
535			break;
536		len /= 2;
537		attr->val = wpabuf_alloc(len);
538		if (attr->val == NULL)
539			break;
540		if (hexstr2bin(pos, wpabuf_put(attr->val, len), len) < 0) {
541			wpabuf_free(attr->val);
542			os_free(attr);
543			return NULL;
544		}
545		break;
546	case 'd':
547		attr->val = wpabuf_alloc(4);
548		if (attr->val)
549			wpabuf_put_be32(attr->val, atoi(pos));
550		break;
551	default:
552		os_free(attr);
553		return NULL;
554	}
555
556	if (attr->val == NULL) {
557		os_free(attr);
558		return NULL;
559	}
560
561	return attr;
562}
563
564
565static int hostapd_parse_das_client(struct hostapd_bss_config *bss,
566				    const char *val)
567{
568	char *secret;
569
570	secret = os_strchr(val, ' ');
571	if (secret == NULL)
572		return -1;
573
574	secret++;
575
576	if (hostapd_parse_ip_addr(val, &bss->radius_das_client_addr))
577		return -1;
578
579	os_free(bss->radius_das_shared_secret);
580	bss->radius_das_shared_secret = (u8 *) os_strdup(secret);
581	if (bss->radius_das_shared_secret == NULL)
582		return -1;
583	bss->radius_das_shared_secret_len = os_strlen(secret);
584
585	return 0;
586}
587#endif /* CONFIG_NO_RADIUS */
588
589
590static int hostapd_config_parse_key_mgmt(int line, const char *value)
591{
592	int val = 0, last;
593	char *start, *end, *buf;
594
595	buf = os_strdup(value);
596	if (buf == NULL)
597		return -1;
598	start = buf;
599
600	while (*start != '\0') {
601		while (*start == ' ' || *start == '\t')
602			start++;
603		if (*start == '\0')
604			break;
605		end = start;
606		while (*end != ' ' && *end != '\t' && *end != '\0')
607			end++;
608		last = *end == '\0';
609		*end = '\0';
610		if (os_strcmp(start, "WPA-PSK") == 0)
611			val |= WPA_KEY_MGMT_PSK;
612		else if (os_strcmp(start, "WPA-EAP") == 0)
613			val |= WPA_KEY_MGMT_IEEE8021X;
614#ifdef CONFIG_IEEE80211R
615		else if (os_strcmp(start, "FT-PSK") == 0)
616			val |= WPA_KEY_MGMT_FT_PSK;
617		else if (os_strcmp(start, "FT-EAP") == 0)
618			val |= WPA_KEY_MGMT_FT_IEEE8021X;
619#endif /* CONFIG_IEEE80211R */
620#ifdef CONFIG_IEEE80211W
621		else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
622			val |= WPA_KEY_MGMT_PSK_SHA256;
623		else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
624			val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
625#endif /* CONFIG_IEEE80211W */
626#ifdef CONFIG_SAE
627		else if (os_strcmp(start, "SAE") == 0)
628			val |= WPA_KEY_MGMT_SAE;
629		else if (os_strcmp(start, "FT-SAE") == 0)
630			val |= WPA_KEY_MGMT_FT_SAE;
631#endif /* CONFIG_SAE */
632		else {
633			wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
634				   line, start);
635			os_free(buf);
636			return -1;
637		}
638
639		if (last)
640			break;
641		start = end + 1;
642	}
643
644	os_free(buf);
645	if (val == 0) {
646		wpa_printf(MSG_ERROR, "Line %d: no key_mgmt values "
647			   "configured.", line);
648		return -1;
649	}
650
651	return val;
652}
653
654
655static int hostapd_config_parse_cipher(int line, const char *value)
656{
657	int val = wpa_parse_cipher(value);
658	if (val < 0) {
659		wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
660			   line, value);
661		return -1;
662	}
663	if (val == 0) {
664		wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.",
665			   line);
666		return -1;
667	}
668	return val;
669}
670
671
672static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
673				   char *val)
674{
675	size_t len = os_strlen(val);
676
677	if (keyidx < 0 || keyidx > 3 || wep->key[keyidx] != NULL)
678		return -1;
679
680	if (val[0] == '"') {
681		if (len < 2 || val[len - 1] != '"')
682			return -1;
683		len -= 2;
684		wep->key[keyidx] = os_malloc(len);
685		if (wep->key[keyidx] == NULL)
686			return -1;
687		os_memcpy(wep->key[keyidx], val + 1, len);
688		wep->len[keyidx] = len;
689	} else {
690		if (len & 1)
691			return -1;
692		len /= 2;
693		wep->key[keyidx] = os_malloc(len);
694		if (wep->key[keyidx] == NULL)
695			return -1;
696		wep->len[keyidx] = len;
697		if (hexstr2bin(val, wep->key[keyidx], len) < 0)
698			return -1;
699	}
700
701	wep->keys_set++;
702
703	return 0;
704}
705
706
707static int hostapd_parse_intlist(int **int_list, char *val)
708{
709	int *list;
710	int count;
711	char *pos, *end;
712
713	os_free(*int_list);
714	*int_list = NULL;
715
716	pos = val;
717	count = 0;
718	while (*pos != '\0') {
719		if (*pos == ' ')
720			count++;
721		pos++;
722	}
723
724	list = os_malloc(sizeof(int) * (count + 2));
725	if (list == NULL)
726		return -1;
727	pos = val;
728	count = 0;
729	while (*pos != '\0') {
730		end = os_strchr(pos, ' ');
731		if (end)
732			*end = '\0';
733
734		list[count++] = atoi(pos);
735		if (!end)
736			break;
737		pos = end + 1;
738	}
739	list[count] = -1;
740
741	*int_list = list;
742	return 0;
743}
744
745
746static int hostapd_config_bss(struct hostapd_config *conf, const char *ifname)
747{
748	struct hostapd_bss_config **all, *bss;
749
750	if (*ifname == '\0')
751		return -1;
752
753	all = os_realloc_array(conf->bss, conf->num_bss + 1,
754			       sizeof(struct hostapd_bss_config *));
755	if (all == NULL) {
756		wpa_printf(MSG_ERROR, "Failed to allocate memory for "
757			   "multi-BSS entry");
758		return -1;
759	}
760	conf->bss = all;
761
762	bss = os_zalloc(sizeof(*bss));
763	if (bss == NULL)
764		return -1;
765	bss->radius = os_zalloc(sizeof(*bss->radius));
766	if (bss->radius == NULL) {
767		wpa_printf(MSG_ERROR, "Failed to allocate memory for "
768			   "multi-BSS RADIUS data");
769		os_free(bss);
770		return -1;
771	}
772
773	conf->bss[conf->num_bss++] = bss;
774	conf->last_bss = bss;
775
776	hostapd_config_defaults_bss(bss);
777	os_strlcpy(bss->iface, ifname, sizeof(bss->iface));
778	os_memcpy(bss->ssid.vlan, bss->iface, IFNAMSIZ + 1);
779
780	return 0;
781}
782
783
784/* convert floats with one decimal place to value*10 int, i.e.,
785 * "1.5" will return 15 */
786static int hostapd_config_read_int10(const char *value)
787{
788	int i, d;
789	char *pos;
790
791	i = atoi(value);
792	pos = os_strchr(value, '.');
793	d = 0;
794	if (pos) {
795		pos++;
796		if (*pos >= '0' && *pos <= '9')
797			d = *pos - '0';
798	}
799
800	return i * 10 + d;
801}
802
803
804static int valid_cw(int cw)
805{
806	return (cw == 1 || cw == 3 || cw == 7 || cw == 15 || cw == 31 ||
807		cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023);
808}
809
810
811enum {
812	IEEE80211_TX_QUEUE_DATA0 = 0, /* used for EDCA AC_VO data */
813	IEEE80211_TX_QUEUE_DATA1 = 1, /* used for EDCA AC_VI data */
814	IEEE80211_TX_QUEUE_DATA2 = 2, /* used for EDCA AC_BE data */
815	IEEE80211_TX_QUEUE_DATA3 = 3 /* used for EDCA AC_BK data */
816};
817
818static int hostapd_config_tx_queue(struct hostapd_config *conf, char *name,
819				   char *val)
820{
821	int num;
822	char *pos;
823	struct hostapd_tx_queue_params *queue;
824
825	/* skip 'tx_queue_' prefix */
826	pos = name + 9;
827	if (os_strncmp(pos, "data", 4) == 0 &&
828	    pos[4] >= '0' && pos[4] <= '9' && pos[5] == '_') {
829		num = pos[4] - '0';
830		pos += 6;
831	} else if (os_strncmp(pos, "after_beacon_", 13) == 0 ||
832		   os_strncmp(pos, "beacon_", 7) == 0) {
833		wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
834		return 0;
835	} else {
836		wpa_printf(MSG_ERROR, "Unknown tx_queue name '%s'", pos);
837		return -1;
838	}
839
840	if (num >= NUM_TX_QUEUES) {
841		/* for backwards compatibility, do not trigger failure */
842		wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
843		return 0;
844	}
845
846	queue = &conf->tx_queue[num];
847
848	if (os_strcmp(pos, "aifs") == 0) {
849		queue->aifs = atoi(val);
850		if (queue->aifs < 0 || queue->aifs > 255) {
851			wpa_printf(MSG_ERROR, "Invalid AIFS value %d",
852				   queue->aifs);
853			return -1;
854		}
855	} else if (os_strcmp(pos, "cwmin") == 0) {
856		queue->cwmin = atoi(val);
857		if (!valid_cw(queue->cwmin)) {
858			wpa_printf(MSG_ERROR, "Invalid cwMin value %d",
859				   queue->cwmin);
860			return -1;
861		}
862	} else if (os_strcmp(pos, "cwmax") == 0) {
863		queue->cwmax = atoi(val);
864		if (!valid_cw(queue->cwmax)) {
865			wpa_printf(MSG_ERROR, "Invalid cwMax value %d",
866				   queue->cwmax);
867			return -1;
868		}
869	} else if (os_strcmp(pos, "burst") == 0) {
870		queue->burst = hostapd_config_read_int10(val);
871	} else {
872		wpa_printf(MSG_ERROR, "Unknown tx_queue field '%s'", pos);
873		return -1;
874	}
875
876	return 0;
877}
878
879
880#ifdef CONFIG_IEEE80211R
881static int add_r0kh(struct hostapd_bss_config *bss, char *value)
882{
883	struct ft_remote_r0kh *r0kh;
884	char *pos, *next;
885
886	r0kh = os_zalloc(sizeof(*r0kh));
887	if (r0kh == NULL)
888		return -1;
889
890	/* 02:01:02:03:04:05 a.example.com 000102030405060708090a0b0c0d0e0f */
891	pos = value;
892	next = os_strchr(pos, ' ');
893	if (next)
894		*next++ = '\0';
895	if (next == NULL || hwaddr_aton(pos, r0kh->addr)) {
896		wpa_printf(MSG_ERROR, "Invalid R0KH MAC address: '%s'", pos);
897		os_free(r0kh);
898		return -1;
899	}
900
901	pos = next;
902	next = os_strchr(pos, ' ');
903	if (next)
904		*next++ = '\0';
905	if (next == NULL || next - pos > FT_R0KH_ID_MAX_LEN) {
906		wpa_printf(MSG_ERROR, "Invalid R0KH-ID: '%s'", pos);
907		os_free(r0kh);
908		return -1;
909	}
910	r0kh->id_len = next - pos - 1;
911	os_memcpy(r0kh->id, pos, r0kh->id_len);
912
913	pos = next;
914	if (hexstr2bin(pos, r0kh->key, sizeof(r0kh->key))) {
915		wpa_printf(MSG_ERROR, "Invalid R0KH key: '%s'", pos);
916		os_free(r0kh);
917		return -1;
918	}
919
920	r0kh->next = bss->r0kh_list;
921	bss->r0kh_list = r0kh;
922
923	return 0;
924}
925
926
927static int add_r1kh(struct hostapd_bss_config *bss, char *value)
928{
929	struct ft_remote_r1kh *r1kh;
930	char *pos, *next;
931
932	r1kh = os_zalloc(sizeof(*r1kh));
933	if (r1kh == NULL)
934		return -1;
935
936	/* 02:01:02:03:04:05 02:01:02:03:04:05
937	 * 000102030405060708090a0b0c0d0e0f */
938	pos = value;
939	next = os_strchr(pos, ' ');
940	if (next)
941		*next++ = '\0';
942	if (next == NULL || hwaddr_aton(pos, r1kh->addr)) {
943		wpa_printf(MSG_ERROR, "Invalid R1KH MAC address: '%s'", pos);
944		os_free(r1kh);
945		return -1;
946	}
947
948	pos = next;
949	next = os_strchr(pos, ' ');
950	if (next)
951		*next++ = '\0';
952	if (next == NULL || hwaddr_aton(pos, r1kh->id)) {
953		wpa_printf(MSG_ERROR, "Invalid R1KH-ID: '%s'", pos);
954		os_free(r1kh);
955		return -1;
956	}
957
958	pos = next;
959	if (hexstr2bin(pos, r1kh->key, sizeof(r1kh->key))) {
960		wpa_printf(MSG_ERROR, "Invalid R1KH key: '%s'", pos);
961		os_free(r1kh);
962		return -1;
963	}
964
965	r1kh->next = bss->r1kh_list;
966	bss->r1kh_list = r1kh;
967
968	return 0;
969}
970#endif /* CONFIG_IEEE80211R */
971
972
973#ifdef CONFIG_IEEE80211N
974static int hostapd_config_ht_capab(struct hostapd_config *conf,
975				   const char *capab)
976{
977	if (os_strstr(capab, "[LDPC]"))
978		conf->ht_capab |= HT_CAP_INFO_LDPC_CODING_CAP;
979	if (os_strstr(capab, "[HT40-]")) {
980		conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
981		conf->secondary_channel = -1;
982	}
983	if (os_strstr(capab, "[HT40+]")) {
984		conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
985		conf->secondary_channel = 1;
986	}
987	if (os_strstr(capab, "[SMPS-STATIC]")) {
988		conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK;
989		conf->ht_capab |= HT_CAP_INFO_SMPS_STATIC;
990	}
991	if (os_strstr(capab, "[SMPS-DYNAMIC]")) {
992		conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK;
993		conf->ht_capab |= HT_CAP_INFO_SMPS_DYNAMIC;
994	}
995	if (os_strstr(capab, "[GF]"))
996		conf->ht_capab |= HT_CAP_INFO_GREEN_FIELD;
997	if (os_strstr(capab, "[SHORT-GI-20]"))
998		conf->ht_capab |= HT_CAP_INFO_SHORT_GI20MHZ;
999	if (os_strstr(capab, "[SHORT-GI-40]"))
1000		conf->ht_capab |= HT_CAP_INFO_SHORT_GI40MHZ;
1001	if (os_strstr(capab, "[TX-STBC]"))
1002		conf->ht_capab |= HT_CAP_INFO_TX_STBC;
1003	if (os_strstr(capab, "[RX-STBC1]")) {
1004		conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK;
1005		conf->ht_capab |= HT_CAP_INFO_RX_STBC_1;
1006	}
1007	if (os_strstr(capab, "[RX-STBC12]")) {
1008		conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK;
1009		conf->ht_capab |= HT_CAP_INFO_RX_STBC_12;
1010	}
1011	if (os_strstr(capab, "[RX-STBC123]")) {
1012		conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK;
1013		conf->ht_capab |= HT_CAP_INFO_RX_STBC_123;
1014	}
1015	if (os_strstr(capab, "[DELAYED-BA]"))
1016		conf->ht_capab |= HT_CAP_INFO_DELAYED_BA;
1017	if (os_strstr(capab, "[MAX-AMSDU-7935]"))
1018		conf->ht_capab |= HT_CAP_INFO_MAX_AMSDU_SIZE;
1019	if (os_strstr(capab, "[DSSS_CCK-40]"))
1020		conf->ht_capab |= HT_CAP_INFO_DSSS_CCK40MHZ;
1021	if (os_strstr(capab, "[PSMP]"))
1022		conf->ht_capab |= HT_CAP_INFO_PSMP_SUPP;
1023	if (os_strstr(capab, "[LSIG-TXOP-PROT]"))
1024		conf->ht_capab |= HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT;
1025
1026	return 0;
1027}
1028#endif /* CONFIG_IEEE80211N */
1029
1030
1031#ifdef CONFIG_IEEE80211AC
1032static int hostapd_config_vht_capab(struct hostapd_config *conf,
1033				    const char *capab)
1034{
1035	if (os_strstr(capab, "[MAX-MPDU-7991]"))
1036		conf->vht_capab |= VHT_CAP_MAX_MPDU_LENGTH_7991;
1037	if (os_strstr(capab, "[MAX-MPDU-11454]"))
1038		conf->vht_capab |= VHT_CAP_MAX_MPDU_LENGTH_11454;
1039	if (os_strstr(capab, "[VHT160]"))
1040		conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
1041	if (os_strstr(capab, "[VHT160-80PLUS80]"))
1042		conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
1043	if (os_strstr(capab, "[VHT160-80PLUS80]"))
1044		conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
1045	if (os_strstr(capab, "[RXLDPC]"))
1046		conf->vht_capab |= VHT_CAP_RXLDPC;
1047	if (os_strstr(capab, "[SHORT-GI-80]"))
1048		conf->vht_capab |= VHT_CAP_SHORT_GI_80;
1049	if (os_strstr(capab, "[SHORT-GI-160]"))
1050		conf->vht_capab |= VHT_CAP_SHORT_GI_160;
1051	if (os_strstr(capab, "[TX-STBC-2BY1]"))
1052		conf->vht_capab |= VHT_CAP_TXSTBC;
1053	if (os_strstr(capab, "[RX-STBC-1]"))
1054		conf->vht_capab |= VHT_CAP_RXSTBC_1;
1055	if (os_strstr(capab, "[RX-STBC-12]"))
1056		conf->vht_capab |= VHT_CAP_RXSTBC_2;
1057	if (os_strstr(capab, "[RX-STBC-123]"))
1058		conf->vht_capab |= VHT_CAP_RXSTBC_3;
1059	if (os_strstr(capab, "[RX-STBC-1234]"))
1060		conf->vht_capab |= VHT_CAP_RXSTBC_4;
1061	if (os_strstr(capab, "[SU-BEAMFORMER]"))
1062		conf->vht_capab |= VHT_CAP_SU_BEAMFORMER_CAPABLE;
1063	if (os_strstr(capab, "[SU-BEAMFORMEE]"))
1064		conf->vht_capab |= VHT_CAP_SU_BEAMFORMEE_CAPABLE;
1065	if (os_strstr(capab, "[BF-ANTENNA-2]") &&
1066	    (conf->vht_capab & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
1067		conf->vht_capab |= (1 << VHT_CAP_BEAMFORMEE_STS_OFFSET);
1068	if (os_strstr(capab, "[SOUNDING-DIMENSION-2]") &&
1069	    (conf->vht_capab & VHT_CAP_SU_BEAMFORMER_CAPABLE))
1070		conf->vht_capab |= (1 << VHT_CAP_SOUNDING_DIMENSION_OFFSET);
1071	if (os_strstr(capab, "[MU-BEAMFORMER]"))
1072		conf->vht_capab |= VHT_CAP_MU_BEAMFORMER_CAPABLE;
1073	if (os_strstr(capab, "[MU-BEAMFORMEE]"))
1074		conf->vht_capab |= VHT_CAP_MU_BEAMFORMEE_CAPABLE;
1075	if (os_strstr(capab, "[VHT-TXOP-PS]"))
1076		conf->vht_capab |= VHT_CAP_VHT_TXOP_PS;
1077	if (os_strstr(capab, "[HTC-VHT]"))
1078		conf->vht_capab |= VHT_CAP_HTC_VHT;
1079	if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP0]"))
1080		conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT;
1081	if (os_strstr(capab, "[VHT-LINK-ADAPT2]") &&
1082	    (conf->vht_capab & VHT_CAP_HTC_VHT))
1083		conf->vht_capab |= VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB;
1084	if (os_strstr(capab, "[VHT-LINK-ADAPT3]") &&
1085	    (conf->vht_capab & VHT_CAP_HTC_VHT))
1086		conf->vht_capab |= VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
1087	if (os_strstr(capab, "[RX-ANTENNA-PATTERN]"))
1088		conf->vht_capab |= VHT_CAP_RX_ANTENNA_PATTERN;
1089	if (os_strstr(capab, "[TX-ANTENNA-PATTERN]"))
1090		conf->vht_capab |= VHT_CAP_TX_ANTENNA_PATTERN;
1091	return 0;
1092}
1093#endif /* CONFIG_IEEE80211AC */
1094
1095
1096#ifdef CONFIG_INTERWORKING
1097static int parse_roaming_consortium(struct hostapd_bss_config *bss, char *pos,
1098				    int line)
1099{
1100	size_t len = os_strlen(pos);
1101	u8 oi[MAX_ROAMING_CONSORTIUM_LEN];
1102
1103	struct hostapd_roaming_consortium *rc;
1104
1105	if ((len & 1) || len < 2 * 3 || len / 2 > MAX_ROAMING_CONSORTIUM_LEN ||
1106	    hexstr2bin(pos, oi, len / 2)) {
1107		wpa_printf(MSG_ERROR, "Line %d: invalid roaming_consortium "
1108			   "'%s'", line, pos);
1109		return -1;
1110	}
1111	len /= 2;
1112
1113	rc = os_realloc_array(bss->roaming_consortium,
1114			      bss->roaming_consortium_count + 1,
1115			      sizeof(struct hostapd_roaming_consortium));
1116	if (rc == NULL)
1117		return -1;
1118
1119	os_memcpy(rc[bss->roaming_consortium_count].oi, oi, len);
1120	rc[bss->roaming_consortium_count].len = len;
1121
1122	bss->roaming_consortium = rc;
1123	bss->roaming_consortium_count++;
1124
1125	return 0;
1126}
1127
1128
1129static int parse_lang_string(struct hostapd_lang_string **array,
1130			     unsigned int *count, char *pos)
1131{
1132	char *sep, *str = NULL;
1133	size_t clen, nlen, slen;
1134	struct hostapd_lang_string *ls;
1135	int ret = -1;
1136
1137	if (*pos == '"' || (*pos == 'P' && pos[1] == '"')) {
1138		str = wpa_config_parse_string(pos, &slen);
1139		if (!str)
1140			return -1;
1141		pos = str;
1142	}
1143
1144	sep = os_strchr(pos, ':');
1145	if (sep == NULL)
1146		goto fail;
1147	*sep++ = '\0';
1148
1149	clen = os_strlen(pos);
1150	if (clen < 2 || clen > sizeof(ls->lang))
1151		goto fail;
1152	nlen = os_strlen(sep);
1153	if (nlen > 252)
1154		goto fail;
1155
1156	ls = os_realloc_array(*array, *count + 1,
1157			      sizeof(struct hostapd_lang_string));
1158	if (ls == NULL)
1159		goto fail;
1160
1161	*array = ls;
1162	ls = &(*array)[*count];
1163	(*count)++;
1164
1165	os_memset(ls->lang, 0, sizeof(ls->lang));
1166	os_memcpy(ls->lang, pos, clen);
1167	ls->name_len = nlen;
1168	os_memcpy(ls->name, sep, nlen);
1169
1170	ret = 0;
1171fail:
1172	os_free(str);
1173	return ret;
1174}
1175
1176
1177static int parse_venue_name(struct hostapd_bss_config *bss, char *pos,
1178			    int line)
1179{
1180	if (parse_lang_string(&bss->venue_name, &bss->venue_name_count, pos)) {
1181		wpa_printf(MSG_ERROR, "Line %d: Invalid venue_name '%s'",
1182			   line, pos);
1183		return -1;
1184	}
1185	return 0;
1186}
1187
1188
1189static int parse_3gpp_cell_net(struct hostapd_bss_config *bss, char *buf,
1190			       int line)
1191{
1192	size_t count;
1193	char *pos;
1194	u8 *info = NULL, *ipos;
1195
1196	/* format: <MCC1,MNC1>[;<MCC2,MNC2>][;...] */
1197
1198	count = 1;
1199	for (pos = buf; *pos; pos++) {
1200		if ((*pos < '0' && *pos > '9') && *pos != ';' && *pos != ',')
1201			goto fail;
1202		if (*pos == ';')
1203			count++;
1204	}
1205	if (1 + count * 3 > 0x7f)
1206		goto fail;
1207
1208	info = os_zalloc(2 + 3 + count * 3);
1209	if (info == NULL)
1210		return -1;
1211
1212	ipos = info;
1213	*ipos++ = 0; /* GUD - Version 1 */
1214	*ipos++ = 3 + count * 3; /* User Data Header Length (UDHL) */
1215	*ipos++ = 0; /* PLMN List IEI */
1216	/* ext(b8) | Length of PLMN List value contents(b7..1) */
1217	*ipos++ = 1 + count * 3;
1218	*ipos++ = count; /* Number of PLMNs */
1219
1220	pos = buf;
1221	while (pos && *pos) {
1222		char *mcc, *mnc;
1223		size_t mnc_len;
1224
1225		mcc = pos;
1226		mnc = os_strchr(pos, ',');
1227		if (mnc == NULL)
1228			goto fail;
1229		*mnc++ = '\0';
1230		pos = os_strchr(mnc, ';');
1231		if (pos)
1232			*pos++ = '\0';
1233
1234		mnc_len = os_strlen(mnc);
1235		if (os_strlen(mcc) != 3 || (mnc_len != 2 && mnc_len != 3))
1236			goto fail;
1237
1238		/* BC coded MCC,MNC */
1239		/* MCC digit 2 | MCC digit 1 */
1240		*ipos++ = ((mcc[1] - '0') << 4) | (mcc[0] - '0');
1241		/* MNC digit 3 | MCC digit 3 */
1242		*ipos++ = (((mnc_len == 2) ? 0xf0 : ((mnc[2] - '0') << 4))) |
1243			(mcc[2] - '0');
1244		/* MNC digit 2 | MNC digit 1 */
1245		*ipos++ = ((mnc[1] - '0') << 4) | (mnc[0] - '0');
1246	}
1247
1248	os_free(bss->anqp_3gpp_cell_net);
1249	bss->anqp_3gpp_cell_net = info;
1250	bss->anqp_3gpp_cell_net_len = 2 + 3 + 3 * count;
1251	wpa_hexdump(MSG_MSGDUMP, "3GPP Cellular Network information",
1252		    bss->anqp_3gpp_cell_net, bss->anqp_3gpp_cell_net_len);
1253
1254	return 0;
1255
1256fail:
1257	wpa_printf(MSG_ERROR, "Line %d: Invalid anqp_3gpp_cell_net: %s",
1258		   line, buf);
1259	os_free(info);
1260	return -1;
1261}
1262
1263
1264static int parse_nai_realm(struct hostapd_bss_config *bss, char *buf, int line)
1265{
1266	struct hostapd_nai_realm_data *realm;
1267	size_t i, j, len;
1268	int *offsets;
1269	char *pos, *end, *rpos;
1270
1271	offsets = os_calloc(bss->nai_realm_count * MAX_NAI_REALMS,
1272			    sizeof(int));
1273	if (offsets == NULL)
1274		return -1;
1275
1276	for (i = 0; i < bss->nai_realm_count; i++) {
1277		realm = &bss->nai_realm_data[i];
1278		for (j = 0; j < MAX_NAI_REALMS; j++) {
1279			offsets[i * MAX_NAI_REALMS + j] =
1280				realm->realm[j] ?
1281				realm->realm[j] - realm->realm_buf : -1;
1282		}
1283	}
1284
1285	realm = os_realloc_array(bss->nai_realm_data, bss->nai_realm_count + 1,
1286				 sizeof(struct hostapd_nai_realm_data));
1287	if (realm == NULL) {
1288		os_free(offsets);
1289		return -1;
1290	}
1291	bss->nai_realm_data = realm;
1292
1293	/* patch the pointers after realloc */
1294	for (i = 0; i < bss->nai_realm_count; i++) {
1295		realm = &bss->nai_realm_data[i];
1296		for (j = 0; j < MAX_NAI_REALMS; j++) {
1297			int offs = offsets[i * MAX_NAI_REALMS + j];
1298			if (offs >= 0)
1299				realm->realm[j] = realm->realm_buf + offs;
1300			else
1301				realm->realm[j] = NULL;
1302		}
1303	}
1304	os_free(offsets);
1305
1306	realm = &bss->nai_realm_data[bss->nai_realm_count];
1307	os_memset(realm, 0, sizeof(*realm));
1308
1309	pos = buf;
1310	realm->encoding = atoi(pos);
1311	pos = os_strchr(pos, ',');
1312	if (pos == NULL)
1313		goto fail;
1314	pos++;
1315
1316	end = os_strchr(pos, ',');
1317	if (end) {
1318		len = end - pos;
1319		*end = '\0';
1320	} else {
1321		len = os_strlen(pos);
1322	}
1323
1324	if (len > MAX_NAI_REALMLEN) {
1325		wpa_printf(MSG_ERROR, "Too long a realm string (%d > max %d "
1326			   "characters)", (int) len, MAX_NAI_REALMLEN);
1327		goto fail;
1328	}
1329	os_memcpy(realm->realm_buf, pos, len);
1330
1331	if (end)
1332		pos = end + 1;
1333	else
1334		pos = NULL;
1335
1336	while (pos && *pos) {
1337		struct hostapd_nai_realm_eap *eap;
1338
1339		if (realm->eap_method_count >= MAX_NAI_EAP_METHODS) {
1340			wpa_printf(MSG_ERROR, "Too many EAP methods");
1341			goto fail;
1342		}
1343
1344		eap = &realm->eap_method[realm->eap_method_count];
1345		realm->eap_method_count++;
1346
1347		end = os_strchr(pos, ',');
1348		if (end == NULL)
1349			end = pos + os_strlen(pos);
1350
1351		eap->eap_method = atoi(pos);
1352		for (;;) {
1353			pos = os_strchr(pos, '[');
1354			if (pos == NULL || pos > end)
1355				break;
1356			pos++;
1357			if (eap->num_auths >= MAX_NAI_AUTH_TYPES) {
1358				wpa_printf(MSG_ERROR, "Too many auth params");
1359				goto fail;
1360			}
1361			eap->auth_id[eap->num_auths] = atoi(pos);
1362			pos = os_strchr(pos, ':');
1363			if (pos == NULL || pos > end)
1364				goto fail;
1365			pos++;
1366			eap->auth_val[eap->num_auths] = atoi(pos);
1367			pos = os_strchr(pos, ']');
1368			if (pos == NULL || pos > end)
1369				goto fail;
1370			pos++;
1371			eap->num_auths++;
1372		}
1373
1374		if (*end != ',')
1375			break;
1376
1377		pos = end + 1;
1378	}
1379
1380	/* Split realm list into null terminated realms */
1381	rpos = realm->realm_buf;
1382	i = 0;
1383	while (*rpos) {
1384		if (i >= MAX_NAI_REALMS) {
1385			wpa_printf(MSG_ERROR, "Too many realms");
1386			goto fail;
1387		}
1388		realm->realm[i++] = rpos;
1389		rpos = os_strchr(rpos, ';');
1390		if (rpos == NULL)
1391			break;
1392		*rpos++ = '\0';
1393	}
1394
1395	bss->nai_realm_count++;
1396
1397	return 0;
1398
1399fail:
1400	wpa_printf(MSG_ERROR, "Line %d: invalid nai_realm '%s'", line, buf);
1401	return -1;
1402}
1403
1404
1405static int parse_qos_map_set(struct hostapd_bss_config *bss,
1406			     char *buf, int line)
1407{
1408	u8 qos_map_set[16 + 2 * 21], count = 0;
1409	char *pos = buf;
1410	int val;
1411
1412	for (;;) {
1413		if (count == sizeof(qos_map_set)) {
1414			wpa_printf(MSG_ERROR, "Line %d: Too many qos_map_set "
1415				   "parameters '%s'", line, buf);
1416			return -1;
1417		}
1418
1419		val = atoi(pos);
1420		if (val > 255 || val < 0) {
1421			wpa_printf(MSG_ERROR, "Line %d: Invalid qos_map_set "
1422				   "'%s'", line, buf);
1423			return -1;
1424		}
1425
1426		qos_map_set[count++] = val;
1427		pos = os_strchr(pos, ',');
1428		if (!pos)
1429			break;
1430		pos++;
1431	}
1432
1433	if (count < 16 || count & 1) {
1434		wpa_printf(MSG_ERROR, "Line %d: Invalid qos_map_set '%s'",
1435			   line, buf);
1436		return -1;
1437	}
1438
1439	os_memcpy(bss->qos_map_set, qos_map_set, count);
1440	bss->qos_map_set_len = count;
1441
1442	return 0;
1443}
1444
1445#endif /* CONFIG_INTERWORKING */
1446
1447
1448#ifdef CONFIG_HS20
1449static int hs20_parse_conn_capab(struct hostapd_bss_config *bss, char *buf,
1450				 int line)
1451{
1452	u8 *conn_cap;
1453	char *pos;
1454
1455	if (bss->hs20_connection_capability_len >= 0xfff0)
1456		return -1;
1457
1458	conn_cap = os_realloc(bss->hs20_connection_capability,
1459			      bss->hs20_connection_capability_len + 4);
1460	if (conn_cap == NULL)
1461		return -1;
1462
1463	bss->hs20_connection_capability = conn_cap;
1464	conn_cap += bss->hs20_connection_capability_len;
1465	pos = buf;
1466	conn_cap[0] = atoi(pos);
1467	pos = os_strchr(pos, ':');
1468	if (pos == NULL)
1469		return -1;
1470	pos++;
1471	WPA_PUT_LE16(conn_cap + 1, atoi(pos));
1472	pos = os_strchr(pos, ':');
1473	if (pos == NULL)
1474		return -1;
1475	pos++;
1476	conn_cap[3] = atoi(pos);
1477	bss->hs20_connection_capability_len += 4;
1478
1479	return 0;
1480}
1481
1482
1483static int hs20_parse_wan_metrics(struct hostapd_bss_config *bss, char *buf,
1484				  int line)
1485{
1486	u8 *wan_metrics;
1487	char *pos;
1488
1489	/* <WAN Info>:<DL Speed>:<UL Speed>:<DL Load>:<UL Load>:<LMD> */
1490
1491	wan_metrics = os_zalloc(13);
1492	if (wan_metrics == NULL)
1493		return -1;
1494
1495	pos = buf;
1496	/* WAN Info */
1497	if (hexstr2bin(pos, wan_metrics, 1) < 0)
1498		goto fail;
1499	pos += 2;
1500	if (*pos != ':')
1501		goto fail;
1502	pos++;
1503
1504	/* Downlink Speed */
1505	WPA_PUT_LE32(wan_metrics + 1, atoi(pos));
1506	pos = os_strchr(pos, ':');
1507	if (pos == NULL)
1508		goto fail;
1509	pos++;
1510
1511	/* Uplink Speed */
1512	WPA_PUT_LE32(wan_metrics + 5, atoi(pos));
1513	pos = os_strchr(pos, ':');
1514	if (pos == NULL)
1515		goto fail;
1516	pos++;
1517
1518	/* Downlink Load */
1519	wan_metrics[9] = atoi(pos);
1520	pos = os_strchr(pos, ':');
1521	if (pos == NULL)
1522		goto fail;
1523	pos++;
1524
1525	/* Uplink Load */
1526	wan_metrics[10] = atoi(pos);
1527	pos = os_strchr(pos, ':');
1528	if (pos == NULL)
1529		goto fail;
1530	pos++;
1531
1532	/* LMD */
1533	WPA_PUT_LE16(wan_metrics + 11, atoi(pos));
1534
1535	os_free(bss->hs20_wan_metrics);
1536	bss->hs20_wan_metrics = wan_metrics;
1537
1538	return 0;
1539
1540fail:
1541	wpa_printf(MSG_ERROR, "Line %d: Invalid hs20_wan_metrics '%s'",
1542		   line, pos);
1543	os_free(wan_metrics);
1544	return -1;
1545}
1546
1547
1548static int hs20_parse_oper_friendly_name(struct hostapd_bss_config *bss,
1549					 char *pos, int line)
1550{
1551	if (parse_lang_string(&bss->hs20_oper_friendly_name,
1552			      &bss->hs20_oper_friendly_name_count, pos)) {
1553		wpa_printf(MSG_ERROR, "Line %d: Invalid "
1554			   "hs20_oper_friendly_name '%s'", line, pos);
1555		return -1;
1556	}
1557	return 0;
1558}
1559#endif /* CONFIG_HS20 */
1560
1561
1562#ifdef CONFIG_WPS_NFC
1563static struct wpabuf * hostapd_parse_bin(const char *buf)
1564{
1565	size_t len;
1566	struct wpabuf *ret;
1567
1568	len = os_strlen(buf);
1569	if (len & 0x01)
1570		return NULL;
1571	len /= 2;
1572
1573	ret = wpabuf_alloc(len);
1574	if (ret == NULL)
1575		return NULL;
1576
1577	if (hexstr2bin(buf, wpabuf_put(ret, len), len)) {
1578		wpabuf_free(ret);
1579		return NULL;
1580	}
1581
1582	return ret;
1583}
1584#endif /* CONFIG_WPS_NFC */
1585
1586
1587static int hostapd_config_fill(struct hostapd_config *conf,
1588			       struct hostapd_bss_config *bss,
1589			       char *buf, char *pos, int line)
1590{
1591	int errors = 0;
1592
1593	{
1594		if (os_strcmp(buf, "interface") == 0) {
1595			os_strlcpy(conf->bss[0]->iface, pos,
1596				   sizeof(conf->bss[0]->iface));
1597		} else if (os_strcmp(buf, "bridge") == 0) {
1598			os_strlcpy(bss->bridge, pos, sizeof(bss->bridge));
1599		} else if (os_strcmp(buf, "vlan_bridge") == 0) {
1600			os_strlcpy(bss->vlan_bridge, pos,
1601			           sizeof(bss->vlan_bridge));
1602		} else if (os_strcmp(buf, "wds_bridge") == 0) {
1603			os_strlcpy(bss->wds_bridge, pos,
1604				   sizeof(bss->wds_bridge));
1605		} else if (os_strcmp(buf, "driver") == 0) {
1606			int j;
1607			/* clear to get error below if setting is invalid */
1608			conf->driver = NULL;
1609			for (j = 0; wpa_drivers[j]; j++) {
1610				if (os_strcmp(pos, wpa_drivers[j]->name) == 0)
1611				{
1612					conf->driver = wpa_drivers[j];
1613					break;
1614				}
1615			}
1616			if (conf->driver == NULL) {
1617				wpa_printf(MSG_ERROR, "Line %d: invalid/"
1618					   "unknown driver '%s'", line, pos);
1619				errors++;
1620			}
1621		} else if (os_strcmp(buf, "debug") == 0) {
1622			wpa_printf(MSG_DEBUG, "Line %d: DEPRECATED: 'debug' "
1623				   "configuration variable is not used "
1624				   "anymore", line);
1625		} else if (os_strcmp(buf, "logger_syslog_level") == 0) {
1626			bss->logger_syslog_level = atoi(pos);
1627		} else if (os_strcmp(buf, "logger_stdout_level") == 0) {
1628			bss->logger_stdout_level = atoi(pos);
1629		} else if (os_strcmp(buf, "logger_syslog") == 0) {
1630			bss->logger_syslog = atoi(pos);
1631		} else if (os_strcmp(buf, "logger_stdout") == 0) {
1632			bss->logger_stdout = atoi(pos);
1633		} else if (os_strcmp(buf, "dump_file") == 0) {
1634			wpa_printf(MSG_INFO, "Line %d: DEPRECATED: 'dump_file' configuration variable is not used anymore",
1635				   line);
1636		} else if (os_strcmp(buf, "ssid") == 0) {
1637			bss->ssid.ssid_len = os_strlen(pos);
1638			if (bss->ssid.ssid_len > HOSTAPD_MAX_SSID_LEN ||
1639			    bss->ssid.ssid_len < 1) {
1640				wpa_printf(MSG_ERROR, "Line %d: invalid SSID "
1641					   "'%s'", line, pos);
1642				errors++;
1643			} else {
1644				os_memcpy(bss->ssid.ssid, pos,
1645					  bss->ssid.ssid_len);
1646				bss->ssid.ssid_set = 1;
1647			}
1648		} else if (os_strcmp(buf, "ssid2") == 0) {
1649			size_t slen;
1650			char *str = wpa_config_parse_string(pos, &slen);
1651			if (str == NULL || slen < 1 ||
1652				   slen > HOSTAPD_MAX_SSID_LEN) {
1653				wpa_printf(MSG_ERROR, "Line %d: invalid SSID "
1654					   "'%s'", line, pos);
1655				errors++;
1656			} else {
1657				os_memcpy(bss->ssid.ssid, str, slen);
1658				bss->ssid.ssid_len = slen;
1659				bss->ssid.ssid_set = 1;
1660			}
1661			os_free(str);
1662		} else if (os_strcmp(buf, "utf8_ssid") == 0) {
1663			bss->ssid.utf8_ssid = atoi(pos) > 0;
1664		} else if (os_strcmp(buf, "macaddr_acl") == 0) {
1665			bss->macaddr_acl = atoi(pos);
1666			if (bss->macaddr_acl != ACCEPT_UNLESS_DENIED &&
1667			    bss->macaddr_acl != DENY_UNLESS_ACCEPTED &&
1668			    bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
1669				wpa_printf(MSG_ERROR, "Line %d: unknown "
1670					   "macaddr_acl %d",
1671					   line, bss->macaddr_acl);
1672			}
1673		} else if (os_strcmp(buf, "accept_mac_file") == 0) {
1674			if (hostapd_config_read_maclist(pos, &bss->accept_mac,
1675							&bss->num_accept_mac))
1676			{
1677				wpa_printf(MSG_ERROR, "Line %d: Failed to "
1678					   "read accept_mac_file '%s'",
1679					   line, pos);
1680				errors++;
1681			}
1682		} else if (os_strcmp(buf, "deny_mac_file") == 0) {
1683			if (hostapd_config_read_maclist(pos, &bss->deny_mac,
1684							&bss->num_deny_mac)) {
1685				wpa_printf(MSG_ERROR, "Line %d: Failed to "
1686					   "read deny_mac_file '%s'",
1687					   line, pos);
1688				errors++;
1689			}
1690		} else if (os_strcmp(buf, "wds_sta") == 0) {
1691			bss->wds_sta = atoi(pos);
1692		} else if (os_strcmp(buf, "start_disabled") == 0) {
1693			bss->start_disabled = atoi(pos);
1694		} else if (os_strcmp(buf, "ap_isolate") == 0) {
1695			bss->isolate = atoi(pos);
1696		} else if (os_strcmp(buf, "ap_max_inactivity") == 0) {
1697			bss->ap_max_inactivity = atoi(pos);
1698		} else if (os_strcmp(buf, "skip_inactivity_poll") == 0) {
1699			bss->skip_inactivity_poll = atoi(pos);
1700		} else if (os_strcmp(buf, "country_code") == 0) {
1701			os_memcpy(conf->country, pos, 2);
1702			/* FIX: make this configurable */
1703			conf->country[2] = ' ';
1704		} else if (os_strcmp(buf, "ieee80211d") == 0) {
1705			conf->ieee80211d = atoi(pos);
1706		} else if (os_strcmp(buf, "ieee80211h") == 0) {
1707			conf->ieee80211h = atoi(pos);
1708		} else if (os_strcmp(buf, "ieee8021x") == 0) {
1709			bss->ieee802_1x = atoi(pos);
1710		} else if (os_strcmp(buf, "eapol_version") == 0) {
1711			bss->eapol_version = atoi(pos);
1712			if (bss->eapol_version < 1 ||
1713			    bss->eapol_version > 2) {
1714				wpa_printf(MSG_ERROR, "Line %d: invalid EAPOL "
1715					   "version (%d): '%s'.",
1716					   line, bss->eapol_version, pos);
1717				errors++;
1718			} else
1719				wpa_printf(MSG_DEBUG, "eapol_version=%d",
1720					   bss->eapol_version);
1721#ifdef EAP_SERVER
1722		} else if (os_strcmp(buf, "eap_authenticator") == 0) {
1723			bss->eap_server = atoi(pos);
1724			wpa_printf(MSG_ERROR, "Line %d: obsolete "
1725				   "eap_authenticator used; this has been "
1726				   "renamed to eap_server", line);
1727		} else if (os_strcmp(buf, "eap_server") == 0) {
1728			bss->eap_server = atoi(pos);
1729		} else if (os_strcmp(buf, "eap_user_file") == 0) {
1730			if (hostapd_config_read_eap_user(pos, bss))
1731				errors++;
1732		} else if (os_strcmp(buf, "ca_cert") == 0) {
1733			os_free(bss->ca_cert);
1734			bss->ca_cert = os_strdup(pos);
1735		} else if (os_strcmp(buf, "server_cert") == 0) {
1736			os_free(bss->server_cert);
1737			bss->server_cert = os_strdup(pos);
1738		} else if (os_strcmp(buf, "private_key") == 0) {
1739			os_free(bss->private_key);
1740			bss->private_key = os_strdup(pos);
1741		} else if (os_strcmp(buf, "private_key_passwd") == 0) {
1742			os_free(bss->private_key_passwd);
1743			bss->private_key_passwd = os_strdup(pos);
1744		} else if (os_strcmp(buf, "check_crl") == 0) {
1745			bss->check_crl = atoi(pos);
1746		} else if (os_strcmp(buf, "ocsp_stapling_response") == 0) {
1747			os_free(bss->ocsp_stapling_response);
1748			bss->ocsp_stapling_response = os_strdup(pos);
1749		} else if (os_strcmp(buf, "dh_file") == 0) {
1750			os_free(bss->dh_file);
1751			bss->dh_file = os_strdup(pos);
1752		} else if (os_strcmp(buf, "fragment_size") == 0) {
1753			bss->fragment_size = atoi(pos);
1754#ifdef EAP_SERVER_FAST
1755		} else if (os_strcmp(buf, "pac_opaque_encr_key") == 0) {
1756			os_free(bss->pac_opaque_encr_key);
1757			bss->pac_opaque_encr_key = os_malloc(16);
1758			if (bss->pac_opaque_encr_key == NULL) {
1759				wpa_printf(MSG_ERROR, "Line %d: No memory for "
1760					   "pac_opaque_encr_key", line);
1761				errors++;
1762			} else if (hexstr2bin(pos, bss->pac_opaque_encr_key,
1763					      16)) {
1764				wpa_printf(MSG_ERROR, "Line %d: Invalid "
1765					   "pac_opaque_encr_key", line);
1766				errors++;
1767			}
1768		} else if (os_strcmp(buf, "eap_fast_a_id") == 0) {
1769			size_t idlen = os_strlen(pos);
1770			if (idlen & 1) {
1771				wpa_printf(MSG_ERROR, "Line %d: Invalid "
1772					   "eap_fast_a_id", line);
1773				errors++;
1774			} else {
1775				os_free(bss->eap_fast_a_id);
1776				bss->eap_fast_a_id = os_malloc(idlen / 2);
1777				if (bss->eap_fast_a_id == NULL ||
1778				    hexstr2bin(pos, bss->eap_fast_a_id,
1779					       idlen / 2)) {
1780					wpa_printf(MSG_ERROR, "Line %d: "
1781						   "Failed to parse "
1782						   "eap_fast_a_id", line);
1783					errors++;
1784				} else
1785					bss->eap_fast_a_id_len = idlen / 2;
1786			}
1787		} else if (os_strcmp(buf, "eap_fast_a_id_info") == 0) {
1788			os_free(bss->eap_fast_a_id_info);
1789			bss->eap_fast_a_id_info = os_strdup(pos);
1790		} else if (os_strcmp(buf, "eap_fast_prov") == 0) {
1791			bss->eap_fast_prov = atoi(pos);
1792		} else if (os_strcmp(buf, "pac_key_lifetime") == 0) {
1793			bss->pac_key_lifetime = atoi(pos);
1794		} else if (os_strcmp(buf, "pac_key_refresh_time") == 0) {
1795			bss->pac_key_refresh_time = atoi(pos);
1796#endif /* EAP_SERVER_FAST */
1797#ifdef EAP_SERVER_SIM
1798		} else if (os_strcmp(buf, "eap_sim_db") == 0) {
1799			os_free(bss->eap_sim_db);
1800			bss->eap_sim_db = os_strdup(pos);
1801		} else if (os_strcmp(buf, "eap_sim_aka_result_ind") == 0) {
1802			bss->eap_sim_aka_result_ind = atoi(pos);
1803#endif /* EAP_SERVER_SIM */
1804#ifdef EAP_SERVER_TNC
1805		} else if (os_strcmp(buf, "tnc") == 0) {
1806			bss->tnc = atoi(pos);
1807#endif /* EAP_SERVER_TNC */
1808#ifdef EAP_SERVER_PWD
1809		} else if (os_strcmp(buf, "pwd_group") == 0) {
1810			bss->pwd_group = atoi(pos);
1811#endif /* EAP_SERVER_PWD */
1812#endif /* EAP_SERVER */
1813		} else if (os_strcmp(buf, "eap_message") == 0) {
1814			char *term;
1815			bss->eap_req_id_text = os_strdup(pos);
1816			if (bss->eap_req_id_text == NULL) {
1817				wpa_printf(MSG_ERROR, "Line %d: Failed to "
1818					   "allocate memory for "
1819					   "eap_req_id_text", line);
1820				errors++;
1821				return errors;
1822			}
1823			bss->eap_req_id_text_len =
1824				os_strlen(bss->eap_req_id_text);
1825			term = os_strstr(bss->eap_req_id_text, "\\0");
1826			if (term) {
1827				*term++ = '\0';
1828				os_memmove(term, term + 1,
1829					   bss->eap_req_id_text_len -
1830					   (term - bss->eap_req_id_text) - 1);
1831				bss->eap_req_id_text_len--;
1832			}
1833		} else if (os_strcmp(buf, "wep_key_len_broadcast") == 0) {
1834			bss->default_wep_key_len = atoi(pos);
1835			if (bss->default_wep_key_len > 13) {
1836				wpa_printf(MSG_ERROR, "Line %d: invalid WEP "
1837					   "key len %lu (= %lu bits)", line,
1838					   (unsigned long)
1839					   bss->default_wep_key_len,
1840					   (unsigned long)
1841					   bss->default_wep_key_len * 8);
1842				errors++;
1843			}
1844		} else if (os_strcmp(buf, "wep_key_len_unicast") == 0) {
1845			bss->individual_wep_key_len = atoi(pos);
1846			if (bss->individual_wep_key_len < 0 ||
1847			    bss->individual_wep_key_len > 13) {
1848				wpa_printf(MSG_ERROR, "Line %d: invalid WEP "
1849					   "key len %d (= %d bits)", line,
1850					   bss->individual_wep_key_len,
1851					   bss->individual_wep_key_len * 8);
1852				errors++;
1853			}
1854		} else if (os_strcmp(buf, "wep_rekey_period") == 0) {
1855			bss->wep_rekeying_period = atoi(pos);
1856			if (bss->wep_rekeying_period < 0) {
1857				wpa_printf(MSG_ERROR, "Line %d: invalid "
1858					   "period %d",
1859					   line, bss->wep_rekeying_period);
1860				errors++;
1861			}
1862		} else if (os_strcmp(buf, "eap_reauth_period") == 0) {
1863			bss->eap_reauth_period = atoi(pos);
1864			if (bss->eap_reauth_period < 0) {
1865				wpa_printf(MSG_ERROR, "Line %d: invalid "
1866					   "period %d",
1867					   line, bss->eap_reauth_period);
1868				errors++;
1869			}
1870		} else if (os_strcmp(buf, "eapol_key_index_workaround") == 0) {
1871			bss->eapol_key_index_workaround = atoi(pos);
1872#ifdef CONFIG_IAPP
1873		} else if (os_strcmp(buf, "iapp_interface") == 0) {
1874			bss->ieee802_11f = 1;
1875			os_strlcpy(bss->iapp_iface, pos,
1876				   sizeof(bss->iapp_iface));
1877#endif /* CONFIG_IAPP */
1878		} else if (os_strcmp(buf, "own_ip_addr") == 0) {
1879			if (hostapd_parse_ip_addr(pos, &bss->own_ip_addr)) {
1880				wpa_printf(MSG_ERROR, "Line %d: invalid IP "
1881					   "address '%s'", line, pos);
1882				errors++;
1883			}
1884		} else if (os_strcmp(buf, "nas_identifier") == 0) {
1885			bss->nas_identifier = os_strdup(pos);
1886#ifndef CONFIG_NO_RADIUS
1887		} else if (os_strcmp(buf, "auth_server_addr") == 0) {
1888			if (hostapd_config_read_radius_addr(
1889				    &bss->radius->auth_servers,
1890				    &bss->radius->num_auth_servers, pos, 1812,
1891				    &bss->radius->auth_server)) {
1892				wpa_printf(MSG_ERROR, "Line %d: invalid IP "
1893					   "address '%s'", line, pos);
1894				errors++;
1895			}
1896		} else if (bss->radius->auth_server &&
1897			   os_strcmp(buf, "auth_server_port") == 0) {
1898			bss->radius->auth_server->port = atoi(pos);
1899		} else if (bss->radius->auth_server &&
1900			   os_strcmp(buf, "auth_server_shared_secret") == 0) {
1901			int len = os_strlen(pos);
1902			if (len == 0) {
1903				/* RFC 2865, Ch. 3 */
1904				wpa_printf(MSG_ERROR, "Line %d: empty shared "
1905					   "secret is not allowed.", line);
1906				errors++;
1907			}
1908			bss->radius->auth_server->shared_secret =
1909				(u8 *) os_strdup(pos);
1910			bss->radius->auth_server->shared_secret_len = len;
1911		} else if (os_strcmp(buf, "acct_server_addr") == 0) {
1912			if (hostapd_config_read_radius_addr(
1913				    &bss->radius->acct_servers,
1914				    &bss->radius->num_acct_servers, pos, 1813,
1915				    &bss->radius->acct_server)) {
1916				wpa_printf(MSG_ERROR, "Line %d: invalid IP "
1917					   "address '%s'", line, pos);
1918				errors++;
1919			}
1920		} else if (bss->radius->acct_server &&
1921			   os_strcmp(buf, "acct_server_port") == 0) {
1922			bss->radius->acct_server->port = atoi(pos);
1923		} else if (bss->radius->acct_server &&
1924			   os_strcmp(buf, "acct_server_shared_secret") == 0) {
1925			int len = os_strlen(pos);
1926			if (len == 0) {
1927				/* RFC 2865, Ch. 3 */
1928				wpa_printf(MSG_ERROR, "Line %d: empty shared "
1929					   "secret is not allowed.", line);
1930				errors++;
1931			}
1932			bss->radius->acct_server->shared_secret =
1933				(u8 *) os_strdup(pos);
1934			bss->radius->acct_server->shared_secret_len = len;
1935		} else if (os_strcmp(buf, "radius_retry_primary_interval") ==
1936			   0) {
1937			bss->radius->retry_primary_interval = atoi(pos);
1938		} else if (os_strcmp(buf, "radius_acct_interim_interval") == 0)
1939		{
1940			bss->acct_interim_interval = atoi(pos);
1941		} else if (os_strcmp(buf, "radius_request_cui") == 0) {
1942			bss->radius_request_cui = atoi(pos);
1943		} else if (os_strcmp(buf, "radius_auth_req_attr") == 0) {
1944			struct hostapd_radius_attr *attr, *a;
1945			attr = hostapd_parse_radius_attr(pos);
1946			if (attr == NULL) {
1947				wpa_printf(MSG_ERROR, "Line %d: invalid "
1948					   "radius_auth_req_attr", line);
1949				errors++;
1950			} else if (bss->radius_auth_req_attr == NULL) {
1951				bss->radius_auth_req_attr = attr;
1952			} else {
1953				a = bss->radius_auth_req_attr;
1954				while (a->next)
1955					a = a->next;
1956				a->next = attr;
1957			}
1958		} else if (os_strcmp(buf, "radius_acct_req_attr") == 0) {
1959			struct hostapd_radius_attr *attr, *a;
1960			attr = hostapd_parse_radius_attr(pos);
1961			if (attr == NULL) {
1962				wpa_printf(MSG_ERROR, "Line %d: invalid "
1963					   "radius_acct_req_attr", line);
1964				errors++;
1965			} else if (bss->radius_acct_req_attr == NULL) {
1966				bss->radius_acct_req_attr = attr;
1967			} else {
1968				a = bss->radius_acct_req_attr;
1969				while (a->next)
1970					a = a->next;
1971				a->next = attr;
1972			}
1973		} else if (os_strcmp(buf, "radius_das_port") == 0) {
1974			bss->radius_das_port = atoi(pos);
1975		} else if (os_strcmp(buf, "radius_das_client") == 0) {
1976			if (hostapd_parse_das_client(bss, pos) < 0) {
1977				wpa_printf(MSG_ERROR, "Line %d: invalid "
1978					   "DAS client", line);
1979				errors++;
1980			}
1981		} else if (os_strcmp(buf, "radius_das_time_window") == 0) {
1982			bss->radius_das_time_window = atoi(pos);
1983		} else if (os_strcmp(buf, "radius_das_require_event_timestamp")
1984			   == 0) {
1985			bss->radius_das_require_event_timestamp = atoi(pos);
1986#endif /* CONFIG_NO_RADIUS */
1987		} else if (os_strcmp(buf, "auth_algs") == 0) {
1988			bss->auth_algs = atoi(pos);
1989			if (bss->auth_algs == 0) {
1990				wpa_printf(MSG_ERROR, "Line %d: no "
1991					   "authentication algorithms allowed",
1992					   line);
1993				errors++;
1994			}
1995		} else if (os_strcmp(buf, "max_num_sta") == 0) {
1996			bss->max_num_sta = atoi(pos);
1997			if (bss->max_num_sta < 0 ||
1998			    bss->max_num_sta > MAX_STA_COUNT) {
1999				wpa_printf(MSG_ERROR, "Line %d: Invalid "
2000					   "max_num_sta=%d; allowed range "
2001					   "0..%d", line, bss->max_num_sta,
2002					   MAX_STA_COUNT);
2003				errors++;
2004			}
2005		} else if (os_strcmp(buf, "wpa") == 0) {
2006			bss->wpa = atoi(pos);
2007		} else if (os_strcmp(buf, "wpa_group_rekey") == 0) {
2008			bss->wpa_group_rekey = atoi(pos);
2009		} else if (os_strcmp(buf, "wpa_strict_rekey") == 0) {
2010			bss->wpa_strict_rekey = atoi(pos);
2011		} else if (os_strcmp(buf, "wpa_gmk_rekey") == 0) {
2012			bss->wpa_gmk_rekey = atoi(pos);
2013		} else if (os_strcmp(buf, "wpa_ptk_rekey") == 0) {
2014			bss->wpa_ptk_rekey = atoi(pos);
2015		} else if (os_strcmp(buf, "wpa_passphrase") == 0) {
2016			int len = os_strlen(pos);
2017			if (len < 8 || len > 63) {
2018				wpa_printf(MSG_ERROR, "Line %d: invalid WPA "
2019					   "passphrase length %d (expected "
2020					   "8..63)", line, len);
2021				errors++;
2022			} else {
2023				os_free(bss->ssid.wpa_passphrase);
2024				bss->ssid.wpa_passphrase = os_strdup(pos);
2025				if (bss->ssid.wpa_passphrase) {
2026					os_free(bss->ssid.wpa_psk);
2027					bss->ssid.wpa_psk = NULL;
2028					bss->ssid.wpa_passphrase_set = 1;
2029				}
2030			}
2031		} else if (os_strcmp(buf, "wpa_psk") == 0) {
2032			os_free(bss->ssid.wpa_psk);
2033			bss->ssid.wpa_psk =
2034				os_zalloc(sizeof(struct hostapd_wpa_psk));
2035			if (bss->ssid.wpa_psk == NULL)
2036				errors++;
2037			else if (hexstr2bin(pos, bss->ssid.wpa_psk->psk,
2038					    PMK_LEN) ||
2039				 pos[PMK_LEN * 2] != '\0') {
2040				wpa_printf(MSG_ERROR, "Line %d: Invalid PSK "
2041					   "'%s'.", line, pos);
2042				errors++;
2043			} else {
2044				bss->ssid.wpa_psk->group = 1;
2045				os_free(bss->ssid.wpa_passphrase);
2046				bss->ssid.wpa_passphrase = NULL;
2047				bss->ssid.wpa_psk_set = 1;
2048			}
2049		} else if (os_strcmp(buf, "wpa_psk_file") == 0) {
2050			os_free(bss->ssid.wpa_psk_file);
2051			bss->ssid.wpa_psk_file = os_strdup(pos);
2052			if (!bss->ssid.wpa_psk_file) {
2053				wpa_printf(MSG_ERROR, "Line %d: allocation "
2054					   "failed", line);
2055				errors++;
2056			}
2057		} else if (os_strcmp(buf, "wpa_key_mgmt") == 0) {
2058			bss->wpa_key_mgmt =
2059				hostapd_config_parse_key_mgmt(line, pos);
2060			if (bss->wpa_key_mgmt == -1)
2061				errors++;
2062		} else if (os_strcmp(buf, "wpa_psk_radius") == 0) {
2063			bss->wpa_psk_radius = atoi(pos);
2064			if (bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
2065			    bss->wpa_psk_radius != PSK_RADIUS_ACCEPTED &&
2066			    bss->wpa_psk_radius != PSK_RADIUS_REQUIRED) {
2067				wpa_printf(MSG_ERROR, "Line %d: unknown "
2068					   "wpa_psk_radius %d",
2069					   line, bss->wpa_psk_radius);
2070				errors++;
2071			}
2072		} else if (os_strcmp(buf, "wpa_pairwise") == 0) {
2073			bss->wpa_pairwise =
2074				hostapd_config_parse_cipher(line, pos);
2075			if (bss->wpa_pairwise == -1 ||
2076			    bss->wpa_pairwise == 0)
2077				errors++;
2078			else if (bss->wpa_pairwise &
2079				 (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 |
2080				  WPA_CIPHER_WEP104)) {
2081				wpa_printf(MSG_ERROR, "Line %d: unsupported "
2082					   "pairwise cipher suite '%s'",
2083					   bss->wpa_pairwise, pos);
2084				errors++;
2085			}
2086		} else if (os_strcmp(buf, "rsn_pairwise") == 0) {
2087			bss->rsn_pairwise =
2088				hostapd_config_parse_cipher(line, pos);
2089			if (bss->rsn_pairwise == -1 ||
2090			    bss->rsn_pairwise == 0)
2091				errors++;
2092			else if (bss->rsn_pairwise &
2093				 (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 |
2094				  WPA_CIPHER_WEP104)) {
2095				wpa_printf(MSG_ERROR, "Line %d: unsupported "
2096					   "pairwise cipher suite '%s'",
2097					   bss->rsn_pairwise, pos);
2098				errors++;
2099			}
2100#ifdef CONFIG_RSN_PREAUTH
2101		} else if (os_strcmp(buf, "rsn_preauth") == 0) {
2102			bss->rsn_preauth = atoi(pos);
2103		} else if (os_strcmp(buf, "rsn_preauth_interfaces") == 0) {
2104			bss->rsn_preauth_interfaces = os_strdup(pos);
2105#endif /* CONFIG_RSN_PREAUTH */
2106#ifdef CONFIG_PEERKEY
2107		} else if (os_strcmp(buf, "peerkey") == 0) {
2108			bss->peerkey = atoi(pos);
2109#endif /* CONFIG_PEERKEY */
2110#ifdef CONFIG_IEEE80211R
2111		} else if (os_strcmp(buf, "mobility_domain") == 0) {
2112			if (os_strlen(pos) != 2 * MOBILITY_DOMAIN_ID_LEN ||
2113			    hexstr2bin(pos, bss->mobility_domain,
2114				       MOBILITY_DOMAIN_ID_LEN) != 0) {
2115				wpa_printf(MSG_DEBUG, "Line %d: Invalid "
2116					   "mobility_domain '%s'", line, pos);
2117				errors++;
2118				return errors;
2119			}
2120		} else if (os_strcmp(buf, "r1_key_holder") == 0) {
2121			if (os_strlen(pos) != 2 * FT_R1KH_ID_LEN ||
2122			    hexstr2bin(pos, bss->r1_key_holder,
2123				       FT_R1KH_ID_LEN) != 0) {
2124				wpa_printf(MSG_DEBUG, "Line %d: Invalid "
2125					   "r1_key_holder '%s'", line, pos);
2126				errors++;
2127				return errors;
2128			}
2129		} else if (os_strcmp(buf, "r0_key_lifetime") == 0) {
2130			bss->r0_key_lifetime = atoi(pos);
2131		} else if (os_strcmp(buf, "reassociation_deadline") == 0) {
2132			bss->reassociation_deadline = atoi(pos);
2133		} else if (os_strcmp(buf, "r0kh") == 0) {
2134			if (add_r0kh(bss, pos) < 0) {
2135				wpa_printf(MSG_DEBUG, "Line %d: Invalid "
2136					   "r0kh '%s'", line, pos);
2137				errors++;
2138				return errors;
2139			}
2140		} else if (os_strcmp(buf, "r1kh") == 0) {
2141			if (add_r1kh(bss, pos) < 0) {
2142				wpa_printf(MSG_DEBUG, "Line %d: Invalid "
2143					   "r1kh '%s'", line, pos);
2144				errors++;
2145				return errors;
2146			}
2147		} else if (os_strcmp(buf, "pmk_r1_push") == 0) {
2148			bss->pmk_r1_push = atoi(pos);
2149		} else if (os_strcmp(buf, "ft_over_ds") == 0) {
2150			bss->ft_over_ds = atoi(pos);
2151#endif /* CONFIG_IEEE80211R */
2152#ifndef CONFIG_NO_CTRL_IFACE
2153		} else if (os_strcmp(buf, "ctrl_interface") == 0) {
2154			os_free(bss->ctrl_interface);
2155			bss->ctrl_interface = os_strdup(pos);
2156		} else if (os_strcmp(buf, "ctrl_interface_group") == 0) {
2157#ifndef CONFIG_NATIVE_WINDOWS
2158			struct group *grp;
2159			char *endp;
2160			const char *group = pos;
2161
2162			grp = getgrnam(group);
2163			if (grp) {
2164				bss->ctrl_interface_gid = grp->gr_gid;
2165				bss->ctrl_interface_gid_set = 1;
2166				wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
2167					   " (from group name '%s')",
2168					   bss->ctrl_interface_gid, group);
2169				return errors;
2170			}
2171
2172			/* Group name not found - try to parse this as gid */
2173			bss->ctrl_interface_gid = strtol(group, &endp, 10);
2174			if (*group == '\0' || *endp != '\0') {
2175				wpa_printf(MSG_DEBUG, "Line %d: Invalid group "
2176					   "'%s'", line, group);
2177				errors++;
2178				return errors;
2179			}
2180			bss->ctrl_interface_gid_set = 1;
2181			wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
2182				   bss->ctrl_interface_gid);
2183#endif /* CONFIG_NATIVE_WINDOWS */
2184#endif /* CONFIG_NO_CTRL_IFACE */
2185#ifdef RADIUS_SERVER
2186		} else if (os_strcmp(buf, "radius_server_clients") == 0) {
2187			os_free(bss->radius_server_clients);
2188			bss->radius_server_clients = os_strdup(pos);
2189		} else if (os_strcmp(buf, "radius_server_auth_port") == 0) {
2190			bss->radius_server_auth_port = atoi(pos);
2191		} else if (os_strcmp(buf, "radius_server_acct_port") == 0) {
2192			bss->radius_server_acct_port = atoi(pos);
2193		} else if (os_strcmp(buf, "radius_server_ipv6") == 0) {
2194			bss->radius_server_ipv6 = atoi(pos);
2195#endif /* RADIUS_SERVER */
2196		} else if (os_strcmp(buf, "test_socket") == 0) {
2197			os_free(bss->test_socket);
2198			bss->test_socket = os_strdup(pos);
2199		} else if (os_strcmp(buf, "use_pae_group_addr") == 0) {
2200			bss->use_pae_group_addr = atoi(pos);
2201		} else if (os_strcmp(buf, "hw_mode") == 0) {
2202			if (os_strcmp(pos, "a") == 0)
2203				conf->hw_mode = HOSTAPD_MODE_IEEE80211A;
2204			else if (os_strcmp(pos, "b") == 0)
2205				conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
2206			else if (os_strcmp(pos, "g") == 0)
2207				conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
2208			else if (os_strcmp(pos, "ad") == 0)
2209				conf->hw_mode = HOSTAPD_MODE_IEEE80211AD;
2210			else {
2211				wpa_printf(MSG_ERROR, "Line %d: unknown "
2212					   "hw_mode '%s'", line, pos);
2213				errors++;
2214			}
2215		} else if (os_strcmp(buf, "wps_rf_bands") == 0) {
2216			if (os_strcmp(pos, "a") == 0)
2217				bss->wps_rf_bands = WPS_RF_50GHZ;
2218			else if (os_strcmp(pos, "g") == 0 ||
2219				 os_strcmp(pos, "b") == 0)
2220				bss->wps_rf_bands = WPS_RF_24GHZ;
2221			else if (os_strcmp(pos, "ag") == 0 ||
2222				 os_strcmp(pos, "ga") == 0)
2223				bss->wps_rf_bands =
2224					WPS_RF_24GHZ | WPS_RF_50GHZ;
2225			else {
2226				wpa_printf(MSG_ERROR, "Line %d: unknown "
2227					   "wps_rf_band '%s'", line, pos);
2228				errors++;
2229			}
2230		} else if (os_strcmp(buf, "channel") == 0) {
2231			if (os_strcmp(pos, "acs_survey") == 0) {
2232#ifndef CONFIG_ACS
2233				wpa_printf(MSG_ERROR, "Line %d: tries to enable ACS but CONFIG_ACS disabled",
2234					   line);
2235				errors++;
2236#endif /* CONFIG_ACS */
2237				conf->channel = 0;
2238			} else
2239				conf->channel = atoi(pos);
2240		} else if (os_strcmp(buf, "beacon_int") == 0) {
2241			int val = atoi(pos);
2242			/* MIB defines range as 1..65535, but very small values
2243			 * cause problems with the current implementation.
2244			 * Since it is unlikely that this small numbers are
2245			 * useful in real life scenarios, do not allow beacon
2246			 * period to be set below 15 TU. */
2247			if (val < 15 || val > 65535) {
2248				wpa_printf(MSG_ERROR, "Line %d: invalid "
2249					   "beacon_int %d (expected "
2250					   "15..65535)", line, val);
2251				errors++;
2252			} else
2253				conf->beacon_int = val;
2254#ifdef CONFIG_ACS
2255		} else if (os_strcmp(buf, "acs_num_scans") == 0) {
2256			int val = atoi(pos);
2257			if (val <= 0 || val > 100) {
2258				wpa_printf(MSG_ERROR, "Line %d: invalid acs_num_scans %d (expected 1..100)",
2259					   line, val);
2260				errors++;
2261			} else
2262				conf->acs_num_scans = val;
2263#endif /* CONFIG_ACS */
2264		} else if (os_strcmp(buf, "dtim_period") == 0) {
2265			bss->dtim_period = atoi(pos);
2266			if (bss->dtim_period < 1 || bss->dtim_period > 255) {
2267				wpa_printf(MSG_ERROR, "Line %d: invalid "
2268					   "dtim_period %d",
2269					   line, bss->dtim_period);
2270				errors++;
2271			}
2272		} else if (os_strcmp(buf, "rts_threshold") == 0) {
2273			conf->rts_threshold = atoi(pos);
2274			if (conf->rts_threshold < 0 ||
2275			    conf->rts_threshold > 2347) {
2276				wpa_printf(MSG_ERROR, "Line %d: invalid "
2277					   "rts_threshold %d",
2278					   line, conf->rts_threshold);
2279				errors++;
2280			}
2281		} else if (os_strcmp(buf, "fragm_threshold") == 0) {
2282			conf->fragm_threshold = atoi(pos);
2283			if (conf->fragm_threshold < 256 ||
2284			    conf->fragm_threshold > 2346) {
2285				wpa_printf(MSG_ERROR, "Line %d: invalid "
2286					   "fragm_threshold %d",
2287					   line, conf->fragm_threshold);
2288				errors++;
2289			}
2290		} else if (os_strcmp(buf, "send_probe_response") == 0) {
2291			int val = atoi(pos);
2292			if (val != 0 && val != 1) {
2293				wpa_printf(MSG_ERROR, "Line %d: invalid "
2294					   "send_probe_response %d (expected "
2295					   "0 or 1)", line, val);
2296			} else
2297				conf->send_probe_response = val;
2298		} else if (os_strcmp(buf, "supported_rates") == 0) {
2299			if (hostapd_parse_intlist(&conf->supported_rates, pos))
2300			{
2301				wpa_printf(MSG_ERROR, "Line %d: invalid rate "
2302					   "list", line);
2303				errors++;
2304			}
2305		} else if (os_strcmp(buf, "basic_rates") == 0) {
2306			if (hostapd_parse_intlist(&conf->basic_rates, pos)) {
2307				wpa_printf(MSG_ERROR, "Line %d: invalid rate "
2308					   "list", line);
2309				errors++;
2310			}
2311		} else if (os_strcmp(buf, "preamble") == 0) {
2312			if (atoi(pos))
2313				conf->preamble = SHORT_PREAMBLE;
2314			else
2315				conf->preamble = LONG_PREAMBLE;
2316		} else if (os_strcmp(buf, "ignore_broadcast_ssid") == 0) {
2317			bss->ignore_broadcast_ssid = atoi(pos);
2318		} else if (os_strcmp(buf, "wep_default_key") == 0) {
2319			bss->ssid.wep.idx = atoi(pos);
2320			if (bss->ssid.wep.idx > 3) {
2321				wpa_printf(MSG_ERROR, "Invalid "
2322					   "wep_default_key index %d",
2323					   bss->ssid.wep.idx);
2324				errors++;
2325			}
2326		} else if (os_strcmp(buf, "wep_key0") == 0 ||
2327			   os_strcmp(buf, "wep_key1") == 0 ||
2328			   os_strcmp(buf, "wep_key2") == 0 ||
2329			   os_strcmp(buf, "wep_key3") == 0) {
2330			if (hostapd_config_read_wep(&bss->ssid.wep,
2331						    buf[7] - '0', pos)) {
2332				wpa_printf(MSG_ERROR, "Line %d: invalid WEP "
2333					   "key '%s'", line, buf);
2334				errors++;
2335			}
2336#ifndef CONFIG_NO_VLAN
2337		} else if (os_strcmp(buf, "dynamic_vlan") == 0) {
2338			bss->ssid.dynamic_vlan = atoi(pos);
2339		} else if (os_strcmp(buf, "vlan_file") == 0) {
2340			if (hostapd_config_read_vlan_file(bss, pos)) {
2341				wpa_printf(MSG_ERROR, "Line %d: failed to "
2342					   "read VLAN file '%s'", line, pos);
2343				errors++;
2344			}
2345		} else if (os_strcmp(buf, "vlan_naming") == 0) {
2346			bss->ssid.vlan_naming = atoi(pos);
2347			if (bss->ssid.vlan_naming >= DYNAMIC_VLAN_NAMING_END ||
2348			    bss->ssid.vlan_naming < 0) {
2349				wpa_printf(MSG_ERROR, "Line %d: invalid "
2350					   "naming scheme %d", line,
2351                                           bss->ssid.vlan_naming);
2352				errors++;
2353                        }
2354#ifdef CONFIG_FULL_DYNAMIC_VLAN
2355		} else if (os_strcmp(buf, "vlan_tagged_interface") == 0) {
2356			bss->ssid.vlan_tagged_interface = os_strdup(pos);
2357#endif /* CONFIG_FULL_DYNAMIC_VLAN */
2358#endif /* CONFIG_NO_VLAN */
2359		} else if (os_strcmp(buf, "ap_table_max_size") == 0) {
2360			conf->ap_table_max_size = atoi(pos);
2361		} else if (os_strcmp(buf, "ap_table_expiration_time") == 0) {
2362			conf->ap_table_expiration_time = atoi(pos);
2363		} else if (os_strncmp(buf, "tx_queue_", 9) == 0) {
2364			if (hostapd_config_tx_queue(conf, buf, pos)) {
2365				wpa_printf(MSG_ERROR, "Line %d: invalid TX "
2366					   "queue item", line);
2367				errors++;
2368			}
2369		} else if (os_strcmp(buf, "wme_enabled") == 0 ||
2370			   os_strcmp(buf, "wmm_enabled") == 0) {
2371			bss->wmm_enabled = atoi(pos);
2372		} else if (os_strcmp(buf, "uapsd_advertisement_enabled") == 0) {
2373			bss->wmm_uapsd = atoi(pos);
2374		} else if (os_strncmp(buf, "wme_ac_", 7) == 0 ||
2375			   os_strncmp(buf, "wmm_ac_", 7) == 0) {
2376			if (hostapd_config_wmm_ac(conf->wmm_ac_params, buf,
2377						  pos)) {
2378				wpa_printf(MSG_ERROR, "Line %d: invalid WMM "
2379					   "ac item", line);
2380				errors++;
2381			}
2382		} else if (os_strcmp(buf, "bss") == 0) {
2383			if (hostapd_config_bss(conf, pos)) {
2384				wpa_printf(MSG_ERROR, "Line %d: invalid bss "
2385					   "item", line);
2386				errors++;
2387			}
2388		} else if (os_strcmp(buf, "bssid") == 0) {
2389			if (hwaddr_aton(pos, bss->bssid)) {
2390				wpa_printf(MSG_ERROR, "Line %d: invalid bssid "
2391					   "item", line);
2392				errors++;
2393			}
2394#ifdef CONFIG_IEEE80211W
2395		} else if (os_strcmp(buf, "ieee80211w") == 0) {
2396			bss->ieee80211w = atoi(pos);
2397		} else if (os_strcmp(buf, "assoc_sa_query_max_timeout") == 0) {
2398			bss->assoc_sa_query_max_timeout = atoi(pos);
2399			if (bss->assoc_sa_query_max_timeout == 0) {
2400				wpa_printf(MSG_ERROR, "Line %d: invalid "
2401					   "assoc_sa_query_max_timeout", line);
2402				errors++;
2403			}
2404		} else if (os_strcmp(buf, "assoc_sa_query_retry_timeout") == 0)
2405		{
2406			bss->assoc_sa_query_retry_timeout = atoi(pos);
2407			if (bss->assoc_sa_query_retry_timeout == 0) {
2408				wpa_printf(MSG_ERROR, "Line %d: invalid "
2409					   "assoc_sa_query_retry_timeout",
2410					   line);
2411				errors++;
2412			}
2413#endif /* CONFIG_IEEE80211W */
2414#ifdef CONFIG_IEEE80211N
2415		} else if (os_strcmp(buf, "ieee80211n") == 0) {
2416			conf->ieee80211n = atoi(pos);
2417		} else if (os_strcmp(buf, "ht_capab") == 0) {
2418			if (hostapd_config_ht_capab(conf, pos) < 0) {
2419				wpa_printf(MSG_ERROR, "Line %d: invalid "
2420					   "ht_capab", line);
2421				errors++;
2422			}
2423		} else if (os_strcmp(buf, "require_ht") == 0) {
2424			conf->require_ht = atoi(pos);
2425		} else if (os_strcmp(buf, "obss_interval") == 0) {
2426			conf->obss_interval = atoi(pos);
2427#endif /* CONFIG_IEEE80211N */
2428#ifdef CONFIG_IEEE80211AC
2429		} else if (os_strcmp(buf, "ieee80211ac") == 0) {
2430			conf->ieee80211ac = atoi(pos);
2431		} else if (os_strcmp(buf, "vht_capab") == 0) {
2432			if (hostapd_config_vht_capab(conf, pos) < 0) {
2433				wpa_printf(MSG_ERROR, "Line %d: invalid "
2434					   "vht_capab", line);
2435				errors++;
2436			}
2437		} else if (os_strcmp(buf, "require_vht") == 0) {
2438			conf->require_vht = atoi(pos);
2439		} else if (os_strcmp(buf, "vht_oper_chwidth") == 0) {
2440			conf->vht_oper_chwidth = atoi(pos);
2441		} else if (os_strcmp(buf, "vht_oper_centr_freq_seg0_idx") == 0)
2442		{
2443			conf->vht_oper_centr_freq_seg0_idx = atoi(pos);
2444		} else if (os_strcmp(buf, "vht_oper_centr_freq_seg1_idx") == 0)
2445		{
2446			conf->vht_oper_centr_freq_seg1_idx = atoi(pos);
2447#endif /* CONFIG_IEEE80211AC */
2448		} else if (os_strcmp(buf, "max_listen_interval") == 0) {
2449			bss->max_listen_interval = atoi(pos);
2450		} else if (os_strcmp(buf, "disable_pmksa_caching") == 0) {
2451			bss->disable_pmksa_caching = atoi(pos);
2452		} else if (os_strcmp(buf, "okc") == 0) {
2453			bss->okc = atoi(pos);
2454#ifdef CONFIG_WPS
2455		} else if (os_strcmp(buf, "wps_state") == 0) {
2456			bss->wps_state = atoi(pos);
2457			if (bss->wps_state < 0 || bss->wps_state > 2) {
2458				wpa_printf(MSG_ERROR, "Line %d: invalid "
2459					   "wps_state", line);
2460				errors++;
2461			}
2462		} else if (os_strcmp(buf, "wps_independent") == 0) {
2463			bss->wps_independent = atoi(pos);
2464		} else if (os_strcmp(buf, "ap_setup_locked") == 0) {
2465			bss->ap_setup_locked = atoi(pos);
2466		} else if (os_strcmp(buf, "uuid") == 0) {
2467			if (uuid_str2bin(pos, bss->uuid)) {
2468				wpa_printf(MSG_ERROR, "Line %d: invalid UUID",
2469					   line);
2470				errors++;
2471			}
2472		} else if (os_strcmp(buf, "wps_pin_requests") == 0) {
2473			os_free(bss->wps_pin_requests);
2474			bss->wps_pin_requests = os_strdup(pos);
2475		} else if (os_strcmp(buf, "device_name") == 0) {
2476			if (os_strlen(pos) > 32) {
2477				wpa_printf(MSG_ERROR, "Line %d: Too long "
2478					   "device_name", line);
2479				errors++;
2480			}
2481			os_free(bss->device_name);
2482			bss->device_name = os_strdup(pos);
2483		} else if (os_strcmp(buf, "manufacturer") == 0) {
2484			if (os_strlen(pos) > 64) {
2485				wpa_printf(MSG_ERROR, "Line %d: Too long "
2486					   "manufacturer", line);
2487				errors++;
2488			}
2489			os_free(bss->manufacturer);
2490			bss->manufacturer = os_strdup(pos);
2491		} else if (os_strcmp(buf, "model_name") == 0) {
2492			if (os_strlen(pos) > 32) {
2493				wpa_printf(MSG_ERROR, "Line %d: Too long "
2494					   "model_name", line);
2495				errors++;
2496			}
2497			os_free(bss->model_name);
2498			bss->model_name = os_strdup(pos);
2499		} else if (os_strcmp(buf, "model_number") == 0) {
2500			if (os_strlen(pos) > 32) {
2501				wpa_printf(MSG_ERROR, "Line %d: Too long "
2502					   "model_number", line);
2503				errors++;
2504			}
2505			os_free(bss->model_number);
2506			bss->model_number = os_strdup(pos);
2507		} else if (os_strcmp(buf, "serial_number") == 0) {
2508			if (os_strlen(pos) > 32) {
2509				wpa_printf(MSG_ERROR, "Line %d: Too long "
2510					   "serial_number", line);
2511				errors++;
2512			}
2513			os_free(bss->serial_number);
2514			bss->serial_number = os_strdup(pos);
2515		} else if (os_strcmp(buf, "device_type") == 0) {
2516			if (wps_dev_type_str2bin(pos, bss->device_type))
2517				errors++;
2518		} else if (os_strcmp(buf, "config_methods") == 0) {
2519			os_free(bss->config_methods);
2520			bss->config_methods = os_strdup(pos);
2521		} else if (os_strcmp(buf, "os_version") == 0) {
2522			if (hexstr2bin(pos, bss->os_version, 4)) {
2523				wpa_printf(MSG_ERROR, "Line %d: invalid "
2524					   "os_version", line);
2525				errors++;
2526			}
2527		} else if (os_strcmp(buf, "ap_pin") == 0) {
2528			os_free(bss->ap_pin);
2529			bss->ap_pin = os_strdup(pos);
2530		} else if (os_strcmp(buf, "skip_cred_build") == 0) {
2531			bss->skip_cred_build = atoi(pos);
2532		} else if (os_strcmp(buf, "extra_cred") == 0) {
2533			os_free(bss->extra_cred);
2534			bss->extra_cred =
2535				(u8 *) os_readfile(pos, &bss->extra_cred_len);
2536			if (bss->extra_cred == NULL) {
2537				wpa_printf(MSG_ERROR, "Line %d: could not "
2538					   "read Credentials from '%s'",
2539					   line, pos);
2540				errors++;
2541			}
2542		} else if (os_strcmp(buf, "wps_cred_processing") == 0) {
2543			bss->wps_cred_processing = atoi(pos);
2544		} else if (os_strcmp(buf, "ap_settings") == 0) {
2545			os_free(bss->ap_settings);
2546			bss->ap_settings =
2547				(u8 *) os_readfile(pos, &bss->ap_settings_len);
2548			if (bss->ap_settings == NULL) {
2549				wpa_printf(MSG_ERROR, "Line %d: could not "
2550					   "read AP Settings from '%s'",
2551					   line, pos);
2552				errors++;
2553			}
2554		} else if (os_strcmp(buf, "upnp_iface") == 0) {
2555			bss->upnp_iface = os_strdup(pos);
2556		} else if (os_strcmp(buf, "friendly_name") == 0) {
2557			os_free(bss->friendly_name);
2558			bss->friendly_name = os_strdup(pos);
2559		} else if (os_strcmp(buf, "manufacturer_url") == 0) {
2560			os_free(bss->manufacturer_url);
2561			bss->manufacturer_url = os_strdup(pos);
2562		} else if (os_strcmp(buf, "model_description") == 0) {
2563			os_free(bss->model_description);
2564			bss->model_description = os_strdup(pos);
2565		} else if (os_strcmp(buf, "model_url") == 0) {
2566			os_free(bss->model_url);
2567			bss->model_url = os_strdup(pos);
2568		} else if (os_strcmp(buf, "upc") == 0) {
2569			os_free(bss->upc);
2570			bss->upc = os_strdup(pos);
2571		} else if (os_strcmp(buf, "pbc_in_m1") == 0) {
2572			bss->pbc_in_m1 = atoi(pos);
2573		} else if (os_strcmp(buf, "server_id") == 0) {
2574			os_free(bss->server_id);
2575			bss->server_id = os_strdup(pos);
2576#ifdef CONFIG_WPS_NFC
2577		} else if (os_strcmp(buf, "wps_nfc_dev_pw_id") == 0) {
2578			bss->wps_nfc_dev_pw_id = atoi(pos);
2579			if (bss->wps_nfc_dev_pw_id < 0x10 ||
2580			    bss->wps_nfc_dev_pw_id > 0xffff) {
2581				wpa_printf(MSG_ERROR, "Line %d: Invalid "
2582					   "wps_nfc_dev_pw_id value", line);
2583				errors++;
2584			}
2585			bss->wps_nfc_pw_from_config = 1;
2586		} else if (os_strcmp(buf, "wps_nfc_dh_pubkey") == 0) {
2587			wpabuf_free(bss->wps_nfc_dh_pubkey);
2588			bss->wps_nfc_dh_pubkey = hostapd_parse_bin(pos);
2589			bss->wps_nfc_pw_from_config = 1;
2590		} else if (os_strcmp(buf, "wps_nfc_dh_privkey") == 0) {
2591			wpabuf_free(bss->wps_nfc_dh_privkey);
2592			bss->wps_nfc_dh_privkey = hostapd_parse_bin(pos);
2593			bss->wps_nfc_pw_from_config = 1;
2594		} else if (os_strcmp(buf, "wps_nfc_dev_pw") == 0) {
2595			wpabuf_free(bss->wps_nfc_dev_pw);
2596			bss->wps_nfc_dev_pw = hostapd_parse_bin(pos);
2597			bss->wps_nfc_pw_from_config = 1;
2598#endif /* CONFIG_WPS_NFC */
2599#endif /* CONFIG_WPS */
2600#ifdef CONFIG_P2P_MANAGER
2601		} else if (os_strcmp(buf, "manage_p2p") == 0) {
2602			int manage = atoi(pos);
2603			if (manage)
2604				bss->p2p |= P2P_MANAGE;
2605			else
2606				bss->p2p &= ~P2P_MANAGE;
2607		} else if (os_strcmp(buf, "allow_cross_connection") == 0) {
2608			if (atoi(pos))
2609				bss->p2p |= P2P_ALLOW_CROSS_CONNECTION;
2610			else
2611				bss->p2p &= ~P2P_ALLOW_CROSS_CONNECTION;
2612#endif /* CONFIG_P2P_MANAGER */
2613		} else if (os_strcmp(buf, "disassoc_low_ack") == 0) {
2614			bss->disassoc_low_ack = atoi(pos);
2615		} else if (os_strcmp(buf, "tdls_prohibit") == 0) {
2616			int val = atoi(pos);
2617			if (val)
2618				bss->tdls |= TDLS_PROHIBIT;
2619			else
2620				bss->tdls &= ~TDLS_PROHIBIT;
2621		} else if (os_strcmp(buf, "tdls_prohibit_chan_switch") == 0) {
2622			int val = atoi(pos);
2623			if (val)
2624				bss->tdls |= TDLS_PROHIBIT_CHAN_SWITCH;
2625			else
2626				bss->tdls &= ~TDLS_PROHIBIT_CHAN_SWITCH;
2627#ifdef CONFIG_RSN_TESTING
2628		} else if (os_strcmp(buf, "rsn_testing") == 0) {
2629			extern int rsn_testing;
2630			rsn_testing = atoi(pos);
2631#endif /* CONFIG_RSN_TESTING */
2632		} else if (os_strcmp(buf, "time_advertisement") == 0) {
2633			bss->time_advertisement = atoi(pos);
2634		} else if (os_strcmp(buf, "time_zone") == 0) {
2635			size_t tz_len = os_strlen(pos);
2636			if (tz_len < 4 || tz_len > 255) {
2637				wpa_printf(MSG_DEBUG, "Line %d: invalid "
2638					   "time_zone", line);
2639				errors++;
2640				return errors;
2641			}
2642			os_free(bss->time_zone);
2643			bss->time_zone = os_strdup(pos);
2644			if (bss->time_zone == NULL)
2645				errors++;
2646#ifdef CONFIG_WNM
2647		} else if (os_strcmp(buf, "wnm_sleep_mode") == 0) {
2648			bss->wnm_sleep_mode = atoi(pos);
2649		} else if (os_strcmp(buf, "bss_transition") == 0) {
2650			bss->bss_transition = atoi(pos);
2651#endif /* CONFIG_WNM */
2652#ifdef CONFIG_INTERWORKING
2653		} else if (os_strcmp(buf, "interworking") == 0) {
2654			bss->interworking = atoi(pos);
2655		} else if (os_strcmp(buf, "access_network_type") == 0) {
2656			bss->access_network_type = atoi(pos);
2657			if (bss->access_network_type < 0 ||
2658			    bss->access_network_type > 15) {
2659				wpa_printf(MSG_ERROR, "Line %d: invalid "
2660					   "access_network_type", line);
2661				errors++;
2662			}
2663		} else if (os_strcmp(buf, "internet") == 0) {
2664			bss->internet = atoi(pos);
2665		} else if (os_strcmp(buf, "asra") == 0) {
2666			bss->asra = atoi(pos);
2667		} else if (os_strcmp(buf, "esr") == 0) {
2668			bss->esr = atoi(pos);
2669		} else if (os_strcmp(buf, "uesa") == 0) {
2670			bss->uesa = atoi(pos);
2671		} else if (os_strcmp(buf, "venue_group") == 0) {
2672			bss->venue_group = atoi(pos);
2673			bss->venue_info_set = 1;
2674		} else if (os_strcmp(buf, "venue_type") == 0) {
2675			bss->venue_type = atoi(pos);
2676			bss->venue_info_set = 1;
2677		} else if (os_strcmp(buf, "hessid") == 0) {
2678			if (hwaddr_aton(pos, bss->hessid)) {
2679				wpa_printf(MSG_ERROR, "Line %d: invalid "
2680					   "hessid", line);
2681				errors++;
2682			}
2683		} else if (os_strcmp(buf, "roaming_consortium") == 0) {
2684			if (parse_roaming_consortium(bss, pos, line) < 0)
2685				errors++;
2686		} else if (os_strcmp(buf, "venue_name") == 0) {
2687			if (parse_venue_name(bss, pos, line) < 0)
2688				errors++;
2689		} else if (os_strcmp(buf, "network_auth_type") == 0) {
2690			u8 auth_type;
2691			u16 redirect_url_len;
2692			if (hexstr2bin(pos, &auth_type, 1)) {
2693				wpa_printf(MSG_ERROR, "Line %d: Invalid "
2694					   "network_auth_type '%s'",
2695					   line, pos);
2696				errors++;
2697				return errors;
2698			}
2699			if (auth_type == 0 || auth_type == 2)
2700				redirect_url_len = os_strlen(pos + 2);
2701			else
2702				redirect_url_len = 0;
2703			os_free(bss->network_auth_type);
2704			bss->network_auth_type =
2705				os_malloc(redirect_url_len + 3 + 1);
2706			if (bss->network_auth_type == NULL) {
2707				errors++;
2708				return errors;
2709			}
2710			*bss->network_auth_type = auth_type;
2711			WPA_PUT_LE16(bss->network_auth_type + 1,
2712				     redirect_url_len);
2713			if (redirect_url_len)
2714				os_memcpy(bss->network_auth_type + 3,
2715					  pos + 2, redirect_url_len);
2716			bss->network_auth_type_len = 3 + redirect_url_len;
2717		} else if (os_strcmp(buf, "ipaddr_type_availability") == 0) {
2718			if (hexstr2bin(pos, &bss->ipaddr_type_availability, 1))
2719			{
2720				wpa_printf(MSG_ERROR, "Line %d: Invalid "
2721					   "ipaddr_type_availability '%s'",
2722					   line, pos);
2723				bss->ipaddr_type_configured = 0;
2724				errors++;
2725				return errors;
2726			}
2727			bss->ipaddr_type_configured = 1;
2728		} else if (os_strcmp(buf, "domain_name") == 0) {
2729			int j, num_domains, domain_len, domain_list_len = 0;
2730			char *tok_start, *tok_prev;
2731			u8 *domain_list, *domain_ptr;
2732
2733			domain_list_len = os_strlen(pos) + 1;
2734			domain_list = os_malloc(domain_list_len);
2735			if (domain_list == NULL) {
2736				errors++;
2737				return errors;
2738			}
2739
2740			domain_ptr = domain_list;
2741			tok_prev = pos;
2742			num_domains = 1;
2743			while ((tok_prev = os_strchr(tok_prev, ','))) {
2744				num_domains++;
2745				tok_prev++;
2746			}
2747			tok_prev = pos;
2748			for (j = 0; j < num_domains; j++) {
2749				tok_start = os_strchr(tok_prev, ',');
2750				if (tok_start) {
2751					domain_len = tok_start - tok_prev;
2752					*domain_ptr = domain_len;
2753					os_memcpy(domain_ptr + 1, tok_prev,
2754						  domain_len);
2755					domain_ptr += domain_len + 1;
2756					tok_prev = ++tok_start;
2757				} else {
2758					domain_len = os_strlen(tok_prev);
2759					*domain_ptr = domain_len;
2760					os_memcpy(domain_ptr + 1, tok_prev,
2761						  domain_len);
2762					domain_ptr += domain_len + 1;
2763				}
2764			}
2765
2766			os_free(bss->domain_name);
2767			bss->domain_name = domain_list;
2768			bss->domain_name_len = domain_list_len;
2769		} else if (os_strcmp(buf, "anqp_3gpp_cell_net") == 0) {
2770			if (parse_3gpp_cell_net(bss, pos, line) < 0)
2771				errors++;
2772		} else if (os_strcmp(buf, "nai_realm") == 0) {
2773			if (parse_nai_realm(bss, pos, line) < 0)
2774				errors++;
2775		} else if (os_strcmp(buf, "gas_frag_limit") == 0) {
2776			bss->gas_frag_limit = atoi(pos);
2777		} else if (os_strcmp(buf, "gas_comeback_delay") == 0) {
2778			bss->gas_comeback_delay = atoi(pos);
2779		} else if (os_strcmp(buf, "qos_map_set") == 0) {
2780			if (parse_qos_map_set(bss, pos, line) < 0)
2781				errors++;
2782#endif /* CONFIG_INTERWORKING */
2783#ifdef CONFIG_RADIUS_TEST
2784		} else if (os_strcmp(buf, "dump_msk_file") == 0) {
2785			os_free(bss->dump_msk_file);
2786			bss->dump_msk_file = os_strdup(pos);
2787#endif /* CONFIG_RADIUS_TEST */
2788#ifdef CONFIG_HS20
2789		} else if (os_strcmp(buf, "hs20") == 0) {
2790			bss->hs20 = atoi(pos);
2791		} else if (os_strcmp(buf, "disable_dgaf") == 0) {
2792			bss->disable_dgaf = atoi(pos);
2793		} else if (os_strcmp(buf, "hs20_oper_friendly_name") == 0) {
2794			if (hs20_parse_oper_friendly_name(bss, pos, line) < 0)
2795				errors++;
2796		} else if (os_strcmp(buf, "hs20_wan_metrics") == 0) {
2797			if (hs20_parse_wan_metrics(bss, pos, line) < 0) {
2798				errors++;
2799				return errors;
2800			}
2801		} else if (os_strcmp(buf, "hs20_conn_capab") == 0) {
2802			if (hs20_parse_conn_capab(bss, pos, line) < 0) {
2803				errors++;
2804				return errors;
2805			}
2806		} else if (os_strcmp(buf, "hs20_operating_class") == 0) {
2807			u8 *oper_class;
2808			size_t oper_class_len;
2809			oper_class_len = os_strlen(pos);
2810			if (oper_class_len < 2 || (oper_class_len & 0x01)) {
2811				wpa_printf(MSG_ERROR, "Line %d: Invalid "
2812					   "hs20_operating_class '%s'",
2813					   line, pos);
2814				errors++;
2815				return errors;
2816			}
2817			oper_class_len /= 2;
2818			oper_class = os_malloc(oper_class_len);
2819			if (oper_class == NULL) {
2820				errors++;
2821				return errors;
2822			}
2823			if (hexstr2bin(pos, oper_class, oper_class_len)) {
2824				wpa_printf(MSG_ERROR, "Line %d: Invalid "
2825					   "hs20_operating_class '%s'",
2826					   line, pos);
2827				os_free(oper_class);
2828				errors++;
2829				return errors;
2830			}
2831			os_free(bss->hs20_operating_class);
2832			bss->hs20_operating_class = oper_class;
2833			bss->hs20_operating_class_len = oper_class_len;
2834#endif /* CONFIG_HS20 */
2835#ifdef CONFIG_TESTING_OPTIONS
2836#define PARSE_TEST_PROBABILITY(_val)					\
2837		} else if (os_strcmp(buf, #_val) == 0) {		\
2838			char *end;					\
2839									\
2840			conf->_val = strtod(pos, &end);			\
2841			if (*end || conf->_val < 0.0d ||		\
2842			    conf->_val > 1.0d) {			\
2843				wpa_printf(MSG_ERROR,			\
2844					   "Line %d: Invalid value '%s'", \
2845					   line, pos);			\
2846				errors++;				\
2847				return errors;				\
2848			}
2849		PARSE_TEST_PROBABILITY(ignore_probe_probability)
2850		PARSE_TEST_PROBABILITY(ignore_auth_probability)
2851		PARSE_TEST_PROBABILITY(ignore_assoc_probability)
2852		PARSE_TEST_PROBABILITY(ignore_reassoc_probability)
2853		PARSE_TEST_PROBABILITY(corrupt_gtk_rekey_mic_probability)
2854		} else if (os_strcmp(buf, "bss_load_test") == 0) {
2855			WPA_PUT_LE16(bss->bss_load_test, atoi(pos));
2856			pos = os_strchr(pos, ':');
2857			if (pos == NULL) {
2858				wpa_printf(MSG_ERROR, "Line %d: Invalid "
2859					   "bss_load_test", line);
2860				return 1;
2861			}
2862			pos++;
2863			bss->bss_load_test[2] = atoi(pos);
2864			pos = os_strchr(pos, ':');
2865			if (pos == NULL) {
2866				wpa_printf(MSG_ERROR, "Line %d: Invalid "
2867					   "bss_load_test", line);
2868				return 1;
2869			}
2870			pos++;
2871			WPA_PUT_LE16(&bss->bss_load_test[3], atoi(pos));
2872			bss->bss_load_test_set = 1;
2873#endif /* CONFIG_TESTING_OPTIONS */
2874		} else if (os_strcmp(buf, "vendor_elements") == 0) {
2875			struct wpabuf *elems;
2876			size_t len = os_strlen(pos);
2877			if (len & 0x01) {
2878				wpa_printf(MSG_ERROR, "Line %d: Invalid "
2879					   "vendor_elements '%s'", line, pos);
2880				return 1;
2881			}
2882			len /= 2;
2883			if (len == 0) {
2884				wpabuf_free(bss->vendor_elements);
2885				bss->vendor_elements = NULL;
2886				return 0;
2887			}
2888
2889			elems = wpabuf_alloc(len);
2890			if (elems == NULL)
2891				return 1;
2892
2893			if (hexstr2bin(pos, wpabuf_put(elems, len), len)) {
2894				wpabuf_free(elems);
2895				wpa_printf(MSG_ERROR, "Line %d: Invalid "
2896					   "vendor_elements '%s'", line, pos);
2897				return 1;
2898			}
2899
2900			wpabuf_free(bss->vendor_elements);
2901			bss->vendor_elements = elems;
2902		} else if (os_strcmp(buf, "sae_anti_clogging_threshold") == 0) {
2903			bss->sae_anti_clogging_threshold = atoi(pos);
2904		} else if (os_strcmp(buf, "sae_groups") == 0) {
2905			if (hostapd_parse_intlist(&bss->sae_groups, pos)) {
2906				wpa_printf(MSG_ERROR, "Line %d: Invalid "
2907					   "sae_groups value '%s'", line, pos);
2908				return 1;
2909			}
2910		} else {
2911			wpa_printf(MSG_ERROR, "Line %d: unknown configuration "
2912				   "item '%s'", line, buf);
2913			errors++;
2914		}
2915	}
2916
2917	return errors;
2918}
2919
2920
2921/**
2922 * hostapd_config_read - Read and parse a configuration file
2923 * @fname: Configuration file name (including path, if needed)
2924 * Returns: Allocated configuration data structure
2925 */
2926struct hostapd_config * hostapd_config_read(const char *fname)
2927{
2928	struct hostapd_config *conf;
2929	struct hostapd_bss_config *bss;
2930	FILE *f;
2931	char buf[512], *pos;
2932	int line = 0;
2933	int errors = 0;
2934	size_t i;
2935
2936	f = fopen(fname, "r");
2937	if (f == NULL) {
2938		wpa_printf(MSG_ERROR, "Could not open configuration file '%s' "
2939			   "for reading.", fname);
2940		return NULL;
2941	}
2942
2943	conf = hostapd_config_defaults();
2944	if (conf == NULL) {
2945		fclose(f);
2946		return NULL;
2947	}
2948
2949	/* set default driver based on configuration */
2950	conf->driver = wpa_drivers[0];
2951	if (conf->driver == NULL) {
2952		wpa_printf(MSG_ERROR, "No driver wrappers registered!");
2953		hostapd_config_free(conf);
2954		fclose(f);
2955		return NULL;
2956	}
2957
2958	bss = conf->last_bss = conf->bss[0];
2959
2960	while (fgets(buf, sizeof(buf), f)) {
2961		bss = conf->last_bss;
2962		line++;
2963
2964		if (buf[0] == '#')
2965			continue;
2966		pos = buf;
2967		while (*pos != '\0') {
2968			if (*pos == '\n') {
2969				*pos = '\0';
2970				break;
2971			}
2972			pos++;
2973		}
2974		if (buf[0] == '\0')
2975			continue;
2976
2977		pos = os_strchr(buf, '=');
2978		if (pos == NULL) {
2979			wpa_printf(MSG_ERROR, "Line %d: invalid line '%s'",
2980				   line, buf);
2981			errors++;
2982			continue;
2983		}
2984		*pos = '\0';
2985		pos++;
2986		errors += hostapd_config_fill(conf, bss, buf, pos, line);
2987	}
2988
2989	fclose(f);
2990
2991	for (i = 0; i < conf->num_bss; i++)
2992		hostapd_set_security_params(conf->bss[i]);
2993
2994	if (hostapd_config_check(conf, 1))
2995		errors++;
2996
2997#ifndef WPA_IGNORE_CONFIG_ERRORS
2998	if (errors) {
2999		wpa_printf(MSG_ERROR, "%d errors found in configuration file "
3000			   "'%s'", errors, fname);
3001		hostapd_config_free(conf);
3002		conf = NULL;
3003	}
3004#endif /* WPA_IGNORE_CONFIG_ERRORS */
3005
3006	return conf;
3007}
3008
3009
3010int hostapd_set_iface(struct hostapd_config *conf,
3011		      struct hostapd_bss_config *bss, char *field, char *value)
3012{
3013	int errors;
3014	size_t i;
3015
3016	errors = hostapd_config_fill(conf, bss, field, value, 0);
3017	if (errors) {
3018		wpa_printf(MSG_INFO, "Failed to set configuration field '%s' "
3019			   "to value '%s'", field, value);
3020		return -1;
3021	}
3022
3023	for (i = 0; i < conf->num_bss; i++)
3024		hostapd_set_security_params(conf->bss[i]);
3025
3026	if (hostapd_config_check(conf, 0)) {
3027		wpa_printf(MSG_ERROR, "Configuration check failed");
3028		return -1;
3029	}
3030
3031	return 0;
3032}
3033