blob: 0d5b28552215dc978373fb2e0961c7bbc534354a [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * WPA Supplicant / Configuration parser and common functions
Hai Shalomc3565922019-10-28 11:58:20 -07003 * Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 */
8
9#include "includes.h"
10
11#include "common.h"
12#include "utils/uuid.h"
Dmitry Shmidtcf32e602014-01-28 10:57:39 -080013#include "utils/ip_addr.h"
Dmitry Shmidt29333592017-01-09 12:27:11 -080014#include "common/ieee802_1x_defs.h"
Hai Shalomc3565922019-10-28 11:58:20 -070015#include "common/sae.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070016#include "crypto/sha1.h"
17#include "rsn_supp/wpa.h"
18#include "eap_peer/eap.h"
Dmitry Shmidt04949592012-07-19 12:16:46 -070019#include "p2p/p2p.h"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080020#include "fst/fst.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070021#include "config.h"
22
23
24#if !defined(CONFIG_CTRL_IFACE) && defined(CONFIG_NO_CONFIG_WRITE)
25#define NO_CONFIG_WRITE
26#endif
27
28/*
29 * Structure for network configuration parsing. This data is used to implement
30 * a generic parser for each network block variable. The table of configuration
31 * variables is defined below in this file (ssid_fields[]).
32 */
33struct parse_data {
34 /* Configuration variable name */
35 char *name;
36
Dmitry Shmidte4663042016-04-04 10:07:49 -070037 /* Parser function for this variable. The parser functions return 0 or 1
38 * to indicate success. Value 0 indicates that the parameter value may
39 * have changed while value 1 means that the value did not change.
40 * Error cases (failure to parse the string) are indicated by returning
41 * -1. */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070042 int (*parser)(const struct parse_data *data, struct wpa_ssid *ssid,
43 int line, const char *value);
44
45#ifndef NO_CONFIG_WRITE
46 /* Writer function (i.e., to get the variable in text format from
47 * internal presentation). */
48 char * (*writer)(const struct parse_data *data, struct wpa_ssid *ssid);
49#endif /* NO_CONFIG_WRITE */
50
51 /* Variable specific parameters for the parser. */
52 void *param1, *param2, *param3, *param4;
53
54 /* 0 = this variable can be included in debug output and ctrl_iface
55 * 1 = this variable contains key/private data and it must not be
56 * included in debug output unless explicitly requested. In
57 * addition, this variable will not be readable through the
58 * ctrl_iface.
59 */
60 int key_data;
61};
62
63
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070064static int wpa_config_parse_str(const struct parse_data *data,
65 struct wpa_ssid *ssid,
66 int line, const char *value)
67{
Dmitry Shmidte4663042016-04-04 10:07:49 -070068 size_t res_len, *dst_len, prev_len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070069 char **dst, *tmp;
70
71 if (os_strcmp(value, "NULL") == 0) {
72 wpa_printf(MSG_DEBUG, "Unset configuration string '%s'",
73 data->name);
74 tmp = NULL;
75 res_len = 0;
76 goto set;
77 }
78
79 tmp = wpa_config_parse_string(value, &res_len);
80 if (tmp == NULL) {
81 wpa_printf(MSG_ERROR, "Line %d: failed to parse %s '%s'.",
82 line, data->name,
83 data->key_data ? "[KEY DATA REMOVED]" : value);
84 return -1;
85 }
86
87 if (data->key_data) {
88 wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
89 (u8 *) tmp, res_len);
90 } else {
91 wpa_hexdump_ascii(MSG_MSGDUMP, data->name,
92 (u8 *) tmp, res_len);
93 }
94
95 if (data->param3 && res_len < (size_t) data->param3) {
96 wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu "
97 "min_len=%ld)", line, data->name,
98 (unsigned long) res_len, (long) data->param3);
99 os_free(tmp);
100 return -1;
101 }
102
103 if (data->param4 && res_len > (size_t) data->param4) {
104 wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu "
105 "max_len=%ld)", line, data->name,
106 (unsigned long) res_len, (long) data->param4);
107 os_free(tmp);
108 return -1;
109 }
110
111set:
112 dst = (char **) (((u8 *) ssid) + (long) data->param1);
113 dst_len = (size_t *) (((u8 *) ssid) + (long) data->param2);
Dmitry Shmidte4663042016-04-04 10:07:49 -0700114
115 if (data->param2)
116 prev_len = *dst_len;
117 else if (*dst)
118 prev_len = os_strlen(*dst);
119 else
120 prev_len = 0;
121 if ((*dst == NULL && tmp == NULL) ||
122 (*dst && tmp && prev_len == res_len &&
123 os_memcmp(*dst, tmp, res_len) == 0)) {
124 /* No change to the previously configured value */
125 os_free(tmp);
126 return 1;
127 }
128
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700129 os_free(*dst);
130 *dst = tmp;
131 if (data->param2)
132 *dst_len = res_len;
133
134 return 0;
135}
136
137
138#ifndef NO_CONFIG_WRITE
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700139static char * wpa_config_write_string_ascii(const u8 *value, size_t len)
140{
141 char *buf;
142
143 buf = os_malloc(len + 3);
144 if (buf == NULL)
145 return NULL;
146 buf[0] = '"';
147 os_memcpy(buf + 1, value, len);
148 buf[len + 1] = '"';
149 buf[len + 2] = '\0';
150
151 return buf;
152}
153
154
155static char * wpa_config_write_string_hex(const u8 *value, size_t len)
156{
157 char *buf;
158
159 buf = os_zalloc(2 * len + 1);
160 if (buf == NULL)
161 return NULL;
162 wpa_snprintf_hex(buf, 2 * len + 1, value, len);
163
164 return buf;
165}
166
167
168static char * wpa_config_write_string(const u8 *value, size_t len)
169{
170 if (value == NULL)
171 return NULL;
172
173 if (is_hex(value, len))
174 return wpa_config_write_string_hex(value, len);
175 else
176 return wpa_config_write_string_ascii(value, len);
177}
178
179
180static char * wpa_config_write_str(const struct parse_data *data,
181 struct wpa_ssid *ssid)
182{
183 size_t len;
184 char **src;
185
186 src = (char **) (((u8 *) ssid) + (long) data->param1);
187 if (*src == NULL)
188 return NULL;
189
190 if (data->param2)
191 len = *((size_t *) (((u8 *) ssid) + (long) data->param2));
192 else
193 len = os_strlen(*src);
194
195 return wpa_config_write_string((const u8 *) *src, len);
196}
197#endif /* NO_CONFIG_WRITE */
198
199
200static int wpa_config_parse_int(const struct parse_data *data,
201 struct wpa_ssid *ssid,
202 int line, const char *value)
203{
Dmitry Shmidt2f023192013-03-12 12:44:17 -0700204 int val, *dst;
205 char *end;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700206
207 dst = (int *) (((u8 *) ssid) + (long) data->param1);
Dmitry Shmidt2f023192013-03-12 12:44:17 -0700208 val = strtol(value, &end, 0);
209 if (*end) {
210 wpa_printf(MSG_ERROR, "Line %d: invalid number \"%s\"",
211 line, value);
212 return -1;
213 }
Dmitry Shmidte4663042016-04-04 10:07:49 -0700214
215 if (*dst == val)
216 return 1;
Dmitry Shmidt2f023192013-03-12 12:44:17 -0700217 *dst = val;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700218 wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst);
219
220 if (data->param3 && *dst < (long) data->param3) {
221 wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d "
222 "min_value=%ld)", line, data->name, *dst,
223 (long) data->param3);
224 *dst = (long) data->param3;
225 return -1;
226 }
227
228 if (data->param4 && *dst > (long) data->param4) {
229 wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d "
230 "max_value=%ld)", line, data->name, *dst,
231 (long) data->param4);
232 *dst = (long) data->param4;
233 return -1;
234 }
235
236 return 0;
237}
238
239
240#ifndef NO_CONFIG_WRITE
241static char * wpa_config_write_int(const struct parse_data *data,
242 struct wpa_ssid *ssid)
243{
244 int *src, res;
245 char *value;
246
247 src = (int *) (((u8 *) ssid) + (long) data->param1);
248
249 value = os_malloc(20);
250 if (value == NULL)
251 return NULL;
252 res = os_snprintf(value, 20, "%d", *src);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800253 if (os_snprintf_error(20, res)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700254 os_free(value);
255 return NULL;
256 }
257 value[20 - 1] = '\0';
258 return value;
259}
260#endif /* NO_CONFIG_WRITE */
261
262
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800263static int wpa_config_parse_addr_list(const struct parse_data *data,
264 int line, const char *value,
265 u8 **list, size_t *num, char *name,
266 u8 abort_on_error, u8 masked)
267{
268 const char *pos;
269 u8 *buf, *n, addr[2 * ETH_ALEN];
270 size_t count;
271
272 buf = NULL;
273 count = 0;
274
275 pos = value;
276 while (pos && *pos) {
277 while (*pos == ' ')
278 pos++;
279
280 if (hwaddr_masked_aton(pos, addr, &addr[ETH_ALEN], masked)) {
281 if (abort_on_error || count == 0) {
282 wpa_printf(MSG_ERROR,
283 "Line %d: Invalid %s address '%s'",
284 line, name, value);
285 os_free(buf);
286 return -1;
287 }
288 /* continue anyway since this could have been from a
289 * truncated configuration file line */
290 wpa_printf(MSG_INFO,
291 "Line %d: Ignore likely truncated %s address '%s'",
292 line, name, pos);
293 } else {
294 n = os_realloc_array(buf, count + 1, 2 * ETH_ALEN);
295 if (n == NULL) {
296 os_free(buf);
297 return -1;
298 }
299 buf = n;
300 os_memmove(buf + 2 * ETH_ALEN, buf,
301 count * 2 * ETH_ALEN);
302 os_memcpy(buf, addr, 2 * ETH_ALEN);
303 count++;
304 wpa_printf(MSG_MSGDUMP,
305 "%s: addr=" MACSTR " mask=" MACSTR,
306 name, MAC2STR(addr),
307 MAC2STR(&addr[ETH_ALEN]));
308 }
309
310 pos = os_strchr(pos, ' ');
311 }
312
313 os_free(*list);
314 *list = buf;
315 *num = count;
316
317 return 0;
318}
319
320
321#ifndef NO_CONFIG_WRITE
322static char * wpa_config_write_addr_list(const struct parse_data *data,
323 const u8 *list, size_t num, char *name)
324{
325 char *value, *end, *pos;
326 int res;
327 size_t i;
328
329 if (list == NULL || num == 0)
330 return NULL;
331
332 value = os_malloc(2 * 20 * num);
333 if (value == NULL)
334 return NULL;
335 pos = value;
336 end = value + 2 * 20 * num;
337
338 for (i = num; i > 0; i--) {
339 const u8 *a = list + (i - 1) * 2 * ETH_ALEN;
340 const u8 *m = a + ETH_ALEN;
341
342 if (i < num)
343 *pos++ = ' ';
344 res = hwaddr_mask_txt(pos, end - pos, a, m);
345 if (res < 0) {
346 os_free(value);
347 return NULL;
348 }
349 pos += res;
350 }
351
352 return value;
353}
354#endif /* NO_CONFIG_WRITE */
355
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700356static int wpa_config_parse_bssid(const struct parse_data *data,
357 struct wpa_ssid *ssid, int line,
358 const char *value)
359{
360 if (value[0] == '\0' || os_strcmp(value, "\"\"") == 0 ||
361 os_strcmp(value, "any") == 0) {
362 ssid->bssid_set = 0;
363 wpa_printf(MSG_MSGDUMP, "BSSID any");
364 return 0;
365 }
366 if (hwaddr_aton(value, ssid->bssid)) {
367 wpa_printf(MSG_ERROR, "Line %d: Invalid BSSID '%s'.",
368 line, value);
369 return -1;
370 }
371 ssid->bssid_set = 1;
372 wpa_hexdump(MSG_MSGDUMP, "BSSID", ssid->bssid, ETH_ALEN);
373 return 0;
374}
375
376
377#ifndef NO_CONFIG_WRITE
378static char * wpa_config_write_bssid(const struct parse_data *data,
379 struct wpa_ssid *ssid)
380{
381 char *value;
382 int res;
383
384 if (!ssid->bssid_set)
385 return NULL;
386
387 value = os_malloc(20);
388 if (value == NULL)
389 return NULL;
390 res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->bssid));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800391 if (os_snprintf_error(20, res)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700392 os_free(value);
393 return NULL;
394 }
395 value[20 - 1] = '\0';
396 return value;
397}
398#endif /* NO_CONFIG_WRITE */
399
400
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700401static int wpa_config_parse_bssid_hint(const struct parse_data *data,
402 struct wpa_ssid *ssid, int line,
403 const char *value)
404{
405 if (value[0] == '\0' || os_strcmp(value, "\"\"") == 0 ||
406 os_strcmp(value, "any") == 0) {
407 ssid->bssid_hint_set = 0;
408 wpa_printf(MSG_MSGDUMP, "BSSID hint any");
409 return 0;
410 }
411 if (hwaddr_aton(value, ssid->bssid_hint)) {
412 wpa_printf(MSG_ERROR, "Line %d: Invalid BSSID hint '%s'.",
413 line, value);
414 return -1;
415 }
416 ssid->bssid_hint_set = 1;
417 wpa_hexdump(MSG_MSGDUMP, "BSSID hint", ssid->bssid_hint, ETH_ALEN);
418 return 0;
419}
420
421
422#ifndef NO_CONFIG_WRITE
423static char * wpa_config_write_bssid_hint(const struct parse_data *data,
424 struct wpa_ssid *ssid)
425{
426 char *value;
427 int res;
428
429 if (!ssid->bssid_hint_set)
430 return NULL;
431
432 value = os_malloc(20);
433 if (!value)
434 return NULL;
435 res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->bssid_hint));
436 if (os_snprintf_error(20, res)) {
437 os_free(value);
438 return NULL;
439 }
440 return value;
441}
442#endif /* NO_CONFIG_WRITE */
443
444
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800445static int wpa_config_parse_bssid_blacklist(const struct parse_data *data,
446 struct wpa_ssid *ssid, int line,
447 const char *value)
448{
449 return wpa_config_parse_addr_list(data, line, value,
450 &ssid->bssid_blacklist,
451 &ssid->num_bssid_blacklist,
452 "bssid_blacklist", 1, 1);
453}
454
455
456#ifndef NO_CONFIG_WRITE
457static char * wpa_config_write_bssid_blacklist(const struct parse_data *data,
458 struct wpa_ssid *ssid)
459{
460 return wpa_config_write_addr_list(data, ssid->bssid_blacklist,
461 ssid->num_bssid_blacklist,
462 "bssid_blacklist");
463}
464#endif /* NO_CONFIG_WRITE */
465
466
467static int wpa_config_parse_bssid_whitelist(const struct parse_data *data,
468 struct wpa_ssid *ssid, int line,
469 const char *value)
470{
471 return wpa_config_parse_addr_list(data, line, value,
472 &ssid->bssid_whitelist,
473 &ssid->num_bssid_whitelist,
474 "bssid_whitelist", 1, 1);
475}
476
477
478#ifndef NO_CONFIG_WRITE
479static char * wpa_config_write_bssid_whitelist(const struct parse_data *data,
480 struct wpa_ssid *ssid)
481{
482 return wpa_config_write_addr_list(data, ssid->bssid_whitelist,
483 ssid->num_bssid_whitelist,
484 "bssid_whitelist");
485}
486#endif /* NO_CONFIG_WRITE */
487
488
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700489static int wpa_config_parse_psk(const struct parse_data *data,
490 struct wpa_ssid *ssid, int line,
491 const char *value)
492{
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700493#ifdef CONFIG_EXT_PASSWORD
494 if (os_strncmp(value, "ext:", 4) == 0) {
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700495 str_clear_free(ssid->passphrase);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700496 ssid->passphrase = NULL;
497 ssid->psk_set = 0;
498 os_free(ssid->ext_psk);
499 ssid->ext_psk = os_strdup(value + 4);
500 if (ssid->ext_psk == NULL)
501 return -1;
502 wpa_printf(MSG_DEBUG, "PSK: External password '%s'",
503 ssid->ext_psk);
504 return 0;
505 }
506#endif /* CONFIG_EXT_PASSWORD */
507
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700508 if (*value == '"') {
509#ifndef CONFIG_NO_PBKDF2
510 const char *pos;
511 size_t len;
512
513 value++;
514 pos = os_strrchr(value, '"');
515 if (pos)
516 len = pos - value;
517 else
518 len = os_strlen(value);
519 if (len < 8 || len > 63) {
520 wpa_printf(MSG_ERROR, "Line %d: Invalid passphrase "
521 "length %lu (expected: 8..63) '%s'.",
522 line, (unsigned long) len, value);
523 return -1;
524 }
525 wpa_hexdump_ascii_key(MSG_MSGDUMP, "PSK (ASCII passphrase)",
526 (u8 *) value, len);
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700527 if (has_ctrl_char((u8 *) value, len)) {
528 wpa_printf(MSG_ERROR,
529 "Line %d: Invalid passphrase character",
530 line);
531 return -1;
532 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700533 if (ssid->passphrase && os_strlen(ssid->passphrase) == len &&
Dmitry Shmidte4663042016-04-04 10:07:49 -0700534 os_memcmp(ssid->passphrase, value, len) == 0) {
535 /* No change to the previously configured value */
536 return 1;
537 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700538 ssid->psk_set = 0;
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700539 str_clear_free(ssid->passphrase);
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700540 ssid->passphrase = dup_binstr(value, len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700541 if (ssid->passphrase == NULL)
542 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700543 return 0;
544#else /* CONFIG_NO_PBKDF2 */
545 wpa_printf(MSG_ERROR, "Line %d: ASCII passphrase not "
546 "supported.", line);
547 return -1;
548#endif /* CONFIG_NO_PBKDF2 */
549 }
550
551 if (hexstr2bin(value, ssid->psk, PMK_LEN) ||
552 value[PMK_LEN * 2] != '\0') {
553 wpa_printf(MSG_ERROR, "Line %d: Invalid PSK '%s'.",
554 line, value);
555 return -1;
556 }
557
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700558 str_clear_free(ssid->passphrase);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700559 ssid->passphrase = NULL;
560
561 ssid->psk_set = 1;
562 wpa_hexdump_key(MSG_MSGDUMP, "PSK", ssid->psk, PMK_LEN);
563 return 0;
564}
565
566
567#ifndef NO_CONFIG_WRITE
568static char * wpa_config_write_psk(const struct parse_data *data,
569 struct wpa_ssid *ssid)
570{
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700571#ifdef CONFIG_EXT_PASSWORD
572 if (ssid->ext_psk) {
573 size_t len = 4 + os_strlen(ssid->ext_psk) + 1;
574 char *buf = os_malloc(len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800575 int res;
576
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700577 if (buf == NULL)
578 return NULL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800579 res = os_snprintf(buf, len, "ext:%s", ssid->ext_psk);
580 if (os_snprintf_error(len, res)) {
581 os_free(buf);
582 buf = NULL;
583 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700584 return buf;
585 }
586#endif /* CONFIG_EXT_PASSWORD */
587
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700588 if (ssid->passphrase)
589 return wpa_config_write_string_ascii(
590 (const u8 *) ssid->passphrase,
591 os_strlen(ssid->passphrase));
592
593 if (ssid->psk_set)
594 return wpa_config_write_string_hex(ssid->psk, PMK_LEN);
595
596 return NULL;
597}
598#endif /* NO_CONFIG_WRITE */
599
600
601static int wpa_config_parse_proto(const struct parse_data *data,
602 struct wpa_ssid *ssid, int line,
603 const char *value)
604{
605 int val = 0, last, errors = 0;
606 char *start, *end, *buf;
607
608 buf = os_strdup(value);
609 if (buf == NULL)
610 return -1;
611 start = buf;
612
613 while (*start != '\0') {
614 while (*start == ' ' || *start == '\t')
615 start++;
616 if (*start == '\0')
617 break;
618 end = start;
619 while (*end != ' ' && *end != '\t' && *end != '\0')
620 end++;
621 last = *end == '\0';
622 *end = '\0';
623 if (os_strcmp(start, "WPA") == 0)
624 val |= WPA_PROTO_WPA;
625 else if (os_strcmp(start, "RSN") == 0 ||
626 os_strcmp(start, "WPA2") == 0)
627 val |= WPA_PROTO_RSN;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800628 else if (os_strcmp(start, "OSEN") == 0)
629 val |= WPA_PROTO_OSEN;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700630 else {
631 wpa_printf(MSG_ERROR, "Line %d: invalid proto '%s'",
632 line, start);
633 errors++;
634 }
635
636 if (last)
637 break;
638 start = end + 1;
639 }
640 os_free(buf);
641
642 if (val == 0) {
643 wpa_printf(MSG_ERROR,
644 "Line %d: no proto values configured.", line);
645 errors++;
646 }
647
Dmitry Shmidte4663042016-04-04 10:07:49 -0700648 if (!errors && ssid->proto == val)
649 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700650 wpa_printf(MSG_MSGDUMP, "proto: 0x%x", val);
651 ssid->proto = val;
652 return errors ? -1 : 0;
653}
654
655
656#ifndef NO_CONFIG_WRITE
657static char * wpa_config_write_proto(const struct parse_data *data,
658 struct wpa_ssid *ssid)
659{
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700660 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700661 char *buf, *pos, *end;
662
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -0800663 pos = buf = os_zalloc(20);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700664 if (buf == NULL)
665 return NULL;
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -0800666 end = buf + 20;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700667
668 if (ssid->proto & WPA_PROTO_WPA) {
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700669 ret = os_snprintf(pos, end - pos, "%sWPA",
670 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800671 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700672 return buf;
673 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700674 }
675
676 if (ssid->proto & WPA_PROTO_RSN) {
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700677 ret = os_snprintf(pos, end - pos, "%sRSN",
678 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800679 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700680 return buf;
681 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700682 }
683
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -0800684 if (ssid->proto & WPA_PROTO_OSEN) {
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700685 ret = os_snprintf(pos, end - pos, "%sOSEN",
686 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800687 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -0800688 return buf;
689 pos += ret;
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700690 }
691
692 if (pos == buf) {
693 os_free(buf);
694 buf = NULL;
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -0800695 }
696
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700697 return buf;
698}
699#endif /* NO_CONFIG_WRITE */
700
701
702static int wpa_config_parse_key_mgmt(const struct parse_data *data,
703 struct wpa_ssid *ssid, int line,
704 const char *value)
705{
706 int val = 0, last, errors = 0;
707 char *start, *end, *buf;
708
709 buf = os_strdup(value);
710 if (buf == NULL)
711 return -1;
712 start = buf;
713
714 while (*start != '\0') {
715 while (*start == ' ' || *start == '\t')
716 start++;
717 if (*start == '\0')
718 break;
719 end = start;
720 while (*end != ' ' && *end != '\t' && *end != '\0')
721 end++;
722 last = *end == '\0';
723 *end = '\0';
724 if (os_strcmp(start, "WPA-PSK") == 0)
725 val |= WPA_KEY_MGMT_PSK;
726 else if (os_strcmp(start, "WPA-EAP") == 0)
727 val |= WPA_KEY_MGMT_IEEE8021X;
728 else if (os_strcmp(start, "IEEE8021X") == 0)
729 val |= WPA_KEY_MGMT_IEEE8021X_NO_WPA;
730 else if (os_strcmp(start, "NONE") == 0)
731 val |= WPA_KEY_MGMT_NONE;
732 else if (os_strcmp(start, "WPA-NONE") == 0)
733 val |= WPA_KEY_MGMT_WPA_NONE;
734#ifdef CONFIG_IEEE80211R
735 else if (os_strcmp(start, "FT-PSK") == 0)
736 val |= WPA_KEY_MGMT_FT_PSK;
737 else if (os_strcmp(start, "FT-EAP") == 0)
738 val |= WPA_KEY_MGMT_FT_IEEE8021X;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700739#ifdef CONFIG_SHA384
740 else if (os_strcmp(start, "FT-EAP-SHA384") == 0)
741 val |= WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
742#endif /* CONFIG_SHA384 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700743#endif /* CONFIG_IEEE80211R */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700744 else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
745 val |= WPA_KEY_MGMT_PSK_SHA256;
746 else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
747 val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700748#ifdef CONFIG_WPS
749 else if (os_strcmp(start, "WPS") == 0)
750 val |= WPA_KEY_MGMT_WPS;
751#endif /* CONFIG_WPS */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800752#ifdef CONFIG_SAE
753 else if (os_strcmp(start, "SAE") == 0)
754 val |= WPA_KEY_MGMT_SAE;
755 else if (os_strcmp(start, "FT-SAE") == 0)
756 val |= WPA_KEY_MGMT_FT_SAE;
757#endif /* CONFIG_SAE */
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800758#ifdef CONFIG_HS20
759 else if (os_strcmp(start, "OSEN") == 0)
760 val |= WPA_KEY_MGMT_OSEN;
761#endif /* CONFIG_HS20 */
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800762#ifdef CONFIG_SUITEB
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800763 else if (os_strcmp(start, "WPA-EAP-SUITE-B") == 0)
764 val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B;
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800765#endif /* CONFIG_SUITEB */
766#ifdef CONFIG_SUITEB192
767 else if (os_strcmp(start, "WPA-EAP-SUITE-B-192") == 0)
768 val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
769#endif /* CONFIG_SUITEB192 */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800770#ifdef CONFIG_FILS
771 else if (os_strcmp(start, "FILS-SHA256") == 0)
772 val |= WPA_KEY_MGMT_FILS_SHA256;
773 else if (os_strcmp(start, "FILS-SHA384") == 0)
774 val |= WPA_KEY_MGMT_FILS_SHA384;
775#ifdef CONFIG_IEEE80211R
776 else if (os_strcmp(start, "FT-FILS-SHA256") == 0)
777 val |= WPA_KEY_MGMT_FT_FILS_SHA256;
778 else if (os_strcmp(start, "FT-FILS-SHA384") == 0)
779 val |= WPA_KEY_MGMT_FT_FILS_SHA384;
780#endif /* CONFIG_IEEE80211R */
781#endif /* CONFIG_FILS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700782#ifdef CONFIG_OWE
783 else if (os_strcmp(start, "OWE") == 0)
784 val |= WPA_KEY_MGMT_OWE;
785#endif /* CONFIG_OWE */
786#ifdef CONFIG_DPP
787 else if (os_strcmp(start, "DPP") == 0)
788 val |= WPA_KEY_MGMT_DPP;
789#endif /* CONFIG_DPP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700790 else {
791 wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
792 line, start);
793 errors++;
794 }
795
796 if (last)
797 break;
798 start = end + 1;
799 }
800 os_free(buf);
801
802 if (val == 0) {
803 wpa_printf(MSG_ERROR,
804 "Line %d: no key_mgmt values configured.", line);
805 errors++;
806 }
807
Dmitry Shmidte4663042016-04-04 10:07:49 -0700808 if (!errors && ssid->key_mgmt == val)
809 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700810 wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", val);
811 ssid->key_mgmt = val;
812 return errors ? -1 : 0;
813}
814
815
816#ifndef NO_CONFIG_WRITE
817static char * wpa_config_write_key_mgmt(const struct parse_data *data,
818 struct wpa_ssid *ssid)
819{
820 char *buf, *pos, *end;
821 int ret;
822
Dmitry Shmidt96571392013-10-14 12:54:46 -0700823 pos = buf = os_zalloc(100);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700824 if (buf == NULL)
825 return NULL;
Dmitry Shmidt96571392013-10-14 12:54:46 -0700826 end = buf + 100;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700827
828 if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
829 ret = os_snprintf(pos, end - pos, "%sWPA-PSK",
830 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800831 if (os_snprintf_error(end - pos, ret)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700832 end[-1] = '\0';
833 return buf;
834 }
835 pos += ret;
836 }
837
838 if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
839 ret = os_snprintf(pos, end - pos, "%sWPA-EAP",
840 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800841 if (os_snprintf_error(end - pos, ret)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700842 end[-1] = '\0';
843 return buf;
844 }
845 pos += ret;
846 }
847
848 if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
849 ret = os_snprintf(pos, end - pos, "%sIEEE8021X",
850 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800851 if (os_snprintf_error(end - pos, ret)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700852 end[-1] = '\0';
853 return buf;
854 }
855 pos += ret;
856 }
857
858 if (ssid->key_mgmt & WPA_KEY_MGMT_NONE) {
859 ret = os_snprintf(pos, end - pos, "%sNONE",
860 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800861 if (os_snprintf_error(end - pos, ret)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700862 end[-1] = '\0';
863 return buf;
864 }
865 pos += ret;
866 }
867
868 if (ssid->key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
869 ret = os_snprintf(pos, end - pos, "%sWPA-NONE",
870 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800871 if (os_snprintf_error(end - pos, ret)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700872 end[-1] = '\0';
873 return buf;
874 }
875 pos += ret;
876 }
877
878#ifdef CONFIG_IEEE80211R
Dmitry Shmidt96571392013-10-14 12:54:46 -0700879 if (ssid->key_mgmt & WPA_KEY_MGMT_FT_PSK) {
880 ret = os_snprintf(pos, end - pos, "%sFT-PSK",
881 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800882 if (os_snprintf_error(end - pos, ret)) {
Dmitry Shmidt96571392013-10-14 12:54:46 -0700883 end[-1] = '\0';
884 return buf;
885 }
886 pos += ret;
887 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700888
Dmitry Shmidt96571392013-10-14 12:54:46 -0700889 if (ssid->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
890 ret = os_snprintf(pos, end - pos, "%sFT-EAP",
891 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800892 if (os_snprintf_error(end - pos, ret)) {
Dmitry Shmidt96571392013-10-14 12:54:46 -0700893 end[-1] = '\0';
894 return buf;
895 }
896 pos += ret;
897 }
Roshan Pius3a1667e2018-07-03 15:17:14 -0700898
899#ifdef CONFIG_SHA384
900 if (ssid->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
901 ret = os_snprintf(pos, end - pos, "%sFT-EAP-SHA384",
902 pos == buf ? "" : " ");
903 if (os_snprintf_error(end - pos, ret)) {
904 end[-1] = '\0';
905 return buf;
906 }
907 pos += ret;
908 }
909#endif /* CONFIG_SHA384 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700910#endif /* CONFIG_IEEE80211R */
911
Dmitry Shmidt96571392013-10-14 12:54:46 -0700912 if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
913 ret = os_snprintf(pos, end - pos, "%sWPA-PSK-SHA256",
914 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800915 if (os_snprintf_error(end - pos, ret)) {
Dmitry Shmidt96571392013-10-14 12:54:46 -0700916 end[-1] = '\0';
917 return buf;
918 }
919 pos += ret;
920 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700921
Dmitry Shmidt96571392013-10-14 12:54:46 -0700922 if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
923 ret = os_snprintf(pos, end - pos, "%sWPA-EAP-SHA256",
924 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800925 if (os_snprintf_error(end - pos, ret)) {
Dmitry Shmidt96571392013-10-14 12:54:46 -0700926 end[-1] = '\0';
927 return buf;
928 }
929 pos += ret;
930 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700931
932#ifdef CONFIG_WPS
Dmitry Shmidt96571392013-10-14 12:54:46 -0700933 if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
934 ret = os_snprintf(pos, end - pos, "%sWPS",
935 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800936 if (os_snprintf_error(end - pos, ret)) {
Dmitry Shmidt96571392013-10-14 12:54:46 -0700937 end[-1] = '\0';
938 return buf;
939 }
940 pos += ret;
941 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700942#endif /* CONFIG_WPS */
943
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800944#ifdef CONFIG_SAE
945 if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
946 ret = os_snprintf(pos, end - pos, "%sSAE",
947 pos == buf ? "" : " ");
948 if (os_snprintf_error(end - pos, ret)) {
949 end[-1] = '\0';
950 return buf;
951 }
952 pos += ret;
953 }
954
955 if (ssid->key_mgmt & WPA_KEY_MGMT_FT_SAE) {
956 ret = os_snprintf(pos, end - pos, "%sFT-SAE",
957 pos == buf ? "" : " ");
958 if (os_snprintf_error(end - pos, ret)) {
959 end[-1] = '\0';
960 return buf;
961 }
962 pos += ret;
963 }
964#endif /* CONFIG_SAE */
965
966#ifdef CONFIG_HS20
967 if (ssid->key_mgmt & WPA_KEY_MGMT_OSEN) {
968 ret = os_snprintf(pos, end - pos, "%sOSEN",
969 pos == buf ? "" : " ");
970 if (os_snprintf_error(end - pos, ret)) {
971 end[-1] = '\0';
972 return buf;
973 }
974 pos += ret;
975 }
976#endif /* CONFIG_HS20 */
977
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800978#ifdef CONFIG_SUITEB
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800979 if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
980 ret = os_snprintf(pos, end - pos, "%sWPA-EAP-SUITE-B",
981 pos == buf ? "" : " ");
982 if (os_snprintf_error(end - pos, ret)) {
983 end[-1] = '\0';
984 return buf;
985 }
986 pos += ret;
987 }
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800988#endif /* CONFIG_SUITEB */
989
990#ifdef CONFIG_SUITEB192
991 if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
992 ret = os_snprintf(pos, end - pos, "%sWPA-EAP-SUITE-B-192",
993 pos == buf ? "" : " ");
994 if (os_snprintf_error(end - pos, ret)) {
995 end[-1] = '\0';
996 return buf;
997 }
998 pos += ret;
999 }
1000#endif /* CONFIG_SUITEB192 */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001001
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001002#ifdef CONFIG_FILS
1003 if (ssid->key_mgmt & WPA_KEY_MGMT_FILS_SHA256) {
1004 ret = os_snprintf(pos, end - pos, "%sFILS-SHA256",
1005 pos == buf ? "" : " ");
1006 if (os_snprintf_error(end - pos, ret)) {
1007 end[-1] = '\0';
1008 return buf;
1009 }
1010 pos += ret;
1011 }
1012 if (ssid->key_mgmt & WPA_KEY_MGMT_FILS_SHA384) {
1013 ret = os_snprintf(pos, end - pos, "%sFILS-SHA384",
1014 pos == buf ? "" : " ");
1015 if (os_snprintf_error(end - pos, ret)) {
1016 end[-1] = '\0';
1017 return buf;
1018 }
1019 pos += ret;
1020 }
1021#ifdef CONFIG_IEEE80211R
1022 if (ssid->key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) {
1023 ret = os_snprintf(pos, end - pos, "%sFT-FILS-SHA256",
1024 pos == buf ? "" : " ");
1025 if (os_snprintf_error(end - pos, ret)) {
1026 end[-1] = '\0';
1027 return buf;
1028 }
1029 pos += ret;
1030 }
1031 if (ssid->key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) {
1032 ret = os_snprintf(pos, end - pos, "%sFT-FILS-SHA384",
1033 pos == buf ? "" : " ");
1034 if (os_snprintf_error(end - pos, ret)) {
1035 end[-1] = '\0';
1036 return buf;
1037 }
1038 pos += ret;
1039 }
1040#endif /* CONFIG_IEEE80211R */
1041#endif /* CONFIG_FILS */
1042
Hai Shalom74f70d42019-02-11 14:42:39 -08001043#ifdef CONFIG_DPP
1044 if (ssid->key_mgmt & WPA_KEY_MGMT_DPP) {
1045 ret = os_snprintf(pos, end - pos, "%sDPP",
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_DPP */
1054
1055#ifdef CONFIG_OWE
1056 if (ssid->key_mgmt & WPA_KEY_MGMT_OWE) {
1057 ret = os_snprintf(pos, end - pos, "%sOWE",
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_OWE */
1066
Dmitry Shmidtc2817022014-07-02 10:32:10 -07001067 if (pos == buf) {
1068 os_free(buf);
1069 buf = NULL;
1070 }
1071
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001072 return buf;
1073}
1074#endif /* NO_CONFIG_WRITE */
1075
1076
1077static int wpa_config_parse_cipher(int line, const char *value)
1078{
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001079#ifdef CONFIG_NO_WPA
1080 return -1;
1081#else /* CONFIG_NO_WPA */
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001082 int val = wpa_parse_cipher(value);
1083 if (val < 0) {
1084 wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
1085 line, value);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001086 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001087 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001088 if (val == 0) {
1089 wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.",
1090 line);
1091 return -1;
1092 }
1093 return val;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001094#endif /* CONFIG_NO_WPA */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001095}
1096
1097
1098#ifndef NO_CONFIG_WRITE
1099static char * wpa_config_write_cipher(int cipher)
1100{
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001101#ifdef CONFIG_NO_WPA
1102 return NULL;
1103#else /* CONFIG_NO_WPA */
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001104 char *buf = os_zalloc(50);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001105 if (buf == NULL)
1106 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001107
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001108 if (wpa_write_ciphers(buf, buf + 50, cipher, " ") < 0) {
1109 os_free(buf);
1110 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001111 }
1112
1113 return buf;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001114#endif /* CONFIG_NO_WPA */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001115}
1116#endif /* NO_CONFIG_WRITE */
1117
1118
1119static int wpa_config_parse_pairwise(const struct parse_data *data,
1120 struct wpa_ssid *ssid, int line,
1121 const char *value)
1122{
1123 int val;
1124 val = wpa_config_parse_cipher(line, value);
1125 if (val == -1)
1126 return -1;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001127 if (val & ~WPA_ALLOWED_PAIRWISE_CIPHERS) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001128 wpa_printf(MSG_ERROR, "Line %d: not allowed pairwise cipher "
1129 "(0x%x).", line, val);
1130 return -1;
1131 }
1132
Dmitry Shmidte4663042016-04-04 10:07:49 -07001133 if (ssid->pairwise_cipher == val)
1134 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001135 wpa_printf(MSG_MSGDUMP, "pairwise: 0x%x", val);
1136 ssid->pairwise_cipher = val;
1137 return 0;
1138}
1139
1140
1141#ifndef NO_CONFIG_WRITE
1142static char * wpa_config_write_pairwise(const struct parse_data *data,
1143 struct wpa_ssid *ssid)
1144{
1145 return wpa_config_write_cipher(ssid->pairwise_cipher);
1146}
1147#endif /* NO_CONFIG_WRITE */
1148
1149
1150static int wpa_config_parse_group(const struct parse_data *data,
1151 struct wpa_ssid *ssid, int line,
1152 const char *value)
1153{
1154 int val;
1155 val = wpa_config_parse_cipher(line, value);
1156 if (val == -1)
1157 return -1;
Dmitry Shmidt41712582015-06-29 11:02:15 -07001158
1159 /*
1160 * Backwards compatibility - filter out WEP ciphers that were previously
1161 * allowed.
1162 */
1163 val &= ~(WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40);
1164
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001165 if (val & ~WPA_ALLOWED_GROUP_CIPHERS) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001166 wpa_printf(MSG_ERROR, "Line %d: not allowed group cipher "
1167 "(0x%x).", line, val);
1168 return -1;
1169 }
1170
Dmitry Shmidte4663042016-04-04 10:07:49 -07001171 if (ssid->group_cipher == val)
1172 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001173 wpa_printf(MSG_MSGDUMP, "group: 0x%x", val);
1174 ssid->group_cipher = val;
1175 return 0;
1176}
1177
1178
1179#ifndef NO_CONFIG_WRITE
1180static char * wpa_config_write_group(const struct parse_data *data,
1181 struct wpa_ssid *ssid)
1182{
1183 return wpa_config_write_cipher(ssid->group_cipher);
1184}
1185#endif /* NO_CONFIG_WRITE */
1186
1187
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001188static int wpa_config_parse_group_mgmt(const struct parse_data *data,
1189 struct wpa_ssid *ssid, int line,
1190 const char *value)
1191{
1192 int val;
1193
1194 val = wpa_config_parse_cipher(line, value);
1195 if (val == -1)
1196 return -1;
1197
1198 if (val & ~WPA_ALLOWED_GROUP_MGMT_CIPHERS) {
1199 wpa_printf(MSG_ERROR,
1200 "Line %d: not allowed group management cipher (0x%x).",
1201 line, val);
1202 return -1;
1203 }
1204
1205 if (ssid->group_mgmt_cipher == val)
1206 return 1;
1207 wpa_printf(MSG_MSGDUMP, "group_mgmt: 0x%x", val);
1208 ssid->group_mgmt_cipher = val;
1209 return 0;
1210}
1211
1212
1213#ifndef NO_CONFIG_WRITE
1214static char * wpa_config_write_group_mgmt(const struct parse_data *data,
1215 struct wpa_ssid *ssid)
1216{
1217 return wpa_config_write_cipher(ssid->group_mgmt_cipher);
1218}
1219#endif /* NO_CONFIG_WRITE */
1220
1221
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001222static int wpa_config_parse_auth_alg(const struct parse_data *data,
1223 struct wpa_ssid *ssid, int line,
1224 const char *value)
1225{
1226 int val = 0, last, errors = 0;
1227 char *start, *end, *buf;
1228
1229 buf = os_strdup(value);
1230 if (buf == NULL)
1231 return -1;
1232 start = buf;
1233
1234 while (*start != '\0') {
1235 while (*start == ' ' || *start == '\t')
1236 start++;
1237 if (*start == '\0')
1238 break;
1239 end = start;
1240 while (*end != ' ' && *end != '\t' && *end != '\0')
1241 end++;
1242 last = *end == '\0';
1243 *end = '\0';
1244 if (os_strcmp(start, "OPEN") == 0)
1245 val |= WPA_AUTH_ALG_OPEN;
1246 else if (os_strcmp(start, "SHARED") == 0)
1247 val |= WPA_AUTH_ALG_SHARED;
1248 else if (os_strcmp(start, "LEAP") == 0)
1249 val |= WPA_AUTH_ALG_LEAP;
1250 else {
1251 wpa_printf(MSG_ERROR, "Line %d: invalid auth_alg '%s'",
1252 line, start);
1253 errors++;
1254 }
1255
1256 if (last)
1257 break;
1258 start = end + 1;
1259 }
1260 os_free(buf);
1261
1262 if (val == 0) {
1263 wpa_printf(MSG_ERROR,
1264 "Line %d: no auth_alg values configured.", line);
1265 errors++;
1266 }
1267
Dmitry Shmidte4663042016-04-04 10:07:49 -07001268 if (!errors && ssid->auth_alg == val)
1269 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001270 wpa_printf(MSG_MSGDUMP, "auth_alg: 0x%x", val);
1271 ssid->auth_alg = val;
1272 return errors ? -1 : 0;
1273}
1274
1275
1276#ifndef NO_CONFIG_WRITE
1277static char * wpa_config_write_auth_alg(const struct parse_data *data,
1278 struct wpa_ssid *ssid)
1279{
1280 char *buf, *pos, *end;
1281 int ret;
1282
1283 pos = buf = os_zalloc(30);
1284 if (buf == NULL)
1285 return NULL;
1286 end = buf + 30;
1287
1288 if (ssid->auth_alg & WPA_AUTH_ALG_OPEN) {
1289 ret = os_snprintf(pos, end - pos, "%sOPEN",
1290 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001291 if (os_snprintf_error(end - pos, ret)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001292 end[-1] = '\0';
1293 return buf;
1294 }
1295 pos += ret;
1296 }
1297
1298 if (ssid->auth_alg & WPA_AUTH_ALG_SHARED) {
1299 ret = os_snprintf(pos, end - pos, "%sSHARED",
1300 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001301 if (os_snprintf_error(end - pos, ret)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001302 end[-1] = '\0';
1303 return buf;
1304 }
1305 pos += ret;
1306 }
1307
1308 if (ssid->auth_alg & WPA_AUTH_ALG_LEAP) {
1309 ret = os_snprintf(pos, end - pos, "%sLEAP",
1310 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001311 if (os_snprintf_error(end - pos, ret)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001312 end[-1] = '\0';
1313 return buf;
1314 }
1315 pos += ret;
1316 }
1317
Dmitry Shmidtc2817022014-07-02 10:32:10 -07001318 if (pos == buf) {
1319 os_free(buf);
1320 buf = NULL;
1321 }
1322
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001323 return buf;
1324}
1325#endif /* NO_CONFIG_WRITE */
1326
1327
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001328static int * wpa_config_parse_int_array(const char *value)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001329{
1330 int *freqs;
1331 size_t used, len;
1332 const char *pos;
1333
1334 used = 0;
1335 len = 10;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001336 freqs = os_calloc(len + 1, sizeof(int));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001337 if (freqs == NULL)
1338 return NULL;
1339
1340 pos = value;
1341 while (pos) {
1342 while (*pos == ' ')
1343 pos++;
1344 if (used == len) {
1345 int *n;
1346 size_t i;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001347 n = os_realloc_array(freqs, len * 2 + 1, sizeof(int));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001348 if (n == NULL) {
1349 os_free(freqs);
1350 return NULL;
1351 }
1352 for (i = len; i <= len * 2; i++)
1353 n[i] = 0;
1354 freqs = n;
1355 len *= 2;
1356 }
1357
1358 freqs[used] = atoi(pos);
1359 if (freqs[used] == 0)
1360 break;
1361 used++;
1362 pos = os_strchr(pos + 1, ' ');
1363 }
1364
1365 return freqs;
1366}
1367
1368
1369static int wpa_config_parse_scan_freq(const struct parse_data *data,
1370 struct wpa_ssid *ssid, int line,
1371 const char *value)
1372{
1373 int *freqs;
1374
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001375 freqs = wpa_config_parse_int_array(value);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001376 if (freqs == NULL)
1377 return -1;
Dmitry Shmidt56052862013-10-04 10:23:25 -07001378 if (freqs[0] == 0) {
1379 os_free(freqs);
1380 freqs = NULL;
1381 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001382 os_free(ssid->scan_freq);
1383 ssid->scan_freq = freqs;
1384
1385 return 0;
1386}
1387
1388
1389static int wpa_config_parse_freq_list(const struct parse_data *data,
1390 struct wpa_ssid *ssid, int line,
1391 const char *value)
1392{
1393 int *freqs;
1394
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001395 freqs = wpa_config_parse_int_array(value);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001396 if (freqs == NULL)
1397 return -1;
Dmitry Shmidt56052862013-10-04 10:23:25 -07001398 if (freqs[0] == 0) {
1399 os_free(freqs);
1400 freqs = NULL;
1401 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001402 os_free(ssid->freq_list);
1403 ssid->freq_list = freqs;
1404
1405 return 0;
1406}
1407
1408
1409#ifndef NO_CONFIG_WRITE
1410static char * wpa_config_write_freqs(const struct parse_data *data,
1411 const int *freqs)
1412{
1413 char *buf, *pos, *end;
1414 int i, ret;
1415 size_t count;
1416
1417 if (freqs == NULL)
1418 return NULL;
1419
1420 count = 0;
1421 for (i = 0; freqs[i]; i++)
1422 count++;
1423
1424 pos = buf = os_zalloc(10 * count + 1);
1425 if (buf == NULL)
1426 return NULL;
1427 end = buf + 10 * count + 1;
1428
1429 for (i = 0; freqs[i]; i++) {
1430 ret = os_snprintf(pos, end - pos, "%s%u",
1431 i == 0 ? "" : " ", freqs[i]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001432 if (os_snprintf_error(end - pos, ret)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001433 end[-1] = '\0';
1434 return buf;
1435 }
1436 pos += ret;
1437 }
1438
1439 return buf;
1440}
1441
1442
1443static char * wpa_config_write_scan_freq(const struct parse_data *data,
1444 struct wpa_ssid *ssid)
1445{
1446 return wpa_config_write_freqs(data, ssid->scan_freq);
1447}
1448
1449
1450static char * wpa_config_write_freq_list(const struct parse_data *data,
1451 struct wpa_ssid *ssid)
1452{
1453 return wpa_config_write_freqs(data, ssid->freq_list);
1454}
1455#endif /* NO_CONFIG_WRITE */
1456
1457
1458#ifdef IEEE8021X_EAPOL
1459static int wpa_config_parse_eap(const struct parse_data *data,
1460 struct wpa_ssid *ssid, int line,
1461 const char *value)
1462{
1463 int last, errors = 0;
1464 char *start, *end, *buf;
1465 struct eap_method_type *methods = NULL, *tmp;
1466 size_t num_methods = 0;
1467
1468 buf = os_strdup(value);
1469 if (buf == NULL)
1470 return -1;
1471 start = buf;
1472
1473 while (*start != '\0') {
1474 while (*start == ' ' || *start == '\t')
1475 start++;
1476 if (*start == '\0')
1477 break;
1478 end = start;
1479 while (*end != ' ' && *end != '\t' && *end != '\0')
1480 end++;
1481 last = *end == '\0';
1482 *end = '\0';
1483 tmp = methods;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001484 methods = os_realloc_array(methods, num_methods + 1,
1485 sizeof(*methods));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001486 if (methods == NULL) {
1487 os_free(tmp);
1488 os_free(buf);
1489 return -1;
1490 }
1491 methods[num_methods].method = eap_peer_get_type(
1492 start, &methods[num_methods].vendor);
1493 if (methods[num_methods].vendor == EAP_VENDOR_IETF &&
1494 methods[num_methods].method == EAP_TYPE_NONE) {
1495 wpa_printf(MSG_ERROR, "Line %d: unknown EAP method "
1496 "'%s'", line, start);
1497 wpa_printf(MSG_ERROR, "You may need to add support for"
1498 " this EAP method during wpa_supplicant\n"
1499 "build time configuration.\n"
1500 "See README for more information.");
1501 errors++;
1502 } else if (methods[num_methods].vendor == EAP_VENDOR_IETF &&
1503 methods[num_methods].method == EAP_TYPE_LEAP)
1504 ssid->leap++;
1505 else
1506 ssid->non_leap++;
1507 num_methods++;
1508 if (last)
1509 break;
1510 start = end + 1;
1511 }
1512 os_free(buf);
1513
1514 tmp = methods;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001515 methods = os_realloc_array(methods, num_methods + 1, sizeof(*methods));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001516 if (methods == NULL) {
1517 os_free(tmp);
1518 return -1;
1519 }
1520 methods[num_methods].vendor = EAP_VENDOR_IETF;
1521 methods[num_methods].method = EAP_TYPE_NONE;
1522 num_methods++;
1523
Dmitry Shmidte4663042016-04-04 10:07:49 -07001524 if (!errors && ssid->eap.eap_methods) {
1525 struct eap_method_type *prev_m;
1526 size_t i, j, prev_methods, match = 0;
1527
1528 prev_m = ssid->eap.eap_methods;
1529 for (i = 0; prev_m[i].vendor != EAP_VENDOR_IETF ||
1530 prev_m[i].method != EAP_TYPE_NONE; i++) {
1531 /* Count the methods */
1532 }
1533 prev_methods = i + 1;
1534
1535 for (i = 0; prev_methods == num_methods && i < prev_methods;
1536 i++) {
1537 for (j = 0; j < num_methods; j++) {
1538 if (prev_m[i].vendor == methods[j].vendor &&
1539 prev_m[i].method == methods[j].method) {
1540 match++;
1541 break;
1542 }
1543 }
1544 }
1545 if (match == num_methods) {
1546 os_free(methods);
1547 return 1;
1548 }
1549 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001550 wpa_hexdump(MSG_MSGDUMP, "eap methods",
1551 (u8 *) methods, num_methods * sizeof(*methods));
Dmitry Shmidt04949592012-07-19 12:16:46 -07001552 os_free(ssid->eap.eap_methods);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001553 ssid->eap.eap_methods = methods;
1554 return errors ? -1 : 0;
1555}
1556
1557
Dmitry Shmidt83474442015-04-15 13:47:09 -07001558#ifndef NO_CONFIG_WRITE
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001559static char * wpa_config_write_eap(const struct parse_data *data,
1560 struct wpa_ssid *ssid)
1561{
1562 int i, ret;
1563 char *buf, *pos, *end;
1564 const struct eap_method_type *eap_methods = ssid->eap.eap_methods;
1565 const char *name;
1566
1567 if (eap_methods == NULL)
1568 return NULL;
1569
1570 pos = buf = os_zalloc(100);
1571 if (buf == NULL)
1572 return NULL;
1573 end = buf + 100;
1574
1575 for (i = 0; eap_methods[i].vendor != EAP_VENDOR_IETF ||
1576 eap_methods[i].method != EAP_TYPE_NONE; i++) {
1577 name = eap_get_name(eap_methods[i].vendor,
1578 eap_methods[i].method);
1579 if (name) {
1580 ret = os_snprintf(pos, end - pos, "%s%s",
1581 pos == buf ? "" : " ", name);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001582 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001583 break;
1584 pos += ret;
1585 }
1586 }
1587
1588 end[-1] = '\0';
1589
1590 return buf;
1591}
Dmitry Shmidt83474442015-04-15 13:47:09 -07001592#endif /* NO_CONFIG_WRITE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001593
1594
1595static int wpa_config_parse_password(const struct parse_data *data,
1596 struct wpa_ssid *ssid, int line,
1597 const char *value)
1598{
1599 u8 *hash;
1600
1601 if (os_strcmp(value, "NULL") == 0) {
Dmitry Shmidte4663042016-04-04 10:07:49 -07001602 if (!ssid->eap.password)
1603 return 1; /* Already unset */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001604 wpa_printf(MSG_DEBUG, "Unset configuration string 'password'");
Dmitry Shmidtc2817022014-07-02 10:32:10 -07001605 bin_clear_free(ssid->eap.password, ssid->eap.password_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001606 ssid->eap.password = NULL;
1607 ssid->eap.password_len = 0;
1608 return 0;
1609 }
1610
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001611#ifdef CONFIG_EXT_PASSWORD
1612 if (os_strncmp(value, "ext:", 4) == 0) {
1613 char *name = os_strdup(value + 4);
Hai Shalomc3565922019-10-28 11:58:20 -07001614 if (!name)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001615 return -1;
Dmitry Shmidtc2817022014-07-02 10:32:10 -07001616 bin_clear_free(ssid->eap.password, ssid->eap.password_len);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001617 ssid->eap.password = (u8 *) name;
1618 ssid->eap.password_len = os_strlen(name);
1619 ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
1620 ssid->eap.flags |= EAP_CONFIG_FLAGS_EXT_PASSWORD;
1621 return 0;
1622 }
1623#endif /* CONFIG_EXT_PASSWORD */
1624
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001625 if (os_strncmp(value, "hash:", 5) != 0) {
1626 char *tmp;
1627 size_t res_len;
1628
1629 tmp = wpa_config_parse_string(value, &res_len);
Hai Shalomc3565922019-10-28 11:58:20 -07001630 if (!tmp) {
1631 wpa_printf(MSG_ERROR,
1632 "Line %d: failed to parse password.", line);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001633 return -1;
1634 }
1635 wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
1636 (u8 *) tmp, res_len);
1637
Dmitry Shmidtc2817022014-07-02 10:32:10 -07001638 bin_clear_free(ssid->eap.password, ssid->eap.password_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001639 ssid->eap.password = (u8 *) tmp;
1640 ssid->eap.password_len = res_len;
1641 ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001642 ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001643
1644 return 0;
1645 }
1646
1647
1648 /* NtPasswordHash: hash:<32 hex digits> */
1649 if (os_strlen(value + 5) != 2 * 16) {
Hai Shalomc3565922019-10-28 11:58:20 -07001650 wpa_printf(MSG_ERROR,
1651 "Line %d: Invalid password hash length (expected 32 hex digits)",
1652 line);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001653 return -1;
1654 }
1655
1656 hash = os_malloc(16);
Hai Shalomc3565922019-10-28 11:58:20 -07001657 if (!hash)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001658 return -1;
1659
1660 if (hexstr2bin(value + 5, hash, 16)) {
1661 os_free(hash);
1662 wpa_printf(MSG_ERROR, "Line %d: Invalid password hash", line);
1663 return -1;
1664 }
1665
1666 wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16);
1667
Dmitry Shmidte4663042016-04-04 10:07:49 -07001668 if (ssid->eap.password && ssid->eap.password_len == 16 &&
1669 os_memcmp(ssid->eap.password, hash, 16) == 0 &&
1670 (ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) {
1671 bin_clear_free(hash, 16);
1672 return 1;
1673 }
Dmitry Shmidtc2817022014-07-02 10:32:10 -07001674 bin_clear_free(ssid->eap.password, ssid->eap.password_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001675 ssid->eap.password = hash;
1676 ssid->eap.password_len = 16;
1677 ssid->eap.flags |= EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001678 ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001679
1680 return 0;
1681}
1682
1683
Hai Shalomc3565922019-10-28 11:58:20 -07001684static int wpa_config_parse_machine_password(const struct parse_data *data,
1685 struct wpa_ssid *ssid, int line,
1686 const char *value)
1687{
1688 u8 *hash;
1689
1690 if (os_strcmp(value, "NULL") == 0) {
1691 if (!ssid->eap.machine_password)
1692 return 1; /* Already unset */
1693 wpa_printf(MSG_DEBUG,
1694 "Unset configuration string 'machine_password'");
1695 bin_clear_free(ssid->eap.machine_password,
1696 ssid->eap.machine_password_len);
1697 ssid->eap.machine_password = NULL;
1698 ssid->eap.machine_password_len = 0;
1699 return 0;
1700 }
1701
1702#ifdef CONFIG_EXT_PASSWORD
1703 if (os_strncmp(value, "ext:", 4) == 0) {
1704 char *name = os_strdup(value + 4);
1705
1706 if (!name)
1707 return -1;
1708 bin_clear_free(ssid->eap.machine_password,
1709 ssid->eap.machine_password_len);
1710 ssid->eap.machine_password = (u8 *) name;
1711 ssid->eap.machine_password_len = os_strlen(name);
1712 ssid->eap.flags &= ~EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH;
1713 ssid->eap.flags |= EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD;
1714 return 0;
1715 }
1716#endif /* CONFIG_EXT_PASSWORD */
1717
1718 if (os_strncmp(value, "hash:", 5) != 0) {
1719 char *tmp;
1720 size_t res_len;
1721
1722 tmp = wpa_config_parse_string(value, &res_len);
1723 if (!tmp) {
1724 wpa_printf(MSG_ERROR,
1725 "Line %d: failed to parse machine_password.",
1726 line);
1727 return -1;
1728 }
1729 wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
1730 (u8 *) tmp, res_len);
1731
1732 bin_clear_free(ssid->eap.machine_password,
1733 ssid->eap.machine_password_len);
1734 ssid->eap.machine_password = (u8 *) tmp;
1735 ssid->eap.machine_password_len = res_len;
1736 ssid->eap.flags &= ~EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH;
1737 ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD;
1738
1739 return 0;
1740 }
1741
1742
1743 /* NtPasswordHash: hash:<32 hex digits> */
1744 if (os_strlen(value + 5) != 2 * 16) {
1745 wpa_printf(MSG_ERROR,
1746 "Line %d: Invalid machine_password hash length (expected 32 hex digits)",
1747 line);
1748 return -1;
1749 }
1750
1751 hash = os_malloc(16);
1752 if (!hash)
1753 return -1;
1754
1755 if (hexstr2bin(value + 5, hash, 16)) {
1756 os_free(hash);
1757 wpa_printf(MSG_ERROR, "Line %d: Invalid machine_password hash",
1758 line);
1759 return -1;
1760 }
1761
1762 wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16);
1763
1764 if (ssid->eap.machine_password &&
1765 ssid->eap.machine_password_len == 16 &&
1766 os_memcmp(ssid->eap.machine_password, hash, 16) == 0 &&
1767 (ssid->eap.flags & EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH)) {
1768 bin_clear_free(hash, 16);
1769 return 1;
1770 }
1771 bin_clear_free(ssid->eap.machine_password,
1772 ssid->eap.machine_password_len);
1773 ssid->eap.machine_password = hash;
1774 ssid->eap.machine_password_len = 16;
1775 ssid->eap.flags |= EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH;
1776 ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD;
1777
1778 return 0;
1779}
1780
1781
Dmitry Shmidt83474442015-04-15 13:47:09 -07001782#ifndef NO_CONFIG_WRITE
Hai Shalomc3565922019-10-28 11:58:20 -07001783
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001784static char * wpa_config_write_password(const struct parse_data *data,
1785 struct wpa_ssid *ssid)
1786{
1787 char *buf;
1788
Hai Shalomc3565922019-10-28 11:58:20 -07001789 if (!ssid->eap.password)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001790 return NULL;
1791
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001792#ifdef CONFIG_EXT_PASSWORD
1793 if (ssid->eap.flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
1794 buf = os_zalloc(4 + ssid->eap.password_len + 1);
Hai Shalomc3565922019-10-28 11:58:20 -07001795 if (!buf)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001796 return NULL;
1797 os_memcpy(buf, "ext:", 4);
1798 os_memcpy(buf + 4, ssid->eap.password, ssid->eap.password_len);
1799 return buf;
1800 }
1801#endif /* CONFIG_EXT_PASSWORD */
1802
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001803 if (!(ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) {
1804 return wpa_config_write_string(
1805 ssid->eap.password, ssid->eap.password_len);
1806 }
1807
1808 buf = os_malloc(5 + 32 + 1);
Hai Shalomc3565922019-10-28 11:58:20 -07001809 if (!buf)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001810 return NULL;
1811
1812 os_memcpy(buf, "hash:", 5);
1813 wpa_snprintf_hex(buf + 5, 32 + 1, ssid->eap.password, 16);
1814
1815 return buf;
1816}
Hai Shalomc3565922019-10-28 11:58:20 -07001817
1818
1819static char * wpa_config_write_machine_password(const struct parse_data *data,
1820 struct wpa_ssid *ssid)
1821{
1822 char *buf;
1823
1824 if (!ssid->eap.machine_password)
1825 return NULL;
1826
1827#ifdef CONFIG_EXT_PASSWORD
1828 if (ssid->eap.flags & EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD) {
1829 buf = os_zalloc(4 + ssid->eap.machine_password_len + 1);
1830 if (!buf)
1831 return NULL;
1832 os_memcpy(buf, "ext:", 4);
1833 os_memcpy(buf + 4, ssid->eap.machine_password,
1834 ssid->eap.machine_password_len);
1835 return buf;
1836 }
1837#endif /* CONFIG_EXT_PASSWORD */
1838
1839 if (!(ssid->eap.flags & EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH)) {
1840 return wpa_config_write_string(
1841 ssid->eap.machine_password,
1842 ssid->eap.machine_password_len);
1843 }
1844
1845 buf = os_malloc(5 + 32 + 1);
1846 if (!buf)
1847 return NULL;
1848
1849 os_memcpy(buf, "hash:", 5);
1850 wpa_snprintf_hex(buf + 5, 32 + 1, ssid->eap.machine_password, 16);
1851
1852 return buf;
1853}
1854
Dmitry Shmidt83474442015-04-15 13:47:09 -07001855#endif /* NO_CONFIG_WRITE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001856#endif /* IEEE8021X_EAPOL */
1857
1858
Hai Shalomfdcde762020-04-02 11:19:20 -07001859#ifdef CONFIG_WEP
1860
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001861static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line,
1862 const char *value, int idx)
1863{
1864 char *buf, title[20];
1865 int res;
1866
1867 buf = wpa_config_parse_string(value, len);
1868 if (buf == NULL) {
1869 wpa_printf(MSG_ERROR, "Line %d: Invalid WEP key %d '%s'.",
1870 line, idx, value);
1871 return -1;
1872 }
1873 if (*len > MAX_WEP_KEY_LEN) {
1874 wpa_printf(MSG_ERROR, "Line %d: Too long WEP key %d '%s'.",
1875 line, idx, value);
1876 os_free(buf);
1877 return -1;
1878 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07001879 if (*len && *len != 5 && *len != 13 && *len != 16) {
1880 wpa_printf(MSG_ERROR, "Line %d: Invalid WEP key length %u - "
1881 "this network block will be ignored",
1882 line, (unsigned int) *len);
1883 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001884 os_memcpy(key, buf, *len);
Dmitry Shmidtc2817022014-07-02 10:32:10 -07001885 str_clear_free(buf);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001886 res = os_snprintf(title, sizeof(title), "wep_key%d", idx);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001887 if (!os_snprintf_error(sizeof(title), res))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001888 wpa_hexdump_key(MSG_MSGDUMP, title, key, *len);
1889 return 0;
1890}
1891
1892
1893static int wpa_config_parse_wep_key0(const struct parse_data *data,
1894 struct wpa_ssid *ssid, int line,
1895 const char *value)
1896{
1897 return wpa_config_parse_wep_key(ssid->wep_key[0],
1898 &ssid->wep_key_len[0], line,
1899 value, 0);
1900}
1901
1902
1903static int wpa_config_parse_wep_key1(const struct parse_data *data,
1904 struct wpa_ssid *ssid, int line,
1905 const char *value)
1906{
1907 return wpa_config_parse_wep_key(ssid->wep_key[1],
1908 &ssid->wep_key_len[1], line,
1909 value, 1);
1910}
1911
1912
1913static int wpa_config_parse_wep_key2(const struct parse_data *data,
1914 struct wpa_ssid *ssid, int line,
1915 const char *value)
1916{
1917 return wpa_config_parse_wep_key(ssid->wep_key[2],
1918 &ssid->wep_key_len[2], line,
1919 value, 2);
1920}
1921
1922
1923static int wpa_config_parse_wep_key3(const struct parse_data *data,
1924 struct wpa_ssid *ssid, int line,
1925 const char *value)
1926{
1927 return wpa_config_parse_wep_key(ssid->wep_key[3],
1928 &ssid->wep_key_len[3], line,
1929 value, 3);
1930}
1931
1932
1933#ifndef NO_CONFIG_WRITE
1934static char * wpa_config_write_wep_key(struct wpa_ssid *ssid, int idx)
1935{
1936 if (ssid->wep_key_len[idx] == 0)
1937 return NULL;
1938 return wpa_config_write_string(ssid->wep_key[idx],
1939 ssid->wep_key_len[idx]);
1940}
1941
1942
1943static char * wpa_config_write_wep_key0(const struct parse_data *data,
1944 struct wpa_ssid *ssid)
1945{
1946 return wpa_config_write_wep_key(ssid, 0);
1947}
1948
1949
1950static char * wpa_config_write_wep_key1(const struct parse_data *data,
1951 struct wpa_ssid *ssid)
1952{
1953 return wpa_config_write_wep_key(ssid, 1);
1954}
1955
1956
1957static char * wpa_config_write_wep_key2(const struct parse_data *data,
1958 struct wpa_ssid *ssid)
1959{
1960 return wpa_config_write_wep_key(ssid, 2);
1961}
1962
1963
1964static char * wpa_config_write_wep_key3(const struct parse_data *data,
1965 struct wpa_ssid *ssid)
1966{
1967 return wpa_config_write_wep_key(ssid, 3);
1968}
1969#endif /* NO_CONFIG_WRITE */
1970
Hai Shalomfdcde762020-04-02 11:19:20 -07001971#endif /* CONFIG_WEP */
1972
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001973
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001974#ifdef CONFIG_P2P
1975
Dmitry Shmidt54605472013-11-08 11:10:19 -08001976static int wpa_config_parse_go_p2p_dev_addr(const struct parse_data *data,
1977 struct wpa_ssid *ssid, int line,
1978 const char *value)
1979{
1980 if (value[0] == '\0' || os_strcmp(value, "\"\"") == 0 ||
1981 os_strcmp(value, "any") == 0) {
1982 os_memset(ssid->go_p2p_dev_addr, 0, ETH_ALEN);
1983 wpa_printf(MSG_MSGDUMP, "GO P2P Device Address any");
1984 return 0;
1985 }
1986 if (hwaddr_aton(value, ssid->go_p2p_dev_addr)) {
1987 wpa_printf(MSG_ERROR, "Line %d: Invalid GO P2P Device Address '%s'.",
1988 line, value);
1989 return -1;
1990 }
1991 ssid->bssid_set = 1;
1992 wpa_printf(MSG_MSGDUMP, "GO P2P Device Address " MACSTR,
1993 MAC2STR(ssid->go_p2p_dev_addr));
1994 return 0;
1995}
1996
1997
1998#ifndef NO_CONFIG_WRITE
1999static char * wpa_config_write_go_p2p_dev_addr(const struct parse_data *data,
2000 struct wpa_ssid *ssid)
2001{
2002 char *value;
2003 int res;
2004
2005 if (is_zero_ether_addr(ssid->go_p2p_dev_addr))
2006 return NULL;
2007
2008 value = os_malloc(20);
2009 if (value == NULL)
2010 return NULL;
2011 res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->go_p2p_dev_addr));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002012 if (os_snprintf_error(20, res)) {
Dmitry Shmidt54605472013-11-08 11:10:19 -08002013 os_free(value);
2014 return NULL;
2015 }
2016 value[20 - 1] = '\0';
2017 return value;
2018}
2019#endif /* NO_CONFIG_WRITE */
2020
2021
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002022static int wpa_config_parse_p2p_client_list(const struct parse_data *data,
2023 struct wpa_ssid *ssid, int line,
2024 const char *value)
2025{
Dmitry Shmidtff787d52015-01-12 13:01:47 -08002026 return wpa_config_parse_addr_list(data, line, value,
2027 &ssid->p2p_client_list,
2028 &ssid->num_p2p_clients,
2029 "p2p_client_list", 0, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002030}
2031
2032
2033#ifndef NO_CONFIG_WRITE
2034static char * wpa_config_write_p2p_client_list(const struct parse_data *data,
2035 struct wpa_ssid *ssid)
2036{
Dmitry Shmidtff787d52015-01-12 13:01:47 -08002037 return wpa_config_write_addr_list(data, ssid->p2p_client_list,
2038 ssid->num_p2p_clients,
2039 "p2p_client_list");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002040}
2041#endif /* NO_CONFIG_WRITE */
2042
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07002043
2044static int wpa_config_parse_psk_list(const struct parse_data *data,
2045 struct wpa_ssid *ssid, int line,
2046 const char *value)
2047{
2048 struct psk_list_entry *p;
2049 const char *pos;
2050
2051 p = os_zalloc(sizeof(*p));
2052 if (p == NULL)
2053 return -1;
2054
2055 pos = value;
2056 if (os_strncmp(pos, "P2P-", 4) == 0) {
2057 p->p2p = 1;
2058 pos += 4;
2059 }
2060
2061 if (hwaddr_aton(pos, p->addr)) {
2062 wpa_printf(MSG_ERROR, "Line %d: Invalid psk_list address '%s'",
2063 line, pos);
2064 os_free(p);
2065 return -1;
2066 }
2067 pos += 17;
2068 if (*pos != '-') {
2069 wpa_printf(MSG_ERROR, "Line %d: Invalid psk_list '%s'",
2070 line, pos);
2071 os_free(p);
2072 return -1;
2073 }
2074 pos++;
2075
2076 if (hexstr2bin(pos, p->psk, PMK_LEN) || pos[PMK_LEN * 2] != '\0') {
2077 wpa_printf(MSG_ERROR, "Line %d: Invalid psk_list PSK '%s'",
2078 line, pos);
2079 os_free(p);
2080 return -1;
2081 }
2082
2083 dl_list_add(&ssid->psk_list, &p->list);
2084
2085 return 0;
2086}
2087
2088
2089#ifndef NO_CONFIG_WRITE
2090static char * wpa_config_write_psk_list(const struct parse_data *data,
2091 struct wpa_ssid *ssid)
2092{
2093 return NULL;
2094}
2095#endif /* NO_CONFIG_WRITE */
2096
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002097#endif /* CONFIG_P2P */
2098
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002099
2100#ifdef CONFIG_MESH
2101
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002102static int wpa_config_parse_mesh_basic_rates(const struct parse_data *data,
2103 struct wpa_ssid *ssid, int line,
2104 const char *value)
2105{
2106 int *rates = wpa_config_parse_int_array(value);
2107
2108 if (rates == NULL) {
2109 wpa_printf(MSG_ERROR, "Line %d: Invalid mesh_basic_rates '%s'",
2110 line, value);
2111 return -1;
2112 }
2113 if (rates[0] == 0) {
2114 os_free(rates);
2115 rates = NULL;
2116 }
2117
2118 os_free(ssid->mesh_basic_rates);
2119 ssid->mesh_basic_rates = rates;
2120
2121 return 0;
2122}
2123
2124
2125#ifndef NO_CONFIG_WRITE
2126
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002127static char * wpa_config_write_mesh_basic_rates(const struct parse_data *data,
2128 struct wpa_ssid *ssid)
2129{
2130 return wpa_config_write_freqs(data, ssid->mesh_basic_rates);
2131}
2132
2133#endif /* NO_CONFIG_WRITE */
2134
2135#endif /* CONFIG_MESH */
2136
2137
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08002138#ifdef CONFIG_MACSEC
2139
2140static int wpa_config_parse_mka_cak(const struct parse_data *data,
2141 struct wpa_ssid *ssid, int line,
2142 const char *value)
2143{
Hai Shalom74f70d42019-02-11 14:42:39 -08002144 size_t len;
2145
2146 len = os_strlen(value);
2147 if (len > 2 * MACSEC_CAK_MAX_LEN ||
2148 (len != 2 * 16 && len != 2 * 32) ||
2149 hexstr2bin(value, ssid->mka_cak, len / 2)) {
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08002150 wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CAK '%s'.",
2151 line, value);
2152 return -1;
2153 }
Hai Shalom74f70d42019-02-11 14:42:39 -08002154 ssid->mka_cak_len = len / 2;
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08002155 ssid->mka_psk_set |= MKA_PSK_SET_CAK;
2156
Hai Shalom74f70d42019-02-11 14:42:39 -08002157 wpa_hexdump_key(MSG_MSGDUMP, "MKA-CAK", ssid->mka_cak,
2158 ssid->mka_cak_len);
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08002159 return 0;
2160}
2161
2162
2163static int wpa_config_parse_mka_ckn(const struct parse_data *data,
2164 struct wpa_ssid *ssid, int line,
2165 const char *value)
2166{
Hai Shalom74f70d42019-02-11 14:42:39 -08002167 size_t len;
2168
2169 len = os_strlen(value);
2170 if (len > 2 * MACSEC_CKN_MAX_LEN || /* too long */
2171 len < 2 || /* too short */
2172 len % 2 != 0 /* not an integral number of bytes */) {
2173 wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CKN '%s'.",
2174 line, value);
2175 return -1;
2176 }
2177 ssid->mka_ckn_len = len / 2;
2178 if (hexstr2bin(value, ssid->mka_ckn, ssid->mka_ckn_len)) {
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08002179 wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CKN '%s'.",
2180 line, value);
2181 return -1;
2182 }
2183
2184 ssid->mka_psk_set |= MKA_PSK_SET_CKN;
2185
Hai Shalom74f70d42019-02-11 14:42:39 -08002186 wpa_hexdump_key(MSG_MSGDUMP, "MKA-CKN", ssid->mka_ckn,
2187 ssid->mka_ckn_len);
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08002188 return 0;
2189}
2190
2191
2192#ifndef NO_CONFIG_WRITE
2193
2194static char * wpa_config_write_mka_cak(const struct parse_data *data,
2195 struct wpa_ssid *ssid)
2196{
2197 if (!(ssid->mka_psk_set & MKA_PSK_SET_CAK))
2198 return NULL;
2199
Hai Shalom74f70d42019-02-11 14:42:39 -08002200 return wpa_config_write_string_hex(ssid->mka_cak, ssid->mka_cak_len);
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08002201}
2202
2203
2204static char * wpa_config_write_mka_ckn(const struct parse_data *data,
2205 struct wpa_ssid *ssid)
2206{
2207 if (!(ssid->mka_psk_set & MKA_PSK_SET_CKN))
2208 return NULL;
Hai Shalom74f70d42019-02-11 14:42:39 -08002209 return wpa_config_write_string_hex(ssid->mka_ckn, ssid->mka_ckn_len);
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08002210}
2211
2212#endif /* NO_CONFIG_WRITE */
2213
2214#endif /* CONFIG_MACSEC */
2215
2216
Hai Shalom74f70d42019-02-11 14:42:39 -08002217#ifdef CONFIG_OCV
2218
2219static int wpa_config_parse_ocv(const struct parse_data *data,
2220 struct wpa_ssid *ssid, int line,
2221 const char *value)
2222{
2223 char *end;
2224
2225 ssid->ocv = strtol(value, &end, 0);
2226 if (*end || ssid->ocv < 0 || ssid->ocv > 1) {
2227 wpa_printf(MSG_ERROR, "Line %d: Invalid ocv value '%s'.",
2228 line, value);
2229 return -1;
2230 }
2231 if (ssid->ocv && ssid->ieee80211w == NO_MGMT_FRAME_PROTECTION)
2232 ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
2233 return 0;
2234}
2235
2236
2237#ifndef NO_CONFIG_WRITE
2238static char * wpa_config_write_ocv(const struct parse_data *data,
2239 struct wpa_ssid *ssid)
2240{
2241 char *value = os_malloc(20);
2242
2243 if (!value)
2244 return NULL;
2245 os_snprintf(value, 20, "%d", ssid->ocv);
2246 value[20 - 1] = '\0';
2247 return value;
2248}
2249#endif /* NO_CONFIG_WRITE */
2250
2251#endif /* CONFIG_OCV */
2252
2253
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002254static int wpa_config_parse_peerkey(const struct parse_data *data,
2255 struct wpa_ssid *ssid, int line,
2256 const char *value)
2257{
2258 wpa_printf(MSG_INFO, "NOTE: Obsolete peerkey parameter ignored");
2259 return 0;
2260}
2261
2262
2263#ifndef NO_CONFIG_WRITE
2264static char * wpa_config_write_peerkey(const struct parse_data *data,
2265 struct wpa_ssid *ssid)
2266{
2267 return NULL;
2268}
2269#endif /* NO_CONFIG_WRITE */
2270
2271
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002272/* Helper macros for network block parser */
2273
2274#ifdef OFFSET
2275#undef OFFSET
2276#endif /* OFFSET */
2277/* OFFSET: Get offset of a variable within the wpa_ssid structure */
2278#define OFFSET(v) ((void *) &((struct wpa_ssid *) 0)->v)
2279
2280/* STR: Define a string variable for an ASCII string; f = field name */
2281#ifdef NO_CONFIG_WRITE
2282#define _STR(f) #f, wpa_config_parse_str, OFFSET(f)
Hai Shalomc3565922019-10-28 11:58:20 -07002283#define _STRe(f, m) #f, wpa_config_parse_str, OFFSET(eap.m)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002284#else /* NO_CONFIG_WRITE */
2285#define _STR(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(f)
Hai Shalomc3565922019-10-28 11:58:20 -07002286#define _STRe(f, m) #f, wpa_config_parse_str, wpa_config_write_str, \
2287 OFFSET(eap.m)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002288#endif /* NO_CONFIG_WRITE */
2289#define STR(f) _STR(f), NULL, NULL, NULL, 0
Hai Shalomc3565922019-10-28 11:58:20 -07002290#define STRe(f, m) _STRe(f, m), NULL, NULL, NULL, 0
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002291#define STR_KEY(f) _STR(f), NULL, NULL, NULL, 1
Hai Shalomc3565922019-10-28 11:58:20 -07002292#define STR_KEYe(f, m) _STRe(f, m), NULL, NULL, NULL, 1
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002293
2294/* STR_LEN: Define a string variable with a separate variable for storing the
2295 * data length. Unlike STR(), this can be used to store arbitrary binary data
2296 * (i.e., even nul termination character). */
2297#define _STR_LEN(f) _STR(f), OFFSET(f ## _len)
Hai Shalomc3565922019-10-28 11:58:20 -07002298#define _STR_LENe(f, m) _STRe(f, m), OFFSET(eap.m ## _len)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002299#define STR_LEN(f) _STR_LEN(f), NULL, NULL, 0
Hai Shalomc3565922019-10-28 11:58:20 -07002300#define STR_LENe(f, m) _STR_LENe(f, m), NULL, NULL, 0
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002301#define STR_LEN_KEY(f) _STR_LEN(f), NULL, NULL, 1
2302
2303/* STR_RANGE: Like STR_LEN(), but with minimum and maximum allowed length
2304 * explicitly specified. */
2305#define _STR_RANGE(f, min, max) _STR_LEN(f), (void *) (min), (void *) (max)
2306#define STR_RANGE(f, min, max) _STR_RANGE(f, min, max), 0
2307#define STR_RANGE_KEY(f, min, max) _STR_RANGE(f, min, max), 1
2308
2309#ifdef NO_CONFIG_WRITE
2310#define _INT(f) #f, wpa_config_parse_int, OFFSET(f), (void *) 0
Hai Shalomc3565922019-10-28 11:58:20 -07002311#define _INTe(f, m) #f, wpa_config_parse_int, OFFSET(eap.m), (void *) 0
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002312#else /* NO_CONFIG_WRITE */
2313#define _INT(f) #f, wpa_config_parse_int, wpa_config_write_int, \
2314 OFFSET(f), (void *) 0
Hai Shalomc3565922019-10-28 11:58:20 -07002315#define _INTe(f, m) #f, wpa_config_parse_int, wpa_config_write_int, \
2316 OFFSET(eap.m), (void *) 0
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002317#endif /* NO_CONFIG_WRITE */
2318
2319/* INT: Define an integer variable */
2320#define INT(f) _INT(f), NULL, NULL, 0
Hai Shalomc3565922019-10-28 11:58:20 -07002321#define INTe(f, m) _INTe(f, m), NULL, NULL, 0
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002322
2323/* INT_RANGE: Define an integer variable with allowed value range */
2324#define INT_RANGE(f, min, max) _INT(f), (void *) (min), (void *) (max), 0
2325
2326/* FUNC: Define a configuration variable that uses a custom function for
2327 * parsing and writing the value. */
2328#ifdef NO_CONFIG_WRITE
2329#define _FUNC(f) #f, wpa_config_parse_ ## f, NULL, NULL, NULL, NULL
2330#else /* NO_CONFIG_WRITE */
2331#define _FUNC(f) #f, wpa_config_parse_ ## f, wpa_config_write_ ## f, \
2332 NULL, NULL, NULL, NULL
2333#endif /* NO_CONFIG_WRITE */
2334#define FUNC(f) _FUNC(f), 0
2335#define FUNC_KEY(f) _FUNC(f), 1
2336
2337/*
2338 * Table of network configuration variables. This table is used to parse each
2339 * network configuration variable, e.g., each line in wpa_supplicant.conf file
2340 * that is inside a network block.
2341 *
2342 * This table is generated using the helper macros defined above and with
2343 * generous help from the C pre-processor. The field name is stored as a string
2344 * into .name and for STR and INT types, the offset of the target buffer within
2345 * struct wpa_ssid is stored in .param1. .param2 (if not NULL) is similar
2346 * offset to the field containing the length of the configuration variable.
2347 * .param3 and .param4 can be used to mark the allowed range (length for STR
2348 * and value for INT).
2349 *
2350 * For each configuration line in wpa_supplicant.conf, the parser goes through
2351 * this table and select the entry that matches with the field name. The parser
2352 * function (.parser) is then called to parse the actual value of the field.
2353 *
2354 * This kind of mechanism makes it easy to add new configuration parameters,
2355 * since only one line needs to be added into this table and into the
2356 * struct wpa_ssid definition if the new variable is either a string or
2357 * integer. More complex types will need to use their own parser and writer
2358 * functions.
2359 */
2360static const struct parse_data ssid_fields[] = {
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07002361 { STR_RANGE(ssid, 0, SSID_MAX_LEN) },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002362 { INT_RANGE(scan_ssid, 0, 1) },
2363 { FUNC(bssid) },
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002364 { FUNC(bssid_hint) },
Dmitry Shmidtff787d52015-01-12 13:01:47 -08002365 { FUNC(bssid_blacklist) },
2366 { FUNC(bssid_whitelist) },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002367 { FUNC_KEY(psk) },
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07002368 { INT(mem_only_psk) },
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002369 { STR_KEY(sae_password) },
Roshan Pius3a1667e2018-07-03 15:17:14 -07002370 { STR(sae_password_id) },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002371 { FUNC(proto) },
2372 { FUNC(key_mgmt) },
Dmitry Shmidt04949592012-07-19 12:16:46 -07002373 { INT(bg_scan_period) },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002374 { FUNC(pairwise) },
2375 { FUNC(group) },
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002376 { FUNC(group_mgmt) },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002377 { FUNC(auth_alg) },
2378 { FUNC(scan_freq) },
2379 { FUNC(freq_list) },
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002380 { INT_RANGE(ht, 0, 1) },
2381 { INT_RANGE(vht, 0, 1) },
2382 { INT_RANGE(ht40, -1, 1) },
Hai Shalom81f62d82019-07-22 12:10:00 -07002383 { INT_RANGE(max_oper_chwidth, CHANWIDTH_USE_HT,
2384 CHANWIDTH_80P80MHZ) },
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002385 { INT(vht_center_freq1) },
2386 { INT(vht_center_freq2) },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002387#ifdef IEEE8021X_EAPOL
2388 { FUNC(eap) },
Hai Shalomc3565922019-10-28 11:58:20 -07002389 { STR_LENe(identity, identity) },
2390 { STR_LENe(anonymous_identity, anonymous_identity) },
2391 { STR_LENe(imsi_identity, imsi_identity) },
2392 { STR_LENe(machine_identity, machine_identity) },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002393 { FUNC_KEY(password) },
Hai Shalomc3565922019-10-28 11:58:20 -07002394 { FUNC_KEY(machine_password) },
2395 { STRe(ca_cert, cert.ca_cert) },
2396 { STRe(ca_path, cert.ca_path) },
2397 { STRe(client_cert, cert.client_cert) },
2398 { STRe(private_key, cert.private_key) },
2399 { STR_KEYe(private_key_passwd, cert.private_key_passwd) },
2400 { STRe(dh_file, cert.dh_file) },
2401 { STRe(subject_match, cert.subject_match) },
2402 { STRe(check_cert_subject, cert.check_cert_subject) },
2403 { STRe(altsubject_match, cert.altsubject_match) },
2404 { STRe(domain_suffix_match, cert.domain_suffix_match) },
2405 { STRe(domain_match, cert.domain_match) },
2406 { STRe(ca_cert2, phase2_cert.ca_cert) },
2407 { STRe(ca_path2, phase2_cert.ca_path) },
2408 { STRe(client_cert2, phase2_cert.client_cert) },
2409 { STRe(private_key2, phase2_cert.private_key) },
2410 { STR_KEYe(private_key2_passwd, phase2_cert.private_key_passwd) },
2411 { STRe(dh_file2, phase2_cert.dh_file) },
2412 { STRe(subject_match2, phase2_cert.subject_match) },
2413 { STRe(check_cert_subject2, phase2_cert.check_cert_subject) },
2414 { STRe(altsubject_match2, phase2_cert.altsubject_match) },
2415 { STRe(domain_suffix_match2, phase2_cert.domain_suffix_match) },
2416 { STRe(domain_match2, phase2_cert.domain_match) },
2417 { STRe(phase1, phase1) },
2418 { STRe(phase2, phase2) },
2419 { STRe(machine_phase2, machine_phase2) },
2420 { STRe(pcsc, pcsc) },
2421 { STR_KEYe(pin, cert.pin) },
2422 { STRe(engine_id, cert.engine_id) },
2423 { STRe(key_id, cert.key_id) },
2424 { STRe(cert_id, cert.cert_id) },
2425 { STRe(ca_cert_id, cert.ca_cert_id) },
2426 { STR_KEYe(pin2, phase2_cert.pin) },
2427 { STRe(engine_id2, phase2_cert.engine_id) },
2428 { STRe(key_id2, phase2_cert.key_id) },
2429 { STRe(cert_id2, phase2_cert.cert_id) },
2430 { STRe(ca_cert_id2, phase2_cert.ca_cert_id) },
2431 { INTe(engine, cert.engine) },
2432 { INTe(engine2, phase2_cert.engine) },
2433 { STRe(machine_ca_cert, machine_cert.ca_cert) },
2434 { STRe(machine_ca_path, machine_cert.ca_path) },
2435 { STRe(machine_client_cert, machine_cert.client_cert) },
2436 { STRe(machine_private_key, machine_cert.private_key) },
2437 { STR_KEYe(machine_private_key_passwd,
2438 machine_cert.private_key_passwd) },
2439 { STRe(machine_dh_file, machine_cert.dh_file) },
2440 { STRe(machine_subject_match, machine_cert.subject_match) },
2441 { STRe(machine_check_cert_subject, machine_cert.check_cert_subject) },
2442 { STRe(machine_altsubject_match, machine_cert.altsubject_match) },
2443 { STRe(machine_domain_suffix_match,
2444 machine_cert.domain_suffix_match) },
2445 { STRe(machine_domain_match, machine_cert.domain_match) },
2446 { STR_KEYe(machine_pin, machine_cert.pin) },
2447 { STRe(machine_engine_id, machine_cert.engine_id) },
2448 { STRe(machine_key_id, machine_cert.key_id) },
2449 { STRe(machine_cert_id, machine_cert.cert_id) },
2450 { STRe(machine_ca_cert_id, machine_cert.ca_cert_id) },
2451 { INTe(machine_engine, machine_cert.engine) },
2452 { INTe(machine_ocsp, machine_cert.ocsp) },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002453 { INT(eapol_flags) },
Hai Shalomc3565922019-10-28 11:58:20 -07002454 { INTe(sim_num, sim_num) },
2455 { STRe(openssl_ciphers, openssl_ciphers) },
2456 { INTe(erp, erp) },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002457#endif /* IEEE8021X_EAPOL */
Hai Shalomfdcde762020-04-02 11:19:20 -07002458#ifdef CONFIG_WEP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002459 { FUNC_KEY(wep_key0) },
2460 { FUNC_KEY(wep_key1) },
2461 { FUNC_KEY(wep_key2) },
2462 { FUNC_KEY(wep_key3) },
2463 { INT(wep_tx_keyidx) },
Hai Shalomfdcde762020-04-02 11:19:20 -07002464#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002465 { INT(priority) },
2466#ifdef IEEE8021X_EAPOL
2467 { INT(eap_workaround) },
Hai Shalomc3565922019-10-28 11:58:20 -07002468 { STRe(pac_file, pac_file) },
2469 { INTe(fragment_size, fragment_size) },
2470 { INTe(ocsp, cert.ocsp) },
2471 { INTe(ocsp2, phase2_cert.ocsp) },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002472#endif /* IEEE8021X_EAPOL */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002473#ifdef CONFIG_MESH
2474 { INT_RANGE(mode, 0, 5) },
2475 { INT_RANGE(no_auto_peer, 0, 1) },
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002476 { INT_RANGE(mesh_rssi_threshold, -255, 1) },
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002477#else /* CONFIG_MESH */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002478 { INT_RANGE(mode, 0, 4) },
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002479#endif /* CONFIG_MESH */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002480 { INT_RANGE(proactive_key_caching, 0, 1) },
2481 { INT_RANGE(disabled, 0, 2) },
2482 { STR(id_str) },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002483 { INT_RANGE(ieee80211w, 0, 2) },
Hai Shalom74f70d42019-02-11 14:42:39 -08002484#ifdef CONFIG_OCV
2485 { FUNC(ocv) },
2486#endif /* CONFIG_OCV */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002487 { FUNC(peerkey) /* obsolete - removed */ },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002488 { INT_RANGE(mixed_cell, 0, 1) },
Hai Shalomc3565922019-10-28 11:58:20 -07002489 { INT_RANGE(frequency, 0, 70200) },
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002490 { INT_RANGE(fixed_freq, 0, 1) },
Hai Shalomc3565922019-10-28 11:58:20 -07002491 { INT_RANGE(enable_edmg, 0, 1) },
2492 { INT_RANGE(edmg_channel, 9, 13) },
Dmitry Shmidt014a3ff2015-12-28 13:27:49 -08002493#ifdef CONFIG_ACS
2494 { INT_RANGE(acs, 0, 1) },
2495#endif /* CONFIG_ACS */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002496#ifdef CONFIG_MESH
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002497 { FUNC(mesh_basic_rates) },
2498 { INT(dot11MeshMaxRetries) },
2499 { INT(dot11MeshRetryTimeout) },
2500 { INT(dot11MeshConfirmTimeout) },
2501 { INT(dot11MeshHoldingTimeout) },
2502#endif /* CONFIG_MESH */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002503 { INT(wpa_ptk_rekey) },
Hai Shalomfdcde762020-04-02 11:19:20 -07002504 { INT_RANGE(wpa_deny_ptk0_rekey, 0, 2) },
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07002505 { INT(group_rekey) },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002506 { STR(bgscan) },
Dmitry Shmidt04949592012-07-19 12:16:46 -07002507 { INT_RANGE(ignore_broadcast_ssid, 0, 2) },
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002508#ifdef CONFIG_P2P
Dmitry Shmidt54605472013-11-08 11:10:19 -08002509 { FUNC(go_p2p_dev_addr) },
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002510 { FUNC(p2p_client_list) },
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07002511 { FUNC(psk_list) },
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002512#endif /* CONFIG_P2P */
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08002513#ifdef CONFIG_HT_OVERRIDES
2514 { INT_RANGE(disable_ht, 0, 1) },
2515 { INT_RANGE(disable_ht40, -1, 1) },
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002516 { INT_RANGE(disable_sgi, 0, 1) },
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07002517 { INT_RANGE(disable_ldpc, 0, 1) },
Dmitry Shmidt61593f02014-04-21 16:27:35 -07002518 { INT_RANGE(ht40_intolerant, 0, 1) },
Hai Shalom74f70d42019-02-11 14:42:39 -08002519 { INT_RANGE(tx_stbc, -1, 1) },
2520 { INT_RANGE(rx_stbc, -1, 3) },
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08002521 { INT_RANGE(disable_max_amsdu, -1, 1) },
2522 { INT_RANGE(ampdu_factor, -1, 3) },
2523 { INT_RANGE(ampdu_density, -1, 7) },
2524 { STR(ht_mcs) },
2525#endif /* CONFIG_HT_OVERRIDES */
Dmitry Shmidt2f023192013-03-12 12:44:17 -07002526#ifdef CONFIG_VHT_OVERRIDES
2527 { INT_RANGE(disable_vht, 0, 1) },
2528 { INT(vht_capa) },
2529 { INT(vht_capa_mask) },
2530 { INT_RANGE(vht_rx_mcs_nss_1, -1, 3) },
2531 { INT_RANGE(vht_rx_mcs_nss_2, -1, 3) },
2532 { INT_RANGE(vht_rx_mcs_nss_3, -1, 3) },
2533 { INT_RANGE(vht_rx_mcs_nss_4, -1, 3) },
2534 { INT_RANGE(vht_rx_mcs_nss_5, -1, 3) },
2535 { INT_RANGE(vht_rx_mcs_nss_6, -1, 3) },
2536 { INT_RANGE(vht_rx_mcs_nss_7, -1, 3) },
2537 { INT_RANGE(vht_rx_mcs_nss_8, -1, 3) },
2538 { INT_RANGE(vht_tx_mcs_nss_1, -1, 3) },
2539 { INT_RANGE(vht_tx_mcs_nss_2, -1, 3) },
2540 { INT_RANGE(vht_tx_mcs_nss_3, -1, 3) },
2541 { INT_RANGE(vht_tx_mcs_nss_4, -1, 3) },
2542 { INT_RANGE(vht_tx_mcs_nss_5, -1, 3) },
2543 { INT_RANGE(vht_tx_mcs_nss_6, -1, 3) },
2544 { INT_RANGE(vht_tx_mcs_nss_7, -1, 3) },
2545 { INT_RANGE(vht_tx_mcs_nss_8, -1, 3) },
2546#endif /* CONFIG_VHT_OVERRIDES */
Hai Shalomfdcde762020-04-02 11:19:20 -07002547#ifdef CONFIG_HE_OVERRIDES
2548 { INT_RANGE(disable_he, 0, 1)},
2549#endif /* CONFIG_HE_OVERRIDES */
Dmitry Shmidt04949592012-07-19 12:16:46 -07002550 { INT(ap_max_inactivity) },
2551 { INT(dtim_period) },
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08002552 { INT(beacon_int) },
Dmitry Shmidt5a1480c2014-05-12 09:46:02 -07002553#ifdef CONFIG_MACSEC
2554 { INT_RANGE(macsec_policy, 0, 1) },
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08002555 { INT_RANGE(macsec_integ_only, 0, 1) },
Hai Shalom74f70d42019-02-11 14:42:39 -08002556 { INT_RANGE(macsec_replay_protect, 0, 1) },
2557 { INT(macsec_replay_window) },
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08002558 { INT_RANGE(macsec_port, 1, 65534) },
Dmitry Shmidt29333592017-01-09 12:27:11 -08002559 { INT_RANGE(mka_priority, 0, 255) },
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08002560 { FUNC_KEY(mka_cak) },
2561 { FUNC_KEY(mka_ckn) },
Dmitry Shmidt5a1480c2014-05-12 09:46:02 -07002562#endif /* CONFIG_MACSEC */
Dmitry Shmidtc2817022014-07-02 10:32:10 -07002563#ifdef CONFIG_HS20
2564 { INT(update_identifier) },
Roshan Pius3a1667e2018-07-03 15:17:14 -07002565 { STR_RANGE(roaming_consortium_selection, 0, MAX_ROAMING_CONS_OI_LEN) },
Dmitry Shmidtc2817022014-07-02 10:32:10 -07002566#endif /* CONFIG_HS20 */
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002567 { INT_RANGE(mac_addr, 0, 2) },
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002568 { INT_RANGE(pbss, 0, 2) },
2569 { INT_RANGE(wps_disabled, 0, 1) },
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002570 { INT_RANGE(fils_dh_group, 0, 65535) },
2571#ifdef CONFIG_DPP
2572 { STR(dpp_connector) },
2573 { STR_LEN(dpp_netaccesskey) },
2574 { INT(dpp_netaccesskey_expiry) },
2575 { STR_LEN(dpp_csign) },
Hai Shalom899fcc72020-10-19 14:38:18 -07002576 { STR_LEN(dpp_pp_key) },
Hai Shalomfdcde762020-04-02 11:19:20 -07002577 { INT_RANGE(dpp_pfs, 0, 2) },
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002578#endif /* CONFIG_DPP */
2579 { INT_RANGE(owe_group, 0, 65535) },
Roshan Pius3a1667e2018-07-03 15:17:14 -07002580 { INT_RANGE(owe_only, 0, 1) },
Hai Shalomfdcde762020-04-02 11:19:20 -07002581 { INT_RANGE(owe_ptk_workaround, 0, 1) },
Hai Shalom74f70d42019-02-11 14:42:39 -08002582 { INT_RANGE(multi_ap_backhaul_sta, 0, 1) },
Hai Shalom81f62d82019-07-22 12:10:00 -07002583 { INT_RANGE(ft_eap_pmksa_caching, 0, 1) },
Hai Shalomfdcde762020-04-02 11:19:20 -07002584 { INT_RANGE(beacon_prot, 0, 1) },
2585 { INT_RANGE(transition_disable, 0, 255) },
Hai Shalom899fcc72020-10-19 14:38:18 -07002586 { INT_RANGE(sae_pk, 0, 2) },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002587};
2588
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002589#undef OFFSET
2590#undef _STR
2591#undef STR
2592#undef STR_KEY
2593#undef _STR_LEN
2594#undef STR_LEN
2595#undef STR_LEN_KEY
2596#undef _STR_RANGE
2597#undef STR_RANGE
2598#undef STR_RANGE_KEY
2599#undef _INT
2600#undef INT
2601#undef INT_RANGE
2602#undef _FUNC
2603#undef FUNC
2604#undef FUNC_KEY
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002605#define NUM_SSID_FIELDS ARRAY_SIZE(ssid_fields)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002606
2607
2608/**
2609 * wpa_config_add_prio_network - Add a network to priority lists
2610 * @config: Configuration data from wpa_config_read()
2611 * @ssid: Pointer to the network configuration to be added to the list
2612 * Returns: 0 on success, -1 on failure
2613 *
2614 * This function is used to add a network block to the priority list of
2615 * networks. This must be called for each network when reading in the full
2616 * configuration. In addition, this can be used indirectly when updating
2617 * priorities by calling wpa_config_update_prio_list().
2618 */
2619int wpa_config_add_prio_network(struct wpa_config *config,
2620 struct wpa_ssid *ssid)
2621{
Hai Shalomfdcde762020-04-02 11:19:20 -07002622 size_t prio;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002623 struct wpa_ssid *prev, **nlist;
2624
2625 /*
2626 * Add to an existing priority list if one is available for the
2627 * configured priority level for this network.
2628 */
2629 for (prio = 0; prio < config->num_prio; prio++) {
2630 prev = config->pssid[prio];
2631 if (prev->priority == ssid->priority) {
2632 while (prev->pnext)
2633 prev = prev->pnext;
2634 prev->pnext = ssid;
2635 return 0;
2636 }
2637 }
2638
2639 /* First network for this priority - add a new priority list */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002640 nlist = os_realloc_array(config->pssid, config->num_prio + 1,
2641 sizeof(struct wpa_ssid *));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002642 if (nlist == NULL)
2643 return -1;
2644
2645 for (prio = 0; prio < config->num_prio; prio++) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07002646 if (nlist[prio]->priority < ssid->priority) {
2647 os_memmove(&nlist[prio + 1], &nlist[prio],
2648 (config->num_prio - prio) *
2649 sizeof(struct wpa_ssid *));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002650 break;
Dmitry Shmidt04949592012-07-19 12:16:46 -07002651 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002652 }
2653
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002654 nlist[prio] = ssid;
2655 config->num_prio++;
2656 config->pssid = nlist;
2657
2658 return 0;
2659}
2660
2661
2662/**
2663 * wpa_config_update_prio_list - Update network priority list
2664 * @config: Configuration data from wpa_config_read()
2665 * Returns: 0 on success, -1 on failure
2666 *
2667 * This function is called to update the priority list of networks in the
2668 * configuration when a network is being added or removed. This is also called
2669 * if a priority for a network is changed.
2670 */
2671int wpa_config_update_prio_list(struct wpa_config *config)
2672{
2673 struct wpa_ssid *ssid;
2674 int ret = 0;
2675
2676 os_free(config->pssid);
2677 config->pssid = NULL;
2678 config->num_prio = 0;
2679
2680 ssid = config->ssid;
2681 while (ssid) {
2682 ssid->pnext = NULL;
2683 if (wpa_config_add_prio_network(config, ssid) < 0)
2684 ret = -1;
2685 ssid = ssid->next;
2686 }
2687
2688 return ret;
2689}
2690
2691
2692#ifdef IEEE8021X_EAPOL
Hai Shalomc3565922019-10-28 11:58:20 -07002693
2694static void eap_peer_config_free_cert(struct eap_peer_cert_config *cert)
2695{
2696 os_free(cert->ca_cert);
2697 os_free(cert->ca_path);
2698 os_free(cert->client_cert);
2699 os_free(cert->private_key);
2700 str_clear_free(cert->private_key_passwd);
2701 os_free(cert->dh_file);
2702 os_free(cert->subject_match);
2703 os_free(cert->check_cert_subject);
2704 os_free(cert->altsubject_match);
2705 os_free(cert->domain_suffix_match);
2706 os_free(cert->domain_match);
2707 str_clear_free(cert->pin);
2708 os_free(cert->engine_id);
2709 os_free(cert->key_id);
2710 os_free(cert->cert_id);
2711 os_free(cert->ca_cert_id);
2712}
2713
2714
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002715static void eap_peer_config_free(struct eap_peer_config *eap)
2716{
2717 os_free(eap->eap_methods);
Dmitry Shmidtc2817022014-07-02 10:32:10 -07002718 bin_clear_free(eap->identity, eap->identity_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002719 os_free(eap->anonymous_identity);
Jouni Malinena3cb6f02017-12-08 17:05:40 +02002720 os_free(eap->imsi_identity);
Hai Shalomc3565922019-10-28 11:58:20 -07002721 os_free(eap->machine_identity);
Dmitry Shmidtc2817022014-07-02 10:32:10 -07002722 bin_clear_free(eap->password, eap->password_len);
Hai Shalomc3565922019-10-28 11:58:20 -07002723 bin_clear_free(eap->machine_password, eap->machine_password_len);
2724 eap_peer_config_free_cert(&eap->cert);
2725 eap_peer_config_free_cert(&eap->phase2_cert);
2726 eap_peer_config_free_cert(&eap->machine_cert);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002727 os_free(eap->phase1);
2728 os_free(eap->phase2);
Hai Shalomc3565922019-10-28 11:58:20 -07002729 os_free(eap->machine_phase2);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002730 os_free(eap->pcsc);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002731 os_free(eap->otp);
2732 os_free(eap->pending_req_otp);
2733 os_free(eap->pac_file);
Dmitry Shmidtc2817022014-07-02 10:32:10 -07002734 bin_clear_free(eap->new_password, eap->new_password_len);
2735 str_clear_free(eap->external_sim_resp);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002736 os_free(eap->openssl_ciphers);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002737}
Hai Shalomc3565922019-10-28 11:58:20 -07002738
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002739#endif /* IEEE8021X_EAPOL */
2740
2741
2742/**
2743 * wpa_config_free_ssid - Free network/ssid configuration data
2744 * @ssid: Configuration data for the network
2745 *
2746 * This function frees all resources allocated for the network configuration
2747 * data.
2748 */
2749void wpa_config_free_ssid(struct wpa_ssid *ssid)
2750{
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07002751 struct psk_list_entry *psk;
2752
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002753 os_free(ssid->ssid);
Dmitry Shmidtc2817022014-07-02 10:32:10 -07002754 str_clear_free(ssid->passphrase);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002755 os_free(ssid->ext_psk);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002756 str_clear_free(ssid->sae_password);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002757 os_free(ssid->sae_password_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002758#ifdef IEEE8021X_EAPOL
2759 eap_peer_config_free(&ssid->eap);
2760#endif /* IEEE8021X_EAPOL */
2761 os_free(ssid->id_str);
2762 os_free(ssid->scan_freq);
2763 os_free(ssid->freq_list);
2764 os_free(ssid->bgscan);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002765 os_free(ssid->p2p_client_list);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08002766 os_free(ssid->bssid_blacklist);
2767 os_free(ssid->bssid_whitelist);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08002768#ifdef CONFIG_HT_OVERRIDES
2769 os_free(ssid->ht_mcs);
2770#endif /* CONFIG_HT_OVERRIDES */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002771#ifdef CONFIG_MESH
2772 os_free(ssid->mesh_basic_rates);
2773#endif /* CONFIG_MESH */
Roshan Pius3a1667e2018-07-03 15:17:14 -07002774#ifdef CONFIG_HS20
2775 os_free(ssid->roaming_consortium_selection);
2776#endif /* CONFIG_HS20 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002777 os_free(ssid->dpp_connector);
2778 bin_clear_free(ssid->dpp_netaccesskey, ssid->dpp_netaccesskey_len);
2779 os_free(ssid->dpp_csign);
Hai Shalom899fcc72020-10-19 14:38:18 -07002780 os_free(ssid->dpp_pp_key);
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07002781 while ((psk = dl_list_first(&ssid->psk_list, struct psk_list_entry,
2782 list))) {
2783 dl_list_del(&psk->list);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002784 bin_clear_free(psk, sizeof(*psk));
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07002785 }
Hai Shalomc3565922019-10-28 11:58:20 -07002786#ifdef CONFIG_SAE
2787 sae_deinit_pt(ssid->pt);
2788#endif /* CONFIG_SAE */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002789 bin_clear_free(ssid, sizeof(*ssid));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002790}
2791
2792
Dmitry Shmidt04949592012-07-19 12:16:46 -07002793void wpa_config_free_cred(struct wpa_cred *cred)
2794{
Dmitry Shmidt051af732013-10-22 13:52:46 -07002795 size_t i;
2796
Dmitry Shmidt04949592012-07-19 12:16:46 -07002797 os_free(cred->realm);
Dmitry Shmidtc2817022014-07-02 10:32:10 -07002798 str_clear_free(cred->username);
2799 str_clear_free(cred->password);
Dmitry Shmidt04949592012-07-19 12:16:46 -07002800 os_free(cred->ca_cert);
2801 os_free(cred->client_cert);
2802 os_free(cred->private_key);
Dmitry Shmidtc2817022014-07-02 10:32:10 -07002803 str_clear_free(cred->private_key_passwd);
Dmitry Shmidt04949592012-07-19 12:16:46 -07002804 os_free(cred->imsi);
Dmitry Shmidtc2817022014-07-02 10:32:10 -07002805 str_clear_free(cred->milenage);
Dmitry Shmidt051af732013-10-22 13:52:46 -07002806 for (i = 0; i < cred->num_domain; i++)
2807 os_free(cred->domain[i]);
Dmitry Shmidt04949592012-07-19 12:16:46 -07002808 os_free(cred->domain);
Dmitry Shmidt051af732013-10-22 13:52:46 -07002809 os_free(cred->domain_suffix_match);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002810 os_free(cred->eap_method);
2811 os_free(cred->phase1);
2812 os_free(cred->phase2);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002813 os_free(cred->excluded_ssid);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002814 os_free(cred->roaming_partner);
2815 os_free(cred->provisioning_sp);
2816 for (i = 0; i < cred->num_req_conn_capab; i++)
2817 os_free(cred->req_conn_capab_port[i]);
2818 os_free(cred->req_conn_capab_port);
2819 os_free(cred->req_conn_capab_proto);
Dmitry Shmidt04949592012-07-19 12:16:46 -07002820 os_free(cred);
2821}
2822
2823
Dmitry Shmidt344abd32014-01-14 13:17:00 -08002824void wpa_config_flush_blobs(struct wpa_config *config)
2825{
2826#ifndef CONFIG_NO_CONFIG_BLOBS
2827 struct wpa_config_blob *blob, *prev;
2828
2829 blob = config->blobs;
2830 config->blobs = NULL;
2831 while (blob) {
2832 prev = blob;
2833 blob = blob->next;
2834 wpa_config_free_blob(prev);
2835 }
2836#endif /* CONFIG_NO_CONFIG_BLOBS */
2837}
2838
2839
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002840/**
2841 * wpa_config_free - Free configuration data
2842 * @config: Configuration data from wpa_config_read()
2843 *
2844 * This function frees all resources allocated for the configuration data by
2845 * wpa_config_read().
2846 */
2847void wpa_config_free(struct wpa_config *config)
2848{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002849 struct wpa_ssid *ssid, *prev = NULL;
Dmitry Shmidt04949592012-07-19 12:16:46 -07002850 struct wpa_cred *cred, *cprev;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002851 int i;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002852
2853 ssid = config->ssid;
2854 while (ssid) {
2855 prev = ssid;
2856 ssid = ssid->next;
2857 wpa_config_free_ssid(prev);
2858 }
2859
Dmitry Shmidt04949592012-07-19 12:16:46 -07002860 cred = config->cred;
2861 while (cred) {
2862 cprev = cred;
2863 cred = cred->next;
2864 wpa_config_free_cred(cprev);
2865 }
2866
Dmitry Shmidt344abd32014-01-14 13:17:00 -08002867 wpa_config_flush_blobs(config);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002868
Dmitry Shmidt04949592012-07-19 12:16:46 -07002869 wpabuf_free(config->wps_vendor_ext_m1);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002870 for (i = 0; i < MAX_WPS_VENDOR_EXT; i++)
2871 wpabuf_free(config->wps_vendor_ext[i]);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002872 os_free(config->ctrl_interface);
2873 os_free(config->ctrl_interface_group);
2874 os_free(config->opensc_engine_path);
2875 os_free(config->pkcs11_engine_path);
2876 os_free(config->pkcs11_module_path);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002877 os_free(config->openssl_ciphers);
Dmitry Shmidt04949592012-07-19 12:16:46 -07002878 os_free(config->pcsc_reader);
Dmitry Shmidtc2817022014-07-02 10:32:10 -07002879 str_clear_free(config->pcsc_pin);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002880 os_free(config->driver_param);
2881 os_free(config->device_name);
2882 os_free(config->manufacturer);
2883 os_free(config->model_name);
2884 os_free(config->model_number);
2885 os_free(config->serial_number);
2886 os_free(config->config_methods);
2887 os_free(config->p2p_ssid_postfix);
2888 os_free(config->pssid);
Dmitry Shmidt04949592012-07-19 12:16:46 -07002889 os_free(config->p2p_pref_chan);
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002890 os_free(config->p2p_no_go_freq.range);
Dmitry Shmidt04949592012-07-19 12:16:46 -07002891 os_free(config->autoscan);
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07002892 os_free(config->freq_list);
Dmitry Shmidt04949592012-07-19 12:16:46 -07002893 wpabuf_free(config->wps_nfc_dh_pubkey);
2894 wpabuf_free(config->wps_nfc_dh_privkey);
2895 wpabuf_free(config->wps_nfc_dev_pw);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002896 os_free(config->ext_password_backend);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002897 os_free(config->sae_groups);
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07002898 wpabuf_free(config->ap_vendor_elements);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002899 os_free(config->osu_dir);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08002900 os_free(config->bgscan);
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07002901 os_free(config->wowlan_triggers);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002902 os_free(config->fst_group_id);
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08002903 os_free(config->sched_scan_plans);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002904#ifdef CONFIG_MBO
2905 os_free(config->non_pref_chan);
2906#endif /* CONFIG_MBO */
Hai Shalomc3565922019-10-28 11:58:20 -07002907 os_free(config->dpp_name);
2908 os_free(config->dpp_mud_url);
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08002909
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002910 os_free(config);
2911}
2912
2913
2914/**
2915 * wpa_config_foreach_network - Iterate over each configured network
2916 * @config: Configuration data from wpa_config_read()
2917 * @func: Callback function to process each network
2918 * @arg: Opaque argument to pass to callback function
2919 *
2920 * Iterate over the set of configured networks calling the specified
2921 * function for each item. We guard against callbacks removing the
2922 * supplied network.
2923 */
2924void wpa_config_foreach_network(struct wpa_config *config,
2925 void (*func)(void *, struct wpa_ssid *),
2926 void *arg)
2927{
2928 struct wpa_ssid *ssid, *next;
2929
2930 ssid = config->ssid;
2931 while (ssid) {
2932 next = ssid->next;
2933 func(arg, ssid);
2934 ssid = next;
2935 }
2936}
2937
2938
2939/**
2940 * wpa_config_get_network - Get configured network based on id
2941 * @config: Configuration data from wpa_config_read()
2942 * @id: Unique network id to search for
2943 * Returns: Network configuration or %NULL if not found
2944 */
2945struct wpa_ssid * wpa_config_get_network(struct wpa_config *config, int id)
2946{
2947 struct wpa_ssid *ssid;
2948
2949 ssid = config->ssid;
2950 while (ssid) {
2951 if (id == ssid->id)
2952 break;
2953 ssid = ssid->next;
2954 }
2955
2956 return ssid;
2957}
2958
2959
2960/**
2961 * wpa_config_add_network - Add a new network with empty configuration
2962 * @config: Configuration data from wpa_config_read()
2963 * Returns: The new network configuration or %NULL if operation failed
2964 */
2965struct wpa_ssid * wpa_config_add_network(struct wpa_config *config)
2966{
2967 int id;
2968 struct wpa_ssid *ssid, *last = NULL;
2969
2970 id = -1;
2971 ssid = config->ssid;
2972 while (ssid) {
2973 if (ssid->id > id)
2974 id = ssid->id;
2975 last = ssid;
2976 ssid = ssid->next;
2977 }
2978 id++;
2979
2980 ssid = os_zalloc(sizeof(*ssid));
2981 if (ssid == NULL)
2982 return NULL;
2983 ssid->id = id;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07002984 dl_list_init(&ssid->psk_list);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002985 if (last)
2986 last->next = ssid;
2987 else
2988 config->ssid = ssid;
2989
2990 wpa_config_update_prio_list(config);
2991
2992 return ssid;
2993}
2994
2995
2996/**
2997 * wpa_config_remove_network - Remove a configured network based on id
2998 * @config: Configuration data from wpa_config_read()
2999 * @id: Unique network id to search for
3000 * Returns: 0 on success, or -1 if the network was not found
3001 */
3002int wpa_config_remove_network(struct wpa_config *config, int id)
3003{
3004 struct wpa_ssid *ssid, *prev = NULL;
3005
3006 ssid = config->ssid;
3007 while (ssid) {
3008 if (id == ssid->id)
3009 break;
3010 prev = ssid;
3011 ssid = ssid->next;
3012 }
3013
3014 if (ssid == NULL)
3015 return -1;
3016
3017 if (prev)
3018 prev->next = ssid->next;
3019 else
3020 config->ssid = ssid->next;
3021
3022 wpa_config_update_prio_list(config);
3023 wpa_config_free_ssid(ssid);
3024 return 0;
3025}
3026
3027
3028/**
3029 * wpa_config_set_network_defaults - Set network default values
3030 * @ssid: Pointer to network configuration data
3031 */
3032void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
3033{
3034 ssid->proto = DEFAULT_PROTO;
3035 ssid->pairwise_cipher = DEFAULT_PAIRWISE;
3036 ssid->group_cipher = DEFAULT_GROUP;
3037 ssid->key_mgmt = DEFAULT_KEY_MGMT;
Hai Shalomfdcde762020-04-02 11:19:20 -07003038 ssid->wpa_deny_ptk0_rekey = PTK0_REKEY_ALLOW_ALWAYS;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003039 ssid->bg_scan_period = DEFAULT_BG_SCAN_PERIOD;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003040 ssid->ht = 1;
Hai Shalom899fcc72020-10-19 14:38:18 -07003041 ssid->vht = 1;
3042 ssid->he = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003043#ifdef IEEE8021X_EAPOL
3044 ssid->eapol_flags = DEFAULT_EAPOL_FLAGS;
3045 ssid->eap_workaround = DEFAULT_EAP_WORKAROUND;
3046 ssid->eap.fragment_size = DEFAULT_FRAGMENT_SIZE;
Dmitry Shmidtf9bdef92014-04-25 10:46:36 -07003047 ssid->eap.sim_num = DEFAULT_USER_SELECTED_SIM;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003048#endif /* IEEE8021X_EAPOL */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003049#ifdef CONFIG_MESH
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003050 ssid->dot11MeshMaxRetries = DEFAULT_MESH_MAX_RETRIES;
3051 ssid->dot11MeshRetryTimeout = DEFAULT_MESH_RETRY_TIMEOUT;
3052 ssid->dot11MeshConfirmTimeout = DEFAULT_MESH_CONFIRM_TIMEOUT;
3053 ssid->dot11MeshHoldingTimeout = DEFAULT_MESH_HOLDING_TIMEOUT;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003054 ssid->mesh_rssi_threshold = DEFAULT_MESH_RSSI_THRESHOLD;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003055#endif /* CONFIG_MESH */
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08003056#ifdef CONFIG_HT_OVERRIDES
3057 ssid->disable_ht = DEFAULT_DISABLE_HT;
3058 ssid->disable_ht40 = DEFAULT_DISABLE_HT40;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08003059 ssid->disable_sgi = DEFAULT_DISABLE_SGI;
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07003060 ssid->disable_ldpc = DEFAULT_DISABLE_LDPC;
Hai Shalom74f70d42019-02-11 14:42:39 -08003061 ssid->tx_stbc = DEFAULT_TX_STBC;
3062 ssid->rx_stbc = DEFAULT_RX_STBC;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08003063 ssid->disable_max_amsdu = DEFAULT_DISABLE_MAX_AMSDU;
3064 ssid->ampdu_factor = DEFAULT_AMPDU_FACTOR;
3065 ssid->ampdu_density = DEFAULT_AMPDU_DENSITY;
3066#endif /* CONFIG_HT_OVERRIDES */
Dmitry Shmidt2f023192013-03-12 12:44:17 -07003067#ifdef CONFIG_VHT_OVERRIDES
3068 ssid->vht_rx_mcs_nss_1 = -1;
3069 ssid->vht_rx_mcs_nss_2 = -1;
3070 ssid->vht_rx_mcs_nss_3 = -1;
3071 ssid->vht_rx_mcs_nss_4 = -1;
3072 ssid->vht_rx_mcs_nss_5 = -1;
3073 ssid->vht_rx_mcs_nss_6 = -1;
3074 ssid->vht_rx_mcs_nss_7 = -1;
3075 ssid->vht_rx_mcs_nss_8 = -1;
3076 ssid->vht_tx_mcs_nss_1 = -1;
3077 ssid->vht_tx_mcs_nss_2 = -1;
3078 ssid->vht_tx_mcs_nss_3 = -1;
3079 ssid->vht_tx_mcs_nss_4 = -1;
3080 ssid->vht_tx_mcs_nss_5 = -1;
3081 ssid->vht_tx_mcs_nss_6 = -1;
3082 ssid->vht_tx_mcs_nss_7 = -1;
3083 ssid->vht_tx_mcs_nss_8 = -1;
3084#endif /* CONFIG_VHT_OVERRIDES */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003085 ssid->proactive_key_caching = -1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003086 ssid->ieee80211w = MGMT_FRAME_PROTECTION_DEFAULT;
Dmitry Shmidt29333592017-01-09 12:27:11 -08003087#ifdef CONFIG_MACSEC
3088 ssid->mka_priority = DEFAULT_PRIO_NOT_KEY_SERVER;
3089#endif /* CONFIG_MACSEC */
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07003090 ssid->mac_addr = -1;
Hai Shalom74f70d42019-02-11 14:42:39 -08003091 ssid->max_oper_chwidth = DEFAULT_MAX_OPER_CHWIDTH;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003092}
3093
3094
3095/**
3096 * wpa_config_set - Set a variable in network configuration
3097 * @ssid: Pointer to network configuration data
3098 * @var: Variable name, e.g., "ssid"
3099 * @value: Variable value
3100 * @line: Line number in configuration file or 0 if not used
Dmitry Shmidte4663042016-04-04 10:07:49 -07003101 * Returns: 0 on success with possible change in the value, 1 on success with
3102 * no change to previously configured value, or -1 on failure
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003103 *
3104 * This function can be used to set network configuration variables based on
3105 * both the configuration file and management interface input. The value
3106 * parameter must be in the same format as the text-based configuration file is
3107 * using. For example, strings are using double quotation marks.
3108 */
3109int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
3110 int line)
3111{
3112 size_t i;
3113 int ret = 0;
3114
3115 if (ssid == NULL || var == NULL || value == NULL)
3116 return -1;
3117
3118 for (i = 0; i < NUM_SSID_FIELDS; i++) {
3119 const struct parse_data *field = &ssid_fields[i];
3120 if (os_strcmp(var, field->name) != 0)
3121 continue;
3122
Dmitry Shmidte4663042016-04-04 10:07:49 -07003123 ret = field->parser(field, ssid, line, value);
3124 if (ret < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003125 if (line) {
3126 wpa_printf(MSG_ERROR, "Line %d: failed to "
3127 "parse %s '%s'.", line, var, value);
3128 }
3129 ret = -1;
3130 }
Hai Shalomc3565922019-10-28 11:58:20 -07003131#ifdef CONFIG_SAE
3132 if (os_strcmp(var, "ssid") == 0 ||
3133 os_strcmp(var, "psk") == 0 ||
3134 os_strcmp(var, "sae_password") == 0 ||
3135 os_strcmp(var, "sae_password_id") == 0) {
3136 sae_deinit_pt(ssid->pt);
3137 ssid->pt = NULL;
3138 }
3139#endif /* CONFIG_SAE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003140 break;
3141 }
3142 if (i == NUM_SSID_FIELDS) {
3143 if (line) {
3144 wpa_printf(MSG_ERROR, "Line %d: unknown network field "
3145 "'%s'.", line, var);
3146 }
3147 ret = -1;
3148 }
Hai Shalom899fcc72020-10-19 14:38:18 -07003149 ssid->was_recently_reconfigured = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003150
3151 return ret;
3152}
3153
3154
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003155int wpa_config_set_quoted(struct wpa_ssid *ssid, const char *var,
3156 const char *value)
3157{
3158 size_t len;
3159 char *buf;
3160 int ret;
3161
3162 len = os_strlen(value);
3163 buf = os_malloc(len + 3);
3164 if (buf == NULL)
3165 return -1;
3166 buf[0] = '"';
3167 os_memcpy(buf + 1, value, len);
3168 buf[len + 1] = '"';
3169 buf[len + 2] = '\0';
3170 ret = wpa_config_set(ssid, var, buf, 0);
3171 os_free(buf);
3172 return ret;
3173}
3174
3175
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003176/**
3177 * wpa_config_get_all - Get all options from network configuration
3178 * @ssid: Pointer to network configuration data
3179 * @get_keys: Determines if keys/passwords will be included in returned list
3180 * (if they may be exported)
3181 * Returns: %NULL terminated list of all set keys and their values in the form
3182 * of [key1, val1, key2, val2, ... , NULL]
3183 *
3184 * This function can be used to get list of all configured network properties.
3185 * The caller is responsible for freeing the returned list and all its
3186 * elements.
3187 */
3188char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys)
3189{
Dmitry Shmidt83474442015-04-15 13:47:09 -07003190#ifdef NO_CONFIG_WRITE
3191 return NULL;
3192#else /* NO_CONFIG_WRITE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003193 const struct parse_data *field;
3194 char *key, *value;
3195 size_t i;
3196 char **props;
3197 int fields_num;
3198
3199 get_keys = get_keys && ssid->export_keys;
3200
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003201 props = os_calloc(2 * NUM_SSID_FIELDS + 1, sizeof(char *));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003202 if (!props)
3203 return NULL;
3204
3205 fields_num = 0;
3206 for (i = 0; i < NUM_SSID_FIELDS; i++) {
3207 field = &ssid_fields[i];
3208 if (field->key_data && !get_keys)
3209 continue;
3210 value = field->writer(field, ssid);
3211 if (value == NULL)
3212 continue;
3213 if (os_strlen(value) == 0) {
3214 os_free(value);
3215 continue;
3216 }
3217
3218 key = os_strdup(field->name);
3219 if (key == NULL) {
3220 os_free(value);
3221 goto err;
3222 }
3223
3224 props[fields_num * 2] = key;
3225 props[fields_num * 2 + 1] = value;
3226
3227 fields_num++;
3228 }
3229
3230 return props;
3231
3232err:
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07003233 for (i = 0; props[i]; i++)
3234 os_free(props[i]);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003235 os_free(props);
3236 return NULL;
Dmitry Shmidt83474442015-04-15 13:47:09 -07003237#endif /* NO_CONFIG_WRITE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003238}
3239
3240
3241#ifndef NO_CONFIG_WRITE
3242/**
3243 * wpa_config_get - Get a variable in network configuration
3244 * @ssid: Pointer to network configuration data
3245 * @var: Variable name, e.g., "ssid"
3246 * Returns: Value of the variable or %NULL on failure
3247 *
3248 * This function can be used to get network configuration variables. The
3249 * returned value is a copy of the configuration variable in text format, i.e,.
3250 * the same format that the text-based configuration file and wpa_config_set()
3251 * are using for the value. The caller is responsible for freeing the returned
3252 * value.
3253 */
3254char * wpa_config_get(struct wpa_ssid *ssid, const char *var)
3255{
3256 size_t i;
3257
3258 if (ssid == NULL || var == NULL)
3259 return NULL;
3260
3261 for (i = 0; i < NUM_SSID_FIELDS; i++) {
3262 const struct parse_data *field = &ssid_fields[i];
Paul Stewart85c72c62016-03-03 15:33:47 -08003263 if (os_strcmp(var, field->name) == 0) {
3264 char *ret = field->writer(field, ssid);
Dmitry Shmidt849734c2016-05-27 09:59:01 -07003265
3266 if (ret && has_newline(ret)) {
Paul Stewart35800752016-03-18 18:14:26 -07003267 wpa_printf(MSG_ERROR,
Dmitry Shmidt849734c2016-05-27 09:59:01 -07003268 "Found newline in value for %s; not returning it",
3269 var);
Paul Stewart85c72c62016-03-03 15:33:47 -08003270 os_free(ret);
3271 ret = NULL;
3272 }
Dmitry Shmidt849734c2016-05-27 09:59:01 -07003273
Paul Stewart85c72c62016-03-03 15:33:47 -08003274 return ret;
3275 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003276 }
3277
3278 return NULL;
3279}
3280
3281
3282/**
3283 * wpa_config_get_no_key - Get a variable in network configuration (no keys)
3284 * @ssid: Pointer to network configuration data
3285 * @var: Variable name, e.g., "ssid"
3286 * Returns: Value of the variable or %NULL on failure
3287 *
3288 * This function can be used to get network configuration variable like
3289 * wpa_config_get(). The only difference is that this functions does not expose
3290 * key/password material from the configuration. In case a key/password field
3291 * is requested, the returned value is an empty string or %NULL if the variable
3292 * is not set or "*" if the variable is set (regardless of its value). The
3293 * returned value is a copy of the configuration variable in text format, i.e,.
3294 * the same format that the text-based configuration file and wpa_config_set()
3295 * are using for the value. The caller is responsible for freeing the returned
3296 * value.
3297 */
3298char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var)
3299{
3300 size_t i;
3301
3302 if (ssid == NULL || var == NULL)
3303 return NULL;
3304
3305 for (i = 0; i < NUM_SSID_FIELDS; i++) {
3306 const struct parse_data *field = &ssid_fields[i];
3307 if (os_strcmp(var, field->name) == 0) {
3308 char *res = field->writer(field, ssid);
3309 if (field->key_data) {
3310 if (res && res[0]) {
3311 wpa_printf(MSG_DEBUG, "Do not allow "
3312 "key_data field to be "
3313 "exposed");
Dmitry Shmidtc2817022014-07-02 10:32:10 -07003314 str_clear_free(res);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003315 return os_strdup("*");
3316 }
3317
3318 os_free(res);
3319 return NULL;
3320 }
3321 return res;
3322 }
3323 }
3324
3325 return NULL;
3326}
3327#endif /* NO_CONFIG_WRITE */
3328
3329
3330/**
3331 * wpa_config_update_psk - Update WPA PSK based on passphrase and SSID
3332 * @ssid: Pointer to network configuration data
3333 *
3334 * This function must be called to update WPA PSK when either SSID or the
3335 * passphrase has changed for the network configuration.
3336 */
3337void wpa_config_update_psk(struct wpa_ssid *ssid)
3338{
3339#ifndef CONFIG_NO_PBKDF2
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003340 pbkdf2_sha1(ssid->passphrase, ssid->ssid, ssid->ssid_len, 4096,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003341 ssid->psk, PMK_LEN);
3342 wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
3343 ssid->psk, PMK_LEN);
3344 ssid->psk_set = 1;
3345#endif /* CONFIG_NO_PBKDF2 */
3346}
3347
3348
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08003349static int wpa_config_set_cred_req_conn_capab(struct wpa_cred *cred,
3350 const char *value)
3351{
3352 u8 *proto;
3353 int **port;
3354 int *ports, *nports;
3355 const char *pos;
3356 unsigned int num_ports;
3357
3358 proto = os_realloc_array(cred->req_conn_capab_proto,
3359 cred->num_req_conn_capab + 1, sizeof(u8));
3360 if (proto == NULL)
3361 return -1;
3362 cred->req_conn_capab_proto = proto;
3363
3364 port = os_realloc_array(cred->req_conn_capab_port,
3365 cred->num_req_conn_capab + 1, sizeof(int *));
3366 if (port == NULL)
3367 return -1;
3368 cred->req_conn_capab_port = port;
3369
3370 proto[cred->num_req_conn_capab] = atoi(value);
3371
3372 pos = os_strchr(value, ':');
3373 if (pos == NULL) {
3374 port[cred->num_req_conn_capab] = NULL;
3375 cred->num_req_conn_capab++;
3376 return 0;
3377 }
3378 pos++;
3379
3380 ports = NULL;
3381 num_ports = 0;
3382
3383 while (*pos) {
3384 nports = os_realloc_array(ports, num_ports + 1, sizeof(int));
3385 if (nports == NULL) {
3386 os_free(ports);
3387 return -1;
3388 }
3389 ports = nports;
3390 ports[num_ports++] = atoi(pos);
3391
3392 pos = os_strchr(pos, ',');
3393 if (pos == NULL)
3394 break;
3395 pos++;
3396 }
3397
3398 nports = os_realloc_array(ports, num_ports + 1, sizeof(int));
3399 if (nports == NULL) {
3400 os_free(ports);
3401 return -1;
3402 }
3403 ports = nports;
3404 ports[num_ports] = -1;
3405
3406 port[cred->num_req_conn_capab] = ports;
3407 cred->num_req_conn_capab++;
3408 return 0;
3409}
3410
3411
Roshan Pius3a1667e2018-07-03 15:17:14 -07003412static int wpa_config_set_cred_roaming_consortiums(struct wpa_cred *cred,
3413 const char *value)
3414{
3415 u8 roaming_consortiums[MAX_ROAMING_CONS][MAX_ROAMING_CONS_OI_LEN];
3416 size_t roaming_consortiums_len[MAX_ROAMING_CONS];
3417 unsigned int num_roaming_consortiums = 0;
3418 const char *pos, *end;
3419 size_t len;
3420
3421 os_memset(roaming_consortiums, 0, sizeof(roaming_consortiums));
3422 os_memset(roaming_consortiums_len, 0, sizeof(roaming_consortiums_len));
3423
3424 for (pos = value;;) {
3425 end = os_strchr(pos, ',');
3426 len = end ? (size_t) (end - pos) : os_strlen(pos);
3427 if (!end && len == 0)
3428 break;
3429 if (len == 0 || (len & 1) != 0 ||
3430 len / 2 > MAX_ROAMING_CONS_OI_LEN ||
3431 hexstr2bin(pos,
3432 roaming_consortiums[num_roaming_consortiums],
3433 len / 2) < 0) {
3434 wpa_printf(MSG_INFO,
3435 "Invalid roaming_consortiums entry: %s",
3436 pos);
3437 return -1;
3438 }
3439 roaming_consortiums_len[num_roaming_consortiums] = len / 2;
3440 num_roaming_consortiums++;
Hai Shalom39ba6fc2019-01-22 12:40:38 -08003441
3442 if (!end)
3443 break;
3444
3445 if (num_roaming_consortiums >= MAX_ROAMING_CONS) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003446 wpa_printf(MSG_INFO,
3447 "Too many roaming_consortiums OIs");
3448 return -1;
3449 }
3450
Roshan Pius3a1667e2018-07-03 15:17:14 -07003451 pos = end + 1;
3452 }
3453
3454 os_memcpy(cred->roaming_consortiums, roaming_consortiums,
3455 sizeof(roaming_consortiums));
3456 os_memcpy(cred->roaming_consortiums_len, roaming_consortiums_len,
3457 sizeof(roaming_consortiums_len));
3458 cred->num_roaming_consortiums = num_roaming_consortiums;
3459
3460 return 0;
3461}
3462
3463
Dmitry Shmidt04949592012-07-19 12:16:46 -07003464int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
3465 const char *value, int line)
3466{
3467 char *val;
3468 size_t len;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003469 int res;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003470
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003471 if (os_strcmp(var, "temporary") == 0) {
3472 cred->temporary = atoi(value);
3473 return 0;
3474 }
3475
Dmitry Shmidt04949592012-07-19 12:16:46 -07003476 if (os_strcmp(var, "priority") == 0) {
3477 cred->priority = atoi(value);
3478 return 0;
3479 }
3480
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08003481 if (os_strcmp(var, "sp_priority") == 0) {
3482 int prio = atoi(value);
3483 if (prio < 0 || prio > 255)
3484 return -1;
3485 cred->sp_priority = prio;
3486 return 0;
3487 }
3488
Dmitry Shmidt04949592012-07-19 12:16:46 -07003489 if (os_strcmp(var, "pcsc") == 0) {
3490 cred->pcsc = atoi(value);
3491 return 0;
3492 }
3493
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003494 if (os_strcmp(var, "eap") == 0) {
3495 struct eap_method_type method;
3496 method.method = eap_peer_get_type(value, &method.vendor);
3497 if (method.vendor == EAP_VENDOR_IETF &&
3498 method.method == EAP_TYPE_NONE) {
3499 wpa_printf(MSG_ERROR, "Line %d: unknown EAP type '%s' "
3500 "for a credential", line, value);
3501 return -1;
3502 }
3503 os_free(cred->eap_method);
3504 cred->eap_method = os_malloc(sizeof(*cred->eap_method));
3505 if (cred->eap_method == NULL)
3506 return -1;
3507 os_memcpy(cred->eap_method, &method, sizeof(method));
3508 return 0;
3509 }
3510
3511 if (os_strcmp(var, "password") == 0 &&
3512 os_strncmp(value, "ext:", 4) == 0) {
Dmitry Shmidt849734c2016-05-27 09:59:01 -07003513 if (has_newline(value))
3514 return -1;
Dmitry Shmidtc2817022014-07-02 10:32:10 -07003515 str_clear_free(cred->password);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003516 cred->password = os_strdup(value);
3517 cred->ext_password = 1;
3518 return 0;
3519 }
3520
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08003521 if (os_strcmp(var, "update_identifier") == 0) {
3522 cred->update_identifier = atoi(value);
3523 return 0;
3524 }
3525
3526 if (os_strcmp(var, "min_dl_bandwidth_home") == 0) {
3527 cred->min_dl_bandwidth_home = atoi(value);
3528 return 0;
3529 }
3530
3531 if (os_strcmp(var, "min_ul_bandwidth_home") == 0) {
3532 cred->min_ul_bandwidth_home = atoi(value);
3533 return 0;
3534 }
3535
3536 if (os_strcmp(var, "min_dl_bandwidth_roaming") == 0) {
3537 cred->min_dl_bandwidth_roaming = atoi(value);
3538 return 0;
3539 }
3540
3541 if (os_strcmp(var, "min_ul_bandwidth_roaming") == 0) {
3542 cred->min_ul_bandwidth_roaming = atoi(value);
3543 return 0;
3544 }
3545
3546 if (os_strcmp(var, "max_bss_load") == 0) {
3547 cred->max_bss_load = atoi(value);
3548 return 0;
3549 }
3550
3551 if (os_strcmp(var, "req_conn_capab") == 0)
3552 return wpa_config_set_cred_req_conn_capab(cred, value);
3553
3554 if (os_strcmp(var, "ocsp") == 0) {
3555 cred->ocsp = atoi(value);
3556 return 0;
3557 }
3558
Dmitry Shmidtf9bdef92014-04-25 10:46:36 -07003559 if (os_strcmp(var, "sim_num") == 0) {
3560 cred->sim_num = atoi(value);
3561 return 0;
3562 }
3563
Dmitry Shmidt04949592012-07-19 12:16:46 -07003564 val = wpa_config_parse_string(value, &len);
Dmitry Shmidt849734c2016-05-27 09:59:01 -07003565 if (val == NULL ||
3566 (os_strcmp(var, "excluded_ssid") != 0 &&
3567 os_strcmp(var, "roaming_consortium") != 0 &&
3568 os_strcmp(var, "required_roaming_consortium") != 0 &&
3569 has_newline(val))) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07003570 wpa_printf(MSG_ERROR, "Line %d: invalid field '%s' string "
3571 "value '%s'.", line, var, value);
Dmitry Shmidt849734c2016-05-27 09:59:01 -07003572 os_free(val);
Dmitry Shmidt04949592012-07-19 12:16:46 -07003573 return -1;
3574 }
3575
3576 if (os_strcmp(var, "realm") == 0) {
3577 os_free(cred->realm);
3578 cred->realm = val;
3579 return 0;
3580 }
3581
3582 if (os_strcmp(var, "username") == 0) {
Dmitry Shmidtc2817022014-07-02 10:32:10 -07003583 str_clear_free(cred->username);
Dmitry Shmidt04949592012-07-19 12:16:46 -07003584 cred->username = val;
3585 return 0;
3586 }
3587
3588 if (os_strcmp(var, "password") == 0) {
Dmitry Shmidtc2817022014-07-02 10:32:10 -07003589 str_clear_free(cred->password);
Dmitry Shmidt04949592012-07-19 12:16:46 -07003590 cred->password = val;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003591 cred->ext_password = 0;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003592 return 0;
3593 }
3594
3595 if (os_strcmp(var, "ca_cert") == 0) {
3596 os_free(cred->ca_cert);
3597 cred->ca_cert = val;
3598 return 0;
3599 }
3600
3601 if (os_strcmp(var, "client_cert") == 0) {
3602 os_free(cred->client_cert);
3603 cred->client_cert = val;
3604 return 0;
3605 }
3606
3607 if (os_strcmp(var, "private_key") == 0) {
3608 os_free(cred->private_key);
3609 cred->private_key = val;
3610 return 0;
3611 }
3612
3613 if (os_strcmp(var, "private_key_passwd") == 0) {
Dmitry Shmidtc2817022014-07-02 10:32:10 -07003614 str_clear_free(cred->private_key_passwd);
Dmitry Shmidt04949592012-07-19 12:16:46 -07003615 cred->private_key_passwd = val;
3616 return 0;
3617 }
3618
3619 if (os_strcmp(var, "imsi") == 0) {
3620 os_free(cred->imsi);
3621 cred->imsi = val;
3622 return 0;
3623 }
3624
3625 if (os_strcmp(var, "milenage") == 0) {
Dmitry Shmidtc2817022014-07-02 10:32:10 -07003626 str_clear_free(cred->milenage);
Dmitry Shmidt04949592012-07-19 12:16:46 -07003627 cred->milenage = val;
3628 return 0;
3629 }
3630
Dmitry Shmidt051af732013-10-22 13:52:46 -07003631 if (os_strcmp(var, "domain_suffix_match") == 0) {
3632 os_free(cred->domain_suffix_match);
3633 cred->domain_suffix_match = val;
3634 return 0;
3635 }
3636
Dmitry Shmidt04949592012-07-19 12:16:46 -07003637 if (os_strcmp(var, "domain") == 0) {
Dmitry Shmidt051af732013-10-22 13:52:46 -07003638 char **new_domain;
3639 new_domain = os_realloc_array(cred->domain,
3640 cred->num_domain + 1,
3641 sizeof(char *));
3642 if (new_domain == NULL) {
3643 os_free(val);
3644 return -1;
3645 }
3646 new_domain[cred->num_domain++] = val;
3647 cred->domain = new_domain;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003648 return 0;
3649 }
3650
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003651 if (os_strcmp(var, "phase1") == 0) {
3652 os_free(cred->phase1);
3653 cred->phase1 = val;
3654 return 0;
3655 }
3656
3657 if (os_strcmp(var, "phase2") == 0) {
3658 os_free(cred->phase2);
3659 cred->phase2 = val;
3660 return 0;
3661 }
3662
3663 if (os_strcmp(var, "roaming_consortium") == 0) {
3664 if (len < 3 || len > sizeof(cred->roaming_consortium)) {
3665 wpa_printf(MSG_ERROR, "Line %d: invalid "
3666 "roaming_consortium length %d (3..15 "
3667 "expected)", line, (int) len);
3668 os_free(val);
3669 return -1;
3670 }
3671 os_memcpy(cred->roaming_consortium, val, len);
3672 cred->roaming_consortium_len = len;
3673 os_free(val);
3674 return 0;
3675 }
3676
Dmitry Shmidt051af732013-10-22 13:52:46 -07003677 if (os_strcmp(var, "required_roaming_consortium") == 0) {
3678 if (len < 3 || len > sizeof(cred->required_roaming_consortium))
3679 {
3680 wpa_printf(MSG_ERROR, "Line %d: invalid "
3681 "required_roaming_consortium length %d "
3682 "(3..15 expected)", line, (int) len);
3683 os_free(val);
3684 return -1;
3685 }
3686 os_memcpy(cred->required_roaming_consortium, val, len);
3687 cred->required_roaming_consortium_len = len;
3688 os_free(val);
3689 return 0;
3690 }
3691
Roshan Pius3a1667e2018-07-03 15:17:14 -07003692 if (os_strcmp(var, "roaming_consortiums") == 0) {
3693 res = wpa_config_set_cred_roaming_consortiums(cred, val);
3694 if (res < 0)
3695 wpa_printf(MSG_ERROR,
3696 "Line %d: invalid roaming_consortiums",
3697 line);
3698 os_free(val);
3699 return res;
3700 }
3701
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08003702 if (os_strcmp(var, "excluded_ssid") == 0) {
3703 struct excluded_ssid *e;
3704
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07003705 if (len > SSID_MAX_LEN) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08003706 wpa_printf(MSG_ERROR, "Line %d: invalid "
3707 "excluded_ssid length %d", line, (int) len);
3708 os_free(val);
3709 return -1;
3710 }
3711
3712 e = os_realloc_array(cred->excluded_ssid,
3713 cred->num_excluded_ssid + 1,
3714 sizeof(struct excluded_ssid));
3715 if (e == NULL) {
3716 os_free(val);
3717 return -1;
3718 }
3719 cred->excluded_ssid = e;
3720
3721 e = &cred->excluded_ssid[cred->num_excluded_ssid++];
3722 os_memcpy(e->ssid, val, len);
3723 e->ssid_len = len;
3724
3725 os_free(val);
3726
3727 return 0;
3728 }
3729
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08003730 if (os_strcmp(var, "roaming_partner") == 0) {
3731 struct roaming_partner *p;
3732 char *pos;
3733
3734 p = os_realloc_array(cred->roaming_partner,
3735 cred->num_roaming_partner + 1,
3736 sizeof(struct roaming_partner));
3737 if (p == NULL) {
3738 os_free(val);
3739 return -1;
3740 }
3741 cred->roaming_partner = p;
3742
3743 p = &cred->roaming_partner[cred->num_roaming_partner];
3744
3745 pos = os_strchr(val, ',');
3746 if (pos == NULL) {
3747 os_free(val);
3748 return -1;
3749 }
3750 *pos++ = '\0';
3751 if (pos - val - 1 >= (int) sizeof(p->fqdn)) {
3752 os_free(val);
3753 return -1;
3754 }
3755 os_memcpy(p->fqdn, val, pos - val);
3756
3757 p->exact_match = atoi(pos);
3758
3759 pos = os_strchr(pos, ',');
3760 if (pos == NULL) {
3761 os_free(val);
3762 return -1;
3763 }
3764 *pos++ = '\0';
3765
3766 p->priority = atoi(pos);
3767
3768 pos = os_strchr(pos, ',');
3769 if (pos == NULL) {
3770 os_free(val);
3771 return -1;
3772 }
3773 *pos++ = '\0';
3774
3775 if (os_strlen(pos) >= sizeof(p->country)) {
3776 os_free(val);
3777 return -1;
3778 }
3779 os_memcpy(p->country, pos, os_strlen(pos) + 1);
3780
3781 cred->num_roaming_partner++;
3782 os_free(val);
3783
3784 return 0;
3785 }
3786
3787 if (os_strcmp(var, "provisioning_sp") == 0) {
3788 os_free(cred->provisioning_sp);
3789 cred->provisioning_sp = val;
3790 return 0;
3791 }
3792
Dmitry Shmidt04949592012-07-19 12:16:46 -07003793 if (line) {
3794 wpa_printf(MSG_ERROR, "Line %d: unknown cred field '%s'.",
3795 line, var);
3796 }
3797
3798 os_free(val);
3799
3800 return -1;
3801}
3802
3803
Dmitry Shmidtc2817022014-07-02 10:32:10 -07003804static char * alloc_int_str(int val)
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07003805{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003806 const unsigned int bufsize = 20;
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07003807 char *buf;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003808 int res;
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07003809
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003810 buf = os_malloc(bufsize);
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07003811 if (buf == NULL)
3812 return NULL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003813 res = os_snprintf(buf, bufsize, "%d", val);
3814 if (os_snprintf_error(bufsize, res)) {
3815 os_free(buf);
3816 buf = NULL;
3817 }
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07003818 return buf;
3819}
3820
3821
Dmitry Shmidtc2817022014-07-02 10:32:10 -07003822static char * alloc_strdup(const char *str)
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07003823{
3824 if (str == NULL)
3825 return NULL;
3826 return os_strdup(str);
3827}
3828
3829
3830char * wpa_config_get_cred_no_key(struct wpa_cred *cred, const char *var)
3831{
3832 if (os_strcmp(var, "temporary") == 0)
3833 return alloc_int_str(cred->temporary);
3834
3835 if (os_strcmp(var, "priority") == 0)
3836 return alloc_int_str(cred->priority);
3837
3838 if (os_strcmp(var, "sp_priority") == 0)
3839 return alloc_int_str(cred->sp_priority);
3840
3841 if (os_strcmp(var, "pcsc") == 0)
3842 return alloc_int_str(cred->pcsc);
3843
3844 if (os_strcmp(var, "eap") == 0) {
3845 if (!cred->eap_method)
3846 return NULL;
3847 return alloc_strdup(eap_get_name(cred->eap_method[0].vendor,
3848 cred->eap_method[0].method));
3849 }
3850
3851 if (os_strcmp(var, "update_identifier") == 0)
3852 return alloc_int_str(cred->update_identifier);
3853
3854 if (os_strcmp(var, "min_dl_bandwidth_home") == 0)
3855 return alloc_int_str(cred->min_dl_bandwidth_home);
3856
3857 if (os_strcmp(var, "min_ul_bandwidth_home") == 0)
3858 return alloc_int_str(cred->min_ul_bandwidth_home);
3859
3860 if (os_strcmp(var, "min_dl_bandwidth_roaming") == 0)
3861 return alloc_int_str(cred->min_dl_bandwidth_roaming);
3862
3863 if (os_strcmp(var, "min_ul_bandwidth_roaming") == 0)
3864 return alloc_int_str(cred->min_ul_bandwidth_roaming);
3865
3866 if (os_strcmp(var, "max_bss_load") == 0)
3867 return alloc_int_str(cred->max_bss_load);
3868
3869 if (os_strcmp(var, "req_conn_capab") == 0) {
3870 unsigned int i;
3871 char *buf, *end, *pos;
3872 int ret;
3873
3874 if (!cred->num_req_conn_capab)
3875 return NULL;
3876
3877 buf = os_malloc(4000);
3878 if (buf == NULL)
3879 return NULL;
3880 pos = buf;
3881 end = pos + 4000;
3882 for (i = 0; i < cred->num_req_conn_capab; i++) {
3883 int *ports;
3884
3885 ret = os_snprintf(pos, end - pos, "%s%u",
3886 i > 0 ? "\n" : "",
3887 cred->req_conn_capab_proto[i]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003888 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07003889 return buf;
3890 pos += ret;
3891
3892 ports = cred->req_conn_capab_port[i];
3893 if (ports) {
3894 int j;
3895 for (j = 0; ports[j] != -1; j++) {
3896 ret = os_snprintf(pos, end - pos,
3897 "%s%d",
3898 j > 0 ? "," : ":",
3899 ports[j]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003900 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07003901 return buf;
3902 pos += ret;
3903 }
3904 }
3905 }
3906
3907 return buf;
3908 }
3909
3910 if (os_strcmp(var, "ocsp") == 0)
3911 return alloc_int_str(cred->ocsp);
3912
3913 if (os_strcmp(var, "realm") == 0)
3914 return alloc_strdup(cred->realm);
3915
3916 if (os_strcmp(var, "username") == 0)
3917 return alloc_strdup(cred->username);
3918
3919 if (os_strcmp(var, "password") == 0) {
3920 if (!cred->password)
3921 return NULL;
3922 return alloc_strdup("*");
3923 }
3924
3925 if (os_strcmp(var, "ca_cert") == 0)
3926 return alloc_strdup(cred->ca_cert);
3927
3928 if (os_strcmp(var, "client_cert") == 0)
3929 return alloc_strdup(cred->client_cert);
3930
3931 if (os_strcmp(var, "private_key") == 0)
3932 return alloc_strdup(cred->private_key);
3933
3934 if (os_strcmp(var, "private_key_passwd") == 0) {
3935 if (!cred->private_key_passwd)
3936 return NULL;
3937 return alloc_strdup("*");
3938 }
3939
3940 if (os_strcmp(var, "imsi") == 0)
3941 return alloc_strdup(cred->imsi);
3942
3943 if (os_strcmp(var, "milenage") == 0) {
3944 if (!(cred->milenage))
3945 return NULL;
3946 return alloc_strdup("*");
3947 }
3948
3949 if (os_strcmp(var, "domain_suffix_match") == 0)
3950 return alloc_strdup(cred->domain_suffix_match);
3951
3952 if (os_strcmp(var, "domain") == 0) {
3953 unsigned int i;
3954 char *buf, *end, *pos;
3955 int ret;
3956
3957 if (!cred->num_domain)
3958 return NULL;
3959
3960 buf = os_malloc(4000);
3961 if (buf == NULL)
3962 return NULL;
3963 pos = buf;
3964 end = pos + 4000;
3965
3966 for (i = 0; i < cred->num_domain; i++) {
3967 ret = os_snprintf(pos, end - pos, "%s%s",
3968 i > 0 ? "\n" : "", cred->domain[i]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003969 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07003970 return buf;
3971 pos += ret;
3972 }
3973
3974 return buf;
3975 }
3976
3977 if (os_strcmp(var, "phase1") == 0)
3978 return alloc_strdup(cred->phase1);
3979
3980 if (os_strcmp(var, "phase2") == 0)
3981 return alloc_strdup(cred->phase2);
3982
3983 if (os_strcmp(var, "roaming_consortium") == 0) {
3984 size_t buflen;
3985 char *buf;
3986
3987 if (!cred->roaming_consortium_len)
3988 return NULL;
3989 buflen = cred->roaming_consortium_len * 2 + 1;
3990 buf = os_malloc(buflen);
3991 if (buf == NULL)
3992 return NULL;
3993 wpa_snprintf_hex(buf, buflen, cred->roaming_consortium,
3994 cred->roaming_consortium_len);
3995 return buf;
3996 }
3997
3998 if (os_strcmp(var, "required_roaming_consortium") == 0) {
3999 size_t buflen;
4000 char *buf;
4001
4002 if (!cred->required_roaming_consortium_len)
4003 return NULL;
4004 buflen = cred->required_roaming_consortium_len * 2 + 1;
4005 buf = os_malloc(buflen);
4006 if (buf == NULL)
4007 return NULL;
4008 wpa_snprintf_hex(buf, buflen, cred->required_roaming_consortium,
4009 cred->required_roaming_consortium_len);
4010 return buf;
4011 }
4012
Roshan Pius3a1667e2018-07-03 15:17:14 -07004013 if (os_strcmp(var, "roaming_consortiums") == 0) {
4014 size_t buflen;
4015 char *buf, *pos;
4016 size_t i;
4017
4018 if (!cred->num_roaming_consortiums)
4019 return NULL;
4020 buflen = cred->num_roaming_consortiums *
4021 MAX_ROAMING_CONS_OI_LEN * 2 + 1;
4022 buf = os_malloc(buflen);
4023 if (!buf)
4024 return NULL;
4025 pos = buf;
4026 for (i = 0; i < cred->num_roaming_consortiums; i++) {
4027 if (i > 0)
4028 *pos++ = ',';
4029 pos += wpa_snprintf_hex(
4030 pos, buf + buflen - pos,
4031 cred->roaming_consortiums[i],
4032 cred->roaming_consortiums_len[i]);
4033 }
4034 *pos = '\0';
4035 return buf;
4036 }
4037
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07004038 if (os_strcmp(var, "excluded_ssid") == 0) {
4039 unsigned int i;
4040 char *buf, *end, *pos;
4041
4042 if (!cred->num_excluded_ssid)
4043 return NULL;
4044
4045 buf = os_malloc(4000);
4046 if (buf == NULL)
4047 return NULL;
4048 pos = buf;
4049 end = pos + 4000;
4050
4051 for (i = 0; i < cred->num_excluded_ssid; i++) {
4052 struct excluded_ssid *e;
4053 int ret;
4054
4055 e = &cred->excluded_ssid[i];
4056 ret = os_snprintf(pos, end - pos, "%s%s",
4057 i > 0 ? "\n" : "",
4058 wpa_ssid_txt(e->ssid, e->ssid_len));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004059 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07004060 return buf;
4061 pos += ret;
4062 }
4063
4064 return buf;
4065 }
4066
4067 if (os_strcmp(var, "roaming_partner") == 0) {
4068 unsigned int i;
4069 char *buf, *end, *pos;
4070
4071 if (!cred->num_roaming_partner)
4072 return NULL;
4073
4074 buf = os_malloc(4000);
4075 if (buf == NULL)
4076 return NULL;
4077 pos = buf;
4078 end = pos + 4000;
4079
4080 for (i = 0; i < cred->num_roaming_partner; i++) {
4081 struct roaming_partner *p;
4082 int ret;
4083
4084 p = &cred->roaming_partner[i];
4085 ret = os_snprintf(pos, end - pos, "%s%s,%d,%u,%s",
4086 i > 0 ? "\n" : "",
4087 p->fqdn, p->exact_match, p->priority,
4088 p->country);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004089 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07004090 return buf;
4091 pos += ret;
4092 }
4093
4094 return buf;
4095 }
4096
4097 if (os_strcmp(var, "provisioning_sp") == 0)
4098 return alloc_strdup(cred->provisioning_sp);
4099
4100 return NULL;
4101}
4102
4103
Dmitry Shmidt04949592012-07-19 12:16:46 -07004104struct wpa_cred * wpa_config_get_cred(struct wpa_config *config, int id)
4105{
4106 struct wpa_cred *cred;
4107
4108 cred = config->cred;
4109 while (cred) {
4110 if (id == cred->id)
4111 break;
4112 cred = cred->next;
4113 }
4114
4115 return cred;
4116}
4117
4118
4119struct wpa_cred * wpa_config_add_cred(struct wpa_config *config)
4120{
4121 int id;
4122 struct wpa_cred *cred, *last = NULL;
4123
4124 id = -1;
4125 cred = config->cred;
4126 while (cred) {
4127 if (cred->id > id)
4128 id = cred->id;
4129 last = cred;
4130 cred = cred->next;
4131 }
4132 id++;
4133
4134 cred = os_zalloc(sizeof(*cred));
4135 if (cred == NULL)
4136 return NULL;
4137 cred->id = id;
Dmitry Shmidtf9bdef92014-04-25 10:46:36 -07004138 cred->sim_num = DEFAULT_USER_SELECTED_SIM;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004139 if (last)
4140 last->next = cred;
4141 else
4142 config->cred = cred;
4143
4144 return cred;
4145}
4146
4147
4148int wpa_config_remove_cred(struct wpa_config *config, int id)
4149{
4150 struct wpa_cred *cred, *prev = NULL;
4151
4152 cred = config->cred;
4153 while (cred) {
4154 if (id == cred->id)
4155 break;
4156 prev = cred;
4157 cred = cred->next;
4158 }
4159
4160 if (cred == NULL)
4161 return -1;
4162
4163 if (prev)
4164 prev->next = cred->next;
4165 else
4166 config->cred = cred->next;
4167
4168 wpa_config_free_cred(cred);
4169 return 0;
4170}
4171
4172
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004173#ifndef CONFIG_NO_CONFIG_BLOBS
4174/**
4175 * wpa_config_get_blob - Get a named configuration blob
4176 * @config: Configuration data from wpa_config_read()
4177 * @name: Name of the blob
4178 * Returns: Pointer to blob data or %NULL if not found
4179 */
4180const struct wpa_config_blob * wpa_config_get_blob(struct wpa_config *config,
4181 const char *name)
4182{
4183 struct wpa_config_blob *blob = config->blobs;
4184
4185 while (blob) {
4186 if (os_strcmp(blob->name, name) == 0)
4187 return blob;
4188 blob = blob->next;
4189 }
4190 return NULL;
4191}
4192
4193
4194/**
4195 * wpa_config_set_blob - Set or add a named configuration blob
4196 * @config: Configuration data from wpa_config_read()
4197 * @blob: New value for the blob
4198 *
4199 * Adds a new configuration blob or replaces the current value of an existing
4200 * blob.
4201 */
4202void wpa_config_set_blob(struct wpa_config *config,
4203 struct wpa_config_blob *blob)
4204{
4205 wpa_config_remove_blob(config, blob->name);
4206 blob->next = config->blobs;
4207 config->blobs = blob;
4208}
4209
4210
4211/**
4212 * wpa_config_free_blob - Free blob data
4213 * @blob: Pointer to blob to be freed
4214 */
4215void wpa_config_free_blob(struct wpa_config_blob *blob)
4216{
4217 if (blob) {
4218 os_free(blob->name);
Dmitry Shmidtc2817022014-07-02 10:32:10 -07004219 bin_clear_free(blob->data, blob->len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004220 os_free(blob);
4221 }
4222}
4223
4224
4225/**
4226 * wpa_config_remove_blob - Remove a named configuration blob
4227 * @config: Configuration data from wpa_config_read()
4228 * @name: Name of the blob to remove
4229 * Returns: 0 if blob was removed or -1 if blob was not found
4230 */
4231int wpa_config_remove_blob(struct wpa_config *config, const char *name)
4232{
4233 struct wpa_config_blob *pos = config->blobs, *prev = NULL;
4234
4235 while (pos) {
4236 if (os_strcmp(pos->name, name) == 0) {
4237 if (prev)
4238 prev->next = pos->next;
4239 else
4240 config->blobs = pos->next;
4241 wpa_config_free_blob(pos);
4242 return 0;
4243 }
4244 prev = pos;
4245 pos = pos->next;
4246 }
4247
4248 return -1;
4249}
4250#endif /* CONFIG_NO_CONFIG_BLOBS */
4251
4252
4253/**
4254 * wpa_config_alloc_empty - Allocate an empty configuration
4255 * @ctrl_interface: Control interface parameters, e.g., path to UNIX domain
4256 * socket
4257 * @driver_param: Driver parameters
4258 * Returns: Pointer to allocated configuration data or %NULL on failure
4259 */
4260struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
4261 const char *driver_param)
4262{
Hai Shalom899fcc72020-10-19 14:38:18 -07004263#define ecw2cw(ecw) ((1 << (ecw)) - 1)
4264
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004265 struct wpa_config *config;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004266 const int aCWmin = 4, aCWmax = 10;
4267 const struct hostapd_wmm_ac_params ac_bk =
4268 { aCWmin, aCWmax, 7, 0, 0 }; /* background traffic */
4269 const struct hostapd_wmm_ac_params ac_be =
4270 { aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */
4271 const struct hostapd_wmm_ac_params ac_vi = /* video traffic */
Hai Shalom899fcc72020-10-19 14:38:18 -07004272 { aCWmin - 1, aCWmin, 2, 3008 / 32, 0 };
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004273 const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */
Hai Shalom899fcc72020-10-19 14:38:18 -07004274 { aCWmin - 2, aCWmin - 1, 2, 1504 / 32, 0 };
4275 const struct hostapd_tx_queue_params txq_bk =
4276 { 7, ecw2cw(aCWmin), ecw2cw(aCWmax), 0 };
4277 const struct hostapd_tx_queue_params txq_be =
4278 { 3, ecw2cw(aCWmin), 4 * (ecw2cw(aCWmin) + 1) - 1, 0 };
4279 const struct hostapd_tx_queue_params txq_vi =
4280 { 1, (ecw2cw(aCWmin) + 1) / 2 - 1, ecw2cw(aCWmin), 30 };
4281 const struct hostapd_tx_queue_params txq_vo =
4282 { 1, (ecw2cw(aCWmin) + 1) / 4 - 1,
4283 (ecw2cw(aCWmin) + 1) / 2 - 1, 15 };
4284
4285#undef ecw2cw
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004286
4287 config = os_zalloc(sizeof(*config));
4288 if (config == NULL)
4289 return NULL;
4290 config->eapol_version = DEFAULT_EAPOL_VERSION;
4291 config->ap_scan = DEFAULT_AP_SCAN;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004292 config->user_mpm = DEFAULT_USER_MPM;
4293 config->max_peer_links = DEFAULT_MAX_PEER_LINKS;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08004294 config->mesh_max_inactivity = DEFAULT_MESH_MAX_INACTIVITY;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004295 config->dot11RSNASAERetransPeriod =
4296 DEFAULT_DOT11_RSNA_SAE_RETRANS_PERIOD;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004297 config->fast_reauth = DEFAULT_FAST_REAUTH;
4298 config->p2p_go_intent = DEFAULT_P2P_GO_INTENT;
4299 config->p2p_intra_bss = DEFAULT_P2P_INTRA_BSS;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004300 config->p2p_go_freq_change_policy = DEFAULT_P2P_GO_FREQ_MOVE;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004301 config->p2p_go_max_inactivity = DEFAULT_P2P_GO_MAX_INACTIVITY;
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07004302 config->p2p_optimize_listen_chan = DEFAULT_P2P_OPTIMIZE_LISTEN_CHAN;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08004303 config->p2p_go_ctwindow = DEFAULT_P2P_GO_CTWINDOW;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004304 config->bss_max_count = DEFAULT_BSS_MAX_COUNT;
4305 config->bss_expiration_age = DEFAULT_BSS_EXPIRATION_AGE;
4306 config->bss_expiration_scan_count = DEFAULT_BSS_EXPIRATION_SCAN_COUNT;
4307 config->max_num_sta = DEFAULT_MAX_NUM_STA;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004308 config->ap_isolate = DEFAULT_AP_ISOLATE;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004309 config->access_network_type = DEFAULT_ACCESS_NETWORK_TYPE;
Dmitry Shmidtea69e842013-05-13 14:52:28 -07004310 config->scan_cur_freq = DEFAULT_SCAN_CUR_FREQ;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004311 config->wmm_ac_params[0] = ac_be;
4312 config->wmm_ac_params[1] = ac_bk;
4313 config->wmm_ac_params[2] = ac_vi;
4314 config->wmm_ac_params[3] = ac_vo;
Hai Shalom899fcc72020-10-19 14:38:18 -07004315 config->tx_queue[0] = txq_vo;
4316 config->tx_queue[1] = txq_vi;
4317 config->tx_queue[2] = txq_be;
4318 config->tx_queue[3] = txq_bk;
Dmitry Shmidt09f57ba2014-06-10 16:07:13 -07004319 config->p2p_search_delay = DEFAULT_P2P_SEARCH_DELAY;
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07004320 config->rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004321 config->key_mgmt_offload = DEFAULT_KEY_MGMT_OFFLOAD;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08004322 config->cert_in_cb = DEFAULT_CERT_IN_CB;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004323 config->wpa_rsc_relaxation = DEFAULT_WPA_RSC_RELAXATION;
Hai Shalomfdcde762020-04-02 11:19:20 -07004324 config->extended_key_id = DEFAULT_EXTENDED_KEY_ID;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004325
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004326#ifdef CONFIG_MBO
4327 config->mbo_cell_capa = DEFAULT_MBO_CELL_CAPA;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004328 config->disassoc_imminent_rssi_threshold =
4329 DEFAULT_DISASSOC_IMMINENT_RSSI_THRESHOLD;
4330 config->oce = DEFAULT_OCE_SUPPORT;
Dennis Jeone2cb56b2020-10-23 21:23:01 +09004331 config->btm_offload = DEFAULT_BTM_OFFLOAD;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004332#endif /* CONFIG_MBO */
4333
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004334 if (ctrl_interface)
4335 config->ctrl_interface = os_strdup(ctrl_interface);
4336 if (driver_param)
4337 config->driver_param = os_strdup(driver_param);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004338 config->gas_rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004339
4340 return config;
4341}
4342
4343
4344#ifndef CONFIG_NO_STDOUT_DEBUG
4345/**
4346 * wpa_config_debug_dump_networks - Debug dump of configured networks
4347 * @config: Configuration data from wpa_config_read()
4348 */
4349void wpa_config_debug_dump_networks(struct wpa_config *config)
4350{
Hai Shalomfdcde762020-04-02 11:19:20 -07004351 size_t prio;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004352 struct wpa_ssid *ssid;
4353
4354 for (prio = 0; prio < config->num_prio; prio++) {
4355 ssid = config->pssid[prio];
4356 wpa_printf(MSG_DEBUG, "Priority group %d",
4357 ssid->priority);
4358 while (ssid) {
4359 wpa_printf(MSG_DEBUG, " id=%d ssid='%s'",
4360 ssid->id,
4361 wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
4362 ssid = ssid->pnext;
4363 }
4364 }
4365}
4366#endif /* CONFIG_NO_STDOUT_DEBUG */
4367
4368
Hai Shalom899fcc72020-10-19 14:38:18 -07004369/**
4370 * Structure for global configuration parsing. This data is used to implement a
4371 * generic parser for the global interface configuration. The table of variables
4372 * is defined below in this file (global_fields[]).
4373 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004374struct global_parse_data {
Hai Shalom899fcc72020-10-19 14:38:18 -07004375 /* Configuration variable name */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004376 char *name;
Hai Shalom899fcc72020-10-19 14:38:18 -07004377
4378 /* Parser function for this variable. The parser functions return 0 or 1
4379 * to indicate success. Value 0 indicates that the parameter value may
4380 * have changed while value 1 means that the value did not change.
4381 * Error cases (failure to parse the string) are indicated by returning
4382 * -1. */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004383 int (*parser)(const struct global_parse_data *data,
4384 struct wpa_config *config, int line, const char *value);
Hai Shalom899fcc72020-10-19 14:38:18 -07004385
4386 /* Getter function to print the variable in text format to buf. */
Dmitry Shmidt7f656022015-02-25 14:36:37 -08004387 int (*get)(const char *name, struct wpa_config *config, long offset,
4388 char *buf, size_t buflen, int pretty_print);
Hai Shalom899fcc72020-10-19 14:38:18 -07004389
4390 /* Variable specific parameters for the parser. */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004391 void *param1, *param2, *param3;
Hai Shalom899fcc72020-10-19 14:38:18 -07004392
4393 /* Indicates which configuration variable has changed. */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004394 unsigned int changed_flag;
4395};
4396
4397
4398static int wpa_global_config_parse_int(const struct global_parse_data *data,
4399 struct wpa_config *config, int line,
4400 const char *pos)
4401{
Dmitry Shmidt2f023192013-03-12 12:44:17 -07004402 int val, *dst;
4403 char *end;
Hai Shalom899fcc72020-10-19 14:38:18 -07004404 bool same;
Dmitry Shmidt2f023192013-03-12 12:44:17 -07004405
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004406 dst = (int *) (((u8 *) config) + (long) data->param1);
Dmitry Shmidt2f023192013-03-12 12:44:17 -07004407 val = strtol(pos, &end, 0);
4408 if (*end) {
4409 wpa_printf(MSG_ERROR, "Line %d: invalid number \"%s\"",
4410 line, pos);
4411 return -1;
4412 }
Hai Shalom899fcc72020-10-19 14:38:18 -07004413 same = *dst == val;
Dmitry Shmidt2f023192013-03-12 12:44:17 -07004414 *dst = val;
4415
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004416 wpa_printf(MSG_DEBUG, "%s=%d", data->name, *dst);
4417
4418 if (data->param2 && *dst < (long) data->param2) {
4419 wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d "
4420 "min_value=%ld)", line, data->name, *dst,
4421 (long) data->param2);
4422 *dst = (long) data->param2;
4423 return -1;
4424 }
4425
4426 if (data->param3 && *dst > (long) data->param3) {
4427 wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d "
4428 "max_value=%ld)", line, data->name, *dst,
4429 (long) data->param3);
4430 *dst = (long) data->param3;
4431 return -1;
4432 }
4433
Hai Shalom899fcc72020-10-19 14:38:18 -07004434 return same;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004435}
4436
4437
4438static int wpa_global_config_parse_str(const struct global_parse_data *data,
4439 struct wpa_config *config, int line,
4440 const char *pos)
4441{
Hai Shalom899fcc72020-10-19 14:38:18 -07004442 size_t len, prev_len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004443 char **dst, *tmp;
4444
4445 len = os_strlen(pos);
4446 if (data->param2 && len < (size_t) data->param2) {
4447 wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu "
4448 "min_len=%ld)", line, data->name,
4449 (unsigned long) len, (long) data->param2);
4450 return -1;
4451 }
4452
4453 if (data->param3 && len > (size_t) data->param3) {
4454 wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu "
4455 "max_len=%ld)", line, data->name,
4456 (unsigned long) len, (long) data->param3);
4457 return -1;
4458 }
4459
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004460 if (has_newline(pos)) {
4461 wpa_printf(MSG_ERROR, "Line %d: invalid %s value with newline",
4462 line, data->name);
4463 return -1;
4464 }
4465
Hai Shalom899fcc72020-10-19 14:38:18 -07004466 dst = (char **) (((u8 *) config) + (long) data->param1);
4467 if (*dst)
4468 prev_len = os_strlen(*dst);
4469 else
4470 prev_len = 0;
4471
4472 /* No change to the previously configured value */
4473 if ((!(*dst) && !pos) ||
4474 (*dst && pos && prev_len == len &&
4475 os_memcmp(*dst, pos, len) == 0))
4476 return 1;
4477
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004478 tmp = os_strdup(pos);
4479 if (tmp == NULL)
4480 return -1;
4481
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004482 os_free(*dst);
4483 *dst = tmp;
4484 wpa_printf(MSG_DEBUG, "%s='%s'", data->name, *dst);
4485
4486 return 0;
4487}
4488
4489
Dmitry Shmidtb96dad42013-11-05 10:07:29 -08004490static int wpa_config_process_bgscan(const struct global_parse_data *data,
4491 struct wpa_config *config, int line,
4492 const char *pos)
4493{
4494 size_t len;
4495 char *tmp;
Dmitry Shmidt97672262014-02-03 13:02:54 -08004496 int res;
Dmitry Shmidtb96dad42013-11-05 10:07:29 -08004497
4498 tmp = wpa_config_parse_string(pos, &len);
4499 if (tmp == NULL) {
4500 wpa_printf(MSG_ERROR, "Line %d: failed to parse %s",
4501 line, data->name);
4502 return -1;
4503 }
4504
Dmitry Shmidt97672262014-02-03 13:02:54 -08004505 res = wpa_global_config_parse_str(data, config, line, tmp);
4506 os_free(tmp);
4507 return res;
Dmitry Shmidtb96dad42013-11-05 10:07:29 -08004508}
4509
4510
Dmitry Shmidt04949592012-07-19 12:16:46 -07004511static int wpa_global_config_parse_bin(const struct global_parse_data *data,
4512 struct wpa_config *config, int line,
4513 const char *pos)
4514{
Dmitry Shmidt04949592012-07-19 12:16:46 -07004515 struct wpabuf **dst, *tmp;
4516
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004517 tmp = wpabuf_parse_bin(pos);
4518 if (!tmp)
Dmitry Shmidt04949592012-07-19 12:16:46 -07004519 return -1;
4520
Dmitry Shmidt04949592012-07-19 12:16:46 -07004521 dst = (struct wpabuf **) (((u8 *) config) + (long) data->param1);
Hai Shalom899fcc72020-10-19 14:38:18 -07004522 if (wpabuf_cmp(*dst, tmp) == 0) {
4523 wpabuf_free(tmp);
4524 return 1;
4525 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07004526 wpabuf_free(*dst);
4527 *dst = tmp;
4528 wpa_printf(MSG_DEBUG, "%s", data->name);
4529
4530 return 0;
4531}
4532
4533
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07004534static int wpa_config_process_freq_list(const struct global_parse_data *data,
4535 struct wpa_config *config, int line,
4536 const char *value)
4537{
4538 int *freqs;
4539
4540 freqs = wpa_config_parse_int_array(value);
4541 if (freqs == NULL)
4542 return -1;
Dmitry Shmidt56052862013-10-04 10:23:25 -07004543 if (freqs[0] == 0) {
4544 os_free(freqs);
4545 freqs = NULL;
4546 }
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07004547 os_free(config->freq_list);
4548 config->freq_list = freqs;
4549 return 0;
4550}
4551
4552
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08004553#ifdef CONFIG_P2P
4554static int wpa_global_config_parse_ipv4(const struct global_parse_data *data,
4555 struct wpa_config *config, int line,
4556 const char *pos)
4557{
4558 u32 *dst;
4559 struct hostapd_ip_addr addr;
4560
4561 if (hostapd_parse_ip_addr(pos, &addr) < 0)
4562 return -1;
4563 if (addr.af != AF_INET)
4564 return -1;
4565
4566 dst = (u32 *) (((u8 *) config) + (long) data->param1);
Hai Shalom899fcc72020-10-19 14:38:18 -07004567 if (os_memcmp(dst, &addr.u.v4.s_addr, 4) == 0)
4568 return 1;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08004569 os_memcpy(dst, &addr.u.v4.s_addr, 4);
4570 wpa_printf(MSG_DEBUG, "%s = 0x%x", data->name,
4571 WPA_GET_BE32((u8 *) dst));
4572
4573 return 0;
4574}
4575#endif /* CONFIG_P2P */
4576
4577
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004578static int wpa_config_process_country(const struct global_parse_data *data,
4579 struct wpa_config *config, int line,
4580 const char *pos)
4581{
4582 if (!pos[0] || !pos[1]) {
4583 wpa_printf(MSG_DEBUG, "Invalid country set");
4584 return -1;
4585 }
Hai Shalom899fcc72020-10-19 14:38:18 -07004586 if (pos[0] == config->country[0] && pos[1] == config->country[1])
4587 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004588 config->country[0] = pos[0];
4589 config->country[1] = pos[1];
4590 wpa_printf(MSG_DEBUG, "country='%c%c'",
4591 config->country[0], config->country[1]);
4592 return 0;
4593}
4594
4595
4596static int wpa_config_process_load_dynamic_eap(
4597 const struct global_parse_data *data, struct wpa_config *config,
4598 int line, const char *so)
4599{
4600 int ret;
4601 wpa_printf(MSG_DEBUG, "load_dynamic_eap=%s", so);
4602 ret = eap_peer_method_load(so);
4603 if (ret == -2) {
4604 wpa_printf(MSG_DEBUG, "This EAP type was already loaded - not "
4605 "reloading.");
4606 } else if (ret) {
4607 wpa_printf(MSG_ERROR, "Line %d: Failed to load dynamic EAP "
4608 "method '%s'.", line, so);
4609 return -1;
4610 }
4611
4612 return 0;
4613}
4614
4615
4616#ifdef CONFIG_WPS
4617
4618static int wpa_config_process_uuid(const struct global_parse_data *data,
4619 struct wpa_config *config, int line,
4620 const char *pos)
4621{
4622 char buf[40];
4623 if (uuid_str2bin(pos, config->uuid)) {
4624 wpa_printf(MSG_ERROR, "Line %d: invalid UUID", line);
4625 return -1;
4626 }
4627 uuid_bin2str(config->uuid, buf, sizeof(buf));
4628 wpa_printf(MSG_DEBUG, "uuid=%s", buf);
4629 return 0;
4630}
4631
4632
4633static int wpa_config_process_device_type(
4634 const struct global_parse_data *data,
4635 struct wpa_config *config, int line, const char *pos)
4636{
4637 return wps_dev_type_str2bin(pos, config->device_type);
4638}
4639
4640
4641static int wpa_config_process_os_version(const struct global_parse_data *data,
4642 struct wpa_config *config, int line,
4643 const char *pos)
4644{
4645 if (hexstr2bin(pos, config->os_version, 4)) {
4646 wpa_printf(MSG_ERROR, "Line %d: invalid os_version", line);
4647 return -1;
4648 }
4649 wpa_printf(MSG_DEBUG, "os_version=%08x",
4650 WPA_GET_BE32(config->os_version));
4651 return 0;
4652}
4653
Dmitry Shmidt04949592012-07-19 12:16:46 -07004654
4655static int wpa_config_process_wps_vendor_ext_m1(
4656 const struct global_parse_data *data,
4657 struct wpa_config *config, int line, const char *pos)
4658{
4659 struct wpabuf *tmp;
4660 int len = os_strlen(pos) / 2;
4661 u8 *p;
4662
4663 if (!len) {
4664 wpa_printf(MSG_ERROR, "Line %d: "
4665 "invalid wps_vendor_ext_m1", line);
4666 return -1;
4667 }
4668
4669 tmp = wpabuf_alloc(len);
4670 if (tmp) {
4671 p = wpabuf_put(tmp, len);
4672
4673 if (hexstr2bin(pos, p, len)) {
4674 wpa_printf(MSG_ERROR, "Line %d: "
4675 "invalid wps_vendor_ext_m1", line);
4676 wpabuf_free(tmp);
4677 return -1;
4678 }
4679
4680 wpabuf_free(config->wps_vendor_ext_m1);
4681 config->wps_vendor_ext_m1 = tmp;
4682 } else {
4683 wpa_printf(MSG_ERROR, "Can not allocate "
4684 "memory for wps_vendor_ext_m1");
4685 return -1;
4686 }
4687
4688 return 0;
4689}
4690
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004691#endif /* CONFIG_WPS */
4692
4693#ifdef CONFIG_P2P
4694static int wpa_config_process_sec_device_type(
4695 const struct global_parse_data *data,
4696 struct wpa_config *config, int line, const char *pos)
4697{
4698 int idx;
4699
4700 if (config->num_sec_device_types >= MAX_SEC_DEVICE_TYPES) {
4701 wpa_printf(MSG_ERROR, "Line %d: too many sec_device_type "
4702 "items", line);
4703 return -1;
4704 }
4705
4706 idx = config->num_sec_device_types;
4707
4708 if (wps_dev_type_str2bin(pos, config->sec_device_type[idx]))
4709 return -1;
4710
4711 config->num_sec_device_types++;
4712 return 0;
4713}
Dmitry Shmidt04949592012-07-19 12:16:46 -07004714
4715
4716static int wpa_config_process_p2p_pref_chan(
4717 const struct global_parse_data *data,
4718 struct wpa_config *config, int line, const char *pos)
4719{
4720 struct p2p_channel *pref = NULL, *n;
Hai Shalomfdcde762020-04-02 11:19:20 -07004721 size_t num = 0;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004722 const char *pos2;
4723 u8 op_class, chan;
4724
4725 /* format: class:chan,class:chan,... */
4726
4727 while (*pos) {
4728 op_class = atoi(pos);
4729 pos2 = os_strchr(pos, ':');
4730 if (pos2 == NULL)
4731 goto fail;
4732 pos2++;
4733 chan = atoi(pos2);
4734
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004735 n = os_realloc_array(pref, num + 1,
4736 sizeof(struct p2p_channel));
Dmitry Shmidt04949592012-07-19 12:16:46 -07004737 if (n == NULL)
4738 goto fail;
4739 pref = n;
4740 pref[num].op_class = op_class;
4741 pref[num].chan = chan;
4742 num++;
4743
4744 pos = os_strchr(pos2, ',');
4745 if (pos == NULL)
4746 break;
4747 pos++;
4748 }
4749
4750 os_free(config->p2p_pref_chan);
4751 config->p2p_pref_chan = pref;
4752 config->num_p2p_pref_chan = num;
4753 wpa_hexdump(MSG_DEBUG, "P2P: Preferred class/channel pairs",
4754 (u8 *) config->p2p_pref_chan,
4755 config->num_p2p_pref_chan * sizeof(struct p2p_channel));
4756
4757 return 0;
4758
4759fail:
4760 os_free(pref);
4761 wpa_printf(MSG_ERROR, "Line %d: Invalid p2p_pref_chan list", line);
4762 return -1;
4763}
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07004764
4765
4766static int wpa_config_process_p2p_no_go_freq(
4767 const struct global_parse_data *data,
4768 struct wpa_config *config, int line, const char *pos)
4769{
4770 int ret;
4771
4772 ret = freq_range_list_parse(&config->p2p_no_go_freq, pos);
4773 if (ret < 0) {
4774 wpa_printf(MSG_ERROR, "Line %d: Invalid p2p_no_go_freq", line);
4775 return -1;
4776 }
4777
4778 wpa_printf(MSG_DEBUG, "P2P: p2p_no_go_freq with %u items",
4779 config->p2p_no_go_freq.num);
4780
4781 return 0;
4782}
4783
Hai Shalom39ba6fc2019-01-22 12:40:38 -08004784static int wpa_config_process_p2p_device_persistent_mac_addr(
4785 const struct global_parse_data *data,
4786 struct wpa_config *config, int line, const char *pos)
4787{
4788 if (hwaddr_aton2(pos, config->p2p_device_persistent_mac_addr) < 0) {
4789 wpa_printf(MSG_ERROR,
4790 "Line %d: Invalid p2p_device_persistent_mac_addr '%s'",
4791 line, pos);
4792 return -1;
4793 }
4794
4795 return 0;
4796}
4797
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004798#endif /* CONFIG_P2P */
4799
4800
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004801static int wpa_config_process_hessid(
4802 const struct global_parse_data *data,
4803 struct wpa_config *config, int line, const char *pos)
4804{
4805 if (hwaddr_aton2(pos, config->hessid) < 0) {
4806 wpa_printf(MSG_ERROR, "Line %d: Invalid hessid '%s'",
4807 line, pos);
4808 return -1;
4809 }
4810
4811 return 0;
4812}
4813
4814
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08004815static int wpa_config_process_sae_groups(
4816 const struct global_parse_data *data,
4817 struct wpa_config *config, int line, const char *pos)
4818{
4819 int *groups = wpa_config_parse_int_array(pos);
4820 if (groups == NULL) {
4821 wpa_printf(MSG_ERROR, "Line %d: Invalid sae_groups '%s'",
4822 line, pos);
4823 return -1;
4824 }
4825
4826 os_free(config->sae_groups);
4827 config->sae_groups = groups;
4828
4829 return 0;
4830}
4831
4832
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004833static int wpa_config_process_ap_vendor_elements(
4834 const struct global_parse_data *data,
4835 struct wpa_config *config, int line, const char *pos)
4836{
4837 struct wpabuf *tmp;
4838 int len = os_strlen(pos) / 2;
4839 u8 *p;
4840
4841 if (!len) {
4842 wpa_printf(MSG_ERROR, "Line %d: invalid ap_vendor_elements",
4843 line);
4844 return -1;
4845 }
4846
4847 tmp = wpabuf_alloc(len);
4848 if (tmp) {
4849 p = wpabuf_put(tmp, len);
4850
4851 if (hexstr2bin(pos, p, len)) {
4852 wpa_printf(MSG_ERROR, "Line %d: invalid "
4853 "ap_vendor_elements", line);
4854 wpabuf_free(tmp);
4855 return -1;
4856 }
4857
4858 wpabuf_free(config->ap_vendor_elements);
4859 config->ap_vendor_elements = tmp;
4860 } else {
4861 wpa_printf(MSG_ERROR, "Cannot allocate memory for "
4862 "ap_vendor_elements");
4863 return -1;
4864 }
4865
4866 return 0;
4867}
4868
4869
Dmitry Shmidt56052862013-10-04 10:23:25 -07004870#ifdef CONFIG_CTRL_IFACE
4871static int wpa_config_process_no_ctrl_interface(
4872 const struct global_parse_data *data,
4873 struct wpa_config *config, int line, const char *pos)
4874{
4875 wpa_printf(MSG_DEBUG, "no_ctrl_interface -> ctrl_interface=NULL");
4876 os_free(config->ctrl_interface);
4877 config->ctrl_interface = NULL;
4878 return 0;
4879}
4880#endif /* CONFIG_CTRL_IFACE */
4881
4882
Dmitry Shmidt7f656022015-02-25 14:36:37 -08004883static int wpa_config_get_int(const char *name, struct wpa_config *config,
4884 long offset, char *buf, size_t buflen,
4885 int pretty_print)
4886{
4887 int *val = (int *) (((u8 *) config) + (long) offset);
4888
4889 if (pretty_print)
4890 return os_snprintf(buf, buflen, "%s=%d\n", name, *val);
4891 return os_snprintf(buf, buflen, "%d", *val);
4892}
4893
4894
4895static int wpa_config_get_str(const char *name, struct wpa_config *config,
4896 long offset, char *buf, size_t buflen,
4897 int pretty_print)
4898{
4899 char **val = (char **) (((u8 *) config) + (long) offset);
4900 int res;
4901
4902 if (pretty_print)
4903 res = os_snprintf(buf, buflen, "%s=%s\n", name,
4904 *val ? *val : "null");
4905 else if (!*val)
4906 return -1;
4907 else
4908 res = os_snprintf(buf, buflen, "%s", *val);
4909 if (os_snprintf_error(buflen, res))
4910 res = -1;
4911
4912 return res;
4913}
4914
4915
Dmitry Shmidtf73259c2015-03-17 11:00:54 -07004916#ifdef CONFIG_P2P
4917static int wpa_config_get_ipv4(const char *name, struct wpa_config *config,
4918 long offset, char *buf, size_t buflen,
4919 int pretty_print)
4920{
4921 void *val = ((u8 *) config) + (long) offset;
4922 int res;
4923 char addr[INET_ADDRSTRLEN];
4924
4925 if (!val || !inet_ntop(AF_INET, val, addr, sizeof(addr)))
4926 return -1;
4927
4928 if (pretty_print)
4929 res = os_snprintf(buf, buflen, "%s=%s\n", name, addr);
4930 else
4931 res = os_snprintf(buf, buflen, "%s", addr);
4932
4933 if (os_snprintf_error(buflen, res))
4934 res = -1;
4935
4936 return res;
4937}
4938#endif /* CONFIG_P2P */
4939
4940
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004941#ifdef OFFSET
4942#undef OFFSET
4943#endif /* OFFSET */
4944/* OFFSET: Get offset of a variable within the wpa_config structure */
4945#define OFFSET(v) ((void *) &((struct wpa_config *) 0)->v)
4946
Dmitry Shmidt7f656022015-02-25 14:36:37 -08004947#define FUNC(f) #f, wpa_config_process_ ## f, NULL, OFFSET(f), NULL, NULL
4948#define FUNC_NO_VAR(f) #f, wpa_config_process_ ## f, NULL, NULL, NULL, NULL
4949#define _INT(f) #f, wpa_global_config_parse_int, wpa_config_get_int, OFFSET(f)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004950#define INT(f) _INT(f), NULL, NULL
4951#define INT_RANGE(f, min, max) _INT(f), (void *) min, (void *) max
Dmitry Shmidt7f656022015-02-25 14:36:37 -08004952#define _STR(f) #f, wpa_global_config_parse_str, wpa_config_get_str, OFFSET(f)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004953#define STR(f) _STR(f), NULL, NULL
4954#define STR_RANGE(f, min, max) _STR(f), (void *) min, (void *) max
Dmitry Shmidt7f656022015-02-25 14:36:37 -08004955#define BIN(f) #f, wpa_global_config_parse_bin, NULL, OFFSET(f), NULL, NULL
Dmitry Shmidtf73259c2015-03-17 11:00:54 -07004956#define IPV4(f) #f, wpa_global_config_parse_ipv4, wpa_config_get_ipv4, \
4957 OFFSET(f), NULL, NULL
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004958
4959static const struct global_parse_data global_fields[] = {
4960#ifdef CONFIG_CTRL_IFACE
4961 { STR(ctrl_interface), 0 },
Dmitry Shmidt56052862013-10-04 10:23:25 -07004962 { FUNC_NO_VAR(no_ctrl_interface), 0 },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004963 { STR(ctrl_interface_group), 0 } /* deprecated */,
4964#endif /* CONFIG_CTRL_IFACE */
Dmitry Shmidt5a1480c2014-05-12 09:46:02 -07004965#ifdef CONFIG_MACSEC
4966 { INT_RANGE(eapol_version, 1, 3), 0 },
4967#else /* CONFIG_MACSEC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004968 { INT_RANGE(eapol_version, 1, 2), 0 },
Dmitry Shmidt5a1480c2014-05-12 09:46:02 -07004969#endif /* CONFIG_MACSEC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004970 { INT(ap_scan), 0 },
Hai Shalom899fcc72020-10-19 14:38:18 -07004971 { FUNC(bgscan), CFG_CHANGED_BGSCAN },
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004972#ifdef CONFIG_MESH
4973 { INT(user_mpm), 0 },
4974 { INT_RANGE(max_peer_links, 0, 255), 0 },
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08004975 { INT(mesh_max_inactivity), 0 },
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004976 { INT(dot11RSNASAERetransPeriod), 0 },
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004977#endif /* CONFIG_MESH */
Dmitry Shmidt04949592012-07-19 12:16:46 -07004978 { INT(disable_scan_offload), 0 },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004979 { INT(fast_reauth), 0 },
4980 { STR(opensc_engine_path), 0 },
4981 { STR(pkcs11_engine_path), 0 },
4982 { STR(pkcs11_module_path), 0 },
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004983 { STR(openssl_ciphers), 0 },
Dmitry Shmidt04949592012-07-19 12:16:46 -07004984 { STR(pcsc_reader), 0 },
4985 { STR(pcsc_pin), 0 },
Dmitry Shmidt051af732013-10-22 13:52:46 -07004986 { INT(external_sim), 0 },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004987 { STR(driver_param), 0 },
4988 { INT(dot11RSNAConfigPMKLifetime), 0 },
4989 { INT(dot11RSNAConfigPMKReauthThreshold), 0 },
4990 { INT(dot11RSNAConfigSATimeout), 0 },
4991#ifndef CONFIG_NO_CONFIG_WRITE
4992 { INT(update_config), 0 },
4993#endif /* CONFIG_NO_CONFIG_WRITE */
4994 { FUNC_NO_VAR(load_dynamic_eap), 0 },
4995#ifdef CONFIG_WPS
4996 { FUNC(uuid), CFG_CHANGED_UUID },
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004997 { INT_RANGE(auto_uuid, 0, 1), 0 },
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07004998 { STR_RANGE(device_name, 0, WPS_DEV_NAME_MAX_LEN),
4999 CFG_CHANGED_DEVICE_NAME },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005000 { STR_RANGE(manufacturer, 0, 64), CFG_CHANGED_WPS_STRING },
5001 { STR_RANGE(model_name, 0, 32), CFG_CHANGED_WPS_STRING },
5002 { STR_RANGE(model_number, 0, 32), CFG_CHANGED_WPS_STRING },
5003 { STR_RANGE(serial_number, 0, 32), CFG_CHANGED_WPS_STRING },
5004 { FUNC(device_type), CFG_CHANGED_DEVICE_TYPE },
5005 { FUNC(os_version), CFG_CHANGED_OS_VERSION },
5006 { STR(config_methods), CFG_CHANGED_CONFIG_METHODS },
5007 { INT_RANGE(wps_cred_processing, 0, 2), 0 },
Hai Shalom021b0b52019-04-10 11:17:58 -07005008 { INT_RANGE(wps_cred_add_sae, 0, 1), 0 },
Dmitry Shmidt04949592012-07-19 12:16:46 -07005009 { FUNC(wps_vendor_ext_m1), CFG_CHANGED_VENDOR_EXTENSION },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005010#endif /* CONFIG_WPS */
5011#ifdef CONFIG_P2P
5012 { FUNC(sec_device_type), CFG_CHANGED_SEC_DEVICE_TYPE },
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005013 { INT(p2p_listen_reg_class), CFG_CHANGED_P2P_LISTEN_CHANNEL },
5014 { INT(p2p_listen_channel), CFG_CHANGED_P2P_LISTEN_CHANNEL },
Dmitry Shmidt56052862013-10-04 10:23:25 -07005015 { INT(p2p_oper_reg_class), CFG_CHANGED_P2P_OPER_CHANNEL },
5016 { INT(p2p_oper_channel), CFG_CHANGED_P2P_OPER_CHANNEL },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005017 { INT_RANGE(p2p_go_intent, 0, 15), 0 },
5018 { STR(p2p_ssid_postfix), CFG_CHANGED_P2P_SSID_POSTFIX },
5019 { INT_RANGE(persistent_reconnect, 0, 1), 0 },
5020 { INT_RANGE(p2p_intra_bss, 0, 1), CFG_CHANGED_P2P_INTRA_BSS },
5021 { INT(p2p_group_idle), 0 },
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005022 { INT_RANGE(p2p_go_freq_change_policy, 0, P2P_GO_FREQ_MOVE_MAX), 0 },
Dmitry Shmidt2271d3f2014-06-23 12:16:31 -07005023 { INT_RANGE(p2p_passphrase_len, 8, 63),
5024 CFG_CHANGED_P2P_PASSPHRASE_LEN },
Dmitry Shmidt04949592012-07-19 12:16:46 -07005025 { FUNC(p2p_pref_chan), CFG_CHANGED_P2P_PREF_CHAN },
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07005026 { FUNC(p2p_no_go_freq), CFG_CHANGED_P2P_PREF_CHAN },
5027 { INT_RANGE(p2p_add_cli_chan, 0, 1), 0 },
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07005028 { INT_RANGE(p2p_optimize_listen_chan, 0, 1), 0 },
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005029 { INT(p2p_go_ht40), 0 },
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07005030 { INT(p2p_go_vht), 0 },
Hai Shalom74f70d42019-02-11 14:42:39 -08005031 { INT(p2p_go_he), 0 },
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005032 { INT(p2p_go_edmg), 0 },
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005033 { INT(p2p_disabled), 0 },
Dmitry Shmidt7f656022015-02-25 14:36:37 -08005034 { INT_RANGE(p2p_go_ctwindow, 0, 127), 0 },
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005035 { INT(p2p_no_group_iface), 0 },
Dmitry Shmidt700a1372013-03-15 14:14:44 -07005036 { INT_RANGE(p2p_ignore_shared_freq, 0, 1), 0 },
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08005037 { IPV4(ip_addr_go), 0 },
5038 { IPV4(ip_addr_mask), 0 },
5039 { IPV4(ip_addr_start), 0 },
5040 { IPV4(ip_addr_end), 0 },
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07005041 { INT_RANGE(p2p_cli_probe, 0, 1), 0 },
Hai Shalom39ba6fc2019-01-22 12:40:38 -08005042 { INT(p2p_device_random_mac_addr), 0 },
5043 { FUNC(p2p_device_persistent_mac_addr), 0 },
5044 { INT(p2p_interface_random_mac_addr), 0 },
Hai Shalom899fcc72020-10-19 14:38:18 -07005045 { INT(p2p_6ghz_disable), 0 },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005046#endif /* CONFIG_P2P */
5047 { FUNC(country), CFG_CHANGED_COUNTRY },
5048 { INT(bss_max_count), 0 },
5049 { INT(bss_expiration_age), 0 },
5050 { INT(bss_expiration_scan_count), 0 },
5051 { INT_RANGE(filter_ssids, 0, 1), 0 },
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005052 { INT_RANGE(filter_rssi, -100, 0), 0 },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005053 { INT(max_num_sta), 0 },
Roshan Pius3a1667e2018-07-03 15:17:14 -07005054 { INT_RANGE(ap_isolate, 0, 1), 0 },
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005055 { INT_RANGE(disassoc_low_ack, 0, 1), 0 },
Dmitry Shmidt04949592012-07-19 12:16:46 -07005056#ifdef CONFIG_HS20
5057 { INT_RANGE(hs20, 0, 1), 0 },
5058#endif /* CONFIG_HS20 */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005059 { INT_RANGE(interworking, 0, 1), 0 },
5060 { FUNC(hessid), 0 },
Dmitry Shmidt04949592012-07-19 12:16:46 -07005061 { INT_RANGE(access_network_type, 0, 15), 0 },
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005062 { INT_RANGE(go_interworking, 0, 1), 0 },
5063 { INT_RANGE(go_access_network_type, 0, 15), 0 },
5064 { INT_RANGE(go_internet, 0, 1), 0 },
5065 { INT_RANGE(go_venue_group, 0, 255), 0 },
5066 { INT_RANGE(go_venue_type, 0, 255), 0 },
Dmitry Shmidt04949592012-07-19 12:16:46 -07005067 { INT_RANGE(pbc_in_m1, 0, 1), 0 },
5068 { STR(autoscan), 0 },
Dmitry Shmidtf8623282013-02-20 14:34:59 -08005069 { INT_RANGE(wps_nfc_dev_pw_id, 0x10, 0xffff),
5070 CFG_CHANGED_NFC_PASSWORD_TOKEN },
5071 { BIN(wps_nfc_dh_pubkey), CFG_CHANGED_NFC_PASSWORD_TOKEN },
5072 { BIN(wps_nfc_dh_privkey), CFG_CHANGED_NFC_PASSWORD_TOKEN },
5073 { BIN(wps_nfc_dev_pw), CFG_CHANGED_NFC_PASSWORD_TOKEN },
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005074 { STR(ext_password_backend), CFG_CHANGED_EXT_PW_BACKEND },
5075 { INT(p2p_go_max_inactivity), 0 },
5076 { INT_RANGE(auto_interworking, 0, 1), 0 },
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005077 { INT(okc), 0 },
5078 { INT(pmf), 0 },
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005079 { FUNC(sae_groups), 0 },
Hai Shalomfdcde762020-04-02 11:19:20 -07005080 { INT_RANGE(sae_pwe, 0, 3), 0 },
Hai Shalomc3565922019-10-28 11:58:20 -07005081 { INT_RANGE(sae_pmkid_in_assoc, 0, 1), 0 },
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08005082 { INT(dtim_period), 0 },
5083 { INT(beacon_int), 0 },
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07005084 { FUNC(ap_vendor_elements), 0 },
Dmitry Shmidt444d5672013-04-01 13:08:44 -07005085 { INT_RANGE(ignore_old_scan_res, 0, 1), 0 },
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07005086 { FUNC(freq_list), 0 },
Dmitry Shmidtea69e842013-05-13 14:52:28 -07005087 { INT(scan_cur_freq), 0 },
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07005088 { INT(sched_scan_interval), 0 },
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005089 { INT(sched_scan_start_delay), 0 },
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08005090 { INT(tdls_external_control), 0},
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08005091 { STR(osu_dir), 0 },
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005092 { STR(wowlan_triggers), CFG_CHANGED_WOWLAN_TRIGGERS },
Dmitry Shmidt09f57ba2014-06-10 16:07:13 -07005093 { INT(p2p_search_delay), 0},
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07005094 { INT(mac_addr), 0 },
5095 { INT(rand_addr_lifetime), 0 },
5096 { INT(preassoc_mac_addr), 0 },
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005097 { INT(key_mgmt_offload), 0},
Dmitry Shmidt807291d2015-01-27 13:40:23 -08005098 { INT(passive_scan), 0 },
Dmitry Shmidt7f656022015-02-25 14:36:37 -08005099 { INT(reassoc_same_bss_optim), 0 },
Dmitry Shmidt7a53dbb2015-06-11 13:13:53 -07005100 { INT(wps_priority), 0},
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005101#ifdef CONFIG_FST
5102 { STR_RANGE(fst_group_id, 1, FST_MAX_GROUP_ID_LEN), 0 },
5103 { INT_RANGE(fst_priority, 1, FST_MAX_PRIO_VALUE), 0 },
5104 { INT_RANGE(fst_llt, 1, FST_MAX_LLT_MS), 0 },
5105#endif /* CONFIG_FST */
Paul Stewart092955c2017-02-06 09:13:09 -08005106 { INT_RANGE(cert_in_cb, 0, 1), 0 },
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005107 { INT_RANGE(wpa_rsc_relaxation, 0, 1), 0 },
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08005108 { STR(sched_scan_plans), CFG_CHANGED_SCHED_SCAN_PLANS },
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005109#ifdef CONFIG_MBO
5110 { STR(non_pref_chan), 0 },
5111 { INT_RANGE(mbo_cell_capa, MBO_CELL_CAPA_AVAILABLE,
5112 MBO_CELL_CAPA_NOT_SUPPORTED), 0 },
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005113 { INT_RANGE(disassoc_imminent_rssi_threshold, -120, 0), 0 },
5114 { INT_RANGE(oce, 0, 3), 0 },
Dennis Jeone2cb56b2020-10-23 21:23:01 +09005115 { INT_RANGE(btm_offload, 0, 1), CFG_CHANGED_DISABLE_BTM_NOTIFY },
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005116#endif /* CONFIG_MBO */
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07005117 { INT(gas_address3), 0 },
Dmitry Shmidt7d175302016-09-06 13:11:34 -07005118 { INT_RANGE(ftm_responder, 0, 1), 0 },
5119 { INT_RANGE(ftm_initiator, 0, 1), 0 },
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005120 { INT(gas_rand_addr_lifetime), 0 },
5121 { INT_RANGE(gas_rand_mac_addr, 0, 2), 0 },
Hai Shalomc3565922019-10-28 11:58:20 -07005122#ifdef CONFIG_DPP
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005123 { INT_RANGE(dpp_config_processing, 0, 2), 0 },
Hai Shalomc3565922019-10-28 11:58:20 -07005124 { STR(dpp_name), 0 },
5125 { STR(dpp_mud_url), 0 },
5126#endif /* CONFIG_DPP */
Hai Shalom39ba6fc2019-01-22 12:40:38 -08005127 { INT_RANGE(coloc_intf_reporting, 0, 1), 0 },
Jimmy Chen0bb4f862019-03-21 18:41:47 +08005128 { INT_RANGE(bss_no_flush_when_down, 0, 1), 0 },
Hai Shalom81f62d82019-07-22 12:10:00 -07005129#ifdef CONFIG_WNM
5130 { INT_RANGE(disable_btm, 0, 1), CFG_CHANGED_DISABLE_BTM },
Hai Shalomfdcde762020-04-02 11:19:20 -07005131 { INT_RANGE(extended_key_id, 0, 1), 0 },
Hai Shalom81f62d82019-07-22 12:10:00 -07005132#endif /* CONFIG_WNM */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005133};
5134
5135#undef FUNC
5136#undef _INT
5137#undef INT
5138#undef INT_RANGE
5139#undef _STR
5140#undef STR
5141#undef STR_RANGE
Dmitry Shmidt04949592012-07-19 12:16:46 -07005142#undef BIN
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08005143#undef IPV4
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07005144#define NUM_GLOBAL_FIELDS ARRAY_SIZE(global_fields)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005145
5146
Dmitry Shmidt7f656022015-02-25 14:36:37 -08005147int wpa_config_dump_values(struct wpa_config *config, char *buf, size_t buflen)
5148{
5149 int result = 0;
5150 size_t i;
5151
5152 for (i = 0; i < NUM_GLOBAL_FIELDS; i++) {
5153 const struct global_parse_data *field = &global_fields[i];
5154 int tmp;
5155
5156 if (!field->get)
5157 continue;
5158
5159 tmp = field->get(field->name, config, (long) field->param1,
5160 buf, buflen, 1);
5161 if (tmp < 0)
5162 return -1;
5163 buf += tmp;
5164 buflen -= tmp;
5165 result += tmp;
5166 }
5167 return result;
5168}
5169
5170
5171int wpa_config_get_value(const char *name, struct wpa_config *config,
5172 char *buf, size_t buflen)
5173{
5174 size_t i;
5175
5176 for (i = 0; i < NUM_GLOBAL_FIELDS; i++) {
5177 const struct global_parse_data *field = &global_fields[i];
5178
5179 if (os_strcmp(name, field->name) != 0)
5180 continue;
5181 if (!field->get)
5182 break;
5183 return field->get(name, config, (long) field->param1,
5184 buf, buflen, 0);
5185 }
5186
5187 return -1;
5188}
5189
5190
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005191int wpa_config_get_num_global_field_names(void)
5192{
5193 return NUM_GLOBAL_FIELDS;
5194}
5195
5196
5197const char * wpa_config_get_global_field_name(unsigned int i, int *no_var)
5198{
5199 if (i >= NUM_GLOBAL_FIELDS)
5200 return NULL;
5201
5202 if (no_var)
5203 *no_var = !global_fields[i].param1;
5204 return global_fields[i].name;
5205}
5206
5207
Hai Shalom899fcc72020-10-19 14:38:18 -07005208/**
5209 * wpa_config_process_global - Set a variable in global configuration
5210 * @config: Pointer to global configuration data
5211 * @pos: Name and value in the format "{name}={value}"
5212 * @line: Line number in configuration file or 0 if not used
5213 * Returns: 0 on success with a possible change in value, 1 on success with no
5214 * change to previously configured value, or -1 on failure
5215 *
5216 * This function can be used to set global configuration variables based on
5217 * both the configuration file and management interface input. The value
5218 * parameter must be in the same format as the text-based configuration file is
5219 * using. For example, strings are using double quotation marks.
5220 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005221int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
5222{
5223 size_t i;
5224 int ret = 0;
5225
5226 for (i = 0; i < NUM_GLOBAL_FIELDS; i++) {
5227 const struct global_parse_data *field = &global_fields[i];
5228 size_t flen = os_strlen(field->name);
5229 if (os_strncmp(pos, field->name, flen) != 0 ||
5230 pos[flen] != '=')
5231 continue;
5232
Hai Shalom899fcc72020-10-19 14:38:18 -07005233 ret = field->parser(field, config, line, pos + flen + 1);
5234 if (ret < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005235 wpa_printf(MSG_ERROR, "Line %d: failed to "
5236 "parse '%s'.", line, pos);
5237 ret = -1;
5238 }
Hai Shalom899fcc72020-10-19 14:38:18 -07005239 if (ret == 1)
5240 break;
Dmitry Shmidtf8623282013-02-20 14:34:59 -08005241 if (field->changed_flag == CFG_CHANGED_NFC_PASSWORD_TOKEN)
5242 config->wps_nfc_pw_from_config = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005243 config->changed_parameters |= field->changed_flag;
5244 break;
5245 }
5246 if (i == NUM_GLOBAL_FIELDS) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005247#ifdef CONFIG_AP
Hai Shalom899fcc72020-10-19 14:38:18 -07005248 if (os_strncmp(pos, "tx_queue_", 9) == 0) {
5249 char *tmp = os_strchr(pos, '=');
5250
5251 if (!tmp) {
5252 if (line < 0)
5253 wpa_printf(MSG_ERROR,
5254 "Line %d: invalid line %s",
5255 line, pos);
5256 return -1;
5257 }
5258 *tmp++ = '\0';
5259 if (hostapd_config_tx_queue(config->tx_queue, pos,
5260 tmp)) {
5261 wpa_printf(MSG_ERROR,
5262 "Line %d: invalid TX queue item",
5263 line);
5264 return -1;
5265 }
5266 }
5267
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005268 if (os_strncmp(pos, "wmm_ac_", 7) == 0) {
5269 char *tmp = os_strchr(pos, '=');
5270 if (tmp == NULL) {
5271 if (line < 0)
5272 return -1;
5273 wpa_printf(MSG_ERROR, "Line %d: invalid line "
5274 "'%s'", line, pos);
5275 return -1;
5276 }
5277 *tmp++ = '\0';
5278 if (hostapd_config_wmm_ac(config->wmm_ac_params, pos,
5279 tmp)) {
5280 wpa_printf(MSG_ERROR, "Line %d: invalid WMM "
5281 "AC item", line);
5282 return -1;
5283 }
Hai Shalomc3565922019-10-28 11:58:20 -07005284 return ret;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005285 }
5286#endif /* CONFIG_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005287 if (line < 0)
5288 return -1;
5289 wpa_printf(MSG_ERROR, "Line %d: unknown global field '%s'.",
5290 line, pos);
5291 ret = -1;
5292 }
5293
5294 return ret;
5295}