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