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