1189251Ssam/*
2189251Ssam * WPA Supplicant / Configuration parser and common functions
3189251Ssam * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
4189251Ssam *
5189251Ssam * This program is free software; you can redistribute it and/or modify
6189251Ssam * it under the terms of the GNU General Public License version 2 as
7189251Ssam * published by the Free Software Foundation.
8189251Ssam *
9189251Ssam * Alternatively, this software may be distributed under the terms of BSD
10189251Ssam * license.
11189251Ssam *
12189251Ssam * See README and COPYING for more details.
13189251Ssam */
14189251Ssam
15189251Ssam#include "includes.h"
16189251Ssam
17189251Ssam#include "common.h"
18214734Srpaulo#include "crypto/sha1.h"
19214734Srpaulo#include "rsn_supp/wpa.h"
20189251Ssam#include "eap_peer/eap.h"
21189251Ssam#include "config.h"
22189251Ssam
23189251Ssam
24189251Ssam#if !defined(CONFIG_CTRL_IFACE) && defined(CONFIG_NO_CONFIG_WRITE)
25189251Ssam#define NO_CONFIG_WRITE
26189251Ssam#endif
27189251Ssam
28189251Ssam/*
29189251Ssam * Structure for network configuration parsing. This data is used to implement
30189251Ssam * a generic parser for each network block variable. The table of configuration
31189251Ssam * variables is defined below in this file (ssid_fields[]).
32189251Ssam */
33189251Ssamstruct parse_data {
34189251Ssam	/* Configuration variable name */
35189251Ssam	char *name;
36189251Ssam
37189251Ssam	/* Parser function for this variable */
38189251Ssam	int (*parser)(const struct parse_data *data, struct wpa_ssid *ssid,
39189251Ssam		      int line, const char *value);
40189251Ssam
41189251Ssam#ifndef NO_CONFIG_WRITE
42189251Ssam	/* Writer function (i.e., to get the variable in text format from
43189251Ssam	 * internal presentation). */
44189251Ssam	char * (*writer)(const struct parse_data *data, struct wpa_ssid *ssid);
45189251Ssam#endif /* NO_CONFIG_WRITE */
46189251Ssam
47189251Ssam	/* Variable specific parameters for the parser. */
48189251Ssam	void *param1, *param2, *param3, *param4;
49189251Ssam
50189251Ssam	/* 0 = this variable can be included in debug output and ctrl_iface
51189251Ssam	 * 1 = this variable contains key/private data and it must not be
52189251Ssam	 *     included in debug output unless explicitly requested. In
53189251Ssam	 *     addition, this variable will not be readable through the
54189251Ssam	 *     ctrl_iface.
55189251Ssam	 */
56189251Ssam	int key_data;
57189251Ssam};
58189251Ssam
59189251Ssam
60189251Ssamstatic char * wpa_config_parse_string(const char *value, size_t *len)
61189251Ssam{
62189251Ssam	if (*value == '"') {
63189251Ssam		const char *pos;
64189251Ssam		char *str;
65189251Ssam		value++;
66189251Ssam		pos = os_strrchr(value, '"');
67189251Ssam		if (pos == NULL || pos[1] != '\0')
68189251Ssam			return NULL;
69189251Ssam		*len = pos - value;
70189251Ssam		str = os_malloc(*len + 1);
71189251Ssam		if (str == NULL)
72189251Ssam			return NULL;
73189251Ssam		os_memcpy(str, value, *len);
74189251Ssam		str[*len] = '\0';
75189251Ssam		return str;
76189251Ssam	} else {
77189251Ssam		u8 *str;
78189251Ssam		size_t tlen, hlen = os_strlen(value);
79189251Ssam		if (hlen & 1)
80189251Ssam			return NULL;
81189251Ssam		tlen = hlen / 2;
82189251Ssam		str = os_malloc(tlen + 1);
83189251Ssam		if (str == NULL)
84189251Ssam			return NULL;
85189251Ssam		if (hexstr2bin(value, str, tlen)) {
86189251Ssam			os_free(str);
87189251Ssam			return NULL;
88189251Ssam		}
89189251Ssam		str[tlen] = '\0';
90189251Ssam		*len = tlen;
91189251Ssam		return (char *) str;
92189251Ssam	}
93189251Ssam}
94189251Ssam
95189251Ssam
96189251Ssamstatic int wpa_config_parse_str(const struct parse_data *data,
97189251Ssam				struct wpa_ssid *ssid,
98189251Ssam				int line, const char *value)
99189251Ssam{
100189251Ssam	size_t res_len, *dst_len;
101189251Ssam	char **dst, *tmp;
102189251Ssam
103189251Ssam	if (os_strcmp(value, "NULL") == 0) {
104189251Ssam		wpa_printf(MSG_DEBUG, "Unset configuration string '%s'",
105189251Ssam			   data->name);
106189251Ssam		tmp = NULL;
107189251Ssam		res_len = 0;
108189251Ssam		goto set;
109189251Ssam	}
110189251Ssam
111189251Ssam	tmp = wpa_config_parse_string(value, &res_len);
112189251Ssam	if (tmp == NULL) {
113189251Ssam		wpa_printf(MSG_ERROR, "Line %d: failed to parse %s '%s'.",
114189251Ssam			   line, data->name,
115189251Ssam			   data->key_data ? "[KEY DATA REMOVED]" : value);
116189251Ssam		return -1;
117189251Ssam	}
118189251Ssam
119189251Ssam	if (data->key_data) {
120189251Ssam		wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
121189251Ssam				      (u8 *) tmp, res_len);
122189251Ssam	} else {
123189251Ssam		wpa_hexdump_ascii(MSG_MSGDUMP, data->name,
124189251Ssam				  (u8 *) tmp, res_len);
125189251Ssam	}
126189251Ssam
127189251Ssam	if (data->param3 && res_len < (size_t) data->param3) {
128189251Ssam		wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu "
129189251Ssam			   "min_len=%ld)", line, data->name,
130189251Ssam			   (unsigned long) res_len, (long) data->param3);
131189251Ssam		os_free(tmp);
132189251Ssam		return -1;
133189251Ssam	}
134189251Ssam
135189251Ssam	if (data->param4 && res_len > (size_t) data->param4) {
136189251Ssam		wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu "
137189251Ssam			   "max_len=%ld)", line, data->name,
138189251Ssam			   (unsigned long) res_len, (long) data->param4);
139189251Ssam		os_free(tmp);
140189251Ssam		return -1;
141189251Ssam	}
142189251Ssam
143189251Ssamset:
144189251Ssam	dst = (char **) (((u8 *) ssid) + (long) data->param1);
145189251Ssam	dst_len = (size_t *) (((u8 *) ssid) + (long) data->param2);
146189251Ssam	os_free(*dst);
147189251Ssam	*dst = tmp;
148189251Ssam	if (data->param2)
149189251Ssam		*dst_len = res_len;
150189251Ssam
151189251Ssam	return 0;
152189251Ssam}
153189251Ssam
154189251Ssam
155189251Ssam#ifndef NO_CONFIG_WRITE
156189251Ssamstatic int is_hex(const u8 *data, size_t len)
157189251Ssam{
158189251Ssam	size_t i;
159189251Ssam
160189251Ssam	for (i = 0; i < len; i++) {
161189251Ssam		if (data[i] < 32 || data[i] >= 127)
162189251Ssam			return 1;
163189251Ssam	}
164189251Ssam	return 0;
165189251Ssam}
166189251Ssam
167189251Ssam
168189251Ssamstatic char * wpa_config_write_string_ascii(const u8 *value, size_t len)
169189251Ssam{
170189251Ssam	char *buf;
171189251Ssam
172189251Ssam	buf = os_malloc(len + 3);
173189251Ssam	if (buf == NULL)
174189251Ssam		return NULL;
175189251Ssam	buf[0] = '"';
176189251Ssam	os_memcpy(buf + 1, value, len);
177189251Ssam	buf[len + 1] = '"';
178189251Ssam	buf[len + 2] = '\0';
179189251Ssam
180189251Ssam	return buf;
181189251Ssam}
182189251Ssam
183189251Ssam
184189251Ssamstatic char * wpa_config_write_string_hex(const u8 *value, size_t len)
185189251Ssam{
186189251Ssam	char *buf;
187189251Ssam
188189251Ssam	buf = os_zalloc(2 * len + 1);
189189251Ssam	if (buf == NULL)
190189251Ssam		return NULL;
191189251Ssam	wpa_snprintf_hex(buf, 2 * len + 1, value, len);
192189251Ssam
193189251Ssam	return buf;
194189251Ssam}
195189251Ssam
196189251Ssam
197189251Ssamstatic char * wpa_config_write_string(const u8 *value, size_t len)
198189251Ssam{
199189251Ssam	if (value == NULL)
200189251Ssam		return NULL;
201189251Ssam
202189251Ssam	if (is_hex(value, len))
203189251Ssam		return wpa_config_write_string_hex(value, len);
204189251Ssam	else
205189251Ssam		return wpa_config_write_string_ascii(value, len);
206189251Ssam}
207189251Ssam
208189251Ssam
209189251Ssamstatic char * wpa_config_write_str(const struct parse_data *data,
210189251Ssam				   struct wpa_ssid *ssid)
211189251Ssam{
212189251Ssam	size_t len;
213189251Ssam	char **src;
214189251Ssam
215189251Ssam	src = (char **) (((u8 *) ssid) + (long) data->param1);
216189251Ssam	if (*src == NULL)
217189251Ssam		return NULL;
218189251Ssam
219189251Ssam	if (data->param2)
220189251Ssam		len = *((size_t *) (((u8 *) ssid) + (long) data->param2));
221189251Ssam	else
222189251Ssam		len = os_strlen(*src);
223189251Ssam
224189251Ssam	return wpa_config_write_string((const u8 *) *src, len);
225189251Ssam}
226189251Ssam#endif /* NO_CONFIG_WRITE */
227189251Ssam
228189251Ssam
229189251Ssamstatic int wpa_config_parse_int(const struct parse_data *data,
230189251Ssam				struct wpa_ssid *ssid,
231189251Ssam				int line, const char *value)
232189251Ssam{
233189251Ssam	int *dst;
234189251Ssam
235189251Ssam	dst = (int *) (((u8 *) ssid) + (long) data->param1);
236189251Ssam	*dst = atoi(value);
237189251Ssam	wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst);
238189251Ssam
239189251Ssam	if (data->param3 && *dst < (long) data->param3) {
240189251Ssam		wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d "
241189251Ssam			   "min_value=%ld)", line, data->name, *dst,
242189251Ssam			   (long) data->param3);
243189251Ssam		*dst = (long) data->param3;
244189251Ssam		return -1;
245189251Ssam	}
246189251Ssam
247189251Ssam	if (data->param4 && *dst > (long) data->param4) {
248189251Ssam		wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d "
249189251Ssam			   "max_value=%ld)", line, data->name, *dst,
250189251Ssam			   (long) data->param4);
251189251Ssam		*dst = (long) data->param4;
252189251Ssam		return -1;
253189251Ssam	}
254189251Ssam
255189251Ssam	return 0;
256189251Ssam}
257189251Ssam
258189251Ssam
259189251Ssam#ifndef NO_CONFIG_WRITE
260189251Ssamstatic char * wpa_config_write_int(const struct parse_data *data,
261189251Ssam				   struct wpa_ssid *ssid)
262189251Ssam{
263189251Ssam	int *src, res;
264189251Ssam	char *value;
265189251Ssam
266189251Ssam	src = (int *) (((u8 *) ssid) + (long) data->param1);
267189251Ssam
268189251Ssam	value = os_malloc(20);
269189251Ssam	if (value == NULL)
270189251Ssam		return NULL;
271189251Ssam	res = os_snprintf(value, 20, "%d", *src);
272189251Ssam	if (res < 0 || res >= 20) {
273189251Ssam		os_free(value);
274189251Ssam		return NULL;
275189251Ssam	}
276189251Ssam	value[20 - 1] = '\0';
277189251Ssam	return value;
278189251Ssam}
279189251Ssam#endif /* NO_CONFIG_WRITE */
280189251Ssam
281189251Ssam
282189251Ssamstatic int wpa_config_parse_bssid(const struct parse_data *data,
283189251Ssam				  struct wpa_ssid *ssid, int line,
284189251Ssam				  const char *value)
285189251Ssam{
286189251Ssam	if (hwaddr_aton(value, ssid->bssid)) {
287189251Ssam		wpa_printf(MSG_ERROR, "Line %d: Invalid BSSID '%s'.",
288189251Ssam			   line, value);
289189251Ssam		return -1;
290189251Ssam	}
291189251Ssam	ssid->bssid_set = 1;
292189251Ssam	wpa_hexdump(MSG_MSGDUMP, "BSSID", ssid->bssid, ETH_ALEN);
293189251Ssam	return 0;
294189251Ssam}
295189251Ssam
296189251Ssam
297189251Ssam#ifndef NO_CONFIG_WRITE
298189251Ssamstatic char * wpa_config_write_bssid(const struct parse_data *data,
299189251Ssam				     struct wpa_ssid *ssid)
300189251Ssam{
301189251Ssam	char *value;
302189251Ssam	int res;
303189251Ssam
304189251Ssam	if (!ssid->bssid_set)
305189251Ssam		return NULL;
306189251Ssam
307189251Ssam	value = os_malloc(20);
308189251Ssam	if (value == NULL)
309189251Ssam		return NULL;
310189251Ssam	res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->bssid));
311189251Ssam	if (res < 0 || res >= 20) {
312189251Ssam		os_free(value);
313189251Ssam		return NULL;
314189251Ssam	}
315189251Ssam	value[20 - 1] = '\0';
316189251Ssam	return value;
317189251Ssam}
318189251Ssam#endif /* NO_CONFIG_WRITE */
319189251Ssam
320189251Ssam
321189251Ssamstatic int wpa_config_parse_psk(const struct parse_data *data,
322189251Ssam				struct wpa_ssid *ssid, int line,
323189251Ssam				const char *value)
324189251Ssam{
325189251Ssam	if (*value == '"') {
326189251Ssam#ifndef CONFIG_NO_PBKDF2
327189251Ssam		const char *pos;
328189251Ssam		size_t len;
329189251Ssam
330189251Ssam		value++;
331189251Ssam		pos = os_strrchr(value, '"');
332189251Ssam		if (pos)
333189251Ssam			len = pos - value;
334189251Ssam		else
335189251Ssam			len = os_strlen(value);
336189251Ssam		if (len < 8 || len > 63) {
337189251Ssam			wpa_printf(MSG_ERROR, "Line %d: Invalid passphrase "
338189251Ssam				   "length %lu (expected: 8..63) '%s'.",
339189251Ssam				   line, (unsigned long) len, value);
340189251Ssam			return -1;
341189251Ssam		}
342189251Ssam		wpa_hexdump_ascii_key(MSG_MSGDUMP, "PSK (ASCII passphrase)",
343189251Ssam				      (u8 *) value, len);
344189251Ssam		if (ssid->passphrase && os_strlen(ssid->passphrase) == len &&
345189251Ssam		    os_memcmp(ssid->passphrase, value, len) == 0)
346189251Ssam			return 0;
347189251Ssam		ssid->psk_set = 0;
348189251Ssam		os_free(ssid->passphrase);
349189251Ssam		ssid->passphrase = os_malloc(len + 1);
350189251Ssam		if (ssid->passphrase == NULL)
351189251Ssam			return -1;
352189251Ssam		os_memcpy(ssid->passphrase, value, len);
353189251Ssam		ssid->passphrase[len] = '\0';
354189251Ssam		return 0;
355189251Ssam#else /* CONFIG_NO_PBKDF2 */
356189251Ssam		wpa_printf(MSG_ERROR, "Line %d: ASCII passphrase not "
357189251Ssam			   "supported.", line);
358189251Ssam		return -1;
359189251Ssam#endif /* CONFIG_NO_PBKDF2 */
360189251Ssam	}
361189251Ssam
362189251Ssam	if (hexstr2bin(value, ssid->psk, PMK_LEN) ||
363189251Ssam	    value[PMK_LEN * 2] != '\0') {
364189251Ssam		wpa_printf(MSG_ERROR, "Line %d: Invalid PSK '%s'.",
365189251Ssam			   line, value);
366189251Ssam		return -1;
367189251Ssam	}
368189251Ssam
369189251Ssam	os_free(ssid->passphrase);
370189251Ssam	ssid->passphrase = NULL;
371189251Ssam
372189251Ssam	ssid->psk_set = 1;
373189251Ssam	wpa_hexdump_key(MSG_MSGDUMP, "PSK", ssid->psk, PMK_LEN);
374189251Ssam	return 0;
375189251Ssam}
376189251Ssam
377189251Ssam
378189251Ssam#ifndef NO_CONFIG_WRITE
379189251Ssamstatic char * wpa_config_write_psk(const struct parse_data *data,
380189251Ssam				   struct wpa_ssid *ssid)
381189251Ssam{
382189251Ssam	if (ssid->passphrase)
383189251Ssam		return wpa_config_write_string_ascii(
384189251Ssam			(const u8 *) ssid->passphrase,
385189251Ssam			os_strlen(ssid->passphrase));
386189251Ssam
387189251Ssam	if (ssid->psk_set)
388189251Ssam		return wpa_config_write_string_hex(ssid->psk, PMK_LEN);
389189251Ssam
390189251Ssam	return NULL;
391189251Ssam}
392189251Ssam#endif /* NO_CONFIG_WRITE */
393189251Ssam
394189251Ssam
395189251Ssamstatic int wpa_config_parse_proto(const struct parse_data *data,
396189251Ssam				  struct wpa_ssid *ssid, int line,
397189251Ssam				  const char *value)
398189251Ssam{
399189251Ssam	int val = 0, last, errors = 0;
400189251Ssam	char *start, *end, *buf;
401189251Ssam
402189251Ssam	buf = os_strdup(value);
403189251Ssam	if (buf == NULL)
404189251Ssam		return -1;
405189251Ssam	start = buf;
406189251Ssam
407189251Ssam	while (*start != '\0') {
408189251Ssam		while (*start == ' ' || *start == '\t')
409189251Ssam			start++;
410189251Ssam		if (*start == '\0')
411189251Ssam			break;
412189251Ssam		end = start;
413189251Ssam		while (*end != ' ' && *end != '\t' && *end != '\0')
414189251Ssam			end++;
415189251Ssam		last = *end == '\0';
416189251Ssam		*end = '\0';
417189251Ssam		if (os_strcmp(start, "WPA") == 0)
418189251Ssam			val |= WPA_PROTO_WPA;
419189251Ssam		else if (os_strcmp(start, "RSN") == 0 ||
420189251Ssam			 os_strcmp(start, "WPA2") == 0)
421189251Ssam			val |= WPA_PROTO_RSN;
422189251Ssam		else {
423189251Ssam			wpa_printf(MSG_ERROR, "Line %d: invalid proto '%s'",
424189251Ssam				   line, start);
425189251Ssam			errors++;
426189251Ssam		}
427189251Ssam
428189251Ssam		if (last)
429189251Ssam			break;
430189251Ssam		start = end + 1;
431189251Ssam	}
432189251Ssam	os_free(buf);
433189251Ssam
434189251Ssam	if (val == 0) {
435189251Ssam		wpa_printf(MSG_ERROR,
436189251Ssam			   "Line %d: no proto values configured.", line);
437189251Ssam		errors++;
438189251Ssam	}
439189251Ssam
440189251Ssam	wpa_printf(MSG_MSGDUMP, "proto: 0x%x", val);
441189251Ssam	ssid->proto = val;
442189251Ssam	return errors ? -1 : 0;
443189251Ssam}
444189251Ssam
445189251Ssam
446189251Ssam#ifndef NO_CONFIG_WRITE
447189251Ssamstatic char * wpa_config_write_proto(const struct parse_data *data,
448189251Ssam				     struct wpa_ssid *ssid)
449189251Ssam{
450189251Ssam	int first = 1, ret;
451189251Ssam	char *buf, *pos, *end;
452189251Ssam
453189251Ssam	pos = buf = os_zalloc(10);
454189251Ssam	if (buf == NULL)
455189251Ssam		return NULL;
456189251Ssam	end = buf + 10;
457189251Ssam
458189251Ssam	if (ssid->proto & WPA_PROTO_WPA) {
459189251Ssam		ret = os_snprintf(pos, end - pos, "%sWPA", first ? "" : " ");
460189251Ssam		if (ret < 0 || ret >= end - pos)
461189251Ssam			return buf;
462189251Ssam		pos += ret;
463189251Ssam		first = 0;
464189251Ssam	}
465189251Ssam
466189251Ssam	if (ssid->proto & WPA_PROTO_RSN) {
467189251Ssam		ret = os_snprintf(pos, end - pos, "%sRSN", first ? "" : " ");
468189251Ssam		if (ret < 0 || ret >= end - pos)
469189251Ssam			return buf;
470189251Ssam		pos += ret;
471189251Ssam		first = 0;
472189251Ssam	}
473189251Ssam
474189251Ssam	return buf;
475189251Ssam}
476189251Ssam#endif /* NO_CONFIG_WRITE */
477189251Ssam
478189251Ssam
479189251Ssamstatic int wpa_config_parse_key_mgmt(const struct parse_data *data,
480189251Ssam				     struct wpa_ssid *ssid, int line,
481189251Ssam				     const char *value)
482189251Ssam{
483189251Ssam	int val = 0, last, errors = 0;
484189251Ssam	char *start, *end, *buf;
485189251Ssam
486189251Ssam	buf = os_strdup(value);
487189251Ssam	if (buf == NULL)
488189251Ssam		return -1;
489189251Ssam	start = buf;
490189251Ssam
491189251Ssam	while (*start != '\0') {
492189251Ssam		while (*start == ' ' || *start == '\t')
493189251Ssam			start++;
494189251Ssam		if (*start == '\0')
495189251Ssam			break;
496189251Ssam		end = start;
497189251Ssam		while (*end != ' ' && *end != '\t' && *end != '\0')
498189251Ssam			end++;
499189251Ssam		last = *end == '\0';
500189251Ssam		*end = '\0';
501189251Ssam		if (os_strcmp(start, "WPA-PSK") == 0)
502189251Ssam			val |= WPA_KEY_MGMT_PSK;
503189251Ssam		else if (os_strcmp(start, "WPA-EAP") == 0)
504189251Ssam			val |= WPA_KEY_MGMT_IEEE8021X;
505189251Ssam		else if (os_strcmp(start, "IEEE8021X") == 0)
506189251Ssam			val |= WPA_KEY_MGMT_IEEE8021X_NO_WPA;
507189251Ssam		else if (os_strcmp(start, "NONE") == 0)
508189251Ssam			val |= WPA_KEY_MGMT_NONE;
509189251Ssam		else if (os_strcmp(start, "WPA-NONE") == 0)
510189251Ssam			val |= WPA_KEY_MGMT_WPA_NONE;
511189251Ssam#ifdef CONFIG_IEEE80211R
512189251Ssam		else if (os_strcmp(start, "FT-PSK") == 0)
513189251Ssam			val |= WPA_KEY_MGMT_FT_PSK;
514189251Ssam		else if (os_strcmp(start, "FT-EAP") == 0)
515189251Ssam			val |= WPA_KEY_MGMT_FT_IEEE8021X;
516189251Ssam#endif /* CONFIG_IEEE80211R */
517189251Ssam#ifdef CONFIG_IEEE80211W
518189251Ssam		else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
519189251Ssam			val |= WPA_KEY_MGMT_PSK_SHA256;
520189251Ssam		else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
521189251Ssam			val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
522189251Ssam#endif /* CONFIG_IEEE80211W */
523189251Ssam#ifdef CONFIG_WPS
524189251Ssam		else if (os_strcmp(start, "WPS") == 0)
525189251Ssam			val |= WPA_KEY_MGMT_WPS;
526189251Ssam#endif /* CONFIG_WPS */
527189251Ssam		else {
528189251Ssam			wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
529189251Ssam				   line, start);
530189251Ssam			errors++;
531189251Ssam		}
532189251Ssam
533189251Ssam		if (last)
534189251Ssam			break;
535189251Ssam		start = end + 1;
536189251Ssam	}
537189251Ssam	os_free(buf);
538189251Ssam
539189251Ssam	if (val == 0) {
540189251Ssam		wpa_printf(MSG_ERROR,
541189251Ssam			   "Line %d: no key_mgmt values configured.", line);
542189251Ssam		errors++;
543189251Ssam	}
544189251Ssam
545189251Ssam	wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", val);
546189251Ssam	ssid->key_mgmt = val;
547189251Ssam	return errors ? -1 : 0;
548189251Ssam}
549189251Ssam
550189251Ssam
551189251Ssam#ifndef NO_CONFIG_WRITE
552189251Ssamstatic char * wpa_config_write_key_mgmt(const struct parse_data *data,
553189251Ssam					struct wpa_ssid *ssid)
554189251Ssam{
555189251Ssam	char *buf, *pos, *end;
556189251Ssam	int ret;
557189251Ssam
558189251Ssam	pos = buf = os_zalloc(50);
559189251Ssam	if (buf == NULL)
560189251Ssam		return NULL;
561189251Ssam	end = buf + 50;
562189251Ssam
563189251Ssam	if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
564189251Ssam		ret = os_snprintf(pos, end - pos, "%sWPA-PSK",
565189251Ssam				  pos == buf ? "" : " ");
566189251Ssam		if (ret < 0 || ret >= end - pos) {
567189251Ssam			end[-1] = '\0';
568189251Ssam			return buf;
569189251Ssam		}
570189251Ssam		pos += ret;
571189251Ssam	}
572189251Ssam
573189251Ssam	if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
574189251Ssam		ret = os_snprintf(pos, end - pos, "%sWPA-EAP",
575189251Ssam				  pos == buf ? "" : " ");
576189251Ssam		if (ret < 0 || ret >= end - pos) {
577189251Ssam			end[-1] = '\0';
578189251Ssam			return buf;
579189251Ssam		}
580189251Ssam		pos += ret;
581189251Ssam	}
582189251Ssam
583189251Ssam	if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
584189251Ssam		ret = os_snprintf(pos, end - pos, "%sIEEE8021X",
585189251Ssam				  pos == buf ? "" : " ");
586189251Ssam		if (ret < 0 || ret >= end - pos) {
587189251Ssam			end[-1] = '\0';
588189251Ssam			return buf;
589189251Ssam		}
590189251Ssam		pos += ret;
591189251Ssam	}
592189251Ssam
593189251Ssam	if (ssid->key_mgmt & WPA_KEY_MGMT_NONE) {
594189251Ssam		ret = os_snprintf(pos, end - pos, "%sNONE",
595189251Ssam				  pos == buf ? "" : " ");
596189251Ssam		if (ret < 0 || ret >= end - pos) {
597189251Ssam			end[-1] = '\0';
598189251Ssam			return buf;
599189251Ssam		}
600189251Ssam		pos += ret;
601189251Ssam	}
602189251Ssam
603189251Ssam	if (ssid->key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
604189251Ssam		ret = os_snprintf(pos, end - pos, "%sWPA-NONE",
605189251Ssam				  pos == buf ? "" : " ");
606189251Ssam		if (ret < 0 || ret >= end - pos) {
607189251Ssam			end[-1] = '\0';
608189251Ssam			return buf;
609189251Ssam		}
610189251Ssam		pos += ret;
611189251Ssam	}
612189251Ssam
613189251Ssam#ifdef CONFIG_IEEE80211R
614189251Ssam	if (ssid->key_mgmt & WPA_KEY_MGMT_FT_PSK)
615189251Ssam		pos += os_snprintf(pos, end - pos, "%sFT-PSK",
616189251Ssam				   pos == buf ? "" : " ");
617189251Ssam
618189251Ssam	if (ssid->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
619189251Ssam		pos += os_snprintf(pos, end - pos, "%sFT-EAP",
620189251Ssam				   pos == buf ? "" : " ");
621189251Ssam#endif /* CONFIG_IEEE80211R */
622189251Ssam
623189251Ssam#ifdef CONFIG_IEEE80211W
624189251Ssam	if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
625189251Ssam		pos += os_snprintf(pos, end - pos, "%sWPA-PSK-SHA256",
626189251Ssam				   pos == buf ? "" : " ");
627189251Ssam
628189251Ssam	if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
629189251Ssam		pos += os_snprintf(pos, end - pos, "%sWPA-EAP-SHA256",
630189251Ssam				   pos == buf ? "" : " ");
631189251Ssam#endif /* CONFIG_IEEE80211W */
632189251Ssam
633189251Ssam#ifdef CONFIG_WPS
634189251Ssam	if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
635189251Ssam		pos += os_snprintf(pos, end - pos, "%sWPS",
636189251Ssam				   pos == buf ? "" : " ");
637189251Ssam#endif /* CONFIG_WPS */
638189251Ssam
639189251Ssam	return buf;
640189251Ssam}
641189251Ssam#endif /* NO_CONFIG_WRITE */
642189251Ssam
643189251Ssam
644189251Ssamstatic int wpa_config_parse_cipher(int line, const char *value)
645189251Ssam{
646189251Ssam	int val = 0, last;
647189251Ssam	char *start, *end, *buf;
648189251Ssam
649189251Ssam	buf = os_strdup(value);
650189251Ssam	if (buf == NULL)
651189251Ssam		return -1;
652189251Ssam	start = buf;
653189251Ssam
654189251Ssam	while (*start != '\0') {
655189251Ssam		while (*start == ' ' || *start == '\t')
656189251Ssam			start++;
657189251Ssam		if (*start == '\0')
658189251Ssam			break;
659189251Ssam		end = start;
660189251Ssam		while (*end != ' ' && *end != '\t' && *end != '\0')
661189251Ssam			end++;
662189251Ssam		last = *end == '\0';
663189251Ssam		*end = '\0';
664189251Ssam		if (os_strcmp(start, "CCMP") == 0)
665189251Ssam			val |= WPA_CIPHER_CCMP;
666189251Ssam		else if (os_strcmp(start, "TKIP") == 0)
667189251Ssam			val |= WPA_CIPHER_TKIP;
668189251Ssam		else if (os_strcmp(start, "WEP104") == 0)
669189251Ssam			val |= WPA_CIPHER_WEP104;
670189251Ssam		else if (os_strcmp(start, "WEP40") == 0)
671189251Ssam			val |= WPA_CIPHER_WEP40;
672189251Ssam		else if (os_strcmp(start, "NONE") == 0)
673189251Ssam			val |= WPA_CIPHER_NONE;
674189251Ssam		else {
675189251Ssam			wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
676189251Ssam				   line, start);
677189251Ssam			os_free(buf);
678189251Ssam			return -1;
679189251Ssam		}
680189251Ssam
681189251Ssam		if (last)
682189251Ssam			break;
683189251Ssam		start = end + 1;
684189251Ssam	}
685189251Ssam	os_free(buf);
686189251Ssam
687189251Ssam	if (val == 0) {
688189251Ssam		wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.",
689189251Ssam			   line);
690189251Ssam		return -1;
691189251Ssam	}
692189251Ssam	return val;
693189251Ssam}
694189251Ssam
695189251Ssam
696189251Ssam#ifndef NO_CONFIG_WRITE
697189251Ssamstatic char * wpa_config_write_cipher(int cipher)
698189251Ssam{
699189251Ssam	char *buf, *pos, *end;
700189251Ssam	int ret;
701189251Ssam
702189251Ssam	pos = buf = os_zalloc(50);
703189251Ssam	if (buf == NULL)
704189251Ssam		return NULL;
705189251Ssam	end = buf + 50;
706189251Ssam
707189251Ssam	if (cipher & WPA_CIPHER_CCMP) {
708189251Ssam		ret = os_snprintf(pos, end - pos, "%sCCMP",
709189251Ssam				  pos == buf ? "" : " ");
710189251Ssam		if (ret < 0 || ret >= end - pos) {
711189251Ssam			end[-1] = '\0';
712189251Ssam			return buf;
713189251Ssam		}
714189251Ssam		pos += ret;
715189251Ssam	}
716189251Ssam
717189251Ssam	if (cipher & WPA_CIPHER_TKIP) {
718189251Ssam		ret = os_snprintf(pos, end - pos, "%sTKIP",
719189251Ssam				  pos == buf ? "" : " ");
720189251Ssam		if (ret < 0 || ret >= end - pos) {
721189251Ssam			end[-1] = '\0';
722189251Ssam			return buf;
723189251Ssam		}
724189251Ssam		pos += ret;
725189251Ssam	}
726189251Ssam
727189251Ssam	if (cipher & WPA_CIPHER_WEP104) {
728189251Ssam		ret = os_snprintf(pos, end - pos, "%sWEP104",
729189251Ssam				  pos == buf ? "" : " ");
730189251Ssam		if (ret < 0 || ret >= end - pos) {
731189251Ssam			end[-1] = '\0';
732189251Ssam			return buf;
733189251Ssam		}
734189251Ssam		pos += ret;
735189251Ssam	}
736189251Ssam
737189251Ssam	if (cipher & WPA_CIPHER_WEP40) {
738189251Ssam		ret = os_snprintf(pos, end - pos, "%sWEP40",
739189251Ssam				  pos == buf ? "" : " ");
740189251Ssam		if (ret < 0 || ret >= end - pos) {
741189251Ssam			end[-1] = '\0';
742189251Ssam			return buf;
743189251Ssam		}
744189251Ssam		pos += ret;
745189251Ssam	}
746189251Ssam
747189251Ssam	if (cipher & WPA_CIPHER_NONE) {
748189251Ssam		ret = os_snprintf(pos, end - pos, "%sNONE",
749189251Ssam				  pos == buf ? "" : " ");
750189251Ssam		if (ret < 0 || ret >= end - pos) {
751189251Ssam			end[-1] = '\0';
752189251Ssam			return buf;
753189251Ssam		}
754189251Ssam		pos += ret;
755189251Ssam	}
756189251Ssam
757189251Ssam	return buf;
758189251Ssam}
759189251Ssam#endif /* NO_CONFIG_WRITE */
760189251Ssam
761189251Ssam
762189251Ssamstatic int wpa_config_parse_pairwise(const struct parse_data *data,
763189251Ssam				     struct wpa_ssid *ssid, int line,
764189251Ssam				     const char *value)
765189251Ssam{
766189251Ssam	int val;
767189251Ssam	val = wpa_config_parse_cipher(line, value);
768189251Ssam	if (val == -1)
769189251Ssam		return -1;
770189251Ssam	if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE)) {
771189251Ssam		wpa_printf(MSG_ERROR, "Line %d: not allowed pairwise cipher "
772189251Ssam			   "(0x%x).", line, val);
773189251Ssam		return -1;
774189251Ssam	}
775189251Ssam
776189251Ssam	wpa_printf(MSG_MSGDUMP, "pairwise: 0x%x", val);
777189251Ssam	ssid->pairwise_cipher = val;
778189251Ssam	return 0;
779189251Ssam}
780189251Ssam
781189251Ssam
782189251Ssam#ifndef NO_CONFIG_WRITE
783189251Ssamstatic char * wpa_config_write_pairwise(const struct parse_data *data,
784189251Ssam					struct wpa_ssid *ssid)
785189251Ssam{
786189251Ssam	return wpa_config_write_cipher(ssid->pairwise_cipher);
787189251Ssam}
788189251Ssam#endif /* NO_CONFIG_WRITE */
789189251Ssam
790189251Ssam
791189251Ssamstatic int wpa_config_parse_group(const struct parse_data *data,
792189251Ssam				  struct wpa_ssid *ssid, int line,
793189251Ssam				  const char *value)
794189251Ssam{
795189251Ssam	int val;
796189251Ssam	val = wpa_config_parse_cipher(line, value);
797189251Ssam	if (val == -1)
798189251Ssam		return -1;
799189251Ssam	if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | WPA_CIPHER_WEP104 |
800189251Ssam		    WPA_CIPHER_WEP40)) {
801189251Ssam		wpa_printf(MSG_ERROR, "Line %d: not allowed group cipher "
802189251Ssam			   "(0x%x).", line, val);
803189251Ssam		return -1;
804189251Ssam	}
805189251Ssam
806189251Ssam	wpa_printf(MSG_MSGDUMP, "group: 0x%x", val);
807189251Ssam	ssid->group_cipher = val;
808189251Ssam	return 0;
809189251Ssam}
810189251Ssam
811189251Ssam
812189251Ssam#ifndef NO_CONFIG_WRITE
813189251Ssamstatic char * wpa_config_write_group(const struct parse_data *data,
814189251Ssam				     struct wpa_ssid *ssid)
815189251Ssam{
816189251Ssam	return wpa_config_write_cipher(ssid->group_cipher);
817189251Ssam}
818189251Ssam#endif /* NO_CONFIG_WRITE */
819189251Ssam
820189251Ssam
821189251Ssamstatic int wpa_config_parse_auth_alg(const struct parse_data *data,
822189251Ssam				     struct wpa_ssid *ssid, int line,
823189251Ssam				     const char *value)
824189251Ssam{
825189251Ssam	int val = 0, last, errors = 0;
826189251Ssam	char *start, *end, *buf;
827189251Ssam
828189251Ssam	buf = os_strdup(value);
829189251Ssam	if (buf == NULL)
830189251Ssam		return -1;
831189251Ssam	start = buf;
832189251Ssam
833189251Ssam	while (*start != '\0') {
834189251Ssam		while (*start == ' ' || *start == '\t')
835189251Ssam			start++;
836189251Ssam		if (*start == '\0')
837189251Ssam			break;
838189251Ssam		end = start;
839189251Ssam		while (*end != ' ' && *end != '\t' && *end != '\0')
840189251Ssam			end++;
841189251Ssam		last = *end == '\0';
842189251Ssam		*end = '\0';
843189251Ssam		if (os_strcmp(start, "OPEN") == 0)
844189251Ssam			val |= WPA_AUTH_ALG_OPEN;
845189251Ssam		else if (os_strcmp(start, "SHARED") == 0)
846189251Ssam			val |= WPA_AUTH_ALG_SHARED;
847189251Ssam		else if (os_strcmp(start, "LEAP") == 0)
848189251Ssam			val |= WPA_AUTH_ALG_LEAP;
849189251Ssam		else {
850189251Ssam			wpa_printf(MSG_ERROR, "Line %d: invalid auth_alg '%s'",
851189251Ssam				   line, start);
852189251Ssam			errors++;
853189251Ssam		}
854189251Ssam
855189251Ssam		if (last)
856189251Ssam			break;
857189251Ssam		start = end + 1;
858189251Ssam	}
859189251Ssam	os_free(buf);
860189251Ssam
861189251Ssam	if (val == 0) {
862189251Ssam		wpa_printf(MSG_ERROR,
863189251Ssam			   "Line %d: no auth_alg values configured.", line);
864189251Ssam		errors++;
865189251Ssam	}
866189251Ssam
867189251Ssam	wpa_printf(MSG_MSGDUMP, "auth_alg: 0x%x", val);
868189251Ssam	ssid->auth_alg = val;
869189251Ssam	return errors ? -1 : 0;
870189251Ssam}
871189251Ssam
872189251Ssam
873189251Ssam#ifndef NO_CONFIG_WRITE
874189251Ssamstatic char * wpa_config_write_auth_alg(const struct parse_data *data,
875189251Ssam					struct wpa_ssid *ssid)
876189251Ssam{
877189251Ssam	char *buf, *pos, *end;
878189251Ssam	int ret;
879189251Ssam
880189251Ssam	pos = buf = os_zalloc(30);
881189251Ssam	if (buf == NULL)
882189251Ssam		return NULL;
883189251Ssam	end = buf + 30;
884189251Ssam
885189251Ssam	if (ssid->auth_alg & WPA_AUTH_ALG_OPEN) {
886189251Ssam		ret = os_snprintf(pos, end - pos, "%sOPEN",
887189251Ssam				  pos == buf ? "" : " ");
888189251Ssam		if (ret < 0 || ret >= end - pos) {
889189251Ssam			end[-1] = '\0';
890189251Ssam			return buf;
891189251Ssam		}
892189251Ssam		pos += ret;
893189251Ssam	}
894189251Ssam
895189251Ssam	if (ssid->auth_alg & WPA_AUTH_ALG_SHARED) {
896189251Ssam		ret = os_snprintf(pos, end - pos, "%sSHARED",
897189251Ssam				  pos == buf ? "" : " ");
898189251Ssam		if (ret < 0 || ret >= end - pos) {
899189251Ssam			end[-1] = '\0';
900189251Ssam			return buf;
901189251Ssam		}
902189251Ssam		pos += ret;
903189251Ssam	}
904189251Ssam
905189251Ssam	if (ssid->auth_alg & WPA_AUTH_ALG_LEAP) {
906189251Ssam		ret = os_snprintf(pos, end - pos, "%sLEAP",
907189251Ssam				  pos == buf ? "" : " ");
908189251Ssam		if (ret < 0 || ret >= end - pos) {
909189251Ssam			end[-1] = '\0';
910189251Ssam			return buf;
911189251Ssam		}
912189251Ssam		pos += ret;
913189251Ssam	}
914189251Ssam
915189251Ssam	return buf;
916189251Ssam}
917189251Ssam#endif /* NO_CONFIG_WRITE */
918189251Ssam
919189251Ssam
920214734Srpaulostatic int * wpa_config_parse_freqs(const struct parse_data *data,
921214734Srpaulo				    struct wpa_ssid *ssid, int line,
922214734Srpaulo				    const char *value)
923214734Srpaulo{
924214734Srpaulo	int *freqs;
925214734Srpaulo	size_t used, len;
926214734Srpaulo	const char *pos;
927214734Srpaulo
928214734Srpaulo	used = 0;
929214734Srpaulo	len = 10;
930214734Srpaulo	freqs = os_zalloc((len + 1) * sizeof(int));
931214734Srpaulo	if (freqs == NULL)
932214734Srpaulo		return NULL;
933214734Srpaulo
934214734Srpaulo	pos = value;
935214734Srpaulo	while (pos) {
936214734Srpaulo		while (*pos == ' ')
937214734Srpaulo			pos++;
938214734Srpaulo		if (used == len) {
939214734Srpaulo			int *n;
940214734Srpaulo			size_t i;
941214734Srpaulo			n = os_realloc(freqs, (len * 2 + 1) * sizeof(int));
942214734Srpaulo			if (n == NULL) {
943214734Srpaulo				os_free(freqs);
944214734Srpaulo				return NULL;
945214734Srpaulo			}
946214734Srpaulo			for (i = len; i <= len * 2; i++)
947214734Srpaulo				n[i] = 0;
948214734Srpaulo			freqs = n;
949214734Srpaulo			len *= 2;
950214734Srpaulo		}
951214734Srpaulo
952214734Srpaulo		freqs[used] = atoi(pos);
953214734Srpaulo		if (freqs[used] == 0)
954214734Srpaulo			break;
955214734Srpaulo		used++;
956214734Srpaulo		pos = os_strchr(pos + 1, ' ');
957214734Srpaulo	}
958214734Srpaulo
959214734Srpaulo	return freqs;
960214734Srpaulo}
961214734Srpaulo
962214734Srpaulo
963214734Srpaulostatic int wpa_config_parse_scan_freq(const struct parse_data *data,
964214734Srpaulo				      struct wpa_ssid *ssid, int line,
965214734Srpaulo				      const char *value)
966214734Srpaulo{
967214734Srpaulo	int *freqs;
968214734Srpaulo
969214734Srpaulo	freqs = wpa_config_parse_freqs(data, ssid, line, value);
970214734Srpaulo	if (freqs == NULL)
971214734Srpaulo		return -1;
972214734Srpaulo	os_free(ssid->scan_freq);
973214734Srpaulo	ssid->scan_freq = freqs;
974214734Srpaulo
975214734Srpaulo	return 0;
976214734Srpaulo}
977214734Srpaulo
978214734Srpaulo
979214734Srpaulostatic int wpa_config_parse_freq_list(const struct parse_data *data,
980214734Srpaulo				      struct wpa_ssid *ssid, int line,
981214734Srpaulo				      const char *value)
982214734Srpaulo{
983214734Srpaulo	int *freqs;
984214734Srpaulo
985214734Srpaulo	freqs = wpa_config_parse_freqs(data, ssid, line, value);
986214734Srpaulo	if (freqs == NULL)
987214734Srpaulo		return -1;
988214734Srpaulo	os_free(ssid->freq_list);
989214734Srpaulo	ssid->freq_list = freqs;
990214734Srpaulo
991214734Srpaulo	return 0;
992214734Srpaulo}
993214734Srpaulo
994214734Srpaulo
995214734Srpaulo#ifndef NO_CONFIG_WRITE
996214734Srpaulostatic char * wpa_config_write_freqs(const struct parse_data *data,
997214734Srpaulo				     const int *freqs)
998214734Srpaulo{
999214734Srpaulo	char *buf, *pos, *end;
1000214734Srpaulo	int i, ret;
1001214734Srpaulo	size_t count;
1002214734Srpaulo
1003214734Srpaulo	if (freqs == NULL)
1004214734Srpaulo		return NULL;
1005214734Srpaulo
1006214734Srpaulo	count = 0;
1007214734Srpaulo	for (i = 0; freqs[i]; i++)
1008214734Srpaulo		count++;
1009214734Srpaulo
1010214734Srpaulo	pos = buf = os_zalloc(10 * count + 1);
1011214734Srpaulo	if (buf == NULL)
1012214734Srpaulo		return NULL;
1013214734Srpaulo	end = buf + 10 * count + 1;
1014214734Srpaulo
1015214734Srpaulo	for (i = 0; freqs[i]; i++) {
1016214734Srpaulo		ret = os_snprintf(pos, end - pos, "%s%u",
1017214734Srpaulo				  i == 0 ? "" : " ", freqs[i]);
1018214734Srpaulo		if (ret < 0 || ret >= end - pos) {
1019214734Srpaulo			end[-1] = '\0';
1020214734Srpaulo			return buf;
1021214734Srpaulo		}
1022214734Srpaulo		pos += ret;
1023214734Srpaulo	}
1024214734Srpaulo
1025214734Srpaulo	return buf;
1026214734Srpaulo}
1027214734Srpaulo
1028214734Srpaulo
1029214734Srpaulostatic char * wpa_config_write_scan_freq(const struct parse_data *data,
1030214734Srpaulo					 struct wpa_ssid *ssid)
1031214734Srpaulo{
1032214734Srpaulo	return wpa_config_write_freqs(data, ssid->scan_freq);
1033214734Srpaulo}
1034214734Srpaulo
1035214734Srpaulo
1036214734Srpaulostatic char * wpa_config_write_freq_list(const struct parse_data *data,
1037214734Srpaulo					 struct wpa_ssid *ssid)
1038214734Srpaulo{
1039214734Srpaulo	return wpa_config_write_freqs(data, ssid->freq_list);
1040214734Srpaulo}
1041214734Srpaulo#endif /* NO_CONFIG_WRITE */
1042214734Srpaulo
1043214734Srpaulo
1044189251Ssam#ifdef IEEE8021X_EAPOL
1045189251Ssamstatic int wpa_config_parse_eap(const struct parse_data *data,
1046189251Ssam				struct wpa_ssid *ssid, int line,
1047189251Ssam				const char *value)
1048189251Ssam{
1049189251Ssam	int last, errors = 0;
1050189251Ssam	char *start, *end, *buf;
1051189251Ssam	struct eap_method_type *methods = NULL, *tmp;
1052189251Ssam	size_t num_methods = 0;
1053189251Ssam
1054189251Ssam	buf = os_strdup(value);
1055189251Ssam	if (buf == NULL)
1056189251Ssam		return -1;
1057189251Ssam	start = buf;
1058189251Ssam
1059189251Ssam	while (*start != '\0') {
1060189251Ssam		while (*start == ' ' || *start == '\t')
1061189251Ssam			start++;
1062189251Ssam		if (*start == '\0')
1063189251Ssam			break;
1064189251Ssam		end = start;
1065189251Ssam		while (*end != ' ' && *end != '\t' && *end != '\0')
1066189251Ssam			end++;
1067189251Ssam		last = *end == '\0';
1068189251Ssam		*end = '\0';
1069189251Ssam		tmp = methods;
1070189251Ssam		methods = os_realloc(methods,
1071189251Ssam				     (num_methods + 1) * sizeof(*methods));
1072189251Ssam		if (methods == NULL) {
1073189251Ssam			os_free(tmp);
1074189251Ssam			os_free(buf);
1075189251Ssam			return -1;
1076189251Ssam		}
1077189251Ssam		methods[num_methods].method = eap_peer_get_type(
1078189251Ssam			start, &methods[num_methods].vendor);
1079189251Ssam		if (methods[num_methods].vendor == EAP_VENDOR_IETF &&
1080189251Ssam		    methods[num_methods].method == EAP_TYPE_NONE) {
1081189251Ssam			wpa_printf(MSG_ERROR, "Line %d: unknown EAP method "
1082189251Ssam				   "'%s'", line, start);
1083189251Ssam			wpa_printf(MSG_ERROR, "You may need to add support for"
1084189251Ssam				   " this EAP method during wpa_supplicant\n"
1085189251Ssam				   "build time configuration.\n"
1086189251Ssam				   "See README for more information.");
1087189251Ssam			errors++;
1088189251Ssam		} else if (methods[num_methods].vendor == EAP_VENDOR_IETF &&
1089189251Ssam			   methods[num_methods].method == EAP_TYPE_LEAP)
1090189251Ssam			ssid->leap++;
1091189251Ssam		else
1092189251Ssam			ssid->non_leap++;
1093189251Ssam		num_methods++;
1094189251Ssam		if (last)
1095189251Ssam			break;
1096189251Ssam		start = end + 1;
1097189251Ssam	}
1098189251Ssam	os_free(buf);
1099189251Ssam
1100189251Ssam	tmp = methods;
1101189251Ssam	methods = os_realloc(methods, (num_methods + 1) * sizeof(*methods));
1102189251Ssam	if (methods == NULL) {
1103189251Ssam		os_free(tmp);
1104189251Ssam		return -1;
1105189251Ssam	}
1106189251Ssam	methods[num_methods].vendor = EAP_VENDOR_IETF;
1107189251Ssam	methods[num_methods].method = EAP_TYPE_NONE;
1108189251Ssam	num_methods++;
1109189251Ssam
1110189251Ssam	wpa_hexdump(MSG_MSGDUMP, "eap methods",
1111189251Ssam		    (u8 *) methods, num_methods * sizeof(*methods));
1112189251Ssam	ssid->eap.eap_methods = methods;
1113189251Ssam	return errors ? -1 : 0;
1114189251Ssam}
1115189251Ssam
1116189251Ssam
1117189251Ssamstatic char * wpa_config_write_eap(const struct parse_data *data,
1118189251Ssam				   struct wpa_ssid *ssid)
1119189251Ssam{
1120189251Ssam	int i, ret;
1121189251Ssam	char *buf, *pos, *end;
1122189251Ssam	const struct eap_method_type *eap_methods = ssid->eap.eap_methods;
1123189251Ssam	const char *name;
1124189251Ssam
1125189251Ssam	if (eap_methods == NULL)
1126189251Ssam		return NULL;
1127189251Ssam
1128189251Ssam	pos = buf = os_zalloc(100);
1129189251Ssam	if (buf == NULL)
1130189251Ssam		return NULL;
1131189251Ssam	end = buf + 100;
1132189251Ssam
1133189251Ssam	for (i = 0; eap_methods[i].vendor != EAP_VENDOR_IETF ||
1134189251Ssam		     eap_methods[i].method != EAP_TYPE_NONE; i++) {
1135189251Ssam		name = eap_get_name(eap_methods[i].vendor,
1136189251Ssam				    eap_methods[i].method);
1137189251Ssam		if (name) {
1138189251Ssam			ret = os_snprintf(pos, end - pos, "%s%s",
1139189251Ssam					  pos == buf ? "" : " ", name);
1140189251Ssam			if (ret < 0 || ret >= end - pos)
1141189251Ssam				break;
1142189251Ssam			pos += ret;
1143189251Ssam		}
1144189251Ssam	}
1145189251Ssam
1146189251Ssam	end[-1] = '\0';
1147189251Ssam
1148189251Ssam	return buf;
1149189251Ssam}
1150189251Ssam
1151189251Ssam
1152189251Ssamstatic int wpa_config_parse_password(const struct parse_data *data,
1153189251Ssam				     struct wpa_ssid *ssid, int line,
1154189251Ssam				     const char *value)
1155189251Ssam{
1156189251Ssam	u8 *hash;
1157189251Ssam
1158189251Ssam	if (os_strcmp(value, "NULL") == 0) {
1159189251Ssam		wpa_printf(MSG_DEBUG, "Unset configuration string 'password'");
1160189251Ssam		os_free(ssid->eap.password);
1161189251Ssam		ssid->eap.password = NULL;
1162189251Ssam		ssid->eap.password_len = 0;
1163189251Ssam		return 0;
1164189251Ssam	}
1165189251Ssam
1166189251Ssam	if (os_strncmp(value, "hash:", 5) != 0) {
1167189251Ssam		char *tmp;
1168189251Ssam		size_t res_len;
1169189251Ssam
1170189251Ssam		tmp = wpa_config_parse_string(value, &res_len);
1171189251Ssam		if (tmp == NULL) {
1172189251Ssam			wpa_printf(MSG_ERROR, "Line %d: failed to parse "
1173189251Ssam				   "password.", line);
1174189251Ssam			return -1;
1175189251Ssam		}
1176189251Ssam		wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
1177189251Ssam				      (u8 *) tmp, res_len);
1178189251Ssam
1179189251Ssam		os_free(ssid->eap.password);
1180189251Ssam		ssid->eap.password = (u8 *) tmp;
1181189251Ssam		ssid->eap.password_len = res_len;
1182189251Ssam		ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
1183189251Ssam
1184189251Ssam		return 0;
1185189251Ssam	}
1186189251Ssam
1187189251Ssam
1188189251Ssam	/* NtPasswordHash: hash:<32 hex digits> */
1189189251Ssam	if (os_strlen(value + 5) != 2 * 16) {
1190189251Ssam		wpa_printf(MSG_ERROR, "Line %d: Invalid password hash length "
1191189251Ssam			   "(expected 32 hex digits)", line);
1192189251Ssam		return -1;
1193189251Ssam	}
1194189251Ssam
1195189251Ssam	hash = os_malloc(16);
1196189251Ssam	if (hash == NULL)
1197189251Ssam		return -1;
1198189251Ssam
1199189251Ssam	if (hexstr2bin(value + 5, hash, 16)) {
1200189251Ssam		os_free(hash);
1201189251Ssam		wpa_printf(MSG_ERROR, "Line %d: Invalid password hash", line);
1202189251Ssam		return -1;
1203189251Ssam	}
1204189251Ssam
1205189251Ssam	wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16);
1206189251Ssam
1207189251Ssam	os_free(ssid->eap.password);
1208189251Ssam	ssid->eap.password = hash;
1209189251Ssam	ssid->eap.password_len = 16;
1210189251Ssam	ssid->eap.flags |= EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
1211189251Ssam
1212189251Ssam	return 0;
1213189251Ssam}
1214189251Ssam
1215189251Ssam
1216189251Ssamstatic char * wpa_config_write_password(const struct parse_data *data,
1217189251Ssam					struct wpa_ssid *ssid)
1218189251Ssam{
1219189251Ssam	char *buf;
1220189251Ssam
1221189251Ssam	if (ssid->eap.password == NULL)
1222189251Ssam		return NULL;
1223189251Ssam
1224189251Ssam	if (!(ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) {
1225189251Ssam		return wpa_config_write_string(
1226189251Ssam			ssid->eap.password, ssid->eap.password_len);
1227189251Ssam	}
1228189251Ssam
1229189251Ssam	buf = os_malloc(5 + 32 + 1);
1230189251Ssam	if (buf == NULL)
1231189251Ssam		return NULL;
1232189251Ssam
1233189251Ssam	os_memcpy(buf, "hash:", 5);
1234189251Ssam	wpa_snprintf_hex(buf + 5, 32 + 1, ssid->eap.password, 16);
1235189251Ssam
1236189251Ssam	return buf;
1237189251Ssam}
1238189251Ssam#endif /* IEEE8021X_EAPOL */
1239189251Ssam
1240189251Ssam
1241189251Ssamstatic int wpa_config_parse_wep_key(u8 *key, size_t *len, int line,
1242189251Ssam				    const char *value, int idx)
1243189251Ssam{
1244189251Ssam	char *buf, title[20];
1245189251Ssam	int res;
1246189251Ssam
1247189251Ssam	buf = wpa_config_parse_string(value, len);
1248189251Ssam	if (buf == NULL) {
1249189251Ssam		wpa_printf(MSG_ERROR, "Line %d: Invalid WEP key %d '%s'.",
1250189251Ssam			   line, idx, value);
1251189251Ssam		return -1;
1252189251Ssam	}
1253189251Ssam	if (*len > MAX_WEP_KEY_LEN) {
1254189251Ssam		wpa_printf(MSG_ERROR, "Line %d: Too long WEP key %d '%s'.",
1255189251Ssam			   line, idx, value);
1256189251Ssam		os_free(buf);
1257189251Ssam		return -1;
1258189251Ssam	}
1259189251Ssam	os_memcpy(key, buf, *len);
1260189251Ssam	os_free(buf);
1261189251Ssam	res = os_snprintf(title, sizeof(title), "wep_key%d", idx);
1262189251Ssam	if (res >= 0 && (size_t) res < sizeof(title))
1263189251Ssam		wpa_hexdump_key(MSG_MSGDUMP, title, key, *len);
1264189251Ssam	return 0;
1265189251Ssam}
1266189251Ssam
1267189251Ssam
1268189251Ssamstatic int wpa_config_parse_wep_key0(const struct parse_data *data,
1269189251Ssam				     struct wpa_ssid *ssid, int line,
1270189251Ssam				     const char *value)
1271189251Ssam{
1272189251Ssam	return wpa_config_parse_wep_key(ssid->wep_key[0],
1273189251Ssam					&ssid->wep_key_len[0], line,
1274189251Ssam					value, 0);
1275189251Ssam}
1276189251Ssam
1277189251Ssam
1278189251Ssamstatic int wpa_config_parse_wep_key1(const struct parse_data *data,
1279189251Ssam				     struct wpa_ssid *ssid, int line,
1280189251Ssam				     const char *value)
1281189251Ssam{
1282189251Ssam	return wpa_config_parse_wep_key(ssid->wep_key[1],
1283189251Ssam					&ssid->wep_key_len[1], line,
1284189251Ssam					value, 1);
1285189251Ssam}
1286189251Ssam
1287189251Ssam
1288189251Ssamstatic int wpa_config_parse_wep_key2(const struct parse_data *data,
1289189251Ssam				     struct wpa_ssid *ssid, int line,
1290189251Ssam				     const char *value)
1291189251Ssam{
1292189251Ssam	return wpa_config_parse_wep_key(ssid->wep_key[2],
1293189251Ssam					&ssid->wep_key_len[2], line,
1294189251Ssam					value, 2);
1295189251Ssam}
1296189251Ssam
1297189251Ssam
1298189251Ssamstatic int wpa_config_parse_wep_key3(const struct parse_data *data,
1299189251Ssam				     struct wpa_ssid *ssid, int line,
1300189251Ssam				     const char *value)
1301189251Ssam{
1302189251Ssam	return wpa_config_parse_wep_key(ssid->wep_key[3],
1303189251Ssam					&ssid->wep_key_len[3], line,
1304189251Ssam					value, 3);
1305189251Ssam}
1306189251Ssam
1307189251Ssam
1308189251Ssam#ifndef NO_CONFIG_WRITE
1309189251Ssamstatic char * wpa_config_write_wep_key(struct wpa_ssid *ssid, int idx)
1310189251Ssam{
1311189251Ssam	if (ssid->wep_key_len[idx] == 0)
1312189251Ssam		return NULL;
1313189251Ssam	return wpa_config_write_string(ssid->wep_key[idx],
1314189251Ssam				       ssid->wep_key_len[idx]);
1315189251Ssam}
1316189251Ssam
1317189251Ssam
1318189251Ssamstatic char * wpa_config_write_wep_key0(const struct parse_data *data,
1319189251Ssam					struct wpa_ssid *ssid)
1320189251Ssam{
1321189251Ssam	return wpa_config_write_wep_key(ssid, 0);
1322189251Ssam}
1323189251Ssam
1324189251Ssam
1325189251Ssamstatic char * wpa_config_write_wep_key1(const struct parse_data *data,
1326189251Ssam					struct wpa_ssid *ssid)
1327189251Ssam{
1328189251Ssam	return wpa_config_write_wep_key(ssid, 1);
1329189251Ssam}
1330189251Ssam
1331189251Ssam
1332189251Ssamstatic char * wpa_config_write_wep_key2(const struct parse_data *data,
1333189251Ssam					struct wpa_ssid *ssid)
1334189251Ssam{
1335189251Ssam	return wpa_config_write_wep_key(ssid, 2);
1336189251Ssam}
1337189251Ssam
1338189251Ssam
1339189251Ssamstatic char * wpa_config_write_wep_key3(const struct parse_data *data,
1340189251Ssam					struct wpa_ssid *ssid)
1341189251Ssam{
1342189251Ssam	return wpa_config_write_wep_key(ssid, 3);
1343189251Ssam}
1344189251Ssam#endif /* NO_CONFIG_WRITE */
1345189251Ssam
1346189251Ssam
1347189251Ssam/* Helper macros for network block parser */
1348189251Ssam
1349189251Ssam#ifdef OFFSET
1350189251Ssam#undef OFFSET
1351189251Ssam#endif /* OFFSET */
1352189251Ssam/* OFFSET: Get offset of a variable within the wpa_ssid structure */
1353189251Ssam#define OFFSET(v) ((void *) &((struct wpa_ssid *) 0)->v)
1354189251Ssam
1355189251Ssam/* STR: Define a string variable for an ASCII string; f = field name */
1356189251Ssam#ifdef NO_CONFIG_WRITE
1357189251Ssam#define _STR(f) #f, wpa_config_parse_str, OFFSET(f)
1358189251Ssam#define _STRe(f) #f, wpa_config_parse_str, OFFSET(eap.f)
1359189251Ssam#else /* NO_CONFIG_WRITE */
1360189251Ssam#define _STR(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(f)
1361189251Ssam#define _STRe(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(eap.f)
1362189251Ssam#endif /* NO_CONFIG_WRITE */
1363189251Ssam#define STR(f) _STR(f), NULL, NULL, NULL, 0
1364189251Ssam#define STRe(f) _STRe(f), NULL, NULL, NULL, 0
1365189251Ssam#define STR_KEY(f) _STR(f), NULL, NULL, NULL, 1
1366189251Ssam#define STR_KEYe(f) _STRe(f), NULL, NULL, NULL, 1
1367189251Ssam
1368189251Ssam/* STR_LEN: Define a string variable with a separate variable for storing the
1369189251Ssam * data length. Unlike STR(), this can be used to store arbitrary binary data
1370189251Ssam * (i.e., even nul termination character). */
1371189251Ssam#define _STR_LEN(f) _STR(f), OFFSET(f ## _len)
1372189251Ssam#define _STR_LENe(f) _STRe(f), OFFSET(eap.f ## _len)
1373189251Ssam#define STR_LEN(f) _STR_LEN(f), NULL, NULL, 0
1374189251Ssam#define STR_LENe(f) _STR_LENe(f), NULL, NULL, 0
1375189251Ssam#define STR_LEN_KEY(f) _STR_LEN(f), NULL, NULL, 1
1376189251Ssam
1377189251Ssam/* STR_RANGE: Like STR_LEN(), but with minimum and maximum allowed length
1378189251Ssam * explicitly specified. */
1379189251Ssam#define _STR_RANGE(f, min, max) _STR_LEN(f), (void *) (min), (void *) (max)
1380189251Ssam#define STR_RANGE(f, min, max) _STR_RANGE(f, min, max), 0
1381189251Ssam#define STR_RANGE_KEY(f, min, max) _STR_RANGE(f, min, max), 1
1382189251Ssam
1383189251Ssam#ifdef NO_CONFIG_WRITE
1384189251Ssam#define _INT(f) #f, wpa_config_parse_int, OFFSET(f), (void *) 0
1385189251Ssam#define _INTe(f) #f, wpa_config_parse_int, OFFSET(eap.f), (void *) 0
1386189251Ssam#else /* NO_CONFIG_WRITE */
1387189251Ssam#define _INT(f) #f, wpa_config_parse_int, wpa_config_write_int, \
1388189251Ssam	OFFSET(f), (void *) 0
1389189251Ssam#define _INTe(f) #f, wpa_config_parse_int, wpa_config_write_int, \
1390189251Ssam	OFFSET(eap.f), (void *) 0
1391189251Ssam#endif /* NO_CONFIG_WRITE */
1392189251Ssam
1393189251Ssam/* INT: Define an integer variable */
1394189251Ssam#define INT(f) _INT(f), NULL, NULL, 0
1395189251Ssam#define INTe(f) _INTe(f), NULL, NULL, 0
1396189251Ssam
1397189251Ssam/* INT_RANGE: Define an integer variable with allowed value range */
1398189251Ssam#define INT_RANGE(f, min, max) _INT(f), (void *) (min), (void *) (max), 0
1399189251Ssam
1400189251Ssam/* FUNC: Define a configuration variable that uses a custom function for
1401189251Ssam * parsing and writing the value. */
1402189251Ssam#ifdef NO_CONFIG_WRITE
1403189251Ssam#define _FUNC(f) #f, wpa_config_parse_ ## f, NULL, NULL, NULL, NULL
1404189251Ssam#else /* NO_CONFIG_WRITE */
1405189251Ssam#define _FUNC(f) #f, wpa_config_parse_ ## f, wpa_config_write_ ## f, \
1406189251Ssam	NULL, NULL, NULL, NULL
1407189251Ssam#endif /* NO_CONFIG_WRITE */
1408189251Ssam#define FUNC(f) _FUNC(f), 0
1409189251Ssam#define FUNC_KEY(f) _FUNC(f), 1
1410189251Ssam
1411189251Ssam/*
1412189251Ssam * Table of network configuration variables. This table is used to parse each
1413189251Ssam * network configuration variable, e.g., each line in wpa_supplicant.conf file
1414189251Ssam * that is inside a network block.
1415189251Ssam *
1416189251Ssam * This table is generated using the helper macros defined above and with
1417189251Ssam * generous help from the C pre-processor. The field name is stored as a string
1418189251Ssam * into .name and for STR and INT types, the offset of the target buffer within
1419189251Ssam * struct wpa_ssid is stored in .param1. .param2 (if not NULL) is similar
1420189251Ssam * offset to the field containing the length of the configuration variable.
1421189251Ssam * .param3 and .param4 can be used to mark the allowed range (length for STR
1422189251Ssam * and value for INT).
1423189251Ssam *
1424189251Ssam * For each configuration line in wpa_supplicant.conf, the parser goes through
1425189251Ssam * this table and select the entry that matches with the field name. The parser
1426189251Ssam * function (.parser) is then called to parse the actual value of the field.
1427189251Ssam *
1428189251Ssam * This kind of mechanism makes it easy to add new configuration parameters,
1429189251Ssam * since only one line needs to be added into this table and into the
1430189251Ssam * struct wpa_ssid definition if the new variable is either a string or
1431189251Ssam * integer. More complex types will need to use their own parser and writer
1432189251Ssam * functions.
1433189251Ssam */
1434189251Ssamstatic const struct parse_data ssid_fields[] = {
1435189251Ssam	{ STR_RANGE(ssid, 0, MAX_SSID_LEN) },
1436189251Ssam	{ INT_RANGE(scan_ssid, 0, 1) },
1437189251Ssam	{ FUNC(bssid) },
1438189251Ssam	{ FUNC_KEY(psk) },
1439189251Ssam	{ FUNC(proto) },
1440189251Ssam	{ FUNC(key_mgmt) },
1441189251Ssam	{ FUNC(pairwise) },
1442189251Ssam	{ FUNC(group) },
1443189251Ssam	{ FUNC(auth_alg) },
1444214734Srpaulo	{ FUNC(scan_freq) },
1445214734Srpaulo	{ FUNC(freq_list) },
1446189251Ssam#ifdef IEEE8021X_EAPOL
1447189251Ssam	{ FUNC(eap) },
1448189251Ssam	{ STR_LENe(identity) },
1449189251Ssam	{ STR_LENe(anonymous_identity) },
1450189251Ssam	{ FUNC_KEY(password) },
1451189251Ssam	{ STRe(ca_cert) },
1452189251Ssam	{ STRe(ca_path) },
1453189251Ssam	{ STRe(client_cert) },
1454189251Ssam	{ STRe(private_key) },
1455189251Ssam	{ STR_KEYe(private_key_passwd) },
1456189251Ssam	{ STRe(dh_file) },
1457189251Ssam	{ STRe(subject_match) },
1458189251Ssam	{ STRe(altsubject_match) },
1459189251Ssam	{ STRe(ca_cert2) },
1460189251Ssam	{ STRe(ca_path2) },
1461189251Ssam	{ STRe(client_cert2) },
1462189251Ssam	{ STRe(private_key2) },
1463189251Ssam	{ STR_KEYe(private_key2_passwd) },
1464189251Ssam	{ STRe(dh_file2) },
1465189251Ssam	{ STRe(subject_match2) },
1466189251Ssam	{ STRe(altsubject_match2) },
1467189251Ssam	{ STRe(phase1) },
1468189251Ssam	{ STRe(phase2) },
1469189251Ssam	{ STRe(pcsc) },
1470189251Ssam	{ STR_KEYe(pin) },
1471189251Ssam	{ STRe(engine_id) },
1472189251Ssam	{ STRe(key_id) },
1473189251Ssam	{ STRe(cert_id) },
1474189251Ssam	{ STRe(ca_cert_id) },
1475189251Ssam	{ STR_KEYe(pin2) },
1476189251Ssam	{ STRe(engine2_id) },
1477189251Ssam	{ STRe(key2_id) },
1478189251Ssam	{ STRe(cert2_id) },
1479189251Ssam	{ STRe(ca_cert2_id) },
1480189251Ssam	{ INTe(engine) },
1481189251Ssam	{ INTe(engine2) },
1482189251Ssam	{ INT(eapol_flags) },
1483189251Ssam#endif /* IEEE8021X_EAPOL */
1484189251Ssam	{ FUNC_KEY(wep_key0) },
1485189251Ssam	{ FUNC_KEY(wep_key1) },
1486189251Ssam	{ FUNC_KEY(wep_key2) },
1487189251Ssam	{ FUNC_KEY(wep_key3) },
1488189251Ssam	{ INT(wep_tx_keyidx) },
1489189251Ssam	{ INT(priority) },
1490189251Ssam#ifdef IEEE8021X_EAPOL
1491189251Ssam	{ INT(eap_workaround) },
1492189251Ssam	{ STRe(pac_file) },
1493189251Ssam	{ INTe(fragment_size) },
1494189251Ssam#endif /* IEEE8021X_EAPOL */
1495214734Srpaulo	{ INT_RANGE(mode, 0, 2) },
1496189251Ssam	{ INT_RANGE(proactive_key_caching, 0, 1) },
1497189251Ssam	{ INT_RANGE(disabled, 0, 1) },
1498189251Ssam	{ STR(id_str) },
1499189251Ssam#ifdef CONFIG_IEEE80211W
1500189251Ssam	{ INT_RANGE(ieee80211w, 0, 2) },
1501189251Ssam#endif /* CONFIG_IEEE80211W */
1502189251Ssam	{ INT_RANGE(peerkey, 0, 1) },
1503189251Ssam	{ INT_RANGE(mixed_cell, 0, 1) },
1504189251Ssam	{ INT_RANGE(frequency, 0, 10000) },
1505214734Srpaulo	{ INT(wpa_ptk_rekey) },
1506214734Srpaulo	{ STR(bgscan) },
1507189251Ssam};
1508189251Ssam
1509189251Ssam#undef OFFSET
1510189251Ssam#undef _STR
1511189251Ssam#undef STR
1512189251Ssam#undef STR_KEY
1513189251Ssam#undef _STR_LEN
1514189251Ssam#undef STR_LEN
1515189251Ssam#undef STR_LEN_KEY
1516189251Ssam#undef _STR_RANGE
1517189251Ssam#undef STR_RANGE
1518189251Ssam#undef STR_RANGE_KEY
1519189251Ssam#undef _INT
1520189251Ssam#undef INT
1521189251Ssam#undef INT_RANGE
1522189251Ssam#undef _FUNC
1523189251Ssam#undef FUNC
1524189251Ssam#undef FUNC_KEY
1525189251Ssam#define NUM_SSID_FIELDS (sizeof(ssid_fields) / sizeof(ssid_fields[0]))
1526189251Ssam
1527189251Ssam
1528189251Ssam/**
1529189251Ssam * wpa_config_add_prio_network - Add a network to priority lists
1530189251Ssam * @config: Configuration data from wpa_config_read()
1531189251Ssam * @ssid: Pointer to the network configuration to be added to the list
1532189251Ssam * Returns: 0 on success, -1 on failure
1533189251Ssam *
1534189251Ssam * This function is used to add a network block to the priority list of
1535189251Ssam * networks. This must be called for each network when reading in the full
1536189251Ssam * configuration. In addition, this can be used indirectly when updating
1537189251Ssam * priorities by calling wpa_config_update_prio_list().
1538189251Ssam */
1539189251Ssamint wpa_config_add_prio_network(struct wpa_config *config,
1540189251Ssam				struct wpa_ssid *ssid)
1541189251Ssam{
1542189251Ssam	int prio;
1543189251Ssam	struct wpa_ssid *prev, **nlist;
1544189251Ssam
1545189251Ssam	/*
1546189251Ssam	 * Add to an existing priority list if one is available for the
1547189251Ssam	 * configured priority level for this network.
1548189251Ssam	 */
1549189251Ssam	for (prio = 0; prio < config->num_prio; prio++) {
1550189251Ssam		prev = config->pssid[prio];
1551189251Ssam		if (prev->priority == ssid->priority) {
1552189251Ssam			while (prev->pnext)
1553189251Ssam				prev = prev->pnext;
1554189251Ssam			prev->pnext = ssid;
1555189251Ssam			return 0;
1556189251Ssam		}
1557189251Ssam	}
1558189251Ssam
1559189251Ssam	/* First network for this priority - add a new priority list */
1560189251Ssam	nlist = os_realloc(config->pssid,
1561189251Ssam			   (config->num_prio + 1) * sizeof(struct wpa_ssid *));
1562189251Ssam	if (nlist == NULL)
1563189251Ssam		return -1;
1564189251Ssam
1565189251Ssam	for (prio = 0; prio < config->num_prio; prio++) {
1566189251Ssam		if (nlist[prio]->priority < ssid->priority)
1567189251Ssam			break;
1568189251Ssam	}
1569189251Ssam
1570189251Ssam	os_memmove(&nlist[prio + 1], &nlist[prio],
1571189251Ssam		   (config->num_prio - prio) * sizeof(struct wpa_ssid *));
1572189251Ssam
1573189251Ssam	nlist[prio] = ssid;
1574189251Ssam	config->num_prio++;
1575189251Ssam	config->pssid = nlist;
1576189251Ssam
1577189251Ssam	return 0;
1578189251Ssam}
1579189251Ssam
1580189251Ssam
1581189251Ssam/**
1582189251Ssam * wpa_config_update_prio_list - Update network priority list
1583189251Ssam * @config: Configuration data from wpa_config_read()
1584189251Ssam * Returns: 0 on success, -1 on failure
1585189251Ssam *
1586189251Ssam * This function is called to update the priority list of networks in the
1587189251Ssam * configuration when a network is being added or removed. This is also called
1588189251Ssam * if a priority for a network is changed.
1589189251Ssam */
1590214734Srpauloint wpa_config_update_prio_list(struct wpa_config *config)
1591189251Ssam{
1592189251Ssam	struct wpa_ssid *ssid;
1593189251Ssam	int ret = 0;
1594189251Ssam
1595189251Ssam	os_free(config->pssid);
1596189251Ssam	config->pssid = NULL;
1597189251Ssam	config->num_prio = 0;
1598189251Ssam
1599189251Ssam	ssid = config->ssid;
1600189251Ssam	while (ssid) {
1601189251Ssam		ssid->pnext = NULL;
1602189251Ssam		if (wpa_config_add_prio_network(config, ssid) < 0)
1603189251Ssam			ret = -1;
1604189251Ssam		ssid = ssid->next;
1605189251Ssam	}
1606189251Ssam
1607189251Ssam	return ret;
1608189251Ssam}
1609189251Ssam
1610189251Ssam
1611189251Ssam#ifdef IEEE8021X_EAPOL
1612189251Ssamstatic void eap_peer_config_free(struct eap_peer_config *eap)
1613189251Ssam{
1614189251Ssam	os_free(eap->eap_methods);
1615189251Ssam	os_free(eap->identity);
1616189251Ssam	os_free(eap->anonymous_identity);
1617189251Ssam	os_free(eap->password);
1618189251Ssam	os_free(eap->ca_cert);
1619189251Ssam	os_free(eap->ca_path);
1620189251Ssam	os_free(eap->client_cert);
1621189251Ssam	os_free(eap->private_key);
1622189251Ssam	os_free(eap->private_key_passwd);
1623189251Ssam	os_free(eap->dh_file);
1624189251Ssam	os_free(eap->subject_match);
1625189251Ssam	os_free(eap->altsubject_match);
1626189251Ssam	os_free(eap->ca_cert2);
1627189251Ssam	os_free(eap->ca_path2);
1628189251Ssam	os_free(eap->client_cert2);
1629189251Ssam	os_free(eap->private_key2);
1630189251Ssam	os_free(eap->private_key2_passwd);
1631189251Ssam	os_free(eap->dh_file2);
1632189251Ssam	os_free(eap->subject_match2);
1633189251Ssam	os_free(eap->altsubject_match2);
1634189251Ssam	os_free(eap->phase1);
1635189251Ssam	os_free(eap->phase2);
1636189251Ssam	os_free(eap->pcsc);
1637189251Ssam	os_free(eap->pin);
1638189251Ssam	os_free(eap->engine_id);
1639189251Ssam	os_free(eap->key_id);
1640189251Ssam	os_free(eap->cert_id);
1641189251Ssam	os_free(eap->ca_cert_id);
1642189251Ssam	os_free(eap->key2_id);
1643189251Ssam	os_free(eap->cert2_id);
1644189251Ssam	os_free(eap->ca_cert2_id);
1645189251Ssam	os_free(eap->pin2);
1646189251Ssam	os_free(eap->engine2_id);
1647189251Ssam	os_free(eap->otp);
1648189251Ssam	os_free(eap->pending_req_otp);
1649189251Ssam	os_free(eap->pac_file);
1650189251Ssam	os_free(eap->new_password);
1651189251Ssam}
1652189251Ssam#endif /* IEEE8021X_EAPOL */
1653189251Ssam
1654189251Ssam
1655189251Ssam/**
1656189251Ssam * wpa_config_free_ssid - Free network/ssid configuration data
1657189251Ssam * @ssid: Configuration data for the network
1658189251Ssam *
1659189251Ssam * This function frees all resources allocated for the network configuration
1660189251Ssam * data.
1661189251Ssam */
1662189251Ssamvoid wpa_config_free_ssid(struct wpa_ssid *ssid)
1663189251Ssam{
1664189251Ssam	os_free(ssid->ssid);
1665189251Ssam	os_free(ssid->passphrase);
1666189251Ssam#ifdef IEEE8021X_EAPOL
1667189251Ssam	eap_peer_config_free(&ssid->eap);
1668189251Ssam#endif /* IEEE8021X_EAPOL */
1669189251Ssam	os_free(ssid->id_str);
1670214734Srpaulo	os_free(ssid->scan_freq);
1671214734Srpaulo	os_free(ssid->freq_list);
1672214734Srpaulo	os_free(ssid->bgscan);
1673189251Ssam	os_free(ssid);
1674189251Ssam}
1675189251Ssam
1676189251Ssam
1677189251Ssam/**
1678189251Ssam * wpa_config_free - Free configuration data
1679189251Ssam * @config: Configuration data from wpa_config_read()
1680189251Ssam *
1681189251Ssam * This function frees all resources allocated for the configuration data by
1682189251Ssam * wpa_config_read().
1683189251Ssam */
1684189251Ssamvoid wpa_config_free(struct wpa_config *config)
1685189251Ssam{
1686189251Ssam#ifndef CONFIG_NO_CONFIG_BLOBS
1687189251Ssam	struct wpa_config_blob *blob, *prevblob;
1688189251Ssam#endif /* CONFIG_NO_CONFIG_BLOBS */
1689189251Ssam	struct wpa_ssid *ssid, *prev = NULL;
1690189251Ssam	ssid = config->ssid;
1691189251Ssam	while (ssid) {
1692189251Ssam		prev = ssid;
1693189251Ssam		ssid = ssid->next;
1694189251Ssam		wpa_config_free_ssid(prev);
1695189251Ssam	}
1696189251Ssam
1697189251Ssam#ifndef CONFIG_NO_CONFIG_BLOBS
1698189251Ssam	blob = config->blobs;
1699189251Ssam	prevblob = NULL;
1700189251Ssam	while (blob) {
1701189251Ssam		prevblob = blob;
1702189251Ssam		blob = blob->next;
1703189251Ssam		wpa_config_free_blob(prevblob);
1704189251Ssam	}
1705189251Ssam#endif /* CONFIG_NO_CONFIG_BLOBS */
1706189251Ssam
1707189251Ssam	os_free(config->ctrl_interface);
1708189251Ssam	os_free(config->ctrl_interface_group);
1709189251Ssam	os_free(config->opensc_engine_path);
1710189251Ssam	os_free(config->pkcs11_engine_path);
1711189251Ssam	os_free(config->pkcs11_module_path);
1712189251Ssam	os_free(config->driver_param);
1713189251Ssam	os_free(config->device_name);
1714189251Ssam	os_free(config->manufacturer);
1715189251Ssam	os_free(config->model_name);
1716189251Ssam	os_free(config->model_number);
1717189251Ssam	os_free(config->serial_number);
1718189251Ssam	os_free(config->device_type);
1719214734Srpaulo	os_free(config->config_methods);
1720189251Ssam	os_free(config->pssid);
1721189251Ssam	os_free(config);
1722189251Ssam}
1723189251Ssam
1724189251Ssam
1725189251Ssam/**
1726189251Ssam * wpa_config_get_network - Get configured network based on id
1727189251Ssam * @config: Configuration data from wpa_config_read()
1728189251Ssam * @id: Unique network id to search for
1729189251Ssam * Returns: Network configuration or %NULL if not found
1730189251Ssam */
1731189251Ssamstruct wpa_ssid * wpa_config_get_network(struct wpa_config *config, int id)
1732189251Ssam{
1733189251Ssam	struct wpa_ssid *ssid;
1734189251Ssam
1735189251Ssam	ssid = config->ssid;
1736189251Ssam	while (ssid) {
1737189251Ssam		if (id == ssid->id)
1738189251Ssam			break;
1739189251Ssam		ssid = ssid->next;
1740189251Ssam	}
1741189251Ssam
1742189251Ssam	return ssid;
1743189251Ssam}
1744189251Ssam
1745189251Ssam
1746189251Ssam/**
1747189251Ssam * wpa_config_add_network - Add a new network with empty configuration
1748189251Ssam * @config: Configuration data from wpa_config_read()
1749189251Ssam * Returns: The new network configuration or %NULL if operation failed
1750189251Ssam */
1751189251Ssamstruct wpa_ssid * wpa_config_add_network(struct wpa_config *config)
1752189251Ssam{
1753189251Ssam	int id;
1754189251Ssam	struct wpa_ssid *ssid, *last = NULL;
1755189251Ssam
1756189251Ssam	id = -1;
1757189251Ssam	ssid = config->ssid;
1758189251Ssam	while (ssid) {
1759189251Ssam		if (ssid->id > id)
1760189251Ssam			id = ssid->id;
1761189251Ssam		last = ssid;
1762189251Ssam		ssid = ssid->next;
1763189251Ssam	}
1764189251Ssam	id++;
1765189251Ssam
1766189251Ssam	ssid = os_zalloc(sizeof(*ssid));
1767189251Ssam	if (ssid == NULL)
1768189251Ssam		return NULL;
1769189251Ssam	ssid->id = id;
1770189251Ssam	if (last)
1771189251Ssam		last->next = ssid;
1772189251Ssam	else
1773189251Ssam		config->ssid = ssid;
1774189251Ssam
1775189251Ssam	wpa_config_update_prio_list(config);
1776189251Ssam
1777189251Ssam	return ssid;
1778189251Ssam}
1779189251Ssam
1780189251Ssam
1781189251Ssam/**
1782189251Ssam * wpa_config_remove_network - Remove a configured network based on id
1783189251Ssam * @config: Configuration data from wpa_config_read()
1784189251Ssam * @id: Unique network id to search for
1785189251Ssam * Returns: 0 on success, or -1 if the network was not found
1786189251Ssam */
1787189251Ssamint wpa_config_remove_network(struct wpa_config *config, int id)
1788189251Ssam{
1789189251Ssam	struct wpa_ssid *ssid, *prev = NULL;
1790189251Ssam
1791189251Ssam	ssid = config->ssid;
1792189251Ssam	while (ssid) {
1793189251Ssam		if (id == ssid->id)
1794189251Ssam			break;
1795189251Ssam		prev = ssid;
1796189251Ssam		ssid = ssid->next;
1797189251Ssam	}
1798189251Ssam
1799189251Ssam	if (ssid == NULL)
1800189251Ssam		return -1;
1801189251Ssam
1802189251Ssam	if (prev)
1803189251Ssam		prev->next = ssid->next;
1804189251Ssam	else
1805189251Ssam		config->ssid = ssid->next;
1806189251Ssam
1807189251Ssam	wpa_config_update_prio_list(config);
1808189251Ssam	wpa_config_free_ssid(ssid);
1809189251Ssam	return 0;
1810189251Ssam}
1811189251Ssam
1812189251Ssam
1813189251Ssam/**
1814189251Ssam * wpa_config_set_network_defaults - Set network default values
1815189251Ssam * @ssid: Pointer to network configuration data
1816189251Ssam */
1817189251Ssamvoid wpa_config_set_network_defaults(struct wpa_ssid *ssid)
1818189251Ssam{
1819189251Ssam	ssid->proto = DEFAULT_PROTO;
1820189251Ssam	ssid->pairwise_cipher = DEFAULT_PAIRWISE;
1821189251Ssam	ssid->group_cipher = DEFAULT_GROUP;
1822189251Ssam	ssid->key_mgmt = DEFAULT_KEY_MGMT;
1823189251Ssam#ifdef IEEE8021X_EAPOL
1824189251Ssam	ssid->eapol_flags = DEFAULT_EAPOL_FLAGS;
1825189251Ssam	ssid->eap_workaround = DEFAULT_EAP_WORKAROUND;
1826189251Ssam	ssid->eap.fragment_size = DEFAULT_FRAGMENT_SIZE;
1827189251Ssam#endif /* IEEE8021X_EAPOL */
1828189251Ssam}
1829189251Ssam
1830189251Ssam
1831189251Ssam/**
1832189251Ssam * wpa_config_set - Set a variable in network configuration
1833189251Ssam * @ssid: Pointer to network configuration data
1834189251Ssam * @var: Variable name, e.g., "ssid"
1835189251Ssam * @value: Variable value
1836189251Ssam * @line: Line number in configuration file or 0 if not used
1837189251Ssam * Returns: 0 on success, -1 on failure
1838189251Ssam *
1839189251Ssam * This function can be used to set network configuration variables based on
1840189251Ssam * both the configuration file and management interface input. The value
1841189251Ssam * parameter must be in the same format as the text-based configuration file is
1842189251Ssam * using. For example, strings are using double quotation marks.
1843189251Ssam */
1844189251Ssamint wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
1845189251Ssam		   int line)
1846189251Ssam{
1847189251Ssam	size_t i;
1848189251Ssam	int ret = 0;
1849189251Ssam
1850189251Ssam	if (ssid == NULL || var == NULL || value == NULL)
1851189251Ssam		return -1;
1852189251Ssam
1853189251Ssam	for (i = 0; i < NUM_SSID_FIELDS; i++) {
1854189251Ssam		const struct parse_data *field = &ssid_fields[i];
1855189251Ssam		if (os_strcmp(var, field->name) != 0)
1856189251Ssam			continue;
1857189251Ssam
1858189251Ssam		if (field->parser(field, ssid, line, value)) {
1859189251Ssam			if (line) {
1860189251Ssam				wpa_printf(MSG_ERROR, "Line %d: failed to "
1861189251Ssam					   "parse %s '%s'.", line, var, value);
1862189251Ssam			}
1863189251Ssam			ret = -1;
1864189251Ssam		}
1865189251Ssam		break;
1866189251Ssam	}
1867189251Ssam	if (i == NUM_SSID_FIELDS) {
1868189251Ssam		if (line) {
1869189251Ssam			wpa_printf(MSG_ERROR, "Line %d: unknown network field "
1870189251Ssam				   "'%s'.", line, var);
1871189251Ssam		}
1872189251Ssam		ret = -1;
1873189251Ssam	}
1874189251Ssam
1875189251Ssam	return ret;
1876189251Ssam}
1877189251Ssam
1878189251Ssam
1879214734Srpaulo/**
1880214734Srpaulo * wpa_config_get_all - Get all options from network configuration
1881214734Srpaulo * @ssid: Pointer to network configuration data
1882214734Srpaulo * @get_keys: Determines if keys/passwords will be included in returned list
1883214734Srpaulo * Returns: %NULL terminated list of all set keys and their values in the form
1884214734Srpaulo * of [key1, val1, key2, val2, ... , NULL]
1885214734Srpaulo *
1886214734Srpaulo * This function can be used to get list of all configured network properties.
1887214734Srpaulo * The caller is responsible for freeing the returned list and all its
1888214734Srpaulo * elements.
1889214734Srpaulo */
1890214734Srpaulochar ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys)
1891214734Srpaulo{
1892214734Srpaulo	const struct parse_data *field;
1893214734Srpaulo	char *key, *value;
1894214734Srpaulo	size_t i;
1895214734Srpaulo	char **props;
1896214734Srpaulo	int fields_num;
1897214734Srpaulo
1898214734Srpaulo	props = os_zalloc(sizeof(char *) * ((2 * NUM_SSID_FIELDS) + 1));
1899214734Srpaulo	if (!props)
1900214734Srpaulo		return NULL;
1901214734Srpaulo
1902214734Srpaulo	fields_num = 0;
1903214734Srpaulo	for (i = 0; i < NUM_SSID_FIELDS; i++) {
1904214734Srpaulo		field = &ssid_fields[i];
1905214734Srpaulo		if (field->key_data && !get_keys)
1906214734Srpaulo			continue;
1907214734Srpaulo		value = field->writer(field, ssid);
1908214734Srpaulo		if (value == NULL)
1909214734Srpaulo			continue;
1910214734Srpaulo		if (os_strlen(value) == 0) {
1911214734Srpaulo			os_free(value);
1912214734Srpaulo			continue;
1913214734Srpaulo		}
1914214734Srpaulo
1915214734Srpaulo		key = os_strdup(field->name);
1916214734Srpaulo		if (key == NULL) {
1917214734Srpaulo			os_free(value);
1918214734Srpaulo			goto err;
1919214734Srpaulo		}
1920214734Srpaulo
1921214734Srpaulo		props[fields_num * 2] = key;
1922214734Srpaulo		props[fields_num * 2 + 1] = value;
1923214734Srpaulo
1924214734Srpaulo		fields_num++;
1925214734Srpaulo	}
1926214734Srpaulo
1927214734Srpaulo	return props;
1928214734Srpaulo
1929214734Srpauloerr:
1930214734Srpaulo	value = *props;
1931214734Srpaulo	while (value)
1932214734Srpaulo		os_free(value++);
1933214734Srpaulo	os_free(props);
1934214734Srpaulo	return NULL;
1935214734Srpaulo}
1936214734Srpaulo
1937214734Srpaulo
1938189251Ssam#ifndef NO_CONFIG_WRITE
1939189251Ssam/**
1940189251Ssam * wpa_config_get - Get a variable in network configuration
1941189251Ssam * @ssid: Pointer to network configuration data
1942189251Ssam * @var: Variable name, e.g., "ssid"
1943189251Ssam * Returns: Value of the variable or %NULL on failure
1944189251Ssam *
1945189251Ssam * This function can be used to get network configuration variables. The
1946189251Ssam * returned value is a copy of the configuration variable in text format, i.e,.
1947189251Ssam * the same format that the text-based configuration file and wpa_config_set()
1948189251Ssam * are using for the value. The caller is responsible for freeing the returned
1949189251Ssam * value.
1950189251Ssam */
1951189251Ssamchar * wpa_config_get(struct wpa_ssid *ssid, const char *var)
1952189251Ssam{
1953189251Ssam	size_t i;
1954189251Ssam
1955189251Ssam	if (ssid == NULL || var == NULL)
1956189251Ssam		return NULL;
1957189251Ssam
1958189251Ssam	for (i = 0; i < NUM_SSID_FIELDS; i++) {
1959189251Ssam		const struct parse_data *field = &ssid_fields[i];
1960189251Ssam		if (os_strcmp(var, field->name) == 0)
1961189251Ssam			return field->writer(field, ssid);
1962189251Ssam	}
1963189251Ssam
1964189251Ssam	return NULL;
1965189251Ssam}
1966189251Ssam
1967189251Ssam
1968189251Ssam/**
1969189251Ssam * wpa_config_get_no_key - Get a variable in network configuration (no keys)
1970189251Ssam * @ssid: Pointer to network configuration data
1971189251Ssam * @var: Variable name, e.g., "ssid"
1972189251Ssam * Returns: Value of the variable or %NULL on failure
1973189251Ssam *
1974189251Ssam * This function can be used to get network configuration variable like
1975189251Ssam * wpa_config_get(). The only difference is that this functions does not expose
1976189251Ssam * key/password material from the configuration. In case a key/password field
1977189251Ssam * is requested, the returned value is an empty string or %NULL if the variable
1978189251Ssam * is not set or "*" if the variable is set (regardless of its value). The
1979189251Ssam * returned value is a copy of the configuration variable in text format, i.e,.
1980189251Ssam * the same format that the text-based configuration file and wpa_config_set()
1981189251Ssam * are using for the value. The caller is responsible for freeing the returned
1982189251Ssam * value.
1983189251Ssam */
1984189251Ssamchar * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var)
1985189251Ssam{
1986189251Ssam	size_t i;
1987189251Ssam
1988189251Ssam	if (ssid == NULL || var == NULL)
1989189251Ssam		return NULL;
1990189251Ssam
1991189251Ssam	for (i = 0; i < NUM_SSID_FIELDS; i++) {
1992189251Ssam		const struct parse_data *field = &ssid_fields[i];
1993189251Ssam		if (os_strcmp(var, field->name) == 0) {
1994189251Ssam			char *res = field->writer(field, ssid);
1995189251Ssam			if (field->key_data) {
1996189251Ssam				if (res && res[0]) {
1997189251Ssam					wpa_printf(MSG_DEBUG, "Do not allow "
1998189251Ssam						   "key_data field to be "
1999189251Ssam						   "exposed");
2000189251Ssam					os_free(res);
2001189251Ssam					return os_strdup("*");
2002189251Ssam				}
2003189251Ssam
2004189251Ssam				os_free(res);
2005189251Ssam				return NULL;
2006189251Ssam			}
2007189251Ssam			return res;
2008189251Ssam		}
2009189251Ssam	}
2010189251Ssam
2011189251Ssam	return NULL;
2012189251Ssam}
2013189251Ssam#endif /* NO_CONFIG_WRITE */
2014189251Ssam
2015189251Ssam
2016189251Ssam/**
2017189251Ssam * wpa_config_update_psk - Update WPA PSK based on passphrase and SSID
2018189251Ssam * @ssid: Pointer to network configuration data
2019189251Ssam *
2020189251Ssam * This function must be called to update WPA PSK when either SSID or the
2021189251Ssam * passphrase has changed for the network configuration.
2022189251Ssam */
2023189251Ssamvoid wpa_config_update_psk(struct wpa_ssid *ssid)
2024189251Ssam{
2025189251Ssam#ifndef CONFIG_NO_PBKDF2
2026189251Ssam	pbkdf2_sha1(ssid->passphrase,
2027189251Ssam		    (char *) ssid->ssid, ssid->ssid_len, 4096,
2028189251Ssam		    ssid->psk, PMK_LEN);
2029189251Ssam	wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
2030189251Ssam			ssid->psk, PMK_LEN);
2031189251Ssam	ssid->psk_set = 1;
2032189251Ssam#endif /* CONFIG_NO_PBKDF2 */
2033189251Ssam}
2034189251Ssam
2035189251Ssam
2036189251Ssam#ifndef CONFIG_NO_CONFIG_BLOBS
2037189251Ssam/**
2038189251Ssam * wpa_config_get_blob - Get a named configuration blob
2039189251Ssam * @config: Configuration data from wpa_config_read()
2040189251Ssam * @name: Name of the blob
2041189251Ssam * Returns: Pointer to blob data or %NULL if not found
2042189251Ssam */
2043189251Ssamconst struct wpa_config_blob * wpa_config_get_blob(struct wpa_config *config,
2044189251Ssam						   const char *name)
2045189251Ssam{
2046189251Ssam	struct wpa_config_blob *blob = config->blobs;
2047189251Ssam
2048189251Ssam	while (blob) {
2049189251Ssam		if (os_strcmp(blob->name, name) == 0)
2050189251Ssam			return blob;
2051189251Ssam		blob = blob->next;
2052189251Ssam	}
2053189251Ssam	return NULL;
2054189251Ssam}
2055189251Ssam
2056189251Ssam
2057189251Ssam/**
2058189251Ssam * wpa_config_set_blob - Set or add a named configuration blob
2059189251Ssam * @config: Configuration data from wpa_config_read()
2060189251Ssam * @blob: New value for the blob
2061189251Ssam *
2062189251Ssam * Adds a new configuration blob or replaces the current value of an existing
2063189251Ssam * blob.
2064189251Ssam */
2065189251Ssamvoid wpa_config_set_blob(struct wpa_config *config,
2066189251Ssam			 struct wpa_config_blob *blob)
2067189251Ssam{
2068189251Ssam	wpa_config_remove_blob(config, blob->name);
2069189251Ssam	blob->next = config->blobs;
2070189251Ssam	config->blobs = blob;
2071189251Ssam}
2072189251Ssam
2073189251Ssam
2074189251Ssam/**
2075189251Ssam * wpa_config_free_blob - Free blob data
2076189251Ssam * @blob: Pointer to blob to be freed
2077189251Ssam */
2078189251Ssamvoid wpa_config_free_blob(struct wpa_config_blob *blob)
2079189251Ssam{
2080189251Ssam	if (blob) {
2081189251Ssam		os_free(blob->name);
2082189251Ssam		os_free(blob->data);
2083189251Ssam		os_free(blob);
2084189251Ssam	}
2085189251Ssam}
2086189251Ssam
2087189251Ssam
2088189251Ssam/**
2089189251Ssam * wpa_config_remove_blob - Remove a named configuration blob
2090189251Ssam * @config: Configuration data from wpa_config_read()
2091189251Ssam * @name: Name of the blob to remove
2092189251Ssam * Returns: 0 if blob was removed or -1 if blob was not found
2093189251Ssam */
2094189251Ssamint wpa_config_remove_blob(struct wpa_config *config, const char *name)
2095189251Ssam{
2096189251Ssam	struct wpa_config_blob *pos = config->blobs, *prev = NULL;
2097189251Ssam
2098189251Ssam	while (pos) {
2099189251Ssam		if (os_strcmp(pos->name, name) == 0) {
2100189251Ssam			if (prev)
2101189251Ssam				prev->next = pos->next;
2102189251Ssam			else
2103189251Ssam				config->blobs = pos->next;
2104189251Ssam			wpa_config_free_blob(pos);
2105189251Ssam			return 0;
2106189251Ssam		}
2107189251Ssam		prev = pos;
2108189251Ssam		pos = pos->next;
2109189251Ssam	}
2110189251Ssam
2111189251Ssam	return -1;
2112189251Ssam}
2113189251Ssam#endif /* CONFIG_NO_CONFIG_BLOBS */
2114189251Ssam
2115189251Ssam
2116189251Ssam/**
2117189251Ssam * wpa_config_alloc_empty - Allocate an empty configuration
2118189251Ssam * @ctrl_interface: Control interface parameters, e.g., path to UNIX domain
2119189251Ssam * socket
2120189251Ssam * @driver_param: Driver parameters
2121189251Ssam * Returns: Pointer to allocated configuration data or %NULL on failure
2122189251Ssam */
2123189251Ssamstruct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
2124189251Ssam					   const char *driver_param)
2125189251Ssam{
2126189251Ssam	struct wpa_config *config;
2127189251Ssam
2128189251Ssam	config = os_zalloc(sizeof(*config));
2129189251Ssam	if (config == NULL)
2130189251Ssam		return NULL;
2131189251Ssam	config->eapol_version = DEFAULT_EAPOL_VERSION;
2132189251Ssam	config->ap_scan = DEFAULT_AP_SCAN;
2133189251Ssam	config->fast_reauth = DEFAULT_FAST_REAUTH;
2134214734Srpaulo	config->bss_max_count = DEFAULT_BSS_MAX_COUNT;
2135189251Ssam
2136189251Ssam	if (ctrl_interface)
2137189251Ssam		config->ctrl_interface = os_strdup(ctrl_interface);
2138189251Ssam	if (driver_param)
2139189251Ssam		config->driver_param = os_strdup(driver_param);
2140189251Ssam
2141189251Ssam	return config;
2142189251Ssam}
2143189251Ssam
2144189251Ssam
2145189251Ssam#ifndef CONFIG_NO_STDOUT_DEBUG
2146189251Ssam/**
2147189251Ssam * wpa_config_debug_dump_networks - Debug dump of configured networks
2148189251Ssam * @config: Configuration data from wpa_config_read()
2149189251Ssam */
2150189251Ssamvoid wpa_config_debug_dump_networks(struct wpa_config *config)
2151189251Ssam{
2152189251Ssam	int prio;
2153189251Ssam	struct wpa_ssid *ssid;
2154189251Ssam
2155189251Ssam	for (prio = 0; prio < config->num_prio; prio++) {
2156189251Ssam		ssid = config->pssid[prio];
2157189251Ssam		wpa_printf(MSG_DEBUG, "Priority group %d",
2158189251Ssam			   ssid->priority);
2159189251Ssam		while (ssid) {
2160189251Ssam			wpa_printf(MSG_DEBUG, "   id=%d ssid='%s'",
2161189251Ssam				   ssid->id,
2162189251Ssam				   wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
2163189251Ssam			ssid = ssid->pnext;
2164189251Ssam		}
2165189251Ssam	}
2166189251Ssam}
2167189251Ssam#endif /* CONFIG_NO_STDOUT_DEBUG */
2168