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