blob: 325ab8db880f7b142548e3767a1bf60f90199cec [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001/*
2 * WPA Supplicant / Configuration parser and common functions
3 * Copyright (c) 2003-2019, 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 "includes.h"
10
11#include "common.h"
12#include "utils/uuid.h"
13#include "utils/ip_addr.h"
14#include "common/ieee802_1x_defs.h"
15#include "common/sae.h"
16#include "crypto/sha1.h"
17#include "rsn_supp/wpa.h"
18#include "eap_peer/eap.h"
19#include "p2p/p2p.h"
20#include "fst/fst.h"
21#include "ap/sta_info.h"
22#include "config.h"
23
24
25#if !defined(CONFIG_CTRL_IFACE) && defined(CONFIG_NO_CONFIG_WRITE)
26#define NO_CONFIG_WRITE
27#endif
28
29/*
30 * Structure for network configuration parsing. This data is used to implement
31 * a generic parser for each network block variable. The table of configuration
32 * variables is defined below in this file (ssid_fields[]).
33 */
34struct parse_data {
35 /* Configuration variable name */
36 char *name;
37
38 /* Parser function for this variable. The parser functions return 0 or 1
39 * to indicate success. Value 0 indicates that the parameter value may
40 * have changed while value 1 means that the value did not change.
41 * Error cases (failure to parse the string) are indicated by returning
42 * -1. */
43 int (*parser)(const struct parse_data *data, struct wpa_ssid *ssid,
44 int line, const char *value);
45
46#ifndef NO_CONFIG_WRITE
47 /* Writer function (i.e., to get the variable in text format from
48 * internal presentation). */
49 char * (*writer)(const struct parse_data *data, struct wpa_ssid *ssid);
50#endif /* NO_CONFIG_WRITE */
51
52 /* Variable specific parameters for the parser. */
53 void *param1, *param2, *param3, *param4;
54
55 /* 0 = this variable can be included in debug output and ctrl_iface
56 * 1 = this variable contains key/private data and it must not be
57 * included in debug output unless explicitly requested. In
58 * addition, this variable will not be readable through the
59 * ctrl_iface.
60 */
61 int key_data;
62};
63
64
65static int wpa_config_parse_str(const struct parse_data *data,
66 struct wpa_ssid *ssid,
67 int line, const char *value)
68{
69 size_t res_len, *dst_len, prev_len;
70 char **dst, *tmp;
71
72 if (os_strcmp(value, "NULL") == 0) {
73 wpa_printf(MSG_DEBUG, "Unset configuration string '%s'",
74 data->name);
75 tmp = NULL;
76 res_len = 0;
77 goto set;
78 }
79
80 tmp = wpa_config_parse_string(value, &res_len);
81 if (tmp == NULL) {
82 wpa_printf(MSG_ERROR, "Line %d: failed to parse %s '%s'.",
83 line, data->name,
84 data->key_data ? "[KEY DATA REMOVED]" : value);
85 return -1;
86 }
87
88 if (data->key_data) {
89 wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
90 (u8 *) tmp, res_len);
91 } else {
92 wpa_hexdump_ascii(MSG_MSGDUMP, data->name,
93 (u8 *) tmp, res_len);
94 }
95
96 if (data->param3 && res_len < (size_t) data->param3) {
97 wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu "
98 "min_len=%ld)", line, data->name,
99 (unsigned long) res_len, (long) data->param3);
100 os_free(tmp);
101 return -1;
102 }
103
104 if (data->param4 && res_len > (size_t) data->param4) {
105 wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu "
106 "max_len=%ld)", line, data->name,
107 (unsigned long) res_len, (long) data->param4);
108 os_free(tmp);
109 return -1;
110 }
111
112set:
113 dst = (char **) (((u8 *) ssid) + (long) data->param1);
114 dst_len = (size_t *) (((u8 *) ssid) + (long) data->param2);
115
116 if (data->param2)
117 prev_len = *dst_len;
118 else if (*dst)
119 prev_len = os_strlen(*dst);
120 else
121 prev_len = 0;
122 if ((*dst == NULL && tmp == NULL) ||
123 (*dst && tmp && prev_len == res_len &&
124 os_memcmp(*dst, tmp, res_len) == 0)) {
125 /* No change to the previously configured value */
126 os_free(tmp);
127 return 1;
128 }
129
130 os_free(*dst);
131 *dst = tmp;
132 if (data->param2)
133 *dst_len = res_len;
134
135 return 0;
136}
137
138
139#ifndef NO_CONFIG_WRITE
140static char * wpa_config_write_string_ascii(const u8 *value, size_t len)
141{
142 char *buf;
143
144 buf = os_malloc(len + 3);
145 if (buf == NULL)
146 return NULL;
147 buf[0] = '"';
148 os_memcpy(buf + 1, value, len);
149 buf[len + 1] = '"';
150 buf[len + 2] = '\0';
151
152 return buf;
153}
154
155
156static char * wpa_config_write_string_hex(const u8 *value, size_t len)
157{
158 char *buf;
159
160 buf = os_zalloc(2 * len + 1);
161 if (buf == NULL)
162 return NULL;
163 wpa_snprintf_hex(buf, 2 * len + 1, value, len);
164
165 return buf;
166}
167
168
169static char * wpa_config_write_string(const u8 *value, size_t len)
170{
171 if (value == NULL)
172 return NULL;
173
174 if (is_hex(value, len))
175 return wpa_config_write_string_hex(value, len);
176 else
177 return wpa_config_write_string_ascii(value, len);
178}
179
180
181static char * wpa_config_write_str(const struct parse_data *data,
182 struct wpa_ssid *ssid)
183{
184 size_t len;
185 char **src;
186
187 src = (char **) (((u8 *) ssid) + (long) data->param1);
188 if (*src == NULL)
189 return NULL;
190
191 if (data->param2)
192 len = *((size_t *) (((u8 *) ssid) + (long) data->param2));
193 else
194 len = os_strlen(*src);
195
196 return wpa_config_write_string((const u8 *) *src, len);
197}
198#endif /* NO_CONFIG_WRITE */
199
200
201static int wpa_config_parse_int(const struct parse_data *data,
202 struct wpa_ssid *ssid,
203 int line, const char *value)
204{
205 int val, *dst;
206 char *end;
207
208 dst = (int *) (((u8 *) ssid) + (long) data->param1);
209 val = strtol(value, &end, 0);
210 if (*end) {
211 wpa_printf(MSG_ERROR, "Line %d: invalid number \"%s\"",
212 line, value);
213 return -1;
214 }
215
216 if (*dst == val)
217 return 1;
218 *dst = val;
219 wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst);
220
221 if (data->param3 && *dst < (long) data->param3) {
222 wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d "
223 "min_value=%ld)", line, data->name, *dst,
224 (long) data->param3);
225 *dst = (long) data->param3;
226 return -1;
227 }
228
229 if (data->param4 && *dst > (long) data->param4) {
230 wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d "
231 "max_value=%ld)", line, data->name, *dst,
232 (long) data->param4);
233 *dst = (long) data->param4;
234 return -1;
235 }
236
237 return 0;
238}
239
240
241#ifndef NO_CONFIG_WRITE
242static char * wpa_config_write_int(const struct parse_data *data,
243 struct wpa_ssid *ssid)
244{
245 int *src, res;
246 char *value;
247
248 src = (int *) (((u8 *) ssid) + (long) data->param1);
249
250 value = os_malloc(20);
251 if (value == NULL)
252 return NULL;
253 res = os_snprintf(value, 20, "%d", *src);
254 if (os_snprintf_error(20, res)) {
255 os_free(value);
256 return NULL;
257 }
258 value[20 - 1] = '\0';
259 return value;
260}
261#endif /* NO_CONFIG_WRITE */
262
263
264static int wpa_config_parse_addr_list(const struct parse_data *data,
265 int line, const char *value,
266 u8 **list, size_t *num, char *name,
267 u8 abort_on_error, u8 masked)
268{
269 const char *pos;
270 u8 *buf, *n, addr[2 * ETH_ALEN];
271 size_t count;
272
273 buf = NULL;
274 count = 0;
275
276 pos = value;
277 while (pos && *pos) {
278 while (*pos == ' ')
279 pos++;
280
281 if (hwaddr_masked_aton(pos, addr, &addr[ETH_ALEN], masked)) {
282 if (abort_on_error || count == 0) {
283 wpa_printf(MSG_ERROR,
284 "Line %d: Invalid %s address '%s'",
285 line, name, value);
286 os_free(buf);
287 return -1;
288 }
289 /* continue anyway since this could have been from a
290 * truncated configuration file line */
291 wpa_printf(MSG_INFO,
292 "Line %d: Ignore likely truncated %s address '%s'",
293 line, name, pos);
294 } else {
295 n = os_realloc_array(buf, count + 1, 2 * ETH_ALEN);
296 if (n == NULL) {
297 os_free(buf);
298 return -1;
299 }
300 buf = n;
301 os_memmove(buf + 2 * ETH_ALEN, buf,
302 count * 2 * ETH_ALEN);
303 os_memcpy(buf, addr, 2 * ETH_ALEN);
304 count++;
305 wpa_printf(MSG_MSGDUMP,
306 "%s: addr=" MACSTR " mask=" MACSTR,
307 name, MAC2STR(addr),
308 MAC2STR(&addr[ETH_ALEN]));
309 }
310
311 pos = os_strchr(pos, ' ');
312 }
313
314 os_free(*list);
315 *list = buf;
316 *num = count;
317
318 return 0;
319}
320
321
322#ifndef NO_CONFIG_WRITE
323static char * wpa_config_write_addr_list(const struct parse_data *data,
324 const u8 *list, size_t num, char *name)
325{
326 char *value, *end, *pos;
327 int res;
328 size_t i;
329
330 if (list == NULL || num == 0)
331 return NULL;
332
333 value = os_malloc(2 * 20 * num);
334 if (value == NULL)
335 return NULL;
336 pos = value;
337 end = value + 2 * 20 * num;
338
339 for (i = num; i > 0; i--) {
340 const u8 *a = list + (i - 1) * 2 * ETH_ALEN;
341 const u8 *m = a + ETH_ALEN;
342
343 if (i < num)
344 *pos++ = ' ';
345 res = hwaddr_mask_txt(pos, end - pos, a, m);
346 if (res < 0) {
347 os_free(value);
348 return NULL;
349 }
350 pos += res;
351 }
352
353 return value;
354}
355#endif /* NO_CONFIG_WRITE */
356
357static int wpa_config_parse_bssid(const struct parse_data *data,
358 struct wpa_ssid *ssid, int line,
359 const char *value)
360{
361 if (value[0] == '\0' || os_strcmp(value, "\"\"") == 0 ||
362 os_strcmp(value, "any") == 0) {
363 ssid->bssid_set = 0;
364 wpa_printf(MSG_MSGDUMP, "BSSID any");
365 return 0;
366 }
367 if (hwaddr_aton(value, ssid->bssid)) {
368 wpa_printf(MSG_ERROR, "Line %d: Invalid BSSID '%s'.",
369 line, value);
370 return -1;
371 }
372 ssid->bssid_set = 1;
373 wpa_hexdump(MSG_MSGDUMP, "BSSID", ssid->bssid, ETH_ALEN);
374 return 0;
375}
376
377
378#ifndef NO_CONFIG_WRITE
379static char * wpa_config_write_bssid(const struct parse_data *data,
380 struct wpa_ssid *ssid)
381{
382 char *value;
383 int res;
384
385 if (!ssid->bssid_set)
386 return NULL;
387
388 value = os_malloc(20);
389 if (value == NULL)
390 return NULL;
391 res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->bssid));
392 if (os_snprintf_error(20, res)) {
393 os_free(value);
394 return NULL;
395 }
396 value[20 - 1] = '\0';
397 return value;
398}
399#endif /* NO_CONFIG_WRITE */
400
401
402static int wpa_config_parse_bssid_hint(const struct parse_data *data,
403 struct wpa_ssid *ssid, int line,
404 const char *value)
405{
406 if (value[0] == '\0' || os_strcmp(value, "\"\"") == 0 ||
407 os_strcmp(value, "any") == 0) {
408 ssid->bssid_hint_set = 0;
409 wpa_printf(MSG_MSGDUMP, "BSSID hint any");
410 return 0;
411 }
412 if (hwaddr_aton(value, ssid->bssid_hint)) {
413 wpa_printf(MSG_ERROR, "Line %d: Invalid BSSID hint '%s'.",
414 line, value);
415 return -1;
416 }
417 ssid->bssid_hint_set = 1;
418 wpa_hexdump(MSG_MSGDUMP, "BSSID hint", ssid->bssid_hint, ETH_ALEN);
419 return 0;
420}
421
422
423#ifndef NO_CONFIG_WRITE
424static char * wpa_config_write_bssid_hint(const struct parse_data *data,
425 struct wpa_ssid *ssid)
426{
427 char *value;
428 int res;
429
430 if (!ssid->bssid_hint_set)
431 return NULL;
432
433 value = os_malloc(20);
434 if (!value)
435 return NULL;
436 res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->bssid_hint));
437 if (os_snprintf_error(20, res)) {
438 os_free(value);
439 return NULL;
440 }
441 return value;
442}
443#endif /* NO_CONFIG_WRITE */
444
445
446static int wpa_config_parse_bssid_ignore(const struct parse_data *data,
447 struct wpa_ssid *ssid, int line,
448 const char *value)
449{
450 return wpa_config_parse_addr_list(data, line, value,
451 &ssid->bssid_ignore,
452 &ssid->num_bssid_ignore,
453 "bssid_ignore", 1, 1);
454}
455
456
457/* deprecated alias for bssid_ignore for backwards compatibility */
458static int wpa_config_parse_bssid_blacklist(const struct parse_data *data,
459 struct wpa_ssid *ssid, int line,
460 const char *value)
461{
462 return wpa_config_parse_addr_list(data, line, value,
463 &ssid->bssid_ignore,
464 &ssid->num_bssid_ignore,
465 "bssid_ignore", 1, 1);
466}
467
468
469#ifndef NO_CONFIG_WRITE
470
471static char * wpa_config_write_bssid_ignore(const struct parse_data *data,
472 struct wpa_ssid *ssid)
473{
474 return wpa_config_write_addr_list(data, ssid->bssid_ignore,
475 ssid->num_bssid_ignore,
476 "bssid_ignore");
477}
478
479
480/* deprecated alias for bssid_ignore for backwards compatibility */
481static char * wpa_config_write_bssid_blacklist(const struct parse_data *data,
482 struct wpa_ssid *ssid)
483{
484 return wpa_config_write_addr_list(data, ssid->bssid_ignore,
485 ssid->num_bssid_ignore,
486 "bssid_ignore");
487}
488
489#endif /* NO_CONFIG_WRITE */
490
491
492static int wpa_config_parse_bssid_accept(const struct parse_data *data,
493 struct wpa_ssid *ssid, int line,
494 const char *value)
495{
496 return wpa_config_parse_addr_list(data, line, value,
497 &ssid->bssid_accept,
498 &ssid->num_bssid_accept,
499 "bssid_accept", 1, 1);
500}
501
502
503/* deprecated alias for bssid_accept for backwards compatibility */
504static int wpa_config_parse_bssid_whitelist(const struct parse_data *data,
505 struct wpa_ssid *ssid, int line,
506 const char *value)
507{
508 return wpa_config_parse_addr_list(data, line, value,
509 &ssid->bssid_accept,
510 &ssid->num_bssid_accept,
511 "bssid_accept", 1, 1);
512}
513
514
515#ifndef NO_CONFIG_WRITE
516
517static char * wpa_config_write_bssid_accept(const struct parse_data *data,
518 struct wpa_ssid *ssid)
519{
520 return wpa_config_write_addr_list(data, ssid->bssid_accept,
521 ssid->num_bssid_accept,
522 "bssid_accept");
523}
524
525
526/* deprecated alias for bssid_accept for backwards compatibility */
527static char * wpa_config_write_bssid_whitelist(const struct parse_data *data,
528 struct wpa_ssid *ssid)
529{
530 return wpa_config_write_addr_list(data, ssid->bssid_accept,
531 ssid->num_bssid_accept,
532 "bssid_accept");
533}
534
535#endif /* NO_CONFIG_WRITE */
536
537
538#ifndef NO_CONFIG_WRITE
539#endif /* NO_CONFIG_WRITE */
540
541
542static int wpa_config_parse_psk(const struct parse_data *data,
543 struct wpa_ssid *ssid, int line,
544 const char *value)
545{
546#ifdef CONFIG_EXT_PASSWORD
547 if (os_strncmp(value, "ext:", 4) == 0) {
548 str_clear_free(ssid->passphrase);
549 ssid->passphrase = NULL;
550 ssid->psk_set = 0;
551 os_free(ssid->ext_psk);
552 ssid->ext_psk = os_strdup(value + 4);
553 if (ssid->ext_psk == NULL)
554 return -1;
555 wpa_printf(MSG_DEBUG, "PSK: External password '%s'",
556 ssid->ext_psk);
557 return 0;
558 }
559#endif /* CONFIG_EXT_PASSWORD */
560
561 if (*value == '"') {
562#ifndef CONFIG_NO_PBKDF2
563 const char *pos;
564 size_t len;
565
566 value++;
567 pos = os_strrchr(value, '"');
568 if (pos)
569 len = pos - value;
570 else
571 len = os_strlen(value);
572 if (len < 8 || len > 63) {
573 wpa_printf(MSG_ERROR, "Line %d: Invalid passphrase "
574 "length %lu (expected: 8..63) '%s'.",
575 line, (unsigned long) len, value);
576 return -1;
577 }
578 wpa_hexdump_ascii_key(MSG_MSGDUMP, "PSK (ASCII passphrase)",
579 (u8 *) value, len);
580 if (has_ctrl_char((u8 *) value, len)) {
581 wpa_printf(MSG_ERROR,
582 "Line %d: Invalid passphrase character",
583 line);
584 return -1;
585 }
586 if (ssid->passphrase && os_strlen(ssid->passphrase) == len &&
587 os_memcmp(ssid->passphrase, value, len) == 0) {
588 /* No change to the previously configured value */
589 return 1;
590 }
591 ssid->psk_set = 0;
592 str_clear_free(ssid->passphrase);
593 ssid->passphrase = dup_binstr(value, len);
594 if (ssid->passphrase == NULL)
595 return -1;
596 return 0;
597#else /* CONFIG_NO_PBKDF2 */
598 wpa_printf(MSG_ERROR, "Line %d: ASCII passphrase not "
599 "supported.", line);
600 return -1;
601#endif /* CONFIG_NO_PBKDF2 */
602 }
603
604 if (hexstr2bin(value, ssid->psk, PMK_LEN) ||
605 value[PMK_LEN * 2] != '\0') {
606 wpa_printf(MSG_ERROR, "Line %d: Invalid PSK '%s'.",
607 line, value);
608 return -1;
609 }
610
611 str_clear_free(ssid->passphrase);
612 ssid->passphrase = NULL;
613
614 ssid->psk_set = 1;
615 wpa_hexdump_key(MSG_MSGDUMP, "PSK", ssid->psk, PMK_LEN);
616 return 0;
617}
618
619
620#ifndef NO_CONFIG_WRITE
621static char * wpa_config_write_psk(const struct parse_data *data,
622 struct wpa_ssid *ssid)
623{
624#ifdef CONFIG_EXT_PASSWORD
625 if (ssid->ext_psk) {
626 size_t len = 4 + os_strlen(ssid->ext_psk) + 1;
627 char *buf = os_malloc(len);
628 int res;
629
630 if (buf == NULL)
631 return NULL;
632 res = os_snprintf(buf, len, "ext:%s", ssid->ext_psk);
633 if (os_snprintf_error(len, res)) {
634 os_free(buf);
635 buf = NULL;
636 }
637 return buf;
638 }
639#endif /* CONFIG_EXT_PASSWORD */
640
641 if (ssid->passphrase)
642 return wpa_config_write_string_ascii(
643 (const u8 *) ssid->passphrase,
644 os_strlen(ssid->passphrase));
645
646 if (ssid->psk_set)
647 return wpa_config_write_string_hex(ssid->psk, PMK_LEN);
648
649 return NULL;
650}
651#endif /* NO_CONFIG_WRITE */
652
653
654static int wpa_config_parse_proto(const struct parse_data *data,
655 struct wpa_ssid *ssid, int line,
656 const char *value)
657{
658 int val = 0, last, errors = 0;
659 char *start, *end, *buf;
660
661 buf = os_strdup(value);
662 if (buf == NULL)
663 return -1;
664 start = buf;
665
666 while (*start != '\0') {
667 while (*start == ' ' || *start == '\t')
668 start++;
669 if (*start == '\0')
670 break;
671 end = start;
672 while (*end != ' ' && *end != '\t' && *end != '\0')
673 end++;
674 last = *end == '\0';
675 *end = '\0';
676 if (os_strcmp(start, "WPA") == 0)
677 val |= WPA_PROTO_WPA;
678 else if (os_strcmp(start, "RSN") == 0 ||
679 os_strcmp(start, "WPA2") == 0)
680 val |= WPA_PROTO_RSN;
681 else if (os_strcmp(start, "OSEN") == 0)
682 val |= WPA_PROTO_OSEN;
683 else {
684 wpa_printf(MSG_ERROR, "Line %d: invalid proto '%s'",
685 line, start);
686 errors++;
687 }
688
689 if (last)
690 break;
691 start = end + 1;
692 }
693 os_free(buf);
694
695 if (val == 0) {
696 wpa_printf(MSG_ERROR,
697 "Line %d: no proto values configured.", line);
698 errors++;
699 }
700
701 if (!errors && ssid->proto == val)
702 return 1;
703 wpa_printf(MSG_MSGDUMP, "proto: 0x%x", val);
704 ssid->proto = val;
705 return errors ? -1 : 0;
706}
707
708
709#ifndef NO_CONFIG_WRITE
710static char * wpa_config_write_proto(const struct parse_data *data,
711 struct wpa_ssid *ssid)
712{
713 int ret;
714 char *buf, *pos, *end;
715
716 pos = buf = os_zalloc(20);
717 if (buf == NULL)
718 return NULL;
719 end = buf + 20;
720
721 if (ssid->proto & WPA_PROTO_WPA) {
722 ret = os_snprintf(pos, end - pos, "%sWPA",
723 pos == buf ? "" : " ");
724 if (os_snprintf_error(end - pos, ret))
725 return buf;
726 pos += ret;
727 }
728
729 if (ssid->proto & WPA_PROTO_RSN) {
730 ret = os_snprintf(pos, end - pos, "%sRSN",
731 pos == buf ? "" : " ");
732 if (os_snprintf_error(end - pos, ret))
733 return buf;
734 pos += ret;
735 }
736
737 if (ssid->proto & WPA_PROTO_OSEN) {
738 ret = os_snprintf(pos, end - pos, "%sOSEN",
739 pos == buf ? "" : " ");
740 if (os_snprintf_error(end - pos, ret))
741 return buf;
742 pos += ret;
743 }
744
745 if (pos == buf) {
746 os_free(buf);
747 buf = NULL;
748 }
749
750 return buf;
751}
752#endif /* NO_CONFIG_WRITE */
753
754
755static int wpa_config_parse_key_mgmt(const struct parse_data *data,
756 struct wpa_ssid *ssid, int line,
757 const char *value)
758{
759 int val = 0, last, errors = 0;
760 char *start, *end, *buf;
761
762 buf = os_strdup(value);
763 if (buf == NULL)
764 return -1;
765 start = buf;
766
767 while (*start != '\0') {
768 while (*start == ' ' || *start == '\t')
769 start++;
770 if (*start == '\0')
771 break;
772 end = start;
773 while (*end != ' ' && *end != '\t' && *end != '\0')
774 end++;
775 last = *end == '\0';
776 *end = '\0';
777 if (os_strcmp(start, "WPA-PSK") == 0)
778 val |= WPA_KEY_MGMT_PSK;
779 else if (os_strcmp(start, "WPA-EAP") == 0)
780 val |= WPA_KEY_MGMT_IEEE8021X;
781 else if (os_strcmp(start, "IEEE8021X") == 0)
782 val |= WPA_KEY_MGMT_IEEE8021X_NO_WPA;
783 else if (os_strcmp(start, "NONE") == 0)
784 val |= WPA_KEY_MGMT_NONE;
785 else if (os_strcmp(start, "WPA-NONE") == 0)
786 val |= WPA_KEY_MGMT_WPA_NONE;
787#ifdef CONFIG_IEEE80211R
788 else if (os_strcmp(start, "FT-PSK") == 0)
789 val |= WPA_KEY_MGMT_FT_PSK;
790 else if (os_strcmp(start, "FT-EAP") == 0)
791 val |= WPA_KEY_MGMT_FT_IEEE8021X;
792#ifdef CONFIG_SHA384
793 else if (os_strcmp(start, "FT-EAP-SHA384") == 0)
794 val |= WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
795#endif /* CONFIG_SHA384 */
796#endif /* CONFIG_IEEE80211R */
797 else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
798 val |= WPA_KEY_MGMT_PSK_SHA256;
799 else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
800 val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
801#ifdef CONFIG_WPS
802 else if (os_strcmp(start, "WPS") == 0)
803 val |= WPA_KEY_MGMT_WPS;
804#endif /* CONFIG_WPS */
805#ifdef CONFIG_SAE
806 else if (os_strcmp(start, "SAE") == 0)
807 val |= WPA_KEY_MGMT_SAE;
808 else if (os_strcmp(start, "SAE-EXT-KEY") == 0)
809 val |= WPA_KEY_MGMT_SAE_EXT_KEY;
810 else if (os_strcmp(start, "FT-SAE") == 0)
811 val |= WPA_KEY_MGMT_FT_SAE;
812 else if (os_strcmp(start, "FT-SAE-EXT-KEY") == 0)
813 val |= WPA_KEY_MGMT_FT_SAE_EXT_KEY;
814#endif /* CONFIG_SAE */
815#ifdef CONFIG_HS20
816 else if (os_strcmp(start, "OSEN") == 0)
817 val |= WPA_KEY_MGMT_OSEN;
818#endif /* CONFIG_HS20 */
819#ifdef CONFIG_SUITEB
820 else if (os_strcmp(start, "WPA-EAP-SUITE-B") == 0)
821 val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B;
822#endif /* CONFIG_SUITEB */
823#ifdef CONFIG_SUITEB192
824 else if (os_strcmp(start, "WPA-EAP-SUITE-B-192") == 0)
825 val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
826#endif /* CONFIG_SUITEB192 */
827#ifdef CONFIG_FILS
828 else if (os_strcmp(start, "FILS-SHA256") == 0)
829 val |= WPA_KEY_MGMT_FILS_SHA256;
830 else if (os_strcmp(start, "FILS-SHA384") == 0)
831 val |= WPA_KEY_MGMT_FILS_SHA384;
832#ifdef CONFIG_IEEE80211R
833 else if (os_strcmp(start, "FT-FILS-SHA256") == 0)
834 val |= WPA_KEY_MGMT_FT_FILS_SHA256;
835 else if (os_strcmp(start, "FT-FILS-SHA384") == 0)
836 val |= WPA_KEY_MGMT_FT_FILS_SHA384;
837#endif /* CONFIG_IEEE80211R */
838#endif /* CONFIG_FILS */
839#ifdef CONFIG_OWE
840 else if (os_strcmp(start, "OWE") == 0)
841 val |= WPA_KEY_MGMT_OWE;
842#endif /* CONFIG_OWE */
843#ifdef CONFIG_DPP
844 else if (os_strcmp(start, "DPP") == 0)
845 val |= WPA_KEY_MGMT_DPP;
846#endif /* CONFIG_DPP */
847 else {
848 wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
849 line, start);
850 errors++;
851 }
852
853 if (last)
854 break;
855 start = end + 1;
856 }
857 os_free(buf);
858
859 if (val == 0) {
860 wpa_printf(MSG_ERROR,
861 "Line %d: no key_mgmt values configured.", line);
862 errors++;
863 }
864
865 if (!errors && ssid->key_mgmt == val)
866 return 1;
867 wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", val);
868 ssid->key_mgmt = val;
869 return errors ? -1 : 0;
870}
871
872
873#ifndef NO_CONFIG_WRITE
874static char * wpa_config_write_key_mgmt(const struct parse_data *data,
875 struct wpa_ssid *ssid)
876{
877 char *buf, *pos, *end;
878 int ret;
879
880 pos = buf = os_zalloc(100);
881 if (buf == NULL)
882 return NULL;
883 end = buf + 100;
884
885 if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
886 ret = os_snprintf(pos, end - pos, "%sWPA-PSK",
887 pos == buf ? "" : " ");
888 if (os_snprintf_error(end - pos, ret)) {
889 end[-1] = '\0';
890 return buf;
891 }
892 pos += ret;
893 }
894
895 if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
896 ret = os_snprintf(pos, end - pos, "%sWPA-EAP",
897 pos == buf ? "" : " ");
898 if (os_snprintf_error(end - pos, ret)) {
899 end[-1] = '\0';
900 return buf;
901 }
902 pos += ret;
903 }
904
905 if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
906 ret = os_snprintf(pos, end - pos, "%sIEEE8021X",
907 pos == buf ? "" : " ");
908 if (os_snprintf_error(end - pos, ret)) {
909 end[-1] = '\0';
910 return buf;
911 }
912 pos += ret;
913 }
914
915 if (ssid->key_mgmt & WPA_KEY_MGMT_NONE) {
916 ret = os_snprintf(pos, end - pos, "%sNONE",
917 pos == buf ? "" : " ");
918 if (os_snprintf_error(end - pos, ret)) {
919 end[-1] = '\0';
920 return buf;
921 }
922 pos += ret;
923 }
924
925 if (ssid->key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
926 ret = os_snprintf(pos, end - pos, "%sWPA-NONE",
927 pos == buf ? "" : " ");
928 if (os_snprintf_error(end - pos, ret)) {
929 end[-1] = '\0';
930 return buf;
931 }
932 pos += ret;
933 }
934
935#ifdef CONFIG_IEEE80211R
936 if (ssid->key_mgmt & WPA_KEY_MGMT_FT_PSK) {
937 ret = os_snprintf(pos, end - pos, "%sFT-PSK",
938 pos == buf ? "" : " ");
939 if (os_snprintf_error(end - pos, ret)) {
940 end[-1] = '\0';
941 return buf;
942 }
943 pos += ret;
944 }
945
946 if (ssid->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
947 ret = os_snprintf(pos, end - pos, "%sFT-EAP",
948 pos == buf ? "" : " ");
949 if (os_snprintf_error(end - pos, ret)) {
950 end[-1] = '\0';
951 return buf;
952 }
953 pos += ret;
954 }
955
956#ifdef CONFIG_SHA384
957 if (ssid->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
958 ret = os_snprintf(pos, end - pos, "%sFT-EAP-SHA384",
959 pos == buf ? "" : " ");
960 if (os_snprintf_error(end - pos, ret)) {
961 end[-1] = '\0';
962 return buf;
963 }
964 pos += ret;
965 }
966#endif /* CONFIG_SHA384 */
967#endif /* CONFIG_IEEE80211R */
968
969 if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
970 ret = os_snprintf(pos, end - pos, "%sWPA-PSK-SHA256",
971 pos == buf ? "" : " ");
972 if (os_snprintf_error(end - pos, ret)) {
973 end[-1] = '\0';
974 return buf;
975 }
976 pos += ret;
977 }
978
979 if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
980 ret = os_snprintf(pos, end - pos, "%sWPA-EAP-SHA256",
981 pos == buf ? "" : " ");
982 if (os_snprintf_error(end - pos, ret)) {
983 end[-1] = '\0';
984 return buf;
985 }
986 pos += ret;
987 }
988
989#ifdef CONFIG_WPS
990 if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
991 ret = os_snprintf(pos, end - pos, "%sWPS",
992 pos == buf ? "" : " ");
993 if (os_snprintf_error(end - pos, ret)) {
994 end[-1] = '\0';
995 return buf;
996 }
997 pos += ret;
998 }
999#endif /* CONFIG_WPS */
1000
1001#ifdef CONFIG_SAE
1002 if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
1003 ret = os_snprintf(pos, end - pos, "%sSAE",
1004 pos == buf ? "" : " ");
1005 if (os_snprintf_error(end - pos, ret)) {
1006 end[-1] = '\0';
1007 return buf;
1008 }
1009 pos += ret;
1010 }
1011
1012 if (ssid->key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) {
1013 ret = os_snprintf(pos, end - pos, "%sSAE-EXT-KEY",
1014 pos == buf ? "" : " ");
1015 if (os_snprintf_error(end - pos, ret)) {
1016 end[-1] = '\0';
1017 return buf;
1018 }
1019 pos += ret;
1020 }
1021
1022 if (ssid->key_mgmt & WPA_KEY_MGMT_FT_SAE) {
1023 ret = os_snprintf(pos, end - pos, "%sFT-SAE",
1024 pos == buf ? "" : " ");
1025 if (os_snprintf_error(end - pos, ret)) {
1026 end[-1] = '\0';
1027 return buf;
1028 }
1029 pos += ret;
1030 }
1031
1032 if (ssid->key_mgmt & WPA_KEY_MGMT_FT_SAE_EXT_KEY) {
1033 ret = os_snprintf(pos, end - pos, "%sFT-SAE-EXT-KEY",
1034 pos == buf ? "" : " ");
1035 if (os_snprintf_error(end - pos, ret)) {
1036 end[-1] = '\0';
1037 return buf;
1038 }
1039 pos += ret;
1040 }
1041#endif /* CONFIG_SAE */
1042
1043#ifdef CONFIG_HS20
1044 if (ssid->key_mgmt & WPA_KEY_MGMT_OSEN) {
1045 ret = os_snprintf(pos, end - pos, "%sOSEN",
1046 pos == buf ? "" : " ");
1047 if (os_snprintf_error(end - pos, ret)) {
1048 end[-1] = '\0';
1049 return buf;
1050 }
1051 pos += ret;
1052 }
1053#endif /* CONFIG_HS20 */
1054
1055#ifdef CONFIG_SUITEB
1056 if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
1057 ret = os_snprintf(pos, end - pos, "%sWPA-EAP-SUITE-B",
1058 pos == buf ? "" : " ");
1059 if (os_snprintf_error(end - pos, ret)) {
1060 end[-1] = '\0';
1061 return buf;
1062 }
1063 pos += ret;
1064 }
1065#endif /* CONFIG_SUITEB */
1066
1067#ifdef CONFIG_SUITEB192
1068 if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
1069 ret = os_snprintf(pos, end - pos, "%sWPA-EAP-SUITE-B-192",
1070 pos == buf ? "" : " ");
1071 if (os_snprintf_error(end - pos, ret)) {
1072 end[-1] = '\0';
1073 return buf;
1074 }
1075 pos += ret;
1076 }
1077#endif /* CONFIG_SUITEB192 */
1078
1079#ifdef CONFIG_FILS
1080 if (ssid->key_mgmt & WPA_KEY_MGMT_FILS_SHA256) {
1081 ret = os_snprintf(pos, end - pos, "%sFILS-SHA256",
1082 pos == buf ? "" : " ");
1083 if (os_snprintf_error(end - pos, ret)) {
1084 end[-1] = '\0';
1085 return buf;
1086 }
1087 pos += ret;
1088 }
1089 if (ssid->key_mgmt & WPA_KEY_MGMT_FILS_SHA384) {
1090 ret = os_snprintf(pos, end - pos, "%sFILS-SHA384",
1091 pos == buf ? "" : " ");
1092 if (os_snprintf_error(end - pos, ret)) {
1093 end[-1] = '\0';
1094 return buf;
1095 }
1096 pos += ret;
1097 }
1098#ifdef CONFIG_IEEE80211R
1099 if (ssid->key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) {
1100 ret = os_snprintf(pos, end - pos, "%sFT-FILS-SHA256",
1101 pos == buf ? "" : " ");
1102 if (os_snprintf_error(end - pos, ret)) {
1103 end[-1] = '\0';
1104 return buf;
1105 }
1106 pos += ret;
1107 }
1108 if (ssid->key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) {
1109 ret = os_snprintf(pos, end - pos, "%sFT-FILS-SHA384",
1110 pos == buf ? "" : " ");
1111 if (os_snprintf_error(end - pos, ret)) {
1112 end[-1] = '\0';
1113 return buf;
1114 }
1115 pos += ret;
1116 }
1117#endif /* CONFIG_IEEE80211R */
1118#endif /* CONFIG_FILS */
1119
1120#ifdef CONFIG_DPP
1121 if (ssid->key_mgmt & WPA_KEY_MGMT_DPP) {
1122 ret = os_snprintf(pos, end - pos, "%sDPP",
1123 pos == buf ? "" : " ");
1124 if (os_snprintf_error(end - pos, ret)) {
1125 end[-1] = '\0';
1126 return buf;
1127 }
1128 pos += ret;
1129 }
1130#endif /* CONFIG_DPP */
1131
1132#ifdef CONFIG_OWE
1133 if (ssid->key_mgmt & WPA_KEY_MGMT_OWE) {
1134 ret = os_snprintf(pos, end - pos, "%sOWE",
1135 pos == buf ? "" : " ");
1136 if (os_snprintf_error(end - pos, ret)) {
1137 end[-1] = '\0';
1138 return buf;
1139 }
1140 pos += ret;
1141 }
1142#endif /* CONFIG_OWE */
1143
1144 if (pos == buf) {
1145 os_free(buf);
1146 buf = NULL;
1147 }
1148
1149 return buf;
1150}
1151#endif /* NO_CONFIG_WRITE */
1152
1153
1154static int wpa_config_parse_cipher(int line, const char *value)
1155{
1156#ifdef CONFIG_NO_WPA
1157 return -1;
1158#else /* CONFIG_NO_WPA */
1159 int val = wpa_parse_cipher(value);
1160 if (val < 0) {
1161 wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
1162 line, value);
1163 return -1;
1164 }
1165 if (val == 0) {
1166 wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.",
1167 line);
1168 return -1;
1169 }
1170 return val;
1171#endif /* CONFIG_NO_WPA */
1172}
1173
1174
1175#ifndef NO_CONFIG_WRITE
1176static char * wpa_config_write_cipher(int cipher)
1177{
1178#ifdef CONFIG_NO_WPA
1179 return NULL;
1180#else /* CONFIG_NO_WPA */
1181 char *buf = os_zalloc(50);
1182 if (buf == NULL)
1183 return NULL;
1184
1185 if (wpa_write_ciphers(buf, buf + 50, cipher, " ") < 0) {
1186 os_free(buf);
1187 return NULL;
1188 }
1189
1190 return buf;
1191#endif /* CONFIG_NO_WPA */
1192}
1193#endif /* NO_CONFIG_WRITE */
1194
1195
1196static int wpa_config_parse_pairwise(const struct parse_data *data,
1197 struct wpa_ssid *ssid, int line,
1198 const char *value)
1199{
1200 int val;
1201 val = wpa_config_parse_cipher(line, value);
1202 if (val == -1)
1203 return -1;
1204 if (val & ~WPA_ALLOWED_PAIRWISE_CIPHERS) {
1205 wpa_printf(MSG_ERROR, "Line %d: not allowed pairwise cipher "
1206 "(0x%x).", line, val);
1207 return -1;
1208 }
1209
1210 if (ssid->pairwise_cipher == val)
1211 return 1;
1212 wpa_printf(MSG_MSGDUMP, "pairwise: 0x%x", val);
1213 ssid->pairwise_cipher = val;
1214 return 0;
1215}
1216
1217
1218#ifndef NO_CONFIG_WRITE
1219static char * wpa_config_write_pairwise(const struct parse_data *data,
1220 struct wpa_ssid *ssid)
1221{
1222 return wpa_config_write_cipher(ssid->pairwise_cipher);
1223}
1224#endif /* NO_CONFIG_WRITE */
1225
1226
1227static int wpa_config_parse_group(const struct parse_data *data,
1228 struct wpa_ssid *ssid, int line,
1229 const char *value)
1230{
1231 int val;
1232 val = wpa_config_parse_cipher(line, value);
1233 if (val == -1)
1234 return -1;
1235
1236 /*
1237 * Backwards compatibility - filter out WEP ciphers that were previously
1238 * allowed.
1239 */
1240 val &= ~(WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40);
1241
1242 if (val & ~WPA_ALLOWED_GROUP_CIPHERS) {
1243 wpa_printf(MSG_ERROR, "Line %d: not allowed group cipher "
1244 "(0x%x).", line, val);
1245 return -1;
1246 }
1247
1248 if (ssid->group_cipher == val)
1249 return 1;
1250 wpa_printf(MSG_MSGDUMP, "group: 0x%x", val);
1251 ssid->group_cipher = val;
1252 return 0;
1253}
1254
1255
1256#ifndef NO_CONFIG_WRITE
1257static char * wpa_config_write_group(const struct parse_data *data,
1258 struct wpa_ssid *ssid)
1259{
1260 return wpa_config_write_cipher(ssid->group_cipher);
1261}
1262#endif /* NO_CONFIG_WRITE */
1263
1264
1265static int wpa_config_parse_group_mgmt(const struct parse_data *data,
1266 struct wpa_ssid *ssid, int line,
1267 const char *value)
1268{
1269 int val;
1270
1271 val = wpa_config_parse_cipher(line, value);
1272 if (val == -1)
1273 return -1;
1274
1275 if (val & ~WPA_ALLOWED_GROUP_MGMT_CIPHERS) {
1276 wpa_printf(MSG_ERROR,
1277 "Line %d: not allowed group management cipher (0x%x).",
1278 line, val);
1279 return -1;
1280 }
1281
1282 if (ssid->group_mgmt_cipher == val)
1283 return 1;
1284 wpa_printf(MSG_MSGDUMP, "group_mgmt: 0x%x", val);
1285 ssid->group_mgmt_cipher = val;
1286 return 0;
1287}
1288
1289
1290#ifndef NO_CONFIG_WRITE
1291static char * wpa_config_write_group_mgmt(const struct parse_data *data,
1292 struct wpa_ssid *ssid)
1293{
1294 return wpa_config_write_cipher(ssid->group_mgmt_cipher);
1295}
1296#endif /* NO_CONFIG_WRITE */
1297
1298
1299static int wpa_config_parse_auth_alg(const struct parse_data *data,
1300 struct wpa_ssid *ssid, int line,
1301 const char *value)
1302{
1303 int val = 0, last, errors = 0;
1304 char *start, *end, *buf;
1305
1306 buf = os_strdup(value);
1307 if (buf == NULL)
1308 return -1;
1309 start = buf;
1310
1311 while (*start != '\0') {
1312 while (*start == ' ' || *start == '\t')
1313 start++;
1314 if (*start == '\0')
1315 break;
1316 end = start;
1317 while (*end != ' ' && *end != '\t' && *end != '\0')
1318 end++;
1319 last = *end == '\0';
1320 *end = '\0';
1321 if (os_strcmp(start, "OPEN") == 0)
1322 val |= WPA_AUTH_ALG_OPEN;
1323 else if (os_strcmp(start, "SHARED") == 0)
1324 val |= WPA_AUTH_ALG_SHARED;
1325 else if (os_strcmp(start, "LEAP") == 0)
1326 val |= WPA_AUTH_ALG_LEAP;
1327 else {
1328 wpa_printf(MSG_ERROR, "Line %d: invalid auth_alg '%s'",
1329 line, start);
1330 errors++;
1331 }
1332
1333 if (last)
1334 break;
1335 start = end + 1;
1336 }
1337 os_free(buf);
1338
1339 if (val == 0) {
1340 wpa_printf(MSG_ERROR,
1341 "Line %d: no auth_alg values configured.", line);
1342 errors++;
1343 }
1344
1345 if (!errors && ssid->auth_alg == val)
1346 return 1;
1347 wpa_printf(MSG_MSGDUMP, "auth_alg: 0x%x", val);
1348 ssid->auth_alg = val;
1349 return errors ? -1 : 0;
1350}
1351
1352
1353#ifndef NO_CONFIG_WRITE
1354static char * wpa_config_write_auth_alg(const struct parse_data *data,
1355 struct wpa_ssid *ssid)
1356{
1357 char *buf, *pos, *end;
1358 int ret;
1359
1360 pos = buf = os_zalloc(30);
1361 if (buf == NULL)
1362 return NULL;
1363 end = buf + 30;
1364
1365 if (ssid->auth_alg & WPA_AUTH_ALG_OPEN) {
1366 ret = os_snprintf(pos, end - pos, "%sOPEN",
1367 pos == buf ? "" : " ");
1368 if (os_snprintf_error(end - pos, ret)) {
1369 end[-1] = '\0';
1370 return buf;
1371 }
1372 pos += ret;
1373 }
1374
1375 if (ssid->auth_alg & WPA_AUTH_ALG_SHARED) {
1376 ret = os_snprintf(pos, end - pos, "%sSHARED",
1377 pos == buf ? "" : " ");
1378 if (os_snprintf_error(end - pos, ret)) {
1379 end[-1] = '\0';
1380 return buf;
1381 }
1382 pos += ret;
1383 }
1384
1385 if (ssid->auth_alg & WPA_AUTH_ALG_LEAP) {
1386 ret = os_snprintf(pos, end - pos, "%sLEAP",
1387 pos == buf ? "" : " ");
1388 if (os_snprintf_error(end - pos, ret)) {
1389 end[-1] = '\0';
1390 return buf;
1391 }
1392 pos += ret;
1393 }
1394
1395 if (pos == buf) {
1396 os_free(buf);
1397 buf = NULL;
1398 }
1399
1400 return buf;
1401}
1402#endif /* NO_CONFIG_WRITE */
1403
1404
1405static int * wpa_config_parse_int_array(const char *value)
1406{
1407 int *freqs;
1408 size_t used, len;
1409 const char *pos;
1410
1411 used = 0;
1412 len = 10;
1413 freqs = os_calloc(len + 1, sizeof(int));
1414 if (freqs == NULL)
1415 return NULL;
1416
1417 pos = value;
1418 while (pos) {
1419 while (*pos == ' ')
1420 pos++;
1421 if (used == len) {
1422 int *n;
1423 size_t i;
1424 n = os_realloc_array(freqs, len * 2 + 1, sizeof(int));
1425 if (n == NULL) {
1426 os_free(freqs);
1427 return NULL;
1428 }
1429 for (i = len; i <= len * 2; i++)
1430 n[i] = 0;
1431 freqs = n;
1432 len *= 2;
1433 }
1434
1435 freqs[used] = atoi(pos);
1436 if (freqs[used] == 0)
1437 break;
1438 used++;
1439 pos = os_strchr(pos + 1, ' ');
1440 }
1441
1442 return freqs;
1443}
1444
1445
1446static int wpa_config_parse_scan_freq(const struct parse_data *data,
1447 struct wpa_ssid *ssid, int line,
1448 const char *value)
1449{
1450 int *freqs;
1451
1452 freqs = wpa_config_parse_int_array(value);
1453 if (freqs == NULL)
1454 return -1;
1455 if (freqs[0] == 0) {
1456 os_free(freqs);
1457 freqs = NULL;
1458 }
1459 os_free(ssid->scan_freq);
1460 ssid->scan_freq = freqs;
1461
1462 return 0;
1463}
1464
1465
1466static int wpa_config_parse_freq_list(const struct parse_data *data,
1467 struct wpa_ssid *ssid, int line,
1468 const char *value)
1469{
1470 int *freqs;
1471
1472 freqs = wpa_config_parse_int_array(value);
1473 if (freqs == NULL)
1474 return -1;
1475 if (freqs[0] == 0) {
1476 os_free(freqs);
1477 freqs = NULL;
1478 }
1479 os_free(ssid->freq_list);
1480 ssid->freq_list = freqs;
1481
1482 return 0;
1483}
1484
1485
1486#ifndef NO_CONFIG_WRITE
1487static char * wpa_config_write_freqs(const struct parse_data *data,
1488 const int *freqs)
1489{
1490 char *buf, *pos, *end;
1491 int i, ret;
1492 size_t count;
1493
1494 if (freqs == NULL)
1495 return NULL;
1496
1497 count = 0;
1498 for (i = 0; freqs[i]; i++)
1499 count++;
1500
1501 pos = buf = os_zalloc(10 * count + 1);
1502 if (buf == NULL)
1503 return NULL;
1504 end = buf + 10 * count + 1;
1505
1506 for (i = 0; freqs[i]; i++) {
1507 ret = os_snprintf(pos, end - pos, "%s%u",
1508 i == 0 ? "" : " ", freqs[i]);
1509 if (os_snprintf_error(end - pos, ret)) {
1510 end[-1] = '\0';
1511 return buf;
1512 }
1513 pos += ret;
1514 }
1515
1516 return buf;
1517}
1518
1519
1520static char * wpa_config_write_scan_freq(const struct parse_data *data,
1521 struct wpa_ssid *ssid)
1522{
1523 return wpa_config_write_freqs(data, ssid->scan_freq);
1524}
1525
1526
1527static char * wpa_config_write_freq_list(const struct parse_data *data,
1528 struct wpa_ssid *ssid)
1529{
1530 return wpa_config_write_freqs(data, ssid->freq_list);
1531}
1532#endif /* NO_CONFIG_WRITE */
1533
1534
1535#ifdef IEEE8021X_EAPOL
1536static int wpa_config_parse_eap(const struct parse_data *data,
1537 struct wpa_ssid *ssid, int line,
1538 const char *value)
1539{
1540 int last, errors = 0;
1541 char *start, *end, *buf;
1542 struct eap_method_type *methods = NULL, *tmp;
1543 size_t num_methods = 0;
1544
1545 buf = os_strdup(value);
1546 if (buf == NULL)
1547 return -1;
1548 start = buf;
1549
1550 while (*start != '\0') {
1551 while (*start == ' ' || *start == '\t')
1552 start++;
1553 if (*start == '\0')
1554 break;
1555 end = start;
1556 while (*end != ' ' && *end != '\t' && *end != '\0')
1557 end++;
1558 last = *end == '\0';
1559 *end = '\0';
1560 tmp = methods;
1561 methods = os_realloc_array(methods, num_methods + 1,
1562 sizeof(*methods));
1563 if (methods == NULL) {
1564 os_free(tmp);
1565 os_free(buf);
1566 return -1;
1567 }
1568 methods[num_methods].method = eap_peer_get_type(
1569 start, &methods[num_methods].vendor);
1570 if (methods[num_methods].vendor == EAP_VENDOR_IETF &&
1571 methods[num_methods].method == EAP_TYPE_NONE) {
1572 wpa_printf(MSG_ERROR, "Line %d: unknown EAP method "
1573 "'%s'", line, start);
1574 wpa_printf(MSG_ERROR, "You may need to add support for"
1575 " this EAP method during wpa_supplicant\n"
1576 "build time configuration.\n"
1577 "See README for more information.");
1578 errors++;
1579 } else if (methods[num_methods].vendor == EAP_VENDOR_IETF &&
1580 methods[num_methods].method == EAP_TYPE_LEAP)
1581 ssid->leap++;
1582 else
1583 ssid->non_leap++;
1584 num_methods++;
1585 if (last)
1586 break;
1587 start = end + 1;
1588 }
1589 os_free(buf);
1590
1591 tmp = methods;
1592 methods = os_realloc_array(methods, num_methods + 1, sizeof(*methods));
1593 if (methods == NULL) {
1594 os_free(tmp);
1595 return -1;
1596 }
1597 methods[num_methods].vendor = EAP_VENDOR_IETF;
1598 methods[num_methods].method = EAP_TYPE_NONE;
1599 num_methods++;
1600
1601 if (!errors && ssid->eap.eap_methods) {
1602 struct eap_method_type *prev_m;
1603 size_t i, j, prev_methods, match = 0;
1604
1605 prev_m = ssid->eap.eap_methods;
1606 for (i = 0; prev_m[i].vendor != EAP_VENDOR_IETF ||
1607 prev_m[i].method != EAP_TYPE_NONE; i++) {
1608 /* Count the methods */
1609 }
1610 prev_methods = i + 1;
1611
1612 for (i = 0; prev_methods == num_methods && i < prev_methods;
1613 i++) {
1614 for (j = 0; j < num_methods; j++) {
1615 if (prev_m[i].vendor == methods[j].vendor &&
1616 prev_m[i].method == methods[j].method) {
1617 match++;
1618 break;
1619 }
1620 }
1621 }
1622 if (match == num_methods) {
1623 os_free(methods);
1624 return 1;
1625 }
1626 }
1627 wpa_hexdump(MSG_MSGDUMP, "eap methods",
1628 (u8 *) methods, num_methods * sizeof(*methods));
1629 os_free(ssid->eap.eap_methods);
1630 ssid->eap.eap_methods = methods;
1631 return errors ? -1 : 0;
1632}
1633
1634
1635#ifndef NO_CONFIG_WRITE
1636static char * wpa_config_write_eap(const struct parse_data *data,
1637 struct wpa_ssid *ssid)
1638{
1639 int i, ret;
1640 char *buf, *pos, *end;
1641 const struct eap_method_type *eap_methods = ssid->eap.eap_methods;
1642 const char *name;
1643
1644 if (eap_methods == NULL)
1645 return NULL;
1646
1647 pos = buf = os_zalloc(100);
1648 if (buf == NULL)
1649 return NULL;
1650 end = buf + 100;
1651
1652 for (i = 0; eap_methods[i].vendor != EAP_VENDOR_IETF ||
1653 eap_methods[i].method != EAP_TYPE_NONE; i++) {
1654 name = eap_get_name(eap_methods[i].vendor,
1655 eap_methods[i].method);
1656 if (name) {
1657 ret = os_snprintf(pos, end - pos, "%s%s",
1658 pos == buf ? "" : " ", name);
1659 if (os_snprintf_error(end - pos, ret))
1660 break;
1661 pos += ret;
1662 }
1663 }
1664
1665 end[-1] = '\0';
1666
1667 return buf;
1668}
1669#endif /* NO_CONFIG_WRITE */
1670
1671
1672static int wpa_config_parse_password(const struct parse_data *data,
1673 struct wpa_ssid *ssid, int line,
1674 const char *value)
1675{
1676 u8 *hash;
1677
1678 if (os_strcmp(value, "NULL") == 0) {
1679 if (!ssid->eap.password)
1680 return 1; /* Already unset */
1681 wpa_printf(MSG_DEBUG, "Unset configuration string 'password'");
1682 bin_clear_free(ssid->eap.password, ssid->eap.password_len);
1683 ssid->eap.password = NULL;
1684 ssid->eap.password_len = 0;
1685 return 0;
1686 }
1687
1688#ifdef CONFIG_EXT_PASSWORD
1689 if (os_strncmp(value, "ext:", 4) == 0) {
1690 char *name = os_strdup(value + 4);
1691 if (!name)
1692 return -1;
1693 bin_clear_free(ssid->eap.password, ssid->eap.password_len);
1694 ssid->eap.password = (u8 *) name;
1695 ssid->eap.password_len = os_strlen(name);
1696 ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
1697 ssid->eap.flags |= EAP_CONFIG_FLAGS_EXT_PASSWORD;
1698 return 0;
1699 }
1700#endif /* CONFIG_EXT_PASSWORD */
1701
1702 if (os_strncmp(value, "hash:", 5) != 0) {
1703 char *tmp;
1704 size_t res_len;
1705
1706 tmp = wpa_config_parse_string(value, &res_len);
1707 if (!tmp) {
1708 wpa_printf(MSG_ERROR,
1709 "Line %d: failed to parse password.", line);
1710 return -1;
1711 }
1712 wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
1713 (u8 *) tmp, res_len);
1714
1715 bin_clear_free(ssid->eap.password, ssid->eap.password_len);
1716 ssid->eap.password = (u8 *) tmp;
1717 ssid->eap.password_len = res_len;
1718 ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
1719 ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD;
1720
1721 return 0;
1722 }
1723
1724
1725 /* NtPasswordHash: hash:<32 hex digits> */
1726 if (os_strlen(value + 5) != 2 * 16) {
1727 wpa_printf(MSG_ERROR,
1728 "Line %d: Invalid password hash length (expected 32 hex digits)",
1729 line);
1730 return -1;
1731 }
1732
1733 hash = os_malloc(16);
1734 if (!hash)
1735 return -1;
1736
1737 if (hexstr2bin(value + 5, hash, 16)) {
1738 os_free(hash);
1739 wpa_printf(MSG_ERROR, "Line %d: Invalid password hash", line);
1740 return -1;
1741 }
1742
1743 wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16);
1744
1745 if (ssid->eap.password && ssid->eap.password_len == 16 &&
1746 os_memcmp(ssid->eap.password, hash, 16) == 0 &&
1747 (ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) {
1748 bin_clear_free(hash, 16);
1749 return 1;
1750 }
1751 bin_clear_free(ssid->eap.password, ssid->eap.password_len);
1752 ssid->eap.password = hash;
1753 ssid->eap.password_len = 16;
1754 ssid->eap.flags |= EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
1755 ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD;
1756
1757 return 0;
1758}
1759
1760
1761static int wpa_config_parse_machine_password(const struct parse_data *data,
1762 struct wpa_ssid *ssid, int line,
1763 const char *value)
1764{
1765 u8 *hash;
1766
1767 if (os_strcmp(value, "NULL") == 0) {
1768 if (!ssid->eap.machine_password)
1769 return 1; /* Already unset */
1770 wpa_printf(MSG_DEBUG,
1771 "Unset configuration string 'machine_password'");
1772 bin_clear_free(ssid->eap.machine_password,
1773 ssid->eap.machine_password_len);
1774 ssid->eap.machine_password = NULL;
1775 ssid->eap.machine_password_len = 0;
1776 return 0;
1777 }
1778
1779#ifdef CONFIG_EXT_PASSWORD
1780 if (os_strncmp(value, "ext:", 4) == 0) {
1781 char *name = os_strdup(value + 4);
1782
1783 if (!name)
1784 return -1;
1785 bin_clear_free(ssid->eap.machine_password,
1786 ssid->eap.machine_password_len);
1787 ssid->eap.machine_password = (u8 *) name;
1788 ssid->eap.machine_password_len = os_strlen(name);
1789 ssid->eap.flags &= ~EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH;
1790 ssid->eap.flags |= EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD;
1791 return 0;
1792 }
1793#endif /* CONFIG_EXT_PASSWORD */
1794
1795 if (os_strncmp(value, "hash:", 5) != 0) {
1796 char *tmp;
1797 size_t res_len;
1798
1799 tmp = wpa_config_parse_string(value, &res_len);
1800 if (!tmp) {
1801 wpa_printf(MSG_ERROR,
1802 "Line %d: failed to parse machine_password.",
1803 line);
1804 return -1;
1805 }
1806 wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
1807 (u8 *) tmp, res_len);
1808
1809 bin_clear_free(ssid->eap.machine_password,
1810 ssid->eap.machine_password_len);
1811 ssid->eap.machine_password = (u8 *) tmp;
1812 ssid->eap.machine_password_len = res_len;
1813 ssid->eap.flags &= ~EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH;
1814 ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD;
1815
1816 return 0;
1817 }
1818
1819
1820 /* NtPasswordHash: hash:<32 hex digits> */
1821 if (os_strlen(value + 5) != 2 * 16) {
1822 wpa_printf(MSG_ERROR,
1823 "Line %d: Invalid machine_password hash length (expected 32 hex digits)",
1824 line);
1825 return -1;
1826 }
1827
1828 hash = os_malloc(16);
1829 if (!hash)
1830 return -1;
1831
1832 if (hexstr2bin(value + 5, hash, 16)) {
1833 os_free(hash);
1834 wpa_printf(MSG_ERROR, "Line %d: Invalid machine_password hash",
1835 line);
1836 return -1;
1837 }
1838
1839 wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16);
1840
1841 if (ssid->eap.machine_password &&
1842 ssid->eap.machine_password_len == 16 &&
1843 os_memcmp(ssid->eap.machine_password, hash, 16) == 0 &&
1844 (ssid->eap.flags & EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH)) {
1845 bin_clear_free(hash, 16);
1846 return 1;
1847 }
1848 bin_clear_free(ssid->eap.machine_password,
1849 ssid->eap.machine_password_len);
1850 ssid->eap.machine_password = hash;
1851 ssid->eap.machine_password_len = 16;
1852 ssid->eap.flags |= EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH;
1853 ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD;
1854
1855 return 0;
1856}
1857
1858
1859#ifndef NO_CONFIG_WRITE
1860
1861static char * wpa_config_write_password(const struct parse_data *data,
1862 struct wpa_ssid *ssid)
1863{
1864 char *buf;
1865
1866 if (!ssid->eap.password)
1867 return NULL;
1868
1869#ifdef CONFIG_EXT_PASSWORD
1870 if (ssid->eap.flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
1871 buf = os_zalloc(4 + ssid->eap.password_len + 1);
1872 if (!buf)
1873 return NULL;
1874 os_memcpy(buf, "ext:", 4);
1875 os_memcpy(buf + 4, ssid->eap.password, ssid->eap.password_len);
1876 return buf;
1877 }
1878#endif /* CONFIG_EXT_PASSWORD */
1879
1880 if (!(ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) {
1881 return wpa_config_write_string(
1882 ssid->eap.password, ssid->eap.password_len);
1883 }
1884
1885 buf = os_malloc(5 + 32 + 1);
1886 if (!buf)
1887 return NULL;
1888
1889 os_memcpy(buf, "hash:", 5);
1890 wpa_snprintf_hex(buf + 5, 32 + 1, ssid->eap.password, 16);
1891
1892 return buf;
1893}
1894
1895
1896static char * wpa_config_write_machine_password(const struct parse_data *data,
1897 struct wpa_ssid *ssid)
1898{
1899 char *buf;
1900
1901 if (!ssid->eap.machine_password)
1902 return NULL;
1903
1904#ifdef CONFIG_EXT_PASSWORD
1905 if (ssid->eap.flags & EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD) {
1906 buf = os_zalloc(4 + ssid->eap.machine_password_len + 1);
1907 if (!buf)
1908 return NULL;
1909 os_memcpy(buf, "ext:", 4);
1910 os_memcpy(buf + 4, ssid->eap.machine_password,
1911 ssid->eap.machine_password_len);
1912 return buf;
1913 }
1914#endif /* CONFIG_EXT_PASSWORD */
1915
1916 if (!(ssid->eap.flags & EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH)) {
1917 return wpa_config_write_string(
1918 ssid->eap.machine_password,
1919 ssid->eap.machine_password_len);
1920 }
1921
1922 buf = os_malloc(5 + 32 + 1);
1923 if (!buf)
1924 return NULL;
1925
1926 os_memcpy(buf, "hash:", 5);
1927 wpa_snprintf_hex(buf + 5, 32 + 1, ssid->eap.machine_password, 16);
1928
1929 return buf;
1930}
1931
1932#endif /* NO_CONFIG_WRITE */
1933#endif /* IEEE8021X_EAPOL */
1934
1935
1936#ifdef CONFIG_WEP
1937
1938static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line,
1939 const char *value, int idx)
1940{
1941 char *buf, title[20];
1942 int res;
1943
1944 buf = wpa_config_parse_string(value, len);
1945 if (buf == NULL) {
1946 wpa_printf(MSG_ERROR, "Line %d: Invalid WEP key %d '%s'.",
1947 line, idx, value);
1948 return -1;
1949 }
1950 if (*len > MAX_WEP_KEY_LEN) {
1951 wpa_printf(MSG_ERROR, "Line %d: Too long WEP key %d '%s'.",
1952 line, idx, value);
1953 os_free(buf);
1954 return -1;
1955 }
1956 if (*len && *len != 5 && *len != 13 && *len != 16) {
1957 wpa_printf(MSG_ERROR, "Line %d: Invalid WEP key length %u - "
1958 "this network block will be ignored",
1959 line, (unsigned int) *len);
1960 }
1961 os_memcpy(key, buf, *len);
1962 str_clear_free(buf);
1963 res = os_snprintf(title, sizeof(title), "wep_key%d", idx);
1964 if (!os_snprintf_error(sizeof(title), res))
1965 wpa_hexdump_key(MSG_MSGDUMP, title, key, *len);
1966 return 0;
1967}
1968
1969
1970static int wpa_config_parse_wep_key0(const struct parse_data *data,
1971 struct wpa_ssid *ssid, int line,
1972 const char *value)
1973{
1974 return wpa_config_parse_wep_key(ssid->wep_key[0],
1975 &ssid->wep_key_len[0], line,
1976 value, 0);
1977}
1978
1979
1980static int wpa_config_parse_wep_key1(const struct parse_data *data,
1981 struct wpa_ssid *ssid, int line,
1982 const char *value)
1983{
1984 return wpa_config_parse_wep_key(ssid->wep_key[1],
1985 &ssid->wep_key_len[1], line,
1986 value, 1);
1987}
1988
1989
1990static int wpa_config_parse_wep_key2(const struct parse_data *data,
1991 struct wpa_ssid *ssid, int line,
1992 const char *value)
1993{
1994 return wpa_config_parse_wep_key(ssid->wep_key[2],
1995 &ssid->wep_key_len[2], line,
1996 value, 2);
1997}
1998
1999
2000static int wpa_config_parse_wep_key3(const struct parse_data *data,
2001 struct wpa_ssid *ssid, int line,
2002 const char *value)
2003{
2004 return wpa_config_parse_wep_key(ssid->wep_key[3],
2005 &ssid->wep_key_len[3], line,
2006 value, 3);
2007}
2008
2009
2010#ifndef NO_CONFIG_WRITE
2011static char * wpa_config_write_wep_key(struct wpa_ssid *ssid, int idx)
2012{
2013 if (ssid->wep_key_len[idx] == 0)
2014 return NULL;
2015 return wpa_config_write_string(ssid->wep_key[idx],
2016 ssid->wep_key_len[idx]);
2017}
2018
2019
2020static char * wpa_config_write_wep_key0(const struct parse_data *data,
2021 struct wpa_ssid *ssid)
2022{
2023 return wpa_config_write_wep_key(ssid, 0);
2024}
2025
2026
2027static char * wpa_config_write_wep_key1(const struct parse_data *data,
2028 struct wpa_ssid *ssid)
2029{
2030 return wpa_config_write_wep_key(ssid, 1);
2031}
2032
2033
2034static char * wpa_config_write_wep_key2(const struct parse_data *data,
2035 struct wpa_ssid *ssid)
2036{
2037 return wpa_config_write_wep_key(ssid, 2);
2038}
2039
2040
2041static char * wpa_config_write_wep_key3(const struct parse_data *data,
2042 struct wpa_ssid *ssid)
2043{
2044 return wpa_config_write_wep_key(ssid, 3);
2045}
2046#endif /* NO_CONFIG_WRITE */
2047
2048#endif /* CONFIG_WEP */
2049
2050
2051#ifdef CONFIG_P2P
2052
2053static int wpa_config_parse_go_p2p_dev_addr(const struct parse_data *data,
2054 struct wpa_ssid *ssid, int line,
2055 const char *value)
2056{
2057 if (value[0] == '\0' || os_strcmp(value, "\"\"") == 0 ||
2058 os_strcmp(value, "any") == 0) {
2059 os_memset(ssid->go_p2p_dev_addr, 0, ETH_ALEN);
2060 wpa_printf(MSG_MSGDUMP, "GO P2P Device Address any");
2061 return 0;
2062 }
2063 if (hwaddr_aton(value, ssid->go_p2p_dev_addr)) {
2064 wpa_printf(MSG_ERROR, "Line %d: Invalid GO P2P Device Address '%s'.",
2065 line, value);
2066 return -1;
2067 }
2068 ssid->bssid_set = 1;
2069 wpa_printf(MSG_MSGDUMP, "GO P2P Device Address " MACSTR,
2070 MAC2STR(ssid->go_p2p_dev_addr));
2071 return 0;
2072}
2073
2074
2075#ifndef NO_CONFIG_WRITE
2076static char * wpa_config_write_go_p2p_dev_addr(const struct parse_data *data,
2077 struct wpa_ssid *ssid)
2078{
2079 char *value;
2080 int res;
2081
2082 if (is_zero_ether_addr(ssid->go_p2p_dev_addr))
2083 return NULL;
2084
2085 value = os_malloc(20);
2086 if (value == NULL)
2087 return NULL;
2088 res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->go_p2p_dev_addr));
2089 if (os_snprintf_error(20, res)) {
2090 os_free(value);
2091 return NULL;
2092 }
2093 value[20 - 1] = '\0';
2094 return value;
2095}
2096#endif /* NO_CONFIG_WRITE */
2097
2098
2099static int wpa_config_parse_p2p_client_list(const struct parse_data *data,
2100 struct wpa_ssid *ssid, int line,
2101 const char *value)
2102{
2103 return wpa_config_parse_addr_list(data, line, value,
2104 &ssid->p2p_client_list,
2105 &ssid->num_p2p_clients,
2106 "p2p_client_list", 0, 0);
2107}
2108
2109
2110#ifndef NO_CONFIG_WRITE
2111static char * wpa_config_write_p2p_client_list(const struct parse_data *data,
2112 struct wpa_ssid *ssid)
2113{
2114 return wpa_config_write_addr_list(data, ssid->p2p_client_list,
2115 ssid->num_p2p_clients,
2116 "p2p_client_list");
2117}
2118#endif /* NO_CONFIG_WRITE */
2119
2120
2121static int wpa_config_parse_psk_list(const struct parse_data *data,
2122 struct wpa_ssid *ssid, int line,
2123 const char *value)
2124{
2125 struct psk_list_entry *p;
2126 const char *pos;
2127
2128 p = os_zalloc(sizeof(*p));
2129 if (p == NULL)
2130 return -1;
2131
2132 pos = value;
2133 if (os_strncmp(pos, "P2P-", 4) == 0) {
2134 p->p2p = 1;
2135 pos += 4;
2136 }
2137
2138 if (hwaddr_aton(pos, p->addr)) {
2139 wpa_printf(MSG_ERROR, "Line %d: Invalid psk_list address '%s'",
2140 line, pos);
2141 os_free(p);
2142 return -1;
2143 }
2144 pos += 17;
2145 if (*pos != '-') {
2146 wpa_printf(MSG_ERROR, "Line %d: Invalid psk_list '%s'",
2147 line, pos);
2148 os_free(p);
2149 return -1;
2150 }
2151 pos++;
2152
2153 if (hexstr2bin(pos, p->psk, PMK_LEN) || pos[PMK_LEN * 2] != '\0') {
2154 wpa_printf(MSG_ERROR, "Line %d: Invalid psk_list PSK '%s'",
2155 line, pos);
2156 os_free(p);
2157 return -1;
2158 }
2159
2160 dl_list_add(&ssid->psk_list, &p->list);
2161
2162 return 0;
2163}
2164
2165
2166#ifndef NO_CONFIG_WRITE
2167static char * wpa_config_write_psk_list(const struct parse_data *data,
2168 struct wpa_ssid *ssid)
2169{
2170 return NULL;
2171}
2172#endif /* NO_CONFIG_WRITE */
2173
2174#endif /* CONFIG_P2P */
2175
2176
2177#ifdef CONFIG_MESH
2178
2179static int wpa_config_parse_mesh_basic_rates(const struct parse_data *data,
2180 struct wpa_ssid *ssid, int line,
2181 const char *value)
2182{
2183 int *rates = wpa_config_parse_int_array(value);
2184
2185 if (rates == NULL) {
2186 wpa_printf(MSG_ERROR, "Line %d: Invalid mesh_basic_rates '%s'",
2187 line, value);
2188 return -1;
2189 }
2190 if (rates[0] == 0) {
2191 os_free(rates);
2192 rates = NULL;
2193 }
2194
2195 os_free(ssid->mesh_basic_rates);
2196 ssid->mesh_basic_rates = rates;
2197
2198 return 0;
2199}
2200
2201
2202#ifndef NO_CONFIG_WRITE
2203
2204static char * wpa_config_write_mesh_basic_rates(const struct parse_data *data,
2205 struct wpa_ssid *ssid)
2206{
2207 return wpa_config_write_freqs(data, ssid->mesh_basic_rates);
2208}
2209
2210#endif /* NO_CONFIG_WRITE */
2211
2212#endif /* CONFIG_MESH */
2213
2214
2215#ifdef CONFIG_MACSEC
2216
2217static int wpa_config_parse_mka_cak(const struct parse_data *data,
2218 struct wpa_ssid *ssid, int line,
2219 const char *value)
2220{
2221 size_t len;
2222
2223 len = os_strlen(value);
2224 if (len > 2 * MACSEC_CAK_MAX_LEN ||
2225 (len != 2 * 16 && len != 2 * 32) ||
2226 hexstr2bin(value, ssid->mka_cak, len / 2)) {
2227 wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CAK '%s'.",
2228 line, value);
2229 return -1;
2230 }
2231 ssid->mka_cak_len = len / 2;
2232 ssid->mka_psk_set |= MKA_PSK_SET_CAK;
2233
2234 wpa_hexdump_key(MSG_MSGDUMP, "MKA-CAK", ssid->mka_cak,
2235 ssid->mka_cak_len);
2236 return 0;
2237}
2238
2239
2240static int wpa_config_parse_mka_ckn(const struct parse_data *data,
2241 struct wpa_ssid *ssid, int line,
2242 const char *value)
2243{
2244 size_t len;
2245
2246 len = os_strlen(value);
2247 if (len > 2 * MACSEC_CKN_MAX_LEN || /* too long */
2248 len < 2 || /* too short */
2249 len % 2 != 0 /* not an integral number of bytes */) {
2250 wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CKN '%s'.",
2251 line, value);
2252 return -1;
2253 }
2254 ssid->mka_ckn_len = len / 2;
2255 if (hexstr2bin(value, ssid->mka_ckn, ssid->mka_ckn_len)) {
2256 wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CKN '%s'.",
2257 line, value);
2258 return -1;
2259 }
2260
2261 ssid->mka_psk_set |= MKA_PSK_SET_CKN;
2262
2263 wpa_hexdump_key(MSG_MSGDUMP, "MKA-CKN", ssid->mka_ckn,
2264 ssid->mka_ckn_len);
2265 return 0;
2266}
2267
2268
2269#ifndef NO_CONFIG_WRITE
2270
2271static char * wpa_config_write_mka_cak(const struct parse_data *data,
2272 struct wpa_ssid *ssid)
2273{
2274 if (!(ssid->mka_psk_set & MKA_PSK_SET_CAK))
2275 return NULL;
2276
2277 return wpa_config_write_string_hex(ssid->mka_cak, ssid->mka_cak_len);
2278}
2279
2280
2281static char * wpa_config_write_mka_ckn(const struct parse_data *data,
2282 struct wpa_ssid *ssid)
2283{
2284 if (!(ssid->mka_psk_set & MKA_PSK_SET_CKN))
2285 return NULL;
2286 return wpa_config_write_string_hex(ssid->mka_ckn, ssid->mka_ckn_len);
2287}
2288
2289#endif /* NO_CONFIG_WRITE */
2290
2291#endif /* CONFIG_MACSEC */
2292
2293
2294#ifdef CONFIG_OCV
2295
2296static int wpa_config_parse_ocv(const struct parse_data *data,
2297 struct wpa_ssid *ssid, int line,
2298 const char *value)
2299{
2300 char *end;
2301
2302 ssid->ocv = strtol(value, &end, 0);
2303 if (*end || ssid->ocv < 0 || ssid->ocv > 1) {
2304 wpa_printf(MSG_ERROR, "Line %d: Invalid ocv value '%s'.",
2305 line, value);
2306 return -1;
2307 }
2308 if (ssid->ocv && ssid->ieee80211w == NO_MGMT_FRAME_PROTECTION)
2309 ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
2310 return 0;
2311}
2312
2313
2314#ifndef NO_CONFIG_WRITE
2315static char * wpa_config_write_ocv(const struct parse_data *data,
2316 struct wpa_ssid *ssid)
2317{
2318 char *value = os_malloc(20);
2319
2320 if (!value)
2321 return NULL;
2322 os_snprintf(value, 20, "%d", ssid->ocv);
2323 value[20 - 1] = '\0';
2324 return value;
2325}
2326#endif /* NO_CONFIG_WRITE */
2327
2328#endif /* CONFIG_OCV */
2329
2330
2331static int wpa_config_parse_peerkey(const struct parse_data *data,
2332 struct wpa_ssid *ssid, int line,
2333 const char *value)
2334{
2335 wpa_printf(MSG_INFO, "NOTE: Obsolete peerkey parameter ignored");
2336 return 0;
2337}
2338
2339
2340#ifndef NO_CONFIG_WRITE
2341static char * wpa_config_write_peerkey(const struct parse_data *data,
2342 struct wpa_ssid *ssid)
2343{
2344 return NULL;
2345}
2346#endif /* NO_CONFIG_WRITE */
2347
2348
2349static int wpa_config_parse_mac_value(const struct parse_data *data,
2350 struct wpa_ssid *ssid, int line,
2351 const char *value)
2352{
2353 u8 mac_value[ETH_ALEN];
2354
2355 if (hwaddr_aton(value, mac_value) == 0) {
2356 if (os_memcmp(mac_value, ssid->mac_value, ETH_ALEN) == 0)
2357 return 1;
2358 os_memcpy(ssid->mac_value, mac_value, ETH_ALEN);
2359 return 0;
2360 }
2361
2362 wpa_printf(MSG_ERROR, "Line %d: Invalid MAC address '%s'",
2363 line, value);
2364 return -1;
2365}
2366
2367
2368#ifndef NO_CONFIG_WRITE
2369static char * wpa_config_write_mac_value(const struct parse_data *data,
2370 struct wpa_ssid *ssid)
2371{
2372 const size_t size = 3 * ETH_ALEN;
2373 char *value;
2374 int res;
2375
2376 if (ssid->mac_addr != WPAS_MAC_ADDR_STYLE_DEDICATED_PER_ESS)
2377 return NULL;
2378
2379 value = os_malloc(size);
2380 if (!value)
2381 return NULL;
2382 res = os_snprintf(value, size, MACSTR, MAC2STR(ssid->mac_value));
2383 if (os_snprintf_error(size, res)) {
2384 os_free(value);
2385 return NULL;
2386 }
2387 value[size - 1] = '\0';
2388 return value;
2389}
2390#endif /* NO_CONFIG_WRITE */
2391
2392
2393static int wpa_config_parse_mcast_rate(const struct parse_data *data,
2394 struct wpa_ssid *ssid, int line,
2395 const char *value)
2396{
2397 ssid->mcast_rate = (int)(strtod(value, NULL) * 10);
2398
2399 return 0;
2400}
2401
2402#ifndef NO_CONFIG_WRITE
2403static char * wpa_config_write_mcast_rate(const struct parse_data *data,
2404 struct wpa_ssid *ssid)
2405{
2406 char *value;
2407 int res;
2408
2409 if (!ssid->mcast_rate == 0)
2410 return NULL;
2411
2412 value = os_malloc(6); /* longest: 300.0 */
2413 if (value == NULL)
2414 return NULL;
2415 res = os_snprintf(value, 5, "%.1f", (double)ssid->mcast_rate / 10);
2416 if (res < 0) {
2417 os_free(value);
2418 return NULL;
2419 }
2420 return value;
2421}
2422#endif /* NO_CONFIG_WRITE */
2423
2424static int wpa_config_parse_rates(const struct parse_data *data,
2425 struct wpa_ssid *ssid, int line,
2426 const char *value)
2427{
2428 int i;
2429 char *pos, *r, *sptr, *end;
2430 double rate;
2431
2432 pos = (char *)value;
2433 r = strtok_r(pos, ",", &sptr);
2434 i = 0;
2435 while (pos && i < WLAN_SUPP_RATES_MAX) {
2436 rate = 0.0;
2437 if (r)
2438 rate = strtod(r, &end);
2439 ssid->rates[i] = rate * 2;
2440 if (*end != '\0' || rate * 2 != ssid->rates[i])
2441 return 1;
2442
2443 i++;
2444 r = strtok_r(NULL, ",", &sptr);
2445 }
2446
2447 return 0;
2448}
2449
2450#ifndef NO_CONFIG_WRITE
2451static char * wpa_config_write_rates(const struct parse_data *data,
2452 struct wpa_ssid *ssid)
2453{
2454 char *value, *pos;
2455 int res, i;
2456
2457 if (ssid->rates[0] <= 0)
2458 return NULL;
2459
2460 value = os_malloc(6 * WLAN_SUPP_RATES_MAX + 1);
2461 if (value == NULL)
2462 return NULL;
2463 pos = value;
2464 for (i = 0; i < WLAN_SUPP_RATES_MAX - 1; i++) {
2465 res = os_snprintf(pos, 6, "%.1f,", (double)ssid->rates[i] / 2);
2466 if (res < 0) {
2467 os_free(value);
2468 return NULL;
2469 }
2470 pos += res;
2471 }
2472 res = os_snprintf(pos, 6, "%.1f",
2473 (double)ssid->rates[WLAN_SUPP_RATES_MAX - 1] / 2);
2474 if (res < 0) {
2475 os_free(value);
2476 return NULL;
2477 }
2478
2479 value[6 * WLAN_SUPP_RATES_MAX] = '\0';
2480 return value;
2481}
2482#endif /* NO_CONFIG_WRITE */
2483
2484/* Helper macros for network block parser */
2485
2486#ifdef OFFSET
2487#undef OFFSET
2488#endif /* OFFSET */
2489/* OFFSET: Get offset of a variable within the wpa_ssid structure */
2490#define OFFSET(v) ((void *) &((struct wpa_ssid *) 0)->v)
2491
2492/* STR: Define a string variable for an ASCII string; f = field name */
2493#ifdef NO_CONFIG_WRITE
2494#define _STR(f) #f, wpa_config_parse_str, OFFSET(f)
2495#define _STRe(f, m) #f, wpa_config_parse_str, OFFSET(eap.m)
2496#else /* NO_CONFIG_WRITE */
2497#define _STR(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(f)
2498#define _STRe(f, m) #f, wpa_config_parse_str, wpa_config_write_str, \
2499 OFFSET(eap.m)
2500#endif /* NO_CONFIG_WRITE */
2501#define STR(f) _STR(f), NULL, NULL, NULL, 0
2502#define STRe(f, m) _STRe(f, m), NULL, NULL, NULL, 0
2503#define STR_KEY(f) _STR(f), NULL, NULL, NULL, 1
2504#define STR_KEYe(f, m) _STRe(f, m), NULL, NULL, NULL, 1
2505
2506/* STR_LEN: Define a string variable with a separate variable for storing the
2507 * data length. Unlike STR(), this can be used to store arbitrary binary data
2508 * (i.e., even nul termination character). */
2509#define _STR_LEN(f) _STR(f), OFFSET(f ## _len)
2510#define _STR_LENe(f, m) _STRe(f, m), OFFSET(eap.m ## _len)
2511#define STR_LEN(f) _STR_LEN(f), NULL, NULL, 0
2512#define STR_LENe(f, m) _STR_LENe(f, m), NULL, NULL, 0
2513#define STR_LEN_KEY(f) _STR_LEN(f), NULL, NULL, 1
2514
2515/* STR_RANGE: Like STR_LEN(), but with minimum and maximum allowed length
2516 * explicitly specified. */
2517#define _STR_RANGE(f, min, max) _STR_LEN(f), (void *) (min), (void *) (max)
2518#define STR_RANGE(f, min, max) _STR_RANGE(f, min, max), 0
2519#define STR_RANGE_KEY(f, min, max) _STR_RANGE(f, min, max), 1
2520
2521#ifdef NO_CONFIG_WRITE
2522#define _INT(f) #f, wpa_config_parse_int, OFFSET(f), (void *) 0
2523#define _INTe(f, m) #f, wpa_config_parse_int, OFFSET(eap.m), (void *) 0
2524#else /* NO_CONFIG_WRITE */
2525#define _INT(f) #f, wpa_config_parse_int, wpa_config_write_int, \
2526 OFFSET(f), (void *) 0
2527#define _INTe(f, m) #f, wpa_config_parse_int, wpa_config_write_int, \
2528 OFFSET(eap.m), (void *) 0
2529#endif /* NO_CONFIG_WRITE */
2530
2531/* INT: Define an integer variable */
2532#define INT(f) _INT(f), NULL, NULL, 0
2533#define INTe(f, m) _INTe(f, m), NULL, NULL, 0
2534
2535/* INT_RANGE: Define an integer variable with allowed value range */
2536#define INT_RANGE(f, min, max) _INT(f), (void *) (min), (void *) (max), 0
2537
2538/* FUNC: Define a configuration variable that uses a custom function for
2539 * parsing and writing the value. */
2540#ifdef NO_CONFIG_WRITE
2541#define _FUNC(f) #f, wpa_config_parse_ ## f, NULL, NULL, NULL, NULL
2542#else /* NO_CONFIG_WRITE */
2543#define _FUNC(f) #f, wpa_config_parse_ ## f, wpa_config_write_ ## f, \
2544 NULL, NULL, NULL, NULL
2545#endif /* NO_CONFIG_WRITE */
2546#define FUNC(f) _FUNC(f), 0
2547#define FUNC_KEY(f) _FUNC(f), 1
2548
2549/*
2550 * Table of network configuration variables. This table is used to parse each
2551 * network configuration variable, e.g., each line in wpa_supplicant.conf file
2552 * that is inside a network block.
2553 *
2554 * This table is generated using the helper macros defined above and with
2555 * generous help from the C pre-processor. The field name is stored as a string
2556 * into .name and for STR and INT types, the offset of the target buffer within
2557 * struct wpa_ssid is stored in .param1. .param2 (if not NULL) is similar
2558 * offset to the field containing the length of the configuration variable.
2559 * .param3 and .param4 can be used to mark the allowed range (length for STR
2560 * and value for INT).
2561 *
2562 * For each configuration line in wpa_supplicant.conf, the parser goes through
2563 * this table and select the entry that matches with the field name. The parser
2564 * function (.parser) is then called to parse the actual value of the field.
2565 *
2566 * This kind of mechanism makes it easy to add new configuration parameters,
2567 * since only one line needs to be added into this table and into the
2568 * struct wpa_ssid definition if the new variable is either a string or
2569 * integer. More complex types will need to use their own parser and writer
2570 * functions.
2571 */
2572static const struct parse_data ssid_fields[] = {
2573 { STR_RANGE(ssid, 0, SSID_MAX_LEN) },
2574 { INT_RANGE(scan_ssid, 0, 1) },
2575 { FUNC(bssid) },
2576 { FUNC(bssid_hint) },
2577 { FUNC(bssid_ignore) },
2578 { FUNC(bssid_accept) },
2579 { FUNC(bssid_blacklist) }, /* deprecated alias for bssid_ignore */
2580 { FUNC(bssid_whitelist) }, /* deprecated alias for bssid_accept */
2581 { FUNC_KEY(psk) },
2582 { INT(mem_only_psk) },
2583 { STR_KEY(sae_password) },
2584 { STR(sae_password_id) },
2585 { FUNC(proto) },
2586 { FUNC(key_mgmt) },
2587 { INT(bg_scan_period) },
2588 { FUNC(pairwise) },
2589 { FUNC(group) },
2590 { FUNC(group_mgmt) },
2591 { FUNC(auth_alg) },
2592 { FUNC(scan_freq) },
2593 { FUNC(freq_list) },
2594 { INT_RANGE(ht, 0, 1) },
2595 { INT_RANGE(vht, 0, 1) },
2596 { INT_RANGE(he, 0, 1) },
2597 { INT_RANGE(ht40, -1, 1) },
2598 { INT_RANGE(max_oper_chwidth, CONF_OPER_CHWIDTH_USE_HT,
2599 CONF_OPER_CHWIDTH_80P80MHZ) },
2600 { INT(vht_center_freq1) },
2601 { INT(vht_center_freq2) },
2602#ifdef IEEE8021X_EAPOL
2603 { FUNC(eap) },
2604 { STR_LENe(identity, identity) },
2605 { STR_LENe(anonymous_identity, anonymous_identity) },
2606 { STR_LENe(imsi_identity, imsi_identity) },
2607 { STR_LENe(machine_identity, machine_identity) },
2608 { FUNC_KEY(password) },
2609 { FUNC_KEY(machine_password) },
2610 { STRe(ca_cert, cert.ca_cert) },
2611 { STRe(ca_path, cert.ca_path) },
2612 { STRe(client_cert, cert.client_cert) },
2613 { STRe(private_key, cert.private_key) },
2614 { STR_KEYe(private_key_passwd, cert.private_key_passwd) },
2615 { STRe(subject_match, cert.subject_match) },
2616 { STRe(check_cert_subject, cert.check_cert_subject) },
2617 { STRe(altsubject_match, cert.altsubject_match) },
2618 { STRe(domain_suffix_match, cert.domain_suffix_match) },
2619 { STRe(domain_match, cert.domain_match) },
2620 { STRe(ca_cert2, phase2_cert.ca_cert) },
2621 { STRe(ca_path2, phase2_cert.ca_path) },
2622 { STRe(client_cert2, phase2_cert.client_cert) },
2623 { STRe(private_key2, phase2_cert.private_key) },
2624 { STR_KEYe(private_key2_passwd, phase2_cert.private_key_passwd) },
2625 { STRe(subject_match2, phase2_cert.subject_match) },
2626 { STRe(check_cert_subject2, phase2_cert.check_cert_subject) },
2627 { STRe(altsubject_match2, phase2_cert.altsubject_match) },
2628 { STRe(domain_suffix_match2, phase2_cert.domain_suffix_match) },
2629 { STRe(domain_match2, phase2_cert.domain_match) },
2630 { STRe(phase1, phase1) },
2631 { STRe(phase2, phase2) },
2632 { STRe(machine_phase2, machine_phase2) },
2633 { STRe(pcsc, pcsc) },
2634 { STR_KEYe(pin, cert.pin) },
2635 { STRe(engine_id, cert.engine_id) },
2636 { STRe(key_id, cert.key_id) },
2637 { STRe(cert_id, cert.cert_id) },
2638 { STRe(ca_cert_id, cert.ca_cert_id) },
2639 { STR_KEYe(pin2, phase2_cert.pin) },
2640 { STRe(engine_id2, phase2_cert.engine_id) },
2641 { STRe(key_id2, phase2_cert.key_id) },
2642 { STRe(cert_id2, phase2_cert.cert_id) },
2643 { STRe(ca_cert_id2, phase2_cert.ca_cert_id) },
2644 { INTe(engine, cert.engine) },
2645 { INTe(engine2, phase2_cert.engine) },
2646 { STRe(machine_ca_cert, machine_cert.ca_cert) },
2647 { STRe(machine_ca_path, machine_cert.ca_path) },
2648 { STRe(machine_client_cert, machine_cert.client_cert) },
2649 { STRe(machine_private_key, machine_cert.private_key) },
2650 { STR_KEYe(machine_private_key_passwd,
2651 machine_cert.private_key_passwd) },
2652 { STRe(machine_subject_match, machine_cert.subject_match) },
2653 { STRe(machine_check_cert_subject, machine_cert.check_cert_subject) },
2654 { STRe(machine_altsubject_match, machine_cert.altsubject_match) },
2655 { STRe(machine_domain_suffix_match,
2656 machine_cert.domain_suffix_match) },
2657 { STRe(machine_domain_match, machine_cert.domain_match) },
2658 { STR_KEYe(machine_pin, machine_cert.pin) },
2659 { STRe(machine_engine_id, machine_cert.engine_id) },
2660 { STRe(machine_key_id, machine_cert.key_id) },
2661 { STRe(machine_cert_id, machine_cert.cert_id) },
2662 { STRe(machine_ca_cert_id, machine_cert.ca_cert_id) },
2663 { INTe(machine_engine, machine_cert.engine) },
2664 { INTe(machine_ocsp, machine_cert.ocsp) },
2665 { INT(eapol_flags) },
2666 { INTe(sim_num, sim_num) },
2667 { STRe(imsi_privacy_cert, imsi_privacy_cert) },
2668 { STRe(imsi_privacy_attr, imsi_privacy_attr) },
2669 { STRe(openssl_ciphers, openssl_ciphers) },
2670 { INTe(erp, erp) },
2671#endif /* IEEE8021X_EAPOL */
2672#ifdef CONFIG_WEP
2673 { FUNC_KEY(wep_key0) },
2674 { FUNC_KEY(wep_key1) },
2675 { FUNC_KEY(wep_key2) },
2676 { FUNC_KEY(wep_key3) },
2677 { INT(wep_tx_keyidx) },
2678#endif /* CONFIG_WEP */
2679 { INT(priority) },
2680#ifdef IEEE8021X_EAPOL
2681 { INT(eap_workaround) },
2682 { STRe(pac_file, pac_file) },
2683 { INTe(fragment_size, fragment_size) },
2684 { INTe(ocsp, cert.ocsp) },
2685 { INTe(ocsp2, phase2_cert.ocsp) },
2686#endif /* IEEE8021X_EAPOL */
2687#ifdef CONFIG_MESH
2688 { INT_RANGE(mode, 0, 5) },
2689 { INT_RANGE(no_auto_peer, 0, 1) },
2690 { INT_RANGE(mesh_fwding, 0, 1) },
2691 { INT_RANGE(mesh_rssi_threshold, -255, 1) },
2692#else /* CONFIG_MESH */
2693 { INT_RANGE(mode, 0, 4) },
2694#endif /* CONFIG_MESH */
2695 { INT_RANGE(noscan, 0, 1) },
2696 { INT_RANGE(proactive_key_caching, 0, 1) },
2697 { INT_RANGE(disabled, 0, 2) },
2698 { STR(id_str) },
2699 { INT_RANGE(ieee80211w, 0, 2) },
2700#ifdef CONFIG_OCV
2701 { FUNC(ocv) },
2702#endif /* CONFIG_OCV */
2703 { FUNC(peerkey) /* obsolete - removed */ },
2704 { INT_RANGE(mixed_cell, 0, 1) },
2705 { INT_RANGE(frequency, 0, 70200) },
2706 { INT_RANGE(fixed_freq, 0, 1) },
2707 { INT_RANGE(enable_edmg, 0, 1) },
2708 { INT_RANGE(edmg_channel, 9, 13) },
2709#ifdef CONFIG_ACS
2710 { INT_RANGE(acs, 0, 1) },
2711#endif /* CONFIG_ACS */
2712#ifdef CONFIG_MESH
2713 { FUNC(mesh_basic_rates) },
2714 { INT(dot11MeshMaxRetries) },
2715 { INT(dot11MeshRetryTimeout) },
2716 { INT(dot11MeshConfirmTimeout) },
2717 { INT(dot11MeshHoldingTimeout) },
2718#endif /* CONFIG_MESH */
2719 { INT(wpa_ptk_rekey) },
2720 { INT_RANGE(wpa_deny_ptk0_rekey, 0, 2) },
2721 { INT(group_rekey) },
2722 { STR(bgscan) },
2723 { INT_RANGE(ignore_broadcast_ssid, 0, 2) },
2724#ifdef CONFIG_P2P
2725 { FUNC(go_p2p_dev_addr) },
2726 { FUNC(p2p_client_list) },
2727 { FUNC(psk_list) },
2728#endif /* CONFIG_P2P */
2729#ifdef CONFIG_HT_OVERRIDES
2730 { INT_RANGE(disable_ht, 0, 1) },
2731 { INT_RANGE(disable_ht40, -1, 1) },
2732 { INT_RANGE(disable_sgi, 0, 1) },
2733 { INT_RANGE(disable_ldpc, 0, 1) },
2734 { INT_RANGE(ht40_intolerant, 0, 1) },
2735 { INT_RANGE(tx_stbc, -1, 1) },
2736 { INT_RANGE(rx_stbc, -1, 3) },
2737 { INT_RANGE(disable_max_amsdu, -1, 1) },
2738 { INT_RANGE(ampdu_factor, -1, 3) },
2739 { INT_RANGE(ampdu_density, -1, 7) },
2740 { STR(ht_mcs) },
2741#endif /* CONFIG_HT_OVERRIDES */
2742#ifdef CONFIG_VHT_OVERRIDES
2743 { INT_RANGE(disable_vht, 0, 1) },
2744 { INT(vht_capa) },
2745 { INT(vht_capa_mask) },
2746 { INT_RANGE(vht_rx_mcs_nss_1, -1, 3) },
2747 { INT_RANGE(vht_rx_mcs_nss_2, -1, 3) },
2748 { INT_RANGE(vht_rx_mcs_nss_3, -1, 3) },
2749 { INT_RANGE(vht_rx_mcs_nss_4, -1, 3) },
2750 { INT_RANGE(vht_rx_mcs_nss_5, -1, 3) },
2751 { INT_RANGE(vht_rx_mcs_nss_6, -1, 3) },
2752 { INT_RANGE(vht_rx_mcs_nss_7, -1, 3) },
2753 { INT_RANGE(vht_rx_mcs_nss_8, -1, 3) },
2754 { INT_RANGE(vht_tx_mcs_nss_1, -1, 3) },
2755 { INT_RANGE(vht_tx_mcs_nss_2, -1, 3) },
2756 { INT_RANGE(vht_tx_mcs_nss_3, -1, 3) },
2757 { INT_RANGE(vht_tx_mcs_nss_4, -1, 3) },
2758 { INT_RANGE(vht_tx_mcs_nss_5, -1, 3) },
2759 { INT_RANGE(vht_tx_mcs_nss_6, -1, 3) },
2760 { INT_RANGE(vht_tx_mcs_nss_7, -1, 3) },
2761 { INT_RANGE(vht_tx_mcs_nss_8, -1, 3) },
2762#endif /* CONFIG_VHT_OVERRIDES */
2763#ifdef CONFIG_HE_OVERRIDES
2764 { INT_RANGE(disable_he, 0, 1)},
2765#endif /* CONFIG_HE_OVERRIDES */
2766 { INT(ap_max_inactivity) },
2767 { INT(dtim_period) },
2768 { INT(beacon_int) },
2769 { FUNC(rates) },
2770 { FUNC(mcast_rate) },
2771#ifdef CONFIG_MACSEC
2772 { INT_RANGE(macsec_policy, 0, 1) },
2773 { INT_RANGE(macsec_integ_only, 0, 1) },
2774 { INT_RANGE(macsec_replay_protect, 0, 1) },
2775 { INT(macsec_replay_window) },
2776 { INT_RANGE(macsec_offload, 0, 2) },
2777 { INT_RANGE(macsec_port, 1, 65534) },
2778 { INT_RANGE(mka_priority, 0, 255) },
2779 { INT_RANGE(macsec_csindex, 0, 1) },
2780 { FUNC_KEY(mka_cak) },
2781 { FUNC_KEY(mka_ckn) },
2782#endif /* CONFIG_MACSEC */
2783#ifdef CONFIG_HS20
2784 { INT(update_identifier) },
2785 { STR_RANGE(roaming_consortium_selection, 0, MAX_ROAMING_CONS_OI_LEN) },
2786#endif /* CONFIG_HS20 */
2787 { INT_RANGE(mac_addr, 0, 3) },
2788 { FUNC_KEY(mac_value) },
2789 { INT_RANGE(pbss, 0, 2) },
2790 { INT_RANGE(wps_disabled, 0, 1) },
2791 { INT_RANGE(fils_dh_group, 0, 65535) },
2792#ifdef CONFIG_DPP
2793 { STR(dpp_connector) },
2794 { STR_LEN(dpp_netaccesskey) },
2795 { INT(dpp_netaccesskey_expiry) },
2796 { STR_LEN(dpp_csign) },
2797 { STR_LEN(dpp_pp_key) },
2798 { INT_RANGE(dpp_pfs, 0, 2) },
2799 { INT_RANGE(dpp_connector_privacy, 0, 1) },
2800#endif /* CONFIG_DPP */
2801 { INT_RANGE(owe_group, 0, 65535) },
2802 { INT_RANGE(owe_only, 0, 1) },
2803 { INT_RANGE(owe_ptk_workaround, 0, 1) },
2804 { INT_RANGE(multi_ap_backhaul_sta, 0, 1) },
2805 { INT_RANGE(ft_eap_pmksa_caching, 0, 1) },
2806 { INT_RANGE(beacon_prot, 0, 1) },
2807 { INT_RANGE(transition_disable, 0, 255) },
2808 { INT_RANGE(sae_pk, 0, 2) },
2809 { INT_RANGE(disable_eht, 0, 1)},
2810 { INT_RANGE(enable_4addr_mode, 0, 1)},
2811};
2812
2813#undef OFFSET
2814#undef _STR
2815#undef STR
2816#undef STR_KEY
2817#undef _STR_LEN
2818#undef STR_LEN
2819#undef STR_LEN_KEY
2820#undef _STR_RANGE
2821#undef STR_RANGE
2822#undef STR_RANGE_KEY
2823#undef _INT
2824#undef INT
2825#undef INT_RANGE
2826#undef _FUNC
2827#undef FUNC
2828#undef FUNC_KEY
2829#define NUM_SSID_FIELDS ARRAY_SIZE(ssid_fields)
2830
2831
2832/**
2833 * wpa_config_add_prio_network - Add a network to priority lists
2834 * @config: Configuration data from wpa_config_read()
2835 * @ssid: Pointer to the network configuration to be added to the list
2836 * Returns: 0 on success, -1 on failure
2837 *
2838 * This function is used to add a network block to the priority list of
2839 * networks. This must be called for each network when reading in the full
2840 * configuration. In addition, this can be used indirectly when updating
2841 * priorities by calling wpa_config_update_prio_list().
2842 */
2843int wpa_config_add_prio_network(struct wpa_config *config,
2844 struct wpa_ssid *ssid)
2845{
2846 size_t prio;
2847 struct wpa_ssid *prev, **nlist;
2848
2849 /*
2850 * Add to an existing priority list if one is available for the
2851 * configured priority level for this network.
2852 */
2853 for (prio = 0; prio < config->num_prio; prio++) {
2854 prev = config->pssid[prio];
2855 if (prev->priority == ssid->priority) {
2856 while (prev->pnext)
2857 prev = prev->pnext;
2858 prev->pnext = ssid;
2859 return 0;
2860 }
2861 }
2862
2863 /* First network for this priority - add a new priority list */
2864 nlist = os_realloc_array(config->pssid, config->num_prio + 1,
2865 sizeof(struct wpa_ssid *));
2866 if (nlist == NULL)
2867 return -1;
2868
2869 for (prio = 0; prio < config->num_prio; prio++) {
2870 if (nlist[prio]->priority < ssid->priority) {
2871 os_memmove(&nlist[prio + 1], &nlist[prio],
2872 (config->num_prio - prio) *
2873 sizeof(struct wpa_ssid *));
2874 break;
2875 }
2876 }
2877
2878 nlist[prio] = ssid;
2879 config->num_prio++;
2880 config->pssid = nlist;
2881
2882 return 0;
2883}
2884
2885
2886/**
2887 * wpa_config_update_prio_list - Update network priority list
2888 * @config: Configuration data from wpa_config_read()
2889 * Returns: 0 on success, -1 on failure
2890 *
2891 * This function is called to update the priority list of networks in the
2892 * configuration when a network is being added or removed. This is also called
2893 * if a priority for a network is changed.
2894 */
2895int wpa_config_update_prio_list(struct wpa_config *config)
2896{
2897 struct wpa_ssid *ssid;
2898 int ret = 0;
2899
2900 os_free(config->pssid);
2901 config->pssid = NULL;
2902 config->num_prio = 0;
2903
2904 ssid = config->ssid;
2905 while (ssid) {
2906 ssid->pnext = NULL;
2907 if (wpa_config_add_prio_network(config, ssid) < 0)
2908 ret = -1;
2909 ssid = ssid->next;
2910 }
2911
2912 return ret;
2913}
2914
2915
2916#ifdef IEEE8021X_EAPOL
2917
2918static void eap_peer_config_free_cert(struct eap_peer_cert_config *cert)
2919{
2920 os_free(cert->ca_cert);
2921 os_free(cert->ca_path);
2922 os_free(cert->client_cert);
2923 os_free(cert->private_key);
2924 str_clear_free(cert->private_key_passwd);
2925 os_free(cert->subject_match);
2926 os_free(cert->check_cert_subject);
2927 os_free(cert->altsubject_match);
2928 os_free(cert->domain_suffix_match);
2929 os_free(cert->domain_match);
2930 str_clear_free(cert->pin);
2931 os_free(cert->engine_id);
2932 os_free(cert->key_id);
2933 os_free(cert->cert_id);
2934 os_free(cert->ca_cert_id);
2935}
2936
2937
2938static void eap_peer_config_free(struct eap_peer_config *eap)
2939{
2940 os_free(eap->eap_methods);
2941 bin_clear_free(eap->identity, eap->identity_len);
2942 os_free(eap->anonymous_identity);
2943 os_free(eap->imsi_identity);
2944 os_free(eap->imsi_privacy_cert);
2945 os_free(eap->imsi_privacy_attr);
2946 os_free(eap->machine_identity);
2947 bin_clear_free(eap->password, eap->password_len);
2948 bin_clear_free(eap->machine_password, eap->machine_password_len);
2949 eap_peer_config_free_cert(&eap->cert);
2950 eap_peer_config_free_cert(&eap->phase2_cert);
2951 eap_peer_config_free_cert(&eap->machine_cert);
2952 os_free(eap->phase1);
2953 os_free(eap->phase2);
2954 os_free(eap->machine_phase2);
2955 os_free(eap->pcsc);
2956 os_free(eap->otp);
2957 os_free(eap->pending_req_otp);
2958 os_free(eap->pac_file);
2959 bin_clear_free(eap->new_password, eap->new_password_len);
2960 str_clear_free(eap->external_sim_resp);
2961 os_free(eap->openssl_ciphers);
2962}
2963
2964#endif /* IEEE8021X_EAPOL */
2965
2966
2967/**
2968 * wpa_config_free_ssid - Free network/ssid configuration data
2969 * @ssid: Configuration data for the network
2970 *
2971 * This function frees all resources allocated for the network configuration
2972 * data.
2973 */
2974void wpa_config_free_ssid(struct wpa_ssid *ssid)
2975{
2976 struct psk_list_entry *psk;
2977
2978 os_free(ssid->ssid);
2979 str_clear_free(ssid->passphrase);
2980 os_free(ssid->ext_psk);
2981 str_clear_free(ssid->sae_password);
2982 os_free(ssid->sae_password_id);
2983#ifdef IEEE8021X_EAPOL
2984 eap_peer_config_free(&ssid->eap);
2985#endif /* IEEE8021X_EAPOL */
2986 os_free(ssid->id_str);
2987 os_free(ssid->scan_freq);
2988 os_free(ssid->freq_list);
2989 os_free(ssid->bgscan);
2990 os_free(ssid->p2p_client_list);
2991 os_free(ssid->bssid_ignore);
2992 os_free(ssid->bssid_accept);
2993#ifdef CONFIG_HT_OVERRIDES
2994 os_free(ssid->ht_mcs);
2995#endif /* CONFIG_HT_OVERRIDES */
2996#ifdef CONFIG_MESH
2997 os_free(ssid->mesh_basic_rates);
2998#endif /* CONFIG_MESH */
2999#ifdef CONFIG_HS20
3000 os_free(ssid->roaming_consortium_selection);
3001#endif /* CONFIG_HS20 */
3002 os_free(ssid->dpp_connector);
3003 bin_clear_free(ssid->dpp_netaccesskey, ssid->dpp_netaccesskey_len);
3004 os_free(ssid->dpp_csign);
3005 os_free(ssid->dpp_pp_key);
3006 while ((psk = dl_list_first(&ssid->psk_list, struct psk_list_entry,
3007 list))) {
3008 dl_list_del(&psk->list);
3009 bin_clear_free(psk, sizeof(*psk));
3010 }
3011#ifdef CONFIG_SAE
3012 sae_deinit_pt(ssid->pt);
3013#endif /* CONFIG_SAE */
3014 bin_clear_free(ssid, sizeof(*ssid));
3015}
3016
3017
3018void wpa_config_free_cred(struct wpa_cred *cred)
3019{
3020 size_t i;
3021
3022 os_free(cred->realm);
3023 str_clear_free(cred->username);
3024 str_clear_free(cred->password);
3025 os_free(cred->ca_cert);
3026 os_free(cred->client_cert);
3027 os_free(cred->private_key);
3028 str_clear_free(cred->private_key_passwd);
3029 os_free(cred->engine_id);
3030 os_free(cred->ca_cert_id);
3031 os_free(cred->cert_id);
3032 os_free(cred->key_id);
3033 os_free(cred->imsi);
3034 str_clear_free(cred->milenage);
3035 for (i = 0; i < cred->num_domain; i++)
3036 os_free(cred->domain[i]);
3037 os_free(cred->domain);
3038 os_free(cred->domain_suffix_match);
3039 os_free(cred->eap_method);
3040 os_free(cred->phase1);
3041 os_free(cred->phase2);
3042 os_free(cred->excluded_ssid);
3043 os_free(cred->roaming_partner);
3044 os_free(cred->provisioning_sp);
3045 for (i = 0; i < cred->num_req_conn_capab; i++)
3046 os_free(cred->req_conn_capab_port[i]);
3047 os_free(cred->req_conn_capab_port);
3048 os_free(cred->req_conn_capab_proto);
3049 os_free(cred->imsi_privacy_cert);
3050 os_free(cred->imsi_privacy_attr);
3051 os_free(cred);
3052}
3053
3054
3055void wpa_config_flush_blobs(struct wpa_config *config)
3056{
3057#ifndef CONFIG_NO_CONFIG_BLOBS
3058 struct wpa_config_blob *blob, *prev;
3059
3060 blob = config->blobs;
3061 config->blobs = NULL;
3062 while (blob) {
3063 prev = blob;
3064 blob = blob->next;
3065 wpa_config_free_blob(prev);
3066 }
3067#endif /* CONFIG_NO_CONFIG_BLOBS */
3068}
3069
3070
3071/**
3072 * wpa_config_free - Free configuration data
3073 * @config: Configuration data from wpa_config_read()
3074 *
3075 * This function frees all resources allocated for the configuration data by
3076 * wpa_config_read().
3077 */
3078void wpa_config_free(struct wpa_config *config)
3079{
3080 struct wpa_ssid *ssid, *prev = NULL;
3081 struct wpa_cred *cred, *cprev;
3082 int i;
3083
3084 ssid = config->ssid;
3085 while (ssid) {
3086 prev = ssid;
3087 ssid = ssid->next;
3088 wpa_config_free_ssid(prev);
3089 }
3090
3091 cred = config->cred;
3092 while (cred) {
3093 cprev = cred;
3094 cred = cred->next;
3095 wpa_config_free_cred(cprev);
3096 }
3097
3098 wpa_config_flush_blobs(config);
3099
3100 wpabuf_free(config->wps_vendor_ext_m1);
3101 for (i = 0; i < MAX_WPS_VENDOR_EXT; i++)
3102 wpabuf_free(config->wps_vendor_ext[i]);
3103 os_free(config->ctrl_interface);
3104 os_free(config->ctrl_interface_group);
3105 os_free(config->opensc_engine_path);
3106 os_free(config->pkcs11_engine_path);
3107 os_free(config->pkcs11_module_path);
3108 os_free(config->openssl_ciphers);
3109 os_free(config->pcsc_reader);
3110 str_clear_free(config->pcsc_pin);
3111 os_free(config->driver_param);
3112 os_free(config->device_name);
3113 os_free(config->manufacturer);
3114 os_free(config->model_name);
3115 os_free(config->model_number);
3116 os_free(config->serial_number);
3117 os_free(config->config_methods);
3118 os_free(config->p2p_ssid_postfix);
3119 os_free(config->pssid);
3120 os_free(config->p2p_pref_chan);
3121 os_free(config->p2p_no_go_freq.range);
3122 os_free(config->autoscan);
3123 os_free(config->freq_list);
3124 os_free(config->initial_freq_list);
3125 wpabuf_free(config->wps_nfc_dh_pubkey);
3126 wpabuf_free(config->wps_nfc_dh_privkey);
3127 wpabuf_free(config->wps_nfc_dev_pw);
3128 os_free(config->ext_password_backend);
3129 os_free(config->sae_groups);
3130 wpabuf_free(config->ap_vendor_elements);
3131 wpabuf_free(config->ap_assocresp_elements);
3132 os_free(config->osu_dir);
3133 os_free(config->bgscan);
3134 os_free(config->wowlan_triggers);
3135 os_free(config->fst_group_id);
3136 os_free(config->sched_scan_plans);
3137#ifdef CONFIG_MBO
3138 os_free(config->non_pref_chan);
3139#endif /* CONFIG_MBO */
3140 os_free(config->dpp_name);
3141 os_free(config->dpp_mud_url);
3142 os_free(config->dpp_extra_conf_req_name);
3143 os_free(config->dpp_extra_conf_req_value);
3144
3145 os_free(config);
3146}
3147
3148
3149/**
3150 * wpa_config_foreach_network - Iterate over each configured network
3151 * @config: Configuration data from wpa_config_read()
3152 * @func: Callback function to process each network
3153 * @arg: Opaque argument to pass to callback function
3154 *
3155 * Iterate over the set of configured networks calling the specified
3156 * function for each item. We guard against callbacks removing the
3157 * supplied network.
3158 */
3159void wpa_config_foreach_network(struct wpa_config *config,
3160 void (*func)(void *, struct wpa_ssid *),
3161 void *arg)
3162{
3163 struct wpa_ssid *ssid, *next;
3164
3165 ssid = config->ssid;
3166 while (ssid) {
3167 next = ssid->next;
3168 func(arg, ssid);
3169 ssid = next;
3170 }
3171}
3172
3173
3174/**
3175 * wpa_config_get_network - Get configured network based on id
3176 * @config: Configuration data from wpa_config_read()
3177 * @id: Unique network id to search for
3178 * Returns: Network configuration or %NULL if not found
3179 */
3180struct wpa_ssid * wpa_config_get_network(struct wpa_config *config, int id)
3181{
3182 struct wpa_ssid *ssid;
3183
3184 ssid = config->ssid;
3185 while (ssid) {
3186 if (id == ssid->id)
3187 break;
3188 ssid = ssid->next;
3189 }
3190
3191 return ssid;
3192}
3193
3194
3195/**
3196 * wpa_config_add_network - Add a new network with empty configuration
3197 * @config: Configuration data from wpa_config_read()
3198 * Returns: The new network configuration or %NULL if operation failed
3199 */
3200struct wpa_ssid * wpa_config_add_network(struct wpa_config *config)
3201{
3202 int id;
3203 struct wpa_ssid *ssid, *last = NULL;
3204
3205 id = -1;
3206 ssid = config->ssid;
3207 while (ssid) {
3208 if (ssid->id > id)
3209 id = ssid->id;
3210 last = ssid;
3211 ssid = ssid->next;
3212 }
3213 id++;
3214
3215 ssid = os_zalloc(sizeof(*ssid));
3216 if (ssid == NULL)
3217 return NULL;
3218 ssid->id = id;
3219 dl_list_init(&ssid->psk_list);
3220 if (last)
3221 last->next = ssid;
3222 else
3223 config->ssid = ssid;
3224
3225 wpa_config_update_prio_list(config);
3226
3227 return ssid;
3228}
3229
3230
3231/**
3232 * wpa_config_remove_network - Remove a configured network based on id
3233 * @config: Configuration data from wpa_config_read()
3234 * @id: Unique network id to search for
3235 * Returns: 0 on success, or -1 if the network was not found
3236 */
3237int wpa_config_remove_network(struct wpa_config *config, int id)
3238{
3239 struct wpa_ssid *ssid, *prev = NULL;
3240
3241 ssid = config->ssid;
3242 while (ssid) {
3243 if (id == ssid->id)
3244 break;
3245 prev = ssid;
3246 ssid = ssid->next;
3247 }
3248
3249 if (ssid == NULL)
3250 return -1;
3251
3252 if (prev)
3253 prev->next = ssid->next;
3254 else
3255 config->ssid = ssid->next;
3256
3257 wpa_config_update_prio_list(config);
3258 wpa_config_free_ssid(ssid);
3259 return 0;
3260}
3261
3262
3263/**
3264 * wpa_config_set_network_defaults - Set network default values
3265 * @ssid: Pointer to network configuration data
3266 */
3267void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
3268{
3269 ssid->proto = DEFAULT_PROTO;
3270 ssid->pairwise_cipher = DEFAULT_PAIRWISE;
3271 ssid->group_cipher = DEFAULT_GROUP;
3272 ssid->key_mgmt = DEFAULT_KEY_MGMT;
3273 ssid->wpa_deny_ptk0_rekey = PTK0_REKEY_ALLOW_ALWAYS;
3274 ssid->bg_scan_period = DEFAULT_BG_SCAN_PERIOD;
3275 ssid->ht = 1;
3276 ssid->vht = 1;
3277 ssid->he = 1;
3278#ifdef IEEE8021X_EAPOL
3279 ssid->eapol_flags = DEFAULT_EAPOL_FLAGS;
3280 ssid->eap_workaround = DEFAULT_EAP_WORKAROUND;
3281 ssid->eap.fragment_size = DEFAULT_FRAGMENT_SIZE;
3282 ssid->eap.sim_num = DEFAULT_USER_SELECTED_SIM;
3283#endif /* IEEE8021X_EAPOL */
3284#ifdef CONFIG_MESH
3285 ssid->dot11MeshMaxRetries = DEFAULT_MESH_MAX_RETRIES;
3286 ssid->dot11MeshRetryTimeout = DEFAULT_MESH_RETRY_TIMEOUT;
3287 ssid->dot11MeshConfirmTimeout = DEFAULT_MESH_CONFIRM_TIMEOUT;
3288 ssid->dot11MeshHoldingTimeout = DEFAULT_MESH_HOLDING_TIMEOUT;
3289 ssid->mesh_fwding = DEFAULT_MESH_FWDING;
3290 ssid->mesh_rssi_threshold = DEFAULT_MESH_RSSI_THRESHOLD;
3291#endif /* CONFIG_MESH */
3292#ifdef CONFIG_HT_OVERRIDES
3293 ssid->disable_ht = DEFAULT_DISABLE_HT;
3294 ssid->disable_ht40 = DEFAULT_DISABLE_HT40;
3295 ssid->disable_sgi = DEFAULT_DISABLE_SGI;
3296 ssid->disable_ldpc = DEFAULT_DISABLE_LDPC;
3297 ssid->tx_stbc = DEFAULT_TX_STBC;
3298 ssid->rx_stbc = DEFAULT_RX_STBC;
3299 ssid->disable_max_amsdu = DEFAULT_DISABLE_MAX_AMSDU;
3300 ssid->ampdu_factor = DEFAULT_AMPDU_FACTOR;
3301 ssid->ampdu_density = DEFAULT_AMPDU_DENSITY;
3302#endif /* CONFIG_HT_OVERRIDES */
3303#ifdef CONFIG_VHT_OVERRIDES
3304 ssid->vht_rx_mcs_nss_1 = -1;
3305 ssid->vht_rx_mcs_nss_2 = -1;
3306 ssid->vht_rx_mcs_nss_3 = -1;
3307 ssid->vht_rx_mcs_nss_4 = -1;
3308 ssid->vht_rx_mcs_nss_5 = -1;
3309 ssid->vht_rx_mcs_nss_6 = -1;
3310 ssid->vht_rx_mcs_nss_7 = -1;
3311 ssid->vht_rx_mcs_nss_8 = -1;
3312 ssid->vht_tx_mcs_nss_1 = -1;
3313 ssid->vht_tx_mcs_nss_2 = -1;
3314 ssid->vht_tx_mcs_nss_3 = -1;
3315 ssid->vht_tx_mcs_nss_4 = -1;
3316 ssid->vht_tx_mcs_nss_5 = -1;
3317 ssid->vht_tx_mcs_nss_6 = -1;
3318 ssid->vht_tx_mcs_nss_7 = -1;
3319 ssid->vht_tx_mcs_nss_8 = -1;
3320#endif /* CONFIG_VHT_OVERRIDES */
3321 ssid->proactive_key_caching = -1;
3322 ssid->ieee80211w = MGMT_FRAME_PROTECTION_DEFAULT;
3323 ssid->sae_pwe = DEFAULT_SAE_PWE;
3324#ifdef CONFIG_MACSEC
3325 ssid->mka_priority = DEFAULT_PRIO_NOT_KEY_SERVER;
3326#endif /* CONFIG_MACSEC */
3327 ssid->mac_addr = WPAS_MAC_ADDR_STYLE_NOT_SET;
3328 ssid->max_oper_chwidth = DEFAULT_MAX_OPER_CHWIDTH;
3329}
3330
3331
3332static const char *removed_fields[] = {
3333 "dh_file",
3334 "dh_file2",
3335 "machine_dh_file",
3336 NULL
3337};
3338
3339static bool removed_field(const char *field)
3340{
3341 int i;
3342
3343 for (i = 0; removed_fields[i]; i++) {
3344 if (os_strcmp(field, removed_fields[i]) == 0)
3345 return true;
3346 }
3347
3348 return false;
3349}
3350
3351
3352/**
3353 * wpa_config_set - Set a variable in network configuration
3354 * @ssid: Pointer to network configuration data
3355 * @var: Variable name, e.g., "ssid"
3356 * @value: Variable value
3357 * @line: Line number in configuration file or 0 if not used
3358 * Returns: 0 on success with possible change in the value, 1 on success with
3359 * no change to previously configured value, or -1 on failure
3360 *
3361 * This function can be used to set network configuration variables based on
3362 * both the configuration file and management interface input. The value
3363 * parameter must be in the same format as the text-based configuration file is
3364 * using. For example, strings are using double quotation marks.
3365 */
3366int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
3367 int line)
3368{
3369 size_t i;
3370 int ret = 0;
3371
3372 if (ssid == NULL || var == NULL || value == NULL)
3373 return -1;
3374
3375 for (i = 0; i < NUM_SSID_FIELDS; i++) {
3376 const struct parse_data *field = &ssid_fields[i];
3377 if (os_strcmp(var, field->name) != 0)
3378 continue;
3379
3380 ret = field->parser(field, ssid, line, value);
3381 if (ret < 0) {
3382 if (line) {
3383 wpa_printf(MSG_ERROR, "Line %d: failed to "
3384 "parse %s '%s'.", line, var, value);
3385 }
3386 ret = -1;
3387 }
3388#ifdef CONFIG_SAE
3389 if (os_strcmp(var, "ssid") == 0 ||
3390 os_strcmp(var, "psk") == 0 ||
3391 os_strcmp(var, "sae_password") == 0 ||
3392 os_strcmp(var, "sae_password_id") == 0) {
3393 sae_deinit_pt(ssid->pt);
3394 ssid->pt = NULL;
3395 }
3396#endif /* CONFIG_SAE */
3397 break;
3398 }
3399 if (i == NUM_SSID_FIELDS) {
3400 if (removed_field(var)) {
3401 wpa_printf(MSG_INFO,
3402 "Line %d: Ignore removed configuration field '%s'",
3403 line, var);
3404 return ret;
3405 }
3406 if (line) {
3407 wpa_printf(MSG_ERROR, "Line %d: unknown network field "
3408 "'%s'.", line, var);
3409 }
3410 ret = -1;
3411 }
3412 ssid->was_recently_reconfigured = true;
3413
3414 return ret;
3415}
3416
3417
3418int wpa_config_set_quoted(struct wpa_ssid *ssid, const char *var,
3419 const char *value)
3420{
3421 size_t len;
3422 char *buf;
3423 int ret;
3424
3425 len = os_strlen(value);
3426 buf = os_malloc(len + 3);
3427 if (buf == NULL)
3428 return -1;
3429 buf[0] = '"';
3430 os_memcpy(buf + 1, value, len);
3431 buf[len + 1] = '"';
3432 buf[len + 2] = '\0';
3433 ret = wpa_config_set(ssid, var, buf, 0);
3434 os_free(buf);
3435 return ret;
3436}
3437
3438
3439/**
3440 * wpa_config_get_all - Get all options from network configuration
3441 * @ssid: Pointer to network configuration data
3442 * @get_keys: Determines if keys/passwords will be included in returned list
3443 * (if they may be exported)
3444 * Returns: %NULL terminated list of all set keys and their values in the form
3445 * of [key1, val1, key2, val2, ... , NULL]
3446 *
3447 * This function can be used to get list of all configured network properties.
3448 * The caller is responsible for freeing the returned list and all its
3449 * elements.
3450 */
3451char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys)
3452{
3453#ifdef NO_CONFIG_WRITE
3454 return NULL;
3455#else /* NO_CONFIG_WRITE */
3456 const struct parse_data *field;
3457 char *key, *value;
3458 size_t i;
3459 char **props;
3460 int fields_num;
3461
3462 get_keys = get_keys && ssid->export_keys;
3463
3464 props = os_calloc(2 * NUM_SSID_FIELDS + 1, sizeof(char *));
3465 if (!props)
3466 return NULL;
3467
3468 fields_num = 0;
3469 for (i = 0; i < NUM_SSID_FIELDS; i++) {
3470 field = &ssid_fields[i];
3471 if (field->key_data && !get_keys)
3472 continue;
3473 value = field->writer(field, ssid);
3474 if (value == NULL)
3475 continue;
3476 if (os_strlen(value) == 0) {
3477 os_free(value);
3478 continue;
3479 }
3480
3481 key = os_strdup(field->name);
3482 if (key == NULL) {
3483 os_free(value);
3484 goto err;
3485 }
3486
3487 props[fields_num * 2] = key;
3488 props[fields_num * 2 + 1] = value;
3489
3490 fields_num++;
3491 }
3492
3493 return props;
3494
3495err:
3496 for (i = 0; props[i]; i++)
3497 os_free(props[i]);
3498 os_free(props);
3499 return NULL;
3500#endif /* NO_CONFIG_WRITE */
3501}
3502
3503
3504#ifndef NO_CONFIG_WRITE
3505/**
3506 * wpa_config_get - Get a variable in network configuration
3507 * @ssid: Pointer to network configuration data
3508 * @var: Variable name, e.g., "ssid"
3509 * Returns: Value of the variable or %NULL on failure
3510 *
3511 * This function can be used to get network configuration variables. The
3512 * returned value is a copy of the configuration variable in text format, i.e,.
3513 * the same format that the text-based configuration file and wpa_config_set()
3514 * are using for the value. The caller is responsible for freeing the returned
3515 * value.
3516 */
3517char * wpa_config_get(struct wpa_ssid *ssid, const char *var)
3518{
3519 size_t i;
3520
3521 if (ssid == NULL || var == NULL)
3522 return NULL;
3523
3524 for (i = 0; i < NUM_SSID_FIELDS; i++) {
3525 const struct parse_data *field = &ssid_fields[i];
3526 if (os_strcmp(var, field->name) == 0) {
3527 char *ret = field->writer(field, ssid);
3528
3529 if (ret && has_newline(ret)) {
3530 wpa_printf(MSG_ERROR,
3531 "Found newline in value for %s; not returning it",
3532 var);
3533 os_free(ret);
3534 ret = NULL;
3535 }
3536
3537 return ret;
3538 }
3539 }
3540
3541 return NULL;
3542}
3543
3544
3545/**
3546 * wpa_config_get_no_key - Get a variable in network configuration (no keys)
3547 * @ssid: Pointer to network configuration data
3548 * @var: Variable name, e.g., "ssid"
3549 * Returns: Value of the variable or %NULL on failure
3550 *
3551 * This function can be used to get network configuration variable like
3552 * wpa_config_get(). The only difference is that this functions does not expose
3553 * key/password material from the configuration. In case a key/password field
3554 * is requested, the returned value is an empty string or %NULL if the variable
3555 * is not set or "*" if the variable is set (regardless of its value). The
3556 * returned value is a copy of the configuration variable in text format, i.e,.
3557 * the same format that the text-based configuration file and wpa_config_set()
3558 * are using for the value. The caller is responsible for freeing the returned
3559 * value.
3560 */
3561char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var)
3562{
3563 size_t i;
3564
3565 if (ssid == NULL || var == NULL)
3566 return NULL;
3567
3568 for (i = 0; i < NUM_SSID_FIELDS; i++) {
3569 const struct parse_data *field = &ssid_fields[i];
3570 if (os_strcmp(var, field->name) == 0) {
3571 char *res = field->writer(field, ssid);
3572 if (field->key_data) {
3573 if (res && res[0]) {
3574 wpa_printf(MSG_DEBUG, "Do not allow "
3575 "key_data field to be "
3576 "exposed");
3577 str_clear_free(res);
3578 return os_strdup("*");
3579 }
3580
3581 os_free(res);
3582 return NULL;
3583 }
3584 return res;
3585 }
3586 }
3587
3588 return NULL;
3589}
3590#endif /* NO_CONFIG_WRITE */
3591
3592
3593/**
3594 * wpa_config_update_psk - Update WPA PSK based on passphrase and SSID
3595 * @ssid: Pointer to network configuration data
3596 *
3597 * This function must be called to update WPA PSK when either SSID or the
3598 * passphrase has changed for the network configuration.
3599 */
3600void wpa_config_update_psk(struct wpa_ssid *ssid)
3601{
3602#ifndef CONFIG_NO_PBKDF2
3603 if (pbkdf2_sha1(ssid->passphrase, ssid->ssid, ssid->ssid_len, 4096,
3604 ssid->psk, PMK_LEN) != 0) {
3605 wpa_printf(MSG_ERROR, "Error in pbkdf2_sha1()");
3606 return;
3607 }
3608 wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
3609 ssid->psk, PMK_LEN);
3610 ssid->psk_set = 1;
3611#endif /* CONFIG_NO_PBKDF2 */
3612}
3613
3614
3615static int wpa_config_set_cred_req_conn_capab(struct wpa_cred *cred,
3616 const char *value)
3617{
3618 u8 *proto;
3619 int **port;
3620 int *ports, *nports;
3621 const char *pos;
3622 unsigned int num_ports;
3623
3624 proto = os_realloc_array(cred->req_conn_capab_proto,
3625 cred->num_req_conn_capab + 1, sizeof(u8));
3626 if (proto == NULL)
3627 return -1;
3628 cred->req_conn_capab_proto = proto;
3629
3630 port = os_realloc_array(cred->req_conn_capab_port,
3631 cred->num_req_conn_capab + 1, sizeof(int *));
3632 if (port == NULL)
3633 return -1;
3634 cred->req_conn_capab_port = port;
3635
3636 proto[cred->num_req_conn_capab] = atoi(value);
3637
3638 pos = os_strchr(value, ':');
3639 if (pos == NULL) {
3640 port[cred->num_req_conn_capab] = NULL;
3641 cred->num_req_conn_capab++;
3642 return 0;
3643 }
3644 pos++;
3645
3646 ports = NULL;
3647 num_ports = 0;
3648
3649 while (*pos) {
3650 nports = os_realloc_array(ports, num_ports + 1, sizeof(int));
3651 if (nports == NULL) {
3652 os_free(ports);
3653 return -1;
3654 }
3655 ports = nports;
3656 ports[num_ports++] = atoi(pos);
3657
3658 pos = os_strchr(pos, ',');
3659 if (pos == NULL)
3660 break;
3661 pos++;
3662 }
3663
3664 nports = os_realloc_array(ports, num_ports + 1, sizeof(int));
3665 if (nports == NULL) {
3666 os_free(ports);
3667 return -1;
3668 }
3669 ports = nports;
3670 ports[num_ports] = -1;
3671
3672 port[cred->num_req_conn_capab] = ports;
3673 cred->num_req_conn_capab++;
3674 return 0;
3675}
3676
3677
3678static int
3679wpa_config_set_cred_ois(u8 cred_ois[MAX_ROAMING_CONS][MAX_ROAMING_CONS_OI_LEN],
3680 size_t cred_ois_len[MAX_ROAMING_CONS],
3681 unsigned int *cred_num_ois,
3682 const char *value)
3683{
3684 u8 ois[MAX_ROAMING_CONS][MAX_ROAMING_CONS_OI_LEN];
3685 size_t ois_len[MAX_ROAMING_CONS];
3686 unsigned int num_ois = 0;
3687 const char *pos, *end;
3688 size_t len;
3689
3690 len = os_strlen(value);
3691 if (len / 2 < 3) {
3692 wpa_printf(MSG_ERROR,
3693 "Invalid organisation identifier (OI) list: %s",
3694 value);
3695 return -1;
3696 }
3697
3698 os_memset(ois, 0, sizeof(ois));
3699 os_memset(ois_len, 0, sizeof(ois_len));
3700
3701 for (pos = value;;) {
3702 end = os_strchr(pos, ',');
3703 len = end ? (size_t) (end - pos) : os_strlen(pos);
3704 if (!end && len == 0)
3705 break;
3706 if (len / 2 < 3 || (len & 1) != 0 ||
3707 len / 2 > MAX_ROAMING_CONS_OI_LEN ||
3708 hexstr2bin(pos,
3709 ois[num_ois],
3710 len / 2) < 0) {
3711 wpa_printf(MSG_INFO,
3712 "Invalid organisation identifier (OI) entry: %s",
3713 pos);
3714 return -1;
3715 }
3716 ois_len[num_ois] = len / 2;
3717 num_ois++;
3718
3719 if (!end)
3720 break;
3721
3722 if (num_ois >= MAX_ROAMING_CONS) {
3723 wpa_printf(MSG_INFO,
3724 "Too many OIs");
3725 return -1;
3726 }
3727
3728 pos = end + 1;
3729 }
3730
3731 os_memcpy(cred_ois, ois, sizeof(ois));
3732 os_memcpy(cred_ois_len, ois_len, sizeof(ois_len));
3733 *cred_num_ois = num_ois;
3734
3735 return 0;
3736}
3737
3738
3739int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
3740 const char *value, int line)
3741{
3742 char *val;
3743 size_t len;
3744 int res;
3745
3746 if (os_strcmp(var, "temporary") == 0) {
3747 cred->temporary = atoi(value);
3748 return 0;
3749 }
3750
3751 if (os_strcmp(var, "priority") == 0) {
3752 cred->priority = atoi(value);
3753 return 0;
3754 }
3755
3756 if (os_strcmp(var, "sp_priority") == 0) {
3757 int prio = atoi(value);
3758 if (prio < 0 || prio > 255)
3759 return -1;
3760 cred->sp_priority = prio;
3761 return 0;
3762 }
3763
3764 if (os_strcmp(var, "pcsc") == 0) {
3765 cred->pcsc = atoi(value);
3766 return 0;
3767 }
3768
3769 if (os_strcmp(var, "eap") == 0) {
3770 struct eap_method_type method;
3771 method.method = eap_peer_get_type(value, &method.vendor);
3772 if (method.vendor == EAP_VENDOR_IETF &&
3773 method.method == EAP_TYPE_NONE) {
3774 wpa_printf(MSG_ERROR, "Line %d: unknown EAP type '%s' "
3775 "for a credential", line, value);
3776 return -1;
3777 }
3778 os_free(cred->eap_method);
3779 cred->eap_method = os_malloc(sizeof(*cred->eap_method));
3780 if (cred->eap_method == NULL)
3781 return -1;
3782 os_memcpy(cred->eap_method, &method, sizeof(method));
3783 return 0;
3784 }
3785
3786 if (os_strcmp(var, "password") == 0 &&
3787 os_strncmp(value, "ext:", 4) == 0) {
3788 if (has_newline(value))
3789 return -1;
3790 str_clear_free(cred->password);
3791 cred->password = os_strdup(value);
3792 cred->ext_password = 1;
3793 return 0;
3794 }
3795
3796 if (os_strcmp(var, "update_identifier") == 0) {
3797 cred->update_identifier = atoi(value);
3798 return 0;
3799 }
3800
3801 if (os_strcmp(var, "min_dl_bandwidth_home") == 0) {
3802 cred->min_dl_bandwidth_home = atoi(value);
3803 return 0;
3804 }
3805
3806 if (os_strcmp(var, "min_ul_bandwidth_home") == 0) {
3807 cred->min_ul_bandwidth_home = atoi(value);
3808 return 0;
3809 }
3810
3811 if (os_strcmp(var, "min_dl_bandwidth_roaming") == 0) {
3812 cred->min_dl_bandwidth_roaming = atoi(value);
3813 return 0;
3814 }
3815
3816 if (os_strcmp(var, "min_ul_bandwidth_roaming") == 0) {
3817 cred->min_ul_bandwidth_roaming = atoi(value);
3818 return 0;
3819 }
3820
3821 if (os_strcmp(var, "max_bss_load") == 0) {
3822 cred->max_bss_load = atoi(value);
3823 return 0;
3824 }
3825
3826 if (os_strcmp(var, "req_conn_capab") == 0)
3827 return wpa_config_set_cred_req_conn_capab(cred, value);
3828
3829 if (os_strcmp(var, "ocsp") == 0) {
3830 cred->ocsp = atoi(value);
3831 return 0;
3832 }
3833
3834 if (os_strcmp(var, "sim_num") == 0) {
3835 cred->sim_num = atoi(value);
3836 return 0;
3837 }
3838
3839 if (os_strcmp(var, "engine") == 0) {
3840 cred->engine = atoi(value);
3841 return 0;
3842 }
3843
3844 val = wpa_config_parse_string(value, &len);
3845 if (val == NULL ||
3846 (os_strcmp(var, "excluded_ssid") != 0 &&
3847 os_strcmp(var, "roaming_consortium") != 0 &&
3848 os_strcmp(var, "required_roaming_consortium") != 0 &&
3849 has_newline(val))) {
3850 wpa_printf(MSG_ERROR, "Line %d: invalid field '%s' string "
3851 "value '%s'.", line, var, value);
3852 os_free(val);
3853 return -1;
3854 }
3855
3856 if (os_strcmp(var, "realm") == 0) {
3857 os_free(cred->realm);
3858 cred->realm = val;
3859 return 0;
3860 }
3861
3862 if (os_strcmp(var, "username") == 0) {
3863 str_clear_free(cred->username);
3864 cred->username = val;
3865 return 0;
3866 }
3867
3868 if (os_strcmp(var, "password") == 0) {
3869 str_clear_free(cred->password);
3870 cred->password = val;
3871 cred->ext_password = 0;
3872 return 0;
3873 }
3874
3875 if (os_strcmp(var, "ca_cert") == 0) {
3876 os_free(cred->ca_cert);
3877 cred->ca_cert = val;
3878 return 0;
3879 }
3880
3881 if (os_strcmp(var, "client_cert") == 0) {
3882 os_free(cred->client_cert);
3883 cred->client_cert = val;
3884 return 0;
3885 }
3886
3887 if (os_strcmp(var, "private_key") == 0) {
3888 os_free(cred->private_key);
3889 cred->private_key = val;
3890 return 0;
3891 }
3892
3893 if (os_strcmp(var, "private_key_passwd") == 0) {
3894 str_clear_free(cred->private_key_passwd);
3895 cred->private_key_passwd = val;
3896 return 0;
3897 }
3898
3899 if (os_strcmp(var, "engine_id") == 0) {
3900 os_free(cred->engine_id);
3901 cred->engine_id = val;
3902 return 0;
3903 }
3904
3905 if (os_strcmp(var, "ca_cert_id") == 0) {
3906 os_free(cred->ca_cert_id);
3907 cred->ca_cert_id = val;
3908 return 0;
3909 }
3910
3911 if (os_strcmp(var, "cert_id") == 0) {
3912 os_free(cred->cert_id);
3913 cred->cert_id = val;
3914 return 0;
3915 }
3916
3917 if (os_strcmp(var, "key_id") == 0) {
3918 os_free(cred->key_id);
3919 cred->key_id = val;
3920 return 0;
3921 }
3922
3923 if (os_strcmp(var, "imsi") == 0) {
3924 os_free(cred->imsi);
3925 cred->imsi = val;
3926 return 0;
3927 }
3928
3929 if (os_strcmp(var, "milenage") == 0) {
3930 str_clear_free(cred->milenage);
3931 cred->milenage = val;
3932 return 0;
3933 }
3934
3935 if (os_strcmp(var, "domain_suffix_match") == 0) {
3936 os_free(cred->domain_suffix_match);
3937 cred->domain_suffix_match = val;
3938 return 0;
3939 }
3940
3941 if (os_strcmp(var, "domain") == 0) {
3942 char **new_domain;
3943 new_domain = os_realloc_array(cred->domain,
3944 cred->num_domain + 1,
3945 sizeof(char *));
3946 if (new_domain == NULL) {
3947 os_free(val);
3948 return -1;
3949 }
3950 new_domain[cred->num_domain++] = val;
3951 cred->domain = new_domain;
3952 return 0;
3953 }
3954
3955 if (os_strcmp(var, "phase1") == 0) {
3956 os_free(cred->phase1);
3957 cred->phase1 = val;
3958 return 0;
3959 }
3960
3961 if (os_strcmp(var, "phase2") == 0) {
3962 os_free(cred->phase2);
3963 cred->phase2 = val;
3964 return 0;
3965 }
3966
3967 if (os_strcmp(var, "roaming_consortium") == 0) {
3968 if (len < 3 || len > sizeof(cred->home_ois[0])) {
3969 wpa_printf(MSG_ERROR, "Line %d: invalid "
3970 "roaming_consortium length %d (3..15 "
3971 "expected)", line, (int) len);
3972 os_free(val);
3973 return -1;
3974 }
3975 wpa_printf(MSG_WARNING,
3976 "Line %d: option roaming_consortium is deprecated and will be removed in the future",
3977 line);
3978 os_memcpy(cred->home_ois[0], val, len);
3979 cred->home_ois_len[0] = len;
3980 cred->num_home_ois = 1;
3981 os_free(val);
3982 return 0;
3983 }
3984
3985 if (os_strcmp(var, "required_roaming_consortium") == 0) {
3986 if (len < 3 || len > sizeof(cred->required_home_ois[0])) {
3987 wpa_printf(MSG_ERROR, "Line %d: invalid "
3988 "required_roaming_consortium length %d "
3989 "(3..15 expected)", line, (int) len);
3990 os_free(val);
3991 return -1;
3992 }
3993 wpa_printf(MSG_WARNING,
3994 "Line %d: option required_roaming_consortium is deprecated and will be removed in the future",
3995 line);
3996 os_memcpy(cred->required_home_ois[0], val, len);
3997 cred->required_home_ois_len[0] = len;
3998 cred->num_required_home_ois = 1;
3999 os_free(val);
4000 return 0;
4001 }
4002
4003 if (os_strcmp(var, "home_ois") == 0) {
4004 res = wpa_config_set_cred_ois(cred->home_ois,
4005 cred->home_ois_len,
4006 &cred->num_home_ois,
4007 val);
4008 if (res < 0)
4009 wpa_printf(MSG_ERROR, "Line %d: invalid home_ois",
4010 line);
4011 os_free(val);
4012 return res;
4013 }
4014
4015 if (os_strcmp(var, "required_home_ois") == 0) {
4016 res = wpa_config_set_cred_ois(cred->required_home_ois,
4017 cred->required_home_ois_len,
4018 &cred->num_required_home_ois,
4019 val);
4020 if (res < 0)
4021 wpa_printf(MSG_ERROR,
4022 "Line %d: invalid required_home_ois", line);
4023 os_free(val);
4024 return res;
4025 }
4026
4027 if (os_strcmp(var, "roaming_consortiums") == 0) {
4028 res = wpa_config_set_cred_ois(cred->roaming_consortiums,
4029 cred->roaming_consortiums_len,
4030 &cred->num_roaming_consortiums,
4031 val);
4032 if (res < 0)
4033 wpa_printf(MSG_ERROR,
4034 "Line %d: invalid roaming_consortiums",
4035 line);
4036 os_free(val);
4037 return res;
4038 }
4039
4040 if (os_strcmp(var, "excluded_ssid") == 0) {
4041 struct excluded_ssid *e;
4042
4043 if (len > SSID_MAX_LEN) {
4044 wpa_printf(MSG_ERROR, "Line %d: invalid "
4045 "excluded_ssid length %d", line, (int) len);
4046 os_free(val);
4047 return -1;
4048 }
4049
4050 e = os_realloc_array(cred->excluded_ssid,
4051 cred->num_excluded_ssid + 1,
4052 sizeof(struct excluded_ssid));
4053 if (e == NULL) {
4054 os_free(val);
4055 return -1;
4056 }
4057 cred->excluded_ssid = e;
4058
4059 e = &cred->excluded_ssid[cred->num_excluded_ssid++];
4060 os_memcpy(e->ssid, val, len);
4061 e->ssid_len = len;
4062
4063 os_free(val);
4064
4065 return 0;
4066 }
4067
4068 if (os_strcmp(var, "roaming_partner") == 0) {
4069 struct roaming_partner *p;
4070 char *pos;
4071
4072 p = os_realloc_array(cred->roaming_partner,
4073 cred->num_roaming_partner + 1,
4074 sizeof(struct roaming_partner));
4075 if (p == NULL) {
4076 os_free(val);
4077 return -1;
4078 }
4079 cred->roaming_partner = p;
4080
4081 p = &cred->roaming_partner[cred->num_roaming_partner];
4082
4083 pos = os_strchr(val, ',');
4084 if (pos == NULL) {
4085 os_free(val);
4086 return -1;
4087 }
4088 *pos++ = '\0';
4089 if (pos - val - 1 >= (int) sizeof(p->fqdn)) {
4090 os_free(val);
4091 return -1;
4092 }
4093 os_memcpy(p->fqdn, val, pos - val);
4094
4095 p->exact_match = atoi(pos);
4096
4097 pos = os_strchr(pos, ',');
4098 if (pos == NULL) {
4099 os_free(val);
4100 return -1;
4101 }
4102 *pos++ = '\0';
4103
4104 p->priority = atoi(pos);
4105
4106 pos = os_strchr(pos, ',');
4107 if (pos == NULL) {
4108 os_free(val);
4109 return -1;
4110 }
4111 *pos++ = '\0';
4112
4113 if (os_strlen(pos) >= sizeof(p->country)) {
4114 os_free(val);
4115 return -1;
4116 }
4117 os_memcpy(p->country, pos, os_strlen(pos) + 1);
4118
4119 cred->num_roaming_partner++;
4120 os_free(val);
4121
4122 return 0;
4123 }
4124
4125 if (os_strcmp(var, "provisioning_sp") == 0) {
4126 os_free(cred->provisioning_sp);
4127 cred->provisioning_sp = val;
4128 return 0;
4129 }
4130
4131 if (os_strcmp(var, "imsi_privacy_cert") == 0) {
4132 os_free(cred->imsi_privacy_cert);
4133 cred->imsi_privacy_cert = val;
4134 return 0;
4135 }
4136
4137 if (os_strcmp(var, "imsi_privacy_attr") == 0) {
4138 os_free(cred->imsi_privacy_attr);
4139 cred->imsi_privacy_attr = val;
4140 return 0;
4141 }
4142
4143 if (line) {
4144 wpa_printf(MSG_ERROR, "Line %d: unknown cred field '%s'.",
4145 line, var);
4146 }
4147
4148 os_free(val);
4149
4150 return -1;
4151}
4152
4153
4154static char * alloc_int_str(int val)
4155{
4156 const unsigned int bufsize = 20;
4157 char *buf;
4158 int res;
4159
4160 buf = os_malloc(bufsize);
4161 if (buf == NULL)
4162 return NULL;
4163 res = os_snprintf(buf, bufsize, "%d", val);
4164 if (os_snprintf_error(bufsize, res)) {
4165 os_free(buf);
4166 buf = NULL;
4167 }
4168 return buf;
4169}
4170
4171
4172static char * alloc_strdup(const char *str)
4173{
4174 if (str == NULL)
4175 return NULL;
4176 return os_strdup(str);
4177}
4178
4179
4180char * wpa_config_get_cred_no_key(struct wpa_cred *cred, const char *var)
4181{
4182 if (os_strcmp(var, "temporary") == 0)
4183 return alloc_int_str(cred->temporary);
4184
4185 if (os_strcmp(var, "priority") == 0)
4186 return alloc_int_str(cred->priority);
4187
4188 if (os_strcmp(var, "sp_priority") == 0)
4189 return alloc_int_str(cred->sp_priority);
4190
4191 if (os_strcmp(var, "pcsc") == 0)
4192 return alloc_int_str(cred->pcsc);
4193
4194 if (os_strcmp(var, "eap") == 0) {
4195 if (!cred->eap_method)
4196 return NULL;
4197 return alloc_strdup(eap_get_name(cred->eap_method[0].vendor,
4198 cred->eap_method[0].method));
4199 }
4200
4201 if (os_strcmp(var, "update_identifier") == 0)
4202 return alloc_int_str(cred->update_identifier);
4203
4204 if (os_strcmp(var, "min_dl_bandwidth_home") == 0)
4205 return alloc_int_str(cred->min_dl_bandwidth_home);
4206
4207 if (os_strcmp(var, "min_ul_bandwidth_home") == 0)
4208 return alloc_int_str(cred->min_ul_bandwidth_home);
4209
4210 if (os_strcmp(var, "min_dl_bandwidth_roaming") == 0)
4211 return alloc_int_str(cred->min_dl_bandwidth_roaming);
4212
4213 if (os_strcmp(var, "min_ul_bandwidth_roaming") == 0)
4214 return alloc_int_str(cred->min_ul_bandwidth_roaming);
4215
4216 if (os_strcmp(var, "max_bss_load") == 0)
4217 return alloc_int_str(cred->max_bss_load);
4218
4219 if (os_strcmp(var, "req_conn_capab") == 0) {
4220 unsigned int i;
4221 char *buf, *end, *pos;
4222 int ret;
4223
4224 if (!cred->num_req_conn_capab)
4225 return NULL;
4226
4227 buf = os_malloc(4000);
4228 if (buf == NULL)
4229 return NULL;
4230 pos = buf;
4231 end = pos + 4000;
4232 for (i = 0; i < cred->num_req_conn_capab; i++) {
4233 int *ports;
4234
4235 ret = os_snprintf(pos, end - pos, "%s%u",
4236 i > 0 ? "\n" : "",
4237 cred->req_conn_capab_proto[i]);
4238 if (os_snprintf_error(end - pos, ret))
4239 return buf;
4240 pos += ret;
4241
4242 ports = cred->req_conn_capab_port[i];
4243 if (ports) {
4244 int j;
4245 for (j = 0; ports[j] != -1; j++) {
4246 ret = os_snprintf(pos, end - pos,
4247 "%s%d",
4248 j > 0 ? "," : ":",
4249 ports[j]);
4250 if (os_snprintf_error(end - pos, ret))
4251 return buf;
4252 pos += ret;
4253 }
4254 }
4255 }
4256
4257 return buf;
4258 }
4259
4260 if (os_strcmp(var, "ocsp") == 0)
4261 return alloc_int_str(cred->ocsp);
4262
4263 if (os_strcmp(var, "realm") == 0)
4264 return alloc_strdup(cred->realm);
4265
4266 if (os_strcmp(var, "username") == 0)
4267 return alloc_strdup(cred->username);
4268
4269 if (os_strcmp(var, "password") == 0) {
4270 if (!cred->password)
4271 return NULL;
4272 return alloc_strdup("*");
4273 }
4274
4275 if (os_strcmp(var, "ca_cert") == 0)
4276 return alloc_strdup(cred->ca_cert);
4277
4278 if (os_strcmp(var, "client_cert") == 0)
4279 return alloc_strdup(cred->client_cert);
4280
4281 if (os_strcmp(var, "private_key") == 0)
4282 return alloc_strdup(cred->private_key);
4283
4284 if (os_strcmp(var, "private_key_passwd") == 0) {
4285 if (!cred->private_key_passwd)
4286 return NULL;
4287 return alloc_strdup("*");
4288 }
4289
4290 if (os_strcmp(var, "imsi") == 0)
4291 return alloc_strdup(cred->imsi);
4292
4293 if (os_strcmp(var, "imsi_privacy_cert") == 0)
4294 return alloc_strdup(cred->imsi_privacy_cert);
4295
4296 if (os_strcmp(var, "imsi_privacy_attr") == 0)
4297 return alloc_strdup(cred->imsi_privacy_attr);
4298
4299 if (os_strcmp(var, "milenage") == 0) {
4300 if (!(cred->milenage))
4301 return NULL;
4302 return alloc_strdup("*");
4303 }
4304
4305 if (os_strcmp(var, "domain_suffix_match") == 0)
4306 return alloc_strdup(cred->domain_suffix_match);
4307
4308 if (os_strcmp(var, "domain") == 0) {
4309 unsigned int i;
4310 char *buf, *end, *pos;
4311 int ret;
4312
4313 if (!cred->num_domain)
4314 return NULL;
4315
4316 buf = os_malloc(4000);
4317 if (buf == NULL)
4318 return NULL;
4319 pos = buf;
4320 end = pos + 4000;
4321
4322 for (i = 0; i < cred->num_domain; i++) {
4323 ret = os_snprintf(pos, end - pos, "%s%s",
4324 i > 0 ? "\n" : "", cred->domain[i]);
4325 if (os_snprintf_error(end - pos, ret))
4326 return buf;
4327 pos += ret;
4328 }
4329
4330 return buf;
4331 }
4332
4333 if (os_strcmp(var, "phase1") == 0)
4334 return alloc_strdup(cred->phase1);
4335
4336 if (os_strcmp(var, "phase2") == 0)
4337 return alloc_strdup(cred->phase2);
4338
4339 if (os_strcmp(var, "roaming_consortium") == 0) {
4340 size_t buflen;
4341 char *buf;
4342
4343 if (!cred->num_home_ois || !cred->home_ois_len[0])
4344 return NULL;
4345 buflen = cred->home_ois_len[0] * 2 + 1;
4346 buf = os_malloc(buflen);
4347 if (buf == NULL)
4348 return NULL;
4349 wpa_snprintf_hex(buf, buflen, cred->home_ois[0],
4350 cred->home_ois_len[0]);
4351 return buf;
4352 }
4353
4354 if (os_strcmp(var, "required_roaming_consortium") == 0) {
4355 size_t buflen;
4356 char *buf;
4357
4358 if (!cred->num_required_home_ois ||
4359 !cred->required_home_ois_len[0])
4360 return NULL;
4361 buflen = cred->required_home_ois_len[0] * 2 + 1;
4362 buf = os_malloc(buflen);
4363 if (buf == NULL)
4364 return NULL;
4365 wpa_snprintf_hex(buf, buflen, cred->required_home_ois[0],
4366 cred->required_home_ois_len[0]);
4367 return buf;
4368 }
4369
4370 if (os_strcmp(var, "home_ois") == 0) {
4371 size_t buflen;
4372 char *buf, *pos;
4373 size_t i;
4374
4375 if (!cred->num_home_ois)
4376 return NULL;
4377 buflen = cred->num_home_ois * MAX_ROAMING_CONS_OI_LEN * 2 + 1;
4378 buf = os_malloc(buflen);
4379 if (!buf)
4380 return NULL;
4381 pos = buf;
4382 for (i = 0; i < cred->num_home_ois; i++) {
4383 if (i > 0)
4384 *pos++ = ',';
4385 pos += wpa_snprintf_hex(
4386 pos, buf + buflen - pos,
4387 cred->home_ois[i],
4388 cred->home_ois_len[i]);
4389 }
4390 *pos = '\0';
4391 return buf;
4392 }
4393
4394 if (os_strcmp(var, "required_home_ois") == 0) {
4395 size_t buflen;
4396 char *buf, *pos;
4397 size_t i;
4398
4399 if (!cred->num_required_home_ois)
4400 return NULL;
4401 buflen = cred->num_required_home_ois *
4402 MAX_ROAMING_CONS_OI_LEN * 2 + 1;
4403 buf = os_malloc(buflen);
4404 if (!buf)
4405 return NULL;
4406 pos = buf;
4407 for (i = 0; i < cred->num_required_home_ois; i++) {
4408 if (i > 0)
4409 *pos++ = ',';
4410 pos += wpa_snprintf_hex(
4411 pos, buf + buflen - pos,
4412 cred->required_home_ois[i],
4413 cred->required_home_ois_len[i]);
4414 }
4415 *pos = '\0';
4416 return buf;
4417 }
4418
4419 if (os_strcmp(var, "roaming_consortiums") == 0) {
4420 size_t buflen;
4421 char *buf, *pos;
4422 size_t i;
4423
4424 if (!cred->num_roaming_consortiums)
4425 return NULL;
4426 buflen = cred->num_roaming_consortiums *
4427 MAX_ROAMING_CONS_OI_LEN * 2 + 1;
4428 buf = os_malloc(buflen);
4429 if (!buf)
4430 return NULL;
4431 pos = buf;
4432 for (i = 0; i < cred->num_roaming_consortiums; i++) {
4433 if (i > 0)
4434 *pos++ = ',';
4435 pos += wpa_snprintf_hex(
4436 pos, buf + buflen - pos,
4437 cred->roaming_consortiums[i],
4438 cred->roaming_consortiums_len[i]);
4439 }
4440 *pos = '\0';
4441 return buf;
4442 }
4443
4444 if (os_strcmp(var, "excluded_ssid") == 0) {
4445 unsigned int i;
4446 char *buf, *end, *pos;
4447
4448 if (!cred->num_excluded_ssid)
4449 return NULL;
4450
4451 buf = os_malloc(4000);
4452 if (buf == NULL)
4453 return NULL;
4454 pos = buf;
4455 end = pos + 4000;
4456
4457 for (i = 0; i < cred->num_excluded_ssid; i++) {
4458 struct excluded_ssid *e;
4459 int ret;
4460
4461 e = &cred->excluded_ssid[i];
4462 ret = os_snprintf(pos, end - pos, "%s%s",
4463 i > 0 ? "\n" : "",
4464 wpa_ssid_txt(e->ssid, e->ssid_len));
4465 if (os_snprintf_error(end - pos, ret))
4466 return buf;
4467 pos += ret;
4468 }
4469
4470 return buf;
4471 }
4472
4473 if (os_strcmp(var, "roaming_partner") == 0) {
4474 unsigned int i;
4475 char *buf, *end, *pos;
4476
4477 if (!cred->num_roaming_partner)
4478 return NULL;
4479
4480 buf = os_malloc(4000);
4481 if (buf == NULL)
4482 return NULL;
4483 pos = buf;
4484 end = pos + 4000;
4485
4486 for (i = 0; i < cred->num_roaming_partner; i++) {
4487 struct roaming_partner *p;
4488 int ret;
4489
4490 p = &cred->roaming_partner[i];
4491 ret = os_snprintf(pos, end - pos, "%s%s,%d,%u,%s",
4492 i > 0 ? "\n" : "",
4493 p->fqdn, p->exact_match, p->priority,
4494 p->country);
4495 if (os_snprintf_error(end - pos, ret))
4496 return buf;
4497 pos += ret;
4498 }
4499
4500 return buf;
4501 }
4502
4503 if (os_strcmp(var, "provisioning_sp") == 0)
4504 return alloc_strdup(cred->provisioning_sp);
4505
4506 return NULL;
4507}
4508
4509
4510struct wpa_cred * wpa_config_get_cred(struct wpa_config *config, int id)
4511{
4512 struct wpa_cred *cred;
4513
4514 cred = config->cred;
4515 while (cred) {
4516 if (id == cred->id)
4517 break;
4518 cred = cred->next;
4519 }
4520
4521 return cred;
4522}
4523
4524
4525struct wpa_cred * wpa_config_add_cred(struct wpa_config *config)
4526{
4527 int id;
4528 struct wpa_cred *cred, *last = NULL;
4529
4530 id = -1;
4531 cred = config->cred;
4532 while (cred) {
4533 if (cred->id > id)
4534 id = cred->id;
4535 last = cred;
4536 cred = cred->next;
4537 }
4538 id++;
4539
4540 cred = os_zalloc(sizeof(*cred));
4541 if (cred == NULL)
4542 return NULL;
4543 cred->id = id;
4544 cred->sim_num = DEFAULT_USER_SELECTED_SIM;
4545 if (last)
4546 last->next = cred;
4547 else
4548 config->cred = cred;
4549
4550 return cred;
4551}
4552
4553
4554int wpa_config_remove_cred(struct wpa_config *config, int id)
4555{
4556 struct wpa_cred *cred, *prev = NULL;
4557
4558 cred = config->cred;
4559 while (cred) {
4560 if (id == cred->id)
4561 break;
4562 prev = cred;
4563 cred = cred->next;
4564 }
4565
4566 if (cred == NULL)
4567 return -1;
4568
4569 if (prev)
4570 prev->next = cred->next;
4571 else
4572 config->cred = cred->next;
4573
4574 wpa_config_free_cred(cred);
4575 return 0;
4576}
4577
4578
4579#ifndef CONFIG_NO_CONFIG_BLOBS
4580/**
4581 * wpa_config_get_blob - Get a named configuration blob
4582 * @config: Configuration data from wpa_config_read()
4583 * @name: Name of the blob
4584 * Returns: Pointer to blob data or %NULL if not found
4585 */
4586const struct wpa_config_blob * wpa_config_get_blob(struct wpa_config *config,
4587 const char *name)
4588{
4589 struct wpa_config_blob *blob = config->blobs;
4590
4591 while (blob) {
4592 if (os_strcmp(blob->name, name) == 0)
4593 return blob;
4594 blob = blob->next;
4595 }
4596 return NULL;
4597}
4598
4599
4600/**
4601 * wpa_config_set_blob - Set or add a named configuration blob
4602 * @config: Configuration data from wpa_config_read()
4603 * @blob: New value for the blob
4604 *
4605 * Adds a new configuration blob or replaces the current value of an existing
4606 * blob.
4607 */
4608void wpa_config_set_blob(struct wpa_config *config,
4609 struct wpa_config_blob *blob)
4610{
4611 wpa_config_remove_blob(config, blob->name);
4612 blob->next = config->blobs;
4613 config->blobs = blob;
4614}
4615
4616
4617/**
4618 * wpa_config_free_blob - Free blob data
4619 * @blob: Pointer to blob to be freed
4620 */
4621void wpa_config_free_blob(struct wpa_config_blob *blob)
4622{
4623 if (blob) {
4624 os_free(blob->name);
4625 bin_clear_free(blob->data, blob->len);
4626 os_free(blob);
4627 }
4628}
4629
4630
4631/**
4632 * wpa_config_remove_blob - Remove a named configuration blob
4633 * @config: Configuration data from wpa_config_read()
4634 * @name: Name of the blob to remove
4635 * Returns: 0 if blob was removed or -1 if blob was not found
4636 */
4637int wpa_config_remove_blob(struct wpa_config *config, const char *name)
4638{
4639 struct wpa_config_blob *pos = config->blobs, *prev = NULL;
4640
4641 while (pos) {
4642 if (os_strcmp(pos->name, name) == 0) {
4643 if (prev)
4644 prev->next = pos->next;
4645 else
4646 config->blobs = pos->next;
4647 wpa_config_free_blob(pos);
4648 return 0;
4649 }
4650 prev = pos;
4651 pos = pos->next;
4652 }
4653
4654 return -1;
4655}
4656#endif /* CONFIG_NO_CONFIG_BLOBS */
4657
4658
4659/**
4660 * wpa_config_alloc_empty - Allocate an empty configuration
4661 * @ctrl_interface: Control interface parameters, e.g., path to UNIX domain
4662 * socket
4663 * @driver_param: Driver parameters
4664 * Returns: Pointer to allocated configuration data or %NULL on failure
4665 */
4666struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
4667 const char *driver_param)
4668{
4669#define ecw2cw(ecw) ((1 << (ecw)) - 1)
4670
4671 struct wpa_config *config;
4672 const int aCWmin = 4, aCWmax = 10;
4673 const struct hostapd_wmm_ac_params ac_bk =
4674 { aCWmin, aCWmax, 7, 0, 0 }; /* background traffic */
4675 const struct hostapd_wmm_ac_params ac_be =
4676 { aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */
4677 const struct hostapd_wmm_ac_params ac_vi = /* video traffic */
4678 { aCWmin - 1, aCWmin, 2, 3008 / 32, 0 };
4679 const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */
4680 { aCWmin - 2, aCWmin - 1, 2, 1504 / 32, 0 };
4681 const struct hostapd_tx_queue_params txq_bk =
4682 { 7, ecw2cw(aCWmin), ecw2cw(aCWmax), 0 };
4683 const struct hostapd_tx_queue_params txq_be =
4684 { 3, ecw2cw(aCWmin), 4 * (ecw2cw(aCWmin) + 1) - 1, 0 };
4685 const struct hostapd_tx_queue_params txq_vi =
4686 { 1, (ecw2cw(aCWmin) + 1) / 2 - 1, ecw2cw(aCWmin), 30 };
4687 const struct hostapd_tx_queue_params txq_vo =
4688 { 1, (ecw2cw(aCWmin) + 1) / 4 - 1,
4689 (ecw2cw(aCWmin) + 1) / 2 - 1, 15 };
4690
4691#undef ecw2cw
4692
4693 config = os_zalloc(sizeof(*config));
4694 if (config == NULL)
4695 return NULL;
4696 config->eapol_version = DEFAULT_EAPOL_VERSION;
4697 config->ap_scan = DEFAULT_AP_SCAN;
4698 config->user_mpm = DEFAULT_USER_MPM;
4699 config->max_peer_links = DEFAULT_MAX_PEER_LINKS;
4700 config->mesh_max_inactivity = DEFAULT_MESH_MAX_INACTIVITY;
4701 config->mesh_fwding = DEFAULT_MESH_FWDING;
4702 config->dot11RSNASAERetransPeriod =
4703 DEFAULT_DOT11_RSNA_SAE_RETRANS_PERIOD;
4704 config->fast_reauth = DEFAULT_FAST_REAUTH;
4705 config->p2p_go_intent = DEFAULT_P2P_GO_INTENT;
4706 config->p2p_intra_bss = DEFAULT_P2P_INTRA_BSS;
4707 config->p2p_go_freq_change_policy = DEFAULT_P2P_GO_FREQ_MOVE;
4708 config->p2p_go_max_inactivity = DEFAULT_P2P_GO_MAX_INACTIVITY;
4709 config->p2p_optimize_listen_chan = DEFAULT_P2P_OPTIMIZE_LISTEN_CHAN;
4710 config->p2p_go_ctwindow = DEFAULT_P2P_GO_CTWINDOW;
4711 config->bss_max_count = DEFAULT_BSS_MAX_COUNT;
4712 config->bss_expiration_age = DEFAULT_BSS_EXPIRATION_AGE;
4713 config->bss_expiration_scan_count = DEFAULT_BSS_EXPIRATION_SCAN_COUNT;
4714 config->max_num_sta = DEFAULT_MAX_NUM_STA;
4715 config->ap_isolate = DEFAULT_AP_ISOLATE;
4716 config->access_network_type = DEFAULT_ACCESS_NETWORK_TYPE;
4717 config->scan_cur_freq = DEFAULT_SCAN_CUR_FREQ;
4718 config->scan_res_valid_for_connect = DEFAULT_SCAN_RES_VALID_FOR_CONNECT;
4719 config->wmm_ac_params[0] = ac_be;
4720 config->wmm_ac_params[1] = ac_bk;
4721 config->wmm_ac_params[2] = ac_vi;
4722 config->wmm_ac_params[3] = ac_vo;
4723 config->tx_queue[0] = txq_vo;
4724 config->tx_queue[1] = txq_vi;
4725 config->tx_queue[2] = txq_be;
4726 config->tx_queue[3] = txq_bk;
4727 config->p2p_search_delay = DEFAULT_P2P_SEARCH_DELAY;
4728 config->rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME;
4729 config->key_mgmt_offload = DEFAULT_KEY_MGMT_OFFLOAD;
4730 config->cert_in_cb = DEFAULT_CERT_IN_CB;
4731 config->wpa_rsc_relaxation = DEFAULT_WPA_RSC_RELAXATION;
4732 config->extended_key_id = DEFAULT_EXTENDED_KEY_ID;
4733
4734#ifdef CONFIG_MBO
4735 config->mbo_cell_capa = DEFAULT_MBO_CELL_CAPA;
4736 config->disassoc_imminent_rssi_threshold =
4737 DEFAULT_DISASSOC_IMMINENT_RSSI_THRESHOLD;
4738 config->oce = DEFAULT_OCE_SUPPORT;
4739#endif /* CONFIG_MBO */
4740
4741 if (ctrl_interface)
4742 config->ctrl_interface = os_strdup(ctrl_interface);
4743 if (driver_param)
4744 config->driver_param = os_strdup(driver_param);
4745 config->gas_rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME;
4746
4747 return config;
4748}
4749
4750
4751#ifndef CONFIG_NO_STDOUT_DEBUG
4752/**
4753 * wpa_config_debug_dump_networks - Debug dump of configured networks
4754 * @config: Configuration data from wpa_config_read()
4755 */
4756void wpa_config_debug_dump_networks(struct wpa_config *config)
4757{
4758 size_t prio;
4759 struct wpa_ssid *ssid;
4760
4761 for (prio = 0; prio < config->num_prio; prio++) {
4762 ssid = config->pssid[prio];
4763 wpa_printf(MSG_DEBUG, "Priority group %d",
4764 ssid->priority);
4765 while (ssid) {
4766 wpa_printf(MSG_DEBUG, " id=%d ssid='%s'",
4767 ssid->id,
4768 wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
4769 ssid = ssid->pnext;
4770 }
4771 }
4772}
4773#endif /* CONFIG_NO_STDOUT_DEBUG */
4774
4775
4776/**
4777 * Structure for global configuration parsing. This data is used to implement a
4778 * generic parser for the global interface configuration. The table of variables
4779 * is defined below in this file (global_fields[]).
4780 */
4781struct global_parse_data {
4782 /* Configuration variable name */
4783 char *name;
4784
4785 /* Parser function for this variable. The parser functions return 0 or 1
4786 * to indicate success. Value 0 indicates that the parameter value may
4787 * have changed while value 1 means that the value did not change.
4788 * Error cases (failure to parse the string) are indicated by returning
4789 * -1. */
4790 int (*parser)(const struct global_parse_data *data,
4791 struct wpa_config *config, int line, const char *value);
4792
4793 /* Getter function to print the variable in text format to buf. */
4794 int (*get)(const char *name, struct wpa_config *config, long offset,
4795 char *buf, size_t buflen, int pretty_print);
4796
4797 /* Variable specific parameters for the parser. */
4798 void *param1, *param2, *param3;
4799
4800 /* Indicates which configuration variable has changed. */
4801 unsigned int changed_flag;
4802};
4803
4804
4805static int wpa_global_config_parse_int(const struct global_parse_data *data,
4806 struct wpa_config *config, int line,
4807 const char *pos)
4808{
4809 int val, *dst;
4810 char *end;
4811 bool same;
4812
4813 dst = (int *) (((u8 *) config) + (long) data->param1);
4814 val = strtol(pos, &end, 0);
4815 if (*end) {
4816 wpa_printf(MSG_ERROR, "Line %d: invalid number \"%s\"",
4817 line, pos);
4818 return -1;
4819 }
4820 same = *dst == val;
4821 *dst = val;
4822
4823 wpa_printf(MSG_DEBUG, "%s=%d", data->name, *dst);
4824
4825 if (data->param2 && *dst < (long) data->param2) {
4826 wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d "
4827 "min_value=%ld)", line, data->name, *dst,
4828 (long) data->param2);
4829 *dst = (long) data->param2;
4830 return -1;
4831 }
4832
4833 if (data->param3 && *dst > (long) data->param3) {
4834 wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d "
4835 "max_value=%ld)", line, data->name, *dst,
4836 (long) data->param3);
4837 *dst = (long) data->param3;
4838 return -1;
4839 }
4840
4841 return same;
4842}
4843
4844
4845static int wpa_global_config_parse_str(const struct global_parse_data *data,
4846 struct wpa_config *config, int line,
4847 const char *pos)
4848{
4849 size_t len, prev_len;
4850 char **dst, *tmp;
4851
4852 len = os_strlen(pos);
4853 if (data->param2 && len < (size_t) data->param2) {
4854 wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu "
4855 "min_len=%ld)", line, data->name,
4856 (unsigned long) len, (long) data->param2);
4857 return -1;
4858 }
4859
4860 if (data->param3 && len > (size_t) data->param3) {
4861 wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu "
4862 "max_len=%ld)", line, data->name,
4863 (unsigned long) len, (long) data->param3);
4864 return -1;
4865 }
4866
4867 if (has_newline(pos)) {
4868 wpa_printf(MSG_ERROR, "Line %d: invalid %s value with newline",
4869 line, data->name);
4870 return -1;
4871 }
4872
4873 dst = (char **) (((u8 *) config) + (long) data->param1);
4874 if (*dst)
4875 prev_len = os_strlen(*dst);
4876 else
4877 prev_len = 0;
4878
4879 /* No change to the previously configured value */
4880 if (*dst && prev_len == len && os_memcmp(*dst, pos, len) == 0)
4881 return 1;
4882
4883 tmp = os_strdup(pos);
4884 if (tmp == NULL)
4885 return -1;
4886
4887 os_free(*dst);
4888 *dst = tmp;
4889 wpa_printf(MSG_DEBUG, "%s='%s'", data->name, *dst);
4890
4891 return 0;
4892}
4893
4894
4895static int wpa_config_process_bgscan(const struct global_parse_data *data,
4896 struct wpa_config *config, int line,
4897 const char *pos)
4898{
4899 size_t len;
4900 char *tmp;
4901 int res;
4902
4903 tmp = wpa_config_parse_string(pos, &len);
4904 if (tmp == NULL) {
4905 wpa_printf(MSG_ERROR, "Line %d: failed to parse %s",
4906 line, data->name);
4907 return -1;
4908 }
4909
4910 res = wpa_global_config_parse_str(data, config, line, tmp);
4911 os_free(tmp);
4912 return res;
4913}
4914
4915
4916static int wpa_global_config_parse_bin(const struct global_parse_data *data,
4917 struct wpa_config *config, int line,
4918 const char *pos)
4919{
4920 struct wpabuf **dst, *tmp;
4921
4922 tmp = wpabuf_parse_bin(pos);
4923 if (!tmp)
4924 return -1;
4925
4926 dst = (struct wpabuf **) (((u8 *) config) + (long) data->param1);
4927 if (wpabuf_cmp(*dst, tmp) == 0) {
4928 wpabuf_free(tmp);
4929 return 1;
4930 }
4931 wpabuf_free(*dst);
4932 *dst = tmp;
4933 wpa_printf(MSG_DEBUG, "%s", data->name);
4934
4935 return 0;
4936}
4937
4938
4939static int wpa_config_process_freq_list(const struct global_parse_data *data,
4940 struct wpa_config *config, int line,
4941 const char *value)
4942{
4943 int *freqs;
4944
4945 freqs = wpa_config_parse_int_array(value);
4946 if (freqs == NULL)
4947 return -1;
4948 if (freqs[0] == 0) {
4949 os_free(freqs);
4950 freqs = NULL;
4951 }
4952 os_free(config->freq_list);
4953 config->freq_list = freqs;
4954 return 0;
4955}
4956
4957
4958static int
4959wpa_config_process_initial_freq_list(const struct global_parse_data *data,
4960 struct wpa_config *config, int line,
4961 const char *value)
4962{
4963 int *freqs;
4964
4965 freqs = wpa_config_parse_int_array(value);
4966 if (!freqs)
4967 return -1;
4968 if (freqs[0] == 0) {
4969 os_free(freqs);
4970 freqs = NULL;
4971 }
4972 os_free(config->initial_freq_list);
4973 config->initial_freq_list = freqs;
4974 return 0;
4975}
4976
4977
4978#ifdef CONFIG_P2P
4979static int wpa_global_config_parse_ipv4(const struct global_parse_data *data,
4980 struct wpa_config *config, int line,
4981 const char *pos)
4982{
4983 u32 *dst;
4984 struct hostapd_ip_addr addr;
4985
4986 if (hostapd_parse_ip_addr(pos, &addr) < 0)
4987 return -1;
4988 if (addr.af != AF_INET)
4989 return -1;
4990
4991 dst = (u32 *) (((u8 *) config) + (long) data->param1);
4992 if (os_memcmp(dst, &addr.u.v4.s_addr, 4) == 0)
4993 return 1;
4994 os_memcpy(dst, &addr.u.v4.s_addr, 4);
4995 wpa_printf(MSG_DEBUG, "%s = 0x%x", data->name,
4996 WPA_GET_BE32((u8 *) dst));
4997
4998 return 0;
4999}
5000#endif /* CONFIG_P2P */
5001
5002
5003static int wpa_config_process_country(const struct global_parse_data *data,
5004 struct wpa_config *config, int line,
5005 const char *pos)
5006{
5007 if (!pos[0] || !pos[1]) {
5008 wpa_printf(MSG_DEBUG, "Invalid country set");
5009 return -1;
5010 }
5011 if (pos[0] == config->country[0] && pos[1] == config->country[1])
5012 return 1;
5013 config->country[0] = pos[0];
5014 config->country[1] = pos[1];
5015 wpa_printf(MSG_DEBUG, "country='%c%c'",
5016 config->country[0], config->country[1]);
5017 return 0;
5018}
5019
5020
5021static int wpa_config_process_load_dynamic_eap(
5022 const struct global_parse_data *data, struct wpa_config *config,
5023 int line, const char *so)
5024{
5025 int ret;
5026 wpa_printf(MSG_DEBUG, "load_dynamic_eap=%s", so);
5027 ret = eap_peer_method_load(so);
5028 if (ret == -2) {
5029 wpa_printf(MSG_DEBUG, "This EAP type was already loaded - not "
5030 "reloading.");
5031 } else if (ret) {
5032 wpa_printf(MSG_ERROR, "Line %d: Failed to load dynamic EAP "
5033 "method '%s'.", line, so);
5034 return -1;
5035 }
5036
5037 return 0;
5038}
5039
5040
5041#ifdef CONFIG_WPS
5042
5043static int wpa_config_process_uuid(const struct global_parse_data *data,
5044 struct wpa_config *config, int line,
5045 const char *pos)
5046{
5047 char buf[40];
5048 if (uuid_str2bin(pos, config->uuid)) {
5049 wpa_printf(MSG_ERROR, "Line %d: invalid UUID", line);
5050 return -1;
5051 }
5052 uuid_bin2str(config->uuid, buf, sizeof(buf));
5053 wpa_printf(MSG_DEBUG, "uuid=%s", buf);
5054 return 0;
5055}
5056
5057
5058static int wpa_config_process_device_type(
5059 const struct global_parse_data *data,
5060 struct wpa_config *config, int line, const char *pos)
5061{
5062 return wps_dev_type_str2bin(pos, config->device_type);
5063}
5064
5065
5066static int wpa_config_process_os_version(const struct global_parse_data *data,
5067 struct wpa_config *config, int line,
5068 const char *pos)
5069{
5070 if (hexstr2bin(pos, config->os_version, 4)) {
5071 wpa_printf(MSG_ERROR, "Line %d: invalid os_version", line);
5072 return -1;
5073 }
5074 wpa_printf(MSG_DEBUG, "os_version=%08x",
5075 WPA_GET_BE32(config->os_version));
5076 return 0;
5077}
5078
5079
5080static int wpa_config_process_wps_vendor_ext_m1(
5081 const struct global_parse_data *data,
5082 struct wpa_config *config, int line, const char *pos)
5083{
5084 struct wpabuf *tmp;
5085 int len = os_strlen(pos) / 2;
5086 u8 *p;
5087
5088 if (!len) {
5089 wpa_printf(MSG_ERROR, "Line %d: "
5090 "invalid wps_vendor_ext_m1", line);
5091 return -1;
5092 }
5093
5094 tmp = wpabuf_alloc(len);
5095 if (tmp) {
5096 p = wpabuf_put(tmp, len);
5097
5098 if (hexstr2bin(pos, p, len)) {
5099 wpa_printf(MSG_ERROR, "Line %d: "
5100 "invalid wps_vendor_ext_m1", line);
5101 wpabuf_free(tmp);
5102 return -1;
5103 }
5104
5105 wpabuf_free(config->wps_vendor_ext_m1);
5106 config->wps_vendor_ext_m1 = tmp;
5107 } else {
5108 wpa_printf(MSG_ERROR, "Can not allocate "
5109 "memory for wps_vendor_ext_m1");
5110 return -1;
5111 }
5112
5113 return 0;
5114}
5115
5116#endif /* CONFIG_WPS */
5117
5118#ifdef CONFIG_P2P
5119static int wpa_config_process_sec_device_type(
5120 const struct global_parse_data *data,
5121 struct wpa_config *config, int line, const char *pos)
5122{
5123 int idx;
5124
5125 if (config->num_sec_device_types >= MAX_SEC_DEVICE_TYPES) {
5126 wpa_printf(MSG_ERROR, "Line %d: too many sec_device_type "
5127 "items", line);
5128 return -1;
5129 }
5130
5131 idx = config->num_sec_device_types;
5132
5133 if (wps_dev_type_str2bin(pos, config->sec_device_type[idx]))
5134 return -1;
5135
5136 config->num_sec_device_types++;
5137 return 0;
5138}
5139
5140
5141static int wpa_config_process_p2p_pref_chan(
5142 const struct global_parse_data *data,
5143 struct wpa_config *config, int line, const char *pos)
5144{
5145 struct p2p_channel *pref = NULL, *n;
5146 size_t num = 0;
5147 const char *pos2;
5148 u8 op_class, chan;
5149
5150 /* format: class:chan,class:chan,... */
5151
5152 while (*pos) {
5153 op_class = atoi(pos);
5154 pos2 = os_strchr(pos, ':');
5155 if (pos2 == NULL)
5156 goto fail;
5157 pos2++;
5158 chan = atoi(pos2);
5159
5160 n = os_realloc_array(pref, num + 1,
5161 sizeof(struct p2p_channel));
5162 if (n == NULL)
5163 goto fail;
5164 pref = n;
5165 pref[num].op_class = op_class;
5166 pref[num].chan = chan;
5167 num++;
5168
5169 pos = os_strchr(pos2, ',');
5170 if (pos == NULL)
5171 break;
5172 pos++;
5173 }
5174
5175 os_free(config->p2p_pref_chan);
5176 config->p2p_pref_chan = pref;
5177 config->num_p2p_pref_chan = num;
5178 wpa_hexdump(MSG_DEBUG, "P2P: Preferred class/channel pairs",
5179 (u8 *) config->p2p_pref_chan,
5180 config->num_p2p_pref_chan * sizeof(struct p2p_channel));
5181
5182 return 0;
5183
5184fail:
5185 os_free(pref);
5186 wpa_printf(MSG_ERROR, "Line %d: Invalid p2p_pref_chan list", line);
5187 return -1;
5188}
5189
5190
5191static int wpa_config_process_p2p_no_go_freq(
5192 const struct global_parse_data *data,
5193 struct wpa_config *config, int line, const char *pos)
5194{
5195 int ret;
5196
5197 ret = freq_range_list_parse(&config->p2p_no_go_freq, pos);
5198 if (ret < 0) {
5199 wpa_printf(MSG_ERROR, "Line %d: Invalid p2p_no_go_freq", line);
5200 return -1;
5201 }
5202
5203 wpa_printf(MSG_DEBUG, "P2P: p2p_no_go_freq with %u items",
5204 config->p2p_no_go_freq.num);
5205
5206 return 0;
5207}
5208
5209
5210static int wpa_config_process_p2p_device_persistent_mac_addr(
5211 const struct global_parse_data *data,
5212 struct wpa_config *config, int line, const char *pos)
5213{
5214 if (hwaddr_aton2(pos, config->p2p_device_persistent_mac_addr) < 0) {
5215 wpa_printf(MSG_ERROR,
5216 "Line %d: Invalid p2p_device_persistent_mac_addr '%s'",
5217 line, pos);
5218 return -1;
5219 }
5220
5221 return 0;
5222}
5223
5224#endif /* CONFIG_P2P */
5225
5226
5227static int wpa_config_process_hessid(
5228 const struct global_parse_data *data,
5229 struct wpa_config *config, int line, const char *pos)
5230{
5231 if (hwaddr_aton2(pos, config->hessid) < 0) {
5232 wpa_printf(MSG_ERROR, "Line %d: Invalid hessid '%s'",
5233 line, pos);
5234 return -1;
5235 }
5236
5237 return 0;
5238}
5239
5240
5241static int wpa_config_process_sae_groups(
5242 const struct global_parse_data *data,
5243 struct wpa_config *config, int line, const char *pos)
5244{
5245 int *groups = wpa_config_parse_int_array(pos);
5246 if (groups == NULL) {
5247 wpa_printf(MSG_ERROR, "Line %d: Invalid sae_groups '%s'",
5248 line, pos);
5249 return -1;
5250 }
5251
5252 os_free(config->sae_groups);
5253 config->sae_groups = groups;
5254
5255 return 0;
5256}
5257
5258
5259static int wpa_config_process_ap_vendor_elements(
5260 const struct global_parse_data *data,
5261 struct wpa_config *config, int line, const char *pos)
5262{
5263 struct wpabuf *tmp;
5264
5265 if (!*pos) {
5266 wpabuf_free(config->ap_vendor_elements);
5267 config->ap_vendor_elements = NULL;
5268 return 0;
5269 }
5270
5271 tmp = wpabuf_parse_bin(pos);
5272 if (!tmp) {
5273 wpa_printf(MSG_ERROR, "Line %d: invalid ap_vendor_elements",
5274 line);
5275 return -1;
5276 }
5277 wpabuf_free(config->ap_vendor_elements);
5278 config->ap_vendor_elements = tmp;
5279
5280 return 0;
5281}
5282
5283
5284static int wpa_config_process_ap_assocresp_elements(
5285 const struct global_parse_data *data,
5286 struct wpa_config *config, int line, const char *pos)
5287{
5288 struct wpabuf *tmp;
5289
5290 if (!*pos) {
5291 wpabuf_free(config->ap_assocresp_elements);
5292 config->ap_assocresp_elements = NULL;
5293 return 0;
5294 }
5295
5296 tmp = wpabuf_parse_bin(pos);
5297 if (!tmp) {
5298 wpa_printf(MSG_ERROR, "Line %d: invalid ap_assocresp_elements",
5299 line);
5300 return -1;
5301 }
5302 wpabuf_free(config->ap_assocresp_elements);
5303 config->ap_assocresp_elements = tmp;
5304
5305 return 0;
5306}
5307
5308
5309#ifdef CONFIG_CTRL_IFACE
5310static int wpa_config_process_no_ctrl_interface(
5311 const struct global_parse_data *data,
5312 struct wpa_config *config, int line, const char *pos)
5313{
5314 wpa_printf(MSG_DEBUG, "no_ctrl_interface -> ctrl_interface=NULL");
5315 os_free(config->ctrl_interface);
5316 config->ctrl_interface = NULL;
5317 return 0;
5318}
5319#endif /* CONFIG_CTRL_IFACE */
5320
5321
5322static int wpa_config_get_int(const char *name, struct wpa_config *config,
5323 long offset, char *buf, size_t buflen,
5324 int pretty_print)
5325{
5326 int *val = (int *) (((u8 *) config) + (long) offset);
5327
5328 if (pretty_print)
5329 return os_snprintf(buf, buflen, "%s=%d\n", name, *val);
5330 return os_snprintf(buf, buflen, "%d", *val);
5331}
5332
5333
5334static int wpa_config_get_str(const char *name, struct wpa_config *config,
5335 long offset, char *buf, size_t buflen,
5336 int pretty_print)
5337{
5338 char **val = (char **) (((u8 *) config) + (long) offset);
5339 int res;
5340
5341 if (pretty_print)
5342 res = os_snprintf(buf, buflen, "%s=%s\n", name,
5343 *val ? *val : "null");
5344 else if (!*val)
5345 return -1;
5346 else
5347 res = os_snprintf(buf, buflen, "%s", *val);
5348 if (os_snprintf_error(buflen, res))
5349 res = -1;
5350
5351 return res;
5352}
5353
5354
5355#ifdef CONFIG_P2P
5356static int wpa_config_get_ipv4(const char *name, struct wpa_config *config,
5357 long offset, char *buf, size_t buflen,
5358 int pretty_print)
5359{
5360 void *val = ((u8 *) config) + (long) offset;
5361 int res;
5362 char addr[INET_ADDRSTRLEN];
5363
5364 if (!val || !inet_ntop(AF_INET, val, addr, sizeof(addr)))
5365 return -1;
5366
5367 if (pretty_print)
5368 res = os_snprintf(buf, buflen, "%s=%s\n", name, addr);
5369 else
5370 res = os_snprintf(buf, buflen, "%s", addr);
5371
5372 if (os_snprintf_error(buflen, res))
5373 res = -1;
5374
5375 return res;
5376}
5377#endif /* CONFIG_P2P */
5378
5379
5380#ifdef OFFSET
5381#undef OFFSET
5382#endif /* OFFSET */
5383/* OFFSET: Get offset of a variable within the wpa_config structure */
5384#define OFFSET(v) ((void *) &((struct wpa_config *) 0)->v)
5385
5386#define FUNC(f) #f, wpa_config_process_ ## f, NULL, OFFSET(f), NULL, NULL
5387#define FUNC_NO_VAR(f) #f, wpa_config_process_ ## f, NULL, NULL, NULL, NULL
5388#define _INT(f) #f, wpa_global_config_parse_int, wpa_config_get_int, OFFSET(f)
5389#define INT(f) _INT(f), NULL, NULL
5390#define INT_RANGE(f, min, max) _INT(f), (void *) min, (void *) max
5391#define _STR(f) #f, wpa_global_config_parse_str, wpa_config_get_str, OFFSET(f)
5392#define STR(f) _STR(f), NULL, NULL
5393#define STR_RANGE(f, min, max) _STR(f), (void *) min, (void *) max
5394#define BIN(f) #f, wpa_global_config_parse_bin, NULL, OFFSET(f), NULL, NULL
5395#define IPV4(f) #f, wpa_global_config_parse_ipv4, wpa_config_get_ipv4, \
5396 OFFSET(f), NULL, NULL
5397
5398static const struct global_parse_data global_fields[] = {
5399#ifdef CONFIG_CTRL_IFACE
5400 { STR(ctrl_interface), 0 },
5401 { FUNC_NO_VAR(no_ctrl_interface), 0 },
5402 { STR(ctrl_interface_group), 0 } /* deprecated */,
5403#endif /* CONFIG_CTRL_IFACE */
5404#ifdef CONFIG_MACSEC
5405 { INT_RANGE(eapol_version, 1, 3), 0 },
5406#else /* CONFIG_MACSEC */
5407 { INT_RANGE(eapol_version, 1, 2), 0 },
5408#endif /* CONFIG_MACSEC */
5409 { INT(ap_scan), 0 },
5410 { FUNC(bgscan), CFG_CHANGED_BGSCAN },
5411#ifdef CONFIG_MESH
5412 { INT(user_mpm), 0 },
5413 { INT_RANGE(max_peer_links, 0, 255), 0 },
5414 { INT(mesh_max_inactivity), 0 },
5415 { INT_RANGE(mesh_fwding, 0, 1), 0 },
5416 { INT(dot11RSNASAERetransPeriod), 0 },
5417#endif /* CONFIG_MESH */
5418 { INT(disable_scan_offload), 0 },
5419 { INT(fast_reauth), 0 },
5420 { STR(opensc_engine_path), 0 },
5421 { STR(pkcs11_engine_path), 0 },
5422 { STR(pkcs11_module_path), 0 },
5423 { STR(openssl_ciphers), 0 },
5424 { STR(pcsc_reader), 0 },
5425 { STR(pcsc_pin), 0 },
5426 { INT(external_sim), 0 },
5427 { STR(driver_param), 0 },
5428 { INT(dot11RSNAConfigPMKLifetime), 0 },
5429 { INT(dot11RSNAConfigPMKReauthThreshold), 0 },
5430 { INT(dot11RSNAConfigSATimeout), 0 },
5431#ifndef CONFIG_NO_CONFIG_WRITE
5432 { INT(update_config), 0 },
5433#endif /* CONFIG_NO_CONFIG_WRITE */
5434 { FUNC_NO_VAR(load_dynamic_eap), 0 },
5435#ifdef CONFIG_WPS
5436 { FUNC(uuid), CFG_CHANGED_UUID },
5437 { INT_RANGE(auto_uuid, 0, 1), 0 },
5438 { STR_RANGE(device_name, 0, WPS_DEV_NAME_MAX_LEN),
5439 CFG_CHANGED_DEVICE_NAME },
5440 { STR_RANGE(manufacturer, 0, 64), CFG_CHANGED_WPS_STRING },
5441 { STR_RANGE(model_name, 0, 32), CFG_CHANGED_WPS_STRING },
5442 { STR_RANGE(model_number, 0, 32), CFG_CHANGED_WPS_STRING },
5443 { STR_RANGE(serial_number, 0, 32), CFG_CHANGED_WPS_STRING },
5444 { FUNC(device_type), CFG_CHANGED_DEVICE_TYPE },
5445 { FUNC(os_version), CFG_CHANGED_OS_VERSION },
5446 { STR(config_methods), CFG_CHANGED_CONFIG_METHODS },
5447 { INT_RANGE(wps_cred_processing, 0, 2), 0 },
5448 { INT_RANGE(wps_cred_add_sae, 0, 1), 0 },
5449 { FUNC(wps_vendor_ext_m1), CFG_CHANGED_VENDOR_EXTENSION },
5450#endif /* CONFIG_WPS */
5451#ifdef CONFIG_P2P
5452 { FUNC(sec_device_type), CFG_CHANGED_SEC_DEVICE_TYPE },
5453 { INT(p2p_listen_reg_class), CFG_CHANGED_P2P_LISTEN_CHANNEL },
5454 { INT(p2p_listen_channel), CFG_CHANGED_P2P_LISTEN_CHANNEL },
5455 { INT(p2p_oper_reg_class), CFG_CHANGED_P2P_OPER_CHANNEL },
5456 { INT(p2p_oper_channel), CFG_CHANGED_P2P_OPER_CHANNEL },
5457 { INT_RANGE(p2p_go_intent, 0, 15), 0 },
5458 { STR(p2p_ssid_postfix), CFG_CHANGED_P2P_SSID_POSTFIX },
5459 { INT_RANGE(persistent_reconnect, 0, 1), 0 },
5460 { INT_RANGE(p2p_intra_bss, 0, 1), CFG_CHANGED_P2P_INTRA_BSS },
5461 { INT(p2p_group_idle), 0 },
5462 { INT_RANGE(p2p_go_freq_change_policy, 0, P2P_GO_FREQ_MOVE_MAX), 0 },
5463 { INT_RANGE(p2p_passphrase_len, 8, 63),
5464 CFG_CHANGED_P2P_PASSPHRASE_LEN },
5465 { FUNC(p2p_pref_chan), CFG_CHANGED_P2P_PREF_CHAN },
5466 { FUNC(p2p_no_go_freq), CFG_CHANGED_P2P_PREF_CHAN },
5467 { INT_RANGE(p2p_add_cli_chan, 0, 1), 0 },
5468 { INT_RANGE(p2p_optimize_listen_chan, 0, 1), 0 },
5469 { INT(p2p_go_ht40), 0 },
5470 { INT(p2p_go_vht), 0 },
5471 { INT(p2p_go_he), 0 },
5472 { INT(p2p_go_edmg), 0 },
5473 { INT(p2p_disabled), 0 },
5474 { INT_RANGE(p2p_go_ctwindow, 0, 127), 0 },
5475 { INT(p2p_no_group_iface), 0 },
5476 { INT_RANGE(p2p_ignore_shared_freq, 0, 1), 0 },
5477 { IPV4(ip_addr_go), 0 },
5478 { IPV4(ip_addr_mask), 0 },
5479 { IPV4(ip_addr_start), 0 },
5480 { IPV4(ip_addr_end), 0 },
5481 { INT_RANGE(p2p_cli_probe, 0, 1), 0 },
5482 { INT(p2p_device_random_mac_addr), 0 },
5483 { FUNC(p2p_device_persistent_mac_addr), 0 },
5484 { INT(p2p_interface_random_mac_addr), 0 },
5485 { INT(p2p_6ghz_disable), 0 },
5486#endif /* CONFIG_P2P */
5487 { FUNC(country), CFG_CHANGED_COUNTRY },
5488 { INT(bss_max_count), 0 },
5489 { INT(bss_expiration_age), 0 },
5490 { INT(bss_expiration_scan_count), 0 },
5491 { INT_RANGE(filter_ssids, 0, 1), 0 },
5492 { INT_RANGE(filter_rssi, -100, 0), 0 },
5493 { INT(max_num_sta), 0 },
5494 { INT_RANGE(ap_isolate, 0, 1), 0 },
5495 { INT_RANGE(disassoc_low_ack, 0, 1), 0 },
5496#ifdef CONFIG_HS20
5497 { INT_RANGE(hs20, 0, 1), 0 },
5498#endif /* CONFIG_HS20 */
5499 { INT_RANGE(interworking, 0, 1), 0 },
5500 { FUNC(hessid), 0 },
5501 { INT_RANGE(access_network_type, 0, 15), 0 },
5502 { INT_RANGE(go_interworking, 0, 1), 0 },
5503 { INT_RANGE(go_access_network_type, 0, 15), 0 },
5504 { INT_RANGE(go_internet, 0, 1), 0 },
5505 { INT_RANGE(go_venue_group, 0, 255), 0 },
5506 { INT_RANGE(go_venue_type, 0, 255), 0 },
5507 { INT_RANGE(pbc_in_m1, 0, 1), 0 },
5508 { STR(autoscan), 0 },
5509 { INT_RANGE(wps_nfc_dev_pw_id, 0x10, 0xffff),
5510 CFG_CHANGED_NFC_PASSWORD_TOKEN },
5511 { BIN(wps_nfc_dh_pubkey), CFG_CHANGED_NFC_PASSWORD_TOKEN },
5512 { BIN(wps_nfc_dh_privkey), CFG_CHANGED_NFC_PASSWORD_TOKEN },
5513 { BIN(wps_nfc_dev_pw), CFG_CHANGED_NFC_PASSWORD_TOKEN },
5514 { STR(ext_password_backend), CFG_CHANGED_EXT_PW_BACKEND },
5515 { INT(p2p_go_max_inactivity), 0 },
5516 { INT_RANGE(auto_interworking, 0, 1), 0 },
5517 { INT(okc), 0 },
5518 { INT(pmf), 0 },
5519 { INT_RANGE(sae_check_mfp, 0, 1), 0 },
5520 { FUNC(sae_groups), 0 },
5521 { INT_RANGE(sae_pwe, 0, 3), 0 },
5522 { INT_RANGE(sae_pmkid_in_assoc, 0, 1), 0 },
5523 { INT(dtim_period), 0 },
5524 { INT(beacon_int), 0 },
5525 { FUNC(ap_assocresp_elements), 0 },
5526 { FUNC(ap_vendor_elements), 0 },
5527 { INT_RANGE(ignore_old_scan_res, 0, 1), 0 },
5528 { FUNC(freq_list), 0 },
5529 { FUNC(initial_freq_list), 0},
5530 { INT(scan_cur_freq), 0 },
5531 { INT(scan_res_valid_for_connect), 0},
5532 { INT(sched_scan_interval), 0 },
5533 { INT(sched_scan_start_delay), 0 },
5534 { INT(tdls_external_control), 0},
5535 { STR(osu_dir), 0 },
5536 { STR(wowlan_triggers), CFG_CHANGED_WOWLAN_TRIGGERS },
5537 { INT(p2p_search_delay), 0},
5538 { INT_RANGE(mac_addr, 0, 2), 0 },
5539 { INT(rand_addr_lifetime), 0 },
5540 { INT_RANGE(preassoc_mac_addr, 0, 2), 0 },
5541 { INT(key_mgmt_offload), 0},
5542 { INT(passive_scan), 0 },
5543 { INT(reassoc_same_bss_optim), 0 },
5544 { INT(wps_priority), 0},
5545#ifdef CONFIG_FST
5546 { STR_RANGE(fst_group_id, 1, FST_MAX_GROUP_ID_LEN), 0 },
5547 { INT_RANGE(fst_priority, 1, FST_MAX_PRIO_VALUE), 0 },
5548 { INT_RANGE(fst_llt, 1, FST_MAX_LLT_MS), 0 },
5549#endif /* CONFIG_FST */
5550 { INT_RANGE(cert_in_cb, 0, 1), 0 },
5551 { INT_RANGE(wpa_rsc_relaxation, 0, 1), 0 },
5552 { STR(sched_scan_plans), CFG_CHANGED_SCHED_SCAN_PLANS },
5553#ifdef CONFIG_MBO
5554 { STR(non_pref_chan), 0 },
5555 { INT_RANGE(mbo_cell_capa, MBO_CELL_CAPA_AVAILABLE,
5556 MBO_CELL_CAPA_NOT_SUPPORTED), 0 },
5557 { INT_RANGE(disassoc_imminent_rssi_threshold, -120, 0), 0 },
5558 { INT_RANGE(oce, 0, 3), 0 },
5559#endif /* CONFIG_MBO */
5560 { INT(gas_address3), 0 },
5561 { INT_RANGE(ftm_responder, 0, 1), 0 },
5562 { INT_RANGE(ftm_initiator, 0, 1), 0 },
5563 { INT(gas_rand_addr_lifetime), 0 },
5564 { INT_RANGE(gas_rand_mac_addr, 0, 2), 0 },
5565#ifdef CONFIG_DPP
5566 { INT_RANGE(dpp_config_processing, 0, 2), 0 },
5567 { STR(dpp_name), 0 },
5568 { STR(dpp_mud_url), 0 },
5569 { STR(dpp_extra_conf_req_name), 0 },
5570 { STR(dpp_extra_conf_req_value), 0 },
5571 { INT_RANGE(dpp_connector_privacy_default, 0, 1), 0 },
5572#endif /* CONFIG_DPP */
5573 { INT_RANGE(coloc_intf_reporting, 0, 1), 0 },
5574#ifdef CONFIG_WNM
5575 { INT_RANGE(disable_btm, 0, 1), CFG_CHANGED_DISABLE_BTM },
5576 { INT_RANGE(extended_key_id, 0, 1), 0 },
5577#endif /* CONFIG_WNM */
5578 { INT_RANGE(wowlan_disconnect_on_deinit, 0, 1), 0},
5579#ifdef CONFIG_PASN
5580#ifdef CONFIG_TESTING_OPTIONS
5581 { INT_RANGE(force_kdk_derivation, 0, 1), 0 },
5582 { INT_RANGE(pasn_corrupt_mic, 0, 1), 0 },
5583#endif /* CONFIG_TESTING_OPTIONS */
5584#endif /* CONFIG_PASN */
5585};
5586
5587#undef FUNC
5588#undef _INT
5589#undef INT
5590#undef INT_RANGE
5591#undef _STR
5592#undef STR
5593#undef STR_RANGE
5594#undef BIN
5595#undef IPV4
5596#define NUM_GLOBAL_FIELDS ARRAY_SIZE(global_fields)
5597
5598
5599int wpa_config_dump_values(struct wpa_config *config, char *buf, size_t buflen)
5600{
5601 int result = 0;
5602 size_t i;
5603
5604 for (i = 0; i < NUM_GLOBAL_FIELDS; i++) {
5605 const struct global_parse_data *field = &global_fields[i];
5606 int tmp;
5607
5608 if (!field->get)
5609 continue;
5610
5611 tmp = field->get(field->name, config, (long) field->param1,
5612 buf, buflen, 1);
5613 if (tmp < 0)
5614 return -1;
5615 buf += tmp;
5616 buflen -= tmp;
5617 result += tmp;
5618 }
5619 return result;
5620}
5621
5622
5623int wpa_config_get_value(const char *name, struct wpa_config *config,
5624 char *buf, size_t buflen)
5625{
5626 size_t i;
5627
5628 for (i = 0; i < NUM_GLOBAL_FIELDS; i++) {
5629 const struct global_parse_data *field = &global_fields[i];
5630
5631 if (os_strcmp(name, field->name) != 0)
5632 continue;
5633 if (!field->get)
5634 break;
5635 return field->get(name, config, (long) field->param1,
5636 buf, buflen, 0);
5637 }
5638
5639 return -1;
5640}
5641
5642
5643int wpa_config_get_num_global_field_names(void)
5644{
5645 return NUM_GLOBAL_FIELDS;
5646}
5647
5648
5649const char * wpa_config_get_global_field_name(unsigned int i, int *no_var)
5650{
5651 if (i >= NUM_GLOBAL_FIELDS)
5652 return NULL;
5653
5654 if (no_var)
5655 *no_var = !global_fields[i].param1;
5656 return global_fields[i].name;
5657}
5658
5659
5660/**
5661 * wpa_config_process_global - Set a variable in global configuration
5662 * @config: Pointer to global configuration data
5663 * @pos: Name and value in the format "{name}={value}"
5664 * @line: Line number in configuration file or 0 if not used
5665 * Returns: 0 on success with a possible change in value, 1 on success with no
5666 * change to previously configured value, or -1 on failure
5667 *
5668 * This function can be used to set global configuration variables based on
5669 * both the configuration file and management interface input. The value
5670 * parameter must be in the same format as the text-based configuration file is
5671 * using. For example, strings are using double quotation marks.
5672 */
5673int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
5674{
5675 size_t i;
5676 int ret = 0;
5677
5678 for (i = 0; i < NUM_GLOBAL_FIELDS; i++) {
5679 const struct global_parse_data *field = &global_fields[i];
5680 size_t flen = os_strlen(field->name);
5681 if (os_strncmp(pos, field->name, flen) != 0 ||
5682 pos[flen] != '=')
5683 continue;
5684
5685 ret = field->parser(field, config, line, pos + flen + 1);
5686 if (ret < 0) {
5687 wpa_printf(MSG_ERROR, "Line %d: failed to "
5688 "parse '%s'.", line, pos);
5689 ret = -1;
5690 }
5691 if (ret == 1)
5692 break;
5693 if (field->changed_flag == CFG_CHANGED_NFC_PASSWORD_TOKEN)
5694 config->wps_nfc_pw_from_config = 1;
5695 config->changed_parameters |= field->changed_flag;
5696 break;
5697 }
5698 if (i == NUM_GLOBAL_FIELDS) {
5699#ifdef CONFIG_AP
5700 if (os_strncmp(pos, "tx_queue_", 9) == 0) {
5701 char *tmp = os_strchr(pos, '=');
5702
5703 if (!tmp) {
5704 if (line < 0)
5705 wpa_printf(MSG_ERROR,
5706 "Line %d: invalid line %s",
5707 line, pos);
5708 return -1;
5709 }
5710 *tmp++ = '\0';
5711 if (hostapd_config_tx_queue(config->tx_queue, pos,
5712 tmp)) {
5713 wpa_printf(MSG_ERROR,
5714 "Line %d: invalid TX queue item",
5715 line);
5716 return -1;
5717 }
5718 }
5719
5720 if (os_strncmp(pos, "wmm_ac_", 7) == 0) {
5721 char *tmp = os_strchr(pos, '=');
5722 if (tmp == NULL) {
5723 if (line < 0)
5724 return -1;
5725 wpa_printf(MSG_ERROR, "Line %d: invalid line "
5726 "'%s'", line, pos);
5727 return -1;
5728 }
5729 *tmp++ = '\0';
5730 if (hostapd_config_wmm_ac(config->wmm_ac_params, pos,
5731 tmp)) {
5732 wpa_printf(MSG_ERROR, "Line %d: invalid WMM "
5733 "AC item", line);
5734 return -1;
5735 }
5736 return ret;
5737 }
5738#endif /* CONFIG_AP */
5739 if (line < 0)
5740 return -1;
5741 wpa_printf(MSG_ERROR, "Line %d: unknown global field '%s'.",
5742 line, pos);
5743 ret = -1;
5744 }
5745
5746 return ret;
5747}