]> git.ipfire.org Git - thirdparty/hostap.git/blame - hostapd/config_file.c
GAS server: Add support for ANQP Venue Name element
[thirdparty/hostap.git] / hostapd / config_file.c
CommitLineData
41d719d6
JM
1/*
2 * hostapd / Configuration file parser
3 * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
4 *
0f3d578e
JM
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
41d719d6
JM
7 */
8
6226e38d 9#include "utils/includes.h"
41d719d6
JM
10#ifndef CONFIG_NATIVE_WINDOWS
11#include <grp.h>
12#endif /* CONFIG_NATIVE_WINDOWS */
13
6226e38d
JM
14#include "utils/common.h"
15#include "utils/uuid.h"
41d719d6
JM
16#include "common/ieee802_11_defs.h"
17#include "drivers/driver.h"
18#include "eap_server/eap.h"
19#include "radius/radius_client.h"
6226e38d
JM
20#include "ap/wpa_auth.h"
21#include "ap/ap_config.h"
1057d78e 22#include "config_file.h"
41d719d6
JM
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(*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++;
e9447a94 327 if (num_methods >= EAP_MAX_METHODS)
41d719d6
JM
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(*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#endif /* CONFIG_NO_RADIUS */
495
496
497static int hostapd_config_parse_key_mgmt(int line, const char *value)
498{
499 int val = 0, last;
500 char *start, *end, *buf;
501
502 buf = os_strdup(value);
503 if (buf == NULL)
504 return -1;
505 start = buf;
506
507 while (*start != '\0') {
508 while (*start == ' ' || *start == '\t')
509 start++;
510 if (*start == '\0')
511 break;
512 end = start;
513 while (*end != ' ' && *end != '\t' && *end != '\0')
514 end++;
515 last = *end == '\0';
516 *end = '\0';
517 if (os_strcmp(start, "WPA-PSK") == 0)
518 val |= WPA_KEY_MGMT_PSK;
519 else if (os_strcmp(start, "WPA-EAP") == 0)
520 val |= WPA_KEY_MGMT_IEEE8021X;
521#ifdef CONFIG_IEEE80211R
522 else if (os_strcmp(start, "FT-PSK") == 0)
523 val |= WPA_KEY_MGMT_FT_PSK;
524 else if (os_strcmp(start, "FT-EAP") == 0)
525 val |= WPA_KEY_MGMT_FT_IEEE8021X;
526#endif /* CONFIG_IEEE80211R */
527#ifdef CONFIG_IEEE80211W
528 else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
529 val |= WPA_KEY_MGMT_PSK_SHA256;
530 else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
531 val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
532#endif /* CONFIG_IEEE80211W */
533 else {
534 wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
535 line, start);
536 os_free(buf);
537 return -1;
538 }
539
540 if (last)
541 break;
542 start = end + 1;
543 }
544
545 os_free(buf);
546 if (val == 0) {
547 wpa_printf(MSG_ERROR, "Line %d: no key_mgmt values "
548 "configured.", line);
549 return -1;
550 }
551
552 return val;
553}
554
555
556static int hostapd_config_parse_cipher(int line, const char *value)
557{
558 int val = 0, last;
559 char *start, *end, *buf;
560
561 buf = os_strdup(value);
562 if (buf == NULL)
563 return -1;
564 start = buf;
565
566 while (*start != '\0') {
567 while (*start == ' ' || *start == '\t')
568 start++;
569 if (*start == '\0')
570 break;
571 end = start;
572 while (*end != ' ' && *end != '\t' && *end != '\0')
573 end++;
574 last = *end == '\0';
575 *end = '\0';
576 if (os_strcmp(start, "CCMP") == 0)
577 val |= WPA_CIPHER_CCMP;
578 else if (os_strcmp(start, "TKIP") == 0)
579 val |= WPA_CIPHER_TKIP;
580 else if (os_strcmp(start, "WEP104") == 0)
581 val |= WPA_CIPHER_WEP104;
582 else if (os_strcmp(start, "WEP40") == 0)
583 val |= WPA_CIPHER_WEP40;
584 else if (os_strcmp(start, "NONE") == 0)
585 val |= WPA_CIPHER_NONE;
586 else {
587 wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
588 line, start);
589 os_free(buf);
590 return -1;
591 }
592
593 if (last)
594 break;
595 start = end + 1;
596 }
597 os_free(buf);
598
599 if (val == 0) {
600 wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.",
601 line);
602 return -1;
603 }
604 return val;
605}
606
607
608static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
609 char *val)
610{
611 size_t len = os_strlen(val);
612
613 if (keyidx < 0 || keyidx > 3 || wep->key[keyidx] != NULL)
614 return -1;
615
616 if (val[0] == '"') {
617 if (len < 2 || val[len - 1] != '"')
618 return -1;
619 len -= 2;
620 wep->key[keyidx] = os_malloc(len);
621 if (wep->key[keyidx] == NULL)
622 return -1;
623 os_memcpy(wep->key[keyidx], val + 1, len);
624 wep->len[keyidx] = len;
625 } else {
626 if (len & 1)
627 return -1;
628 len /= 2;
629 wep->key[keyidx] = os_malloc(len);
630 if (wep->key[keyidx] == NULL)
631 return -1;
632 wep->len[keyidx] = len;
633 if (hexstr2bin(val, wep->key[keyidx], len) < 0)
634 return -1;
635 }
636
637 wep->keys_set++;
638
639 return 0;
640}
641
642
643static int hostapd_parse_rates(int **rate_list, char *val)
644{
645 int *list;
646 int count;
647 char *pos, *end;
648
649 os_free(*rate_list);
650 *rate_list = NULL;
651
652 pos = val;
653 count = 0;
654 while (*pos != '\0') {
655 if (*pos == ' ')
656 count++;
657 pos++;
658 }
659
660 list = os_malloc(sizeof(int) * (count + 2));
661 if (list == NULL)
662 return -1;
663 pos = val;
664 count = 0;
665 while (*pos != '\0') {
666 end = os_strchr(pos, ' ');
667 if (end)
668 *end = '\0';
669
670 list[count++] = atoi(pos);
671 if (!end)
672 break;
673 pos = end + 1;
674 }
675 list[count] = -1;
676
677 *rate_list = list;
678 return 0;
679}
680
681
682static int hostapd_config_bss(struct hostapd_config *conf, const char *ifname)
683{
684 struct hostapd_bss_config *bss;
685
686 if (*ifname == '\0')
687 return -1;
688
689 bss = os_realloc(conf->bss, (conf->num_bss + 1) *
690 sizeof(struct hostapd_bss_config));
691 if (bss == NULL) {
692 wpa_printf(MSG_ERROR, "Failed to allocate memory for "
693 "multi-BSS entry");
694 return -1;
695 }
696 conf->bss = bss;
697
698 bss = &(conf->bss[conf->num_bss]);
699 os_memset(bss, 0, sizeof(*bss));
700 bss->radius = os_zalloc(sizeof(*bss->radius));
701 if (bss->radius == NULL) {
702 wpa_printf(MSG_ERROR, "Failed to allocate memory for "
703 "multi-BSS RADIUS data");
704 return -1;
705 }
706
707 conf->num_bss++;
708 conf->last_bss = bss;
709
710 hostapd_config_defaults_bss(bss);
711 os_strlcpy(bss->iface, ifname, sizeof(bss->iface));
712 os_memcpy(bss->ssid.vlan, bss->iface, IFNAMSIZ + 1);
713
714 return 0;
715}
716
717
718/* convert floats with one decimal place to value*10 int, i.e.,
719 * "1.5" will return 15 */
720static int hostapd_config_read_int10(const char *value)
721{
722 int i, d;
723 char *pos;
724
725 i = atoi(value);
726 pos = os_strchr(value, '.');
727 d = 0;
728 if (pos) {
729 pos++;
730 if (*pos >= '0' && *pos <= '9')
731 d = *pos - '0';
732 }
733
734 return i * 10 + d;
735}
736
737
738static int valid_cw(int cw)
739{
740 return (cw == 1 || cw == 3 || cw == 7 || cw == 15 || cw == 31 ||
741 cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023);
742}
743
744
745enum {
746 IEEE80211_TX_QUEUE_DATA0 = 0, /* used for EDCA AC_VO data */
747 IEEE80211_TX_QUEUE_DATA1 = 1, /* used for EDCA AC_VI data */
748 IEEE80211_TX_QUEUE_DATA2 = 2, /* used for EDCA AC_BE data */
7e3c1781 749 IEEE80211_TX_QUEUE_DATA3 = 3 /* used for EDCA AC_BK data */
41d719d6
JM
750};
751
752static int hostapd_config_tx_queue(struct hostapd_config *conf, char *name,
753 char *val)
754{
755 int num;
756 char *pos;
757 struct hostapd_tx_queue_params *queue;
758
759 /* skip 'tx_queue_' prefix */
760 pos = name + 9;
761 if (os_strncmp(pos, "data", 4) == 0 &&
762 pos[4] >= '0' && pos[4] <= '9' && pos[5] == '_') {
763 num = pos[4] - '0';
764 pos += 6;
7e3c1781
JM
765 } else if (os_strncmp(pos, "after_beacon_", 13) == 0 ||
766 os_strncmp(pos, "beacon_", 7) == 0) {
767 wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
768 return 0;
41d719d6
JM
769 } else {
770 wpa_printf(MSG_ERROR, "Unknown tx_queue name '%s'", pos);
771 return -1;
772 }
773
7e3c1781 774 if (num >= NUM_TX_QUEUES) {
d2da2249 775 /* for backwards compatibility, do not trigger failure */
7e3c1781
JM
776 wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
777 return 0;
778 }
779
41d719d6
JM
780 queue = &conf->tx_queue[num];
781
782 if (os_strcmp(pos, "aifs") == 0) {
783 queue->aifs = atoi(val);
784 if (queue->aifs < 0 || queue->aifs > 255) {
785 wpa_printf(MSG_ERROR, "Invalid AIFS value %d",
786 queue->aifs);
787 return -1;
788 }
789 } else if (os_strcmp(pos, "cwmin") == 0) {
790 queue->cwmin = atoi(val);
791 if (!valid_cw(queue->cwmin)) {
792 wpa_printf(MSG_ERROR, "Invalid cwMin value %d",
793 queue->cwmin);
794 return -1;
795 }
796 } else if (os_strcmp(pos, "cwmax") == 0) {
797 queue->cwmax = atoi(val);
798 if (!valid_cw(queue->cwmax)) {
799 wpa_printf(MSG_ERROR, "Invalid cwMax value %d",
800 queue->cwmax);
801 return -1;
802 }
803 } else if (os_strcmp(pos, "burst") == 0) {
804 queue->burst = hostapd_config_read_int10(val);
805 } else {
806 wpa_printf(MSG_ERROR, "Unknown tx_queue field '%s'", pos);
807 return -1;
808 }
809
41d719d6
JM
810 return 0;
811}
812
813
814static int hostapd_config_wmm_ac(struct hostapd_config *conf, char *name,
815 char *val)
816{
817 int num, v;
818 char *pos;
819 struct hostapd_wmm_ac_params *ac;
820
821 /* skip 'wme_ac_' or 'wmm_ac_' prefix */
822 pos = name + 7;
823 if (os_strncmp(pos, "be_", 3) == 0) {
824 num = 0;
825 pos += 3;
826 } else if (os_strncmp(pos, "bk_", 3) == 0) {
827 num = 1;
828 pos += 3;
829 } else if (os_strncmp(pos, "vi_", 3) == 0) {
830 num = 2;
831 pos += 3;
832 } else if (os_strncmp(pos, "vo_", 3) == 0) {
833 num = 3;
834 pos += 3;
835 } else {
836 wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos);
837 return -1;
838 }
839
840 ac = &conf->wmm_ac_params[num];
841
842 if (os_strcmp(pos, "aifs") == 0) {
843 v = atoi(val);
844 if (v < 1 || v > 255) {
845 wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v);
846 return -1;
847 }
848 ac->aifs = v;
849 } else if (os_strcmp(pos, "cwmin") == 0) {
850 v = atoi(val);
851 if (v < 0 || v > 12) {
852 wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v);
853 return -1;
854 }
855 ac->cwmin = v;
856 } else if (os_strcmp(pos, "cwmax") == 0) {
857 v = atoi(val);
858 if (v < 0 || v > 12) {
859 wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v);
860 return -1;
861 }
862 ac->cwmax = v;
863 } else if (os_strcmp(pos, "txop_limit") == 0) {
864 v = atoi(val);
865 if (v < 0 || v > 0xffff) {
866 wpa_printf(MSG_ERROR, "Invalid txop value %d", v);
867 return -1;
868 }
869 ac->txop_limit = v;
870 } else if (os_strcmp(pos, "acm") == 0) {
871 v = atoi(val);
872 if (v < 0 || v > 1) {
873 wpa_printf(MSG_ERROR, "Invalid acm value %d", v);
874 return -1;
875 }
876 ac->admission_control_mandatory = v;
877 } else {
878 wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos);
879 return -1;
880 }
881
882 return 0;
883}
884
885
886#ifdef CONFIG_IEEE80211R
887static int add_r0kh(struct hostapd_bss_config *bss, char *value)
888{
889 struct ft_remote_r0kh *r0kh;
890 char *pos, *next;
891
892 r0kh = os_zalloc(sizeof(*r0kh));
893 if (r0kh == NULL)
894 return -1;
895
896 /* 02:01:02:03:04:05 a.example.com 000102030405060708090a0b0c0d0e0f */
897 pos = value;
898 next = os_strchr(pos, ' ');
899 if (next)
900 *next++ = '\0';
901 if (next == NULL || hwaddr_aton(pos, r0kh->addr)) {
902 wpa_printf(MSG_ERROR, "Invalid R0KH MAC address: '%s'", pos);
903 os_free(r0kh);
904 return -1;
905 }
906
907 pos = next;
908 next = os_strchr(pos, ' ');
909 if (next)
910 *next++ = '\0';
911 if (next == NULL || next - pos > FT_R0KH_ID_MAX_LEN) {
912 wpa_printf(MSG_ERROR, "Invalid R0KH-ID: '%s'", pos);
913 os_free(r0kh);
914 return -1;
915 }
916 r0kh->id_len = next - pos - 1;
917 os_memcpy(r0kh->id, pos, r0kh->id_len);
918
919 pos = next;
920 if (hexstr2bin(pos, r0kh->key, sizeof(r0kh->key))) {
921 wpa_printf(MSG_ERROR, "Invalid R0KH key: '%s'", pos);
922 os_free(r0kh);
923 return -1;
924 }
925
926 r0kh->next = bss->r0kh_list;
927 bss->r0kh_list = r0kh;
928
929 return 0;
930}
931
932
933static int add_r1kh(struct hostapd_bss_config *bss, char *value)
934{
935 struct ft_remote_r1kh *r1kh;
936 char *pos, *next;
937
938 r1kh = os_zalloc(sizeof(*r1kh));
939 if (r1kh == NULL)
940 return -1;
941
942 /* 02:01:02:03:04:05 02:01:02:03:04:05
943 * 000102030405060708090a0b0c0d0e0f */
944 pos = value;
945 next = os_strchr(pos, ' ');
946 if (next)
947 *next++ = '\0';
948 if (next == NULL || hwaddr_aton(pos, r1kh->addr)) {
949 wpa_printf(MSG_ERROR, "Invalid R1KH MAC address: '%s'", pos);
950 os_free(r1kh);
951 return -1;
952 }
953
954 pos = next;
955 next = os_strchr(pos, ' ');
956 if (next)
957 *next++ = '\0';
958 if (next == NULL || hwaddr_aton(pos, r1kh->id)) {
959 wpa_printf(MSG_ERROR, "Invalid R1KH-ID: '%s'", pos);
960 os_free(r1kh);
961 return -1;
962 }
963
964 pos = next;
965 if (hexstr2bin(pos, r1kh->key, sizeof(r1kh->key))) {
966 wpa_printf(MSG_ERROR, "Invalid R1KH key: '%s'", pos);
967 os_free(r1kh);
968 return -1;
969 }
970
971 r1kh->next = bss->r1kh_list;
972 bss->r1kh_list = r1kh;
973
974 return 0;
975}
976#endif /* CONFIG_IEEE80211R */
977
978
979#ifdef CONFIG_IEEE80211N
980static int hostapd_config_ht_capab(struct hostapd_config *conf,
981 const char *capab)
982{
983 if (os_strstr(capab, "[LDPC]"))
984 conf->ht_capab |= HT_CAP_INFO_LDPC_CODING_CAP;
985 if (os_strstr(capab, "[HT40-]")) {
986 conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
987 conf->secondary_channel = -1;
988 }
989 if (os_strstr(capab, "[HT40+]")) {
990 conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
991 conf->secondary_channel = 1;
992 }
993 if (os_strstr(capab, "[SMPS-STATIC]")) {
994 conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK;
995 conf->ht_capab |= HT_CAP_INFO_SMPS_STATIC;
996 }
997 if (os_strstr(capab, "[SMPS-DYNAMIC]")) {
998 conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK;
999 conf->ht_capab |= HT_CAP_INFO_SMPS_DYNAMIC;
1000 }
1001 if (os_strstr(capab, "[GF]"))
1002 conf->ht_capab |= HT_CAP_INFO_GREEN_FIELD;
1003 if (os_strstr(capab, "[SHORT-GI-20]"))
1004 conf->ht_capab |= HT_CAP_INFO_SHORT_GI20MHZ;
1005 if (os_strstr(capab, "[SHORT-GI-40]"))
1006 conf->ht_capab |= HT_CAP_INFO_SHORT_GI40MHZ;
1007 if (os_strstr(capab, "[TX-STBC]"))
1008 conf->ht_capab |= HT_CAP_INFO_TX_STBC;
1009 if (os_strstr(capab, "[RX-STBC1]")) {
1010 conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK;
1011 conf->ht_capab |= HT_CAP_INFO_RX_STBC_1;
1012 }
1013 if (os_strstr(capab, "[RX-STBC12]")) {
1014 conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK;
1015 conf->ht_capab |= HT_CAP_INFO_RX_STBC_12;
1016 }
1017 if (os_strstr(capab, "[RX-STBC123]")) {
1018 conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK;
1019 conf->ht_capab |= HT_CAP_INFO_RX_STBC_123;
1020 }
1021 if (os_strstr(capab, "[DELAYED-BA]"))
1022 conf->ht_capab |= HT_CAP_INFO_DELAYED_BA;
1023 if (os_strstr(capab, "[MAX-AMSDU-7935]"))
1024 conf->ht_capab |= HT_CAP_INFO_MAX_AMSDU_SIZE;
1025 if (os_strstr(capab, "[DSSS_CCK-40]"))
1026 conf->ht_capab |= HT_CAP_INFO_DSSS_CCK40MHZ;
1027 if (os_strstr(capab, "[PSMP]"))
1028 conf->ht_capab |= HT_CAP_INFO_PSMP_SUPP;
1029 if (os_strstr(capab, "[LSIG-TXOP-PROT]"))
1030 conf->ht_capab |= HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT;
1031
1032 return 0;
1033}
1034#endif /* CONFIG_IEEE80211N */
1035
1036
1037static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
1038 struct hostapd_config *conf)
1039{
1040 if (bss->ieee802_1x && !bss->eap_server &&
1041 !bss->radius->auth_servers) {
1042 wpa_printf(MSG_ERROR, "Invalid IEEE 802.1X configuration (no "
1043 "EAP authenticator configured).");
1044 return -1;
1045 }
1046
05ab9712
MB
1047 if (bss->wpa && bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
1048 bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
1049 wpa_printf(MSG_ERROR, "WPA-PSK using RADIUS enabled, but no "
1050 "RADIUS checking (macaddr_acl=2) enabled.");
1051 return -1;
1052 }
1053
41d719d6
JM
1054 if (bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
1055 bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL &&
05ab9712
MB
1056 bss->ssid.wpa_psk_file == NULL &&
1057 (bss->wpa_psk_radius != PSK_RADIUS_REQUIRED ||
1058 bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH)) {
41d719d6
JM
1059 wpa_printf(MSG_ERROR, "WPA-PSK enabled, but PSK or passphrase "
1060 "is not configured.");
1061 return -1;
1062 }
1063
1064 if (hostapd_mac_comp_empty(bss->bssid) != 0) {
1065 size_t i;
1066
1067 for (i = 0; i < conf->num_bss; i++) {
1068 if ((&conf->bss[i] != bss) &&
1069 (hostapd_mac_comp(conf->bss[i].bssid,
1070 bss->bssid) == 0)) {
1071 wpa_printf(MSG_ERROR, "Duplicate BSSID " MACSTR
1072 " on interface '%s' and '%s'.",
1073 MAC2STR(bss->bssid),
1074 conf->bss[i].iface, bss->iface);
1075 return -1;
1076 }
1077 }
1078 }
1079
1080#ifdef CONFIG_IEEE80211R
0bf927a0 1081 if (wpa_key_mgmt_ft(bss->wpa_key_mgmt) &&
41d719d6
JM
1082 (bss->nas_identifier == NULL ||
1083 os_strlen(bss->nas_identifier) < 1 ||
1084 os_strlen(bss->nas_identifier) > FT_R0KH_ID_MAX_LEN)) {
1085 wpa_printf(MSG_ERROR, "FT (IEEE 802.11r) requires "
1086 "nas_identifier to be configured as a 1..48 octet "
1087 "string");
1088 return -1;
1089 }
1090#endif /* CONFIG_IEEE80211R */
1091
1092#ifdef CONFIG_IEEE80211N
6950b2ca
YAP
1093 if (conf->ieee80211n &&
1094 bss->ssid.security_policy == SECURITY_STATIC_WEP) {
f39b07d7 1095 bss->disable_11n = 1;
6950b2ca 1096 wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WEP is not "
f39b07d7 1097 "allowed, disabling HT capabilities");
6950b2ca
YAP
1098 }
1099
41d719d6
JM
1100 if (conf->ieee80211n && bss->wpa &&
1101 !(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
1102 !(bss->rsn_pairwise & WPA_CIPHER_CCMP)) {
f39b07d7 1103 bss->disable_11n = 1;
41d719d6 1104 wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 "
f39b07d7
HS
1105 "requires CCMP to be enabled, disabling HT "
1106 "capabilities");
41d719d6
JM
1107 }
1108#endif /* CONFIG_IEEE80211N */
1109
f61039c7
JM
1110#ifdef CONFIG_WPS2
1111 if (bss->wps_state && bss->ignore_broadcast_ssid) {
1112 wpa_printf(MSG_INFO, "WPS: ignore_broadcast_ssid "
1113 "configuration forced WPS to be disabled");
1114 bss->wps_state = 0;
1115 }
1116
1117 if (bss->wps_state && bss->ssid.wep.keys_set && bss->wpa == 0) {
1118 wpa_printf(MSG_INFO, "WPS: WEP configuration forced WPS to be "
1119 "disabled");
1120 bss->wps_state = 0;
1121 }
1122#endif /* CONFIG_WPS2 */
1123
41d719d6
JM
1124 return 0;
1125}
1126
1127
1128static int hostapd_config_check(struct hostapd_config *conf)
1129{
1130 size_t i;
1131
1132 if (conf->ieee80211d && (!conf->country[0] || !conf->country[1])) {
1133 wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11d without "
1134 "setting the country_code");
1135 return -1;
1136 }
1137
1138 for (i = 0; i < conf->num_bss; i++) {
1139 if (hostapd_config_check_bss(&conf->bss[i], conf))
1140 return -1;
1141 }
1142
1143 return 0;
1144}
1145
1146
4b2a77ab
JM
1147#ifdef CONFIG_INTERWORKING
1148static int parse_roaming_consortium(struct hostapd_bss_config *bss, char *pos,
1149 int line)
1150{
1151 size_t len = os_strlen(pos);
1152 u8 oi[MAX_ROAMING_CONSORTIUM_LEN];
1153
1154 struct hostapd_roaming_consortium *rc;
1155
1156 if ((len & 1) || len < 2 * 3 || len / 2 > MAX_ROAMING_CONSORTIUM_LEN ||
1157 hexstr2bin(pos, oi, len / 2)) {
1158 wpa_printf(MSG_ERROR, "Line %d: invalid roaming_consortium "
1159 "'%s'", line, pos);
1160 return -1;
1161 }
1162 len /= 2;
1163
1164 rc = os_realloc(bss->roaming_consortium,
1165 sizeof(struct hostapd_roaming_consortium) *
1166 (bss->roaming_consortium_count + 1));
1167 if (rc == NULL)
1168 return -1;
1169
1170 os_memcpy(rc[bss->roaming_consortium_count].oi, oi, len);
1171 rc[bss->roaming_consortium_count].len = len;
1172
1173 bss->roaming_consortium = rc;
1174 bss->roaming_consortium_count++;
1175
1176 return 0;
1177}
648cc711
JM
1178
1179
1180static int parse_venue_name(struct hostapd_bss_config *bss, char *pos,
1181 int line)
1182{
1183 char *sep;
1184 size_t clen, nlen;
1185 struct hostapd_venue_name *vn;
1186
1187 sep = os_strchr(pos, ':');
1188 if (sep == NULL)
1189 goto fail;
1190 *sep++ = '\0';
1191
1192 clen = os_strlen(pos);
1193 if (clen < 2)
1194 goto fail;
1195 nlen = os_strlen(sep);
1196 if (nlen > 252)
1197 goto fail;
1198
1199 vn = os_realloc(bss->venue_name,
1200 sizeof(struct hostapd_venue_name) *
1201 (bss->venue_name_count + 1));
1202 if (vn == NULL)
1203 return -1;
1204
1205 bss->venue_name = vn;
1206 vn = &bss->venue_name[bss->venue_name_count];
1207 bss->venue_name_count++;
1208
1209 os_memset(vn->lang, 0, sizeof(vn->lang));
1210 os_memcpy(vn->lang, pos, clen);
1211 vn->name_len = nlen;
1212 os_memcpy(vn->name, sep, nlen);
1213
1214 return 0;
1215
1216fail:
1217 wpa_printf(MSG_ERROR, "Line %d: Invalid venue_name '%s'",
1218 line, pos);
1219 return -1;
1220}
4b2a77ab
JM
1221#endif /* CONFIG_INTERWORKING */
1222
1223
ef45bc89
SP
1224static int hostapd_config_fill(struct hostapd_config *conf,
1225 struct hostapd_bss_config *bss,
1226 char *buf, char *pos, int line)
41d719d6 1227{
41d719d6 1228 int errors = 0;
41d719d6 1229
ef45bc89 1230 {
41d719d6
JM
1231 if (os_strcmp(buf, "interface") == 0) {
1232 os_strlcpy(conf->bss[0].iface, pos,
1233 sizeof(conf->bss[0].iface));
1234 } else if (os_strcmp(buf, "bridge") == 0) {
1235 os_strlcpy(bss->bridge, pos, sizeof(bss->bridge));
d38ae2ea
FF
1236 } else if (os_strcmp(buf, "wds_bridge") == 0) {
1237 os_strlcpy(bss->wds_bridge, pos,
1238 sizeof(bss->wds_bridge));
41d719d6
JM
1239 } else if (os_strcmp(buf, "driver") == 0) {
1240 int j;
1241 /* clear to get error below if setting is invalid */
1242 conf->driver = NULL;
1243 for (j = 0; wpa_drivers[j]; j++) {
1244 if (os_strcmp(pos, wpa_drivers[j]->name) == 0)
1245 {
1246 conf->driver = wpa_drivers[j];
1247 break;
1248 }
1249 }
1250 if (conf->driver == NULL) {
1251 wpa_printf(MSG_ERROR, "Line %d: invalid/"
1252 "unknown driver '%s'", line, pos);
1253 errors++;
1254 }
1255 } else if (os_strcmp(buf, "debug") == 0) {
1256 wpa_printf(MSG_DEBUG, "Line %d: DEPRECATED: 'debug' "
1257 "configuration variable is not used "
1258 "anymore", line);
1259 } else if (os_strcmp(buf, "logger_syslog_level") == 0) {
1260 bss->logger_syslog_level = atoi(pos);
1261 } else if (os_strcmp(buf, "logger_stdout_level") == 0) {
1262 bss->logger_stdout_level = atoi(pos);
1263 } else if (os_strcmp(buf, "logger_syslog") == 0) {
1264 bss->logger_syslog = atoi(pos);
1265 } else if (os_strcmp(buf, "logger_stdout") == 0) {
1266 bss->logger_stdout = atoi(pos);
1267 } else if (os_strcmp(buf, "dump_file") == 0) {
1268 bss->dump_log_name = os_strdup(pos);
1269 } else if (os_strcmp(buf, "ssid") == 0) {
1270 bss->ssid.ssid_len = os_strlen(pos);
1271 if (bss->ssid.ssid_len > HOSTAPD_MAX_SSID_LEN ||
1272 bss->ssid.ssid_len < 1) {
1273 wpa_printf(MSG_ERROR, "Line %d: invalid SSID "
1274 "'%s'", line, pos);
1275 errors++;
1276 } else {
1277 os_memcpy(bss->ssid.ssid, pos,
1278 bss->ssid.ssid_len);
1279 bss->ssid.ssid[bss->ssid.ssid_len] = '\0';
1280 bss->ssid.ssid_set = 1;
1281 }
1282 } else if (os_strcmp(buf, "macaddr_acl") == 0) {
1283 bss->macaddr_acl = atoi(pos);
1284 if (bss->macaddr_acl != ACCEPT_UNLESS_DENIED &&
1285 bss->macaddr_acl != DENY_UNLESS_ACCEPTED &&
1286 bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
1287 wpa_printf(MSG_ERROR, "Line %d: unknown "
1288 "macaddr_acl %d",
1289 line, bss->macaddr_acl);
1290 }
1291 } else if (os_strcmp(buf, "accept_mac_file") == 0) {
1292 if (hostapd_config_read_maclist(pos, &bss->accept_mac,
1293 &bss->num_accept_mac))
1294 {
1295 wpa_printf(MSG_ERROR, "Line %d: Failed to "
1296 "read accept_mac_file '%s'",
1297 line, pos);
1298 errors++;
1299 }
1300 } else if (os_strcmp(buf, "deny_mac_file") == 0) {
1301 if (hostapd_config_read_maclist(pos, &bss->deny_mac,
1302 &bss->num_deny_mac)) {
1303 wpa_printf(MSG_ERROR, "Line %d: Failed to "
1304 "read deny_mac_file '%s'",
1305 line, pos);
1306 errors++;
1307 }
1308 } else if (os_strcmp(buf, "wds_sta") == 0) {
1309 bss->wds_sta = atoi(pos);
d3b42869
FF
1310 } else if (os_strcmp(buf, "ap_isolate") == 0) {
1311 bss->isolate = atoi(pos);
41d719d6
JM
1312 } else if (os_strcmp(buf, "ap_max_inactivity") == 0) {
1313 bss->ap_max_inactivity = atoi(pos);
ef01fa7b
YAP
1314 } else if (os_strcmp(buf, "skip_inactivity_poll") == 0) {
1315 bss->skip_inactivity_poll = atoi(pos);
41d719d6
JM
1316 } else if (os_strcmp(buf, "country_code") == 0) {
1317 os_memcpy(conf->country, pos, 2);
1318 /* FIX: make this configurable */
1319 conf->country[2] = ' ';
1320 } else if (os_strcmp(buf, "ieee80211d") == 0) {
1321 conf->ieee80211d = atoi(pos);
1322 } else if (os_strcmp(buf, "ieee8021x") == 0) {
1323 bss->ieee802_1x = atoi(pos);
1324 } else if (os_strcmp(buf, "eapol_version") == 0) {
1325 bss->eapol_version = atoi(pos);
1326 if (bss->eapol_version < 1 ||
1327 bss->eapol_version > 2) {
1328 wpa_printf(MSG_ERROR, "Line %d: invalid EAPOL "
1329 "version (%d): '%s'.",
1330 line, bss->eapol_version, pos);
1331 errors++;
1332 } else
1333 wpa_printf(MSG_DEBUG, "eapol_version=%d",
1334 bss->eapol_version);
1335#ifdef EAP_SERVER
1336 } else if (os_strcmp(buf, "eap_authenticator") == 0) {
1337 bss->eap_server = atoi(pos);
1338 wpa_printf(MSG_ERROR, "Line %d: obsolete "
1339 "eap_authenticator used; this has been "
1340 "renamed to eap_server", line);
1341 } else if (os_strcmp(buf, "eap_server") == 0) {
1342 bss->eap_server = atoi(pos);
1343 } else if (os_strcmp(buf, "eap_user_file") == 0) {
1344 if (hostapd_config_read_eap_user(pos, bss))
1345 errors++;
1346 } else if (os_strcmp(buf, "ca_cert") == 0) {
1347 os_free(bss->ca_cert);
1348 bss->ca_cert = os_strdup(pos);
1349 } else if (os_strcmp(buf, "server_cert") == 0) {
1350 os_free(bss->server_cert);
1351 bss->server_cert = os_strdup(pos);
1352 } else if (os_strcmp(buf, "private_key") == 0) {
1353 os_free(bss->private_key);
1354 bss->private_key = os_strdup(pos);
1355 } else if (os_strcmp(buf, "private_key_passwd") == 0) {
1356 os_free(bss->private_key_passwd);
1357 bss->private_key_passwd = os_strdup(pos);
1358 } else if (os_strcmp(buf, "check_crl") == 0) {
1359 bss->check_crl = atoi(pos);
1360 } else if (os_strcmp(buf, "dh_file") == 0) {
1361 os_free(bss->dh_file);
1362 bss->dh_file = os_strdup(pos);
7f6ec672
JM
1363 } else if (os_strcmp(buf, "fragment_size") == 0) {
1364 bss->fragment_size = atoi(pos);
41d719d6
JM
1365#ifdef EAP_SERVER_FAST
1366 } else if (os_strcmp(buf, "pac_opaque_encr_key") == 0) {
1367 os_free(bss->pac_opaque_encr_key);
1368 bss->pac_opaque_encr_key = os_malloc(16);
1369 if (bss->pac_opaque_encr_key == NULL) {
1370 wpa_printf(MSG_ERROR, "Line %d: No memory for "
1371 "pac_opaque_encr_key", line);
1372 errors++;
1373 } else if (hexstr2bin(pos, bss->pac_opaque_encr_key,
1374 16)) {
1375 wpa_printf(MSG_ERROR, "Line %d: Invalid "
1376 "pac_opaque_encr_key", line);
1377 errors++;
1378 }
1379 } else if (os_strcmp(buf, "eap_fast_a_id") == 0) {
1380 size_t idlen = os_strlen(pos);
1381 if (idlen & 1) {
1382 wpa_printf(MSG_ERROR, "Line %d: Invalid "
1383 "eap_fast_a_id", line);
1384 errors++;
1385 } else {
1386 os_free(bss->eap_fast_a_id);
1387 bss->eap_fast_a_id = os_malloc(idlen / 2);
1388 if (bss->eap_fast_a_id == NULL ||
1389 hexstr2bin(pos, bss->eap_fast_a_id,
1390 idlen / 2)) {
1391 wpa_printf(MSG_ERROR, "Line %d: "
1392 "Failed to parse "
1393 "eap_fast_a_id", line);
1394 errors++;
1395 } else
1396 bss->eap_fast_a_id_len = idlen / 2;
1397 }
1398 } else if (os_strcmp(buf, "eap_fast_a_id_info") == 0) {
1399 os_free(bss->eap_fast_a_id_info);
1400 bss->eap_fast_a_id_info = os_strdup(pos);
1401 } else if (os_strcmp(buf, "eap_fast_prov") == 0) {
1402 bss->eap_fast_prov = atoi(pos);
1403 } else if (os_strcmp(buf, "pac_key_lifetime") == 0) {
1404 bss->pac_key_lifetime = atoi(pos);
1405 } else if (os_strcmp(buf, "pac_key_refresh_time") == 0) {
1406 bss->pac_key_refresh_time = atoi(pos);
1407#endif /* EAP_SERVER_FAST */
1408#ifdef EAP_SERVER_SIM
1409 } else if (os_strcmp(buf, "eap_sim_db") == 0) {
1410 os_free(bss->eap_sim_db);
1411 bss->eap_sim_db = os_strdup(pos);
1412 } else if (os_strcmp(buf, "eap_sim_aka_result_ind") == 0) {
1413 bss->eap_sim_aka_result_ind = atoi(pos);
1414#endif /* EAP_SERVER_SIM */
1415#ifdef EAP_SERVER_TNC
1416 } else if (os_strcmp(buf, "tnc") == 0) {
1417 bss->tnc = atoi(pos);
1418#endif /* EAP_SERVER_TNC */
df684d82
DH
1419#ifdef EAP_SERVER_PWD
1420 } else if (os_strcmp(buf, "pwd_group") == 0) {
1421 bss->pwd_group = atoi(pos);
1422#endif /* EAP_SERVER_PWD */
41d719d6
JM
1423#endif /* EAP_SERVER */
1424 } else if (os_strcmp(buf, "eap_message") == 0) {
1425 char *term;
1426 bss->eap_req_id_text = os_strdup(pos);
1427 if (bss->eap_req_id_text == NULL) {
1428 wpa_printf(MSG_ERROR, "Line %d: Failed to "
1429 "allocate memory for "
1430 "eap_req_id_text", line);
1431 errors++;
ef45bc89 1432 return errors;
41d719d6
JM
1433 }
1434 bss->eap_req_id_text_len =
1435 os_strlen(bss->eap_req_id_text);
1436 term = os_strstr(bss->eap_req_id_text, "\\0");
1437 if (term) {
1438 *term++ = '\0';
1439 os_memmove(term, term + 1,
1440 bss->eap_req_id_text_len -
1441 (term - bss->eap_req_id_text) - 1);
1442 bss->eap_req_id_text_len--;
1443 }
1444 } else if (os_strcmp(buf, "wep_key_len_broadcast") == 0) {
1445 bss->default_wep_key_len = atoi(pos);
1446 if (bss->default_wep_key_len > 13) {
1447 wpa_printf(MSG_ERROR, "Line %d: invalid WEP "
1448 "key len %lu (= %lu bits)", line,
1449 (unsigned long)
1450 bss->default_wep_key_len,
1451 (unsigned long)
1452 bss->default_wep_key_len * 8);
1453 errors++;
1454 }
1455 } else if (os_strcmp(buf, "wep_key_len_unicast") == 0) {
1456 bss->individual_wep_key_len = atoi(pos);
1457 if (bss->individual_wep_key_len < 0 ||
1458 bss->individual_wep_key_len > 13) {
1459 wpa_printf(MSG_ERROR, "Line %d: invalid WEP "
1460 "key len %d (= %d bits)", line,
1461 bss->individual_wep_key_len,
1462 bss->individual_wep_key_len * 8);
1463 errors++;
1464 }
1465 } else if (os_strcmp(buf, "wep_rekey_period") == 0) {
1466 bss->wep_rekeying_period = atoi(pos);
1467 if (bss->wep_rekeying_period < 0) {
1468 wpa_printf(MSG_ERROR, "Line %d: invalid "
1469 "period %d",
1470 line, bss->wep_rekeying_period);
1471 errors++;
1472 }
1473 } else if (os_strcmp(buf, "eap_reauth_period") == 0) {
1474 bss->eap_reauth_period = atoi(pos);
1475 if (bss->eap_reauth_period < 0) {
1476 wpa_printf(MSG_ERROR, "Line %d: invalid "
1477 "period %d",
1478 line, bss->eap_reauth_period);
1479 errors++;
1480 }
1481 } else if (os_strcmp(buf, "eapol_key_index_workaround") == 0) {
1482 bss->eapol_key_index_workaround = atoi(pos);
1483#ifdef CONFIG_IAPP
1484 } else if (os_strcmp(buf, "iapp_interface") == 0) {
1485 bss->ieee802_11f = 1;
1486 os_strlcpy(bss->iapp_iface, pos,
1487 sizeof(bss->iapp_iface));
1488#endif /* CONFIG_IAPP */
1489 } else if (os_strcmp(buf, "own_ip_addr") == 0) {
1490 if (hostapd_parse_ip_addr(pos, &bss->own_ip_addr)) {
1491 wpa_printf(MSG_ERROR, "Line %d: invalid IP "
1492 "address '%s'", line, pos);
1493 errors++;
1494 }
1495 } else if (os_strcmp(buf, "nas_identifier") == 0) {
1496 bss->nas_identifier = os_strdup(pos);
1497#ifndef CONFIG_NO_RADIUS
1498 } else if (os_strcmp(buf, "auth_server_addr") == 0) {
1499 if (hostapd_config_read_radius_addr(
1500 &bss->radius->auth_servers,
1501 &bss->radius->num_auth_servers, pos, 1812,
1502 &bss->radius->auth_server)) {
1503 wpa_printf(MSG_ERROR, "Line %d: invalid IP "
1504 "address '%s'", line, pos);
1505 errors++;
1506 }
1507 } else if (bss->radius->auth_server &&
1508 os_strcmp(buf, "auth_server_port") == 0) {
1509 bss->radius->auth_server->port = atoi(pos);
1510 } else if (bss->radius->auth_server &&
1511 os_strcmp(buf, "auth_server_shared_secret") == 0) {
1512 int len = os_strlen(pos);
1513 if (len == 0) {
1514 /* RFC 2865, Ch. 3 */
1515 wpa_printf(MSG_ERROR, "Line %d: empty shared "
1516 "secret is not allowed.", line);
1517 errors++;
1518 }
1519 bss->radius->auth_server->shared_secret =
1520 (u8 *) os_strdup(pos);
1521 bss->radius->auth_server->shared_secret_len = len;
1522 } else if (os_strcmp(buf, "acct_server_addr") == 0) {
1523 if (hostapd_config_read_radius_addr(
1524 &bss->radius->acct_servers,
1525 &bss->radius->num_acct_servers, pos, 1813,
1526 &bss->radius->acct_server)) {
1527 wpa_printf(MSG_ERROR, "Line %d: invalid IP "
1528 "address '%s'", line, pos);
1529 errors++;
1530 }
1531 } else if (bss->radius->acct_server &&
1532 os_strcmp(buf, "acct_server_port") == 0) {
1533 bss->radius->acct_server->port = atoi(pos);
1534 } else if (bss->radius->acct_server &&
1535 os_strcmp(buf, "acct_server_shared_secret") == 0) {
1536 int len = os_strlen(pos);
1537 if (len == 0) {
1538 /* RFC 2865, Ch. 3 */
1539 wpa_printf(MSG_ERROR, "Line %d: empty shared "
1540 "secret is not allowed.", line);
1541 errors++;
1542 }
1543 bss->radius->acct_server->shared_secret =
1544 (u8 *) os_strdup(pos);
1545 bss->radius->acct_server->shared_secret_len = len;
1546 } else if (os_strcmp(buf, "radius_retry_primary_interval") ==
1547 0) {
1548 bss->radius->retry_primary_interval = atoi(pos);
1549 } else if (os_strcmp(buf, "radius_acct_interim_interval") == 0)
1550 {
1551 bss->acct_interim_interval = atoi(pos);
1552#endif /* CONFIG_NO_RADIUS */
1553 } else if (os_strcmp(buf, "auth_algs") == 0) {
1554 bss->auth_algs = atoi(pos);
1555 if (bss->auth_algs == 0) {
1556 wpa_printf(MSG_ERROR, "Line %d: no "
1557 "authentication algorithms allowed",
1558 line);
1559 errors++;
1560 }
1561 } else if (os_strcmp(buf, "max_num_sta") == 0) {
1562 bss->max_num_sta = atoi(pos);
1563 if (bss->max_num_sta < 0 ||
1564 bss->max_num_sta > MAX_STA_COUNT) {
1565 wpa_printf(MSG_ERROR, "Line %d: Invalid "
1566 "max_num_sta=%d; allowed range "
1567 "0..%d", line, bss->max_num_sta,
1568 MAX_STA_COUNT);
1569 errors++;
1570 }
1571 } else if (os_strcmp(buf, "wpa") == 0) {
1572 bss->wpa = atoi(pos);
1573 } else if (os_strcmp(buf, "wpa_group_rekey") == 0) {
1574 bss->wpa_group_rekey = atoi(pos);
1575 } else if (os_strcmp(buf, "wpa_strict_rekey") == 0) {
1576 bss->wpa_strict_rekey = atoi(pos);
1577 } else if (os_strcmp(buf, "wpa_gmk_rekey") == 0) {
1578 bss->wpa_gmk_rekey = atoi(pos);
1579 } else if (os_strcmp(buf, "wpa_ptk_rekey") == 0) {
1580 bss->wpa_ptk_rekey = atoi(pos);
1581 } else if (os_strcmp(buf, "wpa_passphrase") == 0) {
1582 int len = os_strlen(pos);
1583 if (len < 8 || len > 63) {
1584 wpa_printf(MSG_ERROR, "Line %d: invalid WPA "
1585 "passphrase length %d (expected "
1586 "8..63)", line, len);
1587 errors++;
1588 } else {
1589 os_free(bss->ssid.wpa_passphrase);
1590 bss->ssid.wpa_passphrase = os_strdup(pos);
31b540eb
SP
1591 os_free(bss->ssid.wpa_psk);
1592 bss->ssid.wpa_psk = NULL;
41d719d6
JM
1593 }
1594 } else if (os_strcmp(buf, "wpa_psk") == 0) {
1595 os_free(bss->ssid.wpa_psk);
1596 bss->ssid.wpa_psk =
1597 os_zalloc(sizeof(struct hostapd_wpa_psk));
1598 if (bss->ssid.wpa_psk == NULL)
1599 errors++;
1600 else if (hexstr2bin(pos, bss->ssid.wpa_psk->psk,
1601 PMK_LEN) ||
1602 pos[PMK_LEN * 2] != '\0') {
1603 wpa_printf(MSG_ERROR, "Line %d: Invalid PSK "
1604 "'%s'.", line, pos);
1605 errors++;
1606 } else {
1607 bss->ssid.wpa_psk->group = 1;
31b540eb
SP
1608 os_free(bss->ssid.wpa_passphrase);
1609 bss->ssid.wpa_passphrase = NULL;
41d719d6
JM
1610 }
1611 } else if (os_strcmp(buf, "wpa_psk_file") == 0) {
1612 os_free(bss->ssid.wpa_psk_file);
1613 bss->ssid.wpa_psk_file = os_strdup(pos);
1614 if (!bss->ssid.wpa_psk_file) {
1615 wpa_printf(MSG_ERROR, "Line %d: allocation "
1616 "failed", line);
1617 errors++;
1618 }
1619 } else if (os_strcmp(buf, "wpa_key_mgmt") == 0) {
1620 bss->wpa_key_mgmt =
1621 hostapd_config_parse_key_mgmt(line, pos);
1622 if (bss->wpa_key_mgmt == -1)
1623 errors++;
05ab9712
MB
1624 } else if (os_strcmp(buf, "wpa_psk_radius") == 0) {
1625 bss->wpa_psk_radius = atoi(pos);
1626 if (bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
1627 bss->wpa_psk_radius != PSK_RADIUS_ACCEPTED &&
1628 bss->wpa_psk_radius != PSK_RADIUS_REQUIRED) {
1629 wpa_printf(MSG_ERROR, "Line %d: unknown "
1630 "wpa_psk_radius %d",
1631 line, bss->wpa_psk_radius);
1632 errors++;
1633 }
41d719d6
JM
1634 } else if (os_strcmp(buf, "wpa_pairwise") == 0) {
1635 bss->wpa_pairwise =
1636 hostapd_config_parse_cipher(line, pos);
1637 if (bss->wpa_pairwise == -1 ||
1638 bss->wpa_pairwise == 0)
1639 errors++;
1640 else if (bss->wpa_pairwise &
1641 (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 |
1642 WPA_CIPHER_WEP104)) {
1643 wpa_printf(MSG_ERROR, "Line %d: unsupported "
1644 "pairwise cipher suite '%s'",
1645 bss->wpa_pairwise, pos);
1646 errors++;
1647 }
1648 } else if (os_strcmp(buf, "rsn_pairwise") == 0) {
1649 bss->rsn_pairwise =
1650 hostapd_config_parse_cipher(line, pos);
1651 if (bss->rsn_pairwise == -1 ||
1652 bss->rsn_pairwise == 0)
1653 errors++;
1654 else if (bss->rsn_pairwise &
1655 (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 |
1656 WPA_CIPHER_WEP104)) {
1657 wpa_printf(MSG_ERROR, "Line %d: unsupported "
1658 "pairwise cipher suite '%s'",
1659 bss->rsn_pairwise, pos);
1660 errors++;
1661 }
1662#ifdef CONFIG_RSN_PREAUTH
1663 } else if (os_strcmp(buf, "rsn_preauth") == 0) {
1664 bss->rsn_preauth = atoi(pos);
1665 } else if (os_strcmp(buf, "rsn_preauth_interfaces") == 0) {
1666 bss->rsn_preauth_interfaces = os_strdup(pos);
1667#endif /* CONFIG_RSN_PREAUTH */
1668#ifdef CONFIG_PEERKEY
1669 } else if (os_strcmp(buf, "peerkey") == 0) {
1670 bss->peerkey = atoi(pos);
1671#endif /* CONFIG_PEERKEY */
1672#ifdef CONFIG_IEEE80211R
1673 } else if (os_strcmp(buf, "mobility_domain") == 0) {
1674 if (os_strlen(pos) != 2 * MOBILITY_DOMAIN_ID_LEN ||
1675 hexstr2bin(pos, bss->mobility_domain,
1676 MOBILITY_DOMAIN_ID_LEN) != 0) {
1677 wpa_printf(MSG_DEBUG, "Line %d: Invalid "
1678 "mobility_domain '%s'", line, pos);
1679 errors++;
ef45bc89 1680 return errors;
41d719d6
JM
1681 }
1682 } else if (os_strcmp(buf, "r1_key_holder") == 0) {
1683 if (os_strlen(pos) != 2 * FT_R1KH_ID_LEN ||
1684 hexstr2bin(pos, bss->r1_key_holder,
1685 FT_R1KH_ID_LEN) != 0) {
1686 wpa_printf(MSG_DEBUG, "Line %d: Invalid "
1687 "r1_key_holder '%s'", line, pos);
1688 errors++;
ef45bc89 1689 return errors;
41d719d6
JM
1690 }
1691 } else if (os_strcmp(buf, "r0_key_lifetime") == 0) {
1692 bss->r0_key_lifetime = atoi(pos);
1693 } else if (os_strcmp(buf, "reassociation_deadline") == 0) {
1694 bss->reassociation_deadline = atoi(pos);
1695 } else if (os_strcmp(buf, "r0kh") == 0) {
1696 if (add_r0kh(bss, pos) < 0) {
1697 wpa_printf(MSG_DEBUG, "Line %d: Invalid "
1698 "r0kh '%s'", line, pos);
1699 errors++;
ef45bc89 1700 return errors;
41d719d6
JM
1701 }
1702 } else if (os_strcmp(buf, "r1kh") == 0) {
1703 if (add_r1kh(bss, pos) < 0) {
1704 wpa_printf(MSG_DEBUG, "Line %d: Invalid "
1705 "r1kh '%s'", line, pos);
1706 errors++;
ef45bc89 1707 return errors;
41d719d6
JM
1708 }
1709 } else if (os_strcmp(buf, "pmk_r1_push") == 0) {
1710 bss->pmk_r1_push = atoi(pos);
d7956add
SP
1711 } else if (os_strcmp(buf, "ft_over_ds") == 0) {
1712 bss->ft_over_ds = atoi(pos);
41d719d6
JM
1713#endif /* CONFIG_IEEE80211R */
1714#ifndef CONFIG_NO_CTRL_IFACE
1715 } else if (os_strcmp(buf, "ctrl_interface") == 0) {
1716 os_free(bss->ctrl_interface);
1717 bss->ctrl_interface = os_strdup(pos);
1718 } else if (os_strcmp(buf, "ctrl_interface_group") == 0) {
1719#ifndef CONFIG_NATIVE_WINDOWS
1720 struct group *grp;
1721 char *endp;
1722 const char *group = pos;
1723
1724 grp = getgrnam(group);
1725 if (grp) {
1726 bss->ctrl_interface_gid = grp->gr_gid;
1727 bss->ctrl_interface_gid_set = 1;
1728 wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
1729 " (from group name '%s')",
1730 bss->ctrl_interface_gid, group);
ef45bc89 1731 return errors;
41d719d6
JM
1732 }
1733
1734 /* Group name not found - try to parse this as gid */
1735 bss->ctrl_interface_gid = strtol(group, &endp, 10);
1736 if (*group == '\0' || *endp != '\0') {
1737 wpa_printf(MSG_DEBUG, "Line %d: Invalid group "
1738 "'%s'", line, group);
1739 errors++;
ef45bc89 1740 return errors;
41d719d6
JM
1741 }
1742 bss->ctrl_interface_gid_set = 1;
1743 wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
1744 bss->ctrl_interface_gid);
1745#endif /* CONFIG_NATIVE_WINDOWS */
1746#endif /* CONFIG_NO_CTRL_IFACE */
1747#ifdef RADIUS_SERVER
1748 } else if (os_strcmp(buf, "radius_server_clients") == 0) {
1749 os_free(bss->radius_server_clients);
1750 bss->radius_server_clients = os_strdup(pos);
1751 } else if (os_strcmp(buf, "radius_server_auth_port") == 0) {
1752 bss->radius_server_auth_port = atoi(pos);
1753 } else if (os_strcmp(buf, "radius_server_ipv6") == 0) {
1754 bss->radius_server_ipv6 = atoi(pos);
1755#endif /* RADIUS_SERVER */
1756 } else if (os_strcmp(buf, "test_socket") == 0) {
1757 os_free(bss->test_socket);
1758 bss->test_socket = os_strdup(pos);
1759 } else if (os_strcmp(buf, "use_pae_group_addr") == 0) {
1760 bss->use_pae_group_addr = atoi(pos);
1761 } else if (os_strcmp(buf, "hw_mode") == 0) {
1762 if (os_strcmp(pos, "a") == 0)
1763 conf->hw_mode = HOSTAPD_MODE_IEEE80211A;
1764 else if (os_strcmp(pos, "b") == 0)
1765 conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
1766 else if (os_strcmp(pos, "g") == 0)
1767 conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
1768 else {
1769 wpa_printf(MSG_ERROR, "Line %d: unknown "
1770 "hw_mode '%s'", line, pos);
1771 errors++;
1772 }
8e5f9134
BC
1773 } else if (os_strcmp(buf, "wps_rf_bands") == 0) {
1774 if (os_strcmp(pos, "a") == 0)
1775 bss->wps_rf_bands = WPS_RF_50GHZ;
1776 else if (os_strcmp(pos, "g") == 0 ||
1777 os_strcmp(pos, "b") == 0)
1778 bss->wps_rf_bands = WPS_RF_24GHZ;
1779 else if (os_strcmp(pos, "ag") == 0 ||
1780 os_strcmp(pos, "ga") == 0)
1781 bss->wps_rf_bands =
1782 WPS_RF_24GHZ | WPS_RF_50GHZ;
1783 else {
1784 wpa_printf(MSG_ERROR, "Line %d: unknown "
1785 "wps_rf_band '%s'", line, pos);
1786 errors++;
1787 }
41d719d6
JM
1788 } else if (os_strcmp(buf, "channel") == 0) {
1789 conf->channel = atoi(pos);
1790 } else if (os_strcmp(buf, "beacon_int") == 0) {
1791 int val = atoi(pos);
1792 /* MIB defines range as 1..65535, but very small values
1793 * cause problems with the current implementation.
1794 * Since it is unlikely that this small numbers are
1795 * useful in real life scenarios, do not allow beacon
1796 * period to be set below 15 TU. */
1797 if (val < 15 || val > 65535) {
1798 wpa_printf(MSG_ERROR, "Line %d: invalid "
1799 "beacon_int %d (expected "
1800 "15..65535)", line, val);
1801 errors++;
1802 } else
1803 conf->beacon_int = val;
1804 } else if (os_strcmp(buf, "dtim_period") == 0) {
1805 bss->dtim_period = atoi(pos);
1806 if (bss->dtim_period < 1 || bss->dtim_period > 255) {
1807 wpa_printf(MSG_ERROR, "Line %d: invalid "
1808 "dtim_period %d",
1809 line, bss->dtim_period);
1810 errors++;
1811 }
1812 } else if (os_strcmp(buf, "rts_threshold") == 0) {
1813 conf->rts_threshold = atoi(pos);
1814 if (conf->rts_threshold < 0 ||
1815 conf->rts_threshold > 2347) {
1816 wpa_printf(MSG_ERROR, "Line %d: invalid "
1817 "rts_threshold %d",
1818 line, conf->rts_threshold);
1819 errors++;
1820 }
1821 } else if (os_strcmp(buf, "fragm_threshold") == 0) {
1822 conf->fragm_threshold = atoi(pos);
1823 if (conf->fragm_threshold < 256 ||
1824 conf->fragm_threshold > 2346) {
1825 wpa_printf(MSG_ERROR, "Line %d: invalid "
1826 "fragm_threshold %d",
1827 line, conf->fragm_threshold);
1828 errors++;
1829 }
1830 } else if (os_strcmp(buf, "send_probe_response") == 0) {
1831 int val = atoi(pos);
1832 if (val != 0 && val != 1) {
1833 wpa_printf(MSG_ERROR, "Line %d: invalid "
1834 "send_probe_response %d (expected "
1835 "0 or 1)", line, val);
1836 } else
1837 conf->send_probe_response = val;
1838 } else if (os_strcmp(buf, "supported_rates") == 0) {
1839 if (hostapd_parse_rates(&conf->supported_rates, pos)) {
1840 wpa_printf(MSG_ERROR, "Line %d: invalid rate "
1841 "list", line);
1842 errors++;
1843 }
1844 } else if (os_strcmp(buf, "basic_rates") == 0) {
1845 if (hostapd_parse_rates(&conf->basic_rates, pos)) {
1846 wpa_printf(MSG_ERROR, "Line %d: invalid rate "
1847 "list", line);
1848 errors++;
1849 }
1850 } else if (os_strcmp(buf, "preamble") == 0) {
1851 if (atoi(pos))
1852 conf->preamble = SHORT_PREAMBLE;
1853 else
1854 conf->preamble = LONG_PREAMBLE;
1855 } else if (os_strcmp(buf, "ignore_broadcast_ssid") == 0) {
1856 bss->ignore_broadcast_ssid = atoi(pos);
1857 } else if (os_strcmp(buf, "wep_default_key") == 0) {
1858 bss->ssid.wep.idx = atoi(pos);
1859 if (bss->ssid.wep.idx > 3) {
1860 wpa_printf(MSG_ERROR, "Invalid "
1861 "wep_default_key index %d",
1862 bss->ssid.wep.idx);
1863 errors++;
1864 }
1865 } else if (os_strcmp(buf, "wep_key0") == 0 ||
1866 os_strcmp(buf, "wep_key1") == 0 ||
1867 os_strcmp(buf, "wep_key2") == 0 ||
1868 os_strcmp(buf, "wep_key3") == 0) {
1869 if (hostapd_config_read_wep(&bss->ssid.wep,
1870 buf[7] - '0', pos)) {
1871 wpa_printf(MSG_ERROR, "Line %d: invalid WEP "
1872 "key '%s'", line, buf);
1873 errors++;
1874 }
1875#ifndef CONFIG_NO_VLAN
1876 } else if (os_strcmp(buf, "dynamic_vlan") == 0) {
1877 bss->ssid.dynamic_vlan = atoi(pos);
1878 } else if (os_strcmp(buf, "vlan_file") == 0) {
1879 if (hostapd_config_read_vlan_file(bss, pos)) {
1880 wpa_printf(MSG_ERROR, "Line %d: failed to "
1881 "read VLAN file '%s'", line, pos);
1882 errors++;
1883 }
1884#ifdef CONFIG_FULL_DYNAMIC_VLAN
1885 } else if (os_strcmp(buf, "vlan_tagged_interface") == 0) {
1886 bss->ssid.vlan_tagged_interface = os_strdup(pos);
1887#endif /* CONFIG_FULL_DYNAMIC_VLAN */
1888#endif /* CONFIG_NO_VLAN */
1889 } else if (os_strcmp(buf, "ap_table_max_size") == 0) {
1890 conf->ap_table_max_size = atoi(pos);
1891 } else if (os_strcmp(buf, "ap_table_expiration_time") == 0) {
1892 conf->ap_table_expiration_time = atoi(pos);
1893 } else if (os_strncmp(buf, "tx_queue_", 9) == 0) {
1894 if (hostapd_config_tx_queue(conf, buf, pos)) {
1895 wpa_printf(MSG_ERROR, "Line %d: invalid TX "
1896 "queue item", line);
1897 errors++;
1898 }
1899 } else if (os_strcmp(buf, "wme_enabled") == 0 ||
1900 os_strcmp(buf, "wmm_enabled") == 0) {
1901 bss->wmm_enabled = atoi(pos);
721abef9
YAP
1902 } else if (os_strcmp(buf, "uapsd_advertisement_enabled") == 0) {
1903 bss->wmm_uapsd = atoi(pos);
41d719d6
JM
1904 } else if (os_strncmp(buf, "wme_ac_", 7) == 0 ||
1905 os_strncmp(buf, "wmm_ac_", 7) == 0) {
1906 if (hostapd_config_wmm_ac(conf, buf, pos)) {
1907 wpa_printf(MSG_ERROR, "Line %d: invalid WMM "
1908 "ac item", line);
1909 errors++;
1910 }
1911 } else if (os_strcmp(buf, "bss") == 0) {
1912 if (hostapd_config_bss(conf, pos)) {
1913 wpa_printf(MSG_ERROR, "Line %d: invalid bss "
1914 "item", line);
1915 errors++;
1916 }
1917 } else if (os_strcmp(buf, "bssid") == 0) {
1918 if (hwaddr_aton(pos, bss->bssid)) {
1919 wpa_printf(MSG_ERROR, "Line %d: invalid bssid "
1920 "item", line);
1921 errors++;
1922 }
1923#ifdef CONFIG_IEEE80211W
1924 } else if (os_strcmp(buf, "ieee80211w") == 0) {
1925 bss->ieee80211w = atoi(pos);
1926 } else if (os_strcmp(buf, "assoc_sa_query_max_timeout") == 0) {
1927 bss->assoc_sa_query_max_timeout = atoi(pos);
1928 if (bss->assoc_sa_query_max_timeout == 0) {
1929 wpa_printf(MSG_ERROR, "Line %d: invalid "
1930 "assoc_sa_query_max_timeout", line);
1931 errors++;
1932 }
1933 } else if (os_strcmp(buf, "assoc_sa_query_retry_timeout") == 0)
1934 {
1935 bss->assoc_sa_query_retry_timeout = atoi(pos);
1936 if (bss->assoc_sa_query_retry_timeout == 0) {
1937 wpa_printf(MSG_ERROR, "Line %d: invalid "
1938 "assoc_sa_query_retry_timeout",
1939 line);
1940 errors++;
1941 }
1942#endif /* CONFIG_IEEE80211W */
1943#ifdef CONFIG_IEEE80211N
1944 } else if (os_strcmp(buf, "ieee80211n") == 0) {
1945 conf->ieee80211n = atoi(pos);
1946 } else if (os_strcmp(buf, "ht_capab") == 0) {
1947 if (hostapd_config_ht_capab(conf, pos) < 0) {
1948 wpa_printf(MSG_ERROR, "Line %d: invalid "
1949 "ht_capab", line);
1950 errors++;
1951 }
29448243
JM
1952 } else if (os_strcmp(buf, "require_ht") == 0) {
1953 conf->require_ht = atoi(pos);
41d719d6
JM
1954#endif /* CONFIG_IEEE80211N */
1955 } else if (os_strcmp(buf, "max_listen_interval") == 0) {
1956 bss->max_listen_interval = atoi(pos);
cb465555
JM
1957 } else if (os_strcmp(buf, "disable_pmksa_caching") == 0) {
1958 bss->disable_pmksa_caching = atoi(pos);
41d719d6
JM
1959 } else if (os_strcmp(buf, "okc") == 0) {
1960 bss->okc = atoi(pos);
1961#ifdef CONFIG_WPS
1962 } else if (os_strcmp(buf, "wps_state") == 0) {
1963 bss->wps_state = atoi(pos);
1964 if (bss->wps_state < 0 || bss->wps_state > 2) {
1965 wpa_printf(MSG_ERROR, "Line %d: invalid "
1966 "wps_state", line);
1967 errors++;
1968 }
1969 } else if (os_strcmp(buf, "ap_setup_locked") == 0) {
1970 bss->ap_setup_locked = atoi(pos);
1971 } else if (os_strcmp(buf, "uuid") == 0) {
1972 if (uuid_str2bin(pos, bss->uuid)) {
1973 wpa_printf(MSG_ERROR, "Line %d: invalid UUID",
1974 line);
1975 errors++;
1976 }
1977 } else if (os_strcmp(buf, "wps_pin_requests") == 0) {
1978 os_free(bss->wps_pin_requests);
1979 bss->wps_pin_requests = os_strdup(pos);
1980 } else if (os_strcmp(buf, "device_name") == 0) {
1981 if (os_strlen(pos) > 32) {
1982 wpa_printf(MSG_ERROR, "Line %d: Too long "
1983 "device_name", line);
1984 errors++;
1985 }
1986 os_free(bss->device_name);
1987 bss->device_name = os_strdup(pos);
1988 } else if (os_strcmp(buf, "manufacturer") == 0) {
1989 if (os_strlen(pos) > 64) {
1990 wpa_printf(MSG_ERROR, "Line %d: Too long "
1991 "manufacturer", line);
1992 errors++;
1993 }
1994 os_free(bss->manufacturer);
1995 bss->manufacturer = os_strdup(pos);
1996 } else if (os_strcmp(buf, "model_name") == 0) {
1997 if (os_strlen(pos) > 32) {
1998 wpa_printf(MSG_ERROR, "Line %d: Too long "
1999 "model_name", line);
2000 errors++;
2001 }
2002 os_free(bss->model_name);
2003 bss->model_name = os_strdup(pos);
2004 } else if (os_strcmp(buf, "model_number") == 0) {
2005 if (os_strlen(pos) > 32) {
2006 wpa_printf(MSG_ERROR, "Line %d: Too long "
2007 "model_number", line);
2008 errors++;
2009 }
2010 os_free(bss->model_number);
2011 bss->model_number = os_strdup(pos);
2012 } else if (os_strcmp(buf, "serial_number") == 0) {
2013 if (os_strlen(pos) > 32) {
2014 wpa_printf(MSG_ERROR, "Line %d: Too long "
2015 "serial_number", line);
2016 errors++;
2017 }
2018 os_free(bss->serial_number);
2019 bss->serial_number = os_strdup(pos);
2020 } else if (os_strcmp(buf, "device_type") == 0) {
2f646b6e
JB
2021 if (wps_dev_type_str2bin(pos, bss->device_type))
2022 errors++;
41d719d6
JM
2023 } else if (os_strcmp(buf, "config_methods") == 0) {
2024 os_free(bss->config_methods);
2025 bss->config_methods = os_strdup(pos);
2026 } else if (os_strcmp(buf, "os_version") == 0) {
2027 if (hexstr2bin(pos, bss->os_version, 4)) {
2028 wpa_printf(MSG_ERROR, "Line %d: invalid "
2029 "os_version", line);
2030 errors++;
2031 }
2032 } else if (os_strcmp(buf, "ap_pin") == 0) {
2033 os_free(bss->ap_pin);
2034 bss->ap_pin = os_strdup(pos);
2035 } else if (os_strcmp(buf, "skip_cred_build") == 0) {
2036 bss->skip_cred_build = atoi(pos);
2037 } else if (os_strcmp(buf, "extra_cred") == 0) {
2038 os_free(bss->extra_cred);
2039 bss->extra_cred =
2040 (u8 *) os_readfile(pos, &bss->extra_cred_len);
2041 if (bss->extra_cred == NULL) {
2042 wpa_printf(MSG_ERROR, "Line %d: could not "
2043 "read Credentials from '%s'",
2044 line, pos);
2045 errors++;
2046 }
2047 } else if (os_strcmp(buf, "wps_cred_processing") == 0) {
2048 bss->wps_cred_processing = atoi(pos);
2049 } else if (os_strcmp(buf, "ap_settings") == 0) {
2050 os_free(bss->ap_settings);
2051 bss->ap_settings =
2052 (u8 *) os_readfile(pos, &bss->ap_settings_len);
2053 if (bss->ap_settings == NULL) {
2054 wpa_printf(MSG_ERROR, "Line %d: could not "
2055 "read AP Settings from '%s'",
2056 line, pos);
2057 errors++;
2058 }
2059 } else if (os_strcmp(buf, "upnp_iface") == 0) {
2060 bss->upnp_iface = os_strdup(pos);
2061 } else if (os_strcmp(buf, "friendly_name") == 0) {
2062 os_free(bss->friendly_name);
2063 bss->friendly_name = os_strdup(pos);
2064 } else if (os_strcmp(buf, "manufacturer_url") == 0) {
2065 os_free(bss->manufacturer_url);
2066 bss->manufacturer_url = os_strdup(pos);
2067 } else if (os_strcmp(buf, "model_description") == 0) {
2068 os_free(bss->model_description);
2069 bss->model_description = os_strdup(pos);
2070 } else if (os_strcmp(buf, "model_url") == 0) {
2071 os_free(bss->model_url);
2072 bss->model_url = os_strdup(pos);
2073 } else if (os_strcmp(buf, "upc") == 0) {
2074 os_free(bss->upc);
2075 bss->upc = os_strdup(pos);
fa516558
JM
2076 } else if (os_strcmp(buf, "pbc_in_m1") == 0) {
2077 bss->pbc_in_m1 = atoi(pos);
41d719d6 2078#endif /* CONFIG_WPS */
962473c1
JM
2079#ifdef CONFIG_P2P_MANAGER
2080 } else if (os_strcmp(buf, "manage_p2p") == 0) {
2081 int manage = atoi(pos);
2082 if (manage)
2083 bss->p2p |= P2P_MANAGE;
2084 else
2085 bss->p2p &= ~P2P_MANAGE;
2086 } else if (os_strcmp(buf, "allow_cross_connection") == 0) {
2087 if (atoi(pos))
2088 bss->p2p |= P2P_ALLOW_CROSS_CONNECTION;
2089 else
2090 bss->p2p &= ~P2P_ALLOW_CROSS_CONNECTION;
2091#endif /* CONFIG_P2P_MANAGER */
0d7e5a3a
JB
2092 } else if (os_strcmp(buf, "disassoc_low_ack") == 0) {
2093 bss->disassoc_low_ack = atoi(pos);
1161ff1e
JM
2094 } else if (os_strcmp(buf, "tdls_prohibit") == 0) {
2095 int val = atoi(pos);
2096 if (val)
2097 bss->tdls |= TDLS_PROHIBIT;
2098 else
2099 bss->tdls &= ~TDLS_PROHIBIT;
2100 } else if (os_strcmp(buf, "tdls_prohibit_chan_switch") == 0) {
2101 int val = atoi(pos);
2102 if (val)
2103 bss->tdls |= TDLS_PROHIBIT_CHAN_SWITCH;
2104 else
2105 bss->tdls &= ~TDLS_PROHIBIT_CHAN_SWITCH;
cd9fc786
JM
2106#ifdef CONFIG_RSN_TESTING
2107 } else if (os_strcmp(buf, "rsn_testing") == 0) {
2108 extern int rsn_testing;
2109 rsn_testing = atoi(pos);
2110#endif /* CONFIG_RSN_TESTING */
39b97072
JM
2111 } else if (os_strcmp(buf, "time_advertisement") == 0) {
2112 bss->time_advertisement = atoi(pos);
2113 } else if (os_strcmp(buf, "time_zone") == 0) {
2114 size_t tz_len = os_strlen(pos);
2115 if (tz_len < 4 || tz_len > 255) {
2116 wpa_printf(MSG_DEBUG, "Line %d: invalid "
2117 "time_zone", line);
2118 errors++;
ef45bc89 2119 return errors;
39b97072
JM
2120 }
2121 os_free(bss->time_zone);
2122 bss->time_zone = os_strdup(pos);
2123 if (bss->time_zone == NULL)
2124 errors++;
b83e3e93
JM
2125#ifdef CONFIG_INTERWORKING
2126 } else if (os_strcmp(buf, "interworking") == 0) {
2127 bss->interworking = atoi(pos);
2128 } else if (os_strcmp(buf, "access_network_type") == 0) {
2129 bss->access_network_type = atoi(pos);
2130 if (bss->access_network_type < 0 ||
2131 bss->access_network_type > 15) {
2132 wpa_printf(MSG_ERROR, "Line %d: invalid "
2133 "access_network_type", line);
2134 errors++;
2135 }
2136 } else if (os_strcmp(buf, "internet") == 0) {
2137 bss->internet = atoi(pos);
2138 } else if (os_strcmp(buf, "asra") == 0) {
2139 bss->asra = atoi(pos);
2140 } else if (os_strcmp(buf, "esr") == 0) {
2141 bss->esr = atoi(pos);
2142 } else if (os_strcmp(buf, "uesa") == 0) {
2143 bss->uesa = atoi(pos);
2144 } else if (os_strcmp(buf, "venue_group") == 0) {
2145 bss->venue_group = atoi(pos);
2146 bss->venue_info_set = 1;
2147 } else if (os_strcmp(buf, "venue_type") == 0) {
2148 bss->venue_type = atoi(pos);
2149 bss->venue_info_set = 1;
2150 } else if (os_strcmp(buf, "hessid") == 0) {
2151 if (hwaddr_aton(pos, bss->hessid)) {
2152 wpa_printf(MSG_ERROR, "Line %d: invalid "
2153 "hessid", line);
2154 errors++;
2155 }
4b2a77ab
JM
2156 } else if (os_strcmp(buf, "roaming_consortium") == 0) {
2157 if (parse_roaming_consortium(bss, pos, line) < 0)
2158 errors++;
648cc711
JM
2159 } else if (os_strcmp(buf, "venue_name") == 0) {
2160 if (parse_venue_name(bss, pos, line) < 0)
2161 errors++;
dca30c3f
JK
2162 } else if (os_strcmp(buf, "gas_frag_limit") == 0) {
2163 bss->gas_frag_limit = atoi(pos);
2164 } else if (os_strcmp(buf, "gas_comeback_delay") == 0) {
2165 bss->gas_comeback_delay = atoi(pos);
b83e3e93 2166#endif /* CONFIG_INTERWORKING */
505a3694
JM
2167#ifdef CONFIG_RADIUS_TEST
2168 } else if (os_strcmp(buf, "dump_msk_file") == 0) {
2169 os_free(bss->dump_msk_file);
2170 bss->dump_msk_file = os_strdup(pos);
2171#endif /* CONFIG_RADIUS_TEST */
41d719d6
JM
2172 } else {
2173 wpa_printf(MSG_ERROR, "Line %d: unknown configuration "
2174 "item '%s'", line, buf);
2175 errors++;
2176 }
2177 }
2178
ef45bc89
SP
2179 return errors;
2180}
2181
2182
a7f5b74d
JM
2183static void hostapd_set_security_params(struct hostapd_bss_config *bss)
2184{
2185 int pairwise;
2186
2187 if (bss->individual_wep_key_len == 0) {
2188 /* individual keys are not use; can use key idx0 for
2189 * broadcast keys */
2190 bss->broadcast_key_idx_min = 0;
2191 }
2192
2193 /* Select group cipher based on the enabled pairwise cipher
2194 * suites */
2195 pairwise = 0;
2196 if (bss->wpa & 1)
2197 pairwise |= bss->wpa_pairwise;
2198 if (bss->wpa & 2) {
2199 if (bss->rsn_pairwise == 0)
2200 bss->rsn_pairwise = bss->wpa_pairwise;
2201 pairwise |= bss->rsn_pairwise;
2202 }
2203 if (pairwise & WPA_CIPHER_TKIP)
2204 bss->wpa_group = WPA_CIPHER_TKIP;
2205 else
2206 bss->wpa_group = WPA_CIPHER_CCMP;
2207
2208 bss->radius->auth_server = bss->radius->auth_servers;
2209 bss->radius->acct_server = bss->radius->acct_servers;
2210
2211 if (bss->wpa && bss->ieee802_1x) {
2212 bss->ssid.security_policy = SECURITY_WPA;
2213 } else if (bss->wpa) {
2214 bss->ssid.security_policy = SECURITY_WPA_PSK;
2215 } else if (bss->ieee802_1x) {
2216 int cipher = WPA_CIPHER_NONE;
2217 bss->ssid.security_policy = SECURITY_IEEE_802_1X;
2218 bss->ssid.wep.default_len = bss->default_wep_key_len;
2219 if (bss->default_wep_key_len)
2220 cipher = bss->default_wep_key_len >= 13 ?
2221 WPA_CIPHER_WEP104 : WPA_CIPHER_WEP40;
2222 bss->wpa_group = cipher;
2223 bss->wpa_pairwise = cipher;
2224 bss->rsn_pairwise = cipher;
2225 } else if (bss->ssid.wep.keys_set) {
2226 int cipher = WPA_CIPHER_WEP40;
2227 if (bss->ssid.wep.len[0] >= 13)
2228 cipher = WPA_CIPHER_WEP104;
2229 bss->ssid.security_policy = SECURITY_STATIC_WEP;
2230 bss->wpa_group = cipher;
2231 bss->wpa_pairwise = cipher;
2232 bss->rsn_pairwise = cipher;
2233 } else {
2234 bss->ssid.security_policy = SECURITY_PLAINTEXT;
2235 bss->wpa_group = WPA_CIPHER_NONE;
2236 bss->wpa_pairwise = WPA_CIPHER_NONE;
2237 bss->rsn_pairwise = WPA_CIPHER_NONE;
2238 }
2239}
2240
2241
ef45bc89
SP
2242/**
2243 * hostapd_config_read - Read and parse a configuration file
2244 * @fname: Configuration file name (including path, if needed)
2245 * Returns: Allocated configuration data structure
2246 */
2247struct hostapd_config * hostapd_config_read(const char *fname)
2248{
2249 struct hostapd_config *conf;
2250 struct hostapd_bss_config *bss;
2251 FILE *f;
2252 char buf[256], *pos;
2253 int line = 0;
2254 int errors = 0;
ef45bc89
SP
2255 size_t i;
2256
2257 f = fopen(fname, "r");
2258 if (f == NULL) {
2259 wpa_printf(MSG_ERROR, "Could not open configuration file '%s' "
2260 "for reading.", fname);
2261 return NULL;
2262 }
2263
2264 conf = hostapd_config_defaults();
2265 if (conf == NULL) {
2266 fclose(f);
2267 return NULL;
2268 }
2269
2270 /* set default driver based on configuration */
2271 conf->driver = wpa_drivers[0];
2272 if (conf->driver == NULL) {
2273 wpa_printf(MSG_ERROR, "No driver wrappers registered!");
2274 hostapd_config_free(conf);
2275 fclose(f);
2276 return NULL;
2277 }
2278
2279 bss = conf->last_bss = conf->bss;
2280
2281 while (fgets(buf, sizeof(buf), f)) {
2282 bss = conf->last_bss;
2283 line++;
2284
2285 if (buf[0] == '#')
2286 continue;
2287 pos = buf;
2288 while (*pos != '\0') {
2289 if (*pos == '\n') {
2290 *pos = '\0';
2291 break;
2292 }
2293 pos++;
2294 }
2295 if (buf[0] == '\0')
2296 continue;
2297
2298 pos = os_strchr(buf, '=');
2299 if (pos == NULL) {
2300 wpa_printf(MSG_ERROR, "Line %d: invalid line '%s'",
2301 line, buf);
2302 errors++;
2303 continue;
2304 }
2305 *pos = '\0';
2306 pos++;
2307 errors += hostapd_config_fill(conf, bss, buf, pos, line);
2308 }
2309
41d719d6
JM
2310 fclose(f);
2311
a7f5b74d
JM
2312 for (i = 0; i < conf->num_bss; i++)
2313 hostapd_set_security_params(&conf->bss[i]);
41d719d6
JM
2314
2315 if (hostapd_config_check(conf))
2316 errors++;
2317
ae6e1bee 2318#ifndef WPA_IGNORE_CONFIG_ERRORS
41d719d6
JM
2319 if (errors) {
2320 wpa_printf(MSG_ERROR, "%d errors found in configuration file "
2321 "'%s'", errors, fname);
2322 hostapd_config_free(conf);
2323 conf = NULL;
2324 }
ae6e1bee 2325#endif /* WPA_IGNORE_CONFIG_ERRORS */
41d719d6
JM
2326
2327 return conf;
2328}
31b79e11
SP
2329
2330
2331int hostapd_set_iface(struct hostapd_config *conf,
2332 struct hostapd_bss_config *bss, char *field, char *value)
2333{
2334 int errors = 0;
2335 size_t i;
2336
2337 errors = hostapd_config_fill(conf, bss, field, value, 0);
2338 if (errors) {
2339 wpa_printf(MSG_INFO, "Failed to set configuration field '%s' "
2340 "to value '%s'", field, value);
2341 return -1;
2342 }
2343
2344 for (i = 0; i < conf->num_bss; i++)
2345 hostapd_set_security_params(&conf->bss[i]);
2346
2347 if (hostapd_config_check(conf)) {
2348 wpa_printf(MSG_ERROR, "Configuration check failed");
2349 errors++;
2350 }
2351
2352 return 0;
2353}