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