]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/wpa/hostapd/config_file.c
Update hostapd/wpa_supplicant to 2.8 to fix multiple vulnerabilities.
[FreeBSD/FreeBSD.git] / contrib / wpa / hostapd / config_file.c
1 /*
2  * hostapd / Configuration file parser
3  * Copyright (c) 2003-2018, 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 "crypto/sha256.h"
18 #include "crypto/tls.h"
19 #include "drivers/driver.h"
20 #include "eap_server/eap.h"
21 #include "radius/radius_client.h"
22 #include "ap/wpa_auth.h"
23 #include "ap/ap_config.h"
24 #include "config_file.h"
25
26
27 #ifndef CONFIG_NO_RADIUS
28 #ifdef EAP_SERVER
29 static struct hostapd_radius_attr *
30 hostapd_parse_radius_attr(const char *value);
31 #endif /* EAP_SERVER */
32 #endif /* CONFIG_NO_RADIUS */
33
34
35 #ifndef CONFIG_NO_VLAN
36 static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
37                                          const char *fname)
38 {
39         FILE *f;
40         char buf[128], *pos, *pos2, *pos3;
41         int line = 0, vlan_id;
42         struct hostapd_vlan *vlan;
43
44         f = fopen(fname, "r");
45         if (!f) {
46                 wpa_printf(MSG_ERROR, "VLAN file '%s' not readable.", fname);
47                 return -1;
48         }
49
50         while (fgets(buf, sizeof(buf), f)) {
51                 line++;
52
53                 if (buf[0] == '#')
54                         continue;
55                 pos = buf;
56                 while (*pos != '\0') {
57                         if (*pos == '\n') {
58                                 *pos = '\0';
59                                 break;
60                         }
61                         pos++;
62                 }
63                 if (buf[0] == '\0')
64                         continue;
65
66                 if (buf[0] == '*') {
67                         vlan_id = VLAN_ID_WILDCARD;
68                         pos = buf + 1;
69                 } else {
70                         vlan_id = strtol(buf, &pos, 10);
71                         if (buf == pos || vlan_id < 1 ||
72                             vlan_id > MAX_VLAN_ID) {
73                                 wpa_printf(MSG_ERROR, "Invalid VLAN ID at "
74                                            "line %d in '%s'", line, fname);
75                                 fclose(f);
76                                 return -1;
77                         }
78                 }
79
80                 while (*pos == ' ' || *pos == '\t')
81                         pos++;
82                 pos2 = pos;
83                 while (*pos2 != ' ' && *pos2 != '\t' && *pos2 != '\0')
84                         pos2++;
85
86                 if (*pos2 != '\0')
87                         *(pos2++) = '\0';
88
89                 if (*pos == '\0' || os_strlen(pos) > IFNAMSIZ) {
90                         wpa_printf(MSG_ERROR, "Invalid VLAN ifname at line %d "
91                                    "in '%s'", line, fname);
92                         fclose(f);
93                         return -1;
94                 }
95
96                 while (*pos2 == ' ' || *pos2 == '\t')
97                         pos2++;
98                 pos3 = pos2;
99                 while (*pos3 != ' ' && *pos3 != '\t' && *pos3 != '\0')
100                         pos3++;
101                 *pos3 = '\0';
102
103                 vlan = os_zalloc(sizeof(*vlan));
104                 if (vlan == NULL) {
105                         wpa_printf(MSG_ERROR, "Out of memory while reading "
106                                    "VLAN interfaces from '%s'", fname);
107                         fclose(f);
108                         return -1;
109                 }
110
111                 vlan->vlan_id = vlan_id;
112                 vlan->vlan_desc.untagged = vlan_id;
113                 vlan->vlan_desc.notempty = !!vlan_id;
114                 os_strlcpy(vlan->ifname, pos, sizeof(vlan->ifname));
115                 os_strlcpy(vlan->bridge, pos2, sizeof(vlan->bridge));
116                 vlan->next = bss->vlan;
117                 bss->vlan = vlan;
118         }
119
120         fclose(f);
121
122         return 0;
123 }
124 #endif /* CONFIG_NO_VLAN */
125
126
127 int hostapd_acl_comp(const void *a, const void *b)
128 {
129         const struct mac_acl_entry *aa = a;
130         const struct mac_acl_entry *bb = b;
131         return os_memcmp(aa->addr, bb->addr, sizeof(macaddr));
132 }
133
134
135 int hostapd_add_acl_maclist(struct mac_acl_entry **acl, int *num,
136                             int vlan_id, const u8 *addr)
137 {
138         struct mac_acl_entry *newacl;
139
140         newacl = os_realloc_array(*acl, *num + 1, sizeof(**acl));
141         if (!newacl) {
142                 wpa_printf(MSG_ERROR, "MAC list reallocation failed");
143                 return -1;
144         }
145
146         *acl = newacl;
147         os_memcpy((*acl)[*num].addr, addr, ETH_ALEN);
148         os_memset(&(*acl)[*num].vlan_id, 0, sizeof((*acl)[*num].vlan_id));
149         (*acl)[*num].vlan_id.untagged = vlan_id;
150         (*acl)[*num].vlan_id.notempty = !!vlan_id;
151         (*num)++;
152
153         return 0;
154 }
155
156
157 void hostapd_remove_acl_mac(struct mac_acl_entry **acl, int *num,
158                             const u8 *addr)
159 {
160         int i = 0;
161
162         while (i < *num) {
163                 if (os_memcmp((*acl)[i].addr, addr, ETH_ALEN) == 0) {
164                         os_remove_in_array(*acl, *num, sizeof(**acl), i);
165                         (*num)--;
166                 } else {
167                         i++;
168                 }
169         }
170 }
171
172
173 static int hostapd_config_read_maclist(const char *fname,
174                                        struct mac_acl_entry **acl, int *num)
175 {
176         FILE *f;
177         char buf[128], *pos;
178         int line = 0;
179         u8 addr[ETH_ALEN];
180         int vlan_id;
181
182         f = fopen(fname, "r");
183         if (!f) {
184                 wpa_printf(MSG_ERROR, "MAC list file '%s' not found.", fname);
185                 return -1;
186         }
187
188         while (fgets(buf, sizeof(buf), f)) {
189                 int rem = 0;
190
191                 line++;
192
193                 if (buf[0] == '#')
194                         continue;
195                 pos = buf;
196                 while (*pos != '\0') {
197                         if (*pos == '\n') {
198                                 *pos = '\0';
199                                 break;
200                         }
201                         pos++;
202                 }
203                 if (buf[0] == '\0')
204                         continue;
205                 pos = buf;
206                 if (buf[0] == '-') {
207                         rem = 1;
208                         pos++;
209                 }
210
211                 if (hwaddr_aton(pos, addr)) {
212                         wpa_printf(MSG_ERROR, "Invalid MAC address '%s' at "
213                                    "line %d in '%s'", pos, line, fname);
214                         fclose(f);
215                         return -1;
216                 }
217
218                 if (rem) {
219                         hostapd_remove_acl_mac(acl, num, addr);
220                         continue;
221                 }
222                 vlan_id = 0;
223                 pos = buf;
224                 while (*pos != '\0' && *pos != ' ' && *pos != '\t')
225                         pos++;
226                 while (*pos == ' ' || *pos == '\t')
227                         pos++;
228                 if (*pos != '\0')
229                         vlan_id = atoi(pos);
230
231                 if (hostapd_add_acl_maclist(acl, num, vlan_id, addr) < 0) {
232                         fclose(f);
233                         return -1;
234                 }
235         }
236
237         fclose(f);
238
239         if (*acl)
240                 qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp);
241
242         return 0;
243 }
244
245
246 #ifdef EAP_SERVER
247
248 static int hostapd_config_eap_user_salted(struct hostapd_eap_user *user,
249                                           const char *hash, size_t len,
250                                           char **pos, int line,
251                                           const char *fname)
252 {
253         char *pos2 = *pos;
254
255         while (*pos2 != '\0' && *pos2 != ' ' && *pos2 != '\t' && *pos2 != '#')
256                 pos2++;
257
258         if (pos2 - *pos < (int) (2 * (len + 1))) { /* at least 1 byte of salt */
259                 wpa_printf(MSG_ERROR,
260                            "Invalid salted %s hash on line %d in '%s'",
261                            hash, line, fname);
262                 return -1;
263         }
264
265         user->password = os_malloc(len);
266         if (!user->password) {
267                 wpa_printf(MSG_ERROR,
268                            "Failed to allocate memory for salted %s hash",
269                            hash);
270                 return -1;
271         }
272
273         if (hexstr2bin(*pos, user->password, len) < 0) {
274                 wpa_printf(MSG_ERROR,
275                            "Invalid salted password on line %d in '%s'",
276                            line, fname);
277                 return -1;
278         }
279         user->password_len = len;
280         *pos += 2 * len;
281
282         user->salt_len = (pos2 - *pos) / 2;
283         user->salt = os_malloc(user->salt_len);
284         if (!user->salt) {
285                 wpa_printf(MSG_ERROR,
286                            "Failed to allocate memory for salted %s hash",
287                            hash);
288                 return -1;
289         }
290
291         if (hexstr2bin(*pos, user->salt, user->salt_len) < 0) {
292                 wpa_printf(MSG_ERROR,
293                            "Invalid salt for password on line %d in '%s'",
294                            line, fname);
295                 return -1;
296         }
297
298         *pos = pos2;
299         return 0;
300 }
301
302
303 static int hostapd_config_read_eap_user(const char *fname,
304                                         struct hostapd_bss_config *conf)
305 {
306         FILE *f;
307         char buf[512], *pos, *start, *pos2;
308         int line = 0, ret = 0, num_methods;
309         struct hostapd_eap_user *user = NULL, *tail = NULL, *new_user = NULL;
310
311         if (os_strncmp(fname, "sqlite:", 7) == 0) {
312 #ifdef CONFIG_SQLITE
313                 os_free(conf->eap_user_sqlite);
314                 conf->eap_user_sqlite = os_strdup(fname + 7);
315                 return 0;
316 #else /* CONFIG_SQLITE */
317                 wpa_printf(MSG_ERROR,
318                            "EAP user file in SQLite DB, but CONFIG_SQLITE was not enabled in the build.");
319                 return -1;
320 #endif /* CONFIG_SQLITE */
321         }
322
323         f = fopen(fname, "r");
324         if (!f) {
325                 wpa_printf(MSG_ERROR, "EAP user file '%s' not found.", fname);
326                 return -1;
327         }
328
329         /* Lines: "user" METHOD,METHOD2 "password" (password optional) */
330         while (fgets(buf, sizeof(buf), f)) {
331                 line++;
332
333                 if (buf[0] == '#')
334                         continue;
335                 pos = buf;
336                 while (*pos != '\0') {
337                         if (*pos == '\n') {
338                                 *pos = '\0';
339                                 break;
340                         }
341                         pos++;
342                 }
343                 if (buf[0] == '\0')
344                         continue;
345
346 #ifndef CONFIG_NO_RADIUS
347                 if (user && os_strncmp(buf, "radius_accept_attr=", 19) == 0) {
348                         struct hostapd_radius_attr *attr, *a;
349                         attr = hostapd_parse_radius_attr(buf + 19);
350                         if (attr == NULL) {
351                                 wpa_printf(MSG_ERROR, "Invalid radius_auth_req_attr: %s",
352                                            buf + 19);
353                                 user = NULL; /* already in the BSS list */
354                                 goto failed;
355                         }
356                         if (user->accept_attr == NULL) {
357                                 user->accept_attr = attr;
358                         } else {
359                                 a = user->accept_attr;
360                                 while (a->next)
361                                         a = a->next;
362                                 a->next = attr;
363                         }
364                         continue;
365                 }
366 #endif /* CONFIG_NO_RADIUS */
367
368                 user = NULL;
369
370                 if (buf[0] != '"' && buf[0] != '*') {
371                         wpa_printf(MSG_ERROR, "Invalid EAP identity (no \" in "
372                                    "start) on line %d in '%s'", line, fname);
373                         goto failed;
374                 }
375
376                 user = os_zalloc(sizeof(*user));
377                 if (user == NULL) {
378                         wpa_printf(MSG_ERROR, "EAP user allocation failed");
379                         goto failed;
380                 }
381                 user->force_version = -1;
382
383                 if (buf[0] == '*') {
384                         pos = buf;
385                 } else {
386                         pos = buf + 1;
387                         start = pos;
388                         while (*pos != '"' && *pos != '\0')
389                                 pos++;
390                         if (*pos == '\0') {
391                                 wpa_printf(MSG_ERROR, "Invalid EAP identity "
392                                            "(no \" in end) on line %d in '%s'",
393                                            line, fname);
394                                 goto failed;
395                         }
396
397                         user->identity = os_memdup(start, pos - start);
398                         if (user->identity == NULL) {
399                                 wpa_printf(MSG_ERROR, "Failed to allocate "
400                                            "memory for EAP identity");
401                                 goto failed;
402                         }
403                         user->identity_len = pos - start;
404
405                         if (pos[0] == '"' && pos[1] == '*') {
406                                 user->wildcard_prefix = 1;
407                                 pos++;
408                         }
409                 }
410                 pos++;
411                 while (*pos == ' ' || *pos == '\t')
412                         pos++;
413
414                 if (*pos == '\0') {
415                         wpa_printf(MSG_ERROR, "No EAP method on line %d in "
416                                    "'%s'", line, fname);
417                         goto failed;
418                 }
419
420                 start = pos;
421                 while (*pos != ' ' && *pos != '\t' && *pos != '\0')
422                         pos++;
423                 if (*pos == '\0') {
424                         pos = NULL;
425                 } else {
426                         *pos = '\0';
427                         pos++;
428                 }
429                 num_methods = 0;
430                 while (*start) {
431                         char *pos3 = os_strchr(start, ',');
432                         if (pos3) {
433                                 *pos3++ = '\0';
434                         }
435                         user->methods[num_methods].method =
436                                 eap_server_get_type(
437                                         start,
438                                         &user->methods[num_methods].vendor);
439                         if (user->methods[num_methods].vendor ==
440                             EAP_VENDOR_IETF &&
441                             user->methods[num_methods].method == EAP_TYPE_NONE)
442                         {
443                                 if (os_strcmp(start, "TTLS-PAP") == 0) {
444                                         user->ttls_auth |= EAP_TTLS_AUTH_PAP;
445                                         goto skip_eap;
446                                 }
447                                 if (os_strcmp(start, "TTLS-CHAP") == 0) {
448                                         user->ttls_auth |= EAP_TTLS_AUTH_CHAP;
449                                         goto skip_eap;
450                                 }
451                                 if (os_strcmp(start, "TTLS-MSCHAP") == 0) {
452                                         user->ttls_auth |=
453                                                 EAP_TTLS_AUTH_MSCHAP;
454                                         goto skip_eap;
455                                 }
456                                 if (os_strcmp(start, "TTLS-MSCHAPV2") == 0) {
457                                         user->ttls_auth |=
458                                                 EAP_TTLS_AUTH_MSCHAPV2;
459                                         goto skip_eap;
460                                 }
461                                 if (os_strcmp(start, "MACACL") == 0) {
462                                         user->macacl = 1;
463                                         goto skip_eap;
464                                 }
465                                 wpa_printf(MSG_ERROR, "Unsupported EAP type "
466                                            "'%s' on line %d in '%s'",
467                                            start, line, fname);
468                                 goto failed;
469                         }
470
471                         num_methods++;
472                         if (num_methods >= EAP_MAX_METHODS)
473                                 break;
474                 skip_eap:
475                         if (pos3 == NULL)
476                                 break;
477                         start = pos3;
478                 }
479                 if (num_methods == 0 && user->ttls_auth == 0 && !user->macacl) {
480                         wpa_printf(MSG_ERROR, "No EAP types configured on "
481                                    "line %d in '%s'", line, fname);
482                         goto failed;
483                 }
484
485                 if (pos == NULL)
486                         goto done;
487
488                 while (*pos == ' ' || *pos == '\t')
489                         pos++;
490                 if (*pos == '\0')
491                         goto done;
492
493                 if (os_strncmp(pos, "[ver=0]", 7) == 0) {
494                         user->force_version = 0;
495                         goto done;
496                 }
497
498                 if (os_strncmp(pos, "[ver=1]", 7) == 0) {
499                         user->force_version = 1;
500                         goto done;
501                 }
502
503                 if (os_strncmp(pos, "[2]", 3) == 0) {
504                         user->phase2 = 1;
505                         goto done;
506                 }
507
508                 if (*pos == '"') {
509                         pos++;
510                         start = pos;
511                         while (*pos != '"' && *pos != '\0')
512                                 pos++;
513                         if (*pos == '\0') {
514                                 wpa_printf(MSG_ERROR, "Invalid EAP password "
515                                            "(no \" in end) on line %d in '%s'",
516                                            line, fname);
517                                 goto failed;
518                         }
519
520                         user->password = os_memdup(start, pos - start);
521                         if (user->password == NULL) {
522                                 wpa_printf(MSG_ERROR, "Failed to allocate "
523                                            "memory for EAP password");
524                                 goto failed;
525                         }
526                         user->password_len = pos - start;
527
528                         pos++;
529                 } else if (os_strncmp(pos, "hash:", 5) == 0) {
530                         pos += 5;
531                         pos2 = pos;
532                         while (*pos2 != '\0' && *pos2 != ' ' &&
533                                *pos2 != '\t' && *pos2 != '#')
534                                 pos2++;
535                         if (pos2 - pos != 32) {
536                                 wpa_printf(MSG_ERROR, "Invalid password hash "
537                                            "on line %d in '%s'", line, fname);
538                                 goto failed;
539                         }
540                         user->password = os_malloc(16);
541                         if (user->password == NULL) {
542                                 wpa_printf(MSG_ERROR, "Failed to allocate "
543                                            "memory for EAP password hash");
544                                 goto failed;
545                         }
546                         if (hexstr2bin(pos, user->password, 16) < 0) {
547                                 wpa_printf(MSG_ERROR, "Invalid hash password "
548                                            "on line %d in '%s'", line, fname);
549                                 goto failed;
550                         }
551                         user->password_len = 16;
552                         user->password_hash = 1;
553                         pos = pos2;
554                 } else if (os_strncmp(pos, "ssha1:", 6) == 0) {
555                         pos += 6;
556                         if (hostapd_config_eap_user_salted(user, "sha1", 20,
557                                                            &pos,
558                                                            line, fname) < 0)
559                                 goto failed;
560                 } else if (os_strncmp(pos, "ssha256:", 8) == 0) {
561                         pos += 8;
562                         if (hostapd_config_eap_user_salted(user, "sha256", 32,
563                                                            &pos,
564                                                            line, fname) < 0)
565                                 goto failed;
566                 } else if (os_strncmp(pos, "ssha512:", 8) == 0) {
567                         pos += 8;
568                         if (hostapd_config_eap_user_salted(user, "sha512", 64,
569                                                            &pos,
570                                                            line, fname) < 0)
571                                 goto failed;
572                 } else {
573                         pos2 = pos;
574                         while (*pos2 != '\0' && *pos2 != ' ' &&
575                                *pos2 != '\t' && *pos2 != '#')
576                                 pos2++;
577                         if ((pos2 - pos) & 1) {
578                                 wpa_printf(MSG_ERROR, "Invalid hex password "
579                                            "on line %d in '%s'", line, fname);
580                                 goto failed;
581                         }
582                         user->password = os_malloc((pos2 - pos) / 2);
583                         if (user->password == NULL) {
584                                 wpa_printf(MSG_ERROR, "Failed to allocate "
585                                            "memory for EAP password");
586                                 goto failed;
587                         }
588                         if (hexstr2bin(pos, user->password,
589                                        (pos2 - pos) / 2) < 0) {
590                                 wpa_printf(MSG_ERROR, "Invalid hex password "
591                                            "on line %d in '%s'", line, fname);
592                                 goto failed;
593                         }
594                         user->password_len = (pos2 - pos) / 2;
595                         pos = pos2;
596                 }
597
598                 while (*pos == ' ' || *pos == '\t')
599                         pos++;
600                 if (os_strncmp(pos, "[2]", 3) == 0) {
601                         user->phase2 = 1;
602                 }
603
604         done:
605                 if (tail == NULL) {
606                         tail = new_user = user;
607                 } else {
608                         tail->next = user;
609                         tail = user;
610                 }
611                 continue;
612
613         failed:
614                 if (user)
615                         hostapd_config_free_eap_user(user);
616                 ret = -1;
617                 break;
618         }
619
620         fclose(f);
621
622         if (ret == 0) {
623                 hostapd_config_free_eap_users(conf->eap_user);
624                 conf->eap_user = new_user;
625         } else {
626                 hostapd_config_free_eap_users(new_user);
627         }
628
629         return ret;
630 }
631
632 #endif /* EAP_SERVER */
633
634
635 #ifndef CONFIG_NO_RADIUS
636 static int
637 hostapd_config_read_radius_addr(struct hostapd_radius_server **server,
638                                 int *num_server, const char *val, int def_port,
639                                 struct hostapd_radius_server **curr_serv)
640 {
641         struct hostapd_radius_server *nserv;
642         int ret;
643         static int server_index = 1;
644
645         nserv = os_realloc_array(*server, *num_server + 1, sizeof(*nserv));
646         if (nserv == NULL)
647                 return -1;
648
649         *server = nserv;
650         nserv = &nserv[*num_server];
651         (*num_server)++;
652         (*curr_serv) = nserv;
653
654         os_memset(nserv, 0, sizeof(*nserv));
655         nserv->port = def_port;
656         ret = hostapd_parse_ip_addr(val, &nserv->addr);
657         nserv->index = server_index++;
658
659         return ret;
660 }
661
662
663 static struct hostapd_radius_attr *
664 hostapd_parse_radius_attr(const char *value)
665 {
666         const char *pos;
667         char syntax;
668         struct hostapd_radius_attr *attr;
669         size_t len;
670
671         attr = os_zalloc(sizeof(*attr));
672         if (attr == NULL)
673                 return NULL;
674
675         attr->type = atoi(value);
676
677         pos = os_strchr(value, ':');
678         if (pos == NULL) {
679                 attr->val = wpabuf_alloc(1);
680                 if (attr->val == NULL) {
681                         os_free(attr);
682                         return NULL;
683                 }
684                 wpabuf_put_u8(attr->val, 0);
685                 return attr;
686         }
687
688         pos++;
689         if (pos[0] == '\0' || pos[1] != ':') {
690                 os_free(attr);
691                 return NULL;
692         }
693         syntax = *pos++;
694         pos++;
695
696         switch (syntax) {
697         case 's':
698                 attr->val = wpabuf_alloc_copy(pos, os_strlen(pos));
699                 break;
700         case 'x':
701                 len = os_strlen(pos);
702                 if (len & 1)
703                         break;
704                 len /= 2;
705                 attr->val = wpabuf_alloc(len);
706                 if (attr->val == NULL)
707                         break;
708                 if (hexstr2bin(pos, wpabuf_put(attr->val, len), len) < 0) {
709                         wpabuf_free(attr->val);
710                         os_free(attr);
711                         return NULL;
712                 }
713                 break;
714         case 'd':
715                 attr->val = wpabuf_alloc(4);
716                 if (attr->val)
717                         wpabuf_put_be32(attr->val, atoi(pos));
718                 break;
719         default:
720                 os_free(attr);
721                 return NULL;
722         }
723
724         if (attr->val == NULL) {
725                 os_free(attr);
726                 return NULL;
727         }
728
729         return attr;
730 }
731
732
733 static int hostapd_parse_das_client(struct hostapd_bss_config *bss, char *val)
734 {
735         char *secret;
736
737         secret = os_strchr(val, ' ');
738         if (secret == NULL)
739                 return -1;
740
741         *secret++ = '\0';
742
743         if (hostapd_parse_ip_addr(val, &bss->radius_das_client_addr))
744                 return -1;
745
746         os_free(bss->radius_das_shared_secret);
747         bss->radius_das_shared_secret = (u8 *) os_strdup(secret);
748         if (bss->radius_das_shared_secret == NULL)
749                 return -1;
750         bss->radius_das_shared_secret_len = os_strlen(secret);
751
752         return 0;
753 }
754 #endif /* CONFIG_NO_RADIUS */
755
756
757 static int hostapd_config_parse_key_mgmt(int line, const char *value)
758 {
759         int val = 0, last;
760         char *start, *end, *buf;
761
762         buf = os_strdup(value);
763         if (buf == NULL)
764                 return -1;
765         start = buf;
766
767         while (*start != '\0') {
768                 while (*start == ' ' || *start == '\t')
769                         start++;
770                 if (*start == '\0')
771                         break;
772                 end = start;
773                 while (*end != ' ' && *end != '\t' && *end != '\0')
774                         end++;
775                 last = *end == '\0';
776                 *end = '\0';
777                 if (os_strcmp(start, "WPA-PSK") == 0)
778                         val |= WPA_KEY_MGMT_PSK;
779                 else if (os_strcmp(start, "WPA-EAP") == 0)
780                         val |= WPA_KEY_MGMT_IEEE8021X;
781 #ifdef CONFIG_IEEE80211R_AP
782                 else if (os_strcmp(start, "FT-PSK") == 0)
783                         val |= WPA_KEY_MGMT_FT_PSK;
784                 else if (os_strcmp(start, "FT-EAP") == 0)
785                         val |= WPA_KEY_MGMT_FT_IEEE8021X;
786 #ifdef CONFIG_SHA384
787                 else if (os_strcmp(start, "FT-EAP-SHA384") == 0)
788                         val |= WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
789 #endif /* CONFIG_SHA384 */
790 #endif /* CONFIG_IEEE80211R_AP */
791 #ifdef CONFIG_IEEE80211W
792                 else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
793                         val |= WPA_KEY_MGMT_PSK_SHA256;
794                 else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
795                         val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
796 #endif /* CONFIG_IEEE80211W */
797 #ifdef CONFIG_SAE
798                 else if (os_strcmp(start, "SAE") == 0)
799                         val |= WPA_KEY_MGMT_SAE;
800                 else if (os_strcmp(start, "FT-SAE") == 0)
801                         val |= WPA_KEY_MGMT_FT_SAE;
802 #endif /* CONFIG_SAE */
803 #ifdef CONFIG_SUITEB
804                 else if (os_strcmp(start, "WPA-EAP-SUITE-B") == 0)
805                         val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B;
806 #endif /* CONFIG_SUITEB */
807 #ifdef CONFIG_SUITEB192
808                 else if (os_strcmp(start, "WPA-EAP-SUITE-B-192") == 0)
809                         val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
810 #endif /* CONFIG_SUITEB192 */
811 #ifdef CONFIG_FILS
812                 else if (os_strcmp(start, "FILS-SHA256") == 0)
813                         val |= WPA_KEY_MGMT_FILS_SHA256;
814                 else if (os_strcmp(start, "FILS-SHA384") == 0)
815                         val |= WPA_KEY_MGMT_FILS_SHA384;
816 #ifdef CONFIG_IEEE80211R_AP
817                 else if (os_strcmp(start, "FT-FILS-SHA256") == 0)
818                         val |= WPA_KEY_MGMT_FT_FILS_SHA256;
819                 else if (os_strcmp(start, "FT-FILS-SHA384") == 0)
820                         val |= WPA_KEY_MGMT_FT_FILS_SHA384;
821 #endif /* CONFIG_IEEE80211R_AP */
822 #endif /* CONFIG_FILS */
823 #ifdef CONFIG_OWE
824                 else if (os_strcmp(start, "OWE") == 0)
825                         val |= WPA_KEY_MGMT_OWE;
826 #endif /* CONFIG_OWE */
827 #ifdef CONFIG_DPP
828                 else if (os_strcmp(start, "DPP") == 0)
829                         val |= WPA_KEY_MGMT_DPP;
830 #endif /* CONFIG_DPP */
831 #ifdef CONFIG_HS20
832                 else if (os_strcmp(start, "OSEN") == 0)
833                         val |= WPA_KEY_MGMT_OSEN;
834 #endif /* CONFIG_HS20 */
835                 else {
836                         wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
837                                    line, start);
838                         os_free(buf);
839                         return -1;
840                 }
841
842                 if (last)
843                         break;
844                 start = end + 1;
845         }
846
847         os_free(buf);
848         if (val == 0) {
849                 wpa_printf(MSG_ERROR, "Line %d: no key_mgmt values "
850                            "configured.", line);
851                 return -1;
852         }
853
854         return val;
855 }
856
857
858 static int hostapd_config_parse_cipher(int line, const char *value)
859 {
860         int val = wpa_parse_cipher(value);
861         if (val < 0) {
862                 wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
863                            line, value);
864                 return -1;
865         }
866         if (val == 0) {
867                 wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.",
868                            line);
869                 return -1;
870         }
871         return val;
872 }
873
874
875 static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
876                                    char *val)
877 {
878         size_t len = os_strlen(val);
879
880         if (keyidx < 0 || keyidx > 3)
881                 return -1;
882
883         if (len == 0) {
884                 int i, set = 0;
885
886                 bin_clear_free(wep->key[keyidx], wep->len[keyidx]);
887                 wep->key[keyidx] = NULL;
888                 wep->len[keyidx] = 0;
889                 for (i = 0; i < NUM_WEP_KEYS; i++) {
890                         if (wep->key[i])
891                                 set++;
892                 }
893                 if (!set)
894                         wep->keys_set = 0;
895                 return 0;
896         }
897
898         if (wep->key[keyidx] != NULL)
899                 return -1;
900
901         if (val[0] == '"') {
902                 if (len < 2 || val[len - 1] != '"')
903                         return -1;
904                 len -= 2;
905                 wep->key[keyidx] = os_memdup(val + 1, len);
906                 if (wep->key[keyidx] == NULL)
907                         return -1;
908                 wep->len[keyidx] = len;
909         } else {
910                 if (len & 1)
911                         return -1;
912                 len /= 2;
913                 wep->key[keyidx] = os_malloc(len);
914                 if (wep->key[keyidx] == NULL)
915                         return -1;
916                 wep->len[keyidx] = len;
917                 if (hexstr2bin(val, wep->key[keyidx], len) < 0)
918                         return -1;
919         }
920
921         wep->keys_set++;
922
923         return 0;
924 }
925
926
927 static int hostapd_parse_chanlist(struct hostapd_config *conf, char *val)
928 {
929         char *pos;
930
931         /* for backwards compatibility, translate ' ' in conf str to ',' */
932         pos = val;
933         while (pos) {
934                 pos = os_strchr(pos, ' ');
935                 if (pos)
936                         *pos++ = ',';
937         }
938         if (freq_range_list_parse(&conf->acs_ch_list, val))
939                 return -1;
940
941         return 0;
942 }
943
944
945 static int hostapd_parse_intlist(int **int_list, char *val)
946 {
947         int *list;
948         int count;
949         char *pos, *end;
950
951         os_free(*int_list);
952         *int_list = NULL;
953
954         pos = val;
955         count = 0;
956         while (*pos != '\0') {
957                 if (*pos == ' ')
958                         count++;
959                 pos++;
960         }
961
962         list = os_malloc(sizeof(int) * (count + 2));
963         if (list == NULL)
964                 return -1;
965         pos = val;
966         count = 0;
967         while (*pos != '\0') {
968                 end = os_strchr(pos, ' ');
969                 if (end)
970                         *end = '\0';
971
972                 list[count++] = atoi(pos);
973                 if (!end)
974                         break;
975                 pos = end + 1;
976         }
977         list[count] = -1;
978
979         *int_list = list;
980         return 0;
981 }
982
983
984 static int hostapd_config_bss(struct hostapd_config *conf, const char *ifname)
985 {
986         struct hostapd_bss_config **all, *bss;
987
988         if (*ifname == '\0')
989                 return -1;
990
991         all = os_realloc_array(conf->bss, conf->num_bss + 1,
992                                sizeof(struct hostapd_bss_config *));
993         if (all == NULL) {
994                 wpa_printf(MSG_ERROR, "Failed to allocate memory for "
995                            "multi-BSS entry");
996                 return -1;
997         }
998         conf->bss = all;
999
1000         bss = os_zalloc(sizeof(*bss));
1001         if (bss == NULL)
1002                 return -1;
1003         bss->radius = os_zalloc(sizeof(*bss->radius));
1004         if (bss->radius == NULL) {
1005                 wpa_printf(MSG_ERROR, "Failed to allocate memory for "
1006                            "multi-BSS RADIUS data");
1007                 os_free(bss);
1008                 return -1;
1009         }
1010
1011         conf->bss[conf->num_bss++] = bss;
1012         conf->last_bss = bss;
1013
1014         hostapd_config_defaults_bss(bss);
1015         os_strlcpy(bss->iface, ifname, sizeof(bss->iface));
1016         os_memcpy(bss->ssid.vlan, bss->iface, IFNAMSIZ + 1);
1017
1018         return 0;
1019 }
1020
1021
1022 /* convert floats with one decimal place to value*10 int, i.e.,
1023  * "1.5" will return 15 */
1024 static int hostapd_config_read_int10(const char *value)
1025 {
1026         int i, d;
1027         char *pos;
1028
1029         i = atoi(value);
1030         pos = os_strchr(value, '.');
1031         d = 0;
1032         if (pos) {
1033                 pos++;
1034                 if (*pos >= '0' && *pos <= '9')
1035                         d = *pos - '0';
1036         }
1037
1038         return i * 10 + d;
1039 }
1040
1041
1042 static int valid_cw(int cw)
1043 {
1044         return (cw == 1 || cw == 3 || cw == 7 || cw == 15 || cw == 31 ||
1045                 cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023 ||
1046                 cw == 2047 || cw == 4095 || cw == 8191 || cw == 16383 ||
1047                 cw == 32767);
1048 }
1049
1050
1051 enum {
1052         IEEE80211_TX_QUEUE_DATA0 = 0, /* used for EDCA AC_VO data */
1053         IEEE80211_TX_QUEUE_DATA1 = 1, /* used for EDCA AC_VI data */
1054         IEEE80211_TX_QUEUE_DATA2 = 2, /* used for EDCA AC_BE data */
1055         IEEE80211_TX_QUEUE_DATA3 = 3 /* used for EDCA AC_BK data */
1056 };
1057
1058 static int hostapd_config_tx_queue(struct hostapd_config *conf,
1059                                    const char *name, const char *val)
1060 {
1061         int num;
1062         const char *pos;
1063         struct hostapd_tx_queue_params *queue;
1064
1065         /* skip 'tx_queue_' prefix */
1066         pos = name + 9;
1067         if (os_strncmp(pos, "data", 4) == 0 &&
1068             pos[4] >= '0' && pos[4] <= '9' && pos[5] == '_') {
1069                 num = pos[4] - '0';
1070                 pos += 6;
1071         } else if (os_strncmp(pos, "after_beacon_", 13) == 0 ||
1072                    os_strncmp(pos, "beacon_", 7) == 0) {
1073                 wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
1074                 return 0;
1075         } else {
1076                 wpa_printf(MSG_ERROR, "Unknown tx_queue name '%s'", pos);
1077                 return -1;
1078         }
1079
1080         if (num >= NUM_TX_QUEUES) {
1081                 /* for backwards compatibility, do not trigger failure */
1082                 wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
1083                 return 0;
1084         }
1085
1086         queue = &conf->tx_queue[num];
1087
1088         if (os_strcmp(pos, "aifs") == 0) {
1089                 queue->aifs = atoi(val);
1090                 if (queue->aifs < 0 || queue->aifs > 255) {
1091                         wpa_printf(MSG_ERROR, "Invalid AIFS value %d",
1092                                    queue->aifs);
1093                         return -1;
1094                 }
1095         } else if (os_strcmp(pos, "cwmin") == 0) {
1096                 queue->cwmin = atoi(val);
1097                 if (!valid_cw(queue->cwmin)) {
1098                         wpa_printf(MSG_ERROR, "Invalid cwMin value %d",
1099                                    queue->cwmin);
1100                         return -1;
1101                 }
1102         } else if (os_strcmp(pos, "cwmax") == 0) {
1103                 queue->cwmax = atoi(val);
1104                 if (!valid_cw(queue->cwmax)) {
1105                         wpa_printf(MSG_ERROR, "Invalid cwMax value %d",
1106                                    queue->cwmax);
1107                         return -1;
1108                 }
1109         } else if (os_strcmp(pos, "burst") == 0) {
1110                 queue->burst = hostapd_config_read_int10(val);
1111         } else {
1112                 wpa_printf(MSG_ERROR, "Unknown tx_queue field '%s'", pos);
1113                 return -1;
1114         }
1115
1116         return 0;
1117 }
1118
1119
1120 #ifdef CONFIG_IEEE80211R_AP
1121
1122 static int rkh_derive_key(const char *pos, u8 *key, size_t key_len)
1123 {
1124         u8 oldkey[16];
1125         int ret;
1126
1127         if (!hexstr2bin(pos, key, key_len))
1128                 return 0;
1129
1130         /* Try to use old short key for backwards compatibility */
1131         if (hexstr2bin(pos, oldkey, sizeof(oldkey)))
1132                 return -1;
1133
1134         ret = hmac_sha256_kdf(oldkey, sizeof(oldkey), "FT OLDKEY", NULL, 0,
1135                               key, key_len);
1136         os_memset(oldkey, 0, sizeof(oldkey));
1137         return ret;
1138 }
1139
1140
1141 static int add_r0kh(struct hostapd_bss_config *bss, char *value)
1142 {
1143         struct ft_remote_r0kh *r0kh;
1144         char *pos, *next;
1145
1146         r0kh = os_zalloc(sizeof(*r0kh));
1147         if (r0kh == NULL)
1148                 return -1;
1149
1150         /* 02:01:02:03:04:05 a.example.com 000102030405060708090a0b0c0d0e0f */
1151         pos = value;
1152         next = os_strchr(pos, ' ');
1153         if (next)
1154                 *next++ = '\0';
1155         if (next == NULL || hwaddr_aton(pos, r0kh->addr)) {
1156                 wpa_printf(MSG_ERROR, "Invalid R0KH MAC address: '%s'", pos);
1157                 os_free(r0kh);
1158                 return -1;
1159         }
1160
1161         pos = next;
1162         next = os_strchr(pos, ' ');
1163         if (next)
1164                 *next++ = '\0';
1165         if (next == NULL || next - pos > FT_R0KH_ID_MAX_LEN) {
1166                 wpa_printf(MSG_ERROR, "Invalid R0KH-ID: '%s'", pos);
1167                 os_free(r0kh);
1168                 return -1;
1169         }
1170         r0kh->id_len = next - pos - 1;
1171         os_memcpy(r0kh->id, pos, r0kh->id_len);
1172
1173         pos = next;
1174         if (rkh_derive_key(pos, r0kh->key, sizeof(r0kh->key)) < 0) {
1175                 wpa_printf(MSG_ERROR, "Invalid R0KH key: '%s'", pos);
1176                 os_free(r0kh);
1177                 return -1;
1178         }
1179
1180         r0kh->next = bss->r0kh_list;
1181         bss->r0kh_list = r0kh;
1182
1183         return 0;
1184 }
1185
1186
1187 static int add_r1kh(struct hostapd_bss_config *bss, char *value)
1188 {
1189         struct ft_remote_r1kh *r1kh;
1190         char *pos, *next;
1191
1192         r1kh = os_zalloc(sizeof(*r1kh));
1193         if (r1kh == NULL)
1194                 return -1;
1195
1196         /* 02:01:02:03:04:05 02:01:02:03:04:05
1197          * 000102030405060708090a0b0c0d0e0f */
1198         pos = value;
1199         next = os_strchr(pos, ' ');
1200         if (next)
1201                 *next++ = '\0';
1202         if (next == NULL || hwaddr_aton(pos, r1kh->addr)) {
1203                 wpa_printf(MSG_ERROR, "Invalid R1KH MAC address: '%s'", pos);
1204                 os_free(r1kh);
1205                 return -1;
1206         }
1207
1208         pos = next;
1209         next = os_strchr(pos, ' ');
1210         if (next)
1211                 *next++ = '\0';
1212         if (next == NULL || hwaddr_aton(pos, r1kh->id)) {
1213                 wpa_printf(MSG_ERROR, "Invalid R1KH-ID: '%s'", pos);
1214                 os_free(r1kh);
1215                 return -1;
1216         }
1217
1218         pos = next;
1219         if (rkh_derive_key(pos, r1kh->key, sizeof(r1kh->key)) < 0) {
1220                 wpa_printf(MSG_ERROR, "Invalid R1KH key: '%s'", pos);
1221                 os_free(r1kh);
1222                 return -1;
1223         }
1224
1225         r1kh->next = bss->r1kh_list;
1226         bss->r1kh_list = r1kh;
1227
1228         return 0;
1229 }
1230 #endif /* CONFIG_IEEE80211R_AP */
1231
1232
1233 #ifdef CONFIG_IEEE80211N
1234 static int hostapd_config_ht_capab(struct hostapd_config *conf,
1235                                    const char *capab)
1236 {
1237         if (os_strstr(capab, "[LDPC]"))
1238                 conf->ht_capab |= HT_CAP_INFO_LDPC_CODING_CAP;
1239         if (os_strstr(capab, "[HT40-]")) {
1240                 conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
1241                 conf->secondary_channel = -1;
1242         }
1243         if (os_strstr(capab, "[HT40+]")) {
1244                 conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
1245                 conf->secondary_channel = 1;
1246         }
1247         if (os_strstr(capab, "[HT40+]") && os_strstr(capab, "[HT40-]")) {
1248                 conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
1249                 conf->ht40_plus_minus_allowed = 1;
1250         }
1251         if (!os_strstr(capab, "[HT40+]") && !os_strstr(capab, "[HT40-]"))
1252                 conf->secondary_channel = 0;
1253         if (os_strstr(capab, "[SMPS-STATIC]")) {
1254                 conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK;
1255                 conf->ht_capab |= HT_CAP_INFO_SMPS_STATIC;
1256         }
1257         if (os_strstr(capab, "[SMPS-DYNAMIC]")) {
1258                 conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK;
1259                 conf->ht_capab |= HT_CAP_INFO_SMPS_DYNAMIC;
1260         }
1261         if (os_strstr(capab, "[GF]"))
1262                 conf->ht_capab |= HT_CAP_INFO_GREEN_FIELD;
1263         if (os_strstr(capab, "[SHORT-GI-20]"))
1264                 conf->ht_capab |= HT_CAP_INFO_SHORT_GI20MHZ;
1265         if (os_strstr(capab, "[SHORT-GI-40]"))
1266                 conf->ht_capab |= HT_CAP_INFO_SHORT_GI40MHZ;
1267         if (os_strstr(capab, "[TX-STBC]"))
1268                 conf->ht_capab |= HT_CAP_INFO_TX_STBC;
1269         if (os_strstr(capab, "[RX-STBC1]")) {
1270                 conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK;
1271                 conf->ht_capab |= HT_CAP_INFO_RX_STBC_1;
1272         }
1273         if (os_strstr(capab, "[RX-STBC12]")) {
1274                 conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK;
1275                 conf->ht_capab |= HT_CAP_INFO_RX_STBC_12;
1276         }
1277         if (os_strstr(capab, "[RX-STBC123]")) {
1278                 conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK;
1279                 conf->ht_capab |= HT_CAP_INFO_RX_STBC_123;
1280         }
1281         if (os_strstr(capab, "[DELAYED-BA]"))
1282                 conf->ht_capab |= HT_CAP_INFO_DELAYED_BA;
1283         if (os_strstr(capab, "[MAX-AMSDU-7935]"))
1284                 conf->ht_capab |= HT_CAP_INFO_MAX_AMSDU_SIZE;
1285         if (os_strstr(capab, "[DSSS_CCK-40]"))
1286                 conf->ht_capab |= HT_CAP_INFO_DSSS_CCK40MHZ;
1287         if (os_strstr(capab, "[40-INTOLERANT]"))
1288                 conf->ht_capab |= HT_CAP_INFO_40MHZ_INTOLERANT;
1289         if (os_strstr(capab, "[LSIG-TXOP-PROT]"))
1290                 conf->ht_capab |= HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT;
1291
1292         return 0;
1293 }
1294 #endif /* CONFIG_IEEE80211N */
1295
1296
1297 #ifdef CONFIG_IEEE80211AC
1298 static int hostapd_config_vht_capab(struct hostapd_config *conf,
1299                                     const char *capab)
1300 {
1301         if (os_strstr(capab, "[MAX-MPDU-7991]"))
1302                 conf->vht_capab |= VHT_CAP_MAX_MPDU_LENGTH_7991;
1303         if (os_strstr(capab, "[MAX-MPDU-11454]"))
1304                 conf->vht_capab |= VHT_CAP_MAX_MPDU_LENGTH_11454;
1305         if (os_strstr(capab, "[VHT160]"))
1306                 conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
1307         if (os_strstr(capab, "[VHT160-80PLUS80]"))
1308                 conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
1309         if (os_strstr(capab, "[RXLDPC]"))
1310                 conf->vht_capab |= VHT_CAP_RXLDPC;
1311         if (os_strstr(capab, "[SHORT-GI-80]"))
1312                 conf->vht_capab |= VHT_CAP_SHORT_GI_80;
1313         if (os_strstr(capab, "[SHORT-GI-160]"))
1314                 conf->vht_capab |= VHT_CAP_SHORT_GI_160;
1315         if (os_strstr(capab, "[TX-STBC-2BY1]"))
1316                 conf->vht_capab |= VHT_CAP_TXSTBC;
1317         if (os_strstr(capab, "[RX-STBC-1]"))
1318                 conf->vht_capab |= VHT_CAP_RXSTBC_1;
1319         if (os_strstr(capab, "[RX-STBC-12]"))
1320                 conf->vht_capab |= VHT_CAP_RXSTBC_2;
1321         if (os_strstr(capab, "[RX-STBC-123]"))
1322                 conf->vht_capab |= VHT_CAP_RXSTBC_3;
1323         if (os_strstr(capab, "[RX-STBC-1234]"))
1324                 conf->vht_capab |= VHT_CAP_RXSTBC_4;
1325         if (os_strstr(capab, "[SU-BEAMFORMER]"))
1326                 conf->vht_capab |= VHT_CAP_SU_BEAMFORMER_CAPABLE;
1327         if (os_strstr(capab, "[SU-BEAMFORMEE]"))
1328                 conf->vht_capab |= VHT_CAP_SU_BEAMFORMEE_CAPABLE;
1329         if (os_strstr(capab, "[BF-ANTENNA-2]") &&
1330             (conf->vht_capab & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
1331                 conf->vht_capab |= (1 << VHT_CAP_BEAMFORMEE_STS_OFFSET);
1332         if (os_strstr(capab, "[BF-ANTENNA-3]") &&
1333             (conf->vht_capab & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
1334                 conf->vht_capab |= (2 << VHT_CAP_BEAMFORMEE_STS_OFFSET);
1335         if (os_strstr(capab, "[BF-ANTENNA-4]") &&
1336             (conf->vht_capab & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
1337                 conf->vht_capab |= (3 << VHT_CAP_BEAMFORMEE_STS_OFFSET);
1338         if (os_strstr(capab, "[SOUNDING-DIMENSION-2]") &&
1339             (conf->vht_capab & VHT_CAP_SU_BEAMFORMER_CAPABLE))
1340                 conf->vht_capab |= (1 << VHT_CAP_SOUNDING_DIMENSION_OFFSET);
1341         if (os_strstr(capab, "[SOUNDING-DIMENSION-3]") &&
1342             (conf->vht_capab & VHT_CAP_SU_BEAMFORMER_CAPABLE))
1343                 conf->vht_capab |= (2 << VHT_CAP_SOUNDING_DIMENSION_OFFSET);
1344         if (os_strstr(capab, "[SOUNDING-DIMENSION-4]") &&
1345             (conf->vht_capab & VHT_CAP_SU_BEAMFORMER_CAPABLE))
1346                 conf->vht_capab |= (3 << VHT_CAP_SOUNDING_DIMENSION_OFFSET);
1347         if (os_strstr(capab, "[MU-BEAMFORMER]"))
1348                 conf->vht_capab |= VHT_CAP_MU_BEAMFORMER_CAPABLE;
1349         if (os_strstr(capab, "[VHT-TXOP-PS]"))
1350                 conf->vht_capab |= VHT_CAP_VHT_TXOP_PS;
1351         if (os_strstr(capab, "[HTC-VHT]"))
1352                 conf->vht_capab |= VHT_CAP_HTC_VHT;
1353         if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP7]"))
1354                 conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX;
1355         else if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP6]"))
1356                 conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_6;
1357         else if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP5]"))
1358                 conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_5;
1359         else if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP4]"))
1360                 conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_4;
1361         else if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP3]"))
1362                 conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_3;
1363         else if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP2]"))
1364                 conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_2;
1365         else if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP1]"))
1366                 conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_1;
1367         if (os_strstr(capab, "[VHT-LINK-ADAPT2]") &&
1368             (conf->vht_capab & VHT_CAP_HTC_VHT))
1369                 conf->vht_capab |= VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB;
1370         if (os_strstr(capab, "[VHT-LINK-ADAPT3]") &&
1371             (conf->vht_capab & VHT_CAP_HTC_VHT))
1372                 conf->vht_capab |= VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
1373         if (os_strstr(capab, "[RX-ANTENNA-PATTERN]"))
1374                 conf->vht_capab |= VHT_CAP_RX_ANTENNA_PATTERN;
1375         if (os_strstr(capab, "[TX-ANTENNA-PATTERN]"))
1376                 conf->vht_capab |= VHT_CAP_TX_ANTENNA_PATTERN;
1377         return 0;
1378 }
1379 #endif /* CONFIG_IEEE80211AC */
1380
1381
1382 #ifdef CONFIG_IEEE80211AX
1383
1384 static u8 find_bit_offset(u8 val)
1385 {
1386         u8 res = 0;
1387
1388         for (; val; val >>= 1) {
1389                 if (val & 1)
1390                         break;
1391                 res++;
1392         }
1393
1394         return res;
1395 }
1396
1397
1398 static u8 set_he_cap(int val, u8 mask)
1399 {
1400         return (u8) (mask & (val << find_bit_offset(mask)));
1401 }
1402
1403 #endif /* CONFIG_IEEE80211AX */
1404
1405
1406 #ifdef CONFIG_INTERWORKING
1407 static int parse_roaming_consortium(struct hostapd_bss_config *bss, char *pos,
1408                                     int line)
1409 {
1410         size_t len = os_strlen(pos);
1411         u8 oi[MAX_ROAMING_CONSORTIUM_LEN];
1412
1413         struct hostapd_roaming_consortium *rc;
1414
1415         if ((len & 1) || len < 2 * 3 || len / 2 > MAX_ROAMING_CONSORTIUM_LEN ||
1416             hexstr2bin(pos, oi, len / 2)) {
1417                 wpa_printf(MSG_ERROR, "Line %d: invalid roaming_consortium "
1418                            "'%s'", line, pos);
1419                 return -1;
1420         }
1421         len /= 2;
1422
1423         rc = os_realloc_array(bss->roaming_consortium,
1424                               bss->roaming_consortium_count + 1,
1425                               sizeof(struct hostapd_roaming_consortium));
1426         if (rc == NULL)
1427                 return -1;
1428
1429         os_memcpy(rc[bss->roaming_consortium_count].oi, oi, len);
1430         rc[bss->roaming_consortium_count].len = len;
1431
1432         bss->roaming_consortium = rc;
1433         bss->roaming_consortium_count++;
1434
1435         return 0;
1436 }
1437
1438
1439 static int parse_lang_string(struct hostapd_lang_string **array,
1440                              unsigned int *count, char *pos)
1441 {
1442         char *sep, *str = NULL;
1443         size_t clen, nlen, slen;
1444         struct hostapd_lang_string *ls;
1445         int ret = -1;
1446
1447         if (*pos == '"' || (*pos == 'P' && pos[1] == '"')) {
1448                 str = wpa_config_parse_string(pos, &slen);
1449                 if (!str)
1450                         return -1;
1451                 pos = str;
1452         }
1453
1454         sep = os_strchr(pos, ':');
1455         if (sep == NULL)
1456                 goto fail;
1457         *sep++ = '\0';
1458
1459         clen = os_strlen(pos);
1460         if (clen < 2 || clen > sizeof(ls->lang))
1461                 goto fail;
1462         nlen = os_strlen(sep);
1463         if (nlen > 252)
1464                 goto fail;
1465
1466         ls = os_realloc_array(*array, *count + 1,
1467                               sizeof(struct hostapd_lang_string));
1468         if (ls == NULL)
1469                 goto fail;
1470
1471         *array = ls;
1472         ls = &(*array)[*count];
1473         (*count)++;
1474
1475         os_memset(ls->lang, 0, sizeof(ls->lang));
1476         os_memcpy(ls->lang, pos, clen);
1477         ls->name_len = nlen;
1478         os_memcpy(ls->name, sep, nlen);
1479
1480         ret = 0;
1481 fail:
1482         os_free(str);
1483         return ret;
1484 }
1485
1486
1487 static int parse_venue_name(struct hostapd_bss_config *bss, char *pos,
1488                             int line)
1489 {
1490         if (parse_lang_string(&bss->venue_name, &bss->venue_name_count, pos)) {
1491                 wpa_printf(MSG_ERROR, "Line %d: Invalid venue_name '%s'",
1492                            line, pos);
1493                 return -1;
1494         }
1495         return 0;
1496 }
1497
1498
1499 static int parse_venue_url(struct hostapd_bss_config *bss, char *pos,
1500                             int line)
1501 {
1502         char *sep;
1503         size_t nlen;
1504         struct hostapd_venue_url *url;
1505         int ret = -1;
1506
1507         sep = os_strchr(pos, ':');
1508         if (!sep)
1509                 goto fail;
1510         *sep++ = '\0';
1511
1512         nlen = os_strlen(sep);
1513         if (nlen > 254)
1514                 goto fail;
1515
1516         url = os_realloc_array(bss->venue_url, bss->venue_url_count + 1,
1517                                sizeof(struct hostapd_venue_url));
1518         if (!url)
1519                 goto fail;
1520
1521         bss->venue_url = url;
1522         url = &bss->venue_url[bss->venue_url_count++];
1523
1524         url->venue_number = atoi(pos);
1525         url->url_len = nlen;
1526         os_memcpy(url->url, sep, nlen);
1527
1528         ret = 0;
1529 fail:
1530         if (ret)
1531                 wpa_printf(MSG_ERROR, "Line %d: Invalid venue_url '%s'",
1532                            line, pos);
1533         return ret;
1534 }
1535
1536
1537 static int parse_3gpp_cell_net(struct hostapd_bss_config *bss, char *buf,
1538                                int line)
1539 {
1540         size_t count;
1541         char *pos;
1542         u8 *info = NULL, *ipos;
1543
1544         /* format: <MCC1,MNC1>[;<MCC2,MNC2>][;...] */
1545
1546         count = 1;
1547         for (pos = buf; *pos; pos++) {
1548                 if ((*pos < '0' || *pos > '9') && *pos != ';' && *pos != ',')
1549                         goto fail;
1550                 if (*pos == ';')
1551                         count++;
1552         }
1553         if (1 + count * 3 > 0x7f)
1554                 goto fail;
1555
1556         info = os_zalloc(2 + 3 + count * 3);
1557         if (info == NULL)
1558                 return -1;
1559
1560         ipos = info;
1561         *ipos++ = 0; /* GUD - Version 1 */
1562         *ipos++ = 3 + count * 3; /* User Data Header Length (UDHL) */
1563         *ipos++ = 0; /* PLMN List IEI */
1564         /* ext(b8) | Length of PLMN List value contents(b7..1) */
1565         *ipos++ = 1 + count * 3;
1566         *ipos++ = count; /* Number of PLMNs */
1567
1568         pos = buf;
1569         while (pos && *pos) {
1570                 char *mcc, *mnc;
1571                 size_t mnc_len;
1572
1573                 mcc = pos;
1574                 mnc = os_strchr(pos, ',');
1575                 if (mnc == NULL)
1576                         goto fail;
1577                 *mnc++ = '\0';
1578                 pos = os_strchr(mnc, ';');
1579                 if (pos)
1580                         *pos++ = '\0';
1581
1582                 mnc_len = os_strlen(mnc);
1583                 if (os_strlen(mcc) != 3 || (mnc_len != 2 && mnc_len != 3))
1584                         goto fail;
1585
1586                 /* BC coded MCC,MNC */
1587                 /* MCC digit 2 | MCC digit 1 */
1588                 *ipos++ = ((mcc[1] - '0') << 4) | (mcc[0] - '0');
1589                 /* MNC digit 3 | MCC digit 3 */
1590                 *ipos++ = (((mnc_len == 2) ? 0xf0 : ((mnc[2] - '0') << 4))) |
1591                         (mcc[2] - '0');
1592                 /* MNC digit 2 | MNC digit 1 */
1593                 *ipos++ = ((mnc[1] - '0') << 4) | (mnc[0] - '0');
1594         }
1595
1596         os_free(bss->anqp_3gpp_cell_net);
1597         bss->anqp_3gpp_cell_net = info;
1598         bss->anqp_3gpp_cell_net_len = 2 + 3 + 3 * count;
1599         wpa_hexdump(MSG_MSGDUMP, "3GPP Cellular Network information",
1600                     bss->anqp_3gpp_cell_net, bss->anqp_3gpp_cell_net_len);
1601
1602         return 0;
1603
1604 fail:
1605         wpa_printf(MSG_ERROR, "Line %d: Invalid anqp_3gpp_cell_net: %s",
1606                    line, buf);
1607         os_free(info);
1608         return -1;
1609 }
1610
1611
1612 static int parse_nai_realm(struct hostapd_bss_config *bss, char *buf, int line)
1613 {
1614         struct hostapd_nai_realm_data *realm;
1615         size_t i, j, len;
1616         int *offsets;
1617         char *pos, *end, *rpos;
1618
1619         offsets = os_calloc(bss->nai_realm_count * MAX_NAI_REALMS,
1620                             sizeof(int));
1621         if (offsets == NULL)
1622                 return -1;
1623
1624         for (i = 0; i < bss->nai_realm_count; i++) {
1625                 realm = &bss->nai_realm_data[i];
1626                 for (j = 0; j < MAX_NAI_REALMS; j++) {
1627                         offsets[i * MAX_NAI_REALMS + j] =
1628                                 realm->realm[j] ?
1629                                 realm->realm[j] - realm->realm_buf : -1;
1630                 }
1631         }
1632
1633         realm = os_realloc_array(bss->nai_realm_data, bss->nai_realm_count + 1,
1634                                  sizeof(struct hostapd_nai_realm_data));
1635         if (realm == NULL) {
1636                 os_free(offsets);
1637                 return -1;
1638         }
1639         bss->nai_realm_data = realm;
1640
1641         /* patch the pointers after realloc */
1642         for (i = 0; i < bss->nai_realm_count; i++) {
1643                 realm = &bss->nai_realm_data[i];
1644                 for (j = 0; j < MAX_NAI_REALMS; j++) {
1645                         int offs = offsets[i * MAX_NAI_REALMS + j];
1646                         if (offs >= 0)
1647                                 realm->realm[j] = realm->realm_buf + offs;
1648                         else
1649                                 realm->realm[j] = NULL;
1650                 }
1651         }
1652         os_free(offsets);
1653
1654         realm = &bss->nai_realm_data[bss->nai_realm_count];
1655         os_memset(realm, 0, sizeof(*realm));
1656
1657         pos = buf;
1658         realm->encoding = atoi(pos);
1659         pos = os_strchr(pos, ',');
1660         if (pos == NULL)
1661                 goto fail;
1662         pos++;
1663
1664         end = os_strchr(pos, ',');
1665         if (end) {
1666                 len = end - pos;
1667                 *end = '\0';
1668         } else {
1669                 len = os_strlen(pos);
1670         }
1671
1672         if (len > MAX_NAI_REALMLEN) {
1673                 wpa_printf(MSG_ERROR, "Too long a realm string (%d > max %d "
1674                            "characters)", (int) len, MAX_NAI_REALMLEN);
1675                 goto fail;
1676         }
1677         os_memcpy(realm->realm_buf, pos, len);
1678
1679         if (end)
1680                 pos = end + 1;
1681         else
1682                 pos = NULL;
1683
1684         while (pos && *pos) {
1685                 struct hostapd_nai_realm_eap *eap;
1686
1687                 if (realm->eap_method_count >= MAX_NAI_EAP_METHODS) {
1688                         wpa_printf(MSG_ERROR, "Too many EAP methods");
1689                         goto fail;
1690                 }
1691
1692                 eap = &realm->eap_method[realm->eap_method_count];
1693                 realm->eap_method_count++;
1694
1695                 end = os_strchr(pos, ',');
1696                 if (end == NULL)
1697                         end = pos + os_strlen(pos);
1698
1699                 eap->eap_method = atoi(pos);
1700                 for (;;) {
1701                         pos = os_strchr(pos, '[');
1702                         if (pos == NULL || pos > end)
1703                                 break;
1704                         pos++;
1705                         if (eap->num_auths >= MAX_NAI_AUTH_TYPES) {
1706                                 wpa_printf(MSG_ERROR, "Too many auth params");
1707                                 goto fail;
1708                         }
1709                         eap->auth_id[eap->num_auths] = atoi(pos);
1710                         pos = os_strchr(pos, ':');
1711                         if (pos == NULL || pos > end)
1712                                 goto fail;
1713                         pos++;
1714                         eap->auth_val[eap->num_auths] = atoi(pos);
1715                         pos = os_strchr(pos, ']');
1716                         if (pos == NULL || pos > end)
1717                                 goto fail;
1718                         pos++;
1719                         eap->num_auths++;
1720                 }
1721
1722                 if (*end != ',')
1723                         break;
1724
1725                 pos = end + 1;
1726         }
1727
1728         /* Split realm list into null terminated realms */
1729         rpos = realm->realm_buf;
1730         i = 0;
1731         while (*rpos) {
1732                 if (i >= MAX_NAI_REALMS) {
1733                         wpa_printf(MSG_ERROR, "Too many realms");
1734                         goto fail;
1735                 }
1736                 realm->realm[i++] = rpos;
1737                 rpos = os_strchr(rpos, ';');
1738                 if (rpos == NULL)
1739                         break;
1740                 *rpos++ = '\0';
1741         }
1742
1743         bss->nai_realm_count++;
1744
1745         return 0;
1746
1747 fail:
1748         wpa_printf(MSG_ERROR, "Line %d: invalid nai_realm '%s'", line, buf);
1749         return -1;
1750 }
1751
1752
1753 static int parse_anqp_elem(struct hostapd_bss_config *bss, char *buf, int line)
1754 {
1755         char *delim;
1756         u16 infoid;
1757         size_t len;
1758         struct wpabuf *payload;
1759         struct anqp_element *elem;
1760
1761         delim = os_strchr(buf, ':');
1762         if (!delim)
1763                 return -1;
1764         delim++;
1765         infoid = atoi(buf);
1766         len = os_strlen(delim);
1767         if (len & 1)
1768                 return -1;
1769         len /= 2;
1770         payload = wpabuf_alloc(len);
1771         if (!payload)
1772                 return -1;
1773         if (hexstr2bin(delim, wpabuf_put(payload, len), len) < 0) {
1774                 wpabuf_free(payload);
1775                 return -1;
1776         }
1777
1778         dl_list_for_each(elem, &bss->anqp_elem, struct anqp_element, list) {
1779                 if (elem->infoid == infoid) {
1780                         /* Update existing entry */
1781                         wpabuf_free(elem->payload);
1782                         elem->payload = payload;
1783                         return 0;
1784                 }
1785         }
1786
1787         /* Add a new entry */
1788         elem = os_zalloc(sizeof(*elem));
1789         if (!elem) {
1790                 wpabuf_free(payload);
1791                 return -1;
1792         }
1793         elem->infoid = infoid;
1794         elem->payload = payload;
1795         dl_list_add(&bss->anqp_elem, &elem->list);
1796
1797         return 0;
1798 }
1799
1800
1801 static int parse_qos_map_set(struct hostapd_bss_config *bss,
1802                              char *buf, int line)
1803 {
1804         u8 qos_map_set[16 + 2 * 21], count = 0;
1805         char *pos = buf;
1806         int val;
1807
1808         for (;;) {
1809                 if (count == sizeof(qos_map_set)) {
1810                         wpa_printf(MSG_ERROR, "Line %d: Too many qos_map_set "
1811                                    "parameters '%s'", line, buf);
1812                         return -1;
1813                 }
1814
1815                 val = atoi(pos);
1816                 if (val > 255 || val < 0) {
1817                         wpa_printf(MSG_ERROR, "Line %d: Invalid qos_map_set "
1818                                    "'%s'", line, buf);
1819                         return -1;
1820                 }
1821
1822                 qos_map_set[count++] = val;
1823                 pos = os_strchr(pos, ',');
1824                 if (!pos)
1825                         break;
1826                 pos++;
1827         }
1828
1829         if (count < 16 || count & 1) {
1830                 wpa_printf(MSG_ERROR, "Line %d: Invalid qos_map_set '%s'",
1831                            line, buf);
1832                 return -1;
1833         }
1834
1835         os_memcpy(bss->qos_map_set, qos_map_set, count);
1836         bss->qos_map_set_len = count;
1837
1838         return 0;
1839 }
1840
1841 #endif /* CONFIG_INTERWORKING */
1842
1843
1844 #ifdef CONFIG_HS20
1845 static int hs20_parse_conn_capab(struct hostapd_bss_config *bss, char *buf,
1846                                  int line)
1847 {
1848         u8 *conn_cap;
1849         char *pos;
1850
1851         if (bss->hs20_connection_capability_len >= 0xfff0)
1852                 return -1;
1853
1854         conn_cap = os_realloc(bss->hs20_connection_capability,
1855                               bss->hs20_connection_capability_len + 4);
1856         if (conn_cap == NULL)
1857                 return -1;
1858
1859         bss->hs20_connection_capability = conn_cap;
1860         conn_cap += bss->hs20_connection_capability_len;
1861         pos = buf;
1862         conn_cap[0] = atoi(pos);
1863         pos = os_strchr(pos, ':');
1864         if (pos == NULL)
1865                 return -1;
1866         pos++;
1867         WPA_PUT_LE16(conn_cap + 1, atoi(pos));
1868         pos = os_strchr(pos, ':');
1869         if (pos == NULL)
1870                 return -1;
1871         pos++;
1872         conn_cap[3] = atoi(pos);
1873         bss->hs20_connection_capability_len += 4;
1874
1875         return 0;
1876 }
1877
1878
1879 static int hs20_parse_wan_metrics(struct hostapd_bss_config *bss, char *buf,
1880                                   int line)
1881 {
1882         u8 *wan_metrics;
1883         char *pos;
1884
1885         /* <WAN Info>:<DL Speed>:<UL Speed>:<DL Load>:<UL Load>:<LMD> */
1886
1887         wan_metrics = os_zalloc(13);
1888         if (wan_metrics == NULL)
1889                 return -1;
1890
1891         pos = buf;
1892         /* WAN Info */
1893         if (hexstr2bin(pos, wan_metrics, 1) < 0)
1894                 goto fail;
1895         pos += 2;
1896         if (*pos != ':')
1897                 goto fail;
1898         pos++;
1899
1900         /* Downlink Speed */
1901         WPA_PUT_LE32(wan_metrics + 1, atoi(pos));
1902         pos = os_strchr(pos, ':');
1903         if (pos == NULL)
1904                 goto fail;
1905         pos++;
1906
1907         /* Uplink Speed */
1908         WPA_PUT_LE32(wan_metrics + 5, atoi(pos));
1909         pos = os_strchr(pos, ':');
1910         if (pos == NULL)
1911                 goto fail;
1912         pos++;
1913
1914         /* Downlink Load */
1915         wan_metrics[9] = atoi(pos);
1916         pos = os_strchr(pos, ':');
1917         if (pos == NULL)
1918                 goto fail;
1919         pos++;
1920
1921         /* Uplink Load */
1922         wan_metrics[10] = atoi(pos);
1923         pos = os_strchr(pos, ':');
1924         if (pos == NULL)
1925                 goto fail;
1926         pos++;
1927
1928         /* LMD */
1929         WPA_PUT_LE16(wan_metrics + 11, atoi(pos));
1930
1931         os_free(bss->hs20_wan_metrics);
1932         bss->hs20_wan_metrics = wan_metrics;
1933
1934         return 0;
1935
1936 fail:
1937         wpa_printf(MSG_ERROR, "Line %d: Invalid hs20_wan_metrics '%s'",
1938                    line, buf);
1939         os_free(wan_metrics);
1940         return -1;
1941 }
1942
1943
1944 static int hs20_parse_oper_friendly_name(struct hostapd_bss_config *bss,
1945                                          char *pos, int line)
1946 {
1947         if (parse_lang_string(&bss->hs20_oper_friendly_name,
1948                               &bss->hs20_oper_friendly_name_count, pos)) {
1949                 wpa_printf(MSG_ERROR, "Line %d: Invalid "
1950                            "hs20_oper_friendly_name '%s'", line, pos);
1951                 return -1;
1952         }
1953         return 0;
1954 }
1955
1956
1957 static int hs20_parse_icon(struct hostapd_bss_config *bss, char *pos)
1958 {
1959         struct hs20_icon *icon;
1960         char *end;
1961
1962         icon = os_realloc_array(bss->hs20_icons, bss->hs20_icons_count + 1,
1963                                 sizeof(struct hs20_icon));
1964         if (icon == NULL)
1965                 return -1;
1966         bss->hs20_icons = icon;
1967         icon = &bss->hs20_icons[bss->hs20_icons_count];
1968         os_memset(icon, 0, sizeof(*icon));
1969
1970         icon->width = atoi(pos);
1971         pos = os_strchr(pos, ':');
1972         if (pos == NULL)
1973                 return -1;
1974         pos++;
1975
1976         icon->height = atoi(pos);
1977         pos = os_strchr(pos, ':');
1978         if (pos == NULL)
1979                 return -1;
1980         pos++;
1981
1982         end = os_strchr(pos, ':');
1983         if (end == NULL || end - pos > 3)
1984                 return -1;
1985         os_memcpy(icon->language, pos, end - pos);
1986         pos = end + 1;
1987
1988         end = os_strchr(pos, ':');
1989         if (end == NULL || end - pos > 255)
1990                 return -1;
1991         os_memcpy(icon->type, pos, end - pos);
1992         pos = end + 1;
1993
1994         end = os_strchr(pos, ':');
1995         if (end == NULL || end - pos > 255)
1996                 return -1;
1997         os_memcpy(icon->name, pos, end - pos);
1998         pos = end + 1;
1999
2000         if (os_strlen(pos) > 255)
2001                 return -1;
2002         os_memcpy(icon->file, pos, os_strlen(pos));
2003
2004         bss->hs20_icons_count++;
2005
2006         return 0;
2007 }
2008
2009
2010 static int hs20_parse_osu_ssid(struct hostapd_bss_config *bss,
2011                                char *pos, int line)
2012 {
2013         size_t slen;
2014         char *str;
2015
2016         str = wpa_config_parse_string(pos, &slen);
2017         if (str == NULL || slen < 1 || slen > SSID_MAX_LEN) {
2018                 wpa_printf(MSG_ERROR, "Line %d: Invalid SSID '%s'", line, pos);
2019                 os_free(str);
2020                 return -1;
2021         }
2022
2023         os_memcpy(bss->osu_ssid, str, slen);
2024         bss->osu_ssid_len = slen;
2025         os_free(str);
2026
2027         return 0;
2028 }
2029
2030
2031 static int hs20_parse_osu_server_uri(struct hostapd_bss_config *bss,
2032                                      char *pos, int line)
2033 {
2034         struct hs20_osu_provider *p;
2035
2036         p = os_realloc_array(bss->hs20_osu_providers,
2037                              bss->hs20_osu_providers_count + 1, sizeof(*p));
2038         if (p == NULL)
2039                 return -1;
2040
2041         bss->hs20_osu_providers = p;
2042         bss->last_osu = &bss->hs20_osu_providers[bss->hs20_osu_providers_count];
2043         bss->hs20_osu_providers_count++;
2044         os_memset(bss->last_osu, 0, sizeof(*p));
2045         bss->last_osu->server_uri = os_strdup(pos);
2046
2047         return 0;
2048 }
2049
2050
2051 static int hs20_parse_osu_friendly_name(struct hostapd_bss_config *bss,
2052                                         char *pos, int line)
2053 {
2054         if (bss->last_osu == NULL) {
2055                 wpa_printf(MSG_ERROR, "Line %d: Unexpected OSU field", line);
2056                 return -1;
2057         }
2058
2059         if (parse_lang_string(&bss->last_osu->friendly_name,
2060                               &bss->last_osu->friendly_name_count, pos)) {
2061                 wpa_printf(MSG_ERROR, "Line %d: Invalid osu_friendly_name '%s'",
2062                            line, pos);
2063                 return -1;
2064         }
2065
2066         return 0;
2067 }
2068
2069
2070 static int hs20_parse_osu_nai(struct hostapd_bss_config *bss,
2071                               char *pos, int line)
2072 {
2073         if (bss->last_osu == NULL) {
2074                 wpa_printf(MSG_ERROR, "Line %d: Unexpected OSU field", line);
2075                 return -1;
2076         }
2077
2078         os_free(bss->last_osu->osu_nai);
2079         bss->last_osu->osu_nai = os_strdup(pos);
2080         if (bss->last_osu->osu_nai == NULL)
2081                 return -1;
2082
2083         return 0;
2084 }
2085
2086
2087 static int hs20_parse_osu_nai2(struct hostapd_bss_config *bss,
2088                                char *pos, int line)
2089 {
2090         if (bss->last_osu == NULL) {
2091                 wpa_printf(MSG_ERROR, "Line %d: Unexpected OSU field", line);
2092                 return -1;
2093         }
2094
2095         os_free(bss->last_osu->osu_nai2);
2096         bss->last_osu->osu_nai2 = os_strdup(pos);
2097         if (bss->last_osu->osu_nai2 == NULL)
2098                 return -1;
2099         bss->hs20_osu_providers_nai_count++;
2100
2101         return 0;
2102 }
2103
2104
2105 static int hs20_parse_osu_method_list(struct hostapd_bss_config *bss, char *pos,
2106                                       int line)
2107 {
2108         if (bss->last_osu == NULL) {
2109                 wpa_printf(MSG_ERROR, "Line %d: Unexpected OSU field", line);
2110                 return -1;
2111         }
2112
2113         if (hostapd_parse_intlist(&bss->last_osu->method_list, pos)) {
2114                 wpa_printf(MSG_ERROR, "Line %d: Invalid osu_method_list", line);
2115                 return -1;
2116         }
2117
2118         return 0;
2119 }
2120
2121
2122 static int hs20_parse_osu_icon(struct hostapd_bss_config *bss, char *pos,
2123                                int line)
2124 {
2125         char **n;
2126         struct hs20_osu_provider *p = bss->last_osu;
2127
2128         if (p == NULL) {
2129                 wpa_printf(MSG_ERROR, "Line %d: Unexpected OSU field", line);
2130                 return -1;
2131         }
2132
2133         n = os_realloc_array(p->icons, p->icons_count + 1, sizeof(char *));
2134         if (n == NULL)
2135                 return -1;
2136         p->icons = n;
2137         p->icons[p->icons_count] = os_strdup(pos);
2138         if (p->icons[p->icons_count] == NULL)
2139                 return -1;
2140         p->icons_count++;
2141
2142         return 0;
2143 }
2144
2145
2146 static int hs20_parse_osu_service_desc(struct hostapd_bss_config *bss,
2147                                        char *pos, int line)
2148 {
2149         if (bss->last_osu == NULL) {
2150                 wpa_printf(MSG_ERROR, "Line %d: Unexpected OSU field", line);
2151                 return -1;
2152         }
2153
2154         if (parse_lang_string(&bss->last_osu->service_desc,
2155                               &bss->last_osu->service_desc_count, pos)) {
2156                 wpa_printf(MSG_ERROR, "Line %d: Invalid osu_service_desc '%s'",
2157                            line, pos);
2158                 return -1;
2159         }
2160
2161         return 0;
2162 }
2163
2164
2165 static int hs20_parse_operator_icon(struct hostapd_bss_config *bss, char *pos,
2166                                     int line)
2167 {
2168         char **n;
2169
2170         n = os_realloc_array(bss->hs20_operator_icon,
2171                              bss->hs20_operator_icon_count + 1, sizeof(char *));
2172         if (!n)
2173                 return -1;
2174         bss->hs20_operator_icon = n;
2175         bss->hs20_operator_icon[bss->hs20_operator_icon_count] = os_strdup(pos);
2176         if (!bss->hs20_operator_icon[bss->hs20_operator_icon_count])
2177                 return -1;
2178         bss->hs20_operator_icon_count++;
2179
2180         return 0;
2181 }
2182
2183 #endif /* CONFIG_HS20 */
2184
2185
2186 #ifdef CONFIG_ACS
2187 static int hostapd_config_parse_acs_chan_bias(struct hostapd_config *conf,
2188                                               char *pos)
2189 {
2190         struct acs_bias *bias = NULL, *tmp;
2191         unsigned int num = 0;
2192         char *end;
2193
2194         while (*pos) {
2195                 tmp = os_realloc_array(bias, num + 1, sizeof(*bias));
2196                 if (!tmp)
2197                         goto fail;
2198                 bias = tmp;
2199
2200                 bias[num].channel = atoi(pos);
2201                 if (bias[num].channel <= 0)
2202                         goto fail;
2203                 pos = os_strchr(pos, ':');
2204                 if (!pos)
2205                         goto fail;
2206                 pos++;
2207                 bias[num].bias = strtod(pos, &end);
2208                 if (end == pos || bias[num].bias < 0.0)
2209                         goto fail;
2210                 pos = end;
2211                 if (*pos != ' ' && *pos != '\0')
2212                         goto fail;
2213                 num++;
2214         }
2215
2216         os_free(conf->acs_chan_bias);
2217         conf->acs_chan_bias = bias;
2218         conf->num_acs_chan_bias = num;
2219
2220         return 0;
2221 fail:
2222         os_free(bias);
2223         return -1;
2224 }
2225 #endif /* CONFIG_ACS */
2226
2227
2228 static int parse_wpabuf_hex(int line, const char *name, struct wpabuf **buf,
2229                             const char *val)
2230 {
2231         struct wpabuf *elems;
2232
2233         if (val[0] == '\0') {
2234                 wpabuf_free(*buf);
2235                 *buf = NULL;
2236                 return 0;
2237         }
2238
2239         elems = wpabuf_parse_bin(val);
2240         if (!elems) {
2241                 wpa_printf(MSG_ERROR, "Line %d: Invalid %s '%s'",
2242                            line, name, val);
2243                 return -1;
2244         }
2245
2246         wpabuf_free(*buf);
2247         *buf = elems;
2248
2249         return 0;
2250 }
2251
2252
2253 #ifdef CONFIG_FILS
2254 static int parse_fils_realm(struct hostapd_bss_config *bss, const char *val)
2255 {
2256         struct fils_realm *realm;
2257         size_t len;
2258
2259         len = os_strlen(val);
2260         realm = os_zalloc(sizeof(*realm) + len + 1);
2261         if (!realm)
2262                 return -1;
2263
2264         os_memcpy(realm->realm, val, len);
2265         if (fils_domain_name_hash(val, realm->hash) < 0) {
2266                 os_free(realm);
2267                 return -1;
2268         }
2269         dl_list_add_tail(&bss->fils_realms, &realm->list);
2270
2271         return 0;
2272 }
2273 #endif /* CONFIG_FILS */
2274
2275
2276 #ifdef EAP_SERVER
2277 static unsigned int parse_tls_flags(const char *val)
2278 {
2279         unsigned int flags = 0;
2280
2281         /* Disable TLS v1.3 by default for now to avoid interoperability issue.
2282          * This can be enabled by default once the implementation has been fully
2283          * completed and tested with other implementations. */
2284         flags |= TLS_CONN_DISABLE_TLSv1_3;
2285
2286         if (os_strstr(val, "[ALLOW-SIGN-RSA-MD5]"))
2287                 flags |= TLS_CONN_ALLOW_SIGN_RSA_MD5;
2288         if (os_strstr(val, "[DISABLE-TIME-CHECKS]"))
2289                 flags |= TLS_CONN_DISABLE_TIME_CHECKS;
2290         if (os_strstr(val, "[DISABLE-TLSv1.0]"))
2291                 flags |= TLS_CONN_DISABLE_TLSv1_0;
2292         if (os_strstr(val, "[ENABLE-TLSv1.0]"))
2293                 flags |= TLS_CONN_ENABLE_TLSv1_0;
2294         if (os_strstr(val, "[DISABLE-TLSv1.1]"))
2295                 flags |= TLS_CONN_DISABLE_TLSv1_1;
2296         if (os_strstr(val, "[ENABLE-TLSv1.1]"))
2297                 flags |= TLS_CONN_ENABLE_TLSv1_1;
2298         if (os_strstr(val, "[DISABLE-TLSv1.2]"))
2299                 flags |= TLS_CONN_DISABLE_TLSv1_2;
2300         if (os_strstr(val, "[ENABLE-TLSv1.2]"))
2301                 flags |= TLS_CONN_ENABLE_TLSv1_2;
2302         if (os_strstr(val, "[DISABLE-TLSv1.3]"))
2303                 flags |= TLS_CONN_DISABLE_TLSv1_3;
2304         if (os_strstr(val, "[ENABLE-TLSv1.3]"))
2305                 flags &= ~TLS_CONN_DISABLE_TLSv1_3;
2306         if (os_strstr(val, "[SUITEB]"))
2307                 flags |= TLS_CONN_SUITEB;
2308         if (os_strstr(val, "[SUITEB-NO-ECDH]"))
2309                 flags |= TLS_CONN_SUITEB_NO_ECDH | TLS_CONN_SUITEB;
2310
2311         return flags;
2312 }
2313 #endif /* EAP_SERVER */
2314
2315
2316 #ifdef CONFIG_SAE
2317 static int parse_sae_password(struct hostapd_bss_config *bss, const char *val)
2318 {
2319         struct sae_password_entry *pw;
2320         const char *pos = val, *pos2, *end = NULL;
2321
2322         pw = os_zalloc(sizeof(*pw));
2323         if (!pw)
2324                 return -1;
2325         os_memset(pw->peer_addr, 0xff, ETH_ALEN); /* default to wildcard */
2326
2327         pos2 = os_strstr(pos, "|mac=");
2328         if (pos2) {
2329                 end = pos2;
2330                 pos2 += 5;
2331                 if (hwaddr_aton(pos2, pw->peer_addr) < 0)
2332                         goto fail;
2333                 pos = pos2 + ETH_ALEN * 3 - 1;
2334         }
2335
2336         pos2 = os_strstr(pos, "|vlanid=");
2337         if (pos2) {
2338                 if (!end)
2339                         end = pos2;
2340                 pos2 += 8;
2341                 pw->vlan_id = atoi(pos2);
2342         }
2343
2344         pos2 = os_strstr(pos, "|id=");
2345         if (pos2) {
2346                 if (!end)
2347                         end = pos2;
2348                 pos2 += 4;
2349                 pw->identifier = os_strdup(pos2);
2350                 if (!pw->identifier)
2351                         goto fail;
2352         }
2353
2354         if (!end) {
2355                 pw->password = os_strdup(val);
2356                 if (!pw->password)
2357                         goto fail;
2358         } else {
2359                 pw->password = os_malloc(end - val + 1);
2360                 if (!pw->password)
2361                         goto fail;
2362                 os_memcpy(pw->password, val, end - val);
2363                 pw->password[end - val] = '\0';
2364         }
2365
2366         pw->next = bss->sae_passwords;
2367         bss->sae_passwords = pw;
2368
2369         return 0;
2370 fail:
2371         str_clear_free(pw->password);
2372         os_free(pw->identifier);
2373         os_free(pw);
2374         return -1;
2375 }
2376 #endif /* CONFIG_SAE */
2377
2378
2379 static int hostapd_config_fill(struct hostapd_config *conf,
2380                                struct hostapd_bss_config *bss,
2381                                const char *buf, char *pos, int line)
2382 {
2383         if (os_strcmp(buf, "interface") == 0) {
2384                 os_strlcpy(conf->bss[0]->iface, pos,
2385                            sizeof(conf->bss[0]->iface));
2386         } else if (os_strcmp(buf, "bridge") == 0) {
2387                 os_strlcpy(bss->bridge, pos, sizeof(bss->bridge));
2388         } else if (os_strcmp(buf, "vlan_bridge") == 0) {
2389                 os_strlcpy(bss->vlan_bridge, pos, sizeof(bss->vlan_bridge));
2390         } else if (os_strcmp(buf, "wds_bridge") == 0) {
2391                 os_strlcpy(bss->wds_bridge, pos, sizeof(bss->wds_bridge));
2392         } else if (os_strcmp(buf, "driver") == 0) {
2393                 int j;
2394                 const struct wpa_driver_ops *driver = NULL;
2395
2396                 for (j = 0; wpa_drivers[j]; j++) {
2397                         if (os_strcmp(pos, wpa_drivers[j]->name) == 0) {
2398                                 driver = wpa_drivers[j];
2399                                 break;
2400                         }
2401                 }
2402                 if (!driver) {
2403                         wpa_printf(MSG_ERROR,
2404                                    "Line %d: invalid/unknown driver '%s'",
2405                                    line, pos);
2406                         return 1;
2407                 }
2408                 conf->driver = driver;
2409         } else if (os_strcmp(buf, "driver_params") == 0) {
2410                 os_free(conf->driver_params);
2411                 conf->driver_params = os_strdup(pos);
2412         } else if (os_strcmp(buf, "debug") == 0) {
2413                 wpa_printf(MSG_DEBUG, "Line %d: DEPRECATED: 'debug' configuration variable is not used anymore",
2414                            line);
2415         } else if (os_strcmp(buf, "logger_syslog_level") == 0) {
2416                 bss->logger_syslog_level = atoi(pos);
2417         } else if (os_strcmp(buf, "logger_stdout_level") == 0) {
2418                 bss->logger_stdout_level = atoi(pos);
2419         } else if (os_strcmp(buf, "logger_syslog") == 0) {
2420                 bss->logger_syslog = atoi(pos);
2421         } else if (os_strcmp(buf, "logger_stdout") == 0) {
2422                 bss->logger_stdout = atoi(pos);
2423         } else if (os_strcmp(buf, "dump_file") == 0) {
2424                 wpa_printf(MSG_INFO, "Line %d: DEPRECATED: 'dump_file' configuration variable is not used anymore",
2425                            line);
2426         } else if (os_strcmp(buf, "ssid") == 0) {
2427                 bss->ssid.ssid_len = os_strlen(pos);
2428                 if (bss->ssid.ssid_len > SSID_MAX_LEN ||
2429                     bss->ssid.ssid_len < 1) {
2430                         wpa_printf(MSG_ERROR, "Line %d: invalid SSID '%s'",
2431                                    line, pos);
2432                         return 1;
2433                 }
2434                 os_memcpy(bss->ssid.ssid, pos, bss->ssid.ssid_len);
2435                 bss->ssid.ssid_set = 1;
2436         } else if (os_strcmp(buf, "ssid2") == 0) {
2437                 size_t slen;
2438                 char *str = wpa_config_parse_string(pos, &slen);
2439                 if (str == NULL || slen < 1 || slen > SSID_MAX_LEN) {
2440                         wpa_printf(MSG_ERROR, "Line %d: invalid SSID '%s'",
2441                                    line, pos);
2442                         os_free(str);
2443                         return 1;
2444                 }
2445                 os_memcpy(bss->ssid.ssid, str, slen);
2446                 bss->ssid.ssid_len = slen;
2447                 bss->ssid.ssid_set = 1;
2448                 os_free(str);
2449         } else if (os_strcmp(buf, "utf8_ssid") == 0) {
2450                 bss->ssid.utf8_ssid = atoi(pos) > 0;
2451         } else if (os_strcmp(buf, "macaddr_acl") == 0) {
2452                 enum macaddr_acl acl = atoi(pos);
2453
2454                 if (acl != ACCEPT_UNLESS_DENIED &&
2455                     acl != DENY_UNLESS_ACCEPTED &&
2456                     acl != USE_EXTERNAL_RADIUS_AUTH) {
2457                         wpa_printf(MSG_ERROR, "Line %d: unknown macaddr_acl %d",
2458                                    line, acl);
2459                         return 1;
2460                 }
2461                 bss->macaddr_acl = acl;
2462         } else if (os_strcmp(buf, "accept_mac_file") == 0) {
2463                 if (hostapd_config_read_maclist(pos, &bss->accept_mac,
2464                                                 &bss->num_accept_mac)) {
2465                         wpa_printf(MSG_ERROR, "Line %d: Failed to read accept_mac_file '%s'",
2466                                    line, pos);
2467                         return 1;
2468                 }
2469         } else if (os_strcmp(buf, "deny_mac_file") == 0) {
2470                 if (hostapd_config_read_maclist(pos, &bss->deny_mac,
2471                                                 &bss->num_deny_mac)) {
2472                         wpa_printf(MSG_ERROR, "Line %d: Failed to read deny_mac_file '%s'",
2473                                    line, pos);
2474                         return 1;
2475                 }
2476         } else if (os_strcmp(buf, "wds_sta") == 0) {
2477                 bss->wds_sta = atoi(pos);
2478         } else if (os_strcmp(buf, "start_disabled") == 0) {
2479                 bss->start_disabled = atoi(pos);
2480         } else if (os_strcmp(buf, "ap_isolate") == 0) {
2481                 bss->isolate = atoi(pos);
2482         } else if (os_strcmp(buf, "ap_max_inactivity") == 0) {
2483                 bss->ap_max_inactivity = atoi(pos);
2484         } else if (os_strcmp(buf, "skip_inactivity_poll") == 0) {
2485                 bss->skip_inactivity_poll = atoi(pos);
2486         } else if (os_strcmp(buf, "country_code") == 0) {
2487                 os_memcpy(conf->country, pos, 2);
2488         } else if (os_strcmp(buf, "country3") == 0) {
2489                 conf->country[2] = strtol(pos, NULL, 16);
2490         } else if (os_strcmp(buf, "ieee80211d") == 0) {
2491                 conf->ieee80211d = atoi(pos);
2492         } else if (os_strcmp(buf, "ieee80211h") == 0) {
2493                 conf->ieee80211h = atoi(pos);
2494         } else if (os_strcmp(buf, "ieee8021x") == 0) {
2495                 bss->ieee802_1x = atoi(pos);
2496         } else if (os_strcmp(buf, "eapol_version") == 0) {
2497                 int eapol_version = atoi(pos);
2498
2499                 if (eapol_version < 1 || eapol_version > 2) {
2500                         wpa_printf(MSG_ERROR,
2501                                    "Line %d: invalid EAPOL version (%d): '%s'.",
2502                                    line, eapol_version, pos);
2503                         return 1;
2504                 }
2505                 bss->eapol_version = eapol_version;
2506                 wpa_printf(MSG_DEBUG, "eapol_version=%d", bss->eapol_version);
2507 #ifdef EAP_SERVER
2508         } else if (os_strcmp(buf, "eap_authenticator") == 0) {
2509                 bss->eap_server = atoi(pos);
2510                 wpa_printf(MSG_ERROR, "Line %d: obsolete eap_authenticator used; this has been renamed to eap_server", line);
2511         } else if (os_strcmp(buf, "eap_server") == 0) {
2512                 bss->eap_server = atoi(pos);
2513         } else if (os_strcmp(buf, "eap_user_file") == 0) {
2514                 if (hostapd_config_read_eap_user(pos, bss))
2515                         return 1;
2516         } else if (os_strcmp(buf, "ca_cert") == 0) {
2517                 os_free(bss->ca_cert);
2518                 bss->ca_cert = os_strdup(pos);
2519         } else if (os_strcmp(buf, "server_cert") == 0) {
2520                 os_free(bss->server_cert);
2521                 bss->server_cert = os_strdup(pos);
2522         } else if (os_strcmp(buf, "private_key") == 0) {
2523                 os_free(bss->private_key);
2524                 bss->private_key = os_strdup(pos);
2525         } else if (os_strcmp(buf, "private_key_passwd") == 0) {
2526                 os_free(bss->private_key_passwd);
2527                 bss->private_key_passwd = os_strdup(pos);
2528         } else if (os_strcmp(buf, "check_cert_subject") == 0) {
2529                 if (!pos[0]) {
2530                         wpa_printf(MSG_ERROR, "Line %d: unknown check_cert_subject '%s'",
2531                                    line, pos);
2532                         return 1;
2533                 }
2534                 os_free(bss->check_cert_subject);
2535                 bss->check_cert_subject = os_strdup(pos);
2536                 if (!bss->check_cert_subject)
2537                         return 1;
2538         } else if (os_strcmp(buf, "check_crl") == 0) {
2539                 bss->check_crl = atoi(pos);
2540         } else if (os_strcmp(buf, "check_crl_strict") == 0) {
2541                 bss->check_crl_strict = atoi(pos);
2542         } else if (os_strcmp(buf, "crl_reload_interval") == 0) {
2543                 bss->crl_reload_interval = atoi(pos);
2544         } else if (os_strcmp(buf, "tls_session_lifetime") == 0) {
2545                 bss->tls_session_lifetime = atoi(pos);
2546         } else if (os_strcmp(buf, "tls_flags") == 0) {
2547                 bss->tls_flags = parse_tls_flags(pos);
2548         } else if (os_strcmp(buf, "ocsp_stapling_response") == 0) {
2549                 os_free(bss->ocsp_stapling_response);
2550                 bss->ocsp_stapling_response = os_strdup(pos);
2551         } else if (os_strcmp(buf, "ocsp_stapling_response_multi") == 0) {
2552                 os_free(bss->ocsp_stapling_response_multi);
2553                 bss->ocsp_stapling_response_multi = os_strdup(pos);
2554         } else if (os_strcmp(buf, "dh_file") == 0) {
2555                 os_free(bss->dh_file);
2556                 bss->dh_file = os_strdup(pos);
2557         } else if (os_strcmp(buf, "openssl_ciphers") == 0) {
2558                 os_free(bss->openssl_ciphers);
2559                 bss->openssl_ciphers = os_strdup(pos);
2560         } else if (os_strcmp(buf, "openssl_ecdh_curves") == 0) {
2561                 os_free(bss->openssl_ecdh_curves);
2562                 bss->openssl_ecdh_curves = os_strdup(pos);
2563         } else if (os_strcmp(buf, "fragment_size") == 0) {
2564                 bss->fragment_size = atoi(pos);
2565 #ifdef EAP_SERVER_FAST
2566         } else if (os_strcmp(buf, "pac_opaque_encr_key") == 0) {
2567                 os_free(bss->pac_opaque_encr_key);
2568                 bss->pac_opaque_encr_key = os_malloc(16);
2569                 if (bss->pac_opaque_encr_key == NULL) {
2570                         wpa_printf(MSG_ERROR,
2571                                    "Line %d: No memory for pac_opaque_encr_key",
2572                                    line);
2573                         return 1;
2574                 } else if (hexstr2bin(pos, bss->pac_opaque_encr_key, 16)) {
2575                         wpa_printf(MSG_ERROR, "Line %d: Invalid pac_opaque_encr_key",
2576                                    line);
2577                         return 1;
2578                 }
2579         } else if (os_strcmp(buf, "eap_fast_a_id") == 0) {
2580                 size_t idlen = os_strlen(pos);
2581                 if (idlen & 1) {
2582                         wpa_printf(MSG_ERROR, "Line %d: Invalid eap_fast_a_id",
2583                                    line);
2584                         return 1;
2585                 }
2586                 os_free(bss->eap_fast_a_id);
2587                 bss->eap_fast_a_id = os_malloc(idlen / 2);
2588                 if (bss->eap_fast_a_id == NULL ||
2589                     hexstr2bin(pos, bss->eap_fast_a_id, idlen / 2)) {
2590                         wpa_printf(MSG_ERROR, "Line %d: Failed to parse eap_fast_a_id",
2591                                    line);
2592                         os_free(bss->eap_fast_a_id);
2593                         bss->eap_fast_a_id = NULL;
2594                         return 1;
2595                 } else {
2596                         bss->eap_fast_a_id_len = idlen / 2;
2597                 }
2598         } else if (os_strcmp(buf, "eap_fast_a_id_info") == 0) {
2599                 os_free(bss->eap_fast_a_id_info);
2600                 bss->eap_fast_a_id_info = os_strdup(pos);
2601         } else if (os_strcmp(buf, "eap_fast_prov") == 0) {
2602                 bss->eap_fast_prov = atoi(pos);
2603         } else if (os_strcmp(buf, "pac_key_lifetime") == 0) {
2604                 bss->pac_key_lifetime = atoi(pos);
2605         } else if (os_strcmp(buf, "pac_key_refresh_time") == 0) {
2606                 bss->pac_key_refresh_time = atoi(pos);
2607 #endif /* EAP_SERVER_FAST */
2608 #ifdef EAP_SERVER_SIM
2609         } else if (os_strcmp(buf, "eap_sim_db") == 0) {
2610                 os_free(bss->eap_sim_db);
2611                 bss->eap_sim_db = os_strdup(pos);
2612         } else if (os_strcmp(buf, "eap_sim_db_timeout") == 0) {
2613                 bss->eap_sim_db_timeout = atoi(pos);
2614         } else if (os_strcmp(buf, "eap_sim_aka_result_ind") == 0) {
2615                 bss->eap_sim_aka_result_ind = atoi(pos);
2616 #endif /* EAP_SERVER_SIM */
2617 #ifdef EAP_SERVER_TNC
2618         } else if (os_strcmp(buf, "tnc") == 0) {
2619                 bss->tnc = atoi(pos);
2620 #endif /* EAP_SERVER_TNC */
2621 #ifdef EAP_SERVER_PWD
2622         } else if (os_strcmp(buf, "pwd_group") == 0) {
2623                 bss->pwd_group = atoi(pos);
2624 #endif /* EAP_SERVER_PWD */
2625 #ifdef CONFIG_ERP
2626         } else if (os_strcmp(buf, "eap_server_erp") == 0) {
2627                 bss->eap_server_erp = atoi(pos);
2628 #endif /* CONFIG_ERP */
2629 #endif /* EAP_SERVER */
2630         } else if (os_strcmp(buf, "eap_message") == 0) {
2631                 char *term;
2632                 os_free(bss->eap_req_id_text);
2633                 bss->eap_req_id_text = os_strdup(pos);
2634                 if (bss->eap_req_id_text == NULL) {
2635                         wpa_printf(MSG_ERROR, "Line %d: Failed to allocate memory for eap_req_id_text",
2636                                    line);
2637                         return 1;
2638                 }
2639                 bss->eap_req_id_text_len = os_strlen(bss->eap_req_id_text);
2640                 term = os_strstr(bss->eap_req_id_text, "\\0");
2641                 if (term) {
2642                         *term++ = '\0';
2643                         os_memmove(term, term + 1,
2644                                    bss->eap_req_id_text_len -
2645                                    (term - bss->eap_req_id_text) - 1);
2646                         bss->eap_req_id_text_len--;
2647                 }
2648         } else if (os_strcmp(buf, "erp_send_reauth_start") == 0) {
2649                 bss->erp_send_reauth_start = atoi(pos);
2650         } else if (os_strcmp(buf, "erp_domain") == 0) {
2651                 os_free(bss->erp_domain);
2652                 bss->erp_domain = os_strdup(pos);
2653         } else if (os_strcmp(buf, "wep_key_len_broadcast") == 0) {
2654                 int val = atoi(pos);
2655
2656                 if (val < 0 || val > 13) {
2657                         wpa_printf(MSG_ERROR,
2658                                    "Line %d: invalid WEP key len %d (= %d bits)",
2659                                    line, val, val * 8);
2660                         return 1;
2661                 }
2662                 bss->default_wep_key_len = val;
2663         } else if (os_strcmp(buf, "wep_key_len_unicast") == 0) {
2664                 int val = atoi(pos);
2665
2666                 if (val < 0 || val > 13) {
2667                         wpa_printf(MSG_ERROR,
2668                                    "Line %d: invalid WEP key len %d (= %d bits)",
2669                                    line, val, val * 8);
2670                         return 1;
2671                 }
2672                 bss->individual_wep_key_len = val;
2673         } else if (os_strcmp(buf, "wep_rekey_period") == 0) {
2674                 bss->wep_rekeying_period = atoi(pos);
2675                 if (bss->wep_rekeying_period < 0) {
2676                         wpa_printf(MSG_ERROR, "Line %d: invalid period %d",
2677                                    line, bss->wep_rekeying_period);
2678                         return 1;
2679                 }
2680         } else if (os_strcmp(buf, "eap_reauth_period") == 0) {
2681                 bss->eap_reauth_period = atoi(pos);
2682                 if (bss->eap_reauth_period < 0) {
2683                         wpa_printf(MSG_ERROR, "Line %d: invalid period %d",
2684                                    line, bss->eap_reauth_period);
2685                         return 1;
2686                 }
2687         } else if (os_strcmp(buf, "eapol_key_index_workaround") == 0) {
2688                 bss->eapol_key_index_workaround = atoi(pos);
2689 #ifdef CONFIG_IAPP
2690         } else if (os_strcmp(buf, "iapp_interface") == 0) {
2691                 bss->ieee802_11f = 1;
2692                 os_strlcpy(bss->iapp_iface, pos, sizeof(bss->iapp_iface));
2693 #endif /* CONFIG_IAPP */
2694         } else if (os_strcmp(buf, "own_ip_addr") == 0) {
2695                 if (hostapd_parse_ip_addr(pos, &bss->own_ip_addr)) {
2696                         wpa_printf(MSG_ERROR,
2697                                    "Line %d: invalid IP address '%s'",
2698                                    line, pos);
2699                         return 1;
2700                 }
2701         } else if (os_strcmp(buf, "nas_identifier") == 0) {
2702                 os_free(bss->nas_identifier);
2703                 bss->nas_identifier = os_strdup(pos);
2704 #ifndef CONFIG_NO_RADIUS
2705         } else if (os_strcmp(buf, "radius_client_addr") == 0) {
2706                 if (hostapd_parse_ip_addr(pos, &bss->radius->client_addr)) {
2707                         wpa_printf(MSG_ERROR,
2708                                    "Line %d: invalid IP address '%s'",
2709                                    line, pos);
2710                         return 1;
2711                 }
2712                 bss->radius->force_client_addr = 1;
2713         } else if (os_strcmp(buf, "auth_server_addr") == 0) {
2714                 if (hostapd_config_read_radius_addr(
2715                             &bss->radius->auth_servers,
2716                             &bss->radius->num_auth_servers, pos, 1812,
2717                             &bss->radius->auth_server)) {
2718                         wpa_printf(MSG_ERROR,
2719                                    "Line %d: invalid IP address '%s'",
2720                                    line, pos);
2721                         return 1;
2722                 }
2723         } else if (bss->radius->auth_server &&
2724                    os_strcmp(buf, "auth_server_addr_replace") == 0) {
2725                 if (hostapd_parse_ip_addr(pos,
2726                                           &bss->radius->auth_server->addr)) {
2727                         wpa_printf(MSG_ERROR,
2728                                    "Line %d: invalid IP address '%s'",
2729                                    line, pos);
2730                         return 1;
2731                 }
2732         } else if (bss->radius->auth_server &&
2733                    os_strcmp(buf, "auth_server_port") == 0) {
2734                 bss->radius->auth_server->port = atoi(pos);
2735         } else if (bss->radius->auth_server &&
2736                    os_strcmp(buf, "auth_server_shared_secret") == 0) {
2737                 int len = os_strlen(pos);
2738                 if (len == 0) {
2739                         /* RFC 2865, Ch. 3 */
2740                         wpa_printf(MSG_ERROR, "Line %d: empty shared secret is not allowed",
2741                                    line);
2742                         return 1;
2743                 }
2744                 os_free(bss->radius->auth_server->shared_secret);
2745                 bss->radius->auth_server->shared_secret = (u8 *) os_strdup(pos);
2746                 bss->radius->auth_server->shared_secret_len = len;
2747         } else if (os_strcmp(buf, "acct_server_addr") == 0) {
2748                 if (hostapd_config_read_radius_addr(
2749                             &bss->radius->acct_servers,
2750                             &bss->radius->num_acct_servers, pos, 1813,
2751                             &bss->radius->acct_server)) {
2752                         wpa_printf(MSG_ERROR,
2753                                    "Line %d: invalid IP address '%s'",
2754                                    line, pos);
2755                         return 1;
2756                 }
2757         } else if (bss->radius->acct_server &&
2758                    os_strcmp(buf, "acct_server_addr_replace") == 0) {
2759                 if (hostapd_parse_ip_addr(pos,
2760                                           &bss->radius->acct_server->addr)) {
2761                         wpa_printf(MSG_ERROR,
2762                                    "Line %d: invalid IP address '%s'",
2763                                    line, pos);
2764                         return 1;
2765                 }
2766         } else if (bss->radius->acct_server &&
2767                    os_strcmp(buf, "acct_server_port") == 0) {
2768                 bss->radius->acct_server->port = atoi(pos);
2769         } else if (bss->radius->acct_server &&
2770                    os_strcmp(buf, "acct_server_shared_secret") == 0) {
2771                 int len = os_strlen(pos);
2772                 if (len == 0) {
2773                         /* RFC 2865, Ch. 3 */
2774                         wpa_printf(MSG_ERROR, "Line %d: empty shared secret is not allowed",
2775                                    line);
2776                         return 1;
2777                 }
2778                 os_free(bss->radius->acct_server->shared_secret);
2779                 bss->radius->acct_server->shared_secret = (u8 *) os_strdup(pos);
2780                 bss->radius->acct_server->shared_secret_len = len;
2781         } else if (os_strcmp(buf, "radius_retry_primary_interval") == 0) {
2782                 bss->radius->retry_primary_interval = atoi(pos);
2783         } else if (os_strcmp(buf, "radius_acct_interim_interval") == 0) {
2784                 bss->acct_interim_interval = atoi(pos);
2785         } else if (os_strcmp(buf, "radius_request_cui") == 0) {
2786                 bss->radius_request_cui = atoi(pos);
2787         } else if (os_strcmp(buf, "radius_auth_req_attr") == 0) {
2788                 struct hostapd_radius_attr *attr, *a;
2789                 attr = hostapd_parse_radius_attr(pos);
2790                 if (attr == NULL) {
2791                         wpa_printf(MSG_ERROR,
2792                                    "Line %d: invalid radius_auth_req_attr",
2793                                    line);
2794                         return 1;
2795                 } else if (bss->radius_auth_req_attr == NULL) {
2796                         bss->radius_auth_req_attr = attr;
2797                 } else {
2798                         a = bss->radius_auth_req_attr;
2799                         while (a->next)
2800                                 a = a->next;
2801                         a->next = attr;
2802                 }
2803         } else if (os_strcmp(buf, "radius_acct_req_attr") == 0) {
2804                 struct hostapd_radius_attr *attr, *a;
2805                 attr = hostapd_parse_radius_attr(pos);
2806                 if (attr == NULL) {
2807                         wpa_printf(MSG_ERROR,
2808                                    "Line %d: invalid radius_acct_req_attr",
2809                                    line);
2810                         return 1;
2811                 } else if (bss->radius_acct_req_attr == NULL) {
2812                         bss->radius_acct_req_attr = attr;
2813                 } else {
2814                         a = bss->radius_acct_req_attr;
2815                         while (a->next)
2816                                 a = a->next;
2817                         a->next = attr;
2818                 }
2819         } else if (os_strcmp(buf, "radius_das_port") == 0) {
2820                 bss->radius_das_port = atoi(pos);
2821         } else if (os_strcmp(buf, "radius_das_client") == 0) {
2822                 if (hostapd_parse_das_client(bss, pos) < 0) {
2823                         wpa_printf(MSG_ERROR, "Line %d: invalid DAS client",
2824                                    line);
2825                         return 1;
2826                 }
2827         } else if (os_strcmp(buf, "radius_das_time_window") == 0) {
2828                 bss->radius_das_time_window = atoi(pos);
2829         } else if (os_strcmp(buf, "radius_das_require_event_timestamp") == 0) {
2830                 bss->radius_das_require_event_timestamp = atoi(pos);
2831         } else if (os_strcmp(buf, "radius_das_require_message_authenticator") ==
2832                    0) {
2833                 bss->radius_das_require_message_authenticator = atoi(pos);
2834 #endif /* CONFIG_NO_RADIUS */
2835         } else if (os_strcmp(buf, "auth_algs") == 0) {
2836                 bss->auth_algs = atoi(pos);
2837                 if (bss->auth_algs == 0) {
2838                         wpa_printf(MSG_ERROR, "Line %d: no authentication algorithms allowed",
2839                                    line);
2840                         return 1;
2841                 }
2842         } else if (os_strcmp(buf, "max_num_sta") == 0) {
2843                 bss->max_num_sta = atoi(pos);
2844                 if (bss->max_num_sta < 0 ||
2845                     bss->max_num_sta > MAX_STA_COUNT) {
2846                         wpa_printf(MSG_ERROR, "Line %d: Invalid max_num_sta=%d; allowed range 0..%d",
2847                                    line, bss->max_num_sta, MAX_STA_COUNT);
2848                         return 1;
2849                 }
2850         } else if (os_strcmp(buf, "wpa") == 0) {
2851                 bss->wpa = atoi(pos);
2852         } else if (os_strcmp(buf, "wpa_group_rekey") == 0) {
2853                 bss->wpa_group_rekey = atoi(pos);
2854                 bss->wpa_group_rekey_set = 1;
2855         } else if (os_strcmp(buf, "wpa_strict_rekey") == 0) {
2856                 bss->wpa_strict_rekey = atoi(pos);
2857         } else if (os_strcmp(buf, "wpa_gmk_rekey") == 0) {
2858                 bss->wpa_gmk_rekey = atoi(pos);
2859         } else if (os_strcmp(buf, "wpa_ptk_rekey") == 0) {
2860                 bss->wpa_ptk_rekey = atoi(pos);
2861         } else if (os_strcmp(buf, "wpa_group_update_count") == 0) {
2862                 char *endp;
2863                 unsigned long val = strtoul(pos, &endp, 0);
2864
2865                 if (*endp || val < 1 || val > (u32) -1) {
2866                         wpa_printf(MSG_ERROR,
2867                                    "Line %d: Invalid wpa_group_update_count=%lu; allowed range 1..4294967295",
2868                                    line, val);
2869                         return 1;
2870                 }
2871                 bss->wpa_group_update_count = (u32) val;
2872         } else if (os_strcmp(buf, "wpa_pairwise_update_count") == 0) {
2873                 char *endp;
2874                 unsigned long val = strtoul(pos, &endp, 0);
2875
2876                 if (*endp || val < 1 || val > (u32) -1) {
2877                         wpa_printf(MSG_ERROR,
2878                                    "Line %d: Invalid wpa_pairwise_update_count=%lu; allowed range 1..4294967295",
2879                                    line, val);
2880                         return 1;
2881                 }
2882                 bss->wpa_pairwise_update_count = (u32) val;
2883         } else if (os_strcmp(buf, "wpa_disable_eapol_key_retries") == 0) {
2884                 bss->wpa_disable_eapol_key_retries = atoi(pos);
2885         } else if (os_strcmp(buf, "wpa_passphrase") == 0) {
2886                 int len = os_strlen(pos);
2887                 if (len < 8 || len > 63) {
2888                         wpa_printf(MSG_ERROR, "Line %d: invalid WPA passphrase length %d (expected 8..63)",
2889                                    line, len);
2890                         return 1;
2891                 }
2892                 os_free(bss->ssid.wpa_passphrase);
2893                 bss->ssid.wpa_passphrase = os_strdup(pos);
2894                 if (bss->ssid.wpa_passphrase) {
2895                         hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk);
2896                         bss->ssid.wpa_passphrase_set = 1;
2897                 }
2898         } else if (os_strcmp(buf, "wpa_psk") == 0) {
2899                 hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk);
2900                 bss->ssid.wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk));
2901                 if (bss->ssid.wpa_psk == NULL)
2902                         return 1;
2903                 if (hexstr2bin(pos, bss->ssid.wpa_psk->psk, PMK_LEN) ||
2904                     pos[PMK_LEN * 2] != '\0') {
2905                         wpa_printf(MSG_ERROR, "Line %d: Invalid PSK '%s'.",
2906                                    line, pos);
2907                         hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk);
2908                         return 1;
2909                 }
2910                 bss->ssid.wpa_psk->group = 1;
2911                 os_free(bss->ssid.wpa_passphrase);
2912                 bss->ssid.wpa_passphrase = NULL;
2913                 bss->ssid.wpa_psk_set = 1;
2914         } else if (os_strcmp(buf, "wpa_psk_file") == 0) {
2915                 os_free(bss->ssid.wpa_psk_file);
2916                 bss->ssid.wpa_psk_file = os_strdup(pos);
2917                 if (!bss->ssid.wpa_psk_file) {
2918                         wpa_printf(MSG_ERROR, "Line %d: allocation failed",
2919                                    line);
2920                         return 1;
2921                 }
2922         } else if (os_strcmp(buf, "wpa_key_mgmt") == 0) {
2923                 bss->wpa_key_mgmt = hostapd_config_parse_key_mgmt(line, pos);
2924                 if (bss->wpa_key_mgmt == -1)
2925                         return 1;
2926         } else if (os_strcmp(buf, "wpa_psk_radius") == 0) {
2927                 bss->wpa_psk_radius = atoi(pos);
2928                 if (bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
2929                     bss->wpa_psk_radius != PSK_RADIUS_ACCEPTED &&
2930                     bss->wpa_psk_radius != PSK_RADIUS_REQUIRED) {
2931                         wpa_printf(MSG_ERROR,
2932                                    "Line %d: unknown wpa_psk_radius %d",
2933                                    line, bss->wpa_psk_radius);
2934                         return 1;
2935                 }
2936         } else if (os_strcmp(buf, "wpa_pairwise") == 0) {
2937                 bss->wpa_pairwise = hostapd_config_parse_cipher(line, pos);
2938                 if (bss->wpa_pairwise == -1 || bss->wpa_pairwise == 0)
2939                         return 1;
2940                 if (bss->wpa_pairwise &
2941                     (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)) {
2942                         wpa_printf(MSG_ERROR, "Line %d: unsupported pairwise cipher suite '%s'",
2943                                    line, pos);
2944                         return 1;
2945                 }
2946         } else if (os_strcmp(buf, "rsn_pairwise") == 0) {
2947                 bss->rsn_pairwise = hostapd_config_parse_cipher(line, pos);
2948                 if (bss->rsn_pairwise == -1 || bss->rsn_pairwise == 0)
2949                         return 1;
2950                 if (bss->rsn_pairwise &
2951                     (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)) {
2952                         wpa_printf(MSG_ERROR, "Line %d: unsupported pairwise cipher suite '%s'",
2953                                    line, pos);
2954                         return 1;
2955                 }
2956         } else if (os_strcmp(buf, "group_cipher") == 0) {
2957                 bss->group_cipher = hostapd_config_parse_cipher(line, pos);
2958                 if (bss->group_cipher == -1 || bss->group_cipher == 0)
2959                         return 1;
2960                 if (bss->group_cipher != WPA_CIPHER_TKIP &&
2961                     bss->group_cipher != WPA_CIPHER_CCMP &&
2962                     bss->group_cipher != WPA_CIPHER_GCMP &&
2963                     bss->group_cipher != WPA_CIPHER_GCMP_256 &&
2964                     bss->group_cipher != WPA_CIPHER_CCMP_256) {
2965                         wpa_printf(MSG_ERROR,
2966                                    "Line %d: unsupported group cipher suite '%s'",
2967                                    line, pos);
2968                         return 1;
2969                 }
2970 #ifdef CONFIG_RSN_PREAUTH
2971         } else if (os_strcmp(buf, "rsn_preauth") == 0) {
2972                 bss->rsn_preauth = atoi(pos);
2973         } else if (os_strcmp(buf, "rsn_preauth_interfaces") == 0) {
2974                 os_free(bss->rsn_preauth_interfaces);
2975                 bss->rsn_preauth_interfaces = os_strdup(pos);
2976 #endif /* CONFIG_RSN_PREAUTH */
2977         } else if (os_strcmp(buf, "peerkey") == 0) {
2978                 wpa_printf(MSG_INFO,
2979                            "Line %d: Obsolete peerkey parameter ignored", line);
2980 #ifdef CONFIG_IEEE80211R_AP
2981         } else if (os_strcmp(buf, "mobility_domain") == 0) {
2982                 if (os_strlen(pos) != 2 * MOBILITY_DOMAIN_ID_LEN ||
2983                     hexstr2bin(pos, bss->mobility_domain,
2984                                MOBILITY_DOMAIN_ID_LEN) != 0) {
2985                         wpa_printf(MSG_ERROR,
2986                                    "Line %d: Invalid mobility_domain '%s'",
2987                                    line, pos);
2988                         return 1;
2989                 }
2990         } else if (os_strcmp(buf, "r1_key_holder") == 0) {
2991                 if (os_strlen(pos) != 2 * FT_R1KH_ID_LEN ||
2992                     hexstr2bin(pos, bss->r1_key_holder, FT_R1KH_ID_LEN) != 0) {
2993                         wpa_printf(MSG_ERROR,
2994                                    "Line %d: Invalid r1_key_holder '%s'",
2995                                    line, pos);
2996                         return 1;
2997                 }
2998         } else if (os_strcmp(buf, "r0_key_lifetime") == 0) {
2999                 /* DEPRECATED: Use ft_r0_key_lifetime instead. */
3000                 bss->r0_key_lifetime = atoi(pos) * 60;
3001         } else if (os_strcmp(buf, "ft_r0_key_lifetime") == 0) {
3002                 bss->r0_key_lifetime = atoi(pos);
3003         } else if (os_strcmp(buf, "r1_max_key_lifetime") == 0) {
3004                 bss->r1_max_key_lifetime = atoi(pos);
3005         } else if (os_strcmp(buf, "reassociation_deadline") == 0) {
3006                 bss->reassociation_deadline = atoi(pos);
3007         } else if (os_strcmp(buf, "rkh_pos_timeout") == 0) {
3008                 bss->rkh_pos_timeout = atoi(pos);
3009         } else if (os_strcmp(buf, "rkh_neg_timeout") == 0) {
3010                 bss->rkh_neg_timeout = atoi(pos);
3011         } else if (os_strcmp(buf, "rkh_pull_timeout") == 0) {
3012                 bss->rkh_pull_timeout = atoi(pos);
3013         } else if (os_strcmp(buf, "rkh_pull_retries") == 0) {
3014                 bss->rkh_pull_retries = atoi(pos);
3015         } else if (os_strcmp(buf, "r0kh") == 0) {
3016                 if (add_r0kh(bss, pos) < 0) {
3017                         wpa_printf(MSG_DEBUG, "Line %d: Invalid r0kh '%s'",
3018                                    line, pos);
3019                         return 1;
3020                 }
3021         } else if (os_strcmp(buf, "r1kh") == 0) {
3022                 if (add_r1kh(bss, pos) < 0) {
3023                         wpa_printf(MSG_DEBUG, "Line %d: Invalid r1kh '%s'",
3024                                    line, pos);
3025                         return 1;
3026                 }
3027         } else if (os_strcmp(buf, "pmk_r1_push") == 0) {
3028                 bss->pmk_r1_push = atoi(pos);
3029         } else if (os_strcmp(buf, "ft_over_ds") == 0) {
3030                 bss->ft_over_ds = atoi(pos);
3031         } else if (os_strcmp(buf, "ft_psk_generate_local") == 0) {
3032                 bss->ft_psk_generate_local = atoi(pos);
3033 #endif /* CONFIG_IEEE80211R_AP */
3034 #ifndef CONFIG_NO_CTRL_IFACE
3035         } else if (os_strcmp(buf, "ctrl_interface") == 0) {
3036                 os_free(bss->ctrl_interface);
3037                 bss->ctrl_interface = os_strdup(pos);
3038         } else if (os_strcmp(buf, "ctrl_interface_group") == 0) {
3039 #ifndef CONFIG_NATIVE_WINDOWS
3040                 struct group *grp;
3041                 char *endp;
3042                 const char *group = pos;
3043
3044                 grp = getgrnam(group);
3045                 if (grp) {
3046                         bss->ctrl_interface_gid = grp->gr_gid;
3047                         bss->ctrl_interface_gid_set = 1;
3048                         wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d (from group name '%s')",
3049                                    bss->ctrl_interface_gid, group);
3050                         return 0;
3051                 }
3052
3053                 /* Group name not found - try to parse this as gid */
3054                 bss->ctrl_interface_gid = strtol(group, &endp, 10);
3055                 if (*group == '\0' || *endp != '\0') {
3056                         wpa_printf(MSG_DEBUG, "Line %d: Invalid group '%s'",
3057                                    line, group);
3058                         return 1;
3059                 }
3060                 bss->ctrl_interface_gid_set = 1;
3061                 wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
3062                            bss->ctrl_interface_gid);
3063 #endif /* CONFIG_NATIVE_WINDOWS */
3064 #endif /* CONFIG_NO_CTRL_IFACE */
3065 #ifdef RADIUS_SERVER
3066         } else if (os_strcmp(buf, "radius_server_clients") == 0) {
3067                 os_free(bss->radius_server_clients);
3068                 bss->radius_server_clients = os_strdup(pos);
3069         } else if (os_strcmp(buf, "radius_server_auth_port") == 0) {
3070                 bss->radius_server_auth_port = atoi(pos);
3071         } else if (os_strcmp(buf, "radius_server_acct_port") == 0) {
3072                 bss->radius_server_acct_port = atoi(pos);
3073         } else if (os_strcmp(buf, "radius_server_ipv6") == 0) {
3074                 bss->radius_server_ipv6 = atoi(pos);
3075 #endif /* RADIUS_SERVER */
3076         } else if (os_strcmp(buf, "use_pae_group_addr") == 0) {
3077                 bss->use_pae_group_addr = atoi(pos);
3078         } else if (os_strcmp(buf, "hw_mode") == 0) {
3079                 if (os_strcmp(pos, "a") == 0)
3080                         conf->hw_mode = HOSTAPD_MODE_IEEE80211A;
3081                 else if (os_strcmp(pos, "b") == 0)
3082                         conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
3083                 else if (os_strcmp(pos, "g") == 0)
3084                         conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
3085                 else if (os_strcmp(pos, "ad") == 0)
3086                         conf->hw_mode = HOSTAPD_MODE_IEEE80211AD;
3087                 else if (os_strcmp(pos, "any") == 0)
3088                         conf->hw_mode = HOSTAPD_MODE_IEEE80211ANY;
3089                 else {
3090                         wpa_printf(MSG_ERROR, "Line %d: unknown hw_mode '%s'",
3091                                    line, pos);
3092                         return 1;
3093                 }
3094         } else if (os_strcmp(buf, "wps_rf_bands") == 0) {
3095                 if (os_strcmp(pos, "ad") == 0)
3096                         bss->wps_rf_bands = WPS_RF_60GHZ;
3097                 else if (os_strcmp(pos, "a") == 0)
3098                         bss->wps_rf_bands = WPS_RF_50GHZ;
3099                 else if (os_strcmp(pos, "g") == 0 ||
3100                          os_strcmp(pos, "b") == 0)
3101                         bss->wps_rf_bands = WPS_RF_24GHZ;
3102                 else if (os_strcmp(pos, "ag") == 0 ||
3103                          os_strcmp(pos, "ga") == 0)
3104                         bss->wps_rf_bands = WPS_RF_24GHZ | WPS_RF_50GHZ;
3105                 else {
3106                         wpa_printf(MSG_ERROR,
3107                                    "Line %d: unknown wps_rf_band '%s'",
3108                                    line, pos);
3109                         return 1;
3110                 }
3111         } else if (os_strcmp(buf, "acs_exclude_dfs") == 0) {
3112                 conf->acs_exclude_dfs = atoi(pos);
3113         } else if (os_strcmp(buf, "channel") == 0) {
3114                 if (os_strcmp(pos, "acs_survey") == 0) {
3115 #ifndef CONFIG_ACS
3116                         wpa_printf(MSG_ERROR, "Line %d: tries to enable ACS but CONFIG_ACS disabled",
3117                                    line);
3118                         return 1;
3119 #else /* CONFIG_ACS */
3120                         conf->acs = 1;
3121                         conf->channel = 0;
3122 #endif /* CONFIG_ACS */
3123                 } else {
3124                         conf->channel = atoi(pos);
3125                         conf->acs = conf->channel == 0;
3126                 }
3127         } else if (os_strcmp(buf, "chanlist") == 0) {
3128                 if (hostapd_parse_chanlist(conf, pos)) {
3129                         wpa_printf(MSG_ERROR, "Line %d: invalid channel list",
3130                                    line);
3131                         return 1;
3132                 }
3133         } else if (os_strcmp(buf, "beacon_int") == 0) {
3134                 int val = atoi(pos);
3135                 /* MIB defines range as 1..65535, but very small values
3136                  * cause problems with the current implementation.
3137                  * Since it is unlikely that this small numbers are
3138                  * useful in real life scenarios, do not allow beacon
3139                  * period to be set below 10 TU. */
3140                 if (val < 10 || val > 65535) {
3141                         wpa_printf(MSG_ERROR,
3142                                    "Line %d: invalid beacon_int %d (expected 10..65535)",
3143                                    line, val);
3144                         return 1;
3145                 }
3146                 conf->beacon_int = val;
3147 #ifdef CONFIG_ACS
3148         } else if (os_strcmp(buf, "acs_num_scans") == 0) {
3149                 int val = atoi(pos);
3150                 if (val <= 0 || val > 100) {
3151                         wpa_printf(MSG_ERROR, "Line %d: invalid acs_num_scans %d (expected 1..100)",
3152                                    line, val);
3153                         return 1;
3154                 }
3155                 conf->acs_num_scans = val;
3156         } else if (os_strcmp(buf, "acs_chan_bias") == 0) {
3157                 if (hostapd_config_parse_acs_chan_bias(conf, pos)) {
3158                         wpa_printf(MSG_ERROR, "Line %d: invalid acs_chan_bias",
3159                                    line);
3160                         return -1;
3161                 }
3162 #endif /* CONFIG_ACS */
3163         } else if (os_strcmp(buf, "dtim_period") == 0) {
3164                 int val = atoi(pos);
3165
3166                 if (val < 1 || val > 255) {
3167                         wpa_printf(MSG_ERROR, "Line %d: invalid dtim_period %d",
3168                                    line, val);
3169                         return 1;
3170                 }
3171                 bss->dtim_period = val;
3172         } else if (os_strcmp(buf, "bss_load_update_period") == 0) {
3173                 int val = atoi(pos);
3174
3175                 if (val < 0 || val > 100) {
3176                         wpa_printf(MSG_ERROR,
3177                                    "Line %d: invalid bss_load_update_period %d",
3178                                    line, val);
3179                         return 1;
3180                 }
3181                 bss->bss_load_update_period = val;
3182         } else if (os_strcmp(buf, "chan_util_avg_period") == 0) {
3183                 int val = atoi(pos);
3184
3185                 if (val < 0) {
3186                         wpa_printf(MSG_ERROR,
3187                                    "Line %d: invalid chan_util_avg_period",
3188                                    line);
3189                         return 1;
3190                 }
3191                 bss->chan_util_avg_period = val;
3192         } else if (os_strcmp(buf, "rts_threshold") == 0) {
3193                 conf->rts_threshold = atoi(pos);
3194                 if (conf->rts_threshold < -1 || conf->rts_threshold > 65535) {
3195                         wpa_printf(MSG_ERROR,
3196                                    "Line %d: invalid rts_threshold %d",
3197                                    line, conf->rts_threshold);
3198                         return 1;
3199                 }
3200         } else if (os_strcmp(buf, "fragm_threshold") == 0) {
3201                 conf->fragm_threshold = atoi(pos);
3202                 if (conf->fragm_threshold == -1) {
3203                         /* allow a value of -1 */
3204                 } else if (conf->fragm_threshold < 256 ||
3205                            conf->fragm_threshold > 2346) {
3206                         wpa_printf(MSG_ERROR,
3207                                    "Line %d: invalid fragm_threshold %d",
3208                                    line, conf->fragm_threshold);
3209                         return 1;
3210                 }
3211         } else if (os_strcmp(buf, "send_probe_response") == 0) {
3212                 int val = atoi(pos);
3213                 if (val != 0 && val != 1) {
3214                         wpa_printf(MSG_ERROR, "Line %d: invalid send_probe_response %d (expected 0 or 1)",
3215                                    line, val);
3216                         return 1;
3217                 }
3218                 bss->send_probe_response = val;
3219         } else if (os_strcmp(buf, "supported_rates") == 0) {
3220                 if (hostapd_parse_intlist(&conf->supported_rates, pos)) {
3221                         wpa_printf(MSG_ERROR, "Line %d: invalid rate list",
3222                                    line);
3223                         return 1;
3224                 }
3225         } else if (os_strcmp(buf, "basic_rates") == 0) {
3226                 if (hostapd_parse_intlist(&conf->basic_rates, pos)) {
3227                         wpa_printf(MSG_ERROR, "Line %d: invalid rate list",
3228                                    line);
3229                         return 1;
3230                 }
3231         } else if (os_strcmp(buf, "beacon_rate") == 0) {
3232                 int val;
3233
3234                 if (os_strncmp(pos, "ht:", 3) == 0) {
3235                         val = atoi(pos + 3);
3236                         if (val < 0 || val > 31) {
3237                                 wpa_printf(MSG_ERROR,
3238                                            "Line %d: invalid beacon_rate HT-MCS %d",
3239                                            line, val);
3240                                 return 1;
3241                         }
3242                         conf->rate_type = BEACON_RATE_HT;
3243                         conf->beacon_rate = val;
3244                 } else if (os_strncmp(pos, "vht:", 4) == 0) {
3245                         val = atoi(pos + 4);
3246                         if (val < 0 || val > 9) {
3247                                 wpa_printf(MSG_ERROR,
3248                                            "Line %d: invalid beacon_rate VHT-MCS %d",
3249                                            line, val);
3250                                 return 1;
3251                         }
3252                         conf->rate_type = BEACON_RATE_VHT;
3253                         conf->beacon_rate = val;
3254                 } else {
3255                         val = atoi(pos);
3256                         if (val < 10 || val > 10000) {
3257                                 wpa_printf(MSG_ERROR,
3258                                            "Line %d: invalid legacy beacon_rate %d",
3259                                            line, val);
3260                                 return 1;
3261                         }
3262                         conf->rate_type = BEACON_RATE_LEGACY;
3263                         conf->beacon_rate = val;
3264                 }
3265         } else if (os_strcmp(buf, "preamble") == 0) {
3266                 if (atoi(pos))
3267                         conf->preamble = SHORT_PREAMBLE;
3268                 else
3269                         conf->preamble = LONG_PREAMBLE;
3270         } else if (os_strcmp(buf, "ignore_broadcast_ssid") == 0) {
3271                 bss->ignore_broadcast_ssid = atoi(pos);
3272         } else if (os_strcmp(buf, "no_probe_resp_if_max_sta") == 0) {
3273                 bss->no_probe_resp_if_max_sta = atoi(pos);
3274         } else if (os_strcmp(buf, "wep_default_key") == 0) {
3275                 bss->ssid.wep.idx = atoi(pos);
3276                 if (bss->ssid.wep.idx > 3) {
3277                         wpa_printf(MSG_ERROR,
3278                                    "Invalid wep_default_key index %d",
3279                                    bss->ssid.wep.idx);
3280                         return 1;
3281                 }
3282         } else if (os_strcmp(buf, "wep_key0") == 0 ||
3283                    os_strcmp(buf, "wep_key1") == 0 ||
3284                    os_strcmp(buf, "wep_key2") == 0 ||
3285                    os_strcmp(buf, "wep_key3") == 0) {
3286                 if (hostapd_config_read_wep(&bss->ssid.wep,
3287                                             buf[7] - '0', pos)) {
3288                         wpa_printf(MSG_ERROR, "Line %d: invalid WEP key '%s'",
3289                                    line, buf);
3290                         return 1;
3291                 }
3292 #ifndef CONFIG_NO_VLAN
3293         } else if (os_strcmp(buf, "dynamic_vlan") == 0) {
3294                 bss->ssid.dynamic_vlan = atoi(pos);
3295         } else if (os_strcmp(buf, "per_sta_vif") == 0) {
3296                 bss->ssid.per_sta_vif = atoi(pos);
3297         } else if (os_strcmp(buf, "vlan_file") == 0) {
3298                 if (hostapd_config_read_vlan_file(bss, pos)) {
3299                         wpa_printf(MSG_ERROR, "Line %d: failed to read VLAN file '%s'",
3300                                    line, pos);
3301                         return 1;
3302                 }
3303         } else if (os_strcmp(buf, "vlan_naming") == 0) {
3304                 bss->ssid.vlan_naming = atoi(pos);
3305                 if (bss->ssid.vlan_naming >= DYNAMIC_VLAN_NAMING_END ||
3306                     bss->ssid.vlan_naming < 0) {
3307                         wpa_printf(MSG_ERROR,
3308                                    "Line %d: invalid naming scheme %d",
3309                                    line, bss->ssid.vlan_naming);
3310                         return 1;
3311                 }
3312 #ifdef CONFIG_FULL_DYNAMIC_VLAN
3313         } else if (os_strcmp(buf, "vlan_tagged_interface") == 0) {
3314                 os_free(bss->ssid.vlan_tagged_interface);
3315                 bss->ssid.vlan_tagged_interface = os_strdup(pos);
3316 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
3317 #endif /* CONFIG_NO_VLAN */
3318         } else if (os_strcmp(buf, "ap_table_max_size") == 0) {
3319                 conf->ap_table_max_size = atoi(pos);
3320         } else if (os_strcmp(buf, "ap_table_expiration_time") == 0) {
3321                 conf->ap_table_expiration_time = atoi(pos);
3322         } else if (os_strncmp(buf, "tx_queue_", 9) == 0) {
3323                 if (hostapd_config_tx_queue(conf, buf, pos)) {
3324                         wpa_printf(MSG_ERROR, "Line %d: invalid TX queue item",
3325                                    line);
3326                         return 1;
3327                 }
3328         } else if (os_strcmp(buf, "wme_enabled") == 0 ||
3329                    os_strcmp(buf, "wmm_enabled") == 0) {
3330                 bss->wmm_enabled = atoi(pos);
3331         } else if (os_strcmp(buf, "uapsd_advertisement_enabled") == 0) {
3332                 bss->wmm_uapsd = atoi(pos);
3333         } else if (os_strncmp(buf, "wme_ac_", 7) == 0 ||
3334                    os_strncmp(buf, "wmm_ac_", 7) == 0) {
3335                 if (hostapd_config_wmm_ac(conf->wmm_ac_params, buf, pos)) {
3336                         wpa_printf(MSG_ERROR, "Line %d: invalid WMM ac item",
3337                                    line);
3338                         return 1;
3339                 }
3340         } else if (os_strcmp(buf, "bss") == 0) {
3341                 if (hostapd_config_bss(conf, pos)) {
3342                         wpa_printf(MSG_ERROR, "Line %d: invalid bss item",
3343                                    line);
3344                         return 1;
3345                 }
3346         } else if (os_strcmp(buf, "bssid") == 0) {
3347                 if (hwaddr_aton(pos, bss->bssid)) {
3348                         wpa_printf(MSG_ERROR, "Line %d: invalid bssid item",
3349                                    line);
3350                         return 1;
3351                 }
3352         } else if (os_strcmp(buf, "use_driver_iface_addr") == 0) {
3353                 conf->use_driver_iface_addr = atoi(pos);
3354 #ifdef CONFIG_IEEE80211W
3355         } else if (os_strcmp(buf, "ieee80211w") == 0) {
3356                 bss->ieee80211w = atoi(pos);
3357         } else if (os_strcmp(buf, "group_mgmt_cipher") == 0) {
3358                 if (os_strcmp(pos, "AES-128-CMAC") == 0) {
3359                         bss->group_mgmt_cipher = WPA_CIPHER_AES_128_CMAC;
3360                 } else if (os_strcmp(pos, "BIP-GMAC-128") == 0) {
3361                         bss->group_mgmt_cipher = WPA_CIPHER_BIP_GMAC_128;
3362                 } else if (os_strcmp(pos, "BIP-GMAC-256") == 0) {
3363                         bss->group_mgmt_cipher = WPA_CIPHER_BIP_GMAC_256;
3364                 } else if (os_strcmp(pos, "BIP-CMAC-256") == 0) {
3365                         bss->group_mgmt_cipher = WPA_CIPHER_BIP_CMAC_256;
3366                 } else {
3367                         wpa_printf(MSG_ERROR, "Line %d: invalid group_mgmt_cipher: %s",
3368                                    line, pos);
3369                         return 1;
3370                 }
3371         } else if (os_strcmp(buf, "assoc_sa_query_max_timeout") == 0) {
3372                 bss->assoc_sa_query_max_timeout = atoi(pos);
3373                 if (bss->assoc_sa_query_max_timeout == 0) {
3374                         wpa_printf(MSG_ERROR, "Line %d: invalid assoc_sa_query_max_timeout",
3375                                    line);
3376                         return 1;
3377                 }
3378         } else if (os_strcmp(buf, "assoc_sa_query_retry_timeout") == 0) {
3379                 bss->assoc_sa_query_retry_timeout = atoi(pos);
3380                 if (bss->assoc_sa_query_retry_timeout == 0) {
3381                         wpa_printf(MSG_ERROR, "Line %d: invalid assoc_sa_query_retry_timeout",
3382                                    line);
3383                         return 1;
3384                 }
3385 #endif /* CONFIG_IEEE80211W */
3386 #ifdef CONFIG_OCV
3387         } else if (os_strcmp(buf, "ocv") == 0) {
3388                 bss->ocv = atoi(pos);
3389                 if (bss->ocv && !bss->ieee80211w)
3390                         bss->ieee80211w = 1;
3391 #endif /* CONFIG_OCV */
3392 #ifdef CONFIG_IEEE80211N
3393         } else if (os_strcmp(buf, "ieee80211n") == 0) {
3394                 conf->ieee80211n = atoi(pos);
3395         } else if (os_strcmp(buf, "ht_capab") == 0) {
3396                 if (hostapd_config_ht_capab(conf, pos) < 0) {
3397                         wpa_printf(MSG_ERROR, "Line %d: invalid ht_capab",
3398                                    line);
3399                         return 1;
3400                 }
3401         } else if (os_strcmp(buf, "require_ht") == 0) {
3402                 conf->require_ht = atoi(pos);
3403         } else if (os_strcmp(buf, "obss_interval") == 0) {
3404                 conf->obss_interval = atoi(pos);
3405 #endif /* CONFIG_IEEE80211N */
3406 #ifdef CONFIG_IEEE80211AC
3407         } else if (os_strcmp(buf, "ieee80211ac") == 0) {
3408                 conf->ieee80211ac = atoi(pos);
3409         } else if (os_strcmp(buf, "vht_capab") == 0) {
3410                 if (hostapd_config_vht_capab(conf, pos) < 0) {
3411                         wpa_printf(MSG_ERROR, "Line %d: invalid vht_capab",
3412                                    line);
3413                         return 1;
3414                 }
3415         } else if (os_strcmp(buf, "require_vht") == 0) {
3416                 conf->require_vht = atoi(pos);
3417         } else if (os_strcmp(buf, "vht_oper_chwidth") == 0) {
3418                 conf->vht_oper_chwidth = atoi(pos);
3419         } else if (os_strcmp(buf, "vht_oper_centr_freq_seg0_idx") == 0) {
3420                 conf->vht_oper_centr_freq_seg0_idx = atoi(pos);
3421         } else if (os_strcmp(buf, "vht_oper_centr_freq_seg1_idx") == 0) {
3422                 conf->vht_oper_centr_freq_seg1_idx = atoi(pos);
3423         } else if (os_strcmp(buf, "vendor_vht") == 0) {
3424                 bss->vendor_vht = atoi(pos);
3425         } else if (os_strcmp(buf, "use_sta_nsts") == 0) {
3426                 bss->use_sta_nsts = atoi(pos);
3427 #endif /* CONFIG_IEEE80211AC */
3428 #ifdef CONFIG_IEEE80211AX
3429         } else if (os_strcmp(buf, "ieee80211ax") == 0) {
3430                 conf->ieee80211ax = atoi(pos);
3431         } else if (os_strcmp(buf, "he_su_beamformer") == 0) {
3432                 conf->he_phy_capab.he_su_beamformer = atoi(pos);
3433         } else if (os_strcmp(buf, "he_su_beamformee") == 0) {
3434                 conf->he_phy_capab.he_su_beamformee = atoi(pos);
3435         } else if (os_strcmp(buf, "he_mu_beamformer") == 0) {
3436                 conf->he_phy_capab.he_mu_beamformer = atoi(pos);
3437         } else if (os_strcmp(buf, "he_bss_color") == 0) {
3438                 conf->he_op.he_bss_color = atoi(pos);
3439         } else if (os_strcmp(buf, "he_default_pe_duration") == 0) {
3440                 conf->he_op.he_default_pe_duration = atoi(pos);
3441         } else if (os_strcmp(buf, "he_twt_required") == 0) {
3442                 conf->he_op.he_twt_required = atoi(pos);
3443         } else if (os_strcmp(buf, "he_rts_threshold") == 0) {
3444                 conf->he_op.he_rts_threshold = atoi(pos);
3445         } else if (os_strcmp(buf, "he_mu_edca_qos_info_param_count") == 0) {
3446                 conf->he_mu_edca.he_qos_info |=
3447                         set_he_cap(atoi(pos), HE_QOS_INFO_EDCA_PARAM_SET_COUNT);
3448         } else if (os_strcmp(buf, "he_mu_edca_qos_info_q_ack") == 0) {
3449                 conf->he_mu_edca.he_qos_info |=
3450                         set_he_cap(atoi(pos), HE_QOS_INFO_Q_ACK);
3451         } else if (os_strcmp(buf, "he_mu_edca_qos_info_queue_request") == 0) {
3452                 conf->he_mu_edca.he_qos_info |=
3453                         set_he_cap(atoi(pos), HE_QOS_INFO_QUEUE_REQUEST);
3454         } else if (os_strcmp(buf, "he_mu_edca_qos_info_txop_request") == 0) {
3455                 conf->he_mu_edca.he_qos_info |=
3456                         set_he_cap(atoi(pos), HE_QOS_INFO_TXOP_REQUEST);
3457         } else if (os_strcmp(buf, "he_mu_edca_ac_be_aifsn") == 0) {
3458                 conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_ACI_IDX] |=
3459                         set_he_cap(atoi(pos), HE_MU_AC_PARAM_AIFSN);
3460         } else if (os_strcmp(buf, "he_mu_edca_ac_be_acm") == 0) {
3461                 conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_ACI_IDX] |=
3462                         set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACM);
3463         } else if (os_strcmp(buf, "he_mu_edca_ac_be_aci") == 0) {
3464                 conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_ACI_IDX] |=
3465                         set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACI);
3466         } else if (os_strcmp(buf, "he_mu_edca_ac_be_ecwmin") == 0) {
3467                 conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_ECW_IDX] |=
3468                         set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMIN);
3469         } else if (os_strcmp(buf, "he_mu_edca_ac_be_ecwmax") == 0) {
3470                 conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_ECW_IDX] |=
3471                         set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMAX);
3472         } else if (os_strcmp(buf, "he_mu_edca_ac_be_timer") == 0) {
3473                 conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_TIMER_IDX] =
3474                         atoi(pos) & 0xff;
3475         } else if (os_strcmp(buf, "he_mu_edca_ac_bk_aifsn") == 0) {
3476                 conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_ACI_IDX] |=
3477                         set_he_cap(atoi(pos), HE_MU_AC_PARAM_AIFSN);
3478         } else if (os_strcmp(buf, "he_mu_edca_ac_bk_acm") == 0) {
3479                 conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_ACI_IDX] |=
3480                         set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACM);
3481         } else if (os_strcmp(buf, "he_mu_edca_ac_bk_aci") == 0) {
3482                 conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_ACI_IDX] |=
3483                         set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACI);
3484         } else if (os_strcmp(buf, "he_mu_edca_ac_bk_ecwmin") == 0) {
3485                 conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_ECW_IDX] |=
3486                         set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMIN);
3487         } else if (os_strcmp(buf, "he_mu_edca_ac_bk_ecwmax") == 0) {
3488                 conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_ECW_IDX] |=
3489                         set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMAX);
3490         } else if (os_strcmp(buf, "he_mu_edca_ac_bk_timer") == 0) {
3491                 conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_TIMER_IDX] =
3492                         atoi(pos) & 0xff;
3493         } else if (os_strcmp(buf, "he_mu_edca_ac_vi_aifsn") == 0) {
3494                 conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_ACI_IDX] |=
3495                         set_he_cap(atoi(pos), HE_MU_AC_PARAM_AIFSN);
3496         } else if (os_strcmp(buf, "he_mu_edca_ac_vi_acm") == 0) {
3497                 conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_ACI_IDX] |=
3498                         set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACM);
3499         } else if (os_strcmp(buf, "he_mu_edca_ac_vi_aci") == 0) {
3500                 conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_ACI_IDX] |=
3501                         set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACI);
3502         } else if (os_strcmp(buf, "he_mu_edca_ac_vi_ecwmin") == 0) {
3503                 conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_ECW_IDX] |=
3504                         set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMIN);
3505         } else if (os_strcmp(buf, "he_mu_edca_ac_vi_ecwmax") == 0) {
3506                 conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_ECW_IDX] |=
3507                         set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMAX);
3508         } else if (os_strcmp(buf, "he_mu_edca_ac_vi_timer") == 0) {
3509                 conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_TIMER_IDX] =
3510                         atoi(pos) & 0xff;
3511         } else if (os_strcmp(buf, "he_mu_edca_ac_vo_aifsn") == 0) {
3512                 conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_ACI_IDX] |=
3513                         set_he_cap(atoi(pos), HE_MU_AC_PARAM_AIFSN);
3514         } else if (os_strcmp(buf, "he_mu_edca_ac_vo_acm") == 0) {
3515                 conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_ACI_IDX] |=
3516                         set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACM);
3517         } else if (os_strcmp(buf, "he_mu_edca_ac_vo_aci") == 0) {
3518                 conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_ACI_IDX] |=
3519                         set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACI);
3520         } else if (os_strcmp(buf, "he_mu_edca_ac_vo_ecwmin") == 0) {
3521                 conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_ECW_IDX] |=
3522                         set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMIN);
3523         } else if (os_strcmp(buf, "he_mu_edca_ac_vo_ecwmax") == 0) {
3524                 conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_ECW_IDX] |=
3525                         set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMAX);
3526         } else if (os_strcmp(buf, "he_mu_edca_ac_vo_timer") == 0) {
3527                 conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_TIMER_IDX] =
3528                         atoi(pos) & 0xff;
3529 #endif /* CONFIG_IEEE80211AX */
3530         } else if (os_strcmp(buf, "max_listen_interval") == 0) {
3531                 bss->max_listen_interval = atoi(pos);
3532         } else if (os_strcmp(buf, "disable_pmksa_caching") == 0) {
3533                 bss->disable_pmksa_caching = atoi(pos);
3534         } else if (os_strcmp(buf, "okc") == 0) {
3535                 bss->okc = atoi(pos);
3536 #ifdef CONFIG_WPS
3537         } else if (os_strcmp(buf, "wps_state") == 0) {
3538                 bss->wps_state = atoi(pos);
3539                 if (bss->wps_state < 0 || bss->wps_state > 2) {
3540                         wpa_printf(MSG_ERROR, "Line %d: invalid wps_state",
3541                                    line);
3542                         return 1;
3543                 }
3544         } else if (os_strcmp(buf, "wps_independent") == 0) {
3545                 bss->wps_independent = atoi(pos);
3546         } else if (os_strcmp(buf, "ap_setup_locked") == 0) {
3547                 bss->ap_setup_locked = atoi(pos);
3548         } else if (os_strcmp(buf, "uuid") == 0) {
3549                 if (uuid_str2bin(pos, bss->uuid)) {
3550                         wpa_printf(MSG_ERROR, "Line %d: invalid UUID", line);
3551                         return 1;
3552                 }
3553         } else if (os_strcmp(buf, "wps_pin_requests") == 0) {
3554                 os_free(bss->wps_pin_requests);
3555                 bss->wps_pin_requests = os_strdup(pos);
3556         } else if (os_strcmp(buf, "device_name") == 0) {
3557                 if (os_strlen(pos) > WPS_DEV_NAME_MAX_LEN) {
3558                         wpa_printf(MSG_ERROR, "Line %d: Too long "
3559                                    "device_name", line);
3560                         return 1;
3561                 }
3562                 os_free(bss->device_name);
3563                 bss->device_name = os_strdup(pos);
3564         } else if (os_strcmp(buf, "manufacturer") == 0) {
3565                 if (os_strlen(pos) > 64) {
3566                         wpa_printf(MSG_ERROR, "Line %d: Too long manufacturer",
3567                                    line);
3568                         return 1;
3569                 }
3570                 os_free(bss->manufacturer);
3571                 bss->manufacturer = os_strdup(pos);
3572         } else if (os_strcmp(buf, "model_name") == 0) {
3573                 if (os_strlen(pos) > 32) {
3574                         wpa_printf(MSG_ERROR, "Line %d: Too long model_name",
3575                                    line);
3576                         return 1;
3577                 }
3578                 os_free(bss->model_name);
3579                 bss->model_name = os_strdup(pos);
3580         } else if (os_strcmp(buf, "model_number") == 0) {
3581                 if (os_strlen(pos) > 32) {
3582                         wpa_printf(MSG_ERROR, "Line %d: Too long model_number",
3583                                    line);
3584                         return 1;
3585                 }
3586                 os_free(bss->model_number);
3587                 bss->model_number = os_strdup(pos);
3588         } else if (os_strcmp(buf, "serial_number") == 0) {
3589                 if (os_strlen(pos) > 32) {
3590                         wpa_printf(MSG_ERROR, "Line %d: Too long serial_number",
3591                                    line);
3592                         return 1;
3593                 }
3594                 os_free(bss->serial_number);
3595                 bss->serial_number = os_strdup(pos);
3596         } else if (os_strcmp(buf, "device_type") == 0) {
3597                 if (wps_dev_type_str2bin(pos, bss->device_type))
3598                         return 1;
3599         } else if (os_strcmp(buf, "config_methods") == 0) {
3600                 os_free(bss->config_methods);
3601                 bss->config_methods = os_strdup(pos);
3602         } else if (os_strcmp(buf, "os_version") == 0) {
3603                 if (hexstr2bin(pos, bss->os_version, 4)) {
3604                         wpa_printf(MSG_ERROR, "Line %d: invalid os_version",
3605                                    line);
3606                         return 1;
3607                 }
3608         } else if (os_strcmp(buf, "ap_pin") == 0) {
3609                 os_free(bss->ap_pin);
3610                 if (*pos == '\0')
3611                         bss->ap_pin = NULL;
3612                 else
3613                         bss->ap_pin = os_strdup(pos);
3614         } else if (os_strcmp(buf, "skip_cred_build") == 0) {
3615                 bss->skip_cred_build = atoi(pos);
3616         } else if (os_strcmp(buf, "extra_cred") == 0) {
3617                 os_free(bss->extra_cred);
3618                 bss->extra_cred = (u8 *) os_readfile(pos, &bss->extra_cred_len);
3619                 if (bss->extra_cred == NULL) {
3620                         wpa_printf(MSG_ERROR, "Line %d: could not read Credentials from '%s'",
3621                                    line, pos);
3622                         return 1;
3623                 }
3624         } else if (os_strcmp(buf, "wps_cred_processing") == 0) {
3625                 bss->wps_cred_processing = atoi(pos);
3626         } else if (os_strcmp(buf, "wps_cred_add_sae") == 0) {
3627                 bss->wps_cred_add_sae = atoi(pos);
3628         } else if (os_strcmp(buf, "ap_settings") == 0) {
3629                 os_free(bss->ap_settings);
3630                 bss->ap_settings =
3631                         (u8 *) os_readfile(pos, &bss->ap_settings_len);
3632                 if (bss->ap_settings == NULL) {
3633                         wpa_printf(MSG_ERROR, "Line %d: could not read AP Settings from '%s'",
3634                                    line, pos);
3635                         return 1;
3636                 }
3637         } else if (os_strcmp(buf, "multi_ap_backhaul_ssid") == 0) {
3638                 size_t slen;
3639                 char *str = wpa_config_parse_string(pos, &slen);
3640
3641                 if (!str || slen < 1 || slen > SSID_MAX_LEN) {
3642                         wpa_printf(MSG_ERROR, "Line %d: invalid SSID '%s'",
3643                                    line, pos);
3644                         os_free(str);
3645                         return 1;
3646                 }
3647                 os_memcpy(bss->multi_ap_backhaul_ssid.ssid, str, slen);
3648                 bss->multi_ap_backhaul_ssid.ssid_len = slen;
3649                 bss->multi_ap_backhaul_ssid.ssid_set = 1;
3650                 os_free(str);
3651         } else if (os_strcmp(buf, "multi_ap_backhaul_wpa_passphrase") == 0) {
3652                 int len = os_strlen(pos);
3653
3654                 if (len < 8 || len > 63) {
3655                         wpa_printf(MSG_ERROR,
3656                                    "Line %d: invalid WPA passphrase length %d (expected 8..63)",
3657                                    line, len);
3658                         return 1;
3659                 }
3660                 os_free(bss->multi_ap_backhaul_ssid.wpa_passphrase);
3661                 bss->multi_ap_backhaul_ssid.wpa_passphrase = os_strdup(pos);
3662                 if (bss->multi_ap_backhaul_ssid.wpa_passphrase) {
3663                         hostapd_config_clear_wpa_psk(
3664                                 &bss->multi_ap_backhaul_ssid.wpa_psk);
3665                         bss->multi_ap_backhaul_ssid.wpa_passphrase_set = 1;
3666                 }
3667         } else if (os_strcmp(buf, "multi_ap_backhaul_wpa_psk") == 0) {
3668                 hostapd_config_clear_wpa_psk(
3669                         &bss->multi_ap_backhaul_ssid.wpa_psk);
3670                 bss->multi_ap_backhaul_ssid.wpa_psk =
3671                         os_zalloc(sizeof(struct hostapd_wpa_psk));
3672                 if (!bss->multi_ap_backhaul_ssid.wpa_psk)
3673                         return 1;
3674                 if (hexstr2bin(pos, bss->multi_ap_backhaul_ssid.wpa_psk->psk,
3675                                PMK_LEN) ||
3676                     pos[PMK_LEN * 2] != '\0') {
3677                         wpa_printf(MSG_ERROR, "Line %d: Invalid PSK '%s'.",
3678                                    line, pos);
3679                         hostapd_config_clear_wpa_psk(
3680                                 &bss->multi_ap_backhaul_ssid.wpa_psk);
3681                         return 1;
3682                 }
3683                 bss->multi_ap_backhaul_ssid.wpa_psk->group = 1;
3684                 os_free(bss->multi_ap_backhaul_ssid.wpa_passphrase);
3685                 bss->multi_ap_backhaul_ssid.wpa_passphrase = NULL;
3686                 bss->multi_ap_backhaul_ssid.wpa_psk_set = 1;
3687         } else if (os_strcmp(buf, "upnp_iface") == 0) {
3688                 os_free(bss->upnp_iface);
3689                 bss->upnp_iface = os_strdup(pos);
3690         } else if (os_strcmp(buf, "friendly_name") == 0) {
3691                 os_free(bss->friendly_name);
3692                 bss->friendly_name = os_strdup(pos);
3693         } else if (os_strcmp(buf, "manufacturer_url") == 0) {
3694                 os_free(bss->manufacturer_url);
3695                 bss->manufacturer_url = os_strdup(pos);
3696         } else if (os_strcmp(buf, "model_description") == 0) {
3697                 os_free(bss->model_description);
3698                 bss->model_description = os_strdup(pos);
3699         } else if (os_strcmp(buf, "model_url") == 0) {
3700                 os_free(bss->model_url);
3701                 bss->model_url = os_strdup(pos);
3702         } else if (os_strcmp(buf, "upc") == 0) {
3703                 os_free(bss->upc);
3704                 bss->upc = os_strdup(pos);
3705         } else if (os_strcmp(buf, "pbc_in_m1") == 0) {
3706                 bss->pbc_in_m1 = atoi(pos);
3707         } else if (os_strcmp(buf, "server_id") == 0) {
3708                 os_free(bss->server_id);
3709                 bss->server_id = os_strdup(pos);
3710 #ifdef CONFIG_WPS_NFC
3711         } else if (os_strcmp(buf, "wps_nfc_dev_pw_id") == 0) {
3712                 bss->wps_nfc_dev_pw_id = atoi(pos);
3713                 if (bss->wps_nfc_dev_pw_id < 0x10 ||
3714                     bss->wps_nfc_dev_pw_id > 0xffff) {
3715                         wpa_printf(MSG_ERROR, "Line %d: Invalid wps_nfc_dev_pw_id value",
3716                                    line);
3717                         return 1;
3718                 }
3719                 bss->wps_nfc_pw_from_config = 1;
3720         } else if (os_strcmp(buf, "wps_nfc_dh_pubkey") == 0) {
3721                 wpabuf_free(bss->wps_nfc_dh_pubkey);
3722                 bss->wps_nfc_dh_pubkey = wpabuf_parse_bin(pos);
3723                 bss->wps_nfc_pw_from_config = 1;
3724         } else if (os_strcmp(buf, "wps_nfc_dh_privkey") == 0) {
3725                 wpabuf_free(bss->wps_nfc_dh_privkey);
3726                 bss->wps_nfc_dh_privkey = wpabuf_parse_bin(pos);
3727                 bss->wps_nfc_pw_from_config = 1;
3728         } else if (os_strcmp(buf, "wps_nfc_dev_pw") == 0) {
3729                 wpabuf_free(bss->wps_nfc_dev_pw);
3730                 bss->wps_nfc_dev_pw = wpabuf_parse_bin(pos);
3731                 bss->wps_nfc_pw_from_config = 1;
3732 #endif /* CONFIG_WPS_NFC */
3733 #endif /* CONFIG_WPS */
3734 #ifdef CONFIG_P2P_MANAGER
3735         } else if (os_strcmp(buf, "manage_p2p") == 0) {
3736                 if (atoi(pos))
3737                         bss->p2p |= P2P_MANAGE;
3738                 else
3739                         bss->p2p &= ~P2P_MANAGE;
3740         } else if (os_strcmp(buf, "allow_cross_connection") == 0) {
3741                 if (atoi(pos))
3742                         bss->p2p |= P2P_ALLOW_CROSS_CONNECTION;
3743                 else
3744                         bss->p2p &= ~P2P_ALLOW_CROSS_CONNECTION;
3745 #endif /* CONFIG_P2P_MANAGER */
3746         } else if (os_strcmp(buf, "disassoc_low_ack") == 0) {
3747                 bss->disassoc_low_ack = atoi(pos);
3748         } else if (os_strcmp(buf, "tdls_prohibit") == 0) {
3749                 if (atoi(pos))
3750                         bss->tdls |= TDLS_PROHIBIT;
3751                 else
3752                         bss->tdls &= ~TDLS_PROHIBIT;
3753         } else if (os_strcmp(buf, "tdls_prohibit_chan_switch") == 0) {
3754                 if (atoi(pos))
3755                         bss->tdls |= TDLS_PROHIBIT_CHAN_SWITCH;
3756                 else
3757                         bss->tdls &= ~TDLS_PROHIBIT_CHAN_SWITCH;
3758 #ifdef CONFIG_RSN_TESTING
3759         } else if (os_strcmp(buf, "rsn_testing") == 0) {
3760                 extern int rsn_testing;
3761                 rsn_testing = atoi(pos);
3762 #endif /* CONFIG_RSN_TESTING */
3763         } else if (os_strcmp(buf, "time_advertisement") == 0) {
3764                 bss->time_advertisement = atoi(pos);
3765         } else if (os_strcmp(buf, "time_zone") == 0) {
3766                 size_t tz_len = os_strlen(pos);
3767                 if (tz_len < 4 || tz_len > 255) {
3768                         wpa_printf(MSG_DEBUG, "Line %d: invalid time_zone",
3769                                    line);
3770                         return 1;
3771                 }
3772                 os_free(bss->time_zone);
3773                 bss->time_zone = os_strdup(pos);
3774                 if (bss->time_zone == NULL)
3775                         return 1;
3776 #ifdef CONFIG_WNM_AP
3777         } else if (os_strcmp(buf, "wnm_sleep_mode") == 0) {
3778                 bss->wnm_sleep_mode = atoi(pos);
3779         } else if (os_strcmp(buf, "wnm_sleep_mode_no_keys") == 0) {
3780                 bss->wnm_sleep_mode_no_keys = atoi(pos);
3781         } else if (os_strcmp(buf, "bss_transition") == 0) {
3782                 bss->bss_transition = atoi(pos);
3783 #endif /* CONFIG_WNM_AP */
3784 #ifdef CONFIG_INTERWORKING
3785         } else if (os_strcmp(buf, "interworking") == 0) {
3786                 bss->interworking = atoi(pos);
3787         } else if (os_strcmp(buf, "access_network_type") == 0) {
3788                 bss->access_network_type = atoi(pos);
3789                 if (bss->access_network_type < 0 ||
3790                     bss->access_network_type > 15) {
3791                         wpa_printf(MSG_ERROR,
3792                                    "Line %d: invalid access_network_type",
3793                                    line);
3794                         return 1;
3795                 }
3796         } else if (os_strcmp(buf, "internet") == 0) {
3797                 bss->internet = atoi(pos);
3798         } else if (os_strcmp(buf, "asra") == 0) {
3799                 bss->asra = atoi(pos);
3800         } else if (os_strcmp(buf, "esr") == 0) {
3801                 bss->esr = atoi(pos);
3802         } else if (os_strcmp(buf, "uesa") == 0) {
3803                 bss->uesa = atoi(pos);
3804         } else if (os_strcmp(buf, "venue_group") == 0) {
3805                 bss->venue_group = atoi(pos);
3806                 bss->venue_info_set = 1;
3807         } else if (os_strcmp(buf, "venue_type") == 0) {
3808                 bss->venue_type = atoi(pos);
3809                 bss->venue_info_set = 1;
3810         } else if (os_strcmp(buf, "hessid") == 0) {
3811                 if (hwaddr_aton(pos, bss->hessid)) {
3812                         wpa_printf(MSG_ERROR, "Line %d: invalid hessid", line);
3813                         return 1;
3814                 }
3815         } else if (os_strcmp(buf, "roaming_consortium") == 0) {
3816                 if (parse_roaming_consortium(bss, pos, line) < 0)
3817                         return 1;
3818         } else if (os_strcmp(buf, "venue_name") == 0) {
3819                 if (parse_venue_name(bss, pos, line) < 0)
3820                         return 1;
3821         } else if (os_strcmp(buf, "venue_url") == 0) {
3822                 if (parse_venue_url(bss, pos, line) < 0)
3823                         return 1;
3824         } else if (os_strcmp(buf, "network_auth_type") == 0) {
3825                 u8 auth_type;
3826                 u16 redirect_url_len;
3827                 if (hexstr2bin(pos, &auth_type, 1)) {
3828                         wpa_printf(MSG_ERROR,
3829                                    "Line %d: Invalid network_auth_type '%s'",
3830                                    line, pos);
3831                         return 1;
3832                 }
3833                 if (auth_type == 0 || auth_type == 2)
3834                         redirect_url_len = os_strlen(pos + 2);
3835                 else
3836                         redirect_url_len = 0;
3837                 os_free(bss->network_auth_type);
3838                 bss->network_auth_type = os_malloc(redirect_url_len + 3 + 1);
3839                 if (bss->network_auth_type == NULL)
3840                         return 1;
3841                 *bss->network_auth_type = auth_type;
3842                 WPA_PUT_LE16(bss->network_auth_type + 1, redirect_url_len);
3843                 if (redirect_url_len)
3844                         os_memcpy(bss->network_auth_type + 3, pos + 2,
3845                                   redirect_url_len);
3846                 bss->network_auth_type_len = 3 + redirect_url_len;
3847         } else if (os_strcmp(buf, "ipaddr_type_availability") == 0) {
3848                 if (hexstr2bin(pos, &bss->ipaddr_type_availability, 1)) {
3849                         wpa_printf(MSG_ERROR, "Line %d: Invalid ipaddr_type_availability '%s'",
3850                                    line, pos);
3851                         bss->ipaddr_type_configured = 0;
3852                         return 1;
3853                 }
3854                 bss->ipaddr_type_configured = 1;
3855         } else if (os_strcmp(buf, "domain_name") == 0) {
3856                 int j, num_domains, domain_len, domain_list_len = 0;
3857                 char *tok_start, *tok_prev;
3858                 u8 *domain_list, *domain_ptr;
3859
3860                 domain_list_len = os_strlen(pos) + 1;
3861                 domain_list = os_malloc(domain_list_len);
3862                 if (domain_list == NULL)
3863                         return 1;
3864
3865                 domain_ptr = domain_list;
3866                 tok_prev = pos;
3867                 num_domains = 1;
3868                 while ((tok_prev = os_strchr(tok_prev, ','))) {
3869                         num_domains++;
3870                         tok_prev++;
3871                 }
3872                 tok_prev = pos;
3873                 for (j = 0; j < num_domains; j++) {
3874                         tok_start = os_strchr(tok_prev, ',');
3875                         if (tok_start) {
3876                                 domain_len = tok_start - tok_prev;
3877                                 *domain_ptr = domain_len;
3878                                 os_memcpy(domain_ptr + 1, tok_prev, domain_len);
3879                                 domain_ptr += domain_len + 1;
3880                                 tok_prev = ++tok_start;
3881                         } else {
3882                                 domain_len = os_strlen(tok_prev);
3883                                 *domain_ptr = domain_len;
3884                                 os_memcpy(domain_ptr + 1, tok_prev, domain_len);
3885                                 domain_ptr += domain_len + 1;
3886                         }
3887                 }
3888
3889                 os_free(bss->domain_name);
3890                 bss->domain_name = domain_list;
3891                 bss->domain_name_len = domain_list_len;
3892         } else if (os_strcmp(buf, "anqp_3gpp_cell_net") == 0) {
3893                 if (parse_3gpp_cell_net(bss, pos, line) < 0)
3894                         return 1;
3895         } else if (os_strcmp(buf, "nai_realm") == 0) {
3896                 if (parse_nai_realm(bss, pos, line) < 0)
3897                         return 1;
3898         } else if (os_strcmp(buf, "anqp_elem") == 0) {
3899                 if (parse_anqp_elem(bss, pos, line) < 0)
3900                         return 1;
3901         } else if (os_strcmp(buf, "gas_frag_limit") == 0) {
3902                 int val = atoi(pos);
3903
3904                 if (val <= 0) {
3905                         wpa_printf(MSG_ERROR,
3906                                    "Line %d: Invalid gas_frag_limit '%s'",
3907                                    line, pos);
3908                         return 1;
3909                 }
3910                 bss->gas_frag_limit = val;
3911         } else if (os_strcmp(buf, "gas_comeback_delay") == 0) {
3912                 bss->gas_comeback_delay = atoi(pos);
3913         } else if (os_strcmp(buf, "qos_map_set") == 0) {
3914                 if (parse_qos_map_set(bss, pos, line) < 0)
3915                         return 1;
3916 #endif /* CONFIG_INTERWORKING */
3917 #ifdef CONFIG_RADIUS_TEST
3918         } else if (os_strcmp(buf, "dump_msk_file") == 0) {
3919                 os_free(bss->dump_msk_file);
3920                 bss->dump_msk_file = os_strdup(pos);
3921 #endif /* CONFIG_RADIUS_TEST */
3922 #ifdef CONFIG_PROXYARP
3923         } else if (os_strcmp(buf, "proxy_arp") == 0) {
3924                 bss->proxy_arp = atoi(pos);
3925 #endif /* CONFIG_PROXYARP */
3926 #ifdef CONFIG_HS20
3927         } else if (os_strcmp(buf, "hs20") == 0) {
3928                 bss->hs20 = atoi(pos);
3929         } else if (os_strcmp(buf, "hs20_release") == 0) {
3930                 int val = atoi(pos);
3931
3932                 if (val < 1 || val > (HS20_VERSION >> 4) + 1) {
3933                         wpa_printf(MSG_ERROR,
3934                                    "Line %d: Unsupported hs20_release: %s",
3935                                    line, pos);
3936                         return 1;
3937                 }
3938                 bss->hs20_release = val;
3939         } else if (os_strcmp(buf, "disable_dgaf") == 0) {
3940                 bss->disable_dgaf = atoi(pos);
3941         } else if (os_strcmp(buf, "na_mcast_to_ucast") == 0) {
3942                 bss->na_mcast_to_ucast = atoi(pos);
3943         } else if (os_strcmp(buf, "osen") == 0) {
3944                 bss->osen = atoi(pos);
3945         } else if (os_strcmp(buf, "anqp_domain_id") == 0) {
3946                 bss->anqp_domain_id = atoi(pos);
3947         } else if (os_strcmp(buf, "hs20_deauth_req_timeout") == 0) {
3948                 bss->hs20_deauth_req_timeout = atoi(pos);
3949         } else if (os_strcmp(buf, "hs20_oper_friendly_name") == 0) {
3950                 if (hs20_parse_oper_friendly_name(bss, pos, line) < 0)
3951                         return 1;
3952         } else if (os_strcmp(buf, "hs20_wan_metrics") == 0) {
3953                 if (hs20_parse_wan_metrics(bss, pos, line) < 0)
3954                         return 1;
3955         } else if (os_strcmp(buf, "hs20_conn_capab") == 0) {
3956                 if (hs20_parse_conn_capab(bss, pos, line) < 0) {
3957                         return 1;
3958                 }
3959         } else if (os_strcmp(buf, "hs20_operating_class") == 0) {
3960                 u8 *oper_class;
3961                 size_t oper_class_len;
3962                 oper_class_len = os_strlen(pos);
3963                 if (oper_class_len < 2 || (oper_class_len & 0x01)) {
3964                         wpa_printf(MSG_ERROR,
3965                                    "Line %d: Invalid hs20_operating_class '%s'",
3966                                    line, pos);
3967                         return 1;
3968                 }
3969                 oper_class_len /= 2;
3970                 oper_class = os_malloc(oper_class_len);
3971                 if (oper_class == NULL)
3972                         return 1;
3973                 if (hexstr2bin(pos, oper_class, oper_class_len)) {
3974                         wpa_printf(MSG_ERROR,
3975                                    "Line %d: Invalid hs20_operating_class '%s'",
3976                                    line, pos);
3977                         os_free(oper_class);
3978                         return 1;
3979                 }
3980                 os_free(bss->hs20_operating_class);
3981                 bss->hs20_operating_class = oper_class;
3982                 bss->hs20_operating_class_len = oper_class_len;
3983         } else if (os_strcmp(buf, "hs20_icon") == 0) {
3984                 if (hs20_parse_icon(bss, pos) < 0) {
3985                         wpa_printf(MSG_ERROR, "Line %d: Invalid hs20_icon '%s'",
3986                                    line, pos);
3987                         return 1;
3988                 }
3989         } else if (os_strcmp(buf, "osu_ssid") == 0) {
3990                 if (hs20_parse_osu_ssid(bss, pos, line) < 0)
3991                         return 1;
3992         } else if (os_strcmp(buf, "osu_server_uri") == 0) {
3993                 if (hs20_parse_osu_server_uri(bss, pos, line) < 0)
3994                         return 1;
3995         } else if (os_strcmp(buf, "osu_friendly_name") == 0) {
3996                 if (hs20_parse_osu_friendly_name(bss, pos, line) < 0)
3997                         return 1;
3998         } else if (os_strcmp(buf, "osu_nai") == 0) {
3999                 if (hs20_parse_osu_nai(bss, pos, line) < 0)
4000                         return 1;
4001         } else if (os_strcmp(buf, "osu_nai2") == 0) {
4002                 if (hs20_parse_osu_nai2(bss, pos, line) < 0)
4003                         return 1;
4004         } else if (os_strcmp(buf, "osu_method_list") == 0) {
4005                 if (hs20_parse_osu_method_list(bss, pos, line) < 0)
4006                         return 1;
4007         } else if (os_strcmp(buf, "osu_icon") == 0) {
4008                 if (hs20_parse_osu_icon(bss, pos, line) < 0)
4009                         return 1;
4010         } else if (os_strcmp(buf, "osu_service_desc") == 0) {
4011                 if (hs20_parse_osu_service_desc(bss, pos, line) < 0)
4012                         return 1;
4013         } else if (os_strcmp(buf, "operator_icon") == 0) {
4014                 if (hs20_parse_operator_icon(bss, pos, line) < 0)
4015                         return 1;
4016         } else if (os_strcmp(buf, "subscr_remediation_url") == 0) {
4017                 os_free(bss->subscr_remediation_url);
4018                 bss->subscr_remediation_url = os_strdup(pos);
4019         } else if (os_strcmp(buf, "subscr_remediation_method") == 0) {
4020                 bss->subscr_remediation_method = atoi(pos);
4021         } else if (os_strcmp(buf, "hs20_t_c_filename") == 0) {
4022                 os_free(bss->t_c_filename);
4023                 bss->t_c_filename = os_strdup(pos);
4024         } else if (os_strcmp(buf, "hs20_t_c_timestamp") == 0) {
4025                 bss->t_c_timestamp = strtol(pos, NULL, 0);
4026         } else if (os_strcmp(buf, "hs20_t_c_server_url") == 0) {
4027                 os_free(bss->t_c_server_url);
4028                 bss->t_c_server_url = os_strdup(pos);
4029         } else if (os_strcmp(buf, "hs20_sim_provisioning_url") == 0) {
4030                 os_free(bss->hs20_sim_provisioning_url);
4031                 bss->hs20_sim_provisioning_url = os_strdup(pos);
4032 #endif /* CONFIG_HS20 */
4033 #ifdef CONFIG_MBO
4034         } else if (os_strcmp(buf, "mbo") == 0) {
4035                 bss->mbo_enabled = atoi(pos);
4036         } else if (os_strcmp(buf, "mbo_cell_data_conn_pref") == 0) {
4037                 bss->mbo_cell_data_conn_pref = atoi(pos);
4038         } else if (os_strcmp(buf, "oce") == 0) {
4039                 bss->oce = atoi(pos);
4040 #endif /* CONFIG_MBO */
4041 #ifdef CONFIG_TESTING_OPTIONS
4042 #define PARSE_TEST_PROBABILITY(_val)                            \
4043         } else if (os_strcmp(buf, #_val) == 0) {                \
4044                 char *end;                                      \
4045                                                                 \
4046                 conf->_val = strtod(pos, &end);                 \
4047                 if (*end || conf->_val < 0.0 ||                 \
4048                     conf->_val > 1.0) {                         \
4049                         wpa_printf(MSG_ERROR,                   \
4050                                    "Line %d: Invalid value '%s'", \
4051                                    line, pos);                  \
4052                         return 1;                               \
4053                 }
4054         PARSE_TEST_PROBABILITY(ignore_probe_probability)
4055         PARSE_TEST_PROBABILITY(ignore_auth_probability)
4056         PARSE_TEST_PROBABILITY(ignore_assoc_probability)
4057         PARSE_TEST_PROBABILITY(ignore_reassoc_probability)
4058         PARSE_TEST_PROBABILITY(corrupt_gtk_rekey_mic_probability)
4059         } else if (os_strcmp(buf, "ecsa_ie_only") == 0) {
4060                 conf->ecsa_ie_only = atoi(pos);
4061         } else if (os_strcmp(buf, "bss_load_test") == 0) {
4062                 WPA_PUT_LE16(bss->bss_load_test, atoi(pos));
4063                 pos = os_strchr(pos, ':');
4064                 if (pos == NULL) {
4065                         wpa_printf(MSG_ERROR, "Line %d: Invalid bss_load_test",
4066                                    line);
4067                         return 1;
4068                 }
4069                 pos++;
4070                 bss->bss_load_test[2] = atoi(pos);
4071                 pos = os_strchr(pos, ':');
4072                 if (pos == NULL) {
4073                         wpa_printf(MSG_ERROR, "Line %d: Invalid bss_load_test",
4074                                    line);
4075                         return 1;
4076                 }
4077                 pos++;
4078                 WPA_PUT_LE16(&bss->bss_load_test[3], atoi(pos));
4079                 bss->bss_load_test_set = 1;
4080         } else if (os_strcmp(buf, "radio_measurements") == 0) {
4081                 /*
4082                  * DEPRECATED: This parameter will be removed in the future.
4083                  * Use rrm_neighbor_report instead.
4084                  */
4085                 int val = atoi(pos);
4086
4087                 if (val & BIT(0))
4088                         bss->radio_measurements[0] |=
4089                                 WLAN_RRM_CAPS_NEIGHBOR_REPORT;
4090         } else if (os_strcmp(buf, "own_ie_override") == 0) {
4091                 struct wpabuf *tmp;
4092                 size_t len = os_strlen(pos) / 2;
4093
4094                 tmp = wpabuf_alloc(len);
4095                 if (!tmp)
4096                         return 1;
4097
4098                 if (hexstr2bin(pos, wpabuf_put(tmp, len), len)) {
4099                         wpabuf_free(tmp);
4100                         wpa_printf(MSG_ERROR,
4101                                    "Line %d: Invalid own_ie_override '%s'",
4102                                    line, pos);
4103                         return 1;
4104                 }
4105
4106                 wpabuf_free(bss->own_ie_override);
4107                 bss->own_ie_override = tmp;
4108         } else if (os_strcmp(buf, "sae_reflection_attack") == 0) {
4109                 bss->sae_reflection_attack = atoi(pos);
4110         } else if (os_strcmp(buf, "sae_commit_override") == 0) {
4111                 wpabuf_free(bss->sae_commit_override);
4112                 bss->sae_commit_override = wpabuf_parse_bin(pos);
4113 #endif /* CONFIG_TESTING_OPTIONS */
4114 #ifdef CONFIG_SAE
4115         } else if (os_strcmp(buf, "sae_password") == 0) {
4116                 if (parse_sae_password(bss, pos) < 0) {
4117                         wpa_printf(MSG_ERROR, "Line %d: Invalid sae_password",
4118                                    line);
4119                         return 1;
4120                 }
4121 #endif /* CONFIG_SAE */
4122         } else if (os_strcmp(buf, "vendor_elements") == 0) {
4123                 if (parse_wpabuf_hex(line, buf, &bss->vendor_elements, pos))
4124                         return 1;
4125         } else if (os_strcmp(buf, "assocresp_elements") == 0) {
4126                 if (parse_wpabuf_hex(line, buf, &bss->assocresp_elements, pos))
4127                         return 1;
4128         } else if (os_strcmp(buf, "sae_anti_clogging_threshold") == 0) {
4129                 bss->sae_anti_clogging_threshold = atoi(pos);
4130         } else if (os_strcmp(buf, "sae_sync") == 0) {
4131                 bss->sae_sync = atoi(pos);
4132         } else if (os_strcmp(buf, "sae_groups") == 0) {
4133                 if (hostapd_parse_intlist(&bss->sae_groups, pos)) {
4134                         wpa_printf(MSG_ERROR,
4135                                    "Line %d: Invalid sae_groups value '%s'",
4136                                    line, pos);
4137                         return 1;
4138                 }
4139         } else if (os_strcmp(buf, "sae_require_mfp") == 0) {
4140                 bss->sae_require_mfp = atoi(pos);
4141         } else if (os_strcmp(buf, "local_pwr_constraint") == 0) {
4142                 int val = atoi(pos);
4143                 if (val < 0 || val > 255) {
4144                         wpa_printf(MSG_ERROR, "Line %d: Invalid local_pwr_constraint %d (expected 0..255)",
4145                                    line, val);
4146                         return 1;
4147                 }
4148                 conf->local_pwr_constraint = val;
4149         } else if (os_strcmp(buf, "spectrum_mgmt_required") == 0) {
4150                 conf->spectrum_mgmt_required = atoi(pos);
4151         } else if (os_strcmp(buf, "wowlan_triggers") == 0) {
4152                 os_free(bss->wowlan_triggers);
4153                 bss->wowlan_triggers = os_strdup(pos);
4154 #ifdef CONFIG_FST
4155         } else if (os_strcmp(buf, "fst_group_id") == 0) {
4156                 size_t len = os_strlen(pos);
4157
4158                 if (!len || len >= sizeof(conf->fst_cfg.group_id)) {
4159                         wpa_printf(MSG_ERROR,
4160                                    "Line %d: Invalid fst_group_id value '%s'",
4161                                    line, pos);
4162                         return 1;
4163                 }
4164
4165                 if (conf->fst_cfg.group_id[0]) {
4166                         wpa_printf(MSG_ERROR,
4167                                    "Line %d: Duplicate fst_group value '%s'",
4168                                    line, pos);
4169                         return 1;
4170                 }
4171
4172                 os_strlcpy(conf->fst_cfg.group_id, pos,
4173                            sizeof(conf->fst_cfg.group_id));
4174         } else if (os_strcmp(buf, "fst_priority") == 0) {
4175                 char *endp;
4176                 long int val;
4177
4178                 if (!*pos) {
4179                         wpa_printf(MSG_ERROR,
4180                                    "Line %d: fst_priority value not supplied (expected 1..%u)",
4181                                    line, FST_MAX_PRIO_VALUE);
4182                         return -1;
4183                 }
4184
4185                 val = strtol(pos, &endp, 0);
4186                 if (*endp || val < 1 || val > FST_MAX_PRIO_VALUE) {
4187                         wpa_printf(MSG_ERROR,
4188                                    "Line %d: Invalid fst_priority %ld (%s) (expected 1..%u)",
4189                                    line, val, pos, FST_MAX_PRIO_VALUE);
4190                         return 1;
4191                 }
4192                 conf->fst_cfg.priority = (u8) val;
4193         } else if (os_strcmp(buf, "fst_llt") == 0) {
4194                 char *endp;
4195                 long int val;
4196
4197                 if (!*pos) {
4198                         wpa_printf(MSG_ERROR,
4199                                    "Line %d: fst_llt value not supplied (expected 1..%u)",
4200                                    line, FST_MAX_LLT_MS);
4201                         return -1;
4202                 }
4203                 val = strtol(pos, &endp, 0);
4204                 if (*endp || val < 1 ||
4205                     (unsigned long int) val > FST_MAX_LLT_MS) {
4206                         wpa_printf(MSG_ERROR,
4207                                    "Line %d: Invalid fst_llt %ld (%s) (expected 1..%u)",
4208                                    line, val, pos, FST_MAX_LLT_MS);
4209                         return 1;
4210                 }
4211                 conf->fst_cfg.llt = (u32) val;
4212 #endif /* CONFIG_FST */
4213         } else if (os_strcmp(buf, "track_sta_max_num") == 0) {
4214                 conf->track_sta_max_num = atoi(pos);
4215         } else if (os_strcmp(buf, "track_sta_max_age") == 0) {
4216                 conf->track_sta_max_age = atoi(pos);
4217         } else if (os_strcmp(buf, "no_probe_resp_if_seen_on") == 0) {
4218                 os_free(bss->no_probe_resp_if_seen_on);
4219                 bss->no_probe_resp_if_seen_on = os_strdup(pos);
4220         } else if (os_strcmp(buf, "no_auth_if_seen_on") == 0) {
4221                 os_free(bss->no_auth_if_seen_on);
4222                 bss->no_auth_if_seen_on = os_strdup(pos);
4223         } else if (os_strcmp(buf, "lci") == 0) {
4224                 wpabuf_free(conf->lci);
4225                 conf->lci = wpabuf_parse_bin(pos);
4226                 if (conf->lci && wpabuf_len(conf->lci) == 0) {
4227                         wpabuf_free(conf->lci);
4228                         conf->lci = NULL;
4229                 }
4230         } else if (os_strcmp(buf, "civic") == 0) {
4231                 wpabuf_free(conf->civic);
4232                 conf->civic = wpabuf_parse_bin(pos);
4233                 if (conf->civic && wpabuf_len(conf->civic) == 0) {
4234                         wpabuf_free(conf->civic);
4235                         conf->civic = NULL;
4236                 }
4237         } else if (os_strcmp(buf, "rrm_neighbor_report") == 0) {
4238                 if (atoi(pos))
4239                         bss->radio_measurements[0] |=
4240                                 WLAN_RRM_CAPS_NEIGHBOR_REPORT;
4241         } else if (os_strcmp(buf, "rrm_beacon_report") == 0) {
4242                 if (atoi(pos))
4243                         bss->radio_measurements[0] |=
4244                                 WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE |
4245                                 WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE |
4246                                 WLAN_RRM_CAPS_BEACON_REPORT_TABLE;
4247         } else if (os_strcmp(buf, "gas_address3") == 0) {
4248                 bss->gas_address3 = atoi(pos);
4249         } else if (os_strcmp(buf, "stationary_ap") == 0) {
4250                 conf->stationary_ap = atoi(pos);
4251         } else if (os_strcmp(buf, "ftm_responder") == 0) {
4252                 bss->ftm_responder = atoi(pos);
4253         } else if (os_strcmp(buf, "ftm_initiator") == 0) {
4254                 bss->ftm_initiator = atoi(pos);
4255 #ifdef CONFIG_FILS
4256         } else if (os_strcmp(buf, "fils_cache_id") == 0) {
4257                 if (hexstr2bin(pos, bss->fils_cache_id, FILS_CACHE_ID_LEN)) {
4258                         wpa_printf(MSG_ERROR,
4259                                    "Line %d: Invalid fils_cache_id '%s'",
4260                                    line, pos);
4261                         return 1;
4262                 }
4263                 bss->fils_cache_id_set = 1;
4264         } else if (os_strcmp(buf, "fils_realm") == 0) {
4265                 if (parse_fils_realm(bss, pos) < 0)
4266                         return 1;
4267         } else if (os_strcmp(buf, "fils_dh_group") == 0) {
4268                 bss->fils_dh_group = atoi(pos);
4269         } else if (os_strcmp(buf, "dhcp_server") == 0) {
4270                 if (hostapd_parse_ip_addr(pos, &bss->dhcp_server)) {
4271                         wpa_printf(MSG_ERROR,
4272                                    "Line %d: invalid IP address '%s'",
4273                                    line, pos);
4274                         return 1;
4275                 }
4276         } else if (os_strcmp(buf, "dhcp_rapid_commit_proxy") == 0) {
4277                 bss->dhcp_rapid_commit_proxy = atoi(pos);
4278         } else if (os_strcmp(buf, "fils_hlp_wait_time") == 0) {
4279                 bss->fils_hlp_wait_time = atoi(pos);
4280         } else if (os_strcmp(buf, "dhcp_server_port") == 0) {
4281                 bss->dhcp_server_port = atoi(pos);
4282         } else if (os_strcmp(buf, "dhcp_relay_port") == 0) {
4283                 bss->dhcp_relay_port = atoi(pos);
4284 #endif /* CONFIG_FILS */
4285         } else if (os_strcmp(buf, "multicast_to_unicast") == 0) {
4286                 bss->multicast_to_unicast = atoi(pos);
4287         } else if (os_strcmp(buf, "broadcast_deauth") == 0) {
4288                 bss->broadcast_deauth = atoi(pos);
4289 #ifdef CONFIG_DPP
4290         } else if (os_strcmp(buf, "dpp_connector") == 0) {
4291                 os_free(bss->dpp_connector);
4292                 bss->dpp_connector = os_strdup(pos);
4293         } else if (os_strcmp(buf, "dpp_netaccesskey") == 0) {
4294                 if (parse_wpabuf_hex(line, buf, &bss->dpp_netaccesskey, pos))
4295                         return 1;
4296         } else if (os_strcmp(buf, "dpp_netaccesskey_expiry") == 0) {
4297                 bss->dpp_netaccesskey_expiry = strtol(pos, NULL, 0);
4298         } else if (os_strcmp(buf, "dpp_csign") == 0) {
4299                 if (parse_wpabuf_hex(line, buf, &bss->dpp_csign, pos))
4300                         return 1;
4301 #endif /* CONFIG_DPP */
4302 #ifdef CONFIG_OWE
4303         } else if (os_strcmp(buf, "owe_transition_bssid") == 0) {
4304                 if (hwaddr_aton(pos, bss->owe_transition_bssid)) {
4305                         wpa_printf(MSG_ERROR,
4306                                    "Line %d: invalid owe_transition_bssid",
4307                                    line);
4308                         return 1;
4309                 }
4310         } else if (os_strcmp(buf, "owe_transition_ssid") == 0) {
4311                 size_t slen;
4312                 char *str = wpa_config_parse_string(pos, &slen);
4313
4314                 if (!str || slen < 1 || slen > SSID_MAX_LEN) {
4315                         wpa_printf(MSG_ERROR, "Line %d: invalid SSID '%s'",
4316                                    line, pos);
4317                         os_free(str);
4318                         return 1;
4319                 }
4320                 os_memcpy(bss->owe_transition_ssid, str, slen);
4321                 bss->owe_transition_ssid_len = slen;
4322                 os_free(str);
4323         } else if (os_strcmp(buf, "owe_transition_ifname") == 0) {
4324                 os_strlcpy(bss->owe_transition_ifname, pos,
4325                            sizeof(bss->owe_transition_ifname));
4326         } else if (os_strcmp(buf, "owe_groups") == 0) {
4327                 if (hostapd_parse_intlist(&bss->owe_groups, pos)) {
4328                         wpa_printf(MSG_ERROR,
4329                                    "Line %d: Invalid owe_groups value '%s'",
4330                                    line, pos);
4331                         return 1;
4332                 }
4333         } else if (os_strcmp(buf, "coloc_intf_reporting") == 0) {
4334                 bss->coloc_intf_reporting = atoi(pos);
4335 #endif /* CONFIG_OWE */
4336         } else if (os_strcmp(buf, "multi_ap") == 0) {
4337                 int val = atoi(pos);
4338
4339                 if (val < 0 || val > 3) {
4340                         wpa_printf(MSG_ERROR, "Line %d: Invalid multi_ap '%s'",
4341                                    line, buf);
4342                         return -1;
4343                 }
4344
4345                 bss->multi_ap = val;
4346         } else if (os_strcmp(buf, "rssi_reject_assoc_rssi") == 0) {
4347                 conf->rssi_reject_assoc_rssi = atoi(pos);
4348         } else if (os_strcmp(buf, "rssi_reject_assoc_timeout") == 0) {
4349                 conf->rssi_reject_assoc_timeout = atoi(pos);
4350         } else if (os_strcmp(buf, "pbss") == 0) {
4351                 bss->pbss = atoi(pos);
4352         } else {
4353                 wpa_printf(MSG_ERROR,
4354                            "Line %d: unknown configuration item '%s'",
4355                            line, buf);
4356                 return 1;
4357         }
4358
4359         return 0;
4360 }
4361
4362
4363 /**
4364  * hostapd_config_read - Read and parse a configuration file
4365  * @fname: Configuration file name (including path, if needed)
4366  * Returns: Allocated configuration data structure
4367  */
4368 struct hostapd_config * hostapd_config_read(const char *fname)
4369 {
4370         struct hostapd_config *conf;
4371         FILE *f;
4372         char buf[4096], *pos;
4373         int line = 0;
4374         int errors = 0;
4375         size_t i;
4376
4377         f = fopen(fname, "r");
4378         if (f == NULL) {
4379                 wpa_printf(MSG_ERROR, "Could not open configuration file '%s' "
4380                            "for reading.", fname);
4381                 return NULL;
4382         }
4383
4384         conf = hostapd_config_defaults();
4385         if (conf == NULL) {
4386                 fclose(f);
4387                 return NULL;
4388         }
4389
4390         /* set default driver based on configuration */
4391         conf->driver = wpa_drivers[0];
4392         if (conf->driver == NULL) {
4393                 wpa_printf(MSG_ERROR, "No driver wrappers registered!");
4394                 hostapd_config_free(conf);
4395                 fclose(f);
4396                 return NULL;
4397         }
4398
4399         conf->last_bss = conf->bss[0];
4400
4401         while (fgets(buf, sizeof(buf), f)) {
4402                 struct hostapd_bss_config *bss;
4403
4404                 bss = conf->last_bss;
4405                 line++;
4406
4407                 if (buf[0] == '#')
4408                         continue;
4409                 pos = buf;
4410                 while (*pos != '\0') {
4411                         if (*pos == '\n') {
4412                                 *pos = '\0';
4413                                 break;
4414                         }
4415                         pos++;
4416                 }
4417                 if (buf[0] == '\0')
4418                         continue;
4419
4420                 pos = os_strchr(buf, '=');
4421                 if (pos == NULL) {
4422                         wpa_printf(MSG_ERROR, "Line %d: invalid line '%s'",
4423                                    line, buf);
4424                         errors++;
4425                         continue;
4426                 }
4427                 *pos = '\0';
4428                 pos++;
4429                 errors += hostapd_config_fill(conf, bss, buf, pos, line);
4430         }
4431
4432         fclose(f);
4433
4434         for (i = 0; i < conf->num_bss; i++)
4435                 hostapd_set_security_params(conf->bss[i], 1);
4436
4437         if (hostapd_config_check(conf, 1))
4438                 errors++;
4439
4440 #ifndef WPA_IGNORE_CONFIG_ERRORS
4441         if (errors) {
4442                 wpa_printf(MSG_ERROR, "%d errors found in configuration file "
4443                            "'%s'", errors, fname);
4444                 hostapd_config_free(conf);
4445                 conf = NULL;
4446         }
4447 #endif /* WPA_IGNORE_CONFIG_ERRORS */
4448
4449         return conf;
4450 }
4451
4452
4453 int hostapd_set_iface(struct hostapd_config *conf,
4454                       struct hostapd_bss_config *bss, const char *field,
4455                       char *value)
4456 {
4457         int errors;
4458         size_t i;
4459
4460         errors = hostapd_config_fill(conf, bss, field, value, 0);
4461         if (errors) {
4462                 wpa_printf(MSG_INFO, "Failed to set configuration field '%s' "
4463                            "to value '%s'", field, value);
4464                 return -1;
4465         }
4466
4467         for (i = 0; i < conf->num_bss; i++)
4468                 hostapd_set_security_params(conf->bss[i], 0);
4469
4470         if (hostapd_config_check(conf, 0)) {
4471                 wpa_printf(MSG_ERROR, "Configuration check failed");
4472                 return -1;
4473         }
4474
4475         return 0;
4476 }