]> git.ipfire.org Git - thirdparty/hostap.git/blame - wpa_supplicant/config.c
GAS server: Add forgotten break statement to a switch case
[thirdparty/hostap.git] / wpa_supplicant / config.c
CommitLineData
6fc6879b
JM
1/*
2 * WPA Supplicant / Configuration parser and common functions
f64adcd7 3 * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
6fc6879b 4 *
0f3d578e
JM
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
6fc6879b
JM
7 */
8
9#include "includes.h"
10
11#include "common.h"
121adf9c 12#include "utils/uuid.h"
03da66bd 13#include "crypto/sha1.h"
3acb5005 14#include "rsn_supp/wpa.h"
6fc6879b 15#include "eap_peer/eap.h"
21d996f7 16#include "p2p/p2p.h"
6fc6879b
JM
17#include "config.h"
18
19
20#if !defined(CONFIG_CTRL_IFACE) && defined(CONFIG_NO_CONFIG_WRITE)
21#define NO_CONFIG_WRITE
22#endif
23
24/*
25 * Structure for network configuration parsing. This data is used to implement
26 * a generic parser for each network block variable. The table of configuration
27 * variables is defined below in this file (ssid_fields[]).
28 */
29struct parse_data {
30 /* Configuration variable name */
31 char *name;
32
33 /* Parser function for this variable */
34 int (*parser)(const struct parse_data *data, struct wpa_ssid *ssid,
35 int line, const char *value);
36
37#ifndef NO_CONFIG_WRITE
38 /* Writer function (i.e., to get the variable in text format from
39 * internal presentation). */
40 char * (*writer)(const struct parse_data *data, struct wpa_ssid *ssid);
41#endif /* NO_CONFIG_WRITE */
42
43 /* Variable specific parameters for the parser. */
44 void *param1, *param2, *param3, *param4;
45
46 /* 0 = this variable can be included in debug output and ctrl_iface
47 * 1 = this variable contains key/private data and it must not be
48 * included in debug output unless explicitly requested. In
49 * addition, this variable will not be readable through the
50 * ctrl_iface.
51 */
52 int key_data;
53};
54
55
56static char * wpa_config_parse_string(const char *value, size_t *len)
57{
58 if (*value == '"') {
e237a6b0
JM
59 const char *pos;
60 char *str;
6fc6879b
JM
61 value++;
62 pos = os_strrchr(value, '"');
63 if (pos == NULL || pos[1] != '\0')
64 return NULL;
e237a6b0
JM
65 *len = pos - value;
66 str = os_malloc(*len + 1);
67 if (str == NULL)
68 return NULL;
69 os_memcpy(str, value, *len);
70 str[*len] = '\0';
5c4b93d7
JM
71 return str;
72 } else if (*value == 'P' && value[1] == '"') {
73 const char *pos;
74 char *tstr, *str;
75 size_t tlen;
76 value += 2;
77 pos = os_strrchr(value, '"');
78 if (pos == NULL || pos[1] != '\0')
79 return NULL;
80 tlen = pos - value;
81 tstr = os_malloc(tlen + 1);
82 if (tstr == NULL)
83 return NULL;
84 os_memcpy(tstr, value, tlen);
85 tstr[tlen] = '\0';
86
87 str = os_malloc(tlen + 1);
88 if (str == NULL) {
89 os_free(tstr);
90 return NULL;
91 }
92
93 *len = printf_decode((u8 *) str, tlen + 1, tstr);
94 os_free(tstr);
95
e237a6b0 96 return str;
6fc6879b
JM
97 } else {
98 u8 *str;
99 size_t tlen, hlen = os_strlen(value);
100 if (hlen & 1)
101 return NULL;
102 tlen = hlen / 2;
103 str = os_malloc(tlen + 1);
104 if (str == NULL)
105 return NULL;
106 if (hexstr2bin(value, str, tlen)) {
107 os_free(str);
108 return NULL;
109 }
110 str[tlen] = '\0';
111 *len = tlen;
112 return (char *) str;
113 }
114}
115
116
117static int wpa_config_parse_str(const struct parse_data *data,
118 struct wpa_ssid *ssid,
119 int line, const char *value)
120{
121 size_t res_len, *dst_len;
122 char **dst, *tmp;
123
b56c0546
JM
124 if (os_strcmp(value, "NULL") == 0) {
125 wpa_printf(MSG_DEBUG, "Unset configuration string '%s'",
126 data->name);
127 tmp = NULL;
128 res_len = 0;
129 goto set;
130 }
131
6fc6879b
JM
132 tmp = wpa_config_parse_string(value, &res_len);
133 if (tmp == NULL) {
134 wpa_printf(MSG_ERROR, "Line %d: failed to parse %s '%s'.",
135 line, data->name,
136 data->key_data ? "[KEY DATA REMOVED]" : value);
137 return -1;
138 }
139
140 if (data->key_data) {
141 wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
142 (u8 *) tmp, res_len);
143 } else {
144 wpa_hexdump_ascii(MSG_MSGDUMP, data->name,
145 (u8 *) tmp, res_len);
146 }
147
148 if (data->param3 && res_len < (size_t) data->param3) {
149 wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu "
150 "min_len=%ld)", line, data->name,
151 (unsigned long) res_len, (long) data->param3);
152 os_free(tmp);
153 return -1;
154 }
155
156 if (data->param4 && res_len > (size_t) data->param4) {
157 wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu "
158 "max_len=%ld)", line, data->name,
159 (unsigned long) res_len, (long) data->param4);
160 os_free(tmp);
161 return -1;
162 }
163
b56c0546 164set:
6fc6879b
JM
165 dst = (char **) (((u8 *) ssid) + (long) data->param1);
166 dst_len = (size_t *) (((u8 *) ssid) + (long) data->param2);
167 os_free(*dst);
168 *dst = tmp;
169 if (data->param2)
170 *dst_len = res_len;
171
172 return 0;
173}
174
175
176#ifndef NO_CONFIG_WRITE
177static int is_hex(const u8 *data, size_t len)
178{
179 size_t i;
180
181 for (i = 0; i < len; i++) {
182 if (data[i] < 32 || data[i] >= 127)
183 return 1;
184 }
185 return 0;
186}
187
188
189static char * wpa_config_write_string_ascii(const u8 *value, size_t len)
190{
191 char *buf;
192
193 buf = os_malloc(len + 3);
194 if (buf == NULL)
195 return NULL;
196 buf[0] = '"';
197 os_memcpy(buf + 1, value, len);
198 buf[len + 1] = '"';
199 buf[len + 2] = '\0';
200
201 return buf;
202}
203
204
205static char * wpa_config_write_string_hex(const u8 *value, size_t len)
206{
207 char *buf;
208
209 buf = os_zalloc(2 * len + 1);
210 if (buf == NULL)
211 return NULL;
212 wpa_snprintf_hex(buf, 2 * len + 1, value, len);
213
214 return buf;
215}
216
217
218static char * wpa_config_write_string(const u8 *value, size_t len)
219{
220 if (value == NULL)
221 return NULL;
222
223 if (is_hex(value, len))
224 return wpa_config_write_string_hex(value, len);
225 else
226 return wpa_config_write_string_ascii(value, len);
227}
228
229
230static char * wpa_config_write_str(const struct parse_data *data,
231 struct wpa_ssid *ssid)
232{
233 size_t len;
234 char **src;
235
236 src = (char **) (((u8 *) ssid) + (long) data->param1);
237 if (*src == NULL)
238 return NULL;
239
240 if (data->param2)
241 len = *((size_t *) (((u8 *) ssid) + (long) data->param2));
242 else
243 len = os_strlen(*src);
244
245 return wpa_config_write_string((const u8 *) *src, len);
246}
247#endif /* NO_CONFIG_WRITE */
248
249
250static int wpa_config_parse_int(const struct parse_data *data,
251 struct wpa_ssid *ssid,
252 int line, const char *value)
253{
254 int *dst;
255
256 dst = (int *) (((u8 *) ssid) + (long) data->param1);
257 *dst = atoi(value);
258 wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst);
259
260 if (data->param3 && *dst < (long) data->param3) {
261 wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d "
262 "min_value=%ld)", line, data->name, *dst,
263 (long) data->param3);
264 *dst = (long) data->param3;
265 return -1;
266 }
267
268 if (data->param4 && *dst > (long) data->param4) {
269 wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d "
270 "max_value=%ld)", line, data->name, *dst,
271 (long) data->param4);
272 *dst = (long) data->param4;
273 return -1;
274 }
275
276 return 0;
277}
278
279
280#ifndef NO_CONFIG_WRITE
281static char * wpa_config_write_int(const struct parse_data *data,
282 struct wpa_ssid *ssid)
283{
284 int *src, res;
285 char *value;
286
287 src = (int *) (((u8 *) ssid) + (long) data->param1);
288
289 value = os_malloc(20);
290 if (value == NULL)
291 return NULL;
292 res = os_snprintf(value, 20, "%d", *src);
293 if (res < 0 || res >= 20) {
294 os_free(value);
295 return NULL;
296 }
297 value[20 - 1] = '\0';
298 return value;
299}
300#endif /* NO_CONFIG_WRITE */
301
302
303static int wpa_config_parse_bssid(const struct parse_data *data,
304 struct wpa_ssid *ssid, int line,
305 const char *value)
306{
c0a321c5
WJL
307 if (value[0] == '\0' || os_strcmp(value, "\"\"") == 0 ||
308 os_strcmp(value, "any") == 0) {
309 ssid->bssid_set = 0;
310 wpa_printf(MSG_MSGDUMP, "BSSID any");
311 return 0;
312 }
6fc6879b
JM
313 if (hwaddr_aton(value, ssid->bssid)) {
314 wpa_printf(MSG_ERROR, "Line %d: Invalid BSSID '%s'.",
315 line, value);
316 return -1;
317 }
318 ssid->bssid_set = 1;
319 wpa_hexdump(MSG_MSGDUMP, "BSSID", ssid->bssid, ETH_ALEN);
320 return 0;
321}
322
323
324#ifndef NO_CONFIG_WRITE
325static char * wpa_config_write_bssid(const struct parse_data *data,
326 struct wpa_ssid *ssid)
327{
328 char *value;
329 int res;
330
331 if (!ssid->bssid_set)
332 return NULL;
333
334 value = os_malloc(20);
335 if (value == NULL)
336 return NULL;
337 res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->bssid));
338 if (res < 0 || res >= 20) {
339 os_free(value);
340 return NULL;
341 }
342 value[20 - 1] = '\0';
343 return value;
344}
345#endif /* NO_CONFIG_WRITE */
346
347
348static int wpa_config_parse_psk(const struct parse_data *data,
349 struct wpa_ssid *ssid, int line,
350 const char *value)
351{
9173b16f
JM
352#ifdef CONFIG_EXT_PASSWORD
353 if (os_strncmp(value, "ext:", 4) == 0) {
354 os_free(ssid->passphrase);
355 ssid->passphrase = NULL;
356 ssid->psk_set = 0;
357 os_free(ssid->ext_psk);
358 ssid->ext_psk = os_strdup(value + 4);
359 if (ssid->ext_psk == NULL)
360 return -1;
361 wpa_printf(MSG_DEBUG, "PSK: External password '%s'",
362 ssid->ext_psk);
363 return 0;
364 }
365#endif /* CONFIG_EXT_PASSWORD */
366
6fc6879b
JM
367 if (*value == '"') {
368#ifndef CONFIG_NO_PBKDF2
369 const char *pos;
370 size_t len;
371
372 value++;
373 pos = os_strrchr(value, '"');
374 if (pos)
375 len = pos - value;
376 else
377 len = os_strlen(value);
378 if (len < 8 || len > 63) {
379 wpa_printf(MSG_ERROR, "Line %d: Invalid passphrase "
380 "length %lu (expected: 8..63) '%s'.",
381 line, (unsigned long) len, value);
382 return -1;
383 }
384 wpa_hexdump_ascii_key(MSG_MSGDUMP, "PSK (ASCII passphrase)",
385 (u8 *) value, len);
386 if (ssid->passphrase && os_strlen(ssid->passphrase) == len &&
387 os_memcmp(ssid->passphrase, value, len) == 0)
388 return 0;
389 ssid->psk_set = 0;
390 os_free(ssid->passphrase);
391 ssid->passphrase = os_malloc(len + 1);
392 if (ssid->passphrase == NULL)
393 return -1;
394 os_memcpy(ssid->passphrase, value, len);
395 ssid->passphrase[len] = '\0';
396 return 0;
397#else /* CONFIG_NO_PBKDF2 */
398 wpa_printf(MSG_ERROR, "Line %d: ASCII passphrase not "
399 "supported.", line);
400 return -1;
401#endif /* CONFIG_NO_PBKDF2 */
402 }
403
404 if (hexstr2bin(value, ssid->psk, PMK_LEN) ||
405 value[PMK_LEN * 2] != '\0') {
406 wpa_printf(MSG_ERROR, "Line %d: Invalid PSK '%s'.",
407 line, value);
408 return -1;
409 }
410
411 os_free(ssid->passphrase);
412 ssid->passphrase = NULL;
413
414 ssid->psk_set = 1;
415 wpa_hexdump_key(MSG_MSGDUMP, "PSK", ssid->psk, PMK_LEN);
416 return 0;
417}
418
419
420#ifndef NO_CONFIG_WRITE
421static char * wpa_config_write_psk(const struct parse_data *data,
422 struct wpa_ssid *ssid)
423{
9173b16f
JM
424#ifdef CONFIG_EXT_PASSWORD
425 if (ssid->ext_psk) {
426 size_t len = 4 + os_strlen(ssid->ext_psk) + 1;
427 char *buf = os_malloc(len);
428 if (buf == NULL)
429 return NULL;
430 os_snprintf(buf, len, "ext:%s", ssid->ext_psk);
431 return buf;
432 }
433#endif /* CONFIG_EXT_PASSWORD */
434
6fc6879b
JM
435 if (ssid->passphrase)
436 return wpa_config_write_string_ascii(
437 (const u8 *) ssid->passphrase,
438 os_strlen(ssid->passphrase));
439
440 if (ssid->psk_set)
441 return wpa_config_write_string_hex(ssid->psk, PMK_LEN);
442
443 return NULL;
444}
445#endif /* NO_CONFIG_WRITE */
446
447
448static int wpa_config_parse_proto(const struct parse_data *data,
449 struct wpa_ssid *ssid, int line,
450 const char *value)
451{
452 int val = 0, last, errors = 0;
453 char *start, *end, *buf;
454
455 buf = os_strdup(value);
456 if (buf == NULL)
457 return -1;
458 start = buf;
459
460 while (*start != '\0') {
461 while (*start == ' ' || *start == '\t')
462 start++;
463 if (*start == '\0')
464 break;
465 end = start;
466 while (*end != ' ' && *end != '\t' && *end != '\0')
467 end++;
468 last = *end == '\0';
469 *end = '\0';
470 if (os_strcmp(start, "WPA") == 0)
471 val |= WPA_PROTO_WPA;
472 else if (os_strcmp(start, "RSN") == 0 ||
473 os_strcmp(start, "WPA2") == 0)
474 val |= WPA_PROTO_RSN;
475 else {
476 wpa_printf(MSG_ERROR, "Line %d: invalid proto '%s'",
477 line, start);
478 errors++;
479 }
480
481 if (last)
482 break;
483 start = end + 1;
484 }
485 os_free(buf);
486
487 if (val == 0) {
488 wpa_printf(MSG_ERROR,
489 "Line %d: no proto values configured.", line);
490 errors++;
491 }
492
493 wpa_printf(MSG_MSGDUMP, "proto: 0x%x", val);
494 ssid->proto = val;
495 return errors ? -1 : 0;
496}
497
498
499#ifndef NO_CONFIG_WRITE
500static char * wpa_config_write_proto(const struct parse_data *data,
501 struct wpa_ssid *ssid)
502{
503 int first = 1, ret;
504 char *buf, *pos, *end;
505
506 pos = buf = os_zalloc(10);
507 if (buf == NULL)
508 return NULL;
509 end = buf + 10;
510
511 if (ssid->proto & WPA_PROTO_WPA) {
512 ret = os_snprintf(pos, end - pos, "%sWPA", first ? "" : " ");
513 if (ret < 0 || ret >= end - pos)
514 return buf;
515 pos += ret;
516 first = 0;
517 }
518
519 if (ssid->proto & WPA_PROTO_RSN) {
520 ret = os_snprintf(pos, end - pos, "%sRSN", first ? "" : " ");
521 if (ret < 0 || ret >= end - pos)
522 return buf;
523 pos += ret;
524 first = 0;
525 }
526
527 return buf;
528}
529#endif /* NO_CONFIG_WRITE */
530
531
532static int wpa_config_parse_key_mgmt(const struct parse_data *data,
533 struct wpa_ssid *ssid, int line,
534 const char *value)
535{
536 int val = 0, last, errors = 0;
537 char *start, *end, *buf;
538
539 buf = os_strdup(value);
540 if (buf == NULL)
541 return -1;
542 start = buf;
543
544 while (*start != '\0') {
545 while (*start == ' ' || *start == '\t')
546 start++;
547 if (*start == '\0')
548 break;
549 end = start;
550 while (*end != ' ' && *end != '\t' && *end != '\0')
551 end++;
552 last = *end == '\0';
553 *end = '\0';
554 if (os_strcmp(start, "WPA-PSK") == 0)
555 val |= WPA_KEY_MGMT_PSK;
556 else if (os_strcmp(start, "WPA-EAP") == 0)
557 val |= WPA_KEY_MGMT_IEEE8021X;
558 else if (os_strcmp(start, "IEEE8021X") == 0)
559 val |= WPA_KEY_MGMT_IEEE8021X_NO_WPA;
560 else if (os_strcmp(start, "NONE") == 0)
561 val |= WPA_KEY_MGMT_NONE;
562 else if (os_strcmp(start, "WPA-NONE") == 0)
563 val |= WPA_KEY_MGMT_WPA_NONE;
564#ifdef CONFIG_IEEE80211R
565 else if (os_strcmp(start, "FT-PSK") == 0)
566 val |= WPA_KEY_MGMT_FT_PSK;
567 else if (os_strcmp(start, "FT-EAP") == 0)
568 val |= WPA_KEY_MGMT_FT_IEEE8021X;
569#endif /* CONFIG_IEEE80211R */
56586197
JM
570#ifdef CONFIG_IEEE80211W
571 else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
572 val |= WPA_KEY_MGMT_PSK_SHA256;
573 else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
574 val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
575#endif /* CONFIG_IEEE80211W */
ad08c363
JM
576#ifdef CONFIG_WPS
577 else if (os_strcmp(start, "WPS") == 0)
578 val |= WPA_KEY_MGMT_WPS;
579#endif /* CONFIG_WPS */
6fc6879b
JM
580 else {
581 wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
582 line, start);
583 errors++;
584 }
585
586 if (last)
587 break;
588 start = end + 1;
589 }
590 os_free(buf);
591
592 if (val == 0) {
593 wpa_printf(MSG_ERROR,
594 "Line %d: no key_mgmt values configured.", line);
595 errors++;
596 }
597
598 wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", val);
599 ssid->key_mgmt = val;
600 return errors ? -1 : 0;
601}
602
603
604#ifndef NO_CONFIG_WRITE
605static char * wpa_config_write_key_mgmt(const struct parse_data *data,
606 struct wpa_ssid *ssid)
607{
608 char *buf, *pos, *end;
609 int ret;
610
611 pos = buf = os_zalloc(50);
612 if (buf == NULL)
613 return NULL;
614 end = buf + 50;
615
616 if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
617 ret = os_snprintf(pos, end - pos, "%sWPA-PSK",
618 pos == buf ? "" : " ");
619 if (ret < 0 || ret >= end - pos) {
620 end[-1] = '\0';
621 return buf;
622 }
623 pos += ret;
624 }
625
626 if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
627 ret = os_snprintf(pos, end - pos, "%sWPA-EAP",
628 pos == buf ? "" : " ");
629 if (ret < 0 || ret >= end - pos) {
630 end[-1] = '\0';
631 return buf;
632 }
633 pos += ret;
634 }
635
636 if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
637 ret = os_snprintf(pos, end - pos, "%sIEEE8021X",
638 pos == buf ? "" : " ");
639 if (ret < 0 || ret >= end - pos) {
640 end[-1] = '\0';
641 return buf;
642 }
643 pos += ret;
644 }
645
646 if (ssid->key_mgmt & WPA_KEY_MGMT_NONE) {
647 ret = os_snprintf(pos, end - pos, "%sNONE",
648 pos == buf ? "" : " ");
649 if (ret < 0 || ret >= end - pos) {
650 end[-1] = '\0';
651 return buf;
652 }
653 pos += ret;
654 }
655
656 if (ssid->key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
657 ret = os_snprintf(pos, end - pos, "%sWPA-NONE",
658 pos == buf ? "" : " ");
659 if (ret < 0 || ret >= end - pos) {
660 end[-1] = '\0';
661 return buf;
662 }
663 pos += ret;
664 }
665
666#ifdef CONFIG_IEEE80211R
667 if (ssid->key_mgmt & WPA_KEY_MGMT_FT_PSK)
668 pos += os_snprintf(pos, end - pos, "%sFT-PSK",
669 pos == buf ? "" : " ");
670
671 if (ssid->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
672 pos += os_snprintf(pos, end - pos, "%sFT-EAP",
673 pos == buf ? "" : " ");
674#endif /* CONFIG_IEEE80211R */
675
56586197
JM
676#ifdef CONFIG_IEEE80211W
677 if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
678 pos += os_snprintf(pos, end - pos, "%sWPA-PSK-SHA256",
679 pos == buf ? "" : " ");
680
681 if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
682 pos += os_snprintf(pos, end - pos, "%sWPA-EAP-SHA256",
683 pos == buf ? "" : " ");
684#endif /* CONFIG_IEEE80211W */
685
728fae16
JM
686#ifdef CONFIG_WPS
687 if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
688 pos += os_snprintf(pos, end - pos, "%sWPS",
689 pos == buf ? "" : " ");
690#endif /* CONFIG_WPS */
691
6fc6879b
JM
692 return buf;
693}
694#endif /* NO_CONFIG_WRITE */
695
696
697static int wpa_config_parse_cipher(int line, const char *value)
698{
699 int val = 0, last;
700 char *start, *end, *buf;
701
702 buf = os_strdup(value);
703 if (buf == NULL)
704 return -1;
705 start = buf;
706
707 while (*start != '\0') {
708 while (*start == ' ' || *start == '\t')
709 start++;
710 if (*start == '\0')
711 break;
712 end = start;
713 while (*end != ' ' && *end != '\t' && *end != '\0')
714 end++;
715 last = *end == '\0';
716 *end = '\0';
717 if (os_strcmp(start, "CCMP") == 0)
718 val |= WPA_CIPHER_CCMP;
719 else if (os_strcmp(start, "TKIP") == 0)
720 val |= WPA_CIPHER_TKIP;
721 else if (os_strcmp(start, "WEP104") == 0)
722 val |= WPA_CIPHER_WEP104;
723 else if (os_strcmp(start, "WEP40") == 0)
724 val |= WPA_CIPHER_WEP40;
725 else if (os_strcmp(start, "NONE") == 0)
726 val |= WPA_CIPHER_NONE;
727 else {
728 wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
729 line, start);
730 os_free(buf);
731 return -1;
732 }
733
734 if (last)
735 break;
736 start = end + 1;
737 }
738 os_free(buf);
739
740 if (val == 0) {
741 wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.",
742 line);
743 return -1;
744 }
745 return val;
746}
747
748
749#ifndef NO_CONFIG_WRITE
750static char * wpa_config_write_cipher(int cipher)
751{
752 char *buf, *pos, *end;
753 int ret;
754
755 pos = buf = os_zalloc(50);
756 if (buf == NULL)
757 return NULL;
758 end = buf + 50;
759
760 if (cipher & WPA_CIPHER_CCMP) {
761 ret = os_snprintf(pos, end - pos, "%sCCMP",
762 pos == buf ? "" : " ");
763 if (ret < 0 || ret >= end - pos) {
764 end[-1] = '\0';
765 return buf;
766 }
767 pos += ret;
768 }
769
770 if (cipher & WPA_CIPHER_TKIP) {
771 ret = os_snprintf(pos, end - pos, "%sTKIP",
772 pos == buf ? "" : " ");
773 if (ret < 0 || ret >= end - pos) {
774 end[-1] = '\0';
775 return buf;
776 }
777 pos += ret;
778 }
779
780 if (cipher & WPA_CIPHER_WEP104) {
781 ret = os_snprintf(pos, end - pos, "%sWEP104",
782 pos == buf ? "" : " ");
783 if (ret < 0 || ret >= end - pos) {
784 end[-1] = '\0';
785 return buf;
786 }
787 pos += ret;
788 }
789
790 if (cipher & WPA_CIPHER_WEP40) {
791 ret = os_snprintf(pos, end - pos, "%sWEP40",
792 pos == buf ? "" : " ");
793 if (ret < 0 || ret >= end - pos) {
794 end[-1] = '\0';
795 return buf;
796 }
797 pos += ret;
798 }
799
800 if (cipher & WPA_CIPHER_NONE) {
801 ret = os_snprintf(pos, end - pos, "%sNONE",
802 pos == buf ? "" : " ");
803 if (ret < 0 || ret >= end - pos) {
804 end[-1] = '\0';
805 return buf;
806 }
807 pos += ret;
808 }
809
810 return buf;
811}
812#endif /* NO_CONFIG_WRITE */
813
814
815static int wpa_config_parse_pairwise(const struct parse_data *data,
816 struct wpa_ssid *ssid, int line,
817 const char *value)
818{
819 int val;
820 val = wpa_config_parse_cipher(line, value);
821 if (val == -1)
822 return -1;
823 if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE)) {
824 wpa_printf(MSG_ERROR, "Line %d: not allowed pairwise cipher "
825 "(0x%x).", line, val);
826 return -1;
827 }
828
829 wpa_printf(MSG_MSGDUMP, "pairwise: 0x%x", val);
830 ssid->pairwise_cipher = val;
831 return 0;
832}
833
834
835#ifndef NO_CONFIG_WRITE
836static char * wpa_config_write_pairwise(const struct parse_data *data,
837 struct wpa_ssid *ssid)
838{
839 return wpa_config_write_cipher(ssid->pairwise_cipher);
840}
841#endif /* NO_CONFIG_WRITE */
842
843
844static int wpa_config_parse_group(const struct parse_data *data,
845 struct wpa_ssid *ssid, int line,
846 const char *value)
847{
848 int val;
849 val = wpa_config_parse_cipher(line, value);
850 if (val == -1)
851 return -1;
852 if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | WPA_CIPHER_WEP104 |
853 WPA_CIPHER_WEP40)) {
854 wpa_printf(MSG_ERROR, "Line %d: not allowed group cipher "
855 "(0x%x).", line, val);
856 return -1;
857 }
858
859 wpa_printf(MSG_MSGDUMP, "group: 0x%x", val);
860 ssid->group_cipher = val;
861 return 0;
862}
863
864
865#ifndef NO_CONFIG_WRITE
866static char * wpa_config_write_group(const struct parse_data *data,
867 struct wpa_ssid *ssid)
868{
869 return wpa_config_write_cipher(ssid->group_cipher);
870}
871#endif /* NO_CONFIG_WRITE */
872
873
874static int wpa_config_parse_auth_alg(const struct parse_data *data,
875 struct wpa_ssid *ssid, int line,
876 const char *value)
877{
878 int val = 0, last, errors = 0;
879 char *start, *end, *buf;
880
881 buf = os_strdup(value);
882 if (buf == NULL)
883 return -1;
884 start = buf;
885
886 while (*start != '\0') {
887 while (*start == ' ' || *start == '\t')
888 start++;
889 if (*start == '\0')
890 break;
891 end = start;
892 while (*end != ' ' && *end != '\t' && *end != '\0')
893 end++;
894 last = *end == '\0';
895 *end = '\0';
896 if (os_strcmp(start, "OPEN") == 0)
897 val |= WPA_AUTH_ALG_OPEN;
898 else if (os_strcmp(start, "SHARED") == 0)
899 val |= WPA_AUTH_ALG_SHARED;
900 else if (os_strcmp(start, "LEAP") == 0)
901 val |= WPA_AUTH_ALG_LEAP;
902 else {
903 wpa_printf(MSG_ERROR, "Line %d: invalid auth_alg '%s'",
904 line, start);
905 errors++;
906 }
907
908 if (last)
909 break;
910 start = end + 1;
911 }
912 os_free(buf);
913
914 if (val == 0) {
915 wpa_printf(MSG_ERROR,
916 "Line %d: no auth_alg values configured.", line);
917 errors++;
918 }
919
920 wpa_printf(MSG_MSGDUMP, "auth_alg: 0x%x", val);
921 ssid->auth_alg = val;
922 return errors ? -1 : 0;
923}
924
925
926#ifndef NO_CONFIG_WRITE
927static char * wpa_config_write_auth_alg(const struct parse_data *data,
928 struct wpa_ssid *ssid)
929{
930 char *buf, *pos, *end;
931 int ret;
932
933 pos = buf = os_zalloc(30);
934 if (buf == NULL)
935 return NULL;
936 end = buf + 30;
937
938 if (ssid->auth_alg & WPA_AUTH_ALG_OPEN) {
939 ret = os_snprintf(pos, end - pos, "%sOPEN",
940 pos == buf ? "" : " ");
941 if (ret < 0 || ret >= end - pos) {
942 end[-1] = '\0';
943 return buf;
944 }
945 pos += ret;
946 }
947
948 if (ssid->auth_alg & WPA_AUTH_ALG_SHARED) {
949 ret = os_snprintf(pos, end - pos, "%sSHARED",
950 pos == buf ? "" : " ");
951 if (ret < 0 || ret >= end - pos) {
952 end[-1] = '\0';
953 return buf;
954 }
955 pos += ret;
956 }
957
958 if (ssid->auth_alg & WPA_AUTH_ALG_LEAP) {
959 ret = os_snprintf(pos, end - pos, "%sLEAP",
960 pos == buf ? "" : " ");
961 if (ret < 0 || ret >= end - pos) {
962 end[-1] = '\0';
963 return buf;
964 }
965 pos += ret;
966 }
967
968 return buf;
969}
970#endif /* NO_CONFIG_WRITE */
971
972
b766a9a2
JM
973static int * wpa_config_parse_freqs(const struct parse_data *data,
974 struct wpa_ssid *ssid, int line,
975 const char *value)
d3a98225
JM
976{
977 int *freqs;
978 size_t used, len;
979 const char *pos;
980
981 used = 0;
982 len = 10;
983 freqs = os_zalloc((len + 1) * sizeof(int));
984 if (freqs == NULL)
b766a9a2 985 return NULL;
d3a98225
JM
986
987 pos = value;
988 while (pos) {
989 while (*pos == ' ')
990 pos++;
991 if (used == len) {
992 int *n;
993 size_t i;
994 n = os_realloc(freqs, (len * 2 + 1) * sizeof(int));
995 if (n == NULL) {
996 os_free(freqs);
b766a9a2 997 return NULL;
d3a98225
JM
998 }
999 for (i = len; i <= len * 2; i++)
1000 n[i] = 0;
1001 freqs = n;
1002 len *= 2;
1003 }
1004
1005 freqs[used] = atoi(pos);
1006 if (freqs[used] == 0)
1007 break;
1008 used++;
1009 pos = os_strchr(pos + 1, ' ');
1010 }
1011
b766a9a2
JM
1012 return freqs;
1013}
1014
1015
1016static int wpa_config_parse_scan_freq(const struct parse_data *data,
1017 struct wpa_ssid *ssid, int line,
1018 const char *value)
1019{
1020 int *freqs;
1021
1022 freqs = wpa_config_parse_freqs(data, ssid, line, value);
1023 if (freqs == NULL)
1024 return -1;
d3a98225
JM
1025 os_free(ssid->scan_freq);
1026 ssid->scan_freq = freqs;
1027
1028 return 0;
1029}
1030
1031
b766a9a2
JM
1032static int wpa_config_parse_freq_list(const struct parse_data *data,
1033 struct wpa_ssid *ssid, int line,
1034 const char *value)
1035{
1036 int *freqs;
1037
1038 freqs = wpa_config_parse_freqs(data, ssid, line, value);
1039 if (freqs == NULL)
1040 return -1;
1041 os_free(ssid->freq_list);
1042 ssid->freq_list = freqs;
1043
1044 return 0;
1045}
1046
1047
d3a98225 1048#ifndef NO_CONFIG_WRITE
b766a9a2
JM
1049static char * wpa_config_write_freqs(const struct parse_data *data,
1050 const int *freqs)
d3a98225
JM
1051{
1052 char *buf, *pos, *end;
1053 int i, ret;
1054 size_t count;
1055
b766a9a2 1056 if (freqs == NULL)
d3a98225
JM
1057 return NULL;
1058
1059 count = 0;
b766a9a2 1060 for (i = 0; freqs[i]; i++)
d3a98225
JM
1061 count++;
1062
1063 pos = buf = os_zalloc(10 * count + 1);
1064 if (buf == NULL)
1065 return NULL;
1066 end = buf + 10 * count + 1;
1067
b766a9a2 1068 for (i = 0; freqs[i]; i++) {
d3a98225 1069 ret = os_snprintf(pos, end - pos, "%s%u",
b766a9a2 1070 i == 0 ? "" : " ", freqs[i]);
d3a98225
JM
1071 if (ret < 0 || ret >= end - pos) {
1072 end[-1] = '\0';
1073 return buf;
1074 }
1075 pos += ret;
1076 }
1077
1078 return buf;
1079}
b766a9a2
JM
1080
1081
1082static char * wpa_config_write_scan_freq(const struct parse_data *data,
1083 struct wpa_ssid *ssid)
1084{
1085 return wpa_config_write_freqs(data, ssid->scan_freq);
1086}
1087
1088
1089static char * wpa_config_write_freq_list(const struct parse_data *data,
1090 struct wpa_ssid *ssid)
1091{
1092 return wpa_config_write_freqs(data, ssid->freq_list);
1093}
d3a98225
JM
1094#endif /* NO_CONFIG_WRITE */
1095
1096
6fc6879b
JM
1097#ifdef IEEE8021X_EAPOL
1098static int wpa_config_parse_eap(const struct parse_data *data,
1099 struct wpa_ssid *ssid, int line,
1100 const char *value)
1101{
1102 int last, errors = 0;
1103 char *start, *end, *buf;
1104 struct eap_method_type *methods = NULL, *tmp;
1105 size_t num_methods = 0;
1106
1107 buf = os_strdup(value);
1108 if (buf == NULL)
1109 return -1;
1110 start = buf;
1111
1112 while (*start != '\0') {
1113 while (*start == ' ' || *start == '\t')
1114 start++;
1115 if (*start == '\0')
1116 break;
1117 end = start;
1118 while (*end != ' ' && *end != '\t' && *end != '\0')
1119 end++;
1120 last = *end == '\0';
1121 *end = '\0';
1122 tmp = methods;
1123 methods = os_realloc(methods,
1124 (num_methods + 1) * sizeof(*methods));
1125 if (methods == NULL) {
1126 os_free(tmp);
1127 os_free(buf);
1128 return -1;
1129 }
1130 methods[num_methods].method = eap_peer_get_type(
1131 start, &methods[num_methods].vendor);
1132 if (methods[num_methods].vendor == EAP_VENDOR_IETF &&
1133 methods[num_methods].method == EAP_TYPE_NONE) {
1134 wpa_printf(MSG_ERROR, "Line %d: unknown EAP method "
1135 "'%s'", line, start);
1136 wpa_printf(MSG_ERROR, "You may need to add support for"
1137 " this EAP method during wpa_supplicant\n"
1138 "build time configuration.\n"
1139 "See README for more information.");
1140 errors++;
1141 } else if (methods[num_methods].vendor == EAP_VENDOR_IETF &&
1142 methods[num_methods].method == EAP_TYPE_LEAP)
1143 ssid->leap++;
1144 else
1145 ssid->non_leap++;
1146 num_methods++;
1147 if (last)
1148 break;
1149 start = end + 1;
1150 }
1151 os_free(buf);
1152
1153 tmp = methods;
1154 methods = os_realloc(methods, (num_methods + 1) * sizeof(*methods));
1155 if (methods == NULL) {
1156 os_free(tmp);
1157 return -1;
1158 }
1159 methods[num_methods].vendor = EAP_VENDOR_IETF;
1160 methods[num_methods].method = EAP_TYPE_NONE;
1161 num_methods++;
1162
1163 wpa_hexdump(MSG_MSGDUMP, "eap methods",
1164 (u8 *) methods, num_methods * sizeof(*methods));
bb8b1bb0 1165 os_free(ssid->eap.eap_methods);
6fc6879b
JM
1166 ssid->eap.eap_methods = methods;
1167 return errors ? -1 : 0;
1168}
1169
1170
1171static char * wpa_config_write_eap(const struct parse_data *data,
1172 struct wpa_ssid *ssid)
1173{
1174 int i, ret;
1175 char *buf, *pos, *end;
1176 const struct eap_method_type *eap_methods = ssid->eap.eap_methods;
1177 const char *name;
1178
1179 if (eap_methods == NULL)
1180 return NULL;
1181
1182 pos = buf = os_zalloc(100);
1183 if (buf == NULL)
1184 return NULL;
1185 end = buf + 100;
1186
1187 for (i = 0; eap_methods[i].vendor != EAP_VENDOR_IETF ||
1188 eap_methods[i].method != EAP_TYPE_NONE; i++) {
1189 name = eap_get_name(eap_methods[i].vendor,
1190 eap_methods[i].method);
1191 if (name) {
1192 ret = os_snprintf(pos, end - pos, "%s%s",
1193 pos == buf ? "" : " ", name);
1194 if (ret < 0 || ret >= end - pos)
1195 break;
1196 pos += ret;
1197 }
1198 }
1199
1200 end[-1] = '\0';
1201
1202 return buf;
1203}
1204
1205
1206static int wpa_config_parse_password(const struct parse_data *data,
1207 struct wpa_ssid *ssid, int line,
1208 const char *value)
1209{
1210 u8 *hash;
1211
b56c0546
JM
1212 if (os_strcmp(value, "NULL") == 0) {
1213 wpa_printf(MSG_DEBUG, "Unset configuration string 'password'");
1214 os_free(ssid->eap.password);
1215 ssid->eap.password = NULL;
1216 ssid->eap.password_len = 0;
1217 return 0;
1218 }
1219
0ebb23e3
JM
1220#ifdef CONFIG_EXT_PASSWORD
1221 if (os_strncmp(value, "ext:", 4) == 0) {
1222 char *name = os_strdup(value + 4);
1223 if (name == NULL)
1224 return -1;
1225 os_free(ssid->eap.password);
1226 ssid->eap.password = (u8 *) name;
1227 ssid->eap.password_len = os_strlen(name);
1228 ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
1229 ssid->eap.flags |= EAP_CONFIG_FLAGS_EXT_PASSWORD;
1230 return 0;
1231 }
1232#endif /* CONFIG_EXT_PASSWORD */
1233
6fc6879b
JM
1234 if (os_strncmp(value, "hash:", 5) != 0) {
1235 char *tmp;
1236 size_t res_len;
1237
1238 tmp = wpa_config_parse_string(value, &res_len);
1239 if (tmp == NULL) {
1240 wpa_printf(MSG_ERROR, "Line %d: failed to parse "
1241 "password.", line);
1242 return -1;
1243 }
556f5a2a
HS
1244 wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
1245 (u8 *) tmp, res_len);
6fc6879b
JM
1246
1247 os_free(ssid->eap.password);
1248 ssid->eap.password = (u8 *) tmp;
1249 ssid->eap.password_len = res_len;
1250 ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
0ebb23e3 1251 ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD;
6fc6879b
JM
1252
1253 return 0;
1254 }
1255
1256
1257 /* NtPasswordHash: hash:<32 hex digits> */
1258 if (os_strlen(value + 5) != 2 * 16) {
1259 wpa_printf(MSG_ERROR, "Line %d: Invalid password hash length "
1260 "(expected 32 hex digits)", line);
1261 return -1;
1262 }
1263
1264 hash = os_malloc(16);
1265 if (hash == NULL)
1266 return -1;
1267
1268 if (hexstr2bin(value + 5, hash, 16)) {
1269 os_free(hash);
1270 wpa_printf(MSG_ERROR, "Line %d: Invalid password hash", line);
1271 return -1;
1272 }
1273
1274 wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16);
1275
1276 os_free(ssid->eap.password);
1277 ssid->eap.password = hash;
1278 ssid->eap.password_len = 16;
1279 ssid->eap.flags |= EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
0ebb23e3 1280 ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD;
6fc6879b
JM
1281
1282 return 0;
1283}
1284
1285
1286static char * wpa_config_write_password(const struct parse_data *data,
1287 struct wpa_ssid *ssid)
1288{
1289 char *buf;
1290
1291 if (ssid->eap.password == NULL)
1292 return NULL;
1293
0ebb23e3
JM
1294#ifdef CONFIG_EXT_PASSWORD
1295 if (ssid->eap.flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
1296 buf = os_zalloc(4 + ssid->eap.password_len + 1);
1297 if (buf == NULL)
1298 return NULL;
1299 os_memcpy(buf, "ext:", 4);
1300 os_memcpy(buf + 4, ssid->eap.password, ssid->eap.password_len);
1301 return buf;
1302 }
1303#endif /* CONFIG_EXT_PASSWORD */
1304
6fc6879b
JM
1305 if (!(ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) {
1306 return wpa_config_write_string(
1307 ssid->eap.password, ssid->eap.password_len);
1308 }
1309
1310 buf = os_malloc(5 + 32 + 1);
1311 if (buf == NULL)
1312 return NULL;
1313
1314 os_memcpy(buf, "hash:", 5);
1315 wpa_snprintf_hex(buf + 5, 32 + 1, ssid->eap.password, 16);
1316
1317 return buf;
1318}
1319#endif /* IEEE8021X_EAPOL */
1320
1321
1322static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line,
1323 const char *value, int idx)
1324{
1325 char *buf, title[20];
1326 int res;
1327
1328 buf = wpa_config_parse_string(value, len);
1329 if (buf == NULL) {
1330 wpa_printf(MSG_ERROR, "Line %d: Invalid WEP key %d '%s'.",
1331 line, idx, value);
1332 return -1;
1333 }
1334 if (*len > MAX_WEP_KEY_LEN) {
1335 wpa_printf(MSG_ERROR, "Line %d: Too long WEP key %d '%s'.",
1336 line, idx, value);
1337 os_free(buf);
1338 return -1;
1339 }
fea7c3a0
JM
1340 if (*len && *len != 5 && *len != 13 && *len != 16) {
1341 wpa_printf(MSG_ERROR, "Line %d: Invalid WEP key length %u - "
1342 "this network block will be ignored",
1343 line, (unsigned int) *len);
1344 }
6fc6879b
JM
1345 os_memcpy(key, buf, *len);
1346 os_free(buf);
1347 res = os_snprintf(title, sizeof(title), "wep_key%d", idx);
1348 if (res >= 0 && (size_t) res < sizeof(title))
1349 wpa_hexdump_key(MSG_MSGDUMP, title, key, *len);
1350 return 0;
1351}
1352
1353
1354static int wpa_config_parse_wep_key0(const struct parse_data *data,
1355 struct wpa_ssid *ssid, int line,
1356 const char *value)
1357{
1358 return wpa_config_parse_wep_key(ssid->wep_key[0],
1359 &ssid->wep_key_len[0], line,
1360 value, 0);
1361}
1362
1363
1364static int wpa_config_parse_wep_key1(const struct parse_data *data,
1365 struct wpa_ssid *ssid, int line,
1366 const char *value)
1367{
1368 return wpa_config_parse_wep_key(ssid->wep_key[1],
1369 &ssid->wep_key_len[1], line,
1370 value, 1);
1371}
1372
1373
1374static int wpa_config_parse_wep_key2(const struct parse_data *data,
1375 struct wpa_ssid *ssid, int line,
1376 const char *value)
1377{
1378 return wpa_config_parse_wep_key(ssid->wep_key[2],
1379 &ssid->wep_key_len[2], line,
1380 value, 2);
1381}
1382
1383
1384static int wpa_config_parse_wep_key3(const struct parse_data *data,
1385 struct wpa_ssid *ssid, int line,
1386 const char *value)
1387{
1388 return wpa_config_parse_wep_key(ssid->wep_key[3],
1389 &ssid->wep_key_len[3], line,
1390 value, 3);
1391}
1392
1393
1394#ifndef NO_CONFIG_WRITE
1395static char * wpa_config_write_wep_key(struct wpa_ssid *ssid, int idx)
1396{
1397 if (ssid->wep_key_len[idx] == 0)
1398 return NULL;
1399 return wpa_config_write_string(ssid->wep_key[idx],
1400 ssid->wep_key_len[idx]);
1401}
1402
1403
1404static char * wpa_config_write_wep_key0(const struct parse_data *data,
1405 struct wpa_ssid *ssid)
1406{
1407 return wpa_config_write_wep_key(ssid, 0);
1408}
1409
1410
1411static char * wpa_config_write_wep_key1(const struct parse_data *data,
1412 struct wpa_ssid *ssid)
1413{
1414 return wpa_config_write_wep_key(ssid, 1);
1415}
1416
1417
1418static char * wpa_config_write_wep_key2(const struct parse_data *data,
1419 struct wpa_ssid *ssid)
1420{
1421 return wpa_config_write_wep_key(ssid, 2);
1422}
1423
1424
1425static char * wpa_config_write_wep_key3(const struct parse_data *data,
1426 struct wpa_ssid *ssid)
1427{
1428 return wpa_config_write_wep_key(ssid, 3);
1429}
1430#endif /* NO_CONFIG_WRITE */
1431
1432
fbdcfd57
JM
1433#ifdef CONFIG_P2P
1434
1435static int wpa_config_parse_p2p_client_list(const struct parse_data *data,
1436 struct wpa_ssid *ssid, int line,
1437 const char *value)
1438{
1439 const char *pos;
1440 u8 *buf, *n, addr[ETH_ALEN];
1441 size_t count;
1442
1443 buf = NULL;
1444 count = 0;
1445
1446 pos = value;
1447 while (pos && *pos) {
1448 while (*pos == ' ')
1449 pos++;
1450
1451 if (hwaddr_aton(pos, addr)) {
1452 wpa_printf(MSG_ERROR, "Line %d: Invalid "
1453 "p2p_client_list address '%s'.",
1454 line, value);
1455 /* continue anyway */
1456 } else {
1457 n = os_realloc(buf, (count + 1) * ETH_ALEN);
1458 if (n == NULL) {
1459 os_free(buf);
1460 return -1;
1461 }
1462 buf = n;
1463 os_memcpy(buf + count * ETH_ALEN, addr, ETH_ALEN);
1464 count++;
1465 wpa_hexdump(MSG_MSGDUMP, "p2p_client_list",
1466 addr, ETH_ALEN);
1467 }
1468
1469 pos = os_strchr(pos, ' ');
1470 }
1471
1472 os_free(ssid->p2p_client_list);
1473 ssid->p2p_client_list = buf;
1474 ssid->num_p2p_clients = count;
1475
1476 return 0;
1477}
1478
1479
1480#ifndef NO_CONFIG_WRITE
1481static char * wpa_config_write_p2p_client_list(const struct parse_data *data,
1482 struct wpa_ssid *ssid)
1483{
1484 char *value, *end, *pos;
1485 int res;
1486 size_t i;
1487
1488 if (ssid->p2p_client_list == NULL || ssid->num_p2p_clients == 0)
1489 return NULL;
1490
1491 value = os_malloc(20 * ssid->num_p2p_clients);
1492 if (value == NULL)
1493 return NULL;
1494 pos = value;
1495 end = value + 20 * ssid->num_p2p_clients;
1496
1497 for (i = 0; i < ssid->num_p2p_clients; i++) {
1498 res = os_snprintf(pos, end - pos, MACSTR " ",
1499 MAC2STR(ssid->p2p_client_list +
1500 i * ETH_ALEN));
1501 if (res < 0 || res >= end - pos) {
1502 os_free(value);
1503 return NULL;
1504 }
1505 pos += res;
1506 }
1507
1508 if (pos > value)
1509 pos[-1] = '\0';
1510
1511 return value;
1512}
1513#endif /* NO_CONFIG_WRITE */
1514
1515#endif /* CONFIG_P2P */
1516
6fc6879b
JM
1517/* Helper macros for network block parser */
1518
1519#ifdef OFFSET
1520#undef OFFSET
1521#endif /* OFFSET */
1522/* OFFSET: Get offset of a variable within the wpa_ssid structure */
1523#define OFFSET(v) ((void *) &((struct wpa_ssid *) 0)->v)
1524
1525/* STR: Define a string variable for an ASCII string; f = field name */
1526#ifdef NO_CONFIG_WRITE
1527#define _STR(f) #f, wpa_config_parse_str, OFFSET(f)
1528#define _STRe(f) #f, wpa_config_parse_str, OFFSET(eap.f)
1529#else /* NO_CONFIG_WRITE */
1530#define _STR(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(f)
1531#define _STRe(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(eap.f)
1532#endif /* NO_CONFIG_WRITE */
1533#define STR(f) _STR(f), NULL, NULL, NULL, 0
1534#define STRe(f) _STRe(f), NULL, NULL, NULL, 0
1535#define STR_KEY(f) _STR(f), NULL, NULL, NULL, 1
1536#define STR_KEYe(f) _STRe(f), NULL, NULL, NULL, 1
1537
1538/* STR_LEN: Define a string variable with a separate variable for storing the
1539 * data length. Unlike STR(), this can be used to store arbitrary binary data
1540 * (i.e., even nul termination character). */
1541#define _STR_LEN(f) _STR(f), OFFSET(f ## _len)
1542#define _STR_LENe(f) _STRe(f), OFFSET(eap.f ## _len)
1543#define STR_LEN(f) _STR_LEN(f), NULL, NULL, 0
1544#define STR_LENe(f) _STR_LENe(f), NULL, NULL, 0
1545#define STR_LEN_KEY(f) _STR_LEN(f), NULL, NULL, 1
1546
1547/* STR_RANGE: Like STR_LEN(), but with minimum and maximum allowed length
1548 * explicitly specified. */
1549#define _STR_RANGE(f, min, max) _STR_LEN(f), (void *) (min), (void *) (max)
1550#define STR_RANGE(f, min, max) _STR_RANGE(f, min, max), 0
1551#define STR_RANGE_KEY(f, min, max) _STR_RANGE(f, min, max), 1
1552
1553#ifdef NO_CONFIG_WRITE
1554#define _INT(f) #f, wpa_config_parse_int, OFFSET(f), (void *) 0
1555#define _INTe(f) #f, wpa_config_parse_int, OFFSET(eap.f), (void *) 0
1556#else /* NO_CONFIG_WRITE */
1557#define _INT(f) #f, wpa_config_parse_int, wpa_config_write_int, \
1558 OFFSET(f), (void *) 0
1559#define _INTe(f) #f, wpa_config_parse_int, wpa_config_write_int, \
1560 OFFSET(eap.f), (void *) 0
1561#endif /* NO_CONFIG_WRITE */
1562
1563/* INT: Define an integer variable */
1564#define INT(f) _INT(f), NULL, NULL, 0
1565#define INTe(f) _INTe(f), NULL, NULL, 0
1566
1567/* INT_RANGE: Define an integer variable with allowed value range */
1568#define INT_RANGE(f, min, max) _INT(f), (void *) (min), (void *) (max), 0
1569
1570/* FUNC: Define a configuration variable that uses a custom function for
1571 * parsing and writing the value. */
1572#ifdef NO_CONFIG_WRITE
1573#define _FUNC(f) #f, wpa_config_parse_ ## f, NULL, NULL, NULL, NULL
1574#else /* NO_CONFIG_WRITE */
1575#define _FUNC(f) #f, wpa_config_parse_ ## f, wpa_config_write_ ## f, \
1576 NULL, NULL, NULL, NULL
1577#endif /* NO_CONFIG_WRITE */
1578#define FUNC(f) _FUNC(f), 0
1579#define FUNC_KEY(f) _FUNC(f), 1
1580
1581/*
1582 * Table of network configuration variables. This table is used to parse each
1583 * network configuration variable, e.g., each line in wpa_supplicant.conf file
1584 * that is inside a network block.
1585 *
1586 * This table is generated using the helper macros defined above and with
1587 * generous help from the C pre-processor. The field name is stored as a string
1588 * into .name and for STR and INT types, the offset of the target buffer within
1589 * struct wpa_ssid is stored in .param1. .param2 (if not NULL) is similar
1590 * offset to the field containing the length of the configuration variable.
1591 * .param3 and .param4 can be used to mark the allowed range (length for STR
1592 * and value for INT).
1593 *
1594 * For each configuration line in wpa_supplicant.conf, the parser goes through
1595 * this table and select the entry that matches with the field name. The parser
1596 * function (.parser) is then called to parse the actual value of the field.
1597 *
1598 * This kind of mechanism makes it easy to add new configuration parameters,
1599 * since only one line needs to be added into this table and into the
1600 * struct wpa_ssid definition if the new variable is either a string or
1601 * integer. More complex types will need to use their own parser and writer
1602 * functions.
1603 */
1604static const struct parse_data ssid_fields[] = {
1605 { STR_RANGE(ssid, 0, MAX_SSID_LEN) },
1606 { INT_RANGE(scan_ssid, 0, 1) },
1607 { FUNC(bssid) },
1608 { FUNC_KEY(psk) },
1609 { FUNC(proto) },
1610 { FUNC(key_mgmt) },
1f6c0ab8 1611 { INT(bg_scan_period) },
6fc6879b
JM
1612 { FUNC(pairwise) },
1613 { FUNC(group) },
1614 { FUNC(auth_alg) },
d3a98225 1615 { FUNC(scan_freq) },
b766a9a2 1616 { FUNC(freq_list) },
6fc6879b
JM
1617#ifdef IEEE8021X_EAPOL
1618 { FUNC(eap) },
1619 { STR_LENe(identity) },
1620 { STR_LENe(anonymous_identity) },
556f5a2a 1621 { FUNC_KEY(password) },
6fc6879b
JM
1622 { STRe(ca_cert) },
1623 { STRe(ca_path) },
1624 { STRe(client_cert) },
1625 { STRe(private_key) },
1626 { STR_KEYe(private_key_passwd) },
1627 { STRe(dh_file) },
1628 { STRe(subject_match) },
1629 { STRe(altsubject_match) },
1630 { STRe(ca_cert2) },
1631 { STRe(ca_path2) },
1632 { STRe(client_cert2) },
1633 { STRe(private_key2) },
1634 { STR_KEYe(private_key2_passwd) },
1635 { STRe(dh_file2) },
1636 { STRe(subject_match2) },
1637 { STRe(altsubject_match2) },
1638 { STRe(phase1) },
1639 { STRe(phase2) },
1640 { STRe(pcsc) },
1641 { STR_KEYe(pin) },
1642 { STRe(engine_id) },
1643 { STRe(key_id) },
61ee0f71
DS
1644 { STRe(cert_id) },
1645 { STRe(ca_cert_id) },
98842d51
CL
1646 { STR_KEYe(pin2) },
1647 { STRe(engine2_id) },
61ee0f71
DS
1648 { STRe(key2_id) },
1649 { STRe(cert2_id) },
1650 { STRe(ca_cert2_id) },
6fc6879b 1651 { INTe(engine) },
98842d51 1652 { INTe(engine2) },
6fc6879b
JM
1653 { INT(eapol_flags) },
1654#endif /* IEEE8021X_EAPOL */
1655 { FUNC_KEY(wep_key0) },
1656 { FUNC_KEY(wep_key1) },
1657 { FUNC_KEY(wep_key2) },
1658 { FUNC_KEY(wep_key3) },
1659 { INT(wep_tx_keyidx) },
1660 { INT(priority) },
1661#ifdef IEEE8021X_EAPOL
1662 { INT(eap_workaround) },
1663 { STRe(pac_file) },
1664 { INTe(fragment_size) },
1665#endif /* IEEE8021X_EAPOL */
2c5d725c 1666 { INT_RANGE(mode, 0, 4) },
6fc6879b 1667 { INT_RANGE(proactive_key_caching, 0, 1) },
4dac0245 1668 { INT_RANGE(disabled, 0, 2) },
6fc6879b
JM
1669 { STR(id_str) },
1670#ifdef CONFIG_IEEE80211W
1671 { INT_RANGE(ieee80211w, 0, 2) },
1672#endif /* CONFIG_IEEE80211W */
1673 { INT_RANGE(peerkey, 0, 1) },
1674 { INT_RANGE(mixed_cell, 0, 1) },
581a8cde 1675 { INT_RANGE(frequency, 0, 10000) },
60b94c98
JM
1676 { INT(wpa_ptk_rekey) },
1677 { STR(bgscan) },
e62f4ed0 1678 { INT_RANGE(ignore_broadcast_ssid, 0, 2) },
fbdcfd57
JM
1679#ifdef CONFIG_P2P
1680 { FUNC(p2p_client_list) },
1681#endif /* CONFIG_P2P */
80e8a5ee
BG
1682#ifdef CONFIG_HT_OVERRIDES
1683 { INT_RANGE(disable_ht, 0, 1) },
1684 { INT_RANGE(disable_ht40, -1, 1) },
1685 { INT_RANGE(disable_max_amsdu, -1, 1) },
1686 { INT_RANGE(ampdu_factor, -1, 3) },
1687 { INT_RANGE(ampdu_density, -1, 7) },
1688 { STR(ht_mcs) },
1689#endif /* CONFIG_HT_OVERRIDES */
07f53b8c 1690 { INT(ap_max_inactivity) },
fdfb1c8b 1691 { INT(dtim_period) },
6fc6879b
JM
1692};
1693
1694#undef OFFSET
1695#undef _STR
1696#undef STR
1697#undef STR_KEY
1698#undef _STR_LEN
1699#undef STR_LEN
1700#undef STR_LEN_KEY
1701#undef _STR_RANGE
1702#undef STR_RANGE
1703#undef STR_RANGE_KEY
1704#undef _INT
1705#undef INT
1706#undef INT_RANGE
1707#undef _FUNC
1708#undef FUNC
1709#undef FUNC_KEY
1710#define NUM_SSID_FIELDS (sizeof(ssid_fields) / sizeof(ssid_fields[0]))
1711
1712
1713/**
1714 * wpa_config_add_prio_network - Add a network to priority lists
1715 * @config: Configuration data from wpa_config_read()
1716 * @ssid: Pointer to the network configuration to be added to the list
1717 * Returns: 0 on success, -1 on failure
1718 *
1719 * This function is used to add a network block to the priority list of
1720 * networks. This must be called for each network when reading in the full
1721 * configuration. In addition, this can be used indirectly when updating
1722 * priorities by calling wpa_config_update_prio_list().
1723 */
1724int wpa_config_add_prio_network(struct wpa_config *config,
1725 struct wpa_ssid *ssid)
1726{
1727 int prio;
1728 struct wpa_ssid *prev, **nlist;
1729
1730 /*
1731 * Add to an existing priority list if one is available for the
1732 * configured priority level for this network.
1733 */
1734 for (prio = 0; prio < config->num_prio; prio++) {
1735 prev = config->pssid[prio];
1736 if (prev->priority == ssid->priority) {
1737 while (prev->pnext)
1738 prev = prev->pnext;
1739 prev->pnext = ssid;
1740 return 0;
1741 }
1742 }
1743
1744 /* First network for this priority - add a new priority list */
1745 nlist = os_realloc(config->pssid,
1746 (config->num_prio + 1) * sizeof(struct wpa_ssid *));
1747 if (nlist == NULL)
1748 return -1;
1749
1750 for (prio = 0; prio < config->num_prio; prio++) {
2c60ca73
JM
1751 if (nlist[prio]->priority < ssid->priority) {
1752 os_memmove(&nlist[prio + 1], &nlist[prio],
1753 (config->num_prio - prio) *
1754 sizeof(struct wpa_ssid *));
6fc6879b 1755 break;
2c60ca73 1756 }
6fc6879b
JM
1757 }
1758
6fc6879b
JM
1759 nlist[prio] = ssid;
1760 config->num_prio++;
1761 config->pssid = nlist;
1762
1763 return 0;
1764}
1765
1766
1767/**
1768 * wpa_config_update_prio_list - Update network priority list
1769 * @config: Configuration data from wpa_config_read()
1770 * Returns: 0 on success, -1 on failure
1771 *
1772 * This function is called to update the priority list of networks in the
1773 * configuration when a network is being added or removed. This is also called
1774 * if a priority for a network is changed.
1775 */
aa53509f 1776int wpa_config_update_prio_list(struct wpa_config *config)
6fc6879b
JM
1777{
1778 struct wpa_ssid *ssid;
1779 int ret = 0;
1780
1781 os_free(config->pssid);
1782 config->pssid = NULL;
1783 config->num_prio = 0;
1784
1785 ssid = config->ssid;
1786 while (ssid) {
1787 ssid->pnext = NULL;
1788 if (wpa_config_add_prio_network(config, ssid) < 0)
1789 ret = -1;
1790 ssid = ssid->next;
1791 }
1792
1793 return ret;
1794}
1795
1796
1797#ifdef IEEE8021X_EAPOL
1798static void eap_peer_config_free(struct eap_peer_config *eap)
1799{
1800 os_free(eap->eap_methods);
1801 os_free(eap->identity);
1802 os_free(eap->anonymous_identity);
1803 os_free(eap->password);
1804 os_free(eap->ca_cert);
1805 os_free(eap->ca_path);
1806 os_free(eap->client_cert);
1807 os_free(eap->private_key);
1808 os_free(eap->private_key_passwd);
1809 os_free(eap->dh_file);
1810 os_free(eap->subject_match);
1811 os_free(eap->altsubject_match);
1812 os_free(eap->ca_cert2);
1813 os_free(eap->ca_path2);
1814 os_free(eap->client_cert2);
1815 os_free(eap->private_key2);
1816 os_free(eap->private_key2_passwd);
1817 os_free(eap->dh_file2);
1818 os_free(eap->subject_match2);
1819 os_free(eap->altsubject_match2);
1820 os_free(eap->phase1);
1821 os_free(eap->phase2);
1822 os_free(eap->pcsc);
1823 os_free(eap->pin);
1824 os_free(eap->engine_id);
1825 os_free(eap->key_id);
61ee0f71
DS
1826 os_free(eap->cert_id);
1827 os_free(eap->ca_cert_id);
1828 os_free(eap->key2_id);
1829 os_free(eap->cert2_id);
1830 os_free(eap->ca_cert2_id);
98842d51
CL
1831 os_free(eap->pin2);
1832 os_free(eap->engine2_id);
6fc6879b
JM
1833 os_free(eap->otp);
1834 os_free(eap->pending_req_otp);
1835 os_free(eap->pac_file);
1836 os_free(eap->new_password);
1837}
1838#endif /* IEEE8021X_EAPOL */
1839
1840
1841/**
1842 * wpa_config_free_ssid - Free network/ssid configuration data
1843 * @ssid: Configuration data for the network
1844 *
1845 * This function frees all resources allocated for the network configuration
1846 * data.
1847 */
1848void wpa_config_free_ssid(struct wpa_ssid *ssid)
1849{
1850 os_free(ssid->ssid);
1851 os_free(ssid->passphrase);
9173b16f 1852 os_free(ssid->ext_psk);
6fc6879b
JM
1853#ifdef IEEE8021X_EAPOL
1854 eap_peer_config_free(&ssid->eap);
1855#endif /* IEEE8021X_EAPOL */
1856 os_free(ssid->id_str);
d3a98225 1857 os_free(ssid->scan_freq);
b766a9a2 1858 os_free(ssid->freq_list);
60b94c98 1859 os_free(ssid->bgscan);
fbdcfd57 1860 os_free(ssid->p2p_client_list);
80e8a5ee
BG
1861#ifdef CONFIG_HT_OVERRIDES
1862 os_free(ssid->ht_mcs);
1863#endif /* CONFIG_HT_OVERRIDES */
6fc6879b
JM
1864 os_free(ssid);
1865}
1866
1867
1bb7b8e8
JM
1868void wpa_config_free_cred(struct wpa_cred *cred)
1869{
1870 os_free(cred->realm);
1871 os_free(cred->username);
1872 os_free(cred->password);
1873 os_free(cred->ca_cert);
11e4f46a
JM
1874 os_free(cred->client_cert);
1875 os_free(cred->private_key);
1876 os_free(cred->private_key_passwd);
1bb7b8e8
JM
1877 os_free(cred->imsi);
1878 os_free(cred->milenage);
1879 os_free(cred->domain);
8ca93c59
JM
1880 os_free(cred->eap_method);
1881 os_free(cred->phase1);
1882 os_free(cred->phase2);
1bb7b8e8
JM
1883 os_free(cred);
1884}
1885
1886
6fc6879b
JM
1887/**
1888 * wpa_config_free - Free configuration data
1889 * @config: Configuration data from wpa_config_read()
1890 *
1891 * This function frees all resources allocated for the configuration data by
1892 * wpa_config_read().
1893 */
1894void wpa_config_free(struct wpa_config *config)
1895{
1896#ifndef CONFIG_NO_CONFIG_BLOBS
1897 struct wpa_config_blob *blob, *prevblob;
1898#endif /* CONFIG_NO_CONFIG_BLOBS */
1899 struct wpa_ssid *ssid, *prev = NULL;
1bb7b8e8 1900 struct wpa_cred *cred, *cprev;
e3768e7c 1901
6fc6879b
JM
1902 ssid = config->ssid;
1903 while (ssid) {
1904 prev = ssid;
1905 ssid = ssid->next;
1906 wpa_config_free_ssid(prev);
1907 }
1908
1bb7b8e8
JM
1909 cred = config->cred;
1910 while (cred) {
1911 cprev = cred;
1912 cred = cred->next;
1913 wpa_config_free_cred(cprev);
1914 }
1915
6fc6879b
JM
1916#ifndef CONFIG_NO_CONFIG_BLOBS
1917 blob = config->blobs;
1918 prevblob = NULL;
1919 while (blob) {
1920 prevblob = blob;
1921 blob = blob->next;
1922 wpa_config_free_blob(prevblob);
1923 }
1924#endif /* CONFIG_NO_CONFIG_BLOBS */
1925
71dd3b78 1926 wpabuf_free(config->wps_vendor_ext_m1);
6fc6879b
JM
1927 os_free(config->ctrl_interface);
1928 os_free(config->ctrl_interface_group);
6fc6879b
JM
1929 os_free(config->opensc_engine_path);
1930 os_free(config->pkcs11_engine_path);
1931 os_free(config->pkcs11_module_path);
f64adcd7
JM
1932 os_free(config->pcsc_reader);
1933 os_free(config->pcsc_pin);
6fc6879b 1934 os_free(config->driver_param);
3c0b7aa4
JM
1935 os_free(config->device_name);
1936 os_free(config->manufacturer);
1937 os_free(config->model_name);
1938 os_free(config->model_number);
1939 os_free(config->serial_number);
c0e4dd9e 1940 os_free(config->config_methods);
e3768e7c 1941 os_free(config->p2p_ssid_postfix);
6fc6879b 1942 os_free(config->pssid);
21d996f7 1943 os_free(config->p2p_pref_chan);
b0786fba 1944 os_free(config->autoscan);
3f2c8ba6
JM
1945 wpabuf_free(config->wps_nfc_dh_pubkey);
1946 wpabuf_free(config->wps_nfc_dh_privkey);
1947 wpabuf_free(config->wps_nfc_dev_pw);
306ae225 1948 os_free(config->ext_password_backend);
6fc6879b
JM
1949 os_free(config);
1950}
1951
1952
7c49fdd0
SL
1953/**
1954 * wpa_config_foreach_network - Iterate over each configured network
1955 * @config: Configuration data from wpa_config_read()
1956 * @func: Callback function to process each network
1957 * @arg: Opaque argument to pass to callback function
1958 *
1959 * Iterate over the set of configured networks calling the specified
1960 * function for each item. We guard against callbacks removing the
1961 * supplied network.
1962 */
1963void wpa_config_foreach_network(struct wpa_config *config,
1964 void (*func)(void *, struct wpa_ssid *),
1965 void *arg)
1966{
1967 struct wpa_ssid *ssid, *next;
1968
1969 ssid = config->ssid;
1970 while (ssid) {
1971 next = ssid->next;
1972 func(arg, ssid);
1973 ssid = next;
1974 }
1975}
1976
1977
6fc6879b
JM
1978/**
1979 * wpa_config_get_network - Get configured network based on id
1980 * @config: Configuration data from wpa_config_read()
1981 * @id: Unique network id to search for
1982 * Returns: Network configuration or %NULL if not found
1983 */
1984struct wpa_ssid * wpa_config_get_network(struct wpa_config *config, int id)
1985{
1986 struct wpa_ssid *ssid;
1987
1988 ssid = config->ssid;
1989 while (ssid) {
1990 if (id == ssid->id)
1991 break;
1992 ssid = ssid->next;
1993 }
1994
1995 return ssid;
1996}
1997
1998
1999/**
2000 * wpa_config_add_network - Add a new network with empty configuration
2001 * @config: Configuration data from wpa_config_read()
2002 * Returns: The new network configuration or %NULL if operation failed
2003 */
2004struct wpa_ssid * wpa_config_add_network(struct wpa_config *config)
2005{
2006 int id;
2007 struct wpa_ssid *ssid, *last = NULL;
2008
2009 id = -1;
2010 ssid = config->ssid;
2011 while (ssid) {
2012 if (ssid->id > id)
2013 id = ssid->id;
2014 last = ssid;
2015 ssid = ssid->next;
2016 }
2017 id++;
2018
2019 ssid = os_zalloc(sizeof(*ssid));
2020 if (ssid == NULL)
2021 return NULL;
2022 ssid->id = id;
2023 if (last)
2024 last->next = ssid;
2025 else
2026 config->ssid = ssid;
2027
2028 wpa_config_update_prio_list(config);
2029
2030 return ssid;
2031}
2032
2033
2034/**
2035 * wpa_config_remove_network - Remove a configured network based on id
2036 * @config: Configuration data from wpa_config_read()
2037 * @id: Unique network id to search for
2038 * Returns: 0 on success, or -1 if the network was not found
2039 */
2040int wpa_config_remove_network(struct wpa_config *config, int id)
2041{
2042 struct wpa_ssid *ssid, *prev = NULL;
2043
2044 ssid = config->ssid;
2045 while (ssid) {
2046 if (id == ssid->id)
2047 break;
2048 prev = ssid;
2049 ssid = ssid->next;
2050 }
2051
2052 if (ssid == NULL)
2053 return -1;
2054
2055 if (prev)
2056 prev->next = ssid->next;
2057 else
2058 config->ssid = ssid->next;
2059
2060 wpa_config_update_prio_list(config);
2061 wpa_config_free_ssid(ssid);
2062 return 0;
2063}
2064
2065
2066/**
2067 * wpa_config_set_network_defaults - Set network default values
2068 * @ssid: Pointer to network configuration data
2069 */
2070void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
2071{
2072 ssid->proto = DEFAULT_PROTO;
2073 ssid->pairwise_cipher = DEFAULT_PAIRWISE;
2074 ssid->group_cipher = DEFAULT_GROUP;
2075 ssid->key_mgmt = DEFAULT_KEY_MGMT;
1f6c0ab8 2076 ssid->bg_scan_period = DEFAULT_BG_SCAN_PERIOD;
6fc6879b
JM
2077#ifdef IEEE8021X_EAPOL
2078 ssid->eapol_flags = DEFAULT_EAPOL_FLAGS;
2079 ssid->eap_workaround = DEFAULT_EAP_WORKAROUND;
2080 ssid->eap.fragment_size = DEFAULT_FRAGMENT_SIZE;
2081#endif /* IEEE8021X_EAPOL */
80e8a5ee
BG
2082#ifdef CONFIG_HT_OVERRIDES
2083 ssid->disable_ht = DEFAULT_DISABLE_HT;
2084 ssid->disable_ht40 = DEFAULT_DISABLE_HT40;
2085 ssid->disable_max_amsdu = DEFAULT_DISABLE_MAX_AMSDU;
2086 ssid->ampdu_factor = DEFAULT_AMPDU_FACTOR;
2087 ssid->ampdu_density = DEFAULT_AMPDU_DENSITY;
2088#endif /* CONFIG_HT_OVERRIDES */
6fc6879b
JM
2089}
2090
2091
2092/**
2093 * wpa_config_set - Set a variable in network configuration
2094 * @ssid: Pointer to network configuration data
2095 * @var: Variable name, e.g., "ssid"
2096 * @value: Variable value
2097 * @line: Line number in configuration file or 0 if not used
2098 * Returns: 0 on success, -1 on failure
2099 *
2100 * This function can be used to set network configuration variables based on
2101 * both the configuration file and management interface input. The value
2102 * parameter must be in the same format as the text-based configuration file is
2103 * using. For example, strings are using double quotation marks.
2104 */
2105int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
2106 int line)
2107{
2108 size_t i;
2109 int ret = 0;
2110
2111 if (ssid == NULL || var == NULL || value == NULL)
2112 return -1;
2113
2114 for (i = 0; i < NUM_SSID_FIELDS; i++) {
2115 const struct parse_data *field = &ssid_fields[i];
2116 if (os_strcmp(var, field->name) != 0)
2117 continue;
2118
2119 if (field->parser(field, ssid, line, value)) {
2120 if (line) {
2121 wpa_printf(MSG_ERROR, "Line %d: failed to "
2122 "parse %s '%s'.", line, var, value);
2123 }
2124 ret = -1;
2125 }
2126 break;
2127 }
2128 if (i == NUM_SSID_FIELDS) {
2129 if (line) {
2130 wpa_printf(MSG_ERROR, "Line %d: unknown network field "
2131 "'%s'.", line, var);
2132 }
2133 ret = -1;
2134 }
2135
2136 return ret;
2137}
2138
2139
67e1b984
JM
2140int wpa_config_set_quoted(struct wpa_ssid *ssid, const char *var,
2141 const char *value)
2142{
2143 size_t len;
2144 char *buf;
2145 int ret;
2146
2147 len = os_strlen(value);
2148 buf = os_malloc(len + 3);
2149 if (buf == NULL)
2150 return -1;
2151 buf[0] = '"';
2152 os_memcpy(buf + 1, value, len);
2153 buf[len + 1] = '"';
2154 buf[len + 2] = '\0';
2155 ret = wpa_config_set(ssid, var, buf, 0);
2156 os_free(buf);
2157 return ret;
2158}
2159
2160
3d3d3056
WS
2161/**
2162 * wpa_config_get_all - Get all options from network configuration
2163 * @ssid: Pointer to network configuration data
2164 * @get_keys: Determines if keys/passwords will be included in returned list
d1c8ac88 2165 * (if they may be exported)
3d3d3056
WS
2166 * Returns: %NULL terminated list of all set keys and their values in the form
2167 * of [key1, val1, key2, val2, ... , NULL]
2168 *
2169 * This function can be used to get list of all configured network properties.
2170 * The caller is responsible for freeing the returned list and all its
2171 * elements.
2172 */
2173char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys)
2174{
2175 const struct parse_data *field;
2176 char *key, *value;
2177 size_t i;
2178 char **props;
2179 int fields_num;
2180
d1c8ac88
JB
2181 get_keys = get_keys && ssid->export_keys;
2182
3d3d3056
WS
2183 props = os_zalloc(sizeof(char *) * ((2 * NUM_SSID_FIELDS) + 1));
2184 if (!props)
2185 return NULL;
2186
2187 fields_num = 0;
2188 for (i = 0; i < NUM_SSID_FIELDS; i++) {
2189 field = &ssid_fields[i];
2190 if (field->key_data && !get_keys)
2191 continue;
2192 value = field->writer(field, ssid);
04746865 2193 if (value == NULL)
3d3d3056 2194 continue;
04746865
JM
2195 if (os_strlen(value) == 0) {
2196 os_free(value);
2197 continue;
2198 }
3d3d3056
WS
2199
2200 key = os_strdup(field->name);
04746865
JM
2201 if (key == NULL) {
2202 os_free(value);
3d3d3056 2203 goto err;
04746865 2204 }
3d3d3056
WS
2205
2206 props[fields_num * 2] = key;
2207 props[fields_num * 2 + 1] = value;
2208
2209 fields_num++;
2210 }
2211
2212 return props;
2213
2214err:
2215 value = *props;
2216 while (value)
2217 os_free(value++);
2218 os_free(props);
2219 return NULL;
2220}
2221
2222
6fc6879b
JM
2223#ifndef NO_CONFIG_WRITE
2224/**
2225 * wpa_config_get - Get a variable in network configuration
2226 * @ssid: Pointer to network configuration data
2227 * @var: Variable name, e.g., "ssid"
2228 * Returns: Value of the variable or %NULL on failure
2229 *
2230 * This function can be used to get network configuration variables. The
2231 * returned value is a copy of the configuration variable in text format, i.e,.
2232 * the same format that the text-based configuration file and wpa_config_set()
2233 * are using for the value. The caller is responsible for freeing the returned
2234 * value.
2235 */
2236char * wpa_config_get(struct wpa_ssid *ssid, const char *var)
2237{
2238 size_t i;
2239
2240 if (ssid == NULL || var == NULL)
2241 return NULL;
2242
2243 for (i = 0; i < NUM_SSID_FIELDS; i++) {
2244 const struct parse_data *field = &ssid_fields[i];
2245 if (os_strcmp(var, field->name) == 0)
2246 return field->writer(field, ssid);
2247 }
2248
2249 return NULL;
2250}
2251
2252
2253/**
2254 * wpa_config_get_no_key - Get a variable in network configuration (no keys)
2255 * @ssid: Pointer to network configuration data
2256 * @var: Variable name, e.g., "ssid"
2257 * Returns: Value of the variable or %NULL on failure
2258 *
2259 * This function can be used to get network configuration variable like
2260 * wpa_config_get(). The only difference is that this functions does not expose
2261 * key/password material from the configuration. In case a key/password field
2262 * is requested, the returned value is an empty string or %NULL if the variable
2263 * is not set or "*" if the variable is set (regardless of its value). The
2264 * returned value is a copy of the configuration variable in text format, i.e,.
2265 * the same format that the text-based configuration file and wpa_config_set()
2266 * are using for the value. The caller is responsible for freeing the returned
2267 * value.
2268 */
2269char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var)
2270{
2271 size_t i;
2272
2273 if (ssid == NULL || var == NULL)
2274 return NULL;
2275
2276 for (i = 0; i < NUM_SSID_FIELDS; i++) {
2277 const struct parse_data *field = &ssid_fields[i];
2278 if (os_strcmp(var, field->name) == 0) {
2279 char *res = field->writer(field, ssid);
2280 if (field->key_data) {
2281 if (res && res[0]) {
2282 wpa_printf(MSG_DEBUG, "Do not allow "
2283 "key_data field to be "
2284 "exposed");
2285 os_free(res);
2286 return os_strdup("*");
2287 }
2288
2289 os_free(res);
2290 return NULL;
2291 }
2292 return res;
2293 }
2294 }
2295
2296 return NULL;
2297}
2298#endif /* NO_CONFIG_WRITE */
2299
2300
2301/**
2302 * wpa_config_update_psk - Update WPA PSK based on passphrase and SSID
2303 * @ssid: Pointer to network configuration data
2304 *
2305 * This function must be called to update WPA PSK when either SSID or the
2306 * passphrase has changed for the network configuration.
2307 */
2308void wpa_config_update_psk(struct wpa_ssid *ssid)
2309{
2310#ifndef CONFIG_NO_PBKDF2
2311 pbkdf2_sha1(ssid->passphrase,
2312 (char *) ssid->ssid, ssid->ssid_len, 4096,
2313 ssid->psk, PMK_LEN);
2314 wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
2315 ssid->psk, PMK_LEN);
2316 ssid->psk_set = 1;
2317#endif /* CONFIG_NO_PBKDF2 */
2318}
2319
2320
1bb7b8e8
JM
2321int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
2322 const char *value, int line)
2323{
2324 char *val;
2325 size_t len;
2326
1a712d2f
JM
2327 if (os_strcmp(var, "priority") == 0) {
2328 cred->priority = atoi(value);
2329 return 0;
2330 }
2331
d7b01abd
JM
2332 if (os_strcmp(var, "pcsc") == 0) {
2333 cred->pcsc = atoi(value);
2334 return 0;
2335 }
2336
8ca93c59
JM
2337 if (os_strcmp(var, "eap") == 0) {
2338 struct eap_method_type method;
2339 method.method = eap_peer_get_type(value, &method.vendor);
2340 if (method.vendor == EAP_VENDOR_IETF &&
2341 method.method == EAP_TYPE_NONE) {
2342 wpa_printf(MSG_ERROR, "Line %d: unknown EAP type '%s' "
2343 "for a credential", line, value);
2344 return -1;
2345 }
2346 os_free(cred->eap_method);
2347 cred->eap_method = os_malloc(sizeof(*cred->eap_method));
2348 if (cred->eap_method == NULL)
2349 return -1;
2350 os_memcpy(cred->eap_method, &method, sizeof(method));
2351 return 0;
2352 }
2353
02af9c90
JM
2354 if (os_strcmp(var, "password") == 0 &&
2355 os_strncmp(value, "ext:", 4) == 0) {
2356 os_free(cred->password);
2357 cred->password = os_strdup(value);
2358 cred->ext_password = 1;
2359 return 0;
2360 }
2361
1bb7b8e8 2362 val = wpa_config_parse_string(value, &len);
7d86e537
JM
2363 if (val == NULL) {
2364 wpa_printf(MSG_ERROR, "Line %d: invalid field '%s' string "
2365 "value '%s'.", line, var, value);
1bb7b8e8 2366 return -1;
7d86e537 2367 }
1bb7b8e8
JM
2368
2369 if (os_strcmp(var, "realm") == 0) {
2370 os_free(cred->realm);
2371 cred->realm = val;
2372 return 0;
2373 }
2374
2375 if (os_strcmp(var, "username") == 0) {
2376 os_free(cred->username);
2377 cred->username = val;
2378 return 0;
2379 }
2380
2381 if (os_strcmp(var, "password") == 0) {
2382 os_free(cred->password);
2383 cred->password = val;
02af9c90 2384 cred->ext_password = 0;
1bb7b8e8
JM
2385 return 0;
2386 }
2387
2388 if (os_strcmp(var, "ca_cert") == 0) {
2389 os_free(cred->ca_cert);
2390 cred->ca_cert = val;
2391 return 0;
2392 }
2393
11e4f46a
JM
2394 if (os_strcmp(var, "client_cert") == 0) {
2395 os_free(cred->client_cert);
2396 cred->client_cert = val;
2397 return 0;
2398 }
2399
2400 if (os_strcmp(var, "private_key") == 0) {
2401 os_free(cred->private_key);
2402 cred->private_key = val;
2403 return 0;
2404 }
2405
2406 if (os_strcmp(var, "private_key_passwd") == 0) {
2407 os_free(cred->private_key_passwd);
2408 cred->private_key_passwd = val;
2409 return 0;
2410 }
2411
1bb7b8e8
JM
2412 if (os_strcmp(var, "imsi") == 0) {
2413 os_free(cred->imsi);
2414 cred->imsi = val;
2415 return 0;
2416 }
2417
2418 if (os_strcmp(var, "milenage") == 0) {
2419 os_free(cred->milenage);
2420 cred->milenage = val;
2421 return 0;
2422 }
2423
2424 if (os_strcmp(var, "domain") == 0) {
2425 os_free(cred->domain);
2426 cred->domain = val;
2427 return 0;
2428 }
2429
8ca93c59
JM
2430 if (os_strcmp(var, "phase1") == 0) {
2431 os_free(cred->phase1);
2432 cred->phase1 = val;
2433 return 0;
2434 }
2435
2436 if (os_strcmp(var, "phase2") == 0) {
2437 os_free(cred->phase2);
2438 cred->phase2 = val;
2439 return 0;
2440 }
2441
955567bc
JM
2442 if (os_strcmp(var, "roaming_consortium") == 0) {
2443 if (len < 3 || len > sizeof(cred->roaming_consortium)) {
2444 wpa_printf(MSG_ERROR, "Line %d: invalid "
2445 "roaming_consortium length %d (3..15 "
2446 "expected)", line, (int) len);
2447 os_free(val);
2448 return -1;
2449 }
2450 os_memcpy(cred->roaming_consortium, val, len);
2451 cred->roaming_consortium_len = len;
2452 os_free(val);
2453 return 0;
2454 }
2455
1bb7b8e8
JM
2456 if (line) {
2457 wpa_printf(MSG_ERROR, "Line %d: unknown cred field '%s'.",
2458 line, var);
2459 }
2460
f4b2d69b
JM
2461 os_free(val);
2462
1bb7b8e8
JM
2463 return -1;
2464}
2465
2466
d94c9ee6
JM
2467struct wpa_cred * wpa_config_get_cred(struct wpa_config *config, int id)
2468{
2469 struct wpa_cred *cred;
2470
2471 cred = config->cred;
2472 while (cred) {
2473 if (id == cred->id)
2474 break;
2475 cred = cred->next;
2476 }
2477
2478 return cred;
2479}
2480
2481
2482struct wpa_cred * wpa_config_add_cred(struct wpa_config *config)
2483{
2484 int id;
2485 struct wpa_cred *cred, *last = NULL;
2486
2487 id = -1;
2488 cred = config->cred;
2489 while (cred) {
2490 if (cred->id > id)
2491 id = cred->id;
2492 last = cred;
2493 cred = cred->next;
2494 }
2495 id++;
2496
2497 cred = os_zalloc(sizeof(*cred));
2498 if (cred == NULL)
2499 return NULL;
2500 cred->id = id;
2501 if (last)
2502 last->next = cred;
2503 else
2504 config->cred = cred;
2505
2506 return cred;
2507}
2508
2509
2510int wpa_config_remove_cred(struct wpa_config *config, int id)
2511{
2512 struct wpa_cred *cred, *prev = NULL;
2513
2514 cred = config->cred;
2515 while (cred) {
2516 if (id == cred->id)
2517 break;
2518 prev = cred;
2519 cred = cred->next;
2520 }
2521
2522 if (cred == NULL)
2523 return -1;
2524
2525 if (prev)
2526 prev->next = cred->next;
2527 else
2528 config->cred = cred->next;
2529
2530 wpa_config_free_cred(cred);
2531 return 0;
2532}
2533
2534
6fc6879b
JM
2535#ifndef CONFIG_NO_CONFIG_BLOBS
2536/**
2537 * wpa_config_get_blob - Get a named configuration blob
2538 * @config: Configuration data from wpa_config_read()
2539 * @name: Name of the blob
2540 * Returns: Pointer to blob data or %NULL if not found
2541 */
2542const struct wpa_config_blob * wpa_config_get_blob(struct wpa_config *config,
2543 const char *name)
2544{
2545 struct wpa_config_blob *blob = config->blobs;
2546
2547 while (blob) {
2548 if (os_strcmp(blob->name, name) == 0)
2549 return blob;
2550 blob = blob->next;
2551 }
2552 return NULL;
2553}
2554
2555
2556/**
2557 * wpa_config_set_blob - Set or add a named configuration blob
2558 * @config: Configuration data from wpa_config_read()
2559 * @blob: New value for the blob
2560 *
2561 * Adds a new configuration blob or replaces the current value of an existing
2562 * blob.
2563 */
2564void wpa_config_set_blob(struct wpa_config *config,
2565 struct wpa_config_blob *blob)
2566{
2567 wpa_config_remove_blob(config, blob->name);
2568 blob->next = config->blobs;
2569 config->blobs = blob;
2570}
2571
2572
2573/**
2574 * wpa_config_free_blob - Free blob data
2575 * @blob: Pointer to blob to be freed
2576 */
2577void wpa_config_free_blob(struct wpa_config_blob *blob)
2578{
2579 if (blob) {
2580 os_free(blob->name);
2581 os_free(blob->data);
2582 os_free(blob);
2583 }
2584}
2585
2586
2587/**
2588 * wpa_config_remove_blob - Remove a named configuration blob
2589 * @config: Configuration data from wpa_config_read()
2590 * @name: Name of the blob to remove
2591 * Returns: 0 if blob was removed or -1 if blob was not found
2592 */
2593int wpa_config_remove_blob(struct wpa_config *config, const char *name)
2594{
2595 struct wpa_config_blob *pos = config->blobs, *prev = NULL;
2596
2597 while (pos) {
2598 if (os_strcmp(pos->name, name) == 0) {
2599 if (prev)
2600 prev->next = pos->next;
2601 else
2602 config->blobs = pos->next;
2603 wpa_config_free_blob(pos);
2604 return 0;
2605 }
2606 prev = pos;
2607 pos = pos->next;
2608 }
2609
2610 return -1;
2611}
2612#endif /* CONFIG_NO_CONFIG_BLOBS */
2613
2614
2615/**
2616 * wpa_config_alloc_empty - Allocate an empty configuration
2617 * @ctrl_interface: Control interface parameters, e.g., path to UNIX domain
2618 * socket
2619 * @driver_param: Driver parameters
2620 * Returns: Pointer to allocated configuration data or %NULL on failure
2621 */
2622struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
2623 const char *driver_param)
2624{
2625 struct wpa_config *config;
2626
2627 config = os_zalloc(sizeof(*config));
2628 if (config == NULL)
2629 return NULL;
2630 config->eapol_version = DEFAULT_EAPOL_VERSION;
2631 config->ap_scan = DEFAULT_AP_SCAN;
2632 config->fast_reauth = DEFAULT_FAST_REAUTH;
e3768e7c 2633 config->p2p_go_intent = DEFAULT_P2P_GO_INTENT;
0f66abd2 2634 config->p2p_intra_bss = DEFAULT_P2P_INTRA_BSS;
c9c38b09 2635 config->bss_max_count = DEFAULT_BSS_MAX_COUNT;
78633c37
SL
2636 config->bss_expiration_age = DEFAULT_BSS_EXPIRATION_AGE;
2637 config->bss_expiration_scan_count = DEFAULT_BSS_EXPIRATION_SCAN_COUNT;
dae608d5 2638 config->max_num_sta = DEFAULT_MAX_NUM_STA;
11540c0b 2639 config->access_network_type = DEFAULT_ACCESS_NETWORK_TYPE;
6fc6879b
JM
2640
2641 if (ctrl_interface)
2642 config->ctrl_interface = os_strdup(ctrl_interface);
2643 if (driver_param)
2644 config->driver_param = os_strdup(driver_param);
2645
2646 return config;
2647}
2648
2649
2650#ifndef CONFIG_NO_STDOUT_DEBUG
2651/**
2652 * wpa_config_debug_dump_networks - Debug dump of configured networks
2653 * @config: Configuration data from wpa_config_read()
2654 */
2655void wpa_config_debug_dump_networks(struct wpa_config *config)
2656{
2657 int prio;
2658 struct wpa_ssid *ssid;
2659
2660 for (prio = 0; prio < config->num_prio; prio++) {
2661 ssid = config->pssid[prio];
2662 wpa_printf(MSG_DEBUG, "Priority group %d",
2663 ssid->priority);
2664 while (ssid) {
2665 wpa_printf(MSG_DEBUG, " id=%d ssid='%s'",
2666 ssid->id,
2667 wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
2668 ssid = ssid->pnext;
2669 }
2670 }
2671}
2672#endif /* CONFIG_NO_STDOUT_DEBUG */
121adf9c
JM
2673
2674
2675struct global_parse_data {
2676 char *name;
2677 int (*parser)(const struct global_parse_data *data,
2678 struct wpa_config *config, int line, const char *value);
2679 void *param1, *param2, *param3;
1d47214a 2680 unsigned int changed_flag;
121adf9c
JM
2681};
2682
2683
2684static int wpa_global_config_parse_int(const struct global_parse_data *data,
2685 struct wpa_config *config, int line,
2686 const char *pos)
2687{
2688 int *dst;
2689 dst = (int *) (((u8 *) config) + (long) data->param1);
2690 *dst = atoi(pos);
2691 wpa_printf(MSG_DEBUG, "%s=%d", data->name, *dst);
2692
2693 if (data->param2 && *dst < (long) data->param2) {
2694 wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d "
2695 "min_value=%ld)", line, data->name, *dst,
2696 (long) data->param2);
2697 *dst = (long) data->param2;
2698 return -1;
2699 }
2700
2701 if (data->param3 && *dst > (long) data->param3) {
2702 wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d "
2703 "max_value=%ld)", line, data->name, *dst,
2704 (long) data->param3);
2705 *dst = (long) data->param3;
2706 return -1;
2707 }
2708
2709 return 0;
2710}
2711
2712
2713static int wpa_global_config_parse_str(const struct global_parse_data *data,
2714 struct wpa_config *config, int line,
2715 const char *pos)
2716{
2717 size_t len;
2718 char **dst, *tmp;
2719
2720 len = os_strlen(pos);
2721 if (data->param2 && len < (size_t) data->param2) {
2722 wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu "
2723 "min_len=%ld)", line, data->name,
2724 (unsigned long) len, (long) data->param2);
2725 return -1;
2726 }
2727
2728 if (data->param3 && len > (size_t) data->param3) {
2729 wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu "
2730 "max_len=%ld)", line, data->name,
2731 (unsigned long) len, (long) data->param3);
2732 return -1;
2733 }
2734
2735 tmp = os_strdup(pos);
2736 if (tmp == NULL)
2737 return -1;
2738
2739 dst = (char **) (((u8 *) config) + (long) data->param1);
2740 os_free(*dst);
2741 *dst = tmp;
2742 wpa_printf(MSG_DEBUG, "%s='%s'", data->name, *dst);
2743
2744 return 0;
2745}
2746
2747
3f2c8ba6
JM
2748static int wpa_global_config_parse_bin(const struct global_parse_data *data,
2749 struct wpa_config *config, int line,
2750 const char *pos)
2751{
2752 size_t len;
2753 struct wpabuf **dst, *tmp;
2754
2755 len = os_strlen(pos);
2756 if (len & 0x01)
2757 return -1;
2758
2759 tmp = wpabuf_alloc(len / 2);
2760 if (tmp == NULL)
2761 return -1;
2762
2763 if (hexstr2bin(pos, wpabuf_put(tmp, len / 2), len / 2)) {
2764 wpabuf_free(tmp);
2765 return -1;
2766 }
2767
2768 dst = (struct wpabuf **) (((u8 *) config) + (long) data->param1);
2769 wpabuf_free(*dst);
2770 *dst = tmp;
2771 wpa_printf(MSG_DEBUG, "%s", data->name);
2772
2773 return 0;
2774}
2775
2776
121adf9c
JM
2777static int wpa_config_process_country(const struct global_parse_data *data,
2778 struct wpa_config *config, int line,
2779 const char *pos)
2780{
2781 if (!pos[0] || !pos[1]) {
2782 wpa_printf(MSG_DEBUG, "Invalid country set");
2783 return -1;
2784 }
2785 config->country[0] = pos[0];
2786 config->country[1] = pos[1];
2787 wpa_printf(MSG_DEBUG, "country='%c%c'",
2788 config->country[0], config->country[1]);
2789 return 0;
2790}
2791
2792
2793static int wpa_config_process_load_dynamic_eap(
2794 const struct global_parse_data *data, struct wpa_config *config,
2795 int line, const char *so)
2796{
2797 int ret;
2798 wpa_printf(MSG_DEBUG, "load_dynamic_eap=%s", so);
2799 ret = eap_peer_method_load(so);
2800 if (ret == -2) {
2801 wpa_printf(MSG_DEBUG, "This EAP type was already loaded - not "
2802 "reloading.");
2803 } else if (ret) {
2804 wpa_printf(MSG_ERROR, "Line %d: Failed to load dynamic EAP "
2805 "method '%s'.", line, so);
2806 return -1;
2807 }
2808
2809 return 0;
2810}
2811
2812
2813#ifdef CONFIG_WPS
2814
2815static int wpa_config_process_uuid(const struct global_parse_data *data,
2816 struct wpa_config *config, int line,
2817 const char *pos)
2818{
2819 char buf[40];
2820 if (uuid_str2bin(pos, config->uuid)) {
2821 wpa_printf(MSG_ERROR, "Line %d: invalid UUID", line);
2822 return -1;
2823 }
2824 uuid_bin2str(config->uuid, buf, sizeof(buf));
2825 wpa_printf(MSG_DEBUG, "uuid=%s", buf);
2826 return 0;
2827}
2828
2829
2f646b6e
JB
2830static int wpa_config_process_device_type(
2831 const struct global_parse_data *data,
2832 struct wpa_config *config, int line, const char *pos)
2833{
2834 return wps_dev_type_str2bin(pos, config->device_type);
2835}
2836
2837
121adf9c
JM
2838static int wpa_config_process_os_version(const struct global_parse_data *data,
2839 struct wpa_config *config, int line,
2840 const char *pos)
2841{
2842 if (hexstr2bin(pos, config->os_version, 4)) {
2843 wpa_printf(MSG_ERROR, "Line %d: invalid os_version", line);
2844 return -1;
2845 }
2846 wpa_printf(MSG_DEBUG, "os_version=%08x",
2847 WPA_GET_BE32(config->os_version));
2848 return 0;
2849}
2850
71dd3b78
AS
2851
2852static int wpa_config_process_wps_vendor_ext_m1(
2853 const struct global_parse_data *data,
2854 struct wpa_config *config, int line, const char *pos)
2855{
2856 struct wpabuf *tmp;
2857 int len = os_strlen(pos) / 2;
2858 u8 *p;
2859
2860 if (!len) {
2861 wpa_printf(MSG_ERROR, "Line %d: "
2862 "invalid wps_vendor_ext_m1", line);
2863 return -1;
2864 }
2865
2866 tmp = wpabuf_alloc(len);
2867 if (tmp) {
2868 p = wpabuf_put(tmp, len);
2869
2870 if (hexstr2bin(pos, p, len)) {
2871 wpa_printf(MSG_ERROR, "Line %d: "
2872 "invalid wps_vendor_ext_m1", line);
2873 wpabuf_free(tmp);
2874 return -1;
2875 }
2876
2877 wpabuf_free(config->wps_vendor_ext_m1);
2878 config->wps_vendor_ext_m1 = tmp;
2879 } else {
2880 wpa_printf(MSG_ERROR, "Can not allocate "
2881 "memory for wps_vendor_ext_m1");
2882 return -1;
2883 }
2884
2885 return 0;
2886}
2887
121adf9c
JM
2888#endif /* CONFIG_WPS */
2889
e3768e7c
JM
2890#ifdef CONFIG_P2P
2891static int wpa_config_process_sec_device_type(
2892 const struct global_parse_data *data,
2893 struct wpa_config *config, int line, const char *pos)
2894{
2895 int idx;
2896
2f646b6e 2897 if (config->num_sec_device_types >= MAX_SEC_DEVICE_TYPES) {
e3768e7c
JM
2898 wpa_printf(MSG_ERROR, "Line %d: too many sec_device_type "
2899 "items", line);
2900 return -1;
2901 }
2902
2f646b6e
JB
2903 idx = config->num_sec_device_types;
2904
2905 if (wps_dev_type_str2bin(pos, config->sec_device_type[idx]))
e3768e7c 2906 return -1;
2f646b6e
JB
2907
2908 config->num_sec_device_types++;
e3768e7c
JM
2909 return 0;
2910}
21d996f7
JM
2911
2912
2913static int wpa_config_process_p2p_pref_chan(
2914 const struct global_parse_data *data,
2915 struct wpa_config *config, int line, const char *pos)
2916{
2917 struct p2p_channel *pref = NULL, *n;
2918 unsigned int num = 0;
2919 const char *pos2;
2920 u8 op_class, chan;
2921
2922 /* format: class:chan,class:chan,... */
2923
2924 while (*pos) {
2925 op_class = atoi(pos);
2926 pos2 = os_strchr(pos, ':');
2927 if (pos2 == NULL)
2928 goto fail;
2929 pos2++;
2930 chan = atoi(pos2);
2931
2932 n = os_realloc(pref, (num + 1) * sizeof(struct p2p_channel));
2933 if (n == NULL)
2934 goto fail;
2935 pref = n;
2936 pref[num].op_class = op_class;
2937 pref[num].chan = chan;
2938 num++;
2939
2940 pos = os_strchr(pos2, ',');
2941 if (pos == NULL)
2942 break;
2943 pos++;
2944 }
2945
2946 os_free(config->p2p_pref_chan);
2947 config->p2p_pref_chan = pref;
2948 config->num_p2p_pref_chan = num;
2949 wpa_hexdump(MSG_DEBUG, "P2P: Preferred class/channel pairs",
2950 (u8 *) config->p2p_pref_chan,
2951 config->num_p2p_pref_chan * sizeof(struct p2p_channel));
2952
2953 return 0;
2954
2955fail:
2956 os_free(pref);
2957 wpa_printf(MSG_ERROR, "Line %d: Invalid p2p_pref_chan list", line);
2958 return -1;
2959}
e3768e7c
JM
2960#endif /* CONFIG_P2P */
2961
121adf9c 2962
46ee0427
JM
2963static int wpa_config_process_hessid(
2964 const struct global_parse_data *data,
2965 struct wpa_config *config, int line, const char *pos)
2966{
2967 if (hwaddr_aton2(pos, config->hessid) < 0) {
2968 wpa_printf(MSG_ERROR, "Line %d: Invalid hessid '%s'",
2969 line, pos);
2970 return -1;
2971 }
2972
2973 return 0;
2974}
2975
2976
121adf9c
JM
2977#ifdef OFFSET
2978#undef OFFSET
2979#endif /* OFFSET */
2980/* OFFSET: Get offset of a variable within the wpa_config structure */
2981#define OFFSET(v) ((void *) &((struct wpa_config *) 0)->v)
2982
2983#define FUNC(f) #f, wpa_config_process_ ## f, OFFSET(f), NULL, NULL
2984#define FUNC_NO_VAR(f) #f, wpa_config_process_ ## f, NULL, NULL, NULL
2985#define _INT(f) #f, wpa_global_config_parse_int, OFFSET(f)
2986#define INT(f) _INT(f), NULL, NULL
2987#define INT_RANGE(f, min, max) _INT(f), (void *) min, (void *) max
2988#define _STR(f) #f, wpa_global_config_parse_str, OFFSET(f)
2989#define STR(f) _STR(f), NULL, NULL
2990#define STR_RANGE(f, min, max) _STR(f), (void *) min, (void *) max
3f2c8ba6 2991#define BIN(f) #f, wpa_global_config_parse_bin, OFFSET(f), NULL, NULL
121adf9c
JM
2992
2993static const struct global_parse_data global_fields[] = {
2994#ifdef CONFIG_CTRL_IFACE
1d47214a
JM
2995 { STR(ctrl_interface), 0 },
2996 { STR(ctrl_interface_group), 0 } /* deprecated */,
121adf9c 2997#endif /* CONFIG_CTRL_IFACE */
1d47214a
JM
2998 { INT_RANGE(eapol_version, 1, 2), 0 },
2999 { INT(ap_scan), 0 },
54ddd743 3000 { INT(disable_scan_offload), 0 },
1d47214a
JM
3001 { INT(fast_reauth), 0 },
3002 { STR(opensc_engine_path), 0 },
3003 { STR(pkcs11_engine_path), 0 },
3004 { STR(pkcs11_module_path), 0 },
f64adcd7
JM
3005 { STR(pcsc_reader), 0 },
3006 { STR(pcsc_pin), 0 },
1d47214a
JM
3007 { STR(driver_param), 0 },
3008 { INT(dot11RSNAConfigPMKLifetime), 0 },
3009 { INT(dot11RSNAConfigPMKReauthThreshold), 0 },
3010 { INT(dot11RSNAConfigSATimeout), 0 },
121adf9c 3011#ifndef CONFIG_NO_CONFIG_WRITE
1d47214a 3012 { INT(update_config), 0 },
121adf9c 3013#endif /* CONFIG_NO_CONFIG_WRITE */
1d47214a 3014 { FUNC_NO_VAR(load_dynamic_eap), 0 },
121adf9c 3015#ifdef CONFIG_WPS
1d47214a
JM
3016 { FUNC(uuid), CFG_CHANGED_UUID },
3017 { STR_RANGE(device_name, 0, 32), CFG_CHANGED_DEVICE_NAME },
1c9cb49f
JM
3018 { STR_RANGE(manufacturer, 0, 64), CFG_CHANGED_WPS_STRING },
3019 { STR_RANGE(model_name, 0, 32), CFG_CHANGED_WPS_STRING },
3020 { STR_RANGE(model_number, 0, 32), CFG_CHANGED_WPS_STRING },
3021 { STR_RANGE(serial_number, 0, 32), CFG_CHANGED_WPS_STRING },
2f646b6e 3022 { FUNC(device_type), CFG_CHANGED_DEVICE_TYPE },
1d47214a
JM
3023 { FUNC(os_version), CFG_CHANGED_OS_VERSION },
3024 { STR(config_methods), CFG_CHANGED_CONFIG_METHODS },
3025 { INT_RANGE(wps_cred_processing, 0, 2), 0 },
71dd3b78 3026 { FUNC(wps_vendor_ext_m1), CFG_CHANGED_VENDOR_EXTENSION },
121adf9c 3027#endif /* CONFIG_WPS */
e3768e7c
JM
3028#ifdef CONFIG_P2P
3029 { FUNC(sec_device_type), CFG_CHANGED_SEC_DEVICE_TYPE },
3030 { INT(p2p_listen_reg_class), 0 },
3031 { INT(p2p_listen_channel), 0 },
3032 { INT(p2p_oper_reg_class), 0 },
3033 { INT(p2p_oper_channel), 0 },
3034 { INT_RANGE(p2p_go_intent, 0, 15), 0 },
3035 { STR(p2p_ssid_postfix), CFG_CHANGED_P2P_SSID_POSTFIX },
3036 { INT_RANGE(persistent_reconnect, 0, 1), 0 },
0f66abd2 3037 { INT_RANGE(p2p_intra_bss, 0, 1), CFG_CHANGED_P2P_INTRA_BSS },
3071e181 3038 { INT(p2p_group_idle), 0 },
21d996f7 3039 { FUNC(p2p_pref_chan), CFG_CHANGED_P2P_PREF_CHAN },
e3768e7c 3040#endif /* CONFIG_P2P */
1d47214a
JM
3041 { FUNC(country), CFG_CHANGED_COUNTRY },
3042 { INT(bss_max_count), 0 },
78633c37
SL
3043 { INT(bss_expiration_age), 0 },
3044 { INT(bss_expiration_scan_count), 0 },
dae608d5 3045 { INT_RANGE(filter_ssids, 0, 1), 0 },
bf8d6d24 3046 { INT_RANGE(filter_rssi, -100, 0), 0 },
0d7e5a3a 3047 { INT(max_num_sta), 0 },
46ee0427 3048 { INT_RANGE(disassoc_low_ack, 0, 1), 0 },
66aadbd7
JK
3049#ifdef CONFIG_HS20
3050 { INT_RANGE(hs20, 0, 1), 0 },
3051#endif /* CONFIG_HS20 */
46ee0427 3052 { INT_RANGE(interworking, 0, 1), 0 },
11540c0b 3053 { FUNC(hessid), 0 },
1298c145 3054 { INT_RANGE(access_network_type, 0, 15), 0 },
b0786fba 3055 { INT_RANGE(pbc_in_m1, 0, 1), 0 },
3f2c8ba6
JM
3056 { STR(autoscan), 0 },
3057 { INT_RANGE(wps_nfc_dev_pw_id, 0x10, 0xffff), 0 },
3058 { BIN(wps_nfc_dh_pubkey), 0 },
3059 { BIN(wps_nfc_dh_privkey), 0 },
306ae225
JM
3060 { BIN(wps_nfc_dev_pw), 0 },
3061 { STR(ext_password_backend), CFG_CHANGED_EXT_PW_BACKEND }
121adf9c
JM
3062};
3063
3064#undef FUNC
3065#undef _INT
3066#undef INT
3067#undef INT_RANGE
3068#undef _STR
3069#undef STR
3070#undef STR_RANGE
3f2c8ba6 3071#undef BIN
121adf9c
JM
3072#define NUM_GLOBAL_FIELDS (sizeof(global_fields) / sizeof(global_fields[0]))
3073
3074
3075int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
3076{
3077 size_t i;
3078 int ret = 0;
3079
3080 for (i = 0; i < NUM_GLOBAL_FIELDS; i++) {
3081 const struct global_parse_data *field = &global_fields[i];
3082 size_t flen = os_strlen(field->name);
3083 if (os_strncmp(pos, field->name, flen) != 0 ||
3084 pos[flen] != '=')
3085 continue;
3086
3087 if (field->parser(field, config, line, pos + flen + 1)) {
3088 wpa_printf(MSG_ERROR, "Line %d: failed to "
3089 "parse '%s'.", line, pos);
3090 ret = -1;
3091 }
1d47214a 3092 config->changed_parameters |= field->changed_flag;
121adf9c
JM
3093 break;
3094 }
3095 if (i == NUM_GLOBAL_FIELDS) {
1d47214a
JM
3096 if (line < 0)
3097 return -1;
121adf9c
JM
3098 wpa_printf(MSG_ERROR, "Line %d: unknown global field '%s'.",
3099 line, pos);
3100 ret = -1;
3101 }
3102
3103 return ret;
3104}