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