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