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