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