blob: 78f1e3d0b8b7e8f0e280c5fd20ce4ba0cb708cb9 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * hostapd / Configuration file parser
3 * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
4 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 */
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(*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++;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800327 if (num_methods >= EAP_MAX_METHODS)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700328 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 */
749 IEEE80211_TX_QUEUE_DATA3 = 3 /* used for EDCA AC_BK data */
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;
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;
769 } else {
770 wpa_printf(MSG_ERROR, "Unknown tx_queue name '%s'", pos);
771 return -1;
772 }
773
774 if (num >= NUM_TX_QUEUES) {
775 /* for backwards compatibility, do not trigger failure */
776 wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
777 return 0;
778 }
779
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
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
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001047 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
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001054 if (bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
1055 bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001056 bss->ssid.wpa_psk_file == NULL &&
1057 (bss->wpa_psk_radius != PSK_RADIUS_REQUIRED ||
1058 bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001059 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
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001081 if (wpa_key_mgmt_ft(bss->wpa_key_mgmt) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001082 (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
1093 if (conf->ieee80211n &&
1094 bss->ssid.security_policy == SECURITY_STATIC_WEP) {
1095 bss->disable_11n = 1;
1096 wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WEP is not "
1097 "allowed, disabling HT capabilities");
1098 }
1099
1100 if (conf->ieee80211n && bss->wpa &&
1101 !(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
1102 !(bss->rsn_pairwise & WPA_CIPHER_CCMP)) {
1103 bss->disable_11n = 1;
1104 wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 "
1105 "requires CCMP to be enabled, disabling HT "
1106 "capabilities");
1107 }
1108#endif /* CONFIG_IEEE80211N */
1109
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
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
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001147#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}
1178#endif /* CONFIG_INTERWORKING */
1179
1180
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001181/**
1182 * hostapd_config_read - Read and parse a configuration file
1183 * @fname: Configuration file name (including path, if needed)
1184 * Returns: Allocated configuration data structure
1185 */
1186struct hostapd_config * hostapd_config_read(const char *fname)
1187{
1188 struct hostapd_config *conf;
1189 struct hostapd_bss_config *bss;
1190 FILE *f;
1191 char buf[256], *pos;
1192 int line = 0;
1193 int errors = 0;
1194 int pairwise;
1195 size_t i;
1196
1197 f = fopen(fname, "r");
1198 if (f == NULL) {
1199 wpa_printf(MSG_ERROR, "Could not open configuration file '%s' "
1200 "for reading.", fname);
1201 return NULL;
1202 }
1203
1204 conf = hostapd_config_defaults();
1205 if (conf == NULL) {
1206 fclose(f);
1207 return NULL;
1208 }
1209
1210 /* set default driver based on configuration */
1211 conf->driver = wpa_drivers[0];
1212 if (conf->driver == NULL) {
1213 wpa_printf(MSG_ERROR, "No driver wrappers registered!");
1214 hostapd_config_free(conf);
1215 fclose(f);
1216 return NULL;
1217 }
1218
1219 bss = conf->last_bss = conf->bss;
1220
1221 while (fgets(buf, sizeof(buf), f)) {
1222 bss = conf->last_bss;
1223 line++;
1224
1225 if (buf[0] == '#')
1226 continue;
1227 pos = buf;
1228 while (*pos != '\0') {
1229 if (*pos == '\n') {
1230 *pos = '\0';
1231 break;
1232 }
1233 pos++;
1234 }
1235 if (buf[0] == '\0')
1236 continue;
1237
1238 pos = os_strchr(buf, '=');
1239 if (pos == NULL) {
1240 wpa_printf(MSG_ERROR, "Line %d: invalid line '%s'",
1241 line, buf);
1242 errors++;
1243 continue;
1244 }
1245 *pos = '\0';
1246 pos++;
1247
1248 if (os_strcmp(buf, "interface") == 0) {
1249 os_strlcpy(conf->bss[0].iface, pos,
1250 sizeof(conf->bss[0].iface));
1251 } else if (os_strcmp(buf, "bridge") == 0) {
1252 os_strlcpy(bss->bridge, pos, sizeof(bss->bridge));
1253 } else if (os_strcmp(buf, "wds_bridge") == 0) {
1254 os_strlcpy(bss->wds_bridge, pos,
1255 sizeof(bss->wds_bridge));
1256 } else if (os_strcmp(buf, "driver") == 0) {
1257 int j;
1258 /* clear to get error below if setting is invalid */
1259 conf->driver = NULL;
1260 for (j = 0; wpa_drivers[j]; j++) {
1261 if (os_strcmp(pos, wpa_drivers[j]->name) == 0)
1262 {
1263 conf->driver = wpa_drivers[j];
1264 break;
1265 }
1266 }
1267 if (conf->driver == NULL) {
1268 wpa_printf(MSG_ERROR, "Line %d: invalid/"
1269 "unknown driver '%s'", line, pos);
1270 errors++;
1271 }
1272 } else if (os_strcmp(buf, "debug") == 0) {
1273 wpa_printf(MSG_DEBUG, "Line %d: DEPRECATED: 'debug' "
1274 "configuration variable is not used "
1275 "anymore", line);
1276 } else if (os_strcmp(buf, "logger_syslog_level") == 0) {
1277 bss->logger_syslog_level = atoi(pos);
1278 } else if (os_strcmp(buf, "logger_stdout_level") == 0) {
1279 bss->logger_stdout_level = atoi(pos);
1280 } else if (os_strcmp(buf, "logger_syslog") == 0) {
1281 bss->logger_syslog = atoi(pos);
1282 } else if (os_strcmp(buf, "logger_stdout") == 0) {
1283 bss->logger_stdout = atoi(pos);
1284 } else if (os_strcmp(buf, "dump_file") == 0) {
1285 bss->dump_log_name = os_strdup(pos);
1286 } else if (os_strcmp(buf, "ssid") == 0) {
1287 bss->ssid.ssid_len = os_strlen(pos);
1288 if (bss->ssid.ssid_len > HOSTAPD_MAX_SSID_LEN ||
1289 bss->ssid.ssid_len < 1) {
1290 wpa_printf(MSG_ERROR, "Line %d: invalid SSID "
1291 "'%s'", line, pos);
1292 errors++;
1293 } else {
1294 os_memcpy(bss->ssid.ssid, pos,
1295 bss->ssid.ssid_len);
1296 bss->ssid.ssid[bss->ssid.ssid_len] = '\0';
1297 bss->ssid.ssid_set = 1;
1298 }
1299 } else if (os_strcmp(buf, "macaddr_acl") == 0) {
1300 bss->macaddr_acl = atoi(pos);
1301 if (bss->macaddr_acl != ACCEPT_UNLESS_DENIED &&
1302 bss->macaddr_acl != DENY_UNLESS_ACCEPTED &&
1303 bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
1304 wpa_printf(MSG_ERROR, "Line %d: unknown "
1305 "macaddr_acl %d",
1306 line, bss->macaddr_acl);
1307 }
1308 } else if (os_strcmp(buf, "accept_mac_file") == 0) {
1309 if (hostapd_config_read_maclist(pos, &bss->accept_mac,
1310 &bss->num_accept_mac))
1311 {
1312 wpa_printf(MSG_ERROR, "Line %d: Failed to "
1313 "read accept_mac_file '%s'",
1314 line, pos);
1315 errors++;
1316 }
1317 } else if (os_strcmp(buf, "deny_mac_file") == 0) {
1318 if (hostapd_config_read_maclist(pos, &bss->deny_mac,
1319 &bss->num_deny_mac)) {
1320 wpa_printf(MSG_ERROR, "Line %d: Failed to "
1321 "read deny_mac_file '%s'",
1322 line, pos);
1323 errors++;
1324 }
1325 } else if (os_strcmp(buf, "wds_sta") == 0) {
1326 bss->wds_sta = atoi(pos);
1327 } else if (os_strcmp(buf, "ap_isolate") == 0) {
1328 bss->isolate = atoi(pos);
1329 } else if (os_strcmp(buf, "ap_max_inactivity") == 0) {
1330 bss->ap_max_inactivity = atoi(pos);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001331 } else if (os_strcmp(buf, "skip_inactivity_poll") == 0) {
1332 bss->skip_inactivity_poll = atoi(pos);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001333 } else if (os_strcmp(buf, "country_code") == 0) {
1334 os_memcpy(conf->country, pos, 2);
1335 /* FIX: make this configurable */
1336 conf->country[2] = ' ';
1337 } else if (os_strcmp(buf, "ieee80211d") == 0) {
1338 conf->ieee80211d = atoi(pos);
1339 } else if (os_strcmp(buf, "ieee8021x") == 0) {
1340 bss->ieee802_1x = atoi(pos);
1341 } else if (os_strcmp(buf, "eapol_version") == 0) {
1342 bss->eapol_version = atoi(pos);
1343 if (bss->eapol_version < 1 ||
1344 bss->eapol_version > 2) {
1345 wpa_printf(MSG_ERROR, "Line %d: invalid EAPOL "
1346 "version (%d): '%s'.",
1347 line, bss->eapol_version, pos);
1348 errors++;
1349 } else
1350 wpa_printf(MSG_DEBUG, "eapol_version=%d",
1351 bss->eapol_version);
1352#ifdef EAP_SERVER
1353 } else if (os_strcmp(buf, "eap_authenticator") == 0) {
1354 bss->eap_server = atoi(pos);
1355 wpa_printf(MSG_ERROR, "Line %d: obsolete "
1356 "eap_authenticator used; this has been "
1357 "renamed to eap_server", line);
1358 } else if (os_strcmp(buf, "eap_server") == 0) {
1359 bss->eap_server = atoi(pos);
1360 } else if (os_strcmp(buf, "eap_user_file") == 0) {
1361 if (hostapd_config_read_eap_user(pos, bss))
1362 errors++;
1363 } else if (os_strcmp(buf, "ca_cert") == 0) {
1364 os_free(bss->ca_cert);
1365 bss->ca_cert = os_strdup(pos);
1366 } else if (os_strcmp(buf, "server_cert") == 0) {
1367 os_free(bss->server_cert);
1368 bss->server_cert = os_strdup(pos);
1369 } else if (os_strcmp(buf, "private_key") == 0) {
1370 os_free(bss->private_key);
1371 bss->private_key = os_strdup(pos);
1372 } else if (os_strcmp(buf, "private_key_passwd") == 0) {
1373 os_free(bss->private_key_passwd);
1374 bss->private_key_passwd = os_strdup(pos);
1375 } else if (os_strcmp(buf, "check_crl") == 0) {
1376 bss->check_crl = atoi(pos);
1377 } else if (os_strcmp(buf, "dh_file") == 0) {
1378 os_free(bss->dh_file);
1379 bss->dh_file = os_strdup(pos);
1380 } else if (os_strcmp(buf, "fragment_size") == 0) {
1381 bss->fragment_size = atoi(pos);
1382#ifdef EAP_SERVER_FAST
1383 } else if (os_strcmp(buf, "pac_opaque_encr_key") == 0) {
1384 os_free(bss->pac_opaque_encr_key);
1385 bss->pac_opaque_encr_key = os_malloc(16);
1386 if (bss->pac_opaque_encr_key == NULL) {
1387 wpa_printf(MSG_ERROR, "Line %d: No memory for "
1388 "pac_opaque_encr_key", line);
1389 errors++;
1390 } else if (hexstr2bin(pos, bss->pac_opaque_encr_key,
1391 16)) {
1392 wpa_printf(MSG_ERROR, "Line %d: Invalid "
1393 "pac_opaque_encr_key", line);
1394 errors++;
1395 }
1396 } else if (os_strcmp(buf, "eap_fast_a_id") == 0) {
1397 size_t idlen = os_strlen(pos);
1398 if (idlen & 1) {
1399 wpa_printf(MSG_ERROR, "Line %d: Invalid "
1400 "eap_fast_a_id", line);
1401 errors++;
1402 } else {
1403 os_free(bss->eap_fast_a_id);
1404 bss->eap_fast_a_id = os_malloc(idlen / 2);
1405 if (bss->eap_fast_a_id == NULL ||
1406 hexstr2bin(pos, bss->eap_fast_a_id,
1407 idlen / 2)) {
1408 wpa_printf(MSG_ERROR, "Line %d: "
1409 "Failed to parse "
1410 "eap_fast_a_id", line);
1411 errors++;
1412 } else
1413 bss->eap_fast_a_id_len = idlen / 2;
1414 }
1415 } else if (os_strcmp(buf, "eap_fast_a_id_info") == 0) {
1416 os_free(bss->eap_fast_a_id_info);
1417 bss->eap_fast_a_id_info = os_strdup(pos);
1418 } else if (os_strcmp(buf, "eap_fast_prov") == 0) {
1419 bss->eap_fast_prov = atoi(pos);
1420 } else if (os_strcmp(buf, "pac_key_lifetime") == 0) {
1421 bss->pac_key_lifetime = atoi(pos);
1422 } else if (os_strcmp(buf, "pac_key_refresh_time") == 0) {
1423 bss->pac_key_refresh_time = atoi(pos);
1424#endif /* EAP_SERVER_FAST */
1425#ifdef EAP_SERVER_SIM
1426 } else if (os_strcmp(buf, "eap_sim_db") == 0) {
1427 os_free(bss->eap_sim_db);
1428 bss->eap_sim_db = os_strdup(pos);
1429 } else if (os_strcmp(buf, "eap_sim_aka_result_ind") == 0) {
1430 bss->eap_sim_aka_result_ind = atoi(pos);
1431#endif /* EAP_SERVER_SIM */
1432#ifdef EAP_SERVER_TNC
1433 } else if (os_strcmp(buf, "tnc") == 0) {
1434 bss->tnc = atoi(pos);
1435#endif /* EAP_SERVER_TNC */
1436#ifdef EAP_SERVER_PWD
1437 } else if (os_strcmp(buf, "pwd_group") == 0) {
1438 bss->pwd_group = atoi(pos);
1439#endif /* EAP_SERVER_PWD */
1440#endif /* EAP_SERVER */
1441 } else if (os_strcmp(buf, "eap_message") == 0) {
1442 char *term;
1443 bss->eap_req_id_text = os_strdup(pos);
1444 if (bss->eap_req_id_text == NULL) {
1445 wpa_printf(MSG_ERROR, "Line %d: Failed to "
1446 "allocate memory for "
1447 "eap_req_id_text", line);
1448 errors++;
1449 continue;
1450 }
1451 bss->eap_req_id_text_len =
1452 os_strlen(bss->eap_req_id_text);
1453 term = os_strstr(bss->eap_req_id_text, "\\0");
1454 if (term) {
1455 *term++ = '\0';
1456 os_memmove(term, term + 1,
1457 bss->eap_req_id_text_len -
1458 (term - bss->eap_req_id_text) - 1);
1459 bss->eap_req_id_text_len--;
1460 }
1461 } else if (os_strcmp(buf, "wep_key_len_broadcast") == 0) {
1462 bss->default_wep_key_len = atoi(pos);
1463 if (bss->default_wep_key_len > 13) {
1464 wpa_printf(MSG_ERROR, "Line %d: invalid WEP "
1465 "key len %lu (= %lu bits)", line,
1466 (unsigned long)
1467 bss->default_wep_key_len,
1468 (unsigned long)
1469 bss->default_wep_key_len * 8);
1470 errors++;
1471 }
1472 } else if (os_strcmp(buf, "wep_key_len_unicast") == 0) {
1473 bss->individual_wep_key_len = atoi(pos);
1474 if (bss->individual_wep_key_len < 0 ||
1475 bss->individual_wep_key_len > 13) {
1476 wpa_printf(MSG_ERROR, "Line %d: invalid WEP "
1477 "key len %d (= %d bits)", line,
1478 bss->individual_wep_key_len,
1479 bss->individual_wep_key_len * 8);
1480 errors++;
1481 }
1482 } else if (os_strcmp(buf, "wep_rekey_period") == 0) {
1483 bss->wep_rekeying_period = atoi(pos);
1484 if (bss->wep_rekeying_period < 0) {
1485 wpa_printf(MSG_ERROR, "Line %d: invalid "
1486 "period %d",
1487 line, bss->wep_rekeying_period);
1488 errors++;
1489 }
1490 } else if (os_strcmp(buf, "eap_reauth_period") == 0) {
1491 bss->eap_reauth_period = atoi(pos);
1492 if (bss->eap_reauth_period < 0) {
1493 wpa_printf(MSG_ERROR, "Line %d: invalid "
1494 "period %d",
1495 line, bss->eap_reauth_period);
1496 errors++;
1497 }
1498 } else if (os_strcmp(buf, "eapol_key_index_workaround") == 0) {
1499 bss->eapol_key_index_workaround = atoi(pos);
1500#ifdef CONFIG_IAPP
1501 } else if (os_strcmp(buf, "iapp_interface") == 0) {
1502 bss->ieee802_11f = 1;
1503 os_strlcpy(bss->iapp_iface, pos,
1504 sizeof(bss->iapp_iface));
1505#endif /* CONFIG_IAPP */
1506 } else if (os_strcmp(buf, "own_ip_addr") == 0) {
1507 if (hostapd_parse_ip_addr(pos, &bss->own_ip_addr)) {
1508 wpa_printf(MSG_ERROR, "Line %d: invalid IP "
1509 "address '%s'", line, pos);
1510 errors++;
1511 }
1512 } else if (os_strcmp(buf, "nas_identifier") == 0) {
1513 bss->nas_identifier = os_strdup(pos);
1514#ifndef CONFIG_NO_RADIUS
1515 } else if (os_strcmp(buf, "auth_server_addr") == 0) {
1516 if (hostapd_config_read_radius_addr(
1517 &bss->radius->auth_servers,
1518 &bss->radius->num_auth_servers, pos, 1812,
1519 &bss->radius->auth_server)) {
1520 wpa_printf(MSG_ERROR, "Line %d: invalid IP "
1521 "address '%s'", line, pos);
1522 errors++;
1523 }
1524 } else if (bss->radius->auth_server &&
1525 os_strcmp(buf, "auth_server_port") == 0) {
1526 bss->radius->auth_server->port = atoi(pos);
1527 } else if (bss->radius->auth_server &&
1528 os_strcmp(buf, "auth_server_shared_secret") == 0) {
1529 int len = os_strlen(pos);
1530 if (len == 0) {
1531 /* RFC 2865, Ch. 3 */
1532 wpa_printf(MSG_ERROR, "Line %d: empty shared "
1533 "secret is not allowed.", line);
1534 errors++;
1535 }
1536 bss->radius->auth_server->shared_secret =
1537 (u8 *) os_strdup(pos);
1538 bss->radius->auth_server->shared_secret_len = len;
1539 } else if (os_strcmp(buf, "acct_server_addr") == 0) {
1540 if (hostapd_config_read_radius_addr(
1541 &bss->radius->acct_servers,
1542 &bss->radius->num_acct_servers, pos, 1813,
1543 &bss->radius->acct_server)) {
1544 wpa_printf(MSG_ERROR, "Line %d: invalid IP "
1545 "address '%s'", line, pos);
1546 errors++;
1547 }
1548 } else if (bss->radius->acct_server &&
1549 os_strcmp(buf, "acct_server_port") == 0) {
1550 bss->radius->acct_server->port = atoi(pos);
1551 } else if (bss->radius->acct_server &&
1552 os_strcmp(buf, "acct_server_shared_secret") == 0) {
1553 int len = os_strlen(pos);
1554 if (len == 0) {
1555 /* RFC 2865, Ch. 3 */
1556 wpa_printf(MSG_ERROR, "Line %d: empty shared "
1557 "secret is not allowed.", line);
1558 errors++;
1559 }
1560 bss->radius->acct_server->shared_secret =
1561 (u8 *) os_strdup(pos);
1562 bss->radius->acct_server->shared_secret_len = len;
1563 } else if (os_strcmp(buf, "radius_retry_primary_interval") ==
1564 0) {
1565 bss->radius->retry_primary_interval = atoi(pos);
1566 } else if (os_strcmp(buf, "radius_acct_interim_interval") == 0)
1567 {
1568 bss->acct_interim_interval = atoi(pos);
1569#endif /* CONFIG_NO_RADIUS */
1570 } else if (os_strcmp(buf, "auth_algs") == 0) {
1571 bss->auth_algs = atoi(pos);
1572 if (bss->auth_algs == 0) {
1573 wpa_printf(MSG_ERROR, "Line %d: no "
1574 "authentication algorithms allowed",
1575 line);
1576 errors++;
1577 }
1578 } else if (os_strcmp(buf, "max_num_sta") == 0) {
1579 bss->max_num_sta = atoi(pos);
1580 if (bss->max_num_sta < 0 ||
1581 bss->max_num_sta > MAX_STA_COUNT) {
1582 wpa_printf(MSG_ERROR, "Line %d: Invalid "
1583 "max_num_sta=%d; allowed range "
1584 "0..%d", line, bss->max_num_sta,
1585 MAX_STA_COUNT);
1586 errors++;
1587 }
1588 } else if (os_strcmp(buf, "wpa") == 0) {
1589 bss->wpa = atoi(pos);
1590 } else if (os_strcmp(buf, "wpa_group_rekey") == 0) {
1591 bss->wpa_group_rekey = atoi(pos);
1592 } else if (os_strcmp(buf, "wpa_strict_rekey") == 0) {
1593 bss->wpa_strict_rekey = atoi(pos);
1594 } else if (os_strcmp(buf, "wpa_gmk_rekey") == 0) {
1595 bss->wpa_gmk_rekey = atoi(pos);
1596 } else if (os_strcmp(buf, "wpa_ptk_rekey") == 0) {
1597 bss->wpa_ptk_rekey = atoi(pos);
1598 } else if (os_strcmp(buf, "wpa_passphrase") == 0) {
1599 int len = os_strlen(pos);
1600 if (len < 8 || len > 63) {
1601 wpa_printf(MSG_ERROR, "Line %d: invalid WPA "
1602 "passphrase length %d (expected "
1603 "8..63)", line, len);
1604 errors++;
1605 } else {
1606 os_free(bss->ssid.wpa_passphrase);
1607 bss->ssid.wpa_passphrase = os_strdup(pos);
1608 }
1609 } else if (os_strcmp(buf, "wpa_psk") == 0) {
1610 os_free(bss->ssid.wpa_psk);
1611 bss->ssid.wpa_psk =
1612 os_zalloc(sizeof(struct hostapd_wpa_psk));
1613 if (bss->ssid.wpa_psk == NULL)
1614 errors++;
1615 else if (hexstr2bin(pos, bss->ssid.wpa_psk->psk,
1616 PMK_LEN) ||
1617 pos[PMK_LEN * 2] != '\0') {
1618 wpa_printf(MSG_ERROR, "Line %d: Invalid PSK "
1619 "'%s'.", line, pos);
1620 errors++;
1621 } else {
1622 bss->ssid.wpa_psk->group = 1;
1623 }
1624 } else if (os_strcmp(buf, "wpa_psk_file") == 0) {
1625 os_free(bss->ssid.wpa_psk_file);
1626 bss->ssid.wpa_psk_file = os_strdup(pos);
1627 if (!bss->ssid.wpa_psk_file) {
1628 wpa_printf(MSG_ERROR, "Line %d: allocation "
1629 "failed", line);
1630 errors++;
1631 }
1632 } else if (os_strcmp(buf, "wpa_key_mgmt") == 0) {
1633 bss->wpa_key_mgmt =
1634 hostapd_config_parse_key_mgmt(line, pos);
1635 if (bss->wpa_key_mgmt == -1)
1636 errors++;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001637 } else if (os_strcmp(buf, "wpa_psk_radius") == 0) {
1638 bss->wpa_psk_radius = atoi(pos);
1639 if (bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
1640 bss->wpa_psk_radius != PSK_RADIUS_ACCEPTED &&
1641 bss->wpa_psk_radius != PSK_RADIUS_REQUIRED) {
1642 wpa_printf(MSG_ERROR, "Line %d: unknown "
1643 "wpa_psk_radius %d",
1644 line, bss->wpa_psk_radius);
1645 errors++;
1646 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001647 } else if (os_strcmp(buf, "wpa_pairwise") == 0) {
1648 bss->wpa_pairwise =
1649 hostapd_config_parse_cipher(line, pos);
1650 if (bss->wpa_pairwise == -1 ||
1651 bss->wpa_pairwise == 0)
1652 errors++;
1653 else if (bss->wpa_pairwise &
1654 (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 |
1655 WPA_CIPHER_WEP104)) {
1656 wpa_printf(MSG_ERROR, "Line %d: unsupported "
1657 "pairwise cipher suite '%s'",
1658 bss->wpa_pairwise, pos);
1659 errors++;
1660 }
1661 } else if (os_strcmp(buf, "rsn_pairwise") == 0) {
1662 bss->rsn_pairwise =
1663 hostapd_config_parse_cipher(line, pos);
1664 if (bss->rsn_pairwise == -1 ||
1665 bss->rsn_pairwise == 0)
1666 errors++;
1667 else if (bss->rsn_pairwise &
1668 (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 |
1669 WPA_CIPHER_WEP104)) {
1670 wpa_printf(MSG_ERROR, "Line %d: unsupported "
1671 "pairwise cipher suite '%s'",
1672 bss->rsn_pairwise, pos);
1673 errors++;
1674 }
1675#ifdef CONFIG_RSN_PREAUTH
1676 } else if (os_strcmp(buf, "rsn_preauth") == 0) {
1677 bss->rsn_preauth = atoi(pos);
1678 } else if (os_strcmp(buf, "rsn_preauth_interfaces") == 0) {
1679 bss->rsn_preauth_interfaces = os_strdup(pos);
1680#endif /* CONFIG_RSN_PREAUTH */
1681#ifdef CONFIG_PEERKEY
1682 } else if (os_strcmp(buf, "peerkey") == 0) {
1683 bss->peerkey = atoi(pos);
1684#endif /* CONFIG_PEERKEY */
1685#ifdef CONFIG_IEEE80211R
1686 } else if (os_strcmp(buf, "mobility_domain") == 0) {
1687 if (os_strlen(pos) != 2 * MOBILITY_DOMAIN_ID_LEN ||
1688 hexstr2bin(pos, bss->mobility_domain,
1689 MOBILITY_DOMAIN_ID_LEN) != 0) {
1690 wpa_printf(MSG_DEBUG, "Line %d: Invalid "
1691 "mobility_domain '%s'", line, pos);
1692 errors++;
1693 continue;
1694 }
1695 } else if (os_strcmp(buf, "r1_key_holder") == 0) {
1696 if (os_strlen(pos) != 2 * FT_R1KH_ID_LEN ||
1697 hexstr2bin(pos, bss->r1_key_holder,
1698 FT_R1KH_ID_LEN) != 0) {
1699 wpa_printf(MSG_DEBUG, "Line %d: Invalid "
1700 "r1_key_holder '%s'", line, pos);
1701 errors++;
1702 continue;
1703 }
1704 } else if (os_strcmp(buf, "r0_key_lifetime") == 0) {
1705 bss->r0_key_lifetime = atoi(pos);
1706 } else if (os_strcmp(buf, "reassociation_deadline") == 0) {
1707 bss->reassociation_deadline = atoi(pos);
1708 } else if (os_strcmp(buf, "r0kh") == 0) {
1709 if (add_r0kh(bss, pos) < 0) {
1710 wpa_printf(MSG_DEBUG, "Line %d: Invalid "
1711 "r0kh '%s'", line, pos);
1712 errors++;
1713 continue;
1714 }
1715 } else if (os_strcmp(buf, "r1kh") == 0) {
1716 if (add_r1kh(bss, pos) < 0) {
1717 wpa_printf(MSG_DEBUG, "Line %d: Invalid "
1718 "r1kh '%s'", line, pos);
1719 errors++;
1720 continue;
1721 }
1722 } else if (os_strcmp(buf, "pmk_r1_push") == 0) {
1723 bss->pmk_r1_push = atoi(pos);
1724 } else if (os_strcmp(buf, "ft_over_ds") == 0) {
1725 bss->ft_over_ds = atoi(pos);
1726#endif /* CONFIG_IEEE80211R */
1727#ifndef CONFIG_NO_CTRL_IFACE
1728 } else if (os_strcmp(buf, "ctrl_interface") == 0) {
1729 os_free(bss->ctrl_interface);
1730 bss->ctrl_interface = os_strdup(pos);
1731 } else if (os_strcmp(buf, "ctrl_interface_group") == 0) {
1732#ifndef CONFIG_NATIVE_WINDOWS
1733 struct group *grp;
1734 char *endp;
1735 const char *group = pos;
1736
1737 grp = getgrnam(group);
1738 if (grp) {
1739 bss->ctrl_interface_gid = grp->gr_gid;
1740 bss->ctrl_interface_gid_set = 1;
1741 wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
1742 " (from group name '%s')",
1743 bss->ctrl_interface_gid, group);
1744 continue;
1745 }
1746
1747 /* Group name not found - try to parse this as gid */
1748 bss->ctrl_interface_gid = strtol(group, &endp, 10);
1749 if (*group == '\0' || *endp != '\0') {
1750 wpa_printf(MSG_DEBUG, "Line %d: Invalid group "
1751 "'%s'", line, group);
1752 errors++;
1753 continue;
1754 }
1755 bss->ctrl_interface_gid_set = 1;
1756 wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
1757 bss->ctrl_interface_gid);
1758#endif /* CONFIG_NATIVE_WINDOWS */
1759#endif /* CONFIG_NO_CTRL_IFACE */
1760#ifdef RADIUS_SERVER
1761 } else if (os_strcmp(buf, "radius_server_clients") == 0) {
1762 os_free(bss->radius_server_clients);
1763 bss->radius_server_clients = os_strdup(pos);
1764 } else if (os_strcmp(buf, "radius_server_auth_port") == 0) {
1765 bss->radius_server_auth_port = atoi(pos);
1766 } else if (os_strcmp(buf, "radius_server_ipv6") == 0) {
1767 bss->radius_server_ipv6 = atoi(pos);
1768#endif /* RADIUS_SERVER */
1769 } else if (os_strcmp(buf, "test_socket") == 0) {
1770 os_free(bss->test_socket);
1771 bss->test_socket = os_strdup(pos);
1772 } else if (os_strcmp(buf, "use_pae_group_addr") == 0) {
1773 bss->use_pae_group_addr = atoi(pos);
1774 } else if (os_strcmp(buf, "hw_mode") == 0) {
1775 if (os_strcmp(pos, "a") == 0)
1776 conf->hw_mode = HOSTAPD_MODE_IEEE80211A;
1777 else if (os_strcmp(pos, "b") == 0)
1778 conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
1779 else if (os_strcmp(pos, "g") == 0)
1780 conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
1781 else {
1782 wpa_printf(MSG_ERROR, "Line %d: unknown "
1783 "hw_mode '%s'", line, pos);
1784 errors++;
1785 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001786 } else if (os_strcmp(buf, "wps_rf_bands") == 0) {
1787 if (os_strcmp(pos, "a") == 0)
1788 bss->wps_rf_bands = WPS_RF_50GHZ;
1789 else if (os_strcmp(pos, "g") == 0 ||
1790 os_strcmp(pos, "b") == 0)
1791 bss->wps_rf_bands = WPS_RF_24GHZ;
1792 else if (os_strcmp(pos, "ag") == 0 ||
1793 os_strcmp(pos, "ga") == 0)
1794 bss->wps_rf_bands =
1795 WPS_RF_24GHZ | WPS_RF_50GHZ;
1796 else {
1797 wpa_printf(MSG_ERROR, "Line %d: unknown "
1798 "wps_rf_band '%s'", line, pos);
1799 errors++;
1800 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001801 } else if (os_strcmp(buf, "channel") == 0) {
1802 conf->channel = atoi(pos);
1803 } else if (os_strcmp(buf, "beacon_int") == 0) {
1804 int val = atoi(pos);
1805 /* MIB defines range as 1..65535, but very small values
1806 * cause problems with the current implementation.
1807 * Since it is unlikely that this small numbers are
1808 * useful in real life scenarios, do not allow beacon
1809 * period to be set below 15 TU. */
1810 if (val < 15 || val > 65535) {
1811 wpa_printf(MSG_ERROR, "Line %d: invalid "
1812 "beacon_int %d (expected "
1813 "15..65535)", line, val);
1814 errors++;
1815 } else
1816 conf->beacon_int = val;
1817 } else if (os_strcmp(buf, "dtim_period") == 0) {
1818 bss->dtim_period = atoi(pos);
1819 if (bss->dtim_period < 1 || bss->dtim_period > 255) {
1820 wpa_printf(MSG_ERROR, "Line %d: invalid "
1821 "dtim_period %d",
1822 line, bss->dtim_period);
1823 errors++;
1824 }
1825 } else if (os_strcmp(buf, "rts_threshold") == 0) {
1826 conf->rts_threshold = atoi(pos);
1827 if (conf->rts_threshold < 0 ||
1828 conf->rts_threshold > 2347) {
1829 wpa_printf(MSG_ERROR, "Line %d: invalid "
1830 "rts_threshold %d",
1831 line, conf->rts_threshold);
1832 errors++;
1833 }
1834 } else if (os_strcmp(buf, "fragm_threshold") == 0) {
1835 conf->fragm_threshold = atoi(pos);
1836 if (conf->fragm_threshold < 256 ||
1837 conf->fragm_threshold > 2346) {
1838 wpa_printf(MSG_ERROR, "Line %d: invalid "
1839 "fragm_threshold %d",
1840 line, conf->fragm_threshold);
1841 errors++;
1842 }
1843 } else if (os_strcmp(buf, "send_probe_response") == 0) {
1844 int val = atoi(pos);
1845 if (val != 0 && val != 1) {
1846 wpa_printf(MSG_ERROR, "Line %d: invalid "
1847 "send_probe_response %d (expected "
1848 "0 or 1)", line, val);
1849 } else
1850 conf->send_probe_response = val;
1851 } else if (os_strcmp(buf, "supported_rates") == 0) {
1852 if (hostapd_parse_rates(&conf->supported_rates, pos)) {
1853 wpa_printf(MSG_ERROR, "Line %d: invalid rate "
1854 "list", line);
1855 errors++;
1856 }
1857 } else if (os_strcmp(buf, "basic_rates") == 0) {
1858 if (hostapd_parse_rates(&conf->basic_rates, pos)) {
1859 wpa_printf(MSG_ERROR, "Line %d: invalid rate "
1860 "list", line);
1861 errors++;
1862 }
1863 } else if (os_strcmp(buf, "preamble") == 0) {
1864 if (atoi(pos))
1865 conf->preamble = SHORT_PREAMBLE;
1866 else
1867 conf->preamble = LONG_PREAMBLE;
1868 } else if (os_strcmp(buf, "ignore_broadcast_ssid") == 0) {
1869 bss->ignore_broadcast_ssid = atoi(pos);
1870 } else if (os_strcmp(buf, "wep_default_key") == 0) {
1871 bss->ssid.wep.idx = atoi(pos);
1872 if (bss->ssid.wep.idx > 3) {
1873 wpa_printf(MSG_ERROR, "Invalid "
1874 "wep_default_key index %d",
1875 bss->ssid.wep.idx);
1876 errors++;
1877 }
1878 } else if (os_strcmp(buf, "wep_key0") == 0 ||
1879 os_strcmp(buf, "wep_key1") == 0 ||
1880 os_strcmp(buf, "wep_key2") == 0 ||
1881 os_strcmp(buf, "wep_key3") == 0) {
1882 if (hostapd_config_read_wep(&bss->ssid.wep,
1883 buf[7] - '0', pos)) {
1884 wpa_printf(MSG_ERROR, "Line %d: invalid WEP "
1885 "key '%s'", line, buf);
1886 errors++;
1887 }
1888#ifndef CONFIG_NO_VLAN
1889 } else if (os_strcmp(buf, "dynamic_vlan") == 0) {
1890 bss->ssid.dynamic_vlan = atoi(pos);
1891 } else if (os_strcmp(buf, "vlan_file") == 0) {
1892 if (hostapd_config_read_vlan_file(bss, pos)) {
1893 wpa_printf(MSG_ERROR, "Line %d: failed to "
1894 "read VLAN file '%s'", line, pos);
1895 errors++;
1896 }
1897#ifdef CONFIG_FULL_DYNAMIC_VLAN
1898 } else if (os_strcmp(buf, "vlan_tagged_interface") == 0) {
1899 bss->ssid.vlan_tagged_interface = os_strdup(pos);
1900#endif /* CONFIG_FULL_DYNAMIC_VLAN */
1901#endif /* CONFIG_NO_VLAN */
1902 } else if (os_strcmp(buf, "ap_table_max_size") == 0) {
1903 conf->ap_table_max_size = atoi(pos);
1904 } else if (os_strcmp(buf, "ap_table_expiration_time") == 0) {
1905 conf->ap_table_expiration_time = atoi(pos);
1906 } else if (os_strncmp(buf, "tx_queue_", 9) == 0) {
1907 if (hostapd_config_tx_queue(conf, buf, pos)) {
1908 wpa_printf(MSG_ERROR, "Line %d: invalid TX "
1909 "queue item", line);
1910 errors++;
1911 }
1912 } else if (os_strcmp(buf, "wme_enabled") == 0 ||
1913 os_strcmp(buf, "wmm_enabled") == 0) {
1914 bss->wmm_enabled = atoi(pos);
1915 } else if (os_strcmp(buf, "uapsd_advertisement_enabled") == 0) {
1916 bss->wmm_uapsd = atoi(pos);
1917 } else if (os_strncmp(buf, "wme_ac_", 7) == 0 ||
1918 os_strncmp(buf, "wmm_ac_", 7) == 0) {
1919 if (hostapd_config_wmm_ac(conf, buf, pos)) {
1920 wpa_printf(MSG_ERROR, "Line %d: invalid WMM "
1921 "ac item", line);
1922 errors++;
1923 }
1924 } else if (os_strcmp(buf, "bss") == 0) {
1925 if (hostapd_config_bss(conf, pos)) {
1926 wpa_printf(MSG_ERROR, "Line %d: invalid bss "
1927 "item", line);
1928 errors++;
1929 }
1930 } else if (os_strcmp(buf, "bssid") == 0) {
1931 if (hwaddr_aton(pos, bss->bssid)) {
1932 wpa_printf(MSG_ERROR, "Line %d: invalid bssid "
1933 "item", line);
1934 errors++;
1935 }
1936#ifdef CONFIG_IEEE80211W
1937 } else if (os_strcmp(buf, "ieee80211w") == 0) {
1938 bss->ieee80211w = atoi(pos);
1939 } else if (os_strcmp(buf, "assoc_sa_query_max_timeout") == 0) {
1940 bss->assoc_sa_query_max_timeout = atoi(pos);
1941 if (bss->assoc_sa_query_max_timeout == 0) {
1942 wpa_printf(MSG_ERROR, "Line %d: invalid "
1943 "assoc_sa_query_max_timeout", line);
1944 errors++;
1945 }
1946 } else if (os_strcmp(buf, "assoc_sa_query_retry_timeout") == 0)
1947 {
1948 bss->assoc_sa_query_retry_timeout = atoi(pos);
1949 if (bss->assoc_sa_query_retry_timeout == 0) {
1950 wpa_printf(MSG_ERROR, "Line %d: invalid "
1951 "assoc_sa_query_retry_timeout",
1952 line);
1953 errors++;
1954 }
1955#endif /* CONFIG_IEEE80211W */
1956#ifdef CONFIG_IEEE80211N
1957 } else if (os_strcmp(buf, "ieee80211n") == 0) {
1958 conf->ieee80211n = atoi(pos);
1959 } else if (os_strcmp(buf, "ht_capab") == 0) {
1960 if (hostapd_config_ht_capab(conf, pos) < 0) {
1961 wpa_printf(MSG_ERROR, "Line %d: invalid "
1962 "ht_capab", line);
1963 errors++;
1964 }
1965 } else if (os_strcmp(buf, "require_ht") == 0) {
1966 conf->require_ht = atoi(pos);
1967#endif /* CONFIG_IEEE80211N */
1968 } else if (os_strcmp(buf, "max_listen_interval") == 0) {
1969 bss->max_listen_interval = atoi(pos);
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07001970 } else if (os_strcmp(buf, "disable_pmksa_caching") == 0) {
1971 bss->disable_pmksa_caching = atoi(pos);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001972 } else if (os_strcmp(buf, "okc") == 0) {
1973 bss->okc = atoi(pos);
1974#ifdef CONFIG_WPS
1975 } else if (os_strcmp(buf, "wps_state") == 0) {
1976 bss->wps_state = atoi(pos);
1977 if (bss->wps_state < 0 || bss->wps_state > 2) {
1978 wpa_printf(MSG_ERROR, "Line %d: invalid "
1979 "wps_state", line);
1980 errors++;
1981 }
1982 } else if (os_strcmp(buf, "ap_setup_locked") == 0) {
1983 bss->ap_setup_locked = atoi(pos);
1984 } else if (os_strcmp(buf, "uuid") == 0) {
1985 if (uuid_str2bin(pos, bss->uuid)) {
1986 wpa_printf(MSG_ERROR, "Line %d: invalid UUID",
1987 line);
1988 errors++;
1989 }
1990 } else if (os_strcmp(buf, "wps_pin_requests") == 0) {
1991 os_free(bss->wps_pin_requests);
1992 bss->wps_pin_requests = os_strdup(pos);
1993 } else if (os_strcmp(buf, "device_name") == 0) {
1994 if (os_strlen(pos) > 32) {
1995 wpa_printf(MSG_ERROR, "Line %d: Too long "
1996 "device_name", line);
1997 errors++;
1998 }
1999 os_free(bss->device_name);
2000 bss->device_name = os_strdup(pos);
2001 } else if (os_strcmp(buf, "manufacturer") == 0) {
2002 if (os_strlen(pos) > 64) {
2003 wpa_printf(MSG_ERROR, "Line %d: Too long "
2004 "manufacturer", line);
2005 errors++;
2006 }
2007 os_free(bss->manufacturer);
2008 bss->manufacturer = os_strdup(pos);
2009 } else if (os_strcmp(buf, "model_name") == 0) {
2010 if (os_strlen(pos) > 32) {
2011 wpa_printf(MSG_ERROR, "Line %d: Too long "
2012 "model_name", line);
2013 errors++;
2014 }
2015 os_free(bss->model_name);
2016 bss->model_name = os_strdup(pos);
2017 } else if (os_strcmp(buf, "model_number") == 0) {
2018 if (os_strlen(pos) > 32) {
2019 wpa_printf(MSG_ERROR, "Line %d: Too long "
2020 "model_number", line);
2021 errors++;
2022 }
2023 os_free(bss->model_number);
2024 bss->model_number = os_strdup(pos);
2025 } else if (os_strcmp(buf, "serial_number") == 0) {
2026 if (os_strlen(pos) > 32) {
2027 wpa_printf(MSG_ERROR, "Line %d: Too long "
2028 "serial_number", line);
2029 errors++;
2030 }
2031 os_free(bss->serial_number);
2032 bss->serial_number = os_strdup(pos);
2033 } else if (os_strcmp(buf, "device_type") == 0) {
2034 if (wps_dev_type_str2bin(pos, bss->device_type))
2035 errors++;
2036 } else if (os_strcmp(buf, "config_methods") == 0) {
2037 os_free(bss->config_methods);
2038 bss->config_methods = os_strdup(pos);
2039 } else if (os_strcmp(buf, "os_version") == 0) {
2040 if (hexstr2bin(pos, bss->os_version, 4)) {
2041 wpa_printf(MSG_ERROR, "Line %d: invalid "
2042 "os_version", line);
2043 errors++;
2044 }
2045 } else if (os_strcmp(buf, "ap_pin") == 0) {
2046 os_free(bss->ap_pin);
2047 bss->ap_pin = os_strdup(pos);
2048 } else if (os_strcmp(buf, "skip_cred_build") == 0) {
2049 bss->skip_cred_build = atoi(pos);
2050 } else if (os_strcmp(buf, "extra_cred") == 0) {
2051 os_free(bss->extra_cred);
2052 bss->extra_cred =
2053 (u8 *) os_readfile(pos, &bss->extra_cred_len);
2054 if (bss->extra_cred == NULL) {
2055 wpa_printf(MSG_ERROR, "Line %d: could not "
2056 "read Credentials from '%s'",
2057 line, pos);
2058 errors++;
2059 }
2060 } else if (os_strcmp(buf, "wps_cred_processing") == 0) {
2061 bss->wps_cred_processing = atoi(pos);
2062 } else if (os_strcmp(buf, "ap_settings") == 0) {
2063 os_free(bss->ap_settings);
2064 bss->ap_settings =
2065 (u8 *) os_readfile(pos, &bss->ap_settings_len);
2066 if (bss->ap_settings == NULL) {
2067 wpa_printf(MSG_ERROR, "Line %d: could not "
2068 "read AP Settings from '%s'",
2069 line, pos);
2070 errors++;
2071 }
2072 } else if (os_strcmp(buf, "upnp_iface") == 0) {
2073 bss->upnp_iface = os_strdup(pos);
2074 } else if (os_strcmp(buf, "friendly_name") == 0) {
2075 os_free(bss->friendly_name);
2076 bss->friendly_name = os_strdup(pos);
2077 } else if (os_strcmp(buf, "manufacturer_url") == 0) {
2078 os_free(bss->manufacturer_url);
2079 bss->manufacturer_url = os_strdup(pos);
2080 } else if (os_strcmp(buf, "model_description") == 0) {
2081 os_free(bss->model_description);
2082 bss->model_description = os_strdup(pos);
2083 } else if (os_strcmp(buf, "model_url") == 0) {
2084 os_free(bss->model_url);
2085 bss->model_url = os_strdup(pos);
2086 } else if (os_strcmp(buf, "upc") == 0) {
2087 os_free(bss->upc);
2088 bss->upc = os_strdup(pos);
Jouni Malinen87fd2792011-05-16 18:35:42 +03002089 } else if (os_strcmp(buf, "pbc_in_m1") == 0) {
2090 bss->pbc_in_m1 = atoi(pos);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002091#endif /* CONFIG_WPS */
2092#ifdef CONFIG_P2P_MANAGER
2093 } else if (os_strcmp(buf, "manage_p2p") == 0) {
2094 int manage = atoi(pos);
2095 if (manage)
2096 bss->p2p |= P2P_MANAGE;
2097 else
2098 bss->p2p &= ~P2P_MANAGE;
2099 } else if (os_strcmp(buf, "allow_cross_connection") == 0) {
2100 if (atoi(pos))
2101 bss->p2p |= P2P_ALLOW_CROSS_CONNECTION;
2102 else
2103 bss->p2p &= ~P2P_ALLOW_CROSS_CONNECTION;
2104#endif /* CONFIG_P2P_MANAGER */
2105 } else if (os_strcmp(buf, "disassoc_low_ack") == 0) {
2106 bss->disassoc_low_ack = atoi(pos);
2107 } else if (os_strcmp(buf, "tdls_prohibit") == 0) {
2108 int val = atoi(pos);
2109 if (val)
2110 bss->tdls |= TDLS_PROHIBIT;
2111 else
2112 bss->tdls &= ~TDLS_PROHIBIT;
2113 } else if (os_strcmp(buf, "tdls_prohibit_chan_switch") == 0) {
2114 int val = atoi(pos);
2115 if (val)
2116 bss->tdls |= TDLS_PROHIBIT_CHAN_SWITCH;
2117 else
2118 bss->tdls &= ~TDLS_PROHIBIT_CHAN_SWITCH;
2119#ifdef CONFIG_RSN_TESTING
2120 } else if (os_strcmp(buf, "rsn_testing") == 0) {
2121 extern int rsn_testing;
2122 rsn_testing = atoi(pos);
2123#endif /* CONFIG_RSN_TESTING */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002124 } else if (os_strcmp(buf, "time_advertisement") == 0) {
2125 bss->time_advertisement = atoi(pos);
2126 } else if (os_strcmp(buf, "time_zone") == 0) {
2127 size_t tz_len = os_strlen(pos);
2128 if (tz_len < 4 || tz_len > 255) {
2129 wpa_printf(MSG_DEBUG, "Line %d: invalid "
2130 "time_zone", line);
2131 errors++;
2132 continue;
2133 }
2134 os_free(bss->time_zone);
2135 bss->time_zone = os_strdup(pos);
2136 if (bss->time_zone == NULL)
2137 errors++;
2138#ifdef CONFIG_INTERWORKING
2139 } else if (os_strcmp(buf, "interworking") == 0) {
2140 bss->interworking = atoi(pos);
2141 } else if (os_strcmp(buf, "access_network_type") == 0) {
2142 bss->access_network_type = atoi(pos);
2143 if (bss->access_network_type < 0 ||
2144 bss->access_network_type > 15) {
2145 wpa_printf(MSG_ERROR, "Line %d: invalid "
2146 "access_network_type", line);
2147 errors++;
2148 }
2149 } else if (os_strcmp(buf, "internet") == 0) {
2150 bss->internet = atoi(pos);
2151 } else if (os_strcmp(buf, "asra") == 0) {
2152 bss->asra = atoi(pos);
2153 } else if (os_strcmp(buf, "esr") == 0) {
2154 bss->esr = atoi(pos);
2155 } else if (os_strcmp(buf, "uesa") == 0) {
2156 bss->uesa = atoi(pos);
2157 } else if (os_strcmp(buf, "venue_group") == 0) {
2158 bss->venue_group = atoi(pos);
2159 bss->venue_info_set = 1;
2160 } else if (os_strcmp(buf, "venue_type") == 0) {
2161 bss->venue_type = atoi(pos);
2162 bss->venue_info_set = 1;
2163 } else if (os_strcmp(buf, "hessid") == 0) {
2164 if (hwaddr_aton(pos, bss->hessid)) {
2165 wpa_printf(MSG_ERROR, "Line %d: invalid "
2166 "hessid", line);
2167 errors++;
2168 }
2169 } else if (os_strcmp(buf, "roaming_consortium") == 0) {
2170 if (parse_roaming_consortium(bss, pos, line) < 0)
2171 errors++;
2172#endif /* CONFIG_INTERWORKING */
2173#ifdef CONFIG_RADIUS_TEST
2174 } else if (os_strcmp(buf, "dump_msk_file") == 0) {
2175 os_free(bss->dump_msk_file);
2176 bss->dump_msk_file = os_strdup(pos);
2177#endif /* CONFIG_RADIUS_TEST */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002178 } else {
2179 wpa_printf(MSG_ERROR, "Line %d: unknown configuration "
2180 "item '%s'", line, buf);
2181 errors++;
2182 }
2183 }
2184
2185 fclose(f);
2186
2187 for (i = 0; i < conf->num_bss; i++) {
2188 bss = &conf->bss[i];
2189
2190 if (bss->individual_wep_key_len == 0) {
2191 /* individual keys are not use; can use key idx0 for
2192 * broadcast keys */
2193 bss->broadcast_key_idx_min = 0;
2194 }
2195
2196 /* Select group cipher based on the enabled pairwise cipher
2197 * suites */
2198 pairwise = 0;
2199 if (bss->wpa & 1)
2200 pairwise |= bss->wpa_pairwise;
2201 if (bss->wpa & 2) {
2202 if (bss->rsn_pairwise == 0)
2203 bss->rsn_pairwise = bss->wpa_pairwise;
2204 pairwise |= bss->rsn_pairwise;
2205 }
2206 if (pairwise & WPA_CIPHER_TKIP)
2207 bss->wpa_group = WPA_CIPHER_TKIP;
2208 else
2209 bss->wpa_group = WPA_CIPHER_CCMP;
2210
2211 bss->radius->auth_server = bss->radius->auth_servers;
2212 bss->radius->acct_server = bss->radius->acct_servers;
2213
2214 if (bss->wpa && bss->ieee802_1x) {
2215 bss->ssid.security_policy = SECURITY_WPA;
2216 } else if (bss->wpa) {
2217 bss->ssid.security_policy = SECURITY_WPA_PSK;
2218 } else if (bss->ieee802_1x) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002219 int cipher = WPA_CIPHER_NONE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002220 bss->ssid.security_policy = SECURITY_IEEE_802_1X;
2221 bss->ssid.wep.default_len = bss->default_wep_key_len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002222 if (bss->default_wep_key_len)
2223 cipher = bss->default_wep_key_len >= 13 ?
2224 WPA_CIPHER_WEP104 : WPA_CIPHER_WEP40;
2225 bss->wpa_group = cipher;
2226 bss->wpa_pairwise = cipher;
2227 bss->rsn_pairwise = cipher;
2228 } else if (bss->ssid.wep.keys_set) {
2229 int cipher = WPA_CIPHER_WEP40;
2230 if (bss->ssid.wep.len[0] >= 13)
2231 cipher = WPA_CIPHER_WEP104;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002232 bss->ssid.security_policy = SECURITY_STATIC_WEP;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002233 bss->wpa_group = cipher;
2234 bss->wpa_pairwise = cipher;
2235 bss->rsn_pairwise = cipher;
2236 } else {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002237 bss->ssid.security_policy = SECURITY_PLAINTEXT;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002238 bss->wpa_group = WPA_CIPHER_NONE;
2239 bss->wpa_pairwise = WPA_CIPHER_NONE;
2240 bss->rsn_pairwise = WPA_CIPHER_NONE;
2241 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002242 }
2243
2244 if (hostapd_config_check(conf))
2245 errors++;
2246
2247#ifndef WPA_IGNORE_CONFIG_ERRORS
2248 if (errors) {
2249 wpa_printf(MSG_ERROR, "%d errors found in configuration file "
2250 "'%s'", errors, fname);
2251 hostapd_config_free(conf);
2252 conf = NULL;
2253 }
2254#endif /* WPA_IGNORE_CONFIG_ERRORS */
2255
2256 return conf;
2257}