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