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