1189251Ssam/* 2189251Ssam * WPA Supplicant / Configuration parser and common functions 3346981Scy * Copyright (c) 2003-2018, Jouni Malinen <j@w1.fi> 4189251Ssam * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7189251Ssam */ 8189251Ssam 9189251Ssam#include "includes.h" 10189251Ssam 11189251Ssam#include "common.h" 12252726Srpaulo#include "utils/uuid.h" 13281806Srpaulo#include "utils/ip_addr.h" 14346981Scy#include "common/ieee802_1x_defs.h" 15214734Srpaulo#include "crypto/sha1.h" 16214734Srpaulo#include "rsn_supp/wpa.h" 17189251Ssam#include "eap_peer/eap.h" 18252726Srpaulo#include "p2p/p2p.h" 19289549Srpaulo#include "fst/fst.h" 20189251Ssam#include "config.h" 21189251Ssam 22189251Ssam 23189251Ssam#if !defined(CONFIG_CTRL_IFACE) && defined(CONFIG_NO_CONFIG_WRITE) 24189251Ssam#define NO_CONFIG_WRITE 25189251Ssam#endif 26189251Ssam 27189251Ssam/* 28189251Ssam * Structure for network configuration parsing. This data is used to implement 29189251Ssam * a generic parser for each network block variable. The table of configuration 30189251Ssam * variables is defined below in this file (ssid_fields[]). 31189251Ssam */ 32189251Ssamstruct parse_data { 33189251Ssam /* Configuration variable name */ 34189251Ssam char *name; 35189251Ssam 36337817Scy /* Parser function for this variable. The parser functions return 0 or 1 37337817Scy * to indicate success. Value 0 indicates that the parameter value may 38337817Scy * have changed while value 1 means that the value did not change. 39337817Scy * Error cases (failure to parse the string) are indicated by returning 40337817Scy * -1. */ 41189251Ssam int (*parser)(const struct parse_data *data, struct wpa_ssid *ssid, 42189251Ssam int line, const char *value); 43189251Ssam 44189251Ssam#ifndef NO_CONFIG_WRITE 45189251Ssam /* Writer function (i.e., to get the variable in text format from 46189251Ssam * internal presentation). */ 47189251Ssam char * (*writer)(const struct parse_data *data, struct wpa_ssid *ssid); 48189251Ssam#endif /* NO_CONFIG_WRITE */ 49189251Ssam 50189251Ssam /* Variable specific parameters for the parser. */ 51189251Ssam void *param1, *param2, *param3, *param4; 52189251Ssam 53189251Ssam /* 0 = this variable can be included in debug output and ctrl_iface 54189251Ssam * 1 = this variable contains key/private data and it must not be 55189251Ssam * included in debug output unless explicitly requested. In 56189251Ssam * addition, this variable will not be readable through the 57189251Ssam * ctrl_iface. 58189251Ssam */ 59189251Ssam int key_data; 60189251Ssam}; 61189251Ssam 62189251Ssam 63189251Ssamstatic int wpa_config_parse_str(const struct parse_data *data, 64189251Ssam struct wpa_ssid *ssid, 65189251Ssam int line, const char *value) 66189251Ssam{ 67337817Scy size_t res_len, *dst_len, prev_len; 68189251Ssam char **dst, *tmp; 69189251Ssam 70189251Ssam if (os_strcmp(value, "NULL") == 0) { 71189251Ssam wpa_printf(MSG_DEBUG, "Unset configuration string '%s'", 72189251Ssam data->name); 73189251Ssam tmp = NULL; 74189251Ssam res_len = 0; 75189251Ssam goto set; 76189251Ssam } 77189251Ssam 78189251Ssam tmp = wpa_config_parse_string(value, &res_len); 79189251Ssam if (tmp == NULL) { 80189251Ssam wpa_printf(MSG_ERROR, "Line %d: failed to parse %s '%s'.", 81189251Ssam line, data->name, 82189251Ssam data->key_data ? "[KEY DATA REMOVED]" : value); 83189251Ssam return -1; 84189251Ssam } 85189251Ssam 86189251Ssam if (data->key_data) { 87189251Ssam wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name, 88189251Ssam (u8 *) tmp, res_len); 89189251Ssam } else { 90189251Ssam wpa_hexdump_ascii(MSG_MSGDUMP, data->name, 91189251Ssam (u8 *) tmp, res_len); 92189251Ssam } 93189251Ssam 94189251Ssam if (data->param3 && res_len < (size_t) data->param3) { 95189251Ssam wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu " 96189251Ssam "min_len=%ld)", line, data->name, 97189251Ssam (unsigned long) res_len, (long) data->param3); 98189251Ssam os_free(tmp); 99189251Ssam return -1; 100189251Ssam } 101189251Ssam 102189251Ssam if (data->param4 && res_len > (size_t) data->param4) { 103189251Ssam wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu " 104189251Ssam "max_len=%ld)", line, data->name, 105189251Ssam (unsigned long) res_len, (long) data->param4); 106189251Ssam os_free(tmp); 107189251Ssam return -1; 108189251Ssam } 109189251Ssam 110189251Ssamset: 111189251Ssam dst = (char **) (((u8 *) ssid) + (long) data->param1); 112189251Ssam dst_len = (size_t *) (((u8 *) ssid) + (long) data->param2); 113337817Scy 114337817Scy if (data->param2) 115337817Scy prev_len = *dst_len; 116337817Scy else if (*dst) 117337817Scy prev_len = os_strlen(*dst); 118337817Scy else 119337817Scy prev_len = 0; 120337817Scy if ((*dst == NULL && tmp == NULL) || 121337817Scy (*dst && tmp && prev_len == res_len && 122337817Scy os_memcmp(*dst, tmp, res_len) == 0)) { 123337817Scy /* No change to the previously configured value */ 124337817Scy os_free(tmp); 125337817Scy return 1; 126337817Scy } 127337817Scy 128189251Ssam os_free(*dst); 129189251Ssam *dst = tmp; 130189251Ssam if (data->param2) 131189251Ssam *dst_len = res_len; 132189251Ssam 133189251Ssam return 0; 134189251Ssam} 135189251Ssam 136189251Ssam 137189251Ssam#ifndef NO_CONFIG_WRITE 138189251Ssamstatic char * wpa_config_write_string_ascii(const u8 *value, size_t len) 139189251Ssam{ 140189251Ssam char *buf; 141189251Ssam 142189251Ssam buf = os_malloc(len + 3); 143189251Ssam if (buf == NULL) 144189251Ssam return NULL; 145189251Ssam buf[0] = '"'; 146189251Ssam os_memcpy(buf + 1, value, len); 147189251Ssam buf[len + 1] = '"'; 148189251Ssam buf[len + 2] = '\0'; 149189251Ssam 150189251Ssam return buf; 151189251Ssam} 152189251Ssam 153189251Ssam 154189251Ssamstatic char * wpa_config_write_string_hex(const u8 *value, size_t len) 155189251Ssam{ 156189251Ssam char *buf; 157189251Ssam 158189251Ssam buf = os_zalloc(2 * len + 1); 159189251Ssam if (buf == NULL) 160189251Ssam return NULL; 161189251Ssam wpa_snprintf_hex(buf, 2 * len + 1, value, len); 162189251Ssam 163189251Ssam return buf; 164189251Ssam} 165189251Ssam 166189251Ssam 167189251Ssamstatic char * wpa_config_write_string(const u8 *value, size_t len) 168189251Ssam{ 169189251Ssam if (value == NULL) 170189251Ssam return NULL; 171189251Ssam 172189251Ssam if (is_hex(value, len)) 173189251Ssam return wpa_config_write_string_hex(value, len); 174189251Ssam else 175189251Ssam return wpa_config_write_string_ascii(value, len); 176189251Ssam} 177189251Ssam 178189251Ssam 179189251Ssamstatic char * wpa_config_write_str(const struct parse_data *data, 180189251Ssam struct wpa_ssid *ssid) 181189251Ssam{ 182189251Ssam size_t len; 183189251Ssam char **src; 184189251Ssam 185189251Ssam src = (char **) (((u8 *) ssid) + (long) data->param1); 186189251Ssam if (*src == NULL) 187189251Ssam return NULL; 188189251Ssam 189189251Ssam if (data->param2) 190189251Ssam len = *((size_t *) (((u8 *) ssid) + (long) data->param2)); 191189251Ssam else 192189251Ssam len = os_strlen(*src); 193189251Ssam 194189251Ssam return wpa_config_write_string((const u8 *) *src, len); 195189251Ssam} 196189251Ssam#endif /* NO_CONFIG_WRITE */ 197189251Ssam 198189251Ssam 199189251Ssamstatic int wpa_config_parse_int(const struct parse_data *data, 200189251Ssam struct wpa_ssid *ssid, 201189251Ssam int line, const char *value) 202189251Ssam{ 203281806Srpaulo int val, *dst; 204281806Srpaulo char *end; 205189251Ssam 206189251Ssam dst = (int *) (((u8 *) ssid) + (long) data->param1); 207281806Srpaulo val = strtol(value, &end, 0); 208281806Srpaulo if (*end) { 209281806Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid number \"%s\"", 210281806Srpaulo line, value); 211281806Srpaulo return -1; 212281806Srpaulo } 213337817Scy 214337817Scy if (*dst == val) 215337817Scy return 1; 216281806Srpaulo *dst = val; 217189251Ssam wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst); 218189251Ssam 219189251Ssam if (data->param3 && *dst < (long) data->param3) { 220189251Ssam wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d " 221189251Ssam "min_value=%ld)", line, data->name, *dst, 222189251Ssam (long) data->param3); 223189251Ssam *dst = (long) data->param3; 224189251Ssam return -1; 225189251Ssam } 226189251Ssam 227189251Ssam if (data->param4 && *dst > (long) data->param4) { 228189251Ssam wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d " 229189251Ssam "max_value=%ld)", line, data->name, *dst, 230189251Ssam (long) data->param4); 231189251Ssam *dst = (long) data->param4; 232189251Ssam return -1; 233189251Ssam } 234189251Ssam 235189251Ssam return 0; 236189251Ssam} 237189251Ssam 238189251Ssam 239189251Ssam#ifndef NO_CONFIG_WRITE 240189251Ssamstatic char * wpa_config_write_int(const struct parse_data *data, 241189251Ssam struct wpa_ssid *ssid) 242189251Ssam{ 243189251Ssam int *src, res; 244189251Ssam char *value; 245189251Ssam 246189251Ssam src = (int *) (((u8 *) ssid) + (long) data->param1); 247189251Ssam 248189251Ssam value = os_malloc(20); 249189251Ssam if (value == NULL) 250189251Ssam return NULL; 251189251Ssam res = os_snprintf(value, 20, "%d", *src); 252281806Srpaulo if (os_snprintf_error(20, res)) { 253189251Ssam os_free(value); 254189251Ssam return NULL; 255189251Ssam } 256189251Ssam value[20 - 1] = '\0'; 257189251Ssam return value; 258189251Ssam} 259189251Ssam#endif /* NO_CONFIG_WRITE */ 260189251Ssam 261189251Ssam 262281806Srpaulostatic int wpa_config_parse_addr_list(const struct parse_data *data, 263281806Srpaulo int line, const char *value, 264281806Srpaulo u8 **list, size_t *num, char *name, 265281806Srpaulo u8 abort_on_error, u8 masked) 266281806Srpaulo{ 267281806Srpaulo const char *pos; 268281806Srpaulo u8 *buf, *n, addr[2 * ETH_ALEN]; 269281806Srpaulo size_t count; 270281806Srpaulo 271281806Srpaulo buf = NULL; 272281806Srpaulo count = 0; 273281806Srpaulo 274281806Srpaulo pos = value; 275281806Srpaulo while (pos && *pos) { 276281806Srpaulo while (*pos == ' ') 277281806Srpaulo pos++; 278281806Srpaulo 279281806Srpaulo if (hwaddr_masked_aton(pos, addr, &addr[ETH_ALEN], masked)) { 280281806Srpaulo if (abort_on_error || count == 0) { 281281806Srpaulo wpa_printf(MSG_ERROR, 282281806Srpaulo "Line %d: Invalid %s address '%s'", 283281806Srpaulo line, name, value); 284281806Srpaulo os_free(buf); 285281806Srpaulo return -1; 286281806Srpaulo } 287281806Srpaulo /* continue anyway since this could have been from a 288281806Srpaulo * truncated configuration file line */ 289281806Srpaulo wpa_printf(MSG_INFO, 290281806Srpaulo "Line %d: Ignore likely truncated %s address '%s'", 291281806Srpaulo line, name, pos); 292281806Srpaulo } else { 293281806Srpaulo n = os_realloc_array(buf, count + 1, 2 * ETH_ALEN); 294281806Srpaulo if (n == NULL) { 295281806Srpaulo os_free(buf); 296281806Srpaulo return -1; 297281806Srpaulo } 298281806Srpaulo buf = n; 299281806Srpaulo os_memmove(buf + 2 * ETH_ALEN, buf, 300281806Srpaulo count * 2 * ETH_ALEN); 301281806Srpaulo os_memcpy(buf, addr, 2 * ETH_ALEN); 302281806Srpaulo count++; 303281806Srpaulo wpa_printf(MSG_MSGDUMP, 304281806Srpaulo "%s: addr=" MACSTR " mask=" MACSTR, 305281806Srpaulo name, MAC2STR(addr), 306281806Srpaulo MAC2STR(&addr[ETH_ALEN])); 307281806Srpaulo } 308281806Srpaulo 309281806Srpaulo pos = os_strchr(pos, ' '); 310281806Srpaulo } 311281806Srpaulo 312281806Srpaulo os_free(*list); 313281806Srpaulo *list = buf; 314281806Srpaulo *num = count; 315281806Srpaulo 316281806Srpaulo return 0; 317281806Srpaulo} 318281806Srpaulo 319281806Srpaulo 320281806Srpaulo#ifndef NO_CONFIG_WRITE 321281806Srpaulostatic char * wpa_config_write_addr_list(const struct parse_data *data, 322281806Srpaulo const u8 *list, size_t num, char *name) 323281806Srpaulo{ 324281806Srpaulo char *value, *end, *pos; 325281806Srpaulo int res; 326281806Srpaulo size_t i; 327281806Srpaulo 328281806Srpaulo if (list == NULL || num == 0) 329281806Srpaulo return NULL; 330281806Srpaulo 331281806Srpaulo value = os_malloc(2 * 20 * num); 332281806Srpaulo if (value == NULL) 333281806Srpaulo return NULL; 334281806Srpaulo pos = value; 335281806Srpaulo end = value + 2 * 20 * num; 336281806Srpaulo 337281806Srpaulo for (i = num; i > 0; i--) { 338281806Srpaulo const u8 *a = list + (i - 1) * 2 * ETH_ALEN; 339281806Srpaulo const u8 *m = a + ETH_ALEN; 340281806Srpaulo 341281806Srpaulo if (i < num) 342281806Srpaulo *pos++ = ' '; 343281806Srpaulo res = hwaddr_mask_txt(pos, end - pos, a, m); 344281806Srpaulo if (res < 0) { 345281806Srpaulo os_free(value); 346281806Srpaulo return NULL; 347281806Srpaulo } 348281806Srpaulo pos += res; 349281806Srpaulo } 350281806Srpaulo 351281806Srpaulo return value; 352281806Srpaulo} 353281806Srpaulo#endif /* NO_CONFIG_WRITE */ 354281806Srpaulo 355189251Ssamstatic int wpa_config_parse_bssid(const struct parse_data *data, 356189251Ssam struct wpa_ssid *ssid, int line, 357189251Ssam const char *value) 358189251Ssam{ 359252726Srpaulo if (value[0] == '\0' || os_strcmp(value, "\"\"") == 0 || 360252726Srpaulo os_strcmp(value, "any") == 0) { 361252726Srpaulo ssid->bssid_set = 0; 362252726Srpaulo wpa_printf(MSG_MSGDUMP, "BSSID any"); 363252726Srpaulo return 0; 364252726Srpaulo } 365189251Ssam if (hwaddr_aton(value, ssid->bssid)) { 366189251Ssam wpa_printf(MSG_ERROR, "Line %d: Invalid BSSID '%s'.", 367189251Ssam line, value); 368189251Ssam return -1; 369189251Ssam } 370189251Ssam ssid->bssid_set = 1; 371189251Ssam wpa_hexdump(MSG_MSGDUMP, "BSSID", ssid->bssid, ETH_ALEN); 372189251Ssam return 0; 373189251Ssam} 374189251Ssam 375189251Ssam 376189251Ssam#ifndef NO_CONFIG_WRITE 377189251Ssamstatic char * wpa_config_write_bssid(const struct parse_data *data, 378189251Ssam struct wpa_ssid *ssid) 379189251Ssam{ 380189251Ssam char *value; 381189251Ssam int res; 382189251Ssam 383189251Ssam if (!ssid->bssid_set) 384189251Ssam return NULL; 385189251Ssam 386189251Ssam value = os_malloc(20); 387189251Ssam if (value == NULL) 388189251Ssam return NULL; 389189251Ssam res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->bssid)); 390281806Srpaulo if (os_snprintf_error(20, res)) { 391189251Ssam os_free(value); 392189251Ssam return NULL; 393189251Ssam } 394189251Ssam value[20 - 1] = '\0'; 395189251Ssam return value; 396189251Ssam} 397189251Ssam#endif /* NO_CONFIG_WRITE */ 398189251Ssam 399189251Ssam 400346981Scystatic int wpa_config_parse_bssid_hint(const struct parse_data *data, 401346981Scy struct wpa_ssid *ssid, int line, 402346981Scy const char *value) 403346981Scy{ 404346981Scy if (value[0] == '\0' || os_strcmp(value, "\"\"") == 0 || 405346981Scy os_strcmp(value, "any") == 0) { 406346981Scy ssid->bssid_hint_set = 0; 407346981Scy wpa_printf(MSG_MSGDUMP, "BSSID hint any"); 408346981Scy return 0; 409346981Scy } 410346981Scy if (hwaddr_aton(value, ssid->bssid_hint)) { 411346981Scy wpa_printf(MSG_ERROR, "Line %d: Invalid BSSID hint '%s'.", 412346981Scy line, value); 413346981Scy return -1; 414346981Scy } 415346981Scy ssid->bssid_hint_set = 1; 416346981Scy wpa_hexdump(MSG_MSGDUMP, "BSSID hint", ssid->bssid_hint, ETH_ALEN); 417346981Scy return 0; 418346981Scy} 419346981Scy 420346981Scy 421346981Scy#ifndef NO_CONFIG_WRITE 422346981Scystatic char * wpa_config_write_bssid_hint(const struct parse_data *data, 423346981Scy struct wpa_ssid *ssid) 424346981Scy{ 425346981Scy char *value; 426346981Scy int res; 427346981Scy 428346981Scy if (!ssid->bssid_hint_set) 429346981Scy return NULL; 430346981Scy 431346981Scy value = os_malloc(20); 432346981Scy if (!value) 433346981Scy return NULL; 434346981Scy res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->bssid_hint)); 435346981Scy if (os_snprintf_error(20, res)) { 436346981Scy os_free(value); 437346981Scy return NULL; 438346981Scy } 439346981Scy return value; 440346981Scy} 441346981Scy#endif /* NO_CONFIG_WRITE */ 442346981Scy 443346981Scy 444281806Srpaulostatic int wpa_config_parse_bssid_blacklist(const struct parse_data *data, 445281806Srpaulo struct wpa_ssid *ssid, int line, 446281806Srpaulo const char *value) 447281806Srpaulo{ 448281806Srpaulo return wpa_config_parse_addr_list(data, line, value, 449281806Srpaulo &ssid->bssid_blacklist, 450281806Srpaulo &ssid->num_bssid_blacklist, 451281806Srpaulo "bssid_blacklist", 1, 1); 452281806Srpaulo} 453281806Srpaulo 454281806Srpaulo 455281806Srpaulo#ifndef NO_CONFIG_WRITE 456281806Srpaulostatic char * wpa_config_write_bssid_blacklist(const struct parse_data *data, 457281806Srpaulo struct wpa_ssid *ssid) 458281806Srpaulo{ 459281806Srpaulo return wpa_config_write_addr_list(data, ssid->bssid_blacklist, 460281806Srpaulo ssid->num_bssid_blacklist, 461281806Srpaulo "bssid_blacklist"); 462281806Srpaulo} 463281806Srpaulo#endif /* NO_CONFIG_WRITE */ 464281806Srpaulo 465281806Srpaulo 466281806Srpaulostatic int wpa_config_parse_bssid_whitelist(const struct parse_data *data, 467281806Srpaulo struct wpa_ssid *ssid, int line, 468281806Srpaulo const char *value) 469281806Srpaulo{ 470281806Srpaulo return wpa_config_parse_addr_list(data, line, value, 471281806Srpaulo &ssid->bssid_whitelist, 472281806Srpaulo &ssid->num_bssid_whitelist, 473281806Srpaulo "bssid_whitelist", 1, 1); 474281806Srpaulo} 475281806Srpaulo 476281806Srpaulo 477281806Srpaulo#ifndef NO_CONFIG_WRITE 478281806Srpaulostatic char * wpa_config_write_bssid_whitelist(const struct parse_data *data, 479281806Srpaulo struct wpa_ssid *ssid) 480281806Srpaulo{ 481281806Srpaulo return wpa_config_write_addr_list(data, ssid->bssid_whitelist, 482281806Srpaulo ssid->num_bssid_whitelist, 483281806Srpaulo "bssid_whitelist"); 484281806Srpaulo} 485281806Srpaulo#endif /* NO_CONFIG_WRITE */ 486281806Srpaulo 487281806Srpaulo 488189251Ssamstatic int wpa_config_parse_psk(const struct parse_data *data, 489189251Ssam struct wpa_ssid *ssid, int line, 490189251Ssam const char *value) 491189251Ssam{ 492252726Srpaulo#ifdef CONFIG_EXT_PASSWORD 493252726Srpaulo if (os_strncmp(value, "ext:", 4) == 0) { 494281806Srpaulo str_clear_free(ssid->passphrase); 495252726Srpaulo ssid->passphrase = NULL; 496252726Srpaulo ssid->psk_set = 0; 497252726Srpaulo os_free(ssid->ext_psk); 498252726Srpaulo ssid->ext_psk = os_strdup(value + 4); 499252726Srpaulo if (ssid->ext_psk == NULL) 500252726Srpaulo return -1; 501252726Srpaulo wpa_printf(MSG_DEBUG, "PSK: External password '%s'", 502252726Srpaulo ssid->ext_psk); 503252726Srpaulo return 0; 504252726Srpaulo } 505252726Srpaulo#endif /* CONFIG_EXT_PASSWORD */ 506252726Srpaulo 507189251Ssam if (*value == '"') { 508189251Ssam#ifndef CONFIG_NO_PBKDF2 509189251Ssam const char *pos; 510189251Ssam size_t len; 511189251Ssam 512189251Ssam value++; 513189251Ssam pos = os_strrchr(value, '"'); 514189251Ssam if (pos) 515189251Ssam len = pos - value; 516189251Ssam else 517189251Ssam len = os_strlen(value); 518189251Ssam if (len < 8 || len > 63) { 519189251Ssam wpa_printf(MSG_ERROR, "Line %d: Invalid passphrase " 520189251Ssam "length %lu (expected: 8..63) '%s'.", 521189251Ssam line, (unsigned long) len, value); 522189251Ssam return -1; 523189251Ssam } 524189251Ssam wpa_hexdump_ascii_key(MSG_MSGDUMP, "PSK (ASCII passphrase)", 525189251Ssam (u8 *) value, len); 526337817Scy if (has_ctrl_char((u8 *) value, len)) { 527337817Scy wpa_printf(MSG_ERROR, 528337817Scy "Line %d: Invalid passphrase character", 529337817Scy line); 530337817Scy return -1; 531337817Scy } 532189251Ssam if (ssid->passphrase && os_strlen(ssid->passphrase) == len && 533337817Scy os_memcmp(ssid->passphrase, value, len) == 0) { 534337817Scy /* No change to the previously configured value */ 535337817Scy return 1; 536337817Scy } 537189251Ssam ssid->psk_set = 0; 538281806Srpaulo str_clear_free(ssid->passphrase); 539281806Srpaulo ssid->passphrase = dup_binstr(value, len); 540189251Ssam if (ssid->passphrase == NULL) 541189251Ssam return -1; 542189251Ssam return 0; 543189251Ssam#else /* CONFIG_NO_PBKDF2 */ 544189251Ssam wpa_printf(MSG_ERROR, "Line %d: ASCII passphrase not " 545189251Ssam "supported.", line); 546189251Ssam return -1; 547189251Ssam#endif /* CONFIG_NO_PBKDF2 */ 548189251Ssam } 549189251Ssam 550189251Ssam if (hexstr2bin(value, ssid->psk, PMK_LEN) || 551189251Ssam value[PMK_LEN * 2] != '\0') { 552189251Ssam wpa_printf(MSG_ERROR, "Line %d: Invalid PSK '%s'.", 553189251Ssam line, value); 554189251Ssam return -1; 555189251Ssam } 556189251Ssam 557281806Srpaulo str_clear_free(ssid->passphrase); 558189251Ssam ssid->passphrase = NULL; 559189251Ssam 560189251Ssam ssid->psk_set = 1; 561189251Ssam wpa_hexdump_key(MSG_MSGDUMP, "PSK", ssid->psk, PMK_LEN); 562189251Ssam return 0; 563189251Ssam} 564189251Ssam 565189251Ssam 566189251Ssam#ifndef NO_CONFIG_WRITE 567189251Ssamstatic char * wpa_config_write_psk(const struct parse_data *data, 568189251Ssam struct wpa_ssid *ssid) 569189251Ssam{ 570252726Srpaulo#ifdef CONFIG_EXT_PASSWORD 571252726Srpaulo if (ssid->ext_psk) { 572252726Srpaulo size_t len = 4 + os_strlen(ssid->ext_psk) + 1; 573252726Srpaulo char *buf = os_malloc(len); 574281806Srpaulo int res; 575281806Srpaulo 576252726Srpaulo if (buf == NULL) 577252726Srpaulo return NULL; 578281806Srpaulo res = os_snprintf(buf, len, "ext:%s", ssid->ext_psk); 579281806Srpaulo if (os_snprintf_error(len, res)) { 580281806Srpaulo os_free(buf); 581281806Srpaulo buf = NULL; 582281806Srpaulo } 583252726Srpaulo return buf; 584252726Srpaulo } 585252726Srpaulo#endif /* CONFIG_EXT_PASSWORD */ 586252726Srpaulo 587189251Ssam if (ssid->passphrase) 588189251Ssam return wpa_config_write_string_ascii( 589189251Ssam (const u8 *) ssid->passphrase, 590189251Ssam os_strlen(ssid->passphrase)); 591189251Ssam 592189251Ssam if (ssid->psk_set) 593189251Ssam return wpa_config_write_string_hex(ssid->psk, PMK_LEN); 594189251Ssam 595189251Ssam return NULL; 596189251Ssam} 597189251Ssam#endif /* NO_CONFIG_WRITE */ 598189251Ssam 599189251Ssam 600189251Ssamstatic int wpa_config_parse_proto(const struct parse_data *data, 601189251Ssam struct wpa_ssid *ssid, int line, 602189251Ssam const char *value) 603189251Ssam{ 604189251Ssam int val = 0, last, errors = 0; 605189251Ssam char *start, *end, *buf; 606189251Ssam 607189251Ssam buf = os_strdup(value); 608189251Ssam if (buf == NULL) 609189251Ssam return -1; 610189251Ssam start = buf; 611189251Ssam 612189251Ssam while (*start != '\0') { 613189251Ssam while (*start == ' ' || *start == '\t') 614189251Ssam start++; 615189251Ssam if (*start == '\0') 616189251Ssam break; 617189251Ssam end = start; 618189251Ssam while (*end != ' ' && *end != '\t' && *end != '\0') 619189251Ssam end++; 620189251Ssam last = *end == '\0'; 621189251Ssam *end = '\0'; 622189251Ssam if (os_strcmp(start, "WPA") == 0) 623189251Ssam val |= WPA_PROTO_WPA; 624189251Ssam else if (os_strcmp(start, "RSN") == 0 || 625189251Ssam os_strcmp(start, "WPA2") == 0) 626189251Ssam val |= WPA_PROTO_RSN; 627281806Srpaulo else if (os_strcmp(start, "OSEN") == 0) 628281806Srpaulo val |= WPA_PROTO_OSEN; 629189251Ssam else { 630189251Ssam wpa_printf(MSG_ERROR, "Line %d: invalid proto '%s'", 631189251Ssam line, start); 632189251Ssam errors++; 633189251Ssam } 634189251Ssam 635189251Ssam if (last) 636189251Ssam break; 637189251Ssam start = end + 1; 638189251Ssam } 639189251Ssam os_free(buf); 640189251Ssam 641189251Ssam if (val == 0) { 642189251Ssam wpa_printf(MSG_ERROR, 643189251Ssam "Line %d: no proto values configured.", line); 644189251Ssam errors++; 645189251Ssam } 646189251Ssam 647337817Scy if (!errors && ssid->proto == val) 648337817Scy return 1; 649189251Ssam wpa_printf(MSG_MSGDUMP, "proto: 0x%x", val); 650189251Ssam ssid->proto = val; 651189251Ssam return errors ? -1 : 0; 652189251Ssam} 653189251Ssam 654189251Ssam 655189251Ssam#ifndef NO_CONFIG_WRITE 656189251Ssamstatic char * wpa_config_write_proto(const struct parse_data *data, 657189251Ssam struct wpa_ssid *ssid) 658189251Ssam{ 659281806Srpaulo int ret; 660189251Ssam char *buf, *pos, *end; 661189251Ssam 662281806Srpaulo pos = buf = os_zalloc(20); 663189251Ssam if (buf == NULL) 664189251Ssam return NULL; 665281806Srpaulo end = buf + 20; 666189251Ssam 667189251Ssam if (ssid->proto & WPA_PROTO_WPA) { 668281806Srpaulo ret = os_snprintf(pos, end - pos, "%sWPA", 669281806Srpaulo pos == buf ? "" : " "); 670281806Srpaulo if (os_snprintf_error(end - pos, ret)) 671189251Ssam return buf; 672189251Ssam pos += ret; 673189251Ssam } 674189251Ssam 675189251Ssam if (ssid->proto & WPA_PROTO_RSN) { 676281806Srpaulo ret = os_snprintf(pos, end - pos, "%sRSN", 677281806Srpaulo pos == buf ? "" : " "); 678281806Srpaulo if (os_snprintf_error(end - pos, ret)) 679189251Ssam return buf; 680189251Ssam pos += ret; 681189251Ssam } 682189251Ssam 683281806Srpaulo if (ssid->proto & WPA_PROTO_OSEN) { 684281806Srpaulo ret = os_snprintf(pos, end - pos, "%sOSEN", 685281806Srpaulo pos == buf ? "" : " "); 686281806Srpaulo if (os_snprintf_error(end - pos, ret)) 687281806Srpaulo return buf; 688281806Srpaulo pos += ret; 689281806Srpaulo } 690281806Srpaulo 691281806Srpaulo if (pos == buf) { 692281806Srpaulo os_free(buf); 693281806Srpaulo buf = NULL; 694281806Srpaulo } 695281806Srpaulo 696189251Ssam return buf; 697189251Ssam} 698189251Ssam#endif /* NO_CONFIG_WRITE */ 699189251Ssam 700189251Ssam 701189251Ssamstatic int wpa_config_parse_key_mgmt(const struct parse_data *data, 702189251Ssam struct wpa_ssid *ssid, int line, 703189251Ssam const char *value) 704189251Ssam{ 705189251Ssam int val = 0, last, errors = 0; 706189251Ssam char *start, *end, *buf; 707189251Ssam 708189251Ssam buf = os_strdup(value); 709189251Ssam if (buf == NULL) 710189251Ssam return -1; 711189251Ssam start = buf; 712189251Ssam 713189251Ssam while (*start != '\0') { 714189251Ssam while (*start == ' ' || *start == '\t') 715189251Ssam start++; 716189251Ssam if (*start == '\0') 717189251Ssam break; 718189251Ssam end = start; 719189251Ssam while (*end != ' ' && *end != '\t' && *end != '\0') 720189251Ssam end++; 721189251Ssam last = *end == '\0'; 722189251Ssam *end = '\0'; 723189251Ssam if (os_strcmp(start, "WPA-PSK") == 0) 724189251Ssam val |= WPA_KEY_MGMT_PSK; 725189251Ssam else if (os_strcmp(start, "WPA-EAP") == 0) 726189251Ssam val |= WPA_KEY_MGMT_IEEE8021X; 727189251Ssam else if (os_strcmp(start, "IEEE8021X") == 0) 728189251Ssam val |= WPA_KEY_MGMT_IEEE8021X_NO_WPA; 729189251Ssam else if (os_strcmp(start, "NONE") == 0) 730189251Ssam val |= WPA_KEY_MGMT_NONE; 731189251Ssam else if (os_strcmp(start, "WPA-NONE") == 0) 732189251Ssam val |= WPA_KEY_MGMT_WPA_NONE; 733189251Ssam#ifdef CONFIG_IEEE80211R 734189251Ssam else if (os_strcmp(start, "FT-PSK") == 0) 735189251Ssam val |= WPA_KEY_MGMT_FT_PSK; 736189251Ssam else if (os_strcmp(start, "FT-EAP") == 0) 737189251Ssam val |= WPA_KEY_MGMT_FT_IEEE8021X; 738346981Scy#ifdef CONFIG_SHA384 739346981Scy else if (os_strcmp(start, "FT-EAP-SHA384") == 0) 740346981Scy val |= WPA_KEY_MGMT_FT_IEEE8021X_SHA384; 741346981Scy#endif /* CONFIG_SHA384 */ 742189251Ssam#endif /* CONFIG_IEEE80211R */ 743189251Ssam#ifdef CONFIG_IEEE80211W 744189251Ssam else if (os_strcmp(start, "WPA-PSK-SHA256") == 0) 745189251Ssam val |= WPA_KEY_MGMT_PSK_SHA256; 746189251Ssam else if (os_strcmp(start, "WPA-EAP-SHA256") == 0) 747189251Ssam val |= WPA_KEY_MGMT_IEEE8021X_SHA256; 748189251Ssam#endif /* CONFIG_IEEE80211W */ 749189251Ssam#ifdef CONFIG_WPS 750189251Ssam else if (os_strcmp(start, "WPS") == 0) 751189251Ssam val |= WPA_KEY_MGMT_WPS; 752189251Ssam#endif /* CONFIG_WPS */ 753252726Srpaulo#ifdef CONFIG_SAE 754252726Srpaulo else if (os_strcmp(start, "SAE") == 0) 755252726Srpaulo val |= WPA_KEY_MGMT_SAE; 756252726Srpaulo else if (os_strcmp(start, "FT-SAE") == 0) 757252726Srpaulo val |= WPA_KEY_MGMT_FT_SAE; 758252726Srpaulo#endif /* CONFIG_SAE */ 759281806Srpaulo#ifdef CONFIG_HS20 760281806Srpaulo else if (os_strcmp(start, "OSEN") == 0) 761281806Srpaulo val |= WPA_KEY_MGMT_OSEN; 762281806Srpaulo#endif /* CONFIG_HS20 */ 763281806Srpaulo#ifdef CONFIG_SUITEB 764281806Srpaulo else if (os_strcmp(start, "WPA-EAP-SUITE-B") == 0) 765281806Srpaulo val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B; 766281806Srpaulo#endif /* CONFIG_SUITEB */ 767281806Srpaulo#ifdef CONFIG_SUITEB192 768281806Srpaulo else if (os_strcmp(start, "WPA-EAP-SUITE-B-192") == 0) 769281806Srpaulo val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B_192; 770281806Srpaulo#endif /* CONFIG_SUITEB192 */ 771346981Scy#ifdef CONFIG_FILS 772346981Scy else if (os_strcmp(start, "FILS-SHA256") == 0) 773346981Scy val |= WPA_KEY_MGMT_FILS_SHA256; 774346981Scy else if (os_strcmp(start, "FILS-SHA384") == 0) 775346981Scy val |= WPA_KEY_MGMT_FILS_SHA384; 776346981Scy#ifdef CONFIG_IEEE80211R 777346981Scy else if (os_strcmp(start, "FT-FILS-SHA256") == 0) 778346981Scy val |= WPA_KEY_MGMT_FT_FILS_SHA256; 779346981Scy else if (os_strcmp(start, "FT-FILS-SHA384") == 0) 780346981Scy val |= WPA_KEY_MGMT_FT_FILS_SHA384; 781346981Scy#endif /* CONFIG_IEEE80211R */ 782346981Scy#endif /* CONFIG_FILS */ 783346981Scy#ifdef CONFIG_OWE 784346981Scy else if (os_strcmp(start, "OWE") == 0) 785346981Scy val |= WPA_KEY_MGMT_OWE; 786346981Scy#endif /* CONFIG_OWE */ 787346981Scy#ifdef CONFIG_DPP 788346981Scy else if (os_strcmp(start, "DPP") == 0) 789346981Scy val |= WPA_KEY_MGMT_DPP; 790346981Scy#endif /* CONFIG_DPP */ 791189251Ssam else { 792189251Ssam wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'", 793189251Ssam line, start); 794189251Ssam errors++; 795189251Ssam } 796189251Ssam 797189251Ssam if (last) 798189251Ssam break; 799189251Ssam start = end + 1; 800189251Ssam } 801189251Ssam os_free(buf); 802189251Ssam 803189251Ssam if (val == 0) { 804189251Ssam wpa_printf(MSG_ERROR, 805189251Ssam "Line %d: no key_mgmt values configured.", line); 806189251Ssam errors++; 807189251Ssam } 808189251Ssam 809337817Scy if (!errors && ssid->key_mgmt == val) 810337817Scy return 1; 811189251Ssam wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", val); 812189251Ssam ssid->key_mgmt = val; 813189251Ssam return errors ? -1 : 0; 814189251Ssam} 815189251Ssam 816189251Ssam 817189251Ssam#ifndef NO_CONFIG_WRITE 818189251Ssamstatic char * wpa_config_write_key_mgmt(const struct parse_data *data, 819189251Ssam struct wpa_ssid *ssid) 820189251Ssam{ 821189251Ssam char *buf, *pos, *end; 822189251Ssam int ret; 823189251Ssam 824281806Srpaulo pos = buf = os_zalloc(100); 825189251Ssam if (buf == NULL) 826189251Ssam return NULL; 827281806Srpaulo end = buf + 100; 828189251Ssam 829189251Ssam if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) { 830189251Ssam ret = os_snprintf(pos, end - pos, "%sWPA-PSK", 831189251Ssam pos == buf ? "" : " "); 832281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 833189251Ssam end[-1] = '\0'; 834189251Ssam return buf; 835189251Ssam } 836189251Ssam pos += ret; 837189251Ssam } 838189251Ssam 839189251Ssam if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X) { 840189251Ssam ret = os_snprintf(pos, end - pos, "%sWPA-EAP", 841189251Ssam pos == buf ? "" : " "); 842281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 843189251Ssam end[-1] = '\0'; 844189251Ssam return buf; 845189251Ssam } 846189251Ssam pos += ret; 847189251Ssam } 848189251Ssam 849189251Ssam if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) { 850189251Ssam ret = os_snprintf(pos, end - pos, "%sIEEE8021X", 851189251Ssam pos == buf ? "" : " "); 852281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 853189251Ssam end[-1] = '\0'; 854189251Ssam return buf; 855189251Ssam } 856189251Ssam pos += ret; 857189251Ssam } 858189251Ssam 859189251Ssam if (ssid->key_mgmt & WPA_KEY_MGMT_NONE) { 860189251Ssam ret = os_snprintf(pos, end - pos, "%sNONE", 861189251Ssam pos == buf ? "" : " "); 862281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 863189251Ssam end[-1] = '\0'; 864189251Ssam return buf; 865189251Ssam } 866189251Ssam pos += ret; 867189251Ssam } 868189251Ssam 869189251Ssam if (ssid->key_mgmt & WPA_KEY_MGMT_WPA_NONE) { 870189251Ssam ret = os_snprintf(pos, end - pos, "%sWPA-NONE", 871189251Ssam pos == buf ? "" : " "); 872281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 873189251Ssam end[-1] = '\0'; 874189251Ssam return buf; 875189251Ssam } 876189251Ssam pos += ret; 877189251Ssam } 878189251Ssam 879189251Ssam#ifdef CONFIG_IEEE80211R 880281806Srpaulo if (ssid->key_mgmt & WPA_KEY_MGMT_FT_PSK) { 881281806Srpaulo ret = os_snprintf(pos, end - pos, "%sFT-PSK", 882281806Srpaulo pos == buf ? "" : " "); 883281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 884281806Srpaulo end[-1] = '\0'; 885281806Srpaulo return buf; 886281806Srpaulo } 887281806Srpaulo pos += ret; 888281806Srpaulo } 889189251Ssam 890281806Srpaulo if (ssid->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) { 891281806Srpaulo ret = os_snprintf(pos, end - pos, "%sFT-EAP", 892281806Srpaulo pos == buf ? "" : " "); 893281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 894281806Srpaulo end[-1] = '\0'; 895281806Srpaulo return buf; 896281806Srpaulo } 897281806Srpaulo pos += ret; 898281806Srpaulo } 899346981Scy 900346981Scy#ifdef CONFIG_SHA384 901346981Scy if (ssid->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) { 902346981Scy ret = os_snprintf(pos, end - pos, "%sFT-EAP-SHA384", 903346981Scy pos == buf ? "" : " "); 904346981Scy if (os_snprintf_error(end - pos, ret)) { 905346981Scy end[-1] = '\0'; 906346981Scy return buf; 907346981Scy } 908346981Scy pos += ret; 909346981Scy } 910346981Scy#endif /* CONFIG_SHA384 */ 911189251Ssam#endif /* CONFIG_IEEE80211R */ 912189251Ssam 913189251Ssam#ifdef CONFIG_IEEE80211W 914281806Srpaulo if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256) { 915281806Srpaulo ret = os_snprintf(pos, end - pos, "%sWPA-PSK-SHA256", 916281806Srpaulo pos == buf ? "" : " "); 917281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 918281806Srpaulo end[-1] = '\0'; 919281806Srpaulo return buf; 920189251Ssam } 921281806Srpaulo pos += ret; 922189251Ssam } 923189251Ssam 924281806Srpaulo if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) { 925281806Srpaulo ret = os_snprintf(pos, end - pos, "%sWPA-EAP-SHA256", 926281806Srpaulo pos == buf ? "" : " "); 927281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 928281806Srpaulo end[-1] = '\0'; 929281806Srpaulo return buf; 930281806Srpaulo } 931281806Srpaulo pos += ret; 932189251Ssam } 933281806Srpaulo#endif /* CONFIG_IEEE80211W */ 934189251Ssam 935281806Srpaulo#ifdef CONFIG_WPS 936281806Srpaulo if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) { 937281806Srpaulo ret = os_snprintf(pos, end - pos, "%sWPS", 938189251Ssam pos == buf ? "" : " "); 939281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 940189251Ssam end[-1] = '\0'; 941189251Ssam return buf; 942189251Ssam } 943189251Ssam pos += ret; 944189251Ssam } 945281806Srpaulo#endif /* CONFIG_WPS */ 946189251Ssam 947281806Srpaulo#ifdef CONFIG_SAE 948281806Srpaulo if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) { 949281806Srpaulo ret = os_snprintf(pos, end - pos, "%sSAE", 950252726Srpaulo pos == buf ? "" : " "); 951281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 952252726Srpaulo end[-1] = '\0'; 953252726Srpaulo return buf; 954252726Srpaulo } 955252726Srpaulo pos += ret; 956252726Srpaulo } 957252726Srpaulo 958281806Srpaulo if (ssid->key_mgmt & WPA_KEY_MGMT_FT_SAE) { 959281806Srpaulo ret = os_snprintf(pos, end - pos, "%sFT-SAE", 960189251Ssam pos == buf ? "" : " "); 961281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 962189251Ssam end[-1] = '\0'; 963189251Ssam return buf; 964189251Ssam } 965189251Ssam pos += ret; 966189251Ssam } 967281806Srpaulo#endif /* CONFIG_SAE */ 968189251Ssam 969281806Srpaulo#ifdef CONFIG_HS20 970281806Srpaulo if (ssid->key_mgmt & WPA_KEY_MGMT_OSEN) { 971281806Srpaulo ret = os_snprintf(pos, end - pos, "%sOSEN", 972189251Ssam pos == buf ? "" : " "); 973281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 974189251Ssam end[-1] = '\0'; 975189251Ssam return buf; 976189251Ssam } 977189251Ssam pos += ret; 978189251Ssam } 979281806Srpaulo#endif /* CONFIG_HS20 */ 980189251Ssam 981281806Srpaulo#ifdef CONFIG_SUITEB 982281806Srpaulo if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) { 983281806Srpaulo ret = os_snprintf(pos, end - pos, "%sWPA-EAP-SUITE-B", 984189251Ssam pos == buf ? "" : " "); 985281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 986189251Ssam end[-1] = '\0'; 987189251Ssam return buf; 988189251Ssam } 989189251Ssam pos += ret; 990189251Ssam } 991281806Srpaulo#endif /* CONFIG_SUITEB */ 992189251Ssam 993281806Srpaulo#ifdef CONFIG_SUITEB192 994281806Srpaulo if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) { 995281806Srpaulo ret = os_snprintf(pos, end - pos, "%sWPA-EAP-SUITE-B-192", 996189251Ssam pos == buf ? "" : " "); 997281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 998189251Ssam end[-1] = '\0'; 999189251Ssam return buf; 1000189251Ssam } 1001189251Ssam pos += ret; 1002189251Ssam } 1003281806Srpaulo#endif /* CONFIG_SUITEB192 */ 1004189251Ssam 1005346981Scy#ifdef CONFIG_FILS 1006346981Scy if (ssid->key_mgmt & WPA_KEY_MGMT_FILS_SHA256) { 1007346981Scy ret = os_snprintf(pos, end - pos, "%sFILS-SHA256", 1008346981Scy pos == buf ? "" : " "); 1009346981Scy if (os_snprintf_error(end - pos, ret)) { 1010346981Scy end[-1] = '\0'; 1011346981Scy return buf; 1012346981Scy } 1013346981Scy pos += ret; 1014346981Scy } 1015346981Scy if (ssid->key_mgmt & WPA_KEY_MGMT_FILS_SHA384) { 1016346981Scy ret = os_snprintf(pos, end - pos, "%sFILS-SHA384", 1017346981Scy pos == buf ? "" : " "); 1018346981Scy if (os_snprintf_error(end - pos, ret)) { 1019346981Scy end[-1] = '\0'; 1020346981Scy return buf; 1021346981Scy } 1022346981Scy pos += ret; 1023346981Scy } 1024346981Scy#ifdef CONFIG_IEEE80211R 1025346981Scy if (ssid->key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) { 1026346981Scy ret = os_snprintf(pos, end - pos, "%sFT-FILS-SHA256", 1027346981Scy pos == buf ? "" : " "); 1028346981Scy if (os_snprintf_error(end - pos, ret)) { 1029346981Scy end[-1] = '\0'; 1030346981Scy return buf; 1031346981Scy } 1032346981Scy pos += ret; 1033346981Scy } 1034346981Scy if (ssid->key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) { 1035346981Scy ret = os_snprintf(pos, end - pos, "%sFT-FILS-SHA384", 1036346981Scy pos == buf ? "" : " "); 1037346981Scy if (os_snprintf_error(end - pos, ret)) { 1038346981Scy end[-1] = '\0'; 1039346981Scy return buf; 1040346981Scy } 1041346981Scy pos += ret; 1042346981Scy } 1043346981Scy#endif /* CONFIG_IEEE80211R */ 1044346981Scy#endif /* CONFIG_FILS */ 1045346981Scy 1046346981Scy#ifdef CONFIG_DPP 1047346981Scy if (ssid->key_mgmt & WPA_KEY_MGMT_DPP) { 1048346981Scy ret = os_snprintf(pos, end - pos, "%sDPP", 1049346981Scy pos == buf ? "" : " "); 1050346981Scy if (os_snprintf_error(end - pos, ret)) { 1051346981Scy end[-1] = '\0'; 1052346981Scy return buf; 1053346981Scy } 1054346981Scy pos += ret; 1055346981Scy } 1056346981Scy#endif /* CONFIG_DPP */ 1057346981Scy 1058346981Scy#ifdef CONFIG_OWE 1059346981Scy if (ssid->key_mgmt & WPA_KEY_MGMT_OWE) { 1060346981Scy ret = os_snprintf(pos, end - pos, "%sOWE", 1061346981Scy pos == buf ? "" : " "); 1062346981Scy if (os_snprintf_error(end - pos, ret)) { 1063346981Scy end[-1] = '\0'; 1064346981Scy return buf; 1065346981Scy } 1066346981Scy pos += ret; 1067346981Scy } 1068346981Scy#endif /* CONFIG_OWE */ 1069346981Scy 1070281806Srpaulo if (pos == buf) { 1071281806Srpaulo os_free(buf); 1072281806Srpaulo buf = NULL; 1073281806Srpaulo } 1074281806Srpaulo 1075189251Ssam return buf; 1076189251Ssam} 1077189251Ssam#endif /* NO_CONFIG_WRITE */ 1078189251Ssam 1079189251Ssam 1080281806Srpaulostatic int wpa_config_parse_cipher(int line, const char *value) 1081281806Srpaulo{ 1082337817Scy#ifdef CONFIG_NO_WPA 1083337817Scy return -1; 1084337817Scy#else /* CONFIG_NO_WPA */ 1085281806Srpaulo int val = wpa_parse_cipher(value); 1086281806Srpaulo if (val < 0) { 1087281806Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.", 1088281806Srpaulo line, value); 1089281806Srpaulo return -1; 1090281806Srpaulo } 1091281806Srpaulo if (val == 0) { 1092281806Srpaulo wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.", 1093281806Srpaulo line); 1094281806Srpaulo return -1; 1095281806Srpaulo } 1096281806Srpaulo return val; 1097337817Scy#endif /* CONFIG_NO_WPA */ 1098281806Srpaulo} 1099281806Srpaulo 1100281806Srpaulo 1101281806Srpaulo#ifndef NO_CONFIG_WRITE 1102281806Srpaulostatic char * wpa_config_write_cipher(int cipher) 1103281806Srpaulo{ 1104337817Scy#ifdef CONFIG_NO_WPA 1105337817Scy return NULL; 1106337817Scy#else /* CONFIG_NO_WPA */ 1107281806Srpaulo char *buf = os_zalloc(50); 1108281806Srpaulo if (buf == NULL) 1109281806Srpaulo return NULL; 1110281806Srpaulo 1111281806Srpaulo if (wpa_write_ciphers(buf, buf + 50, cipher, " ") < 0) { 1112281806Srpaulo os_free(buf); 1113281806Srpaulo return NULL; 1114281806Srpaulo } 1115281806Srpaulo 1116281806Srpaulo return buf; 1117337817Scy#endif /* CONFIG_NO_WPA */ 1118281806Srpaulo} 1119281806Srpaulo#endif /* NO_CONFIG_WRITE */ 1120281806Srpaulo 1121281806Srpaulo 1122189251Ssamstatic int wpa_config_parse_pairwise(const struct parse_data *data, 1123189251Ssam struct wpa_ssid *ssid, int line, 1124189251Ssam const char *value) 1125189251Ssam{ 1126189251Ssam int val; 1127189251Ssam val = wpa_config_parse_cipher(line, value); 1128189251Ssam if (val == -1) 1129189251Ssam return -1; 1130281806Srpaulo if (val & ~WPA_ALLOWED_PAIRWISE_CIPHERS) { 1131189251Ssam wpa_printf(MSG_ERROR, "Line %d: not allowed pairwise cipher " 1132189251Ssam "(0x%x).", line, val); 1133189251Ssam return -1; 1134189251Ssam } 1135189251Ssam 1136337817Scy if (ssid->pairwise_cipher == val) 1137337817Scy return 1; 1138189251Ssam wpa_printf(MSG_MSGDUMP, "pairwise: 0x%x", val); 1139189251Ssam ssid->pairwise_cipher = val; 1140189251Ssam return 0; 1141189251Ssam} 1142189251Ssam 1143189251Ssam 1144189251Ssam#ifndef NO_CONFIG_WRITE 1145189251Ssamstatic char * wpa_config_write_pairwise(const struct parse_data *data, 1146189251Ssam struct wpa_ssid *ssid) 1147189251Ssam{ 1148189251Ssam return wpa_config_write_cipher(ssid->pairwise_cipher); 1149189251Ssam} 1150189251Ssam#endif /* NO_CONFIG_WRITE */ 1151189251Ssam 1152189251Ssam 1153189251Ssamstatic int wpa_config_parse_group(const struct parse_data *data, 1154189251Ssam struct wpa_ssid *ssid, int line, 1155189251Ssam const char *value) 1156189251Ssam{ 1157189251Ssam int val; 1158189251Ssam val = wpa_config_parse_cipher(line, value); 1159189251Ssam if (val == -1) 1160189251Ssam return -1; 1161289549Srpaulo 1162289549Srpaulo /* 1163289549Srpaulo * Backwards compatibility - filter out WEP ciphers that were previously 1164289549Srpaulo * allowed. 1165289549Srpaulo */ 1166289549Srpaulo val &= ~(WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40); 1167289549Srpaulo 1168281806Srpaulo if (val & ~WPA_ALLOWED_GROUP_CIPHERS) { 1169189251Ssam wpa_printf(MSG_ERROR, "Line %d: not allowed group cipher " 1170189251Ssam "(0x%x).", line, val); 1171189251Ssam return -1; 1172189251Ssam } 1173189251Ssam 1174337817Scy if (ssid->group_cipher == val) 1175337817Scy return 1; 1176189251Ssam wpa_printf(MSG_MSGDUMP, "group: 0x%x", val); 1177189251Ssam ssid->group_cipher = val; 1178189251Ssam return 0; 1179189251Ssam} 1180189251Ssam 1181189251Ssam 1182189251Ssam#ifndef NO_CONFIG_WRITE 1183189251Ssamstatic char * wpa_config_write_group(const struct parse_data *data, 1184189251Ssam struct wpa_ssid *ssid) 1185189251Ssam{ 1186189251Ssam return wpa_config_write_cipher(ssid->group_cipher); 1187189251Ssam} 1188189251Ssam#endif /* NO_CONFIG_WRITE */ 1189189251Ssam 1190189251Ssam 1191346981Scystatic int wpa_config_parse_group_mgmt(const struct parse_data *data, 1192346981Scy struct wpa_ssid *ssid, int line, 1193346981Scy const char *value) 1194346981Scy{ 1195346981Scy int val; 1196346981Scy 1197346981Scy val = wpa_config_parse_cipher(line, value); 1198346981Scy if (val == -1) 1199346981Scy return -1; 1200346981Scy 1201346981Scy if (val & ~WPA_ALLOWED_GROUP_MGMT_CIPHERS) { 1202346981Scy wpa_printf(MSG_ERROR, 1203346981Scy "Line %d: not allowed group management cipher (0x%x).", 1204346981Scy line, val); 1205346981Scy return -1; 1206346981Scy } 1207346981Scy 1208346981Scy if (ssid->group_mgmt_cipher == val) 1209346981Scy return 1; 1210346981Scy wpa_printf(MSG_MSGDUMP, "group_mgmt: 0x%x", val); 1211346981Scy ssid->group_mgmt_cipher = val; 1212346981Scy return 0; 1213346981Scy} 1214346981Scy 1215346981Scy 1216346981Scy#ifndef NO_CONFIG_WRITE 1217346981Scystatic char * wpa_config_write_group_mgmt(const struct parse_data *data, 1218346981Scy struct wpa_ssid *ssid) 1219346981Scy{ 1220346981Scy return wpa_config_write_cipher(ssid->group_mgmt_cipher); 1221346981Scy} 1222346981Scy#endif /* NO_CONFIG_WRITE */ 1223346981Scy 1224346981Scy 1225189251Ssamstatic int wpa_config_parse_auth_alg(const struct parse_data *data, 1226189251Ssam struct wpa_ssid *ssid, int line, 1227189251Ssam const char *value) 1228189251Ssam{ 1229189251Ssam int val = 0, last, errors = 0; 1230189251Ssam char *start, *end, *buf; 1231189251Ssam 1232189251Ssam buf = os_strdup(value); 1233189251Ssam if (buf == NULL) 1234189251Ssam return -1; 1235189251Ssam start = buf; 1236189251Ssam 1237189251Ssam while (*start != '\0') { 1238189251Ssam while (*start == ' ' || *start == '\t') 1239189251Ssam start++; 1240189251Ssam if (*start == '\0') 1241189251Ssam break; 1242189251Ssam end = start; 1243189251Ssam while (*end != ' ' && *end != '\t' && *end != '\0') 1244189251Ssam end++; 1245189251Ssam last = *end == '\0'; 1246189251Ssam *end = '\0'; 1247189251Ssam if (os_strcmp(start, "OPEN") == 0) 1248189251Ssam val |= WPA_AUTH_ALG_OPEN; 1249189251Ssam else if (os_strcmp(start, "SHARED") == 0) 1250189251Ssam val |= WPA_AUTH_ALG_SHARED; 1251189251Ssam else if (os_strcmp(start, "LEAP") == 0) 1252189251Ssam val |= WPA_AUTH_ALG_LEAP; 1253189251Ssam else { 1254189251Ssam wpa_printf(MSG_ERROR, "Line %d: invalid auth_alg '%s'", 1255189251Ssam line, start); 1256189251Ssam errors++; 1257189251Ssam } 1258189251Ssam 1259189251Ssam if (last) 1260189251Ssam break; 1261189251Ssam start = end + 1; 1262189251Ssam } 1263189251Ssam os_free(buf); 1264189251Ssam 1265189251Ssam if (val == 0) { 1266189251Ssam wpa_printf(MSG_ERROR, 1267189251Ssam "Line %d: no auth_alg values configured.", line); 1268189251Ssam errors++; 1269189251Ssam } 1270189251Ssam 1271337817Scy if (!errors && ssid->auth_alg == val) 1272337817Scy return 1; 1273189251Ssam wpa_printf(MSG_MSGDUMP, "auth_alg: 0x%x", val); 1274189251Ssam ssid->auth_alg = val; 1275189251Ssam return errors ? -1 : 0; 1276189251Ssam} 1277189251Ssam 1278189251Ssam 1279189251Ssam#ifndef NO_CONFIG_WRITE 1280189251Ssamstatic char * wpa_config_write_auth_alg(const struct parse_data *data, 1281189251Ssam struct wpa_ssid *ssid) 1282189251Ssam{ 1283189251Ssam char *buf, *pos, *end; 1284189251Ssam int ret; 1285189251Ssam 1286189251Ssam pos = buf = os_zalloc(30); 1287189251Ssam if (buf == NULL) 1288189251Ssam return NULL; 1289189251Ssam end = buf + 30; 1290189251Ssam 1291189251Ssam if (ssid->auth_alg & WPA_AUTH_ALG_OPEN) { 1292189251Ssam ret = os_snprintf(pos, end - pos, "%sOPEN", 1293189251Ssam pos == buf ? "" : " "); 1294281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 1295189251Ssam end[-1] = '\0'; 1296189251Ssam return buf; 1297189251Ssam } 1298189251Ssam pos += ret; 1299189251Ssam } 1300189251Ssam 1301189251Ssam if (ssid->auth_alg & WPA_AUTH_ALG_SHARED) { 1302189251Ssam ret = os_snprintf(pos, end - pos, "%sSHARED", 1303189251Ssam pos == buf ? "" : " "); 1304281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 1305189251Ssam end[-1] = '\0'; 1306189251Ssam return buf; 1307189251Ssam } 1308189251Ssam pos += ret; 1309189251Ssam } 1310189251Ssam 1311189251Ssam if (ssid->auth_alg & WPA_AUTH_ALG_LEAP) { 1312189251Ssam ret = os_snprintf(pos, end - pos, "%sLEAP", 1313189251Ssam pos == buf ? "" : " "); 1314281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 1315189251Ssam end[-1] = '\0'; 1316189251Ssam return buf; 1317189251Ssam } 1318189251Ssam pos += ret; 1319189251Ssam } 1320189251Ssam 1321281806Srpaulo if (pos == buf) { 1322281806Srpaulo os_free(buf); 1323281806Srpaulo buf = NULL; 1324281806Srpaulo } 1325281806Srpaulo 1326189251Ssam return buf; 1327189251Ssam} 1328189251Ssam#endif /* NO_CONFIG_WRITE */ 1329189251Ssam 1330189251Ssam 1331281806Srpaulostatic int * wpa_config_parse_int_array(const char *value) 1332214734Srpaulo{ 1333214734Srpaulo int *freqs; 1334214734Srpaulo size_t used, len; 1335214734Srpaulo const char *pos; 1336214734Srpaulo 1337214734Srpaulo used = 0; 1338214734Srpaulo len = 10; 1339252726Srpaulo freqs = os_calloc(len + 1, sizeof(int)); 1340214734Srpaulo if (freqs == NULL) 1341214734Srpaulo return NULL; 1342214734Srpaulo 1343214734Srpaulo pos = value; 1344214734Srpaulo while (pos) { 1345214734Srpaulo while (*pos == ' ') 1346214734Srpaulo pos++; 1347214734Srpaulo if (used == len) { 1348214734Srpaulo int *n; 1349214734Srpaulo size_t i; 1350252726Srpaulo n = os_realloc_array(freqs, len * 2 + 1, sizeof(int)); 1351214734Srpaulo if (n == NULL) { 1352214734Srpaulo os_free(freqs); 1353214734Srpaulo return NULL; 1354214734Srpaulo } 1355214734Srpaulo for (i = len; i <= len * 2; i++) 1356214734Srpaulo n[i] = 0; 1357214734Srpaulo freqs = n; 1358214734Srpaulo len *= 2; 1359214734Srpaulo } 1360214734Srpaulo 1361214734Srpaulo freqs[used] = atoi(pos); 1362214734Srpaulo if (freqs[used] == 0) 1363214734Srpaulo break; 1364214734Srpaulo used++; 1365214734Srpaulo pos = os_strchr(pos + 1, ' '); 1366214734Srpaulo } 1367214734Srpaulo 1368214734Srpaulo return freqs; 1369214734Srpaulo} 1370214734Srpaulo 1371214734Srpaulo 1372214734Srpaulostatic int wpa_config_parse_scan_freq(const struct parse_data *data, 1373214734Srpaulo struct wpa_ssid *ssid, int line, 1374214734Srpaulo const char *value) 1375214734Srpaulo{ 1376214734Srpaulo int *freqs; 1377214734Srpaulo 1378281806Srpaulo freqs = wpa_config_parse_int_array(value); 1379214734Srpaulo if (freqs == NULL) 1380214734Srpaulo return -1; 1381281806Srpaulo if (freqs[0] == 0) { 1382281806Srpaulo os_free(freqs); 1383281806Srpaulo freqs = NULL; 1384281806Srpaulo } 1385214734Srpaulo os_free(ssid->scan_freq); 1386214734Srpaulo ssid->scan_freq = freqs; 1387214734Srpaulo 1388214734Srpaulo return 0; 1389214734Srpaulo} 1390214734Srpaulo 1391214734Srpaulo 1392214734Srpaulostatic int wpa_config_parse_freq_list(const struct parse_data *data, 1393214734Srpaulo struct wpa_ssid *ssid, int line, 1394214734Srpaulo const char *value) 1395214734Srpaulo{ 1396214734Srpaulo int *freqs; 1397214734Srpaulo 1398281806Srpaulo freqs = wpa_config_parse_int_array(value); 1399214734Srpaulo if (freqs == NULL) 1400214734Srpaulo return -1; 1401281806Srpaulo if (freqs[0] == 0) { 1402281806Srpaulo os_free(freqs); 1403281806Srpaulo freqs = NULL; 1404281806Srpaulo } 1405214734Srpaulo os_free(ssid->freq_list); 1406214734Srpaulo ssid->freq_list = freqs; 1407214734Srpaulo 1408214734Srpaulo return 0; 1409214734Srpaulo} 1410214734Srpaulo 1411214734Srpaulo 1412214734Srpaulo#ifndef NO_CONFIG_WRITE 1413214734Srpaulostatic char * wpa_config_write_freqs(const struct parse_data *data, 1414214734Srpaulo const int *freqs) 1415214734Srpaulo{ 1416214734Srpaulo char *buf, *pos, *end; 1417214734Srpaulo int i, ret; 1418214734Srpaulo size_t count; 1419214734Srpaulo 1420214734Srpaulo if (freqs == NULL) 1421214734Srpaulo return NULL; 1422214734Srpaulo 1423214734Srpaulo count = 0; 1424214734Srpaulo for (i = 0; freqs[i]; i++) 1425214734Srpaulo count++; 1426214734Srpaulo 1427214734Srpaulo pos = buf = os_zalloc(10 * count + 1); 1428214734Srpaulo if (buf == NULL) 1429214734Srpaulo return NULL; 1430214734Srpaulo end = buf + 10 * count + 1; 1431214734Srpaulo 1432214734Srpaulo for (i = 0; freqs[i]; i++) { 1433214734Srpaulo ret = os_snprintf(pos, end - pos, "%s%u", 1434214734Srpaulo i == 0 ? "" : " ", freqs[i]); 1435281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 1436214734Srpaulo end[-1] = '\0'; 1437214734Srpaulo return buf; 1438214734Srpaulo } 1439214734Srpaulo pos += ret; 1440214734Srpaulo } 1441214734Srpaulo 1442214734Srpaulo return buf; 1443214734Srpaulo} 1444214734Srpaulo 1445214734Srpaulo 1446214734Srpaulostatic char * wpa_config_write_scan_freq(const struct parse_data *data, 1447214734Srpaulo struct wpa_ssid *ssid) 1448214734Srpaulo{ 1449214734Srpaulo return wpa_config_write_freqs(data, ssid->scan_freq); 1450214734Srpaulo} 1451214734Srpaulo 1452214734Srpaulo 1453214734Srpaulostatic char * wpa_config_write_freq_list(const struct parse_data *data, 1454214734Srpaulo struct wpa_ssid *ssid) 1455214734Srpaulo{ 1456214734Srpaulo return wpa_config_write_freqs(data, ssid->freq_list); 1457214734Srpaulo} 1458214734Srpaulo#endif /* NO_CONFIG_WRITE */ 1459214734Srpaulo 1460214734Srpaulo 1461189251Ssam#ifdef IEEE8021X_EAPOL 1462189251Ssamstatic int wpa_config_parse_eap(const struct parse_data *data, 1463189251Ssam struct wpa_ssid *ssid, int line, 1464189251Ssam const char *value) 1465189251Ssam{ 1466189251Ssam int last, errors = 0; 1467189251Ssam char *start, *end, *buf; 1468189251Ssam struct eap_method_type *methods = NULL, *tmp; 1469189251Ssam size_t num_methods = 0; 1470189251Ssam 1471189251Ssam buf = os_strdup(value); 1472189251Ssam if (buf == NULL) 1473189251Ssam return -1; 1474189251Ssam start = buf; 1475189251Ssam 1476189251Ssam while (*start != '\0') { 1477189251Ssam while (*start == ' ' || *start == '\t') 1478189251Ssam start++; 1479189251Ssam if (*start == '\0') 1480189251Ssam break; 1481189251Ssam end = start; 1482189251Ssam while (*end != ' ' && *end != '\t' && *end != '\0') 1483189251Ssam end++; 1484189251Ssam last = *end == '\0'; 1485189251Ssam *end = '\0'; 1486189251Ssam tmp = methods; 1487252726Srpaulo methods = os_realloc_array(methods, num_methods + 1, 1488252726Srpaulo sizeof(*methods)); 1489189251Ssam if (methods == NULL) { 1490189251Ssam os_free(tmp); 1491189251Ssam os_free(buf); 1492189251Ssam return -1; 1493189251Ssam } 1494189251Ssam methods[num_methods].method = eap_peer_get_type( 1495189251Ssam start, &methods[num_methods].vendor); 1496189251Ssam if (methods[num_methods].vendor == EAP_VENDOR_IETF && 1497189251Ssam methods[num_methods].method == EAP_TYPE_NONE) { 1498189251Ssam wpa_printf(MSG_ERROR, "Line %d: unknown EAP method " 1499189251Ssam "'%s'", line, start); 1500189251Ssam wpa_printf(MSG_ERROR, "You may need to add support for" 1501189251Ssam " this EAP method during wpa_supplicant\n" 1502189251Ssam "build time configuration.\n" 1503189251Ssam "See README for more information."); 1504189251Ssam errors++; 1505189251Ssam } else if (methods[num_methods].vendor == EAP_VENDOR_IETF && 1506189251Ssam methods[num_methods].method == EAP_TYPE_LEAP) 1507189251Ssam ssid->leap++; 1508189251Ssam else 1509189251Ssam ssid->non_leap++; 1510189251Ssam num_methods++; 1511189251Ssam if (last) 1512189251Ssam break; 1513189251Ssam start = end + 1; 1514189251Ssam } 1515189251Ssam os_free(buf); 1516189251Ssam 1517189251Ssam tmp = methods; 1518252726Srpaulo methods = os_realloc_array(methods, num_methods + 1, sizeof(*methods)); 1519189251Ssam if (methods == NULL) { 1520189251Ssam os_free(tmp); 1521189251Ssam return -1; 1522189251Ssam } 1523189251Ssam methods[num_methods].vendor = EAP_VENDOR_IETF; 1524189251Ssam methods[num_methods].method = EAP_TYPE_NONE; 1525189251Ssam num_methods++; 1526189251Ssam 1527337817Scy if (!errors && ssid->eap.eap_methods) { 1528337817Scy struct eap_method_type *prev_m; 1529337817Scy size_t i, j, prev_methods, match = 0; 1530337817Scy 1531337817Scy prev_m = ssid->eap.eap_methods; 1532337817Scy for (i = 0; prev_m[i].vendor != EAP_VENDOR_IETF || 1533337817Scy prev_m[i].method != EAP_TYPE_NONE; i++) { 1534337817Scy /* Count the methods */ 1535337817Scy } 1536337817Scy prev_methods = i + 1; 1537337817Scy 1538337817Scy for (i = 0; prev_methods == num_methods && i < prev_methods; 1539337817Scy i++) { 1540337817Scy for (j = 0; j < num_methods; j++) { 1541337817Scy if (prev_m[i].vendor == methods[j].vendor && 1542337817Scy prev_m[i].method == methods[j].method) { 1543337817Scy match++; 1544337817Scy break; 1545337817Scy } 1546337817Scy } 1547337817Scy } 1548337817Scy if (match == num_methods) { 1549337817Scy os_free(methods); 1550337817Scy return 1; 1551337817Scy } 1552337817Scy } 1553189251Ssam wpa_hexdump(MSG_MSGDUMP, "eap methods", 1554189251Ssam (u8 *) methods, num_methods * sizeof(*methods)); 1555252726Srpaulo os_free(ssid->eap.eap_methods); 1556189251Ssam ssid->eap.eap_methods = methods; 1557189251Ssam return errors ? -1 : 0; 1558189251Ssam} 1559189251Ssam 1560189251Ssam 1561289549Srpaulo#ifndef NO_CONFIG_WRITE 1562189251Ssamstatic char * wpa_config_write_eap(const struct parse_data *data, 1563189251Ssam struct wpa_ssid *ssid) 1564189251Ssam{ 1565189251Ssam int i, ret; 1566189251Ssam char *buf, *pos, *end; 1567189251Ssam const struct eap_method_type *eap_methods = ssid->eap.eap_methods; 1568189251Ssam const char *name; 1569189251Ssam 1570189251Ssam if (eap_methods == NULL) 1571189251Ssam return NULL; 1572189251Ssam 1573189251Ssam pos = buf = os_zalloc(100); 1574189251Ssam if (buf == NULL) 1575189251Ssam return NULL; 1576189251Ssam end = buf + 100; 1577189251Ssam 1578189251Ssam for (i = 0; eap_methods[i].vendor != EAP_VENDOR_IETF || 1579189251Ssam eap_methods[i].method != EAP_TYPE_NONE; i++) { 1580189251Ssam name = eap_get_name(eap_methods[i].vendor, 1581189251Ssam eap_methods[i].method); 1582189251Ssam if (name) { 1583189251Ssam ret = os_snprintf(pos, end - pos, "%s%s", 1584189251Ssam pos == buf ? "" : " ", name); 1585281806Srpaulo if (os_snprintf_error(end - pos, ret)) 1586189251Ssam break; 1587189251Ssam pos += ret; 1588189251Ssam } 1589189251Ssam } 1590189251Ssam 1591189251Ssam end[-1] = '\0'; 1592189251Ssam 1593189251Ssam return buf; 1594189251Ssam} 1595289549Srpaulo#endif /* NO_CONFIG_WRITE */ 1596189251Ssam 1597189251Ssam 1598189251Ssamstatic int wpa_config_parse_password(const struct parse_data *data, 1599189251Ssam struct wpa_ssid *ssid, int line, 1600189251Ssam const char *value) 1601189251Ssam{ 1602189251Ssam u8 *hash; 1603189251Ssam 1604189251Ssam if (os_strcmp(value, "NULL") == 0) { 1605337817Scy if (!ssid->eap.password) 1606337817Scy return 1; /* Already unset */ 1607189251Ssam wpa_printf(MSG_DEBUG, "Unset configuration string 'password'"); 1608281806Srpaulo bin_clear_free(ssid->eap.password, ssid->eap.password_len); 1609189251Ssam ssid->eap.password = NULL; 1610189251Ssam ssid->eap.password_len = 0; 1611189251Ssam return 0; 1612189251Ssam } 1613189251Ssam 1614252726Srpaulo#ifdef CONFIG_EXT_PASSWORD 1615252726Srpaulo if (os_strncmp(value, "ext:", 4) == 0) { 1616252726Srpaulo char *name = os_strdup(value + 4); 1617252726Srpaulo if (name == NULL) 1618252726Srpaulo return -1; 1619281806Srpaulo bin_clear_free(ssid->eap.password, ssid->eap.password_len); 1620252726Srpaulo ssid->eap.password = (u8 *) name; 1621252726Srpaulo ssid->eap.password_len = os_strlen(name); 1622252726Srpaulo ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH; 1623252726Srpaulo ssid->eap.flags |= EAP_CONFIG_FLAGS_EXT_PASSWORD; 1624252726Srpaulo return 0; 1625252726Srpaulo } 1626252726Srpaulo#endif /* CONFIG_EXT_PASSWORD */ 1627252726Srpaulo 1628189251Ssam if (os_strncmp(value, "hash:", 5) != 0) { 1629189251Ssam char *tmp; 1630189251Ssam size_t res_len; 1631189251Ssam 1632189251Ssam tmp = wpa_config_parse_string(value, &res_len); 1633189251Ssam if (tmp == NULL) { 1634189251Ssam wpa_printf(MSG_ERROR, "Line %d: failed to parse " 1635189251Ssam "password.", line); 1636189251Ssam return -1; 1637189251Ssam } 1638189251Ssam wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name, 1639189251Ssam (u8 *) tmp, res_len); 1640189251Ssam 1641281806Srpaulo bin_clear_free(ssid->eap.password, ssid->eap.password_len); 1642189251Ssam ssid->eap.password = (u8 *) tmp; 1643189251Ssam ssid->eap.password_len = res_len; 1644189251Ssam ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH; 1645252726Srpaulo ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD; 1646189251Ssam 1647189251Ssam return 0; 1648189251Ssam } 1649189251Ssam 1650189251Ssam 1651189251Ssam /* NtPasswordHash: hash:<32 hex digits> */ 1652189251Ssam if (os_strlen(value + 5) != 2 * 16) { 1653189251Ssam wpa_printf(MSG_ERROR, "Line %d: Invalid password hash length " 1654189251Ssam "(expected 32 hex digits)", line); 1655189251Ssam return -1; 1656189251Ssam } 1657189251Ssam 1658189251Ssam hash = os_malloc(16); 1659189251Ssam if (hash == NULL) 1660189251Ssam return -1; 1661189251Ssam 1662189251Ssam if (hexstr2bin(value + 5, hash, 16)) { 1663189251Ssam os_free(hash); 1664189251Ssam wpa_printf(MSG_ERROR, "Line %d: Invalid password hash", line); 1665189251Ssam return -1; 1666189251Ssam } 1667189251Ssam 1668189251Ssam wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16); 1669189251Ssam 1670337817Scy if (ssid->eap.password && ssid->eap.password_len == 16 && 1671337817Scy os_memcmp(ssid->eap.password, hash, 16) == 0 && 1672337817Scy (ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) { 1673337817Scy bin_clear_free(hash, 16); 1674337817Scy return 1; 1675337817Scy } 1676281806Srpaulo bin_clear_free(ssid->eap.password, ssid->eap.password_len); 1677189251Ssam ssid->eap.password = hash; 1678189251Ssam ssid->eap.password_len = 16; 1679189251Ssam ssid->eap.flags |= EAP_CONFIG_FLAGS_PASSWORD_NTHASH; 1680252726Srpaulo ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD; 1681189251Ssam 1682189251Ssam return 0; 1683189251Ssam} 1684189251Ssam 1685189251Ssam 1686289549Srpaulo#ifndef NO_CONFIG_WRITE 1687189251Ssamstatic char * wpa_config_write_password(const struct parse_data *data, 1688189251Ssam struct wpa_ssid *ssid) 1689189251Ssam{ 1690189251Ssam char *buf; 1691189251Ssam 1692189251Ssam if (ssid->eap.password == NULL) 1693189251Ssam return NULL; 1694189251Ssam 1695252726Srpaulo#ifdef CONFIG_EXT_PASSWORD 1696252726Srpaulo if (ssid->eap.flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) { 1697252726Srpaulo buf = os_zalloc(4 + ssid->eap.password_len + 1); 1698252726Srpaulo if (buf == NULL) 1699252726Srpaulo return NULL; 1700252726Srpaulo os_memcpy(buf, "ext:", 4); 1701252726Srpaulo os_memcpy(buf + 4, ssid->eap.password, ssid->eap.password_len); 1702252726Srpaulo return buf; 1703252726Srpaulo } 1704252726Srpaulo#endif /* CONFIG_EXT_PASSWORD */ 1705252726Srpaulo 1706189251Ssam if (!(ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) { 1707189251Ssam return wpa_config_write_string( 1708189251Ssam ssid->eap.password, ssid->eap.password_len); 1709189251Ssam } 1710189251Ssam 1711189251Ssam buf = os_malloc(5 + 32 + 1); 1712189251Ssam if (buf == NULL) 1713189251Ssam return NULL; 1714189251Ssam 1715189251Ssam os_memcpy(buf, "hash:", 5); 1716189251Ssam wpa_snprintf_hex(buf + 5, 32 + 1, ssid->eap.password, 16); 1717189251Ssam 1718189251Ssam return buf; 1719189251Ssam} 1720289549Srpaulo#endif /* NO_CONFIG_WRITE */ 1721189251Ssam#endif /* IEEE8021X_EAPOL */ 1722189251Ssam 1723189251Ssam 1724189251Ssamstatic int wpa_config_parse_wep_key(u8 *key, size_t *len, int line, 1725189251Ssam const char *value, int idx) 1726189251Ssam{ 1727189251Ssam char *buf, title[20]; 1728189251Ssam int res; 1729189251Ssam 1730189251Ssam buf = wpa_config_parse_string(value, len); 1731189251Ssam if (buf == NULL) { 1732189251Ssam wpa_printf(MSG_ERROR, "Line %d: Invalid WEP key %d '%s'.", 1733189251Ssam line, idx, value); 1734189251Ssam return -1; 1735189251Ssam } 1736189251Ssam if (*len > MAX_WEP_KEY_LEN) { 1737189251Ssam wpa_printf(MSG_ERROR, "Line %d: Too long WEP key %d '%s'.", 1738189251Ssam line, idx, value); 1739189251Ssam os_free(buf); 1740189251Ssam return -1; 1741189251Ssam } 1742252726Srpaulo if (*len && *len != 5 && *len != 13 && *len != 16) { 1743252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid WEP key length %u - " 1744252726Srpaulo "this network block will be ignored", 1745252726Srpaulo line, (unsigned int) *len); 1746252726Srpaulo } 1747189251Ssam os_memcpy(key, buf, *len); 1748281806Srpaulo str_clear_free(buf); 1749189251Ssam res = os_snprintf(title, sizeof(title), "wep_key%d", idx); 1750281806Srpaulo if (!os_snprintf_error(sizeof(title), res)) 1751189251Ssam wpa_hexdump_key(MSG_MSGDUMP, title, key, *len); 1752189251Ssam return 0; 1753189251Ssam} 1754189251Ssam 1755189251Ssam 1756189251Ssamstatic int wpa_config_parse_wep_key0(const struct parse_data *data, 1757189251Ssam struct wpa_ssid *ssid, int line, 1758189251Ssam const char *value) 1759189251Ssam{ 1760189251Ssam return wpa_config_parse_wep_key(ssid->wep_key[0], 1761189251Ssam &ssid->wep_key_len[0], line, 1762189251Ssam value, 0); 1763189251Ssam} 1764189251Ssam 1765189251Ssam 1766189251Ssamstatic int wpa_config_parse_wep_key1(const struct parse_data *data, 1767189251Ssam struct wpa_ssid *ssid, int line, 1768189251Ssam const char *value) 1769189251Ssam{ 1770189251Ssam return wpa_config_parse_wep_key(ssid->wep_key[1], 1771189251Ssam &ssid->wep_key_len[1], line, 1772189251Ssam value, 1); 1773189251Ssam} 1774189251Ssam 1775189251Ssam 1776189251Ssamstatic int wpa_config_parse_wep_key2(const struct parse_data *data, 1777189251Ssam struct wpa_ssid *ssid, int line, 1778189251Ssam const char *value) 1779189251Ssam{ 1780189251Ssam return wpa_config_parse_wep_key(ssid->wep_key[2], 1781189251Ssam &ssid->wep_key_len[2], line, 1782189251Ssam value, 2); 1783189251Ssam} 1784189251Ssam 1785189251Ssam 1786189251Ssamstatic int wpa_config_parse_wep_key3(const struct parse_data *data, 1787189251Ssam struct wpa_ssid *ssid, int line, 1788189251Ssam const char *value) 1789189251Ssam{ 1790189251Ssam return wpa_config_parse_wep_key(ssid->wep_key[3], 1791189251Ssam &ssid->wep_key_len[3], line, 1792189251Ssam value, 3); 1793189251Ssam} 1794189251Ssam 1795189251Ssam 1796189251Ssam#ifndef NO_CONFIG_WRITE 1797189251Ssamstatic char * wpa_config_write_wep_key(struct wpa_ssid *ssid, int idx) 1798189251Ssam{ 1799189251Ssam if (ssid->wep_key_len[idx] == 0) 1800189251Ssam return NULL; 1801189251Ssam return wpa_config_write_string(ssid->wep_key[idx], 1802189251Ssam ssid->wep_key_len[idx]); 1803189251Ssam} 1804189251Ssam 1805189251Ssam 1806189251Ssamstatic char * wpa_config_write_wep_key0(const struct parse_data *data, 1807189251Ssam struct wpa_ssid *ssid) 1808189251Ssam{ 1809189251Ssam return wpa_config_write_wep_key(ssid, 0); 1810189251Ssam} 1811189251Ssam 1812189251Ssam 1813189251Ssamstatic char * wpa_config_write_wep_key1(const struct parse_data *data, 1814189251Ssam struct wpa_ssid *ssid) 1815189251Ssam{ 1816189251Ssam return wpa_config_write_wep_key(ssid, 1); 1817189251Ssam} 1818189251Ssam 1819189251Ssam 1820189251Ssamstatic char * wpa_config_write_wep_key2(const struct parse_data *data, 1821189251Ssam struct wpa_ssid *ssid) 1822189251Ssam{ 1823189251Ssam return wpa_config_write_wep_key(ssid, 2); 1824189251Ssam} 1825189251Ssam 1826189251Ssam 1827189251Ssamstatic char * wpa_config_write_wep_key3(const struct parse_data *data, 1828189251Ssam struct wpa_ssid *ssid) 1829189251Ssam{ 1830189251Ssam return wpa_config_write_wep_key(ssid, 3); 1831189251Ssam} 1832189251Ssam#endif /* NO_CONFIG_WRITE */ 1833189251Ssam 1834189251Ssam 1835252726Srpaulo#ifdef CONFIG_P2P 1836252726Srpaulo 1837281806Srpaulostatic int wpa_config_parse_go_p2p_dev_addr(const struct parse_data *data, 1838252726Srpaulo struct wpa_ssid *ssid, int line, 1839252726Srpaulo const char *value) 1840252726Srpaulo{ 1841281806Srpaulo if (value[0] == '\0' || os_strcmp(value, "\"\"") == 0 || 1842281806Srpaulo os_strcmp(value, "any") == 0) { 1843281806Srpaulo os_memset(ssid->go_p2p_dev_addr, 0, ETH_ALEN); 1844281806Srpaulo wpa_printf(MSG_MSGDUMP, "GO P2P Device Address any"); 1845281806Srpaulo return 0; 1846281806Srpaulo } 1847281806Srpaulo if (hwaddr_aton(value, ssid->go_p2p_dev_addr)) { 1848281806Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid GO P2P Device Address '%s'.", 1849281806Srpaulo line, value); 1850281806Srpaulo return -1; 1851281806Srpaulo } 1852281806Srpaulo ssid->bssid_set = 1; 1853281806Srpaulo wpa_printf(MSG_MSGDUMP, "GO P2P Device Address " MACSTR, 1854281806Srpaulo MAC2STR(ssid->go_p2p_dev_addr)); 1855281806Srpaulo return 0; 1856281806Srpaulo} 1857252726Srpaulo 1858252726Srpaulo 1859281806Srpaulo#ifndef NO_CONFIG_WRITE 1860281806Srpaulostatic char * wpa_config_write_go_p2p_dev_addr(const struct parse_data *data, 1861281806Srpaulo struct wpa_ssid *ssid) 1862281806Srpaulo{ 1863281806Srpaulo char *value; 1864281806Srpaulo int res; 1865252726Srpaulo 1866281806Srpaulo if (is_zero_ether_addr(ssid->go_p2p_dev_addr)) 1867281806Srpaulo return NULL; 1868252726Srpaulo 1869281806Srpaulo value = os_malloc(20); 1870281806Srpaulo if (value == NULL) 1871281806Srpaulo return NULL; 1872281806Srpaulo res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->go_p2p_dev_addr)); 1873281806Srpaulo if (os_snprintf_error(20, res)) { 1874281806Srpaulo os_free(value); 1875281806Srpaulo return NULL; 1876252726Srpaulo } 1877281806Srpaulo value[20 - 1] = '\0'; 1878281806Srpaulo return value; 1879281806Srpaulo} 1880281806Srpaulo#endif /* NO_CONFIG_WRITE */ 1881252726Srpaulo 1882252726Srpaulo 1883281806Srpaulostatic int wpa_config_parse_p2p_client_list(const struct parse_data *data, 1884281806Srpaulo struct wpa_ssid *ssid, int line, 1885281806Srpaulo const char *value) 1886281806Srpaulo{ 1887281806Srpaulo return wpa_config_parse_addr_list(data, line, value, 1888281806Srpaulo &ssid->p2p_client_list, 1889281806Srpaulo &ssid->num_p2p_clients, 1890281806Srpaulo "p2p_client_list", 0, 0); 1891252726Srpaulo} 1892252726Srpaulo 1893252726Srpaulo 1894252726Srpaulo#ifndef NO_CONFIG_WRITE 1895252726Srpaulostatic char * wpa_config_write_p2p_client_list(const struct parse_data *data, 1896252726Srpaulo struct wpa_ssid *ssid) 1897252726Srpaulo{ 1898281806Srpaulo return wpa_config_write_addr_list(data, ssid->p2p_client_list, 1899281806Srpaulo ssid->num_p2p_clients, 1900281806Srpaulo "p2p_client_list"); 1901281806Srpaulo} 1902281806Srpaulo#endif /* NO_CONFIG_WRITE */ 1903252726Srpaulo 1904252726Srpaulo 1905281806Srpaulostatic int wpa_config_parse_psk_list(const struct parse_data *data, 1906281806Srpaulo struct wpa_ssid *ssid, int line, 1907281806Srpaulo const char *value) 1908281806Srpaulo{ 1909281806Srpaulo struct psk_list_entry *p; 1910281806Srpaulo const char *pos; 1911281806Srpaulo 1912281806Srpaulo p = os_zalloc(sizeof(*p)); 1913281806Srpaulo if (p == NULL) 1914281806Srpaulo return -1; 1915281806Srpaulo 1916252726Srpaulo pos = value; 1917281806Srpaulo if (os_strncmp(pos, "P2P-", 4) == 0) { 1918281806Srpaulo p->p2p = 1; 1919281806Srpaulo pos += 4; 1920281806Srpaulo } 1921252726Srpaulo 1922281806Srpaulo if (hwaddr_aton(pos, p->addr)) { 1923281806Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid psk_list address '%s'", 1924281806Srpaulo line, pos); 1925281806Srpaulo os_free(p); 1926281806Srpaulo return -1; 1927252726Srpaulo } 1928281806Srpaulo pos += 17; 1929281806Srpaulo if (*pos != '-') { 1930281806Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid psk_list '%s'", 1931281806Srpaulo line, pos); 1932281806Srpaulo os_free(p); 1933281806Srpaulo return -1; 1934281806Srpaulo } 1935281806Srpaulo pos++; 1936252726Srpaulo 1937281806Srpaulo if (hexstr2bin(pos, p->psk, PMK_LEN) || pos[PMK_LEN * 2] != '\0') { 1938281806Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid psk_list PSK '%s'", 1939281806Srpaulo line, pos); 1940281806Srpaulo os_free(p); 1941281806Srpaulo return -1; 1942281806Srpaulo } 1943252726Srpaulo 1944281806Srpaulo dl_list_add(&ssid->psk_list, &p->list); 1945281806Srpaulo 1946281806Srpaulo return 0; 1947252726Srpaulo} 1948281806Srpaulo 1949281806Srpaulo 1950281806Srpaulo#ifndef NO_CONFIG_WRITE 1951281806Srpaulostatic char * wpa_config_write_psk_list(const struct parse_data *data, 1952281806Srpaulo struct wpa_ssid *ssid) 1953281806Srpaulo{ 1954281806Srpaulo return NULL; 1955281806Srpaulo} 1956252726Srpaulo#endif /* NO_CONFIG_WRITE */ 1957252726Srpaulo 1958252726Srpaulo#endif /* CONFIG_P2P */ 1959252726Srpaulo 1960281806Srpaulo 1961281806Srpaulo#ifdef CONFIG_MESH 1962281806Srpaulo 1963281806Srpaulostatic int wpa_config_parse_mesh_basic_rates(const struct parse_data *data, 1964281806Srpaulo struct wpa_ssid *ssid, int line, 1965281806Srpaulo const char *value) 1966281806Srpaulo{ 1967281806Srpaulo int *rates = wpa_config_parse_int_array(value); 1968281806Srpaulo 1969281806Srpaulo if (rates == NULL) { 1970281806Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid mesh_basic_rates '%s'", 1971281806Srpaulo line, value); 1972281806Srpaulo return -1; 1973281806Srpaulo } 1974281806Srpaulo if (rates[0] == 0) { 1975281806Srpaulo os_free(rates); 1976281806Srpaulo rates = NULL; 1977281806Srpaulo } 1978281806Srpaulo 1979281806Srpaulo os_free(ssid->mesh_basic_rates); 1980281806Srpaulo ssid->mesh_basic_rates = rates; 1981281806Srpaulo 1982281806Srpaulo return 0; 1983281806Srpaulo} 1984281806Srpaulo 1985281806Srpaulo 1986281806Srpaulo#ifndef NO_CONFIG_WRITE 1987281806Srpaulo 1988281806Srpaulostatic char * wpa_config_write_mesh_basic_rates(const struct parse_data *data, 1989281806Srpaulo struct wpa_ssid *ssid) 1990281806Srpaulo{ 1991281806Srpaulo return wpa_config_write_freqs(data, ssid->mesh_basic_rates); 1992281806Srpaulo} 1993281806Srpaulo 1994281806Srpaulo#endif /* NO_CONFIG_WRITE */ 1995281806Srpaulo 1996281806Srpaulo#endif /* CONFIG_MESH */ 1997281806Srpaulo 1998281806Srpaulo 1999346981Scy#ifdef CONFIG_MACSEC 2000346981Scy 2001346981Scystatic int wpa_config_parse_mka_cak(const struct parse_data *data, 2002346981Scy struct wpa_ssid *ssid, int line, 2003346981Scy const char *value) 2004346981Scy{ 2005346981Scy size_t len; 2006346981Scy 2007346981Scy len = os_strlen(value); 2008346981Scy if (len > 2 * MACSEC_CAK_MAX_LEN || 2009346981Scy (len != 2 * 16 && len != 2 * 32) || 2010346981Scy hexstr2bin(value, ssid->mka_cak, len / 2)) { 2011346981Scy wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CAK '%s'.", 2012346981Scy line, value); 2013346981Scy return -1; 2014346981Scy } 2015346981Scy ssid->mka_cak_len = len / 2; 2016346981Scy ssid->mka_psk_set |= MKA_PSK_SET_CAK; 2017346981Scy 2018346981Scy wpa_hexdump_key(MSG_MSGDUMP, "MKA-CAK", ssid->mka_cak, 2019346981Scy ssid->mka_cak_len); 2020346981Scy return 0; 2021346981Scy} 2022346981Scy 2023346981Scy 2024346981Scystatic int wpa_config_parse_mka_ckn(const struct parse_data *data, 2025346981Scy struct wpa_ssid *ssid, int line, 2026346981Scy const char *value) 2027346981Scy{ 2028346981Scy size_t len; 2029346981Scy 2030346981Scy len = os_strlen(value); 2031346981Scy if (len > 2 * MACSEC_CKN_MAX_LEN || /* too long */ 2032346981Scy len < 2 || /* too short */ 2033346981Scy len % 2 != 0 /* not an integral number of bytes */) { 2034346981Scy wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CKN '%s'.", 2035346981Scy line, value); 2036346981Scy return -1; 2037346981Scy } 2038346981Scy ssid->mka_ckn_len = len / 2; 2039346981Scy if (hexstr2bin(value, ssid->mka_ckn, ssid->mka_ckn_len)) { 2040346981Scy wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CKN '%s'.", 2041346981Scy line, value); 2042346981Scy return -1; 2043346981Scy } 2044346981Scy 2045346981Scy ssid->mka_psk_set |= MKA_PSK_SET_CKN; 2046346981Scy 2047346981Scy wpa_hexdump_key(MSG_MSGDUMP, "MKA-CKN", ssid->mka_ckn, 2048346981Scy ssid->mka_ckn_len); 2049346981Scy return 0; 2050346981Scy} 2051346981Scy 2052346981Scy 2053346981Scy#ifndef NO_CONFIG_WRITE 2054346981Scy 2055346981Scystatic char * wpa_config_write_mka_cak(const struct parse_data *data, 2056346981Scy struct wpa_ssid *ssid) 2057346981Scy{ 2058346981Scy if (!(ssid->mka_psk_set & MKA_PSK_SET_CAK)) 2059346981Scy return NULL; 2060346981Scy 2061346981Scy return wpa_config_write_string_hex(ssid->mka_cak, ssid->mka_cak_len); 2062346981Scy} 2063346981Scy 2064346981Scy 2065346981Scystatic char * wpa_config_write_mka_ckn(const struct parse_data *data, 2066346981Scy struct wpa_ssid *ssid) 2067346981Scy{ 2068346981Scy if (!(ssid->mka_psk_set & MKA_PSK_SET_CKN)) 2069346981Scy return NULL; 2070346981Scy return wpa_config_write_string_hex(ssid->mka_ckn, ssid->mka_ckn_len); 2071346981Scy} 2072346981Scy 2073346981Scy#endif /* NO_CONFIG_WRITE */ 2074346981Scy 2075346981Scy#endif /* CONFIG_MACSEC */ 2076346981Scy 2077346981Scy 2078346981Scy#ifdef CONFIG_OCV 2079346981Scy 2080346981Scystatic int wpa_config_parse_ocv(const struct parse_data *data, 2081346981Scy struct wpa_ssid *ssid, int line, 2082346981Scy const char *value) 2083346981Scy{ 2084346981Scy char *end; 2085346981Scy 2086346981Scy ssid->ocv = strtol(value, &end, 0); 2087346981Scy if (*end || ssid->ocv < 0 || ssid->ocv > 1) { 2088346981Scy wpa_printf(MSG_ERROR, "Line %d: Invalid ocv value '%s'.", 2089346981Scy line, value); 2090346981Scy return -1; 2091346981Scy } 2092346981Scy if (ssid->ocv && ssid->ieee80211w == NO_MGMT_FRAME_PROTECTION) 2093346981Scy ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL; 2094346981Scy return 0; 2095346981Scy} 2096346981Scy 2097346981Scy 2098346981Scy#ifndef NO_CONFIG_WRITE 2099346981Scystatic char * wpa_config_write_ocv(const struct parse_data *data, 2100346981Scy struct wpa_ssid *ssid) 2101346981Scy{ 2102346981Scy char *value = os_malloc(20); 2103346981Scy 2104346981Scy if (!value) 2105346981Scy return NULL; 2106346981Scy os_snprintf(value, 20, "%d", ssid->ocv); 2107346981Scy value[20 - 1] = '\0'; 2108346981Scy return value; 2109346981Scy} 2110346981Scy#endif /* NO_CONFIG_WRITE */ 2111346981Scy 2112346981Scy#endif /* CONFIG_OCV */ 2113346981Scy 2114346981Scy 2115346981Scystatic int wpa_config_parse_peerkey(const struct parse_data *data, 2116346981Scy struct wpa_ssid *ssid, int line, 2117346981Scy const char *value) 2118346981Scy{ 2119346981Scy wpa_printf(MSG_INFO, "NOTE: Obsolete peerkey parameter ignored"); 2120346981Scy return 0; 2121346981Scy} 2122346981Scy 2123346981Scy 2124346981Scy#ifndef NO_CONFIG_WRITE 2125346981Scystatic char * wpa_config_write_peerkey(const struct parse_data *data, 2126346981Scy struct wpa_ssid *ssid) 2127346981Scy{ 2128346981Scy return NULL; 2129346981Scy} 2130346981Scy#endif /* NO_CONFIG_WRITE */ 2131346981Scy 2132346981Scy 2133189251Ssam/* Helper macros for network block parser */ 2134189251Ssam 2135189251Ssam#ifdef OFFSET 2136189251Ssam#undef OFFSET 2137189251Ssam#endif /* OFFSET */ 2138189251Ssam/* OFFSET: Get offset of a variable within the wpa_ssid structure */ 2139189251Ssam#define OFFSET(v) ((void *) &((struct wpa_ssid *) 0)->v) 2140189251Ssam 2141189251Ssam/* STR: Define a string variable for an ASCII string; f = field name */ 2142189251Ssam#ifdef NO_CONFIG_WRITE 2143189251Ssam#define _STR(f) #f, wpa_config_parse_str, OFFSET(f) 2144189251Ssam#define _STRe(f) #f, wpa_config_parse_str, OFFSET(eap.f) 2145189251Ssam#else /* NO_CONFIG_WRITE */ 2146189251Ssam#define _STR(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(f) 2147189251Ssam#define _STRe(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(eap.f) 2148189251Ssam#endif /* NO_CONFIG_WRITE */ 2149189251Ssam#define STR(f) _STR(f), NULL, NULL, NULL, 0 2150189251Ssam#define STRe(f) _STRe(f), NULL, NULL, NULL, 0 2151189251Ssam#define STR_KEY(f) _STR(f), NULL, NULL, NULL, 1 2152189251Ssam#define STR_KEYe(f) _STRe(f), NULL, NULL, NULL, 1 2153189251Ssam 2154189251Ssam/* STR_LEN: Define a string variable with a separate variable for storing the 2155189251Ssam * data length. Unlike STR(), this can be used to store arbitrary binary data 2156189251Ssam * (i.e., even nul termination character). */ 2157189251Ssam#define _STR_LEN(f) _STR(f), OFFSET(f ## _len) 2158189251Ssam#define _STR_LENe(f) _STRe(f), OFFSET(eap.f ## _len) 2159189251Ssam#define STR_LEN(f) _STR_LEN(f), NULL, NULL, 0 2160189251Ssam#define STR_LENe(f) _STR_LENe(f), NULL, NULL, 0 2161189251Ssam#define STR_LEN_KEY(f) _STR_LEN(f), NULL, NULL, 1 2162189251Ssam 2163189251Ssam/* STR_RANGE: Like STR_LEN(), but with minimum and maximum allowed length 2164189251Ssam * explicitly specified. */ 2165189251Ssam#define _STR_RANGE(f, min, max) _STR_LEN(f), (void *) (min), (void *) (max) 2166189251Ssam#define STR_RANGE(f, min, max) _STR_RANGE(f, min, max), 0 2167189251Ssam#define STR_RANGE_KEY(f, min, max) _STR_RANGE(f, min, max), 1 2168189251Ssam 2169189251Ssam#ifdef NO_CONFIG_WRITE 2170189251Ssam#define _INT(f) #f, wpa_config_parse_int, OFFSET(f), (void *) 0 2171189251Ssam#define _INTe(f) #f, wpa_config_parse_int, OFFSET(eap.f), (void *) 0 2172189251Ssam#else /* NO_CONFIG_WRITE */ 2173189251Ssam#define _INT(f) #f, wpa_config_parse_int, wpa_config_write_int, \ 2174189251Ssam OFFSET(f), (void *) 0 2175189251Ssam#define _INTe(f) #f, wpa_config_parse_int, wpa_config_write_int, \ 2176189251Ssam OFFSET(eap.f), (void *) 0 2177189251Ssam#endif /* NO_CONFIG_WRITE */ 2178189251Ssam 2179189251Ssam/* INT: Define an integer variable */ 2180189251Ssam#define INT(f) _INT(f), NULL, NULL, 0 2181189251Ssam#define INTe(f) _INTe(f), NULL, NULL, 0 2182189251Ssam 2183189251Ssam/* INT_RANGE: Define an integer variable with allowed value range */ 2184189251Ssam#define INT_RANGE(f, min, max) _INT(f), (void *) (min), (void *) (max), 0 2185189251Ssam 2186189251Ssam/* FUNC: Define a configuration variable that uses a custom function for 2187189251Ssam * parsing and writing the value. */ 2188189251Ssam#ifdef NO_CONFIG_WRITE 2189189251Ssam#define _FUNC(f) #f, wpa_config_parse_ ## f, NULL, NULL, NULL, NULL 2190189251Ssam#else /* NO_CONFIG_WRITE */ 2191189251Ssam#define _FUNC(f) #f, wpa_config_parse_ ## f, wpa_config_write_ ## f, \ 2192189251Ssam NULL, NULL, NULL, NULL 2193189251Ssam#endif /* NO_CONFIG_WRITE */ 2194189251Ssam#define FUNC(f) _FUNC(f), 0 2195189251Ssam#define FUNC_KEY(f) _FUNC(f), 1 2196189251Ssam 2197189251Ssam/* 2198189251Ssam * Table of network configuration variables. This table is used to parse each 2199189251Ssam * network configuration variable, e.g., each line in wpa_supplicant.conf file 2200189251Ssam * that is inside a network block. 2201189251Ssam * 2202189251Ssam * This table is generated using the helper macros defined above and with 2203189251Ssam * generous help from the C pre-processor. The field name is stored as a string 2204189251Ssam * into .name and for STR and INT types, the offset of the target buffer within 2205189251Ssam * struct wpa_ssid is stored in .param1. .param2 (if not NULL) is similar 2206189251Ssam * offset to the field containing the length of the configuration variable. 2207189251Ssam * .param3 and .param4 can be used to mark the allowed range (length for STR 2208189251Ssam * and value for INT). 2209189251Ssam * 2210189251Ssam * For each configuration line in wpa_supplicant.conf, the parser goes through 2211189251Ssam * this table and select the entry that matches with the field name. The parser 2212189251Ssam * function (.parser) is then called to parse the actual value of the field. 2213189251Ssam * 2214189251Ssam * This kind of mechanism makes it easy to add new configuration parameters, 2215189251Ssam * since only one line needs to be added into this table and into the 2216189251Ssam * struct wpa_ssid definition if the new variable is either a string or 2217189251Ssam * integer. More complex types will need to use their own parser and writer 2218189251Ssam * functions. 2219189251Ssam */ 2220189251Ssamstatic const struct parse_data ssid_fields[] = { 2221289549Srpaulo { STR_RANGE(ssid, 0, SSID_MAX_LEN) }, 2222189251Ssam { INT_RANGE(scan_ssid, 0, 1) }, 2223189251Ssam { FUNC(bssid) }, 2224346981Scy { FUNC(bssid_hint) }, 2225281806Srpaulo { FUNC(bssid_blacklist) }, 2226281806Srpaulo { FUNC(bssid_whitelist) }, 2227189251Ssam { FUNC_KEY(psk) }, 2228289549Srpaulo { INT(mem_only_psk) }, 2229346981Scy { STR_KEY(sae_password) }, 2230346981Scy { STR(sae_password_id) }, 2231189251Ssam { FUNC(proto) }, 2232189251Ssam { FUNC(key_mgmt) }, 2233252726Srpaulo { INT(bg_scan_period) }, 2234189251Ssam { FUNC(pairwise) }, 2235189251Ssam { FUNC(group) }, 2236346981Scy { FUNC(group_mgmt) }, 2237189251Ssam { FUNC(auth_alg) }, 2238214734Srpaulo { FUNC(scan_freq) }, 2239214734Srpaulo { FUNC(freq_list) }, 2240346981Scy { INT_RANGE(ht, 0, 1) }, 2241346981Scy { INT_RANGE(vht, 0, 1) }, 2242346981Scy { INT_RANGE(ht40, -1, 1) }, 2243351611Scy { INT_RANGE(max_oper_chwidth, CHANWIDTH_USE_HT, 2244351611Scy CHANWIDTH_80P80MHZ) }, 2245346981Scy { INT(vht_center_freq1) }, 2246346981Scy { INT(vht_center_freq2) }, 2247189251Ssam#ifdef IEEE8021X_EAPOL 2248189251Ssam { FUNC(eap) }, 2249189251Ssam { STR_LENe(identity) }, 2250189251Ssam { STR_LENe(anonymous_identity) }, 2251346981Scy { STR_LENe(imsi_identity) }, 2252189251Ssam { FUNC_KEY(password) }, 2253189251Ssam { STRe(ca_cert) }, 2254189251Ssam { STRe(ca_path) }, 2255189251Ssam { STRe(client_cert) }, 2256189251Ssam { STRe(private_key) }, 2257189251Ssam { STR_KEYe(private_key_passwd) }, 2258189251Ssam { STRe(dh_file) }, 2259189251Ssam { STRe(subject_match) }, 2260346981Scy { STRe(check_cert_subject) }, 2261189251Ssam { STRe(altsubject_match) }, 2262281806Srpaulo { STRe(domain_suffix_match) }, 2263281806Srpaulo { STRe(domain_match) }, 2264189251Ssam { STRe(ca_cert2) }, 2265189251Ssam { STRe(ca_path2) }, 2266189251Ssam { STRe(client_cert2) }, 2267189251Ssam { STRe(private_key2) }, 2268189251Ssam { STR_KEYe(private_key2_passwd) }, 2269189251Ssam { STRe(dh_file2) }, 2270189251Ssam { STRe(subject_match2) }, 2271346981Scy { STRe(check_cert_subject2) }, 2272189251Ssam { STRe(altsubject_match2) }, 2273281806Srpaulo { STRe(domain_suffix_match2) }, 2274281806Srpaulo { STRe(domain_match2) }, 2275189251Ssam { STRe(phase1) }, 2276189251Ssam { STRe(phase2) }, 2277189251Ssam { STRe(pcsc) }, 2278189251Ssam { STR_KEYe(pin) }, 2279189251Ssam { STRe(engine_id) }, 2280189251Ssam { STRe(key_id) }, 2281189251Ssam { STRe(cert_id) }, 2282189251Ssam { STRe(ca_cert_id) }, 2283189251Ssam { STR_KEYe(pin2) }, 2284189251Ssam { STRe(engine2_id) }, 2285189251Ssam { STRe(key2_id) }, 2286189251Ssam { STRe(cert2_id) }, 2287189251Ssam { STRe(ca_cert2_id) }, 2288189251Ssam { INTe(engine) }, 2289189251Ssam { INTe(engine2) }, 2290189251Ssam { INT(eapol_flags) }, 2291281806Srpaulo { INTe(sim_num) }, 2292281806Srpaulo { STRe(openssl_ciphers) }, 2293281806Srpaulo { INTe(erp) }, 2294189251Ssam#endif /* IEEE8021X_EAPOL */ 2295189251Ssam { FUNC_KEY(wep_key0) }, 2296189251Ssam { FUNC_KEY(wep_key1) }, 2297189251Ssam { FUNC_KEY(wep_key2) }, 2298189251Ssam { FUNC_KEY(wep_key3) }, 2299189251Ssam { INT(wep_tx_keyidx) }, 2300189251Ssam { INT(priority) }, 2301189251Ssam#ifdef IEEE8021X_EAPOL 2302189251Ssam { INT(eap_workaround) }, 2303189251Ssam { STRe(pac_file) }, 2304189251Ssam { INTe(fragment_size) }, 2305281806Srpaulo { INTe(ocsp) }, 2306189251Ssam#endif /* IEEE8021X_EAPOL */ 2307281806Srpaulo#ifdef CONFIG_MESH 2308281806Srpaulo { INT_RANGE(mode, 0, 5) }, 2309281806Srpaulo { INT_RANGE(no_auto_peer, 0, 1) }, 2310346981Scy { INT_RANGE(mesh_rssi_threshold, -255, 1) }, 2311281806Srpaulo#else /* CONFIG_MESH */ 2312252726Srpaulo { INT_RANGE(mode, 0, 4) }, 2313281806Srpaulo#endif /* CONFIG_MESH */ 2314189251Ssam { INT_RANGE(proactive_key_caching, 0, 1) }, 2315252726Srpaulo { INT_RANGE(disabled, 0, 2) }, 2316189251Ssam { STR(id_str) }, 2317189251Ssam#ifdef CONFIG_IEEE80211W 2318189251Ssam { INT_RANGE(ieee80211w, 0, 2) }, 2319189251Ssam#endif /* CONFIG_IEEE80211W */ 2320346981Scy#ifdef CONFIG_OCV 2321346981Scy { FUNC(ocv) }, 2322346981Scy#endif /* CONFIG_OCV */ 2323346981Scy { FUNC(peerkey) /* obsolete - removed */ }, 2324189251Ssam { INT_RANGE(mixed_cell, 0, 1) }, 2325252726Srpaulo { INT_RANGE(frequency, 0, 65000) }, 2326281806Srpaulo { INT_RANGE(fixed_freq, 0, 1) }, 2327337817Scy#ifdef CONFIG_ACS 2328337817Scy { INT_RANGE(acs, 0, 1) }, 2329337817Scy#endif /* CONFIG_ACS */ 2330281806Srpaulo#ifdef CONFIG_MESH 2331281806Srpaulo { FUNC(mesh_basic_rates) }, 2332281806Srpaulo { INT(dot11MeshMaxRetries) }, 2333281806Srpaulo { INT(dot11MeshRetryTimeout) }, 2334281806Srpaulo { INT(dot11MeshConfirmTimeout) }, 2335281806Srpaulo { INT(dot11MeshHoldingTimeout) }, 2336281806Srpaulo#endif /* CONFIG_MESH */ 2337214734Srpaulo { INT(wpa_ptk_rekey) }, 2338337817Scy { INT(group_rekey) }, 2339214734Srpaulo { STR(bgscan) }, 2340252726Srpaulo { INT_RANGE(ignore_broadcast_ssid, 0, 2) }, 2341252726Srpaulo#ifdef CONFIG_P2P 2342281806Srpaulo { FUNC(go_p2p_dev_addr) }, 2343252726Srpaulo { FUNC(p2p_client_list) }, 2344281806Srpaulo { FUNC(psk_list) }, 2345252726Srpaulo#endif /* CONFIG_P2P */ 2346252726Srpaulo#ifdef CONFIG_HT_OVERRIDES 2347252726Srpaulo { INT_RANGE(disable_ht, 0, 1) }, 2348252726Srpaulo { INT_RANGE(disable_ht40, -1, 1) }, 2349252726Srpaulo { INT_RANGE(disable_sgi, 0, 1) }, 2350281806Srpaulo { INT_RANGE(disable_ldpc, 0, 1) }, 2351281806Srpaulo { INT_RANGE(ht40_intolerant, 0, 1) }, 2352346981Scy { INT_RANGE(tx_stbc, -1, 1) }, 2353346981Scy { INT_RANGE(rx_stbc, -1, 3) }, 2354252726Srpaulo { INT_RANGE(disable_max_amsdu, -1, 1) }, 2355252726Srpaulo { INT_RANGE(ampdu_factor, -1, 3) }, 2356252726Srpaulo { INT_RANGE(ampdu_density, -1, 7) }, 2357252726Srpaulo { STR(ht_mcs) }, 2358252726Srpaulo#endif /* CONFIG_HT_OVERRIDES */ 2359281806Srpaulo#ifdef CONFIG_VHT_OVERRIDES 2360281806Srpaulo { INT_RANGE(disable_vht, 0, 1) }, 2361281806Srpaulo { INT(vht_capa) }, 2362281806Srpaulo { INT(vht_capa_mask) }, 2363281806Srpaulo { INT_RANGE(vht_rx_mcs_nss_1, -1, 3) }, 2364281806Srpaulo { INT_RANGE(vht_rx_mcs_nss_2, -1, 3) }, 2365281806Srpaulo { INT_RANGE(vht_rx_mcs_nss_3, -1, 3) }, 2366281806Srpaulo { INT_RANGE(vht_rx_mcs_nss_4, -1, 3) }, 2367281806Srpaulo { INT_RANGE(vht_rx_mcs_nss_5, -1, 3) }, 2368281806Srpaulo { INT_RANGE(vht_rx_mcs_nss_6, -1, 3) }, 2369281806Srpaulo { INT_RANGE(vht_rx_mcs_nss_7, -1, 3) }, 2370281806Srpaulo { INT_RANGE(vht_rx_mcs_nss_8, -1, 3) }, 2371281806Srpaulo { INT_RANGE(vht_tx_mcs_nss_1, -1, 3) }, 2372281806Srpaulo { INT_RANGE(vht_tx_mcs_nss_2, -1, 3) }, 2373281806Srpaulo { INT_RANGE(vht_tx_mcs_nss_3, -1, 3) }, 2374281806Srpaulo { INT_RANGE(vht_tx_mcs_nss_4, -1, 3) }, 2375281806Srpaulo { INT_RANGE(vht_tx_mcs_nss_5, -1, 3) }, 2376281806Srpaulo { INT_RANGE(vht_tx_mcs_nss_6, -1, 3) }, 2377281806Srpaulo { INT_RANGE(vht_tx_mcs_nss_7, -1, 3) }, 2378281806Srpaulo { INT_RANGE(vht_tx_mcs_nss_8, -1, 3) }, 2379281806Srpaulo#endif /* CONFIG_VHT_OVERRIDES */ 2380252726Srpaulo { INT(ap_max_inactivity) }, 2381252726Srpaulo { INT(dtim_period) }, 2382281806Srpaulo { INT(beacon_int) }, 2383281806Srpaulo#ifdef CONFIG_MACSEC 2384281806Srpaulo { INT_RANGE(macsec_policy, 0, 1) }, 2385346981Scy { INT_RANGE(macsec_integ_only, 0, 1) }, 2386346981Scy { INT_RANGE(macsec_replay_protect, 0, 1) }, 2387346981Scy { INT(macsec_replay_window) }, 2388346981Scy { INT_RANGE(macsec_port, 1, 65534) }, 2389346981Scy { INT_RANGE(mka_priority, 0, 255) }, 2390346981Scy { FUNC_KEY(mka_cak) }, 2391346981Scy { FUNC_KEY(mka_ckn) }, 2392281806Srpaulo#endif /* CONFIG_MACSEC */ 2393281806Srpaulo#ifdef CONFIG_HS20 2394281806Srpaulo { INT(update_identifier) }, 2395346981Scy { STR_RANGE(roaming_consortium_selection, 0, MAX_ROAMING_CONS_OI_LEN) }, 2396281806Srpaulo#endif /* CONFIG_HS20 */ 2397281806Srpaulo { INT_RANGE(mac_addr, 0, 2) }, 2398337817Scy { INT_RANGE(pbss, 0, 2) }, 2399337817Scy { INT_RANGE(wps_disabled, 0, 1) }, 2400346981Scy { INT_RANGE(fils_dh_group, 0, 65535) }, 2401346981Scy#ifdef CONFIG_DPP 2402346981Scy { STR(dpp_connector) }, 2403346981Scy { STR_LEN(dpp_netaccesskey) }, 2404346981Scy { INT(dpp_netaccesskey_expiry) }, 2405346981Scy { STR_LEN(dpp_csign) }, 2406346981Scy#endif /* CONFIG_DPP */ 2407346981Scy { INT_RANGE(owe_group, 0, 65535) }, 2408346981Scy { INT_RANGE(owe_only, 0, 1) }, 2409346981Scy { INT_RANGE(multi_ap_backhaul_sta, 0, 1) }, 2410351611Scy { INT_RANGE(ft_eap_pmksa_caching, 0, 1) }, 2411189251Ssam}; 2412189251Ssam 2413189251Ssam#undef OFFSET 2414189251Ssam#undef _STR 2415189251Ssam#undef STR 2416189251Ssam#undef STR_KEY 2417189251Ssam#undef _STR_LEN 2418189251Ssam#undef STR_LEN 2419189251Ssam#undef STR_LEN_KEY 2420189251Ssam#undef _STR_RANGE 2421189251Ssam#undef STR_RANGE 2422189251Ssam#undef STR_RANGE_KEY 2423189251Ssam#undef _INT 2424189251Ssam#undef INT 2425189251Ssam#undef INT_RANGE 2426189251Ssam#undef _FUNC 2427189251Ssam#undef FUNC 2428189251Ssam#undef FUNC_KEY 2429281806Srpaulo#define NUM_SSID_FIELDS ARRAY_SIZE(ssid_fields) 2430189251Ssam 2431189251Ssam 2432189251Ssam/** 2433189251Ssam * wpa_config_add_prio_network - Add a network to priority lists 2434189251Ssam * @config: Configuration data from wpa_config_read() 2435189251Ssam * @ssid: Pointer to the network configuration to be added to the list 2436189251Ssam * Returns: 0 on success, -1 on failure 2437189251Ssam * 2438189251Ssam * This function is used to add a network block to the priority list of 2439189251Ssam * networks. This must be called for each network when reading in the full 2440189251Ssam * configuration. In addition, this can be used indirectly when updating 2441189251Ssam * priorities by calling wpa_config_update_prio_list(). 2442189251Ssam */ 2443189251Ssamint wpa_config_add_prio_network(struct wpa_config *config, 2444189251Ssam struct wpa_ssid *ssid) 2445189251Ssam{ 2446189251Ssam int prio; 2447189251Ssam struct wpa_ssid *prev, **nlist; 2448189251Ssam 2449189251Ssam /* 2450189251Ssam * Add to an existing priority list if one is available for the 2451189251Ssam * configured priority level for this network. 2452189251Ssam */ 2453189251Ssam for (prio = 0; prio < config->num_prio; prio++) { 2454189251Ssam prev = config->pssid[prio]; 2455189251Ssam if (prev->priority == ssid->priority) { 2456189251Ssam while (prev->pnext) 2457189251Ssam prev = prev->pnext; 2458189251Ssam prev->pnext = ssid; 2459189251Ssam return 0; 2460189251Ssam } 2461189251Ssam } 2462189251Ssam 2463189251Ssam /* First network for this priority - add a new priority list */ 2464252726Srpaulo nlist = os_realloc_array(config->pssid, config->num_prio + 1, 2465252726Srpaulo sizeof(struct wpa_ssid *)); 2466189251Ssam if (nlist == NULL) 2467189251Ssam return -1; 2468189251Ssam 2469189251Ssam for (prio = 0; prio < config->num_prio; prio++) { 2470252726Srpaulo if (nlist[prio]->priority < ssid->priority) { 2471252726Srpaulo os_memmove(&nlist[prio + 1], &nlist[prio], 2472252726Srpaulo (config->num_prio - prio) * 2473252726Srpaulo sizeof(struct wpa_ssid *)); 2474189251Ssam break; 2475252726Srpaulo } 2476189251Ssam } 2477189251Ssam 2478189251Ssam nlist[prio] = ssid; 2479189251Ssam config->num_prio++; 2480189251Ssam config->pssid = nlist; 2481189251Ssam 2482189251Ssam return 0; 2483189251Ssam} 2484189251Ssam 2485189251Ssam 2486189251Ssam/** 2487189251Ssam * wpa_config_update_prio_list - Update network priority list 2488189251Ssam * @config: Configuration data from wpa_config_read() 2489189251Ssam * Returns: 0 on success, -1 on failure 2490189251Ssam * 2491189251Ssam * This function is called to update the priority list of networks in the 2492189251Ssam * configuration when a network is being added or removed. This is also called 2493189251Ssam * if a priority for a network is changed. 2494189251Ssam */ 2495214734Srpauloint wpa_config_update_prio_list(struct wpa_config *config) 2496189251Ssam{ 2497189251Ssam struct wpa_ssid *ssid; 2498189251Ssam int ret = 0; 2499189251Ssam 2500189251Ssam os_free(config->pssid); 2501189251Ssam config->pssid = NULL; 2502189251Ssam config->num_prio = 0; 2503189251Ssam 2504189251Ssam ssid = config->ssid; 2505189251Ssam while (ssid) { 2506189251Ssam ssid->pnext = NULL; 2507189251Ssam if (wpa_config_add_prio_network(config, ssid) < 0) 2508189251Ssam ret = -1; 2509189251Ssam ssid = ssid->next; 2510189251Ssam } 2511189251Ssam 2512189251Ssam return ret; 2513189251Ssam} 2514189251Ssam 2515189251Ssam 2516189251Ssam#ifdef IEEE8021X_EAPOL 2517189251Ssamstatic void eap_peer_config_free(struct eap_peer_config *eap) 2518189251Ssam{ 2519189251Ssam os_free(eap->eap_methods); 2520281806Srpaulo bin_clear_free(eap->identity, eap->identity_len); 2521189251Ssam os_free(eap->anonymous_identity); 2522346981Scy os_free(eap->imsi_identity); 2523281806Srpaulo bin_clear_free(eap->password, eap->password_len); 2524189251Ssam os_free(eap->ca_cert); 2525189251Ssam os_free(eap->ca_path); 2526189251Ssam os_free(eap->client_cert); 2527189251Ssam os_free(eap->private_key); 2528281806Srpaulo str_clear_free(eap->private_key_passwd); 2529189251Ssam os_free(eap->dh_file); 2530189251Ssam os_free(eap->subject_match); 2531346981Scy os_free(eap->check_cert_subject); 2532189251Ssam os_free(eap->altsubject_match); 2533281806Srpaulo os_free(eap->domain_suffix_match); 2534281806Srpaulo os_free(eap->domain_match); 2535189251Ssam os_free(eap->ca_cert2); 2536189251Ssam os_free(eap->ca_path2); 2537189251Ssam os_free(eap->client_cert2); 2538189251Ssam os_free(eap->private_key2); 2539281806Srpaulo str_clear_free(eap->private_key2_passwd); 2540189251Ssam os_free(eap->dh_file2); 2541189251Ssam os_free(eap->subject_match2); 2542346981Scy os_free(eap->check_cert_subject2); 2543189251Ssam os_free(eap->altsubject_match2); 2544281806Srpaulo os_free(eap->domain_suffix_match2); 2545281806Srpaulo os_free(eap->domain_match2); 2546189251Ssam os_free(eap->phase1); 2547189251Ssam os_free(eap->phase2); 2548189251Ssam os_free(eap->pcsc); 2549281806Srpaulo str_clear_free(eap->pin); 2550189251Ssam os_free(eap->engine_id); 2551189251Ssam os_free(eap->key_id); 2552189251Ssam os_free(eap->cert_id); 2553189251Ssam os_free(eap->ca_cert_id); 2554189251Ssam os_free(eap->key2_id); 2555189251Ssam os_free(eap->cert2_id); 2556189251Ssam os_free(eap->ca_cert2_id); 2557281806Srpaulo str_clear_free(eap->pin2); 2558189251Ssam os_free(eap->engine2_id); 2559189251Ssam os_free(eap->otp); 2560189251Ssam os_free(eap->pending_req_otp); 2561189251Ssam os_free(eap->pac_file); 2562281806Srpaulo bin_clear_free(eap->new_password, eap->new_password_len); 2563281806Srpaulo str_clear_free(eap->external_sim_resp); 2564281806Srpaulo os_free(eap->openssl_ciphers); 2565189251Ssam} 2566189251Ssam#endif /* IEEE8021X_EAPOL */ 2567189251Ssam 2568189251Ssam 2569189251Ssam/** 2570189251Ssam * wpa_config_free_ssid - Free network/ssid configuration data 2571189251Ssam * @ssid: Configuration data for the network 2572189251Ssam * 2573189251Ssam * This function frees all resources allocated for the network configuration 2574189251Ssam * data. 2575189251Ssam */ 2576189251Ssamvoid wpa_config_free_ssid(struct wpa_ssid *ssid) 2577189251Ssam{ 2578281806Srpaulo struct psk_list_entry *psk; 2579281806Srpaulo 2580189251Ssam os_free(ssid->ssid); 2581281806Srpaulo str_clear_free(ssid->passphrase); 2582252726Srpaulo os_free(ssid->ext_psk); 2583346981Scy str_clear_free(ssid->sae_password); 2584346981Scy os_free(ssid->sae_password_id); 2585189251Ssam#ifdef IEEE8021X_EAPOL 2586189251Ssam eap_peer_config_free(&ssid->eap); 2587189251Ssam#endif /* IEEE8021X_EAPOL */ 2588189251Ssam os_free(ssid->id_str); 2589214734Srpaulo os_free(ssid->scan_freq); 2590214734Srpaulo os_free(ssid->freq_list); 2591214734Srpaulo os_free(ssid->bgscan); 2592252726Srpaulo os_free(ssid->p2p_client_list); 2593281806Srpaulo os_free(ssid->bssid_blacklist); 2594281806Srpaulo os_free(ssid->bssid_whitelist); 2595252726Srpaulo#ifdef CONFIG_HT_OVERRIDES 2596252726Srpaulo os_free(ssid->ht_mcs); 2597252726Srpaulo#endif /* CONFIG_HT_OVERRIDES */ 2598281806Srpaulo#ifdef CONFIG_MESH 2599281806Srpaulo os_free(ssid->mesh_basic_rates); 2600281806Srpaulo#endif /* CONFIG_MESH */ 2601346981Scy#ifdef CONFIG_HS20 2602346981Scy os_free(ssid->roaming_consortium_selection); 2603346981Scy#endif /* CONFIG_HS20 */ 2604346981Scy os_free(ssid->dpp_connector); 2605346981Scy bin_clear_free(ssid->dpp_netaccesskey, ssid->dpp_netaccesskey_len); 2606346981Scy os_free(ssid->dpp_csign); 2607281806Srpaulo while ((psk = dl_list_first(&ssid->psk_list, struct psk_list_entry, 2608281806Srpaulo list))) { 2609281806Srpaulo dl_list_del(&psk->list); 2610281806Srpaulo bin_clear_free(psk, sizeof(*psk)); 2611281806Srpaulo } 2612281806Srpaulo bin_clear_free(ssid, sizeof(*ssid)); 2613189251Ssam} 2614189251Ssam 2615189251Ssam 2616252726Srpaulovoid wpa_config_free_cred(struct wpa_cred *cred) 2617252726Srpaulo{ 2618281806Srpaulo size_t i; 2619281806Srpaulo 2620252726Srpaulo os_free(cred->realm); 2621281806Srpaulo str_clear_free(cred->username); 2622281806Srpaulo str_clear_free(cred->password); 2623252726Srpaulo os_free(cred->ca_cert); 2624252726Srpaulo os_free(cred->client_cert); 2625252726Srpaulo os_free(cred->private_key); 2626281806Srpaulo str_clear_free(cred->private_key_passwd); 2627252726Srpaulo os_free(cred->imsi); 2628281806Srpaulo str_clear_free(cred->milenage); 2629281806Srpaulo for (i = 0; i < cred->num_domain; i++) 2630281806Srpaulo os_free(cred->domain[i]); 2631252726Srpaulo os_free(cred->domain); 2632281806Srpaulo os_free(cred->domain_suffix_match); 2633252726Srpaulo os_free(cred->eap_method); 2634252726Srpaulo os_free(cred->phase1); 2635252726Srpaulo os_free(cred->phase2); 2636252726Srpaulo os_free(cred->excluded_ssid); 2637281806Srpaulo os_free(cred->roaming_partner); 2638281806Srpaulo os_free(cred->provisioning_sp); 2639281806Srpaulo for (i = 0; i < cred->num_req_conn_capab; i++) 2640281806Srpaulo os_free(cred->req_conn_capab_port[i]); 2641281806Srpaulo os_free(cred->req_conn_capab_port); 2642281806Srpaulo os_free(cred->req_conn_capab_proto); 2643252726Srpaulo os_free(cred); 2644252726Srpaulo} 2645252726Srpaulo 2646252726Srpaulo 2647281806Srpaulovoid wpa_config_flush_blobs(struct wpa_config *config) 2648281806Srpaulo{ 2649281806Srpaulo#ifndef CONFIG_NO_CONFIG_BLOBS 2650281806Srpaulo struct wpa_config_blob *blob, *prev; 2651281806Srpaulo 2652281806Srpaulo blob = config->blobs; 2653281806Srpaulo config->blobs = NULL; 2654281806Srpaulo while (blob) { 2655281806Srpaulo prev = blob; 2656281806Srpaulo blob = blob->next; 2657281806Srpaulo wpa_config_free_blob(prev); 2658281806Srpaulo } 2659281806Srpaulo#endif /* CONFIG_NO_CONFIG_BLOBS */ 2660281806Srpaulo} 2661281806Srpaulo 2662281806Srpaulo 2663189251Ssam/** 2664189251Ssam * wpa_config_free - Free configuration data 2665189251Ssam * @config: Configuration data from wpa_config_read() 2666189251Ssam * 2667189251Ssam * This function frees all resources allocated for the configuration data by 2668189251Ssam * wpa_config_read(). 2669189251Ssam */ 2670189251Ssamvoid wpa_config_free(struct wpa_config *config) 2671189251Ssam{ 2672189251Ssam struct wpa_ssid *ssid, *prev = NULL; 2673252726Srpaulo struct wpa_cred *cred, *cprev; 2674281806Srpaulo int i; 2675252726Srpaulo 2676189251Ssam ssid = config->ssid; 2677189251Ssam while (ssid) { 2678189251Ssam prev = ssid; 2679189251Ssam ssid = ssid->next; 2680189251Ssam wpa_config_free_ssid(prev); 2681189251Ssam } 2682189251Ssam 2683252726Srpaulo cred = config->cred; 2684252726Srpaulo while (cred) { 2685252726Srpaulo cprev = cred; 2686252726Srpaulo cred = cred->next; 2687252726Srpaulo wpa_config_free_cred(cprev); 2688252726Srpaulo } 2689252726Srpaulo 2690281806Srpaulo wpa_config_flush_blobs(config); 2691189251Ssam 2692252726Srpaulo wpabuf_free(config->wps_vendor_ext_m1); 2693281806Srpaulo for (i = 0; i < MAX_WPS_VENDOR_EXT; i++) 2694281806Srpaulo wpabuf_free(config->wps_vendor_ext[i]); 2695189251Ssam os_free(config->ctrl_interface); 2696189251Ssam os_free(config->ctrl_interface_group); 2697189251Ssam os_free(config->opensc_engine_path); 2698189251Ssam os_free(config->pkcs11_engine_path); 2699189251Ssam os_free(config->pkcs11_module_path); 2700281806Srpaulo os_free(config->openssl_ciphers); 2701252726Srpaulo os_free(config->pcsc_reader); 2702281806Srpaulo str_clear_free(config->pcsc_pin); 2703189251Ssam os_free(config->driver_param); 2704189251Ssam os_free(config->device_name); 2705189251Ssam os_free(config->manufacturer); 2706189251Ssam os_free(config->model_name); 2707189251Ssam os_free(config->model_number); 2708189251Ssam os_free(config->serial_number); 2709214734Srpaulo os_free(config->config_methods); 2710252726Srpaulo os_free(config->p2p_ssid_postfix); 2711189251Ssam os_free(config->pssid); 2712252726Srpaulo os_free(config->p2p_pref_chan); 2713281806Srpaulo os_free(config->p2p_no_go_freq.range); 2714252726Srpaulo os_free(config->autoscan); 2715281806Srpaulo os_free(config->freq_list); 2716252726Srpaulo wpabuf_free(config->wps_nfc_dh_pubkey); 2717252726Srpaulo wpabuf_free(config->wps_nfc_dh_privkey); 2718252726Srpaulo wpabuf_free(config->wps_nfc_dev_pw); 2719252726Srpaulo os_free(config->ext_password_backend); 2720281806Srpaulo os_free(config->sae_groups); 2721281806Srpaulo wpabuf_free(config->ap_vendor_elements); 2722281806Srpaulo os_free(config->osu_dir); 2723281806Srpaulo os_free(config->bgscan); 2724281806Srpaulo os_free(config->wowlan_triggers); 2725289549Srpaulo os_free(config->fst_group_id); 2726337817Scy os_free(config->sched_scan_plans); 2727337817Scy#ifdef CONFIG_MBO 2728337817Scy os_free(config->non_pref_chan); 2729337817Scy#endif /* CONFIG_MBO */ 2730337817Scy 2731189251Ssam os_free(config); 2732189251Ssam} 2733189251Ssam 2734189251Ssam 2735189251Ssam/** 2736252726Srpaulo * wpa_config_foreach_network - Iterate over each configured network 2737252726Srpaulo * @config: Configuration data from wpa_config_read() 2738252726Srpaulo * @func: Callback function to process each network 2739252726Srpaulo * @arg: Opaque argument to pass to callback function 2740252726Srpaulo * 2741252726Srpaulo * Iterate over the set of configured networks calling the specified 2742252726Srpaulo * function for each item. We guard against callbacks removing the 2743252726Srpaulo * supplied network. 2744252726Srpaulo */ 2745252726Srpaulovoid wpa_config_foreach_network(struct wpa_config *config, 2746252726Srpaulo void (*func)(void *, struct wpa_ssid *), 2747252726Srpaulo void *arg) 2748252726Srpaulo{ 2749252726Srpaulo struct wpa_ssid *ssid, *next; 2750252726Srpaulo 2751252726Srpaulo ssid = config->ssid; 2752252726Srpaulo while (ssid) { 2753252726Srpaulo next = ssid->next; 2754252726Srpaulo func(arg, ssid); 2755252726Srpaulo ssid = next; 2756252726Srpaulo } 2757252726Srpaulo} 2758252726Srpaulo 2759252726Srpaulo 2760252726Srpaulo/** 2761189251Ssam * wpa_config_get_network - Get configured network based on id 2762189251Ssam * @config: Configuration data from wpa_config_read() 2763189251Ssam * @id: Unique network id to search for 2764189251Ssam * Returns: Network configuration or %NULL if not found 2765189251Ssam */ 2766189251Ssamstruct wpa_ssid * wpa_config_get_network(struct wpa_config *config, int id) 2767189251Ssam{ 2768189251Ssam struct wpa_ssid *ssid; 2769189251Ssam 2770189251Ssam ssid = config->ssid; 2771189251Ssam while (ssid) { 2772189251Ssam if (id == ssid->id) 2773189251Ssam break; 2774189251Ssam ssid = ssid->next; 2775189251Ssam } 2776189251Ssam 2777189251Ssam return ssid; 2778189251Ssam} 2779189251Ssam 2780189251Ssam 2781189251Ssam/** 2782189251Ssam * wpa_config_add_network - Add a new network with empty configuration 2783189251Ssam * @config: Configuration data from wpa_config_read() 2784189251Ssam * Returns: The new network configuration or %NULL if operation failed 2785189251Ssam */ 2786189251Ssamstruct wpa_ssid * wpa_config_add_network(struct wpa_config *config) 2787189251Ssam{ 2788189251Ssam int id; 2789189251Ssam struct wpa_ssid *ssid, *last = NULL; 2790189251Ssam 2791189251Ssam id = -1; 2792189251Ssam ssid = config->ssid; 2793189251Ssam while (ssid) { 2794189251Ssam if (ssid->id > id) 2795189251Ssam id = ssid->id; 2796189251Ssam last = ssid; 2797189251Ssam ssid = ssid->next; 2798189251Ssam } 2799189251Ssam id++; 2800189251Ssam 2801189251Ssam ssid = os_zalloc(sizeof(*ssid)); 2802189251Ssam if (ssid == NULL) 2803189251Ssam return NULL; 2804189251Ssam ssid->id = id; 2805281806Srpaulo dl_list_init(&ssid->psk_list); 2806189251Ssam if (last) 2807189251Ssam last->next = ssid; 2808189251Ssam else 2809189251Ssam config->ssid = ssid; 2810189251Ssam 2811189251Ssam wpa_config_update_prio_list(config); 2812189251Ssam 2813189251Ssam return ssid; 2814189251Ssam} 2815189251Ssam 2816189251Ssam 2817189251Ssam/** 2818189251Ssam * wpa_config_remove_network - Remove a configured network based on id 2819189251Ssam * @config: Configuration data from wpa_config_read() 2820189251Ssam * @id: Unique network id to search for 2821189251Ssam * Returns: 0 on success, or -1 if the network was not found 2822189251Ssam */ 2823189251Ssamint wpa_config_remove_network(struct wpa_config *config, int id) 2824189251Ssam{ 2825189251Ssam struct wpa_ssid *ssid, *prev = NULL; 2826189251Ssam 2827189251Ssam ssid = config->ssid; 2828189251Ssam while (ssid) { 2829189251Ssam if (id == ssid->id) 2830189251Ssam break; 2831189251Ssam prev = ssid; 2832189251Ssam ssid = ssid->next; 2833189251Ssam } 2834189251Ssam 2835189251Ssam if (ssid == NULL) 2836189251Ssam return -1; 2837189251Ssam 2838189251Ssam if (prev) 2839189251Ssam prev->next = ssid->next; 2840189251Ssam else 2841189251Ssam config->ssid = ssid->next; 2842189251Ssam 2843189251Ssam wpa_config_update_prio_list(config); 2844189251Ssam wpa_config_free_ssid(ssid); 2845189251Ssam return 0; 2846189251Ssam} 2847189251Ssam 2848189251Ssam 2849189251Ssam/** 2850189251Ssam * wpa_config_set_network_defaults - Set network default values 2851189251Ssam * @ssid: Pointer to network configuration data 2852189251Ssam */ 2853189251Ssamvoid wpa_config_set_network_defaults(struct wpa_ssid *ssid) 2854189251Ssam{ 2855189251Ssam ssid->proto = DEFAULT_PROTO; 2856189251Ssam ssid->pairwise_cipher = DEFAULT_PAIRWISE; 2857189251Ssam ssid->group_cipher = DEFAULT_GROUP; 2858189251Ssam ssid->key_mgmt = DEFAULT_KEY_MGMT; 2859252726Srpaulo ssid->bg_scan_period = DEFAULT_BG_SCAN_PERIOD; 2860346981Scy ssid->ht = 1; 2861189251Ssam#ifdef IEEE8021X_EAPOL 2862189251Ssam ssid->eapol_flags = DEFAULT_EAPOL_FLAGS; 2863189251Ssam ssid->eap_workaround = DEFAULT_EAP_WORKAROUND; 2864189251Ssam ssid->eap.fragment_size = DEFAULT_FRAGMENT_SIZE; 2865281806Srpaulo ssid->eap.sim_num = DEFAULT_USER_SELECTED_SIM; 2866189251Ssam#endif /* IEEE8021X_EAPOL */ 2867281806Srpaulo#ifdef CONFIG_MESH 2868281806Srpaulo ssid->dot11MeshMaxRetries = DEFAULT_MESH_MAX_RETRIES; 2869281806Srpaulo ssid->dot11MeshRetryTimeout = DEFAULT_MESH_RETRY_TIMEOUT; 2870281806Srpaulo ssid->dot11MeshConfirmTimeout = DEFAULT_MESH_CONFIRM_TIMEOUT; 2871281806Srpaulo ssid->dot11MeshHoldingTimeout = DEFAULT_MESH_HOLDING_TIMEOUT; 2872346981Scy ssid->mesh_rssi_threshold = DEFAULT_MESH_RSSI_THRESHOLD; 2873281806Srpaulo#endif /* CONFIG_MESH */ 2874252726Srpaulo#ifdef CONFIG_HT_OVERRIDES 2875252726Srpaulo ssid->disable_ht = DEFAULT_DISABLE_HT; 2876252726Srpaulo ssid->disable_ht40 = DEFAULT_DISABLE_HT40; 2877252726Srpaulo ssid->disable_sgi = DEFAULT_DISABLE_SGI; 2878281806Srpaulo ssid->disable_ldpc = DEFAULT_DISABLE_LDPC; 2879346981Scy ssid->tx_stbc = DEFAULT_TX_STBC; 2880346981Scy ssid->rx_stbc = DEFAULT_RX_STBC; 2881252726Srpaulo ssid->disable_max_amsdu = DEFAULT_DISABLE_MAX_AMSDU; 2882252726Srpaulo ssid->ampdu_factor = DEFAULT_AMPDU_FACTOR; 2883252726Srpaulo ssid->ampdu_density = DEFAULT_AMPDU_DENSITY; 2884252726Srpaulo#endif /* CONFIG_HT_OVERRIDES */ 2885281806Srpaulo#ifdef CONFIG_VHT_OVERRIDES 2886281806Srpaulo ssid->vht_rx_mcs_nss_1 = -1; 2887281806Srpaulo ssid->vht_rx_mcs_nss_2 = -1; 2888281806Srpaulo ssid->vht_rx_mcs_nss_3 = -1; 2889281806Srpaulo ssid->vht_rx_mcs_nss_4 = -1; 2890281806Srpaulo ssid->vht_rx_mcs_nss_5 = -1; 2891281806Srpaulo ssid->vht_rx_mcs_nss_6 = -1; 2892281806Srpaulo ssid->vht_rx_mcs_nss_7 = -1; 2893281806Srpaulo ssid->vht_rx_mcs_nss_8 = -1; 2894281806Srpaulo ssid->vht_tx_mcs_nss_1 = -1; 2895281806Srpaulo ssid->vht_tx_mcs_nss_2 = -1; 2896281806Srpaulo ssid->vht_tx_mcs_nss_3 = -1; 2897281806Srpaulo ssid->vht_tx_mcs_nss_4 = -1; 2898281806Srpaulo ssid->vht_tx_mcs_nss_5 = -1; 2899281806Srpaulo ssid->vht_tx_mcs_nss_6 = -1; 2900281806Srpaulo ssid->vht_tx_mcs_nss_7 = -1; 2901281806Srpaulo ssid->vht_tx_mcs_nss_8 = -1; 2902281806Srpaulo#endif /* CONFIG_VHT_OVERRIDES */ 2903252726Srpaulo ssid->proactive_key_caching = -1; 2904252726Srpaulo#ifdef CONFIG_IEEE80211W 2905252726Srpaulo ssid->ieee80211w = MGMT_FRAME_PROTECTION_DEFAULT; 2906252726Srpaulo#endif /* CONFIG_IEEE80211W */ 2907346981Scy#ifdef CONFIG_MACSEC 2908346981Scy ssid->mka_priority = DEFAULT_PRIO_NOT_KEY_SERVER; 2909346981Scy#endif /* CONFIG_MACSEC */ 2910281806Srpaulo ssid->mac_addr = -1; 2911346981Scy ssid->max_oper_chwidth = DEFAULT_MAX_OPER_CHWIDTH; 2912189251Ssam} 2913189251Ssam 2914189251Ssam 2915189251Ssam/** 2916189251Ssam * wpa_config_set - Set a variable in network configuration 2917189251Ssam * @ssid: Pointer to network configuration data 2918189251Ssam * @var: Variable name, e.g., "ssid" 2919189251Ssam * @value: Variable value 2920189251Ssam * @line: Line number in configuration file or 0 if not used 2921337817Scy * Returns: 0 on success with possible change in the value, 1 on success with 2922337817Scy * no change to previously configured value, or -1 on failure 2923189251Ssam * 2924189251Ssam * This function can be used to set network configuration variables based on 2925189251Ssam * both the configuration file and management interface input. The value 2926189251Ssam * parameter must be in the same format as the text-based configuration file is 2927189251Ssam * using. For example, strings are using double quotation marks. 2928189251Ssam */ 2929189251Ssamint wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value, 2930189251Ssam int line) 2931189251Ssam{ 2932189251Ssam size_t i; 2933189251Ssam int ret = 0; 2934189251Ssam 2935189251Ssam if (ssid == NULL || var == NULL || value == NULL) 2936189251Ssam return -1; 2937189251Ssam 2938189251Ssam for (i = 0; i < NUM_SSID_FIELDS; i++) { 2939189251Ssam const struct parse_data *field = &ssid_fields[i]; 2940189251Ssam if (os_strcmp(var, field->name) != 0) 2941189251Ssam continue; 2942189251Ssam 2943337817Scy ret = field->parser(field, ssid, line, value); 2944337817Scy if (ret < 0) { 2945189251Ssam if (line) { 2946189251Ssam wpa_printf(MSG_ERROR, "Line %d: failed to " 2947189251Ssam "parse %s '%s'.", line, var, value); 2948189251Ssam } 2949189251Ssam ret = -1; 2950189251Ssam } 2951189251Ssam break; 2952189251Ssam } 2953189251Ssam if (i == NUM_SSID_FIELDS) { 2954189251Ssam if (line) { 2955189251Ssam wpa_printf(MSG_ERROR, "Line %d: unknown network field " 2956189251Ssam "'%s'.", line, var); 2957189251Ssam } 2958189251Ssam ret = -1; 2959189251Ssam } 2960189251Ssam 2961189251Ssam return ret; 2962189251Ssam} 2963189251Ssam 2964189251Ssam 2965252726Srpauloint wpa_config_set_quoted(struct wpa_ssid *ssid, const char *var, 2966252726Srpaulo const char *value) 2967252726Srpaulo{ 2968252726Srpaulo size_t len; 2969252726Srpaulo char *buf; 2970252726Srpaulo int ret; 2971252726Srpaulo 2972252726Srpaulo len = os_strlen(value); 2973252726Srpaulo buf = os_malloc(len + 3); 2974252726Srpaulo if (buf == NULL) 2975252726Srpaulo return -1; 2976252726Srpaulo buf[0] = '"'; 2977252726Srpaulo os_memcpy(buf + 1, value, len); 2978252726Srpaulo buf[len + 1] = '"'; 2979252726Srpaulo buf[len + 2] = '\0'; 2980252726Srpaulo ret = wpa_config_set(ssid, var, buf, 0); 2981252726Srpaulo os_free(buf); 2982252726Srpaulo return ret; 2983252726Srpaulo} 2984252726Srpaulo 2985252726Srpaulo 2986214734Srpaulo/** 2987214734Srpaulo * wpa_config_get_all - Get all options from network configuration 2988214734Srpaulo * @ssid: Pointer to network configuration data 2989214734Srpaulo * @get_keys: Determines if keys/passwords will be included in returned list 2990252726Srpaulo * (if they may be exported) 2991214734Srpaulo * Returns: %NULL terminated list of all set keys and their values in the form 2992214734Srpaulo * of [key1, val1, key2, val2, ... , NULL] 2993214734Srpaulo * 2994214734Srpaulo * This function can be used to get list of all configured network properties. 2995214734Srpaulo * The caller is responsible for freeing the returned list and all its 2996214734Srpaulo * elements. 2997214734Srpaulo */ 2998214734Srpaulochar ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys) 2999214734Srpaulo{ 3000289549Srpaulo#ifdef NO_CONFIG_WRITE 3001289549Srpaulo return NULL; 3002289549Srpaulo#else /* NO_CONFIG_WRITE */ 3003214734Srpaulo const struct parse_data *field; 3004214734Srpaulo char *key, *value; 3005214734Srpaulo size_t i; 3006214734Srpaulo char **props; 3007214734Srpaulo int fields_num; 3008214734Srpaulo 3009252726Srpaulo get_keys = get_keys && ssid->export_keys; 3010252726Srpaulo 3011252726Srpaulo props = os_calloc(2 * NUM_SSID_FIELDS + 1, sizeof(char *)); 3012214734Srpaulo if (!props) 3013214734Srpaulo return NULL; 3014214734Srpaulo 3015214734Srpaulo fields_num = 0; 3016214734Srpaulo for (i = 0; i < NUM_SSID_FIELDS; i++) { 3017214734Srpaulo field = &ssid_fields[i]; 3018214734Srpaulo if (field->key_data && !get_keys) 3019214734Srpaulo continue; 3020214734Srpaulo value = field->writer(field, ssid); 3021214734Srpaulo if (value == NULL) 3022214734Srpaulo continue; 3023214734Srpaulo if (os_strlen(value) == 0) { 3024214734Srpaulo os_free(value); 3025214734Srpaulo continue; 3026214734Srpaulo } 3027214734Srpaulo 3028214734Srpaulo key = os_strdup(field->name); 3029214734Srpaulo if (key == NULL) { 3030214734Srpaulo os_free(value); 3031214734Srpaulo goto err; 3032214734Srpaulo } 3033214734Srpaulo 3034214734Srpaulo props[fields_num * 2] = key; 3035214734Srpaulo props[fields_num * 2 + 1] = value; 3036214734Srpaulo 3037214734Srpaulo fields_num++; 3038214734Srpaulo } 3039214734Srpaulo 3040214734Srpaulo return props; 3041214734Srpaulo 3042214734Srpauloerr: 3043337817Scy for (i = 0; props[i]; i++) 3044337817Scy os_free(props[i]); 3045214734Srpaulo os_free(props); 3046214734Srpaulo return NULL; 3047289549Srpaulo#endif /* NO_CONFIG_WRITE */ 3048214734Srpaulo} 3049214734Srpaulo 3050214734Srpaulo 3051189251Ssam#ifndef NO_CONFIG_WRITE 3052189251Ssam/** 3053189251Ssam * wpa_config_get - Get a variable in network configuration 3054189251Ssam * @ssid: Pointer to network configuration data 3055189251Ssam * @var: Variable name, e.g., "ssid" 3056189251Ssam * Returns: Value of the variable or %NULL on failure 3057189251Ssam * 3058189251Ssam * This function can be used to get network configuration variables. The 3059189251Ssam * returned value is a copy of the configuration variable in text format, i.e,. 3060189251Ssam * the same format that the text-based configuration file and wpa_config_set() 3061189251Ssam * are using for the value. The caller is responsible for freeing the returned 3062189251Ssam * value. 3063189251Ssam */ 3064189251Ssamchar * wpa_config_get(struct wpa_ssid *ssid, const char *var) 3065189251Ssam{ 3066189251Ssam size_t i; 3067189251Ssam 3068189251Ssam if (ssid == NULL || var == NULL) 3069189251Ssam return NULL; 3070189251Ssam 3071189251Ssam for (i = 0; i < NUM_SSID_FIELDS; i++) { 3072189251Ssam const struct parse_data *field = &ssid_fields[i]; 3073337817Scy if (os_strcmp(var, field->name) == 0) { 3074337817Scy char *ret = field->writer(field, ssid); 3075337817Scy 3076337817Scy if (ret && has_newline(ret)) { 3077337817Scy wpa_printf(MSG_ERROR, 3078337817Scy "Found newline in value for %s; not returning it", 3079337817Scy var); 3080337817Scy os_free(ret); 3081337817Scy ret = NULL; 3082337817Scy } 3083337817Scy 3084337817Scy return ret; 3085337817Scy } 3086189251Ssam } 3087189251Ssam 3088189251Ssam return NULL; 3089189251Ssam} 3090189251Ssam 3091189251Ssam 3092189251Ssam/** 3093189251Ssam * wpa_config_get_no_key - Get a variable in network configuration (no keys) 3094189251Ssam * @ssid: Pointer to network configuration data 3095189251Ssam * @var: Variable name, e.g., "ssid" 3096189251Ssam * Returns: Value of the variable or %NULL on failure 3097189251Ssam * 3098189251Ssam * This function can be used to get network configuration variable like 3099189251Ssam * wpa_config_get(). The only difference is that this functions does not expose 3100189251Ssam * key/password material from the configuration. In case a key/password field 3101189251Ssam * is requested, the returned value is an empty string or %NULL if the variable 3102189251Ssam * is not set or "*" if the variable is set (regardless of its value). The 3103189251Ssam * returned value is a copy of the configuration variable in text format, i.e,. 3104189251Ssam * the same format that the text-based configuration file and wpa_config_set() 3105189251Ssam * are using for the value. The caller is responsible for freeing the returned 3106189251Ssam * value. 3107189251Ssam */ 3108189251Ssamchar * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var) 3109189251Ssam{ 3110189251Ssam size_t i; 3111189251Ssam 3112189251Ssam if (ssid == NULL || var == NULL) 3113189251Ssam return NULL; 3114189251Ssam 3115189251Ssam for (i = 0; i < NUM_SSID_FIELDS; i++) { 3116189251Ssam const struct parse_data *field = &ssid_fields[i]; 3117189251Ssam if (os_strcmp(var, field->name) == 0) { 3118189251Ssam char *res = field->writer(field, ssid); 3119189251Ssam if (field->key_data) { 3120189251Ssam if (res && res[0]) { 3121189251Ssam wpa_printf(MSG_DEBUG, "Do not allow " 3122189251Ssam "key_data field to be " 3123189251Ssam "exposed"); 3124281806Srpaulo str_clear_free(res); 3125189251Ssam return os_strdup("*"); 3126189251Ssam } 3127189251Ssam 3128189251Ssam os_free(res); 3129189251Ssam return NULL; 3130189251Ssam } 3131189251Ssam return res; 3132189251Ssam } 3133189251Ssam } 3134189251Ssam 3135189251Ssam return NULL; 3136189251Ssam} 3137189251Ssam#endif /* NO_CONFIG_WRITE */ 3138189251Ssam 3139189251Ssam 3140189251Ssam/** 3141189251Ssam * wpa_config_update_psk - Update WPA PSK based on passphrase and SSID 3142189251Ssam * @ssid: Pointer to network configuration data 3143189251Ssam * 3144189251Ssam * This function must be called to update WPA PSK when either SSID or the 3145189251Ssam * passphrase has changed for the network configuration. 3146189251Ssam */ 3147189251Ssamvoid wpa_config_update_psk(struct wpa_ssid *ssid) 3148189251Ssam{ 3149189251Ssam#ifndef CONFIG_NO_PBKDF2 3150252726Srpaulo pbkdf2_sha1(ssid->passphrase, ssid->ssid, ssid->ssid_len, 4096, 3151189251Ssam ssid->psk, PMK_LEN); 3152189251Ssam wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)", 3153189251Ssam ssid->psk, PMK_LEN); 3154189251Ssam ssid->psk_set = 1; 3155189251Ssam#endif /* CONFIG_NO_PBKDF2 */ 3156189251Ssam} 3157189251Ssam 3158189251Ssam 3159281806Srpaulostatic int wpa_config_set_cred_req_conn_capab(struct wpa_cred *cred, 3160281806Srpaulo const char *value) 3161281806Srpaulo{ 3162281806Srpaulo u8 *proto; 3163281806Srpaulo int **port; 3164281806Srpaulo int *ports, *nports; 3165281806Srpaulo const char *pos; 3166281806Srpaulo unsigned int num_ports; 3167281806Srpaulo 3168281806Srpaulo proto = os_realloc_array(cred->req_conn_capab_proto, 3169281806Srpaulo cred->num_req_conn_capab + 1, sizeof(u8)); 3170281806Srpaulo if (proto == NULL) 3171281806Srpaulo return -1; 3172281806Srpaulo cred->req_conn_capab_proto = proto; 3173281806Srpaulo 3174281806Srpaulo port = os_realloc_array(cred->req_conn_capab_port, 3175281806Srpaulo cred->num_req_conn_capab + 1, sizeof(int *)); 3176281806Srpaulo if (port == NULL) 3177281806Srpaulo return -1; 3178281806Srpaulo cred->req_conn_capab_port = port; 3179281806Srpaulo 3180281806Srpaulo proto[cred->num_req_conn_capab] = atoi(value); 3181281806Srpaulo 3182281806Srpaulo pos = os_strchr(value, ':'); 3183281806Srpaulo if (pos == NULL) { 3184281806Srpaulo port[cred->num_req_conn_capab] = NULL; 3185281806Srpaulo cred->num_req_conn_capab++; 3186281806Srpaulo return 0; 3187281806Srpaulo } 3188281806Srpaulo pos++; 3189281806Srpaulo 3190281806Srpaulo ports = NULL; 3191281806Srpaulo num_ports = 0; 3192281806Srpaulo 3193281806Srpaulo while (*pos) { 3194281806Srpaulo nports = os_realloc_array(ports, num_ports + 1, sizeof(int)); 3195281806Srpaulo if (nports == NULL) { 3196281806Srpaulo os_free(ports); 3197281806Srpaulo return -1; 3198281806Srpaulo } 3199281806Srpaulo ports = nports; 3200281806Srpaulo ports[num_ports++] = atoi(pos); 3201281806Srpaulo 3202281806Srpaulo pos = os_strchr(pos, ','); 3203281806Srpaulo if (pos == NULL) 3204281806Srpaulo break; 3205281806Srpaulo pos++; 3206281806Srpaulo } 3207281806Srpaulo 3208281806Srpaulo nports = os_realloc_array(ports, num_ports + 1, sizeof(int)); 3209281806Srpaulo if (nports == NULL) { 3210281806Srpaulo os_free(ports); 3211281806Srpaulo return -1; 3212281806Srpaulo } 3213281806Srpaulo ports = nports; 3214281806Srpaulo ports[num_ports] = -1; 3215281806Srpaulo 3216281806Srpaulo port[cred->num_req_conn_capab] = ports; 3217281806Srpaulo cred->num_req_conn_capab++; 3218281806Srpaulo return 0; 3219281806Srpaulo} 3220281806Srpaulo 3221281806Srpaulo 3222346981Scystatic int wpa_config_set_cred_roaming_consortiums(struct wpa_cred *cred, 3223346981Scy const char *value) 3224346981Scy{ 3225346981Scy u8 roaming_consortiums[MAX_ROAMING_CONS][MAX_ROAMING_CONS_OI_LEN]; 3226346981Scy size_t roaming_consortiums_len[MAX_ROAMING_CONS]; 3227346981Scy unsigned int num_roaming_consortiums = 0; 3228346981Scy const char *pos, *end; 3229346981Scy size_t len; 3230346981Scy 3231346981Scy os_memset(roaming_consortiums, 0, sizeof(roaming_consortiums)); 3232346981Scy os_memset(roaming_consortiums_len, 0, sizeof(roaming_consortiums_len)); 3233346981Scy 3234346981Scy for (pos = value;;) { 3235346981Scy end = os_strchr(pos, ','); 3236346981Scy len = end ? (size_t) (end - pos) : os_strlen(pos); 3237346981Scy if (!end && len == 0) 3238346981Scy break; 3239346981Scy if (len == 0 || (len & 1) != 0 || 3240346981Scy len / 2 > MAX_ROAMING_CONS_OI_LEN || 3241346981Scy hexstr2bin(pos, 3242346981Scy roaming_consortiums[num_roaming_consortiums], 3243346981Scy len / 2) < 0) { 3244346981Scy wpa_printf(MSG_INFO, 3245346981Scy "Invalid roaming_consortiums entry: %s", 3246346981Scy pos); 3247346981Scy return -1; 3248346981Scy } 3249346981Scy roaming_consortiums_len[num_roaming_consortiums] = len / 2; 3250346981Scy num_roaming_consortiums++; 3251346981Scy 3252346981Scy if (!end) 3253346981Scy break; 3254346981Scy 3255346981Scy if (num_roaming_consortiums >= MAX_ROAMING_CONS) { 3256346981Scy wpa_printf(MSG_INFO, 3257346981Scy "Too many roaming_consortiums OIs"); 3258346981Scy return -1; 3259346981Scy } 3260346981Scy 3261346981Scy pos = end + 1; 3262346981Scy } 3263346981Scy 3264346981Scy os_memcpy(cred->roaming_consortiums, roaming_consortiums, 3265346981Scy sizeof(roaming_consortiums)); 3266346981Scy os_memcpy(cred->roaming_consortiums_len, roaming_consortiums_len, 3267346981Scy sizeof(roaming_consortiums_len)); 3268346981Scy cred->num_roaming_consortiums = num_roaming_consortiums; 3269346981Scy 3270346981Scy return 0; 3271346981Scy} 3272346981Scy 3273346981Scy 3274252726Srpauloint wpa_config_set_cred(struct wpa_cred *cred, const char *var, 3275252726Srpaulo const char *value, int line) 3276252726Srpaulo{ 3277252726Srpaulo char *val; 3278252726Srpaulo size_t len; 3279346981Scy int res; 3280252726Srpaulo 3281281806Srpaulo if (os_strcmp(var, "temporary") == 0) { 3282281806Srpaulo cred->temporary = atoi(value); 3283281806Srpaulo return 0; 3284281806Srpaulo } 3285281806Srpaulo 3286252726Srpaulo if (os_strcmp(var, "priority") == 0) { 3287252726Srpaulo cred->priority = atoi(value); 3288252726Srpaulo return 0; 3289252726Srpaulo } 3290252726Srpaulo 3291281806Srpaulo if (os_strcmp(var, "sp_priority") == 0) { 3292281806Srpaulo int prio = atoi(value); 3293281806Srpaulo if (prio < 0 || prio > 255) 3294281806Srpaulo return -1; 3295281806Srpaulo cred->sp_priority = prio; 3296281806Srpaulo return 0; 3297281806Srpaulo } 3298281806Srpaulo 3299252726Srpaulo if (os_strcmp(var, "pcsc") == 0) { 3300252726Srpaulo cred->pcsc = atoi(value); 3301252726Srpaulo return 0; 3302252726Srpaulo } 3303252726Srpaulo 3304252726Srpaulo if (os_strcmp(var, "eap") == 0) { 3305252726Srpaulo struct eap_method_type method; 3306252726Srpaulo method.method = eap_peer_get_type(value, &method.vendor); 3307252726Srpaulo if (method.vendor == EAP_VENDOR_IETF && 3308252726Srpaulo method.method == EAP_TYPE_NONE) { 3309252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: unknown EAP type '%s' " 3310252726Srpaulo "for a credential", line, value); 3311252726Srpaulo return -1; 3312252726Srpaulo } 3313252726Srpaulo os_free(cred->eap_method); 3314252726Srpaulo cred->eap_method = os_malloc(sizeof(*cred->eap_method)); 3315252726Srpaulo if (cred->eap_method == NULL) 3316252726Srpaulo return -1; 3317252726Srpaulo os_memcpy(cred->eap_method, &method, sizeof(method)); 3318252726Srpaulo return 0; 3319252726Srpaulo } 3320252726Srpaulo 3321252726Srpaulo if (os_strcmp(var, "password") == 0 && 3322252726Srpaulo os_strncmp(value, "ext:", 4) == 0) { 3323337817Scy if (has_newline(value)) 3324337817Scy return -1; 3325281806Srpaulo str_clear_free(cred->password); 3326252726Srpaulo cred->password = os_strdup(value); 3327252726Srpaulo cred->ext_password = 1; 3328252726Srpaulo return 0; 3329252726Srpaulo } 3330252726Srpaulo 3331281806Srpaulo if (os_strcmp(var, "update_identifier") == 0) { 3332281806Srpaulo cred->update_identifier = atoi(value); 3333281806Srpaulo return 0; 3334281806Srpaulo } 3335281806Srpaulo 3336281806Srpaulo if (os_strcmp(var, "min_dl_bandwidth_home") == 0) { 3337281806Srpaulo cred->min_dl_bandwidth_home = atoi(value); 3338281806Srpaulo return 0; 3339281806Srpaulo } 3340281806Srpaulo 3341281806Srpaulo if (os_strcmp(var, "min_ul_bandwidth_home") == 0) { 3342281806Srpaulo cred->min_ul_bandwidth_home = atoi(value); 3343281806Srpaulo return 0; 3344281806Srpaulo } 3345281806Srpaulo 3346281806Srpaulo if (os_strcmp(var, "min_dl_bandwidth_roaming") == 0) { 3347281806Srpaulo cred->min_dl_bandwidth_roaming = atoi(value); 3348281806Srpaulo return 0; 3349281806Srpaulo } 3350281806Srpaulo 3351281806Srpaulo if (os_strcmp(var, "min_ul_bandwidth_roaming") == 0) { 3352281806Srpaulo cred->min_ul_bandwidth_roaming = atoi(value); 3353281806Srpaulo return 0; 3354281806Srpaulo } 3355281806Srpaulo 3356281806Srpaulo if (os_strcmp(var, "max_bss_load") == 0) { 3357281806Srpaulo cred->max_bss_load = atoi(value); 3358281806Srpaulo return 0; 3359281806Srpaulo } 3360281806Srpaulo 3361281806Srpaulo if (os_strcmp(var, "req_conn_capab") == 0) 3362281806Srpaulo return wpa_config_set_cred_req_conn_capab(cred, value); 3363281806Srpaulo 3364281806Srpaulo if (os_strcmp(var, "ocsp") == 0) { 3365281806Srpaulo cred->ocsp = atoi(value); 3366281806Srpaulo return 0; 3367281806Srpaulo } 3368281806Srpaulo 3369281806Srpaulo if (os_strcmp(var, "sim_num") == 0) { 3370281806Srpaulo cred->sim_num = atoi(value); 3371281806Srpaulo return 0; 3372281806Srpaulo } 3373281806Srpaulo 3374252726Srpaulo val = wpa_config_parse_string(value, &len); 3375337817Scy if (val == NULL || 3376337817Scy (os_strcmp(var, "excluded_ssid") != 0 && 3377337817Scy os_strcmp(var, "roaming_consortium") != 0 && 3378337817Scy os_strcmp(var, "required_roaming_consortium") != 0 && 3379337817Scy has_newline(val))) { 3380252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid field '%s' string " 3381252726Srpaulo "value '%s'.", line, var, value); 3382337817Scy os_free(val); 3383252726Srpaulo return -1; 3384252726Srpaulo } 3385252726Srpaulo 3386252726Srpaulo if (os_strcmp(var, "realm") == 0) { 3387252726Srpaulo os_free(cred->realm); 3388252726Srpaulo cred->realm = val; 3389252726Srpaulo return 0; 3390252726Srpaulo } 3391252726Srpaulo 3392252726Srpaulo if (os_strcmp(var, "username") == 0) { 3393281806Srpaulo str_clear_free(cred->username); 3394252726Srpaulo cred->username = val; 3395252726Srpaulo return 0; 3396252726Srpaulo } 3397252726Srpaulo 3398252726Srpaulo if (os_strcmp(var, "password") == 0) { 3399281806Srpaulo str_clear_free(cred->password); 3400252726Srpaulo cred->password = val; 3401252726Srpaulo cred->ext_password = 0; 3402252726Srpaulo return 0; 3403252726Srpaulo } 3404252726Srpaulo 3405252726Srpaulo if (os_strcmp(var, "ca_cert") == 0) { 3406252726Srpaulo os_free(cred->ca_cert); 3407252726Srpaulo cred->ca_cert = val; 3408252726Srpaulo return 0; 3409252726Srpaulo } 3410252726Srpaulo 3411252726Srpaulo if (os_strcmp(var, "client_cert") == 0) { 3412252726Srpaulo os_free(cred->client_cert); 3413252726Srpaulo cred->client_cert = val; 3414252726Srpaulo return 0; 3415252726Srpaulo } 3416252726Srpaulo 3417252726Srpaulo if (os_strcmp(var, "private_key") == 0) { 3418252726Srpaulo os_free(cred->private_key); 3419252726Srpaulo cred->private_key = val; 3420252726Srpaulo return 0; 3421252726Srpaulo } 3422252726Srpaulo 3423252726Srpaulo if (os_strcmp(var, "private_key_passwd") == 0) { 3424281806Srpaulo str_clear_free(cred->private_key_passwd); 3425252726Srpaulo cred->private_key_passwd = val; 3426252726Srpaulo return 0; 3427252726Srpaulo } 3428252726Srpaulo 3429252726Srpaulo if (os_strcmp(var, "imsi") == 0) { 3430252726Srpaulo os_free(cred->imsi); 3431252726Srpaulo cred->imsi = val; 3432252726Srpaulo return 0; 3433252726Srpaulo } 3434252726Srpaulo 3435252726Srpaulo if (os_strcmp(var, "milenage") == 0) { 3436281806Srpaulo str_clear_free(cred->milenage); 3437252726Srpaulo cred->milenage = val; 3438252726Srpaulo return 0; 3439252726Srpaulo } 3440252726Srpaulo 3441281806Srpaulo if (os_strcmp(var, "domain_suffix_match") == 0) { 3442281806Srpaulo os_free(cred->domain_suffix_match); 3443281806Srpaulo cred->domain_suffix_match = val; 3444281806Srpaulo return 0; 3445281806Srpaulo } 3446281806Srpaulo 3447252726Srpaulo if (os_strcmp(var, "domain") == 0) { 3448281806Srpaulo char **new_domain; 3449281806Srpaulo new_domain = os_realloc_array(cred->domain, 3450281806Srpaulo cred->num_domain + 1, 3451281806Srpaulo sizeof(char *)); 3452281806Srpaulo if (new_domain == NULL) { 3453281806Srpaulo os_free(val); 3454281806Srpaulo return -1; 3455281806Srpaulo } 3456281806Srpaulo new_domain[cred->num_domain++] = val; 3457281806Srpaulo cred->domain = new_domain; 3458252726Srpaulo return 0; 3459252726Srpaulo } 3460252726Srpaulo 3461252726Srpaulo if (os_strcmp(var, "phase1") == 0) { 3462252726Srpaulo os_free(cred->phase1); 3463252726Srpaulo cred->phase1 = val; 3464252726Srpaulo return 0; 3465252726Srpaulo } 3466252726Srpaulo 3467252726Srpaulo if (os_strcmp(var, "phase2") == 0) { 3468252726Srpaulo os_free(cred->phase2); 3469252726Srpaulo cred->phase2 = val; 3470252726Srpaulo return 0; 3471252726Srpaulo } 3472252726Srpaulo 3473252726Srpaulo if (os_strcmp(var, "roaming_consortium") == 0) { 3474252726Srpaulo if (len < 3 || len > sizeof(cred->roaming_consortium)) { 3475252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid " 3476252726Srpaulo "roaming_consortium length %d (3..15 " 3477252726Srpaulo "expected)", line, (int) len); 3478252726Srpaulo os_free(val); 3479252726Srpaulo return -1; 3480252726Srpaulo } 3481252726Srpaulo os_memcpy(cred->roaming_consortium, val, len); 3482252726Srpaulo cred->roaming_consortium_len = len; 3483252726Srpaulo os_free(val); 3484252726Srpaulo return 0; 3485252726Srpaulo } 3486252726Srpaulo 3487281806Srpaulo if (os_strcmp(var, "required_roaming_consortium") == 0) { 3488281806Srpaulo if (len < 3 || len > sizeof(cred->required_roaming_consortium)) 3489281806Srpaulo { 3490281806Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid " 3491281806Srpaulo "required_roaming_consortium length %d " 3492281806Srpaulo "(3..15 expected)", line, (int) len); 3493281806Srpaulo os_free(val); 3494281806Srpaulo return -1; 3495281806Srpaulo } 3496281806Srpaulo os_memcpy(cred->required_roaming_consortium, val, len); 3497281806Srpaulo cred->required_roaming_consortium_len = len; 3498281806Srpaulo os_free(val); 3499281806Srpaulo return 0; 3500281806Srpaulo } 3501281806Srpaulo 3502346981Scy if (os_strcmp(var, "roaming_consortiums") == 0) { 3503346981Scy res = wpa_config_set_cred_roaming_consortiums(cred, val); 3504346981Scy if (res < 0) 3505346981Scy wpa_printf(MSG_ERROR, 3506346981Scy "Line %d: invalid roaming_consortiums", 3507346981Scy line); 3508346981Scy os_free(val); 3509346981Scy return res; 3510346981Scy } 3511346981Scy 3512252726Srpaulo if (os_strcmp(var, "excluded_ssid") == 0) { 3513252726Srpaulo struct excluded_ssid *e; 3514252726Srpaulo 3515289549Srpaulo if (len > SSID_MAX_LEN) { 3516252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid " 3517252726Srpaulo "excluded_ssid length %d", line, (int) len); 3518252726Srpaulo os_free(val); 3519252726Srpaulo return -1; 3520252726Srpaulo } 3521252726Srpaulo 3522252726Srpaulo e = os_realloc_array(cred->excluded_ssid, 3523252726Srpaulo cred->num_excluded_ssid + 1, 3524252726Srpaulo sizeof(struct excluded_ssid)); 3525252726Srpaulo if (e == NULL) { 3526252726Srpaulo os_free(val); 3527252726Srpaulo return -1; 3528252726Srpaulo } 3529252726Srpaulo cred->excluded_ssid = e; 3530252726Srpaulo 3531252726Srpaulo e = &cred->excluded_ssid[cred->num_excluded_ssid++]; 3532252726Srpaulo os_memcpy(e->ssid, val, len); 3533252726Srpaulo e->ssid_len = len; 3534252726Srpaulo 3535252726Srpaulo os_free(val); 3536252726Srpaulo 3537252726Srpaulo return 0; 3538252726Srpaulo } 3539252726Srpaulo 3540281806Srpaulo if (os_strcmp(var, "roaming_partner") == 0) { 3541281806Srpaulo struct roaming_partner *p; 3542281806Srpaulo char *pos; 3543281806Srpaulo 3544281806Srpaulo p = os_realloc_array(cred->roaming_partner, 3545281806Srpaulo cred->num_roaming_partner + 1, 3546281806Srpaulo sizeof(struct roaming_partner)); 3547281806Srpaulo if (p == NULL) { 3548281806Srpaulo os_free(val); 3549281806Srpaulo return -1; 3550281806Srpaulo } 3551281806Srpaulo cred->roaming_partner = p; 3552281806Srpaulo 3553281806Srpaulo p = &cred->roaming_partner[cred->num_roaming_partner]; 3554281806Srpaulo 3555281806Srpaulo pos = os_strchr(val, ','); 3556281806Srpaulo if (pos == NULL) { 3557281806Srpaulo os_free(val); 3558281806Srpaulo return -1; 3559281806Srpaulo } 3560281806Srpaulo *pos++ = '\0'; 3561281806Srpaulo if (pos - val - 1 >= (int) sizeof(p->fqdn)) { 3562281806Srpaulo os_free(val); 3563281806Srpaulo return -1; 3564281806Srpaulo } 3565281806Srpaulo os_memcpy(p->fqdn, val, pos - val); 3566281806Srpaulo 3567281806Srpaulo p->exact_match = atoi(pos); 3568281806Srpaulo 3569281806Srpaulo pos = os_strchr(pos, ','); 3570281806Srpaulo if (pos == NULL) { 3571281806Srpaulo os_free(val); 3572281806Srpaulo return -1; 3573281806Srpaulo } 3574281806Srpaulo *pos++ = '\0'; 3575281806Srpaulo 3576281806Srpaulo p->priority = atoi(pos); 3577281806Srpaulo 3578281806Srpaulo pos = os_strchr(pos, ','); 3579281806Srpaulo if (pos == NULL) { 3580281806Srpaulo os_free(val); 3581281806Srpaulo return -1; 3582281806Srpaulo } 3583281806Srpaulo *pos++ = '\0'; 3584281806Srpaulo 3585281806Srpaulo if (os_strlen(pos) >= sizeof(p->country)) { 3586281806Srpaulo os_free(val); 3587281806Srpaulo return -1; 3588281806Srpaulo } 3589281806Srpaulo os_memcpy(p->country, pos, os_strlen(pos) + 1); 3590281806Srpaulo 3591281806Srpaulo cred->num_roaming_partner++; 3592281806Srpaulo os_free(val); 3593281806Srpaulo 3594281806Srpaulo return 0; 3595281806Srpaulo } 3596281806Srpaulo 3597281806Srpaulo if (os_strcmp(var, "provisioning_sp") == 0) { 3598281806Srpaulo os_free(cred->provisioning_sp); 3599281806Srpaulo cred->provisioning_sp = val; 3600281806Srpaulo return 0; 3601281806Srpaulo } 3602281806Srpaulo 3603252726Srpaulo if (line) { 3604252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: unknown cred field '%s'.", 3605252726Srpaulo line, var); 3606252726Srpaulo } 3607252726Srpaulo 3608252726Srpaulo os_free(val); 3609252726Srpaulo 3610252726Srpaulo return -1; 3611252726Srpaulo} 3612252726Srpaulo 3613252726Srpaulo 3614281806Srpaulostatic char * alloc_int_str(int val) 3615281806Srpaulo{ 3616281806Srpaulo const unsigned int bufsize = 20; 3617281806Srpaulo char *buf; 3618281806Srpaulo int res; 3619281806Srpaulo 3620281806Srpaulo buf = os_malloc(bufsize); 3621281806Srpaulo if (buf == NULL) 3622281806Srpaulo return NULL; 3623281806Srpaulo res = os_snprintf(buf, bufsize, "%d", val); 3624281806Srpaulo if (os_snprintf_error(bufsize, res)) { 3625281806Srpaulo os_free(buf); 3626281806Srpaulo buf = NULL; 3627281806Srpaulo } 3628281806Srpaulo return buf; 3629281806Srpaulo} 3630281806Srpaulo 3631281806Srpaulo 3632281806Srpaulostatic char * alloc_strdup(const char *str) 3633281806Srpaulo{ 3634281806Srpaulo if (str == NULL) 3635281806Srpaulo return NULL; 3636281806Srpaulo return os_strdup(str); 3637281806Srpaulo} 3638281806Srpaulo 3639281806Srpaulo 3640281806Srpaulochar * wpa_config_get_cred_no_key(struct wpa_cred *cred, const char *var) 3641281806Srpaulo{ 3642281806Srpaulo if (os_strcmp(var, "temporary") == 0) 3643281806Srpaulo return alloc_int_str(cred->temporary); 3644281806Srpaulo 3645281806Srpaulo if (os_strcmp(var, "priority") == 0) 3646281806Srpaulo return alloc_int_str(cred->priority); 3647281806Srpaulo 3648281806Srpaulo if (os_strcmp(var, "sp_priority") == 0) 3649281806Srpaulo return alloc_int_str(cred->sp_priority); 3650281806Srpaulo 3651281806Srpaulo if (os_strcmp(var, "pcsc") == 0) 3652281806Srpaulo return alloc_int_str(cred->pcsc); 3653281806Srpaulo 3654281806Srpaulo if (os_strcmp(var, "eap") == 0) { 3655281806Srpaulo if (!cred->eap_method) 3656281806Srpaulo return NULL; 3657281806Srpaulo return alloc_strdup(eap_get_name(cred->eap_method[0].vendor, 3658281806Srpaulo cred->eap_method[0].method)); 3659281806Srpaulo } 3660281806Srpaulo 3661281806Srpaulo if (os_strcmp(var, "update_identifier") == 0) 3662281806Srpaulo return alloc_int_str(cred->update_identifier); 3663281806Srpaulo 3664281806Srpaulo if (os_strcmp(var, "min_dl_bandwidth_home") == 0) 3665281806Srpaulo return alloc_int_str(cred->min_dl_bandwidth_home); 3666281806Srpaulo 3667281806Srpaulo if (os_strcmp(var, "min_ul_bandwidth_home") == 0) 3668281806Srpaulo return alloc_int_str(cred->min_ul_bandwidth_home); 3669281806Srpaulo 3670281806Srpaulo if (os_strcmp(var, "min_dl_bandwidth_roaming") == 0) 3671281806Srpaulo return alloc_int_str(cred->min_dl_bandwidth_roaming); 3672281806Srpaulo 3673281806Srpaulo if (os_strcmp(var, "min_ul_bandwidth_roaming") == 0) 3674281806Srpaulo return alloc_int_str(cred->min_ul_bandwidth_roaming); 3675281806Srpaulo 3676281806Srpaulo if (os_strcmp(var, "max_bss_load") == 0) 3677281806Srpaulo return alloc_int_str(cred->max_bss_load); 3678281806Srpaulo 3679281806Srpaulo if (os_strcmp(var, "req_conn_capab") == 0) { 3680281806Srpaulo unsigned int i; 3681281806Srpaulo char *buf, *end, *pos; 3682281806Srpaulo int ret; 3683281806Srpaulo 3684281806Srpaulo if (!cred->num_req_conn_capab) 3685281806Srpaulo return NULL; 3686281806Srpaulo 3687281806Srpaulo buf = os_malloc(4000); 3688281806Srpaulo if (buf == NULL) 3689281806Srpaulo return NULL; 3690281806Srpaulo pos = buf; 3691281806Srpaulo end = pos + 4000; 3692281806Srpaulo for (i = 0; i < cred->num_req_conn_capab; i++) { 3693281806Srpaulo int *ports; 3694281806Srpaulo 3695281806Srpaulo ret = os_snprintf(pos, end - pos, "%s%u", 3696281806Srpaulo i > 0 ? "\n" : "", 3697281806Srpaulo cred->req_conn_capab_proto[i]); 3698281806Srpaulo if (os_snprintf_error(end - pos, ret)) 3699281806Srpaulo return buf; 3700281806Srpaulo pos += ret; 3701281806Srpaulo 3702281806Srpaulo ports = cred->req_conn_capab_port[i]; 3703281806Srpaulo if (ports) { 3704281806Srpaulo int j; 3705281806Srpaulo for (j = 0; ports[j] != -1; j++) { 3706281806Srpaulo ret = os_snprintf(pos, end - pos, 3707281806Srpaulo "%s%d", 3708281806Srpaulo j > 0 ? "," : ":", 3709281806Srpaulo ports[j]); 3710281806Srpaulo if (os_snprintf_error(end - pos, ret)) 3711281806Srpaulo return buf; 3712281806Srpaulo pos += ret; 3713281806Srpaulo } 3714281806Srpaulo } 3715281806Srpaulo } 3716281806Srpaulo 3717281806Srpaulo return buf; 3718281806Srpaulo } 3719281806Srpaulo 3720281806Srpaulo if (os_strcmp(var, "ocsp") == 0) 3721281806Srpaulo return alloc_int_str(cred->ocsp); 3722281806Srpaulo 3723281806Srpaulo if (os_strcmp(var, "realm") == 0) 3724281806Srpaulo return alloc_strdup(cred->realm); 3725281806Srpaulo 3726281806Srpaulo if (os_strcmp(var, "username") == 0) 3727281806Srpaulo return alloc_strdup(cred->username); 3728281806Srpaulo 3729281806Srpaulo if (os_strcmp(var, "password") == 0) { 3730281806Srpaulo if (!cred->password) 3731281806Srpaulo return NULL; 3732281806Srpaulo return alloc_strdup("*"); 3733281806Srpaulo } 3734281806Srpaulo 3735281806Srpaulo if (os_strcmp(var, "ca_cert") == 0) 3736281806Srpaulo return alloc_strdup(cred->ca_cert); 3737281806Srpaulo 3738281806Srpaulo if (os_strcmp(var, "client_cert") == 0) 3739281806Srpaulo return alloc_strdup(cred->client_cert); 3740281806Srpaulo 3741281806Srpaulo if (os_strcmp(var, "private_key") == 0) 3742281806Srpaulo return alloc_strdup(cred->private_key); 3743281806Srpaulo 3744281806Srpaulo if (os_strcmp(var, "private_key_passwd") == 0) { 3745281806Srpaulo if (!cred->private_key_passwd) 3746281806Srpaulo return NULL; 3747281806Srpaulo return alloc_strdup("*"); 3748281806Srpaulo } 3749281806Srpaulo 3750281806Srpaulo if (os_strcmp(var, "imsi") == 0) 3751281806Srpaulo return alloc_strdup(cred->imsi); 3752281806Srpaulo 3753281806Srpaulo if (os_strcmp(var, "milenage") == 0) { 3754281806Srpaulo if (!(cred->milenage)) 3755281806Srpaulo return NULL; 3756281806Srpaulo return alloc_strdup("*"); 3757281806Srpaulo } 3758281806Srpaulo 3759281806Srpaulo if (os_strcmp(var, "domain_suffix_match") == 0) 3760281806Srpaulo return alloc_strdup(cred->domain_suffix_match); 3761281806Srpaulo 3762281806Srpaulo if (os_strcmp(var, "domain") == 0) { 3763281806Srpaulo unsigned int i; 3764281806Srpaulo char *buf, *end, *pos; 3765281806Srpaulo int ret; 3766281806Srpaulo 3767281806Srpaulo if (!cred->num_domain) 3768281806Srpaulo return NULL; 3769281806Srpaulo 3770281806Srpaulo buf = os_malloc(4000); 3771281806Srpaulo if (buf == NULL) 3772281806Srpaulo return NULL; 3773281806Srpaulo pos = buf; 3774281806Srpaulo end = pos + 4000; 3775281806Srpaulo 3776281806Srpaulo for (i = 0; i < cred->num_domain; i++) { 3777281806Srpaulo ret = os_snprintf(pos, end - pos, "%s%s", 3778281806Srpaulo i > 0 ? "\n" : "", cred->domain[i]); 3779281806Srpaulo if (os_snprintf_error(end - pos, ret)) 3780281806Srpaulo return buf; 3781281806Srpaulo pos += ret; 3782281806Srpaulo } 3783281806Srpaulo 3784281806Srpaulo return buf; 3785281806Srpaulo } 3786281806Srpaulo 3787281806Srpaulo if (os_strcmp(var, "phase1") == 0) 3788281806Srpaulo return alloc_strdup(cred->phase1); 3789281806Srpaulo 3790281806Srpaulo if (os_strcmp(var, "phase2") == 0) 3791281806Srpaulo return alloc_strdup(cred->phase2); 3792281806Srpaulo 3793281806Srpaulo if (os_strcmp(var, "roaming_consortium") == 0) { 3794281806Srpaulo size_t buflen; 3795281806Srpaulo char *buf; 3796281806Srpaulo 3797281806Srpaulo if (!cred->roaming_consortium_len) 3798281806Srpaulo return NULL; 3799281806Srpaulo buflen = cred->roaming_consortium_len * 2 + 1; 3800281806Srpaulo buf = os_malloc(buflen); 3801281806Srpaulo if (buf == NULL) 3802281806Srpaulo return NULL; 3803281806Srpaulo wpa_snprintf_hex(buf, buflen, cred->roaming_consortium, 3804281806Srpaulo cred->roaming_consortium_len); 3805281806Srpaulo return buf; 3806281806Srpaulo } 3807281806Srpaulo 3808281806Srpaulo if (os_strcmp(var, "required_roaming_consortium") == 0) { 3809281806Srpaulo size_t buflen; 3810281806Srpaulo char *buf; 3811281806Srpaulo 3812281806Srpaulo if (!cred->required_roaming_consortium_len) 3813281806Srpaulo return NULL; 3814281806Srpaulo buflen = cred->required_roaming_consortium_len * 2 + 1; 3815281806Srpaulo buf = os_malloc(buflen); 3816281806Srpaulo if (buf == NULL) 3817281806Srpaulo return NULL; 3818281806Srpaulo wpa_snprintf_hex(buf, buflen, cred->required_roaming_consortium, 3819281806Srpaulo cred->required_roaming_consortium_len); 3820281806Srpaulo return buf; 3821281806Srpaulo } 3822281806Srpaulo 3823346981Scy if (os_strcmp(var, "roaming_consortiums") == 0) { 3824346981Scy size_t buflen; 3825346981Scy char *buf, *pos; 3826346981Scy size_t i; 3827346981Scy 3828346981Scy if (!cred->num_roaming_consortiums) 3829346981Scy return NULL; 3830346981Scy buflen = cred->num_roaming_consortiums * 3831346981Scy MAX_ROAMING_CONS_OI_LEN * 2 + 1; 3832346981Scy buf = os_malloc(buflen); 3833346981Scy if (!buf) 3834346981Scy return NULL; 3835346981Scy pos = buf; 3836346981Scy for (i = 0; i < cred->num_roaming_consortiums; i++) { 3837346981Scy if (i > 0) 3838346981Scy *pos++ = ','; 3839346981Scy pos += wpa_snprintf_hex( 3840346981Scy pos, buf + buflen - pos, 3841346981Scy cred->roaming_consortiums[i], 3842346981Scy cred->roaming_consortiums_len[i]); 3843346981Scy } 3844346981Scy *pos = '\0'; 3845346981Scy return buf; 3846346981Scy } 3847346981Scy 3848281806Srpaulo if (os_strcmp(var, "excluded_ssid") == 0) { 3849281806Srpaulo unsigned int i; 3850281806Srpaulo char *buf, *end, *pos; 3851281806Srpaulo 3852281806Srpaulo if (!cred->num_excluded_ssid) 3853281806Srpaulo return NULL; 3854281806Srpaulo 3855281806Srpaulo buf = os_malloc(4000); 3856281806Srpaulo if (buf == NULL) 3857281806Srpaulo return NULL; 3858281806Srpaulo pos = buf; 3859281806Srpaulo end = pos + 4000; 3860281806Srpaulo 3861281806Srpaulo for (i = 0; i < cred->num_excluded_ssid; i++) { 3862281806Srpaulo struct excluded_ssid *e; 3863281806Srpaulo int ret; 3864281806Srpaulo 3865281806Srpaulo e = &cred->excluded_ssid[i]; 3866281806Srpaulo ret = os_snprintf(pos, end - pos, "%s%s", 3867281806Srpaulo i > 0 ? "\n" : "", 3868281806Srpaulo wpa_ssid_txt(e->ssid, e->ssid_len)); 3869281806Srpaulo if (os_snprintf_error(end - pos, ret)) 3870281806Srpaulo return buf; 3871281806Srpaulo pos += ret; 3872281806Srpaulo } 3873281806Srpaulo 3874281806Srpaulo return buf; 3875281806Srpaulo } 3876281806Srpaulo 3877281806Srpaulo if (os_strcmp(var, "roaming_partner") == 0) { 3878281806Srpaulo unsigned int i; 3879281806Srpaulo char *buf, *end, *pos; 3880281806Srpaulo 3881281806Srpaulo if (!cred->num_roaming_partner) 3882281806Srpaulo return NULL; 3883281806Srpaulo 3884281806Srpaulo buf = os_malloc(4000); 3885281806Srpaulo if (buf == NULL) 3886281806Srpaulo return NULL; 3887281806Srpaulo pos = buf; 3888281806Srpaulo end = pos + 4000; 3889281806Srpaulo 3890281806Srpaulo for (i = 0; i < cred->num_roaming_partner; i++) { 3891281806Srpaulo struct roaming_partner *p; 3892281806Srpaulo int ret; 3893281806Srpaulo 3894281806Srpaulo p = &cred->roaming_partner[i]; 3895281806Srpaulo ret = os_snprintf(pos, end - pos, "%s%s,%d,%u,%s", 3896281806Srpaulo i > 0 ? "\n" : "", 3897281806Srpaulo p->fqdn, p->exact_match, p->priority, 3898281806Srpaulo p->country); 3899281806Srpaulo if (os_snprintf_error(end - pos, ret)) 3900281806Srpaulo return buf; 3901281806Srpaulo pos += ret; 3902281806Srpaulo } 3903281806Srpaulo 3904281806Srpaulo return buf; 3905281806Srpaulo } 3906281806Srpaulo 3907281806Srpaulo if (os_strcmp(var, "provisioning_sp") == 0) 3908281806Srpaulo return alloc_strdup(cred->provisioning_sp); 3909281806Srpaulo 3910281806Srpaulo return NULL; 3911281806Srpaulo} 3912281806Srpaulo 3913281806Srpaulo 3914252726Srpaulostruct wpa_cred * wpa_config_get_cred(struct wpa_config *config, int id) 3915252726Srpaulo{ 3916252726Srpaulo struct wpa_cred *cred; 3917252726Srpaulo 3918252726Srpaulo cred = config->cred; 3919252726Srpaulo while (cred) { 3920252726Srpaulo if (id == cred->id) 3921252726Srpaulo break; 3922252726Srpaulo cred = cred->next; 3923252726Srpaulo } 3924252726Srpaulo 3925252726Srpaulo return cred; 3926252726Srpaulo} 3927252726Srpaulo 3928252726Srpaulo 3929252726Srpaulostruct wpa_cred * wpa_config_add_cred(struct wpa_config *config) 3930252726Srpaulo{ 3931252726Srpaulo int id; 3932252726Srpaulo struct wpa_cred *cred, *last = NULL; 3933252726Srpaulo 3934252726Srpaulo id = -1; 3935252726Srpaulo cred = config->cred; 3936252726Srpaulo while (cred) { 3937252726Srpaulo if (cred->id > id) 3938252726Srpaulo id = cred->id; 3939252726Srpaulo last = cred; 3940252726Srpaulo cred = cred->next; 3941252726Srpaulo } 3942252726Srpaulo id++; 3943252726Srpaulo 3944252726Srpaulo cred = os_zalloc(sizeof(*cred)); 3945252726Srpaulo if (cred == NULL) 3946252726Srpaulo return NULL; 3947252726Srpaulo cred->id = id; 3948281806Srpaulo cred->sim_num = DEFAULT_USER_SELECTED_SIM; 3949252726Srpaulo if (last) 3950252726Srpaulo last->next = cred; 3951252726Srpaulo else 3952252726Srpaulo config->cred = cred; 3953252726Srpaulo 3954252726Srpaulo return cred; 3955252726Srpaulo} 3956252726Srpaulo 3957252726Srpaulo 3958252726Srpauloint wpa_config_remove_cred(struct wpa_config *config, int id) 3959252726Srpaulo{ 3960252726Srpaulo struct wpa_cred *cred, *prev = NULL; 3961252726Srpaulo 3962252726Srpaulo cred = config->cred; 3963252726Srpaulo while (cred) { 3964252726Srpaulo if (id == cred->id) 3965252726Srpaulo break; 3966252726Srpaulo prev = cred; 3967252726Srpaulo cred = cred->next; 3968252726Srpaulo } 3969252726Srpaulo 3970252726Srpaulo if (cred == NULL) 3971252726Srpaulo return -1; 3972252726Srpaulo 3973252726Srpaulo if (prev) 3974252726Srpaulo prev->next = cred->next; 3975252726Srpaulo else 3976252726Srpaulo config->cred = cred->next; 3977252726Srpaulo 3978252726Srpaulo wpa_config_free_cred(cred); 3979252726Srpaulo return 0; 3980252726Srpaulo} 3981252726Srpaulo 3982252726Srpaulo 3983189251Ssam#ifndef CONFIG_NO_CONFIG_BLOBS 3984189251Ssam/** 3985189251Ssam * wpa_config_get_blob - Get a named configuration blob 3986189251Ssam * @config: Configuration data from wpa_config_read() 3987189251Ssam * @name: Name of the blob 3988189251Ssam * Returns: Pointer to blob data or %NULL if not found 3989189251Ssam */ 3990189251Ssamconst struct wpa_config_blob * wpa_config_get_blob(struct wpa_config *config, 3991189251Ssam const char *name) 3992189251Ssam{ 3993189251Ssam struct wpa_config_blob *blob = config->blobs; 3994189251Ssam 3995189251Ssam while (blob) { 3996189251Ssam if (os_strcmp(blob->name, name) == 0) 3997189251Ssam return blob; 3998189251Ssam blob = blob->next; 3999189251Ssam } 4000189251Ssam return NULL; 4001189251Ssam} 4002189251Ssam 4003189251Ssam 4004189251Ssam/** 4005189251Ssam * wpa_config_set_blob - Set or add a named configuration blob 4006189251Ssam * @config: Configuration data from wpa_config_read() 4007189251Ssam * @blob: New value for the blob 4008189251Ssam * 4009189251Ssam * Adds a new configuration blob or replaces the current value of an existing 4010189251Ssam * blob. 4011189251Ssam */ 4012189251Ssamvoid wpa_config_set_blob(struct wpa_config *config, 4013189251Ssam struct wpa_config_blob *blob) 4014189251Ssam{ 4015189251Ssam wpa_config_remove_blob(config, blob->name); 4016189251Ssam blob->next = config->blobs; 4017189251Ssam config->blobs = blob; 4018189251Ssam} 4019189251Ssam 4020189251Ssam 4021189251Ssam/** 4022189251Ssam * wpa_config_free_blob - Free blob data 4023189251Ssam * @blob: Pointer to blob to be freed 4024189251Ssam */ 4025189251Ssamvoid wpa_config_free_blob(struct wpa_config_blob *blob) 4026189251Ssam{ 4027189251Ssam if (blob) { 4028189251Ssam os_free(blob->name); 4029281806Srpaulo bin_clear_free(blob->data, blob->len); 4030189251Ssam os_free(blob); 4031189251Ssam } 4032189251Ssam} 4033189251Ssam 4034189251Ssam 4035189251Ssam/** 4036189251Ssam * wpa_config_remove_blob - Remove a named configuration blob 4037189251Ssam * @config: Configuration data from wpa_config_read() 4038189251Ssam * @name: Name of the blob to remove 4039189251Ssam * Returns: 0 if blob was removed or -1 if blob was not found 4040189251Ssam */ 4041189251Ssamint wpa_config_remove_blob(struct wpa_config *config, const char *name) 4042189251Ssam{ 4043189251Ssam struct wpa_config_blob *pos = config->blobs, *prev = NULL; 4044189251Ssam 4045189251Ssam while (pos) { 4046189251Ssam if (os_strcmp(pos->name, name) == 0) { 4047189251Ssam if (prev) 4048189251Ssam prev->next = pos->next; 4049189251Ssam else 4050189251Ssam config->blobs = pos->next; 4051189251Ssam wpa_config_free_blob(pos); 4052189251Ssam return 0; 4053189251Ssam } 4054189251Ssam prev = pos; 4055189251Ssam pos = pos->next; 4056189251Ssam } 4057189251Ssam 4058189251Ssam return -1; 4059189251Ssam} 4060189251Ssam#endif /* CONFIG_NO_CONFIG_BLOBS */ 4061189251Ssam 4062189251Ssam 4063189251Ssam/** 4064189251Ssam * wpa_config_alloc_empty - Allocate an empty configuration 4065189251Ssam * @ctrl_interface: Control interface parameters, e.g., path to UNIX domain 4066189251Ssam * socket 4067189251Ssam * @driver_param: Driver parameters 4068189251Ssam * Returns: Pointer to allocated configuration data or %NULL on failure 4069189251Ssam */ 4070189251Ssamstruct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface, 4071189251Ssam const char *driver_param) 4072189251Ssam{ 4073189251Ssam struct wpa_config *config; 4074252726Srpaulo const int aCWmin = 4, aCWmax = 10; 4075252726Srpaulo const struct hostapd_wmm_ac_params ac_bk = 4076252726Srpaulo { aCWmin, aCWmax, 7, 0, 0 }; /* background traffic */ 4077252726Srpaulo const struct hostapd_wmm_ac_params ac_be = 4078252726Srpaulo { aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */ 4079252726Srpaulo const struct hostapd_wmm_ac_params ac_vi = /* video traffic */ 4080252726Srpaulo { aCWmin - 1, aCWmin, 2, 3000 / 32, 0 }; 4081252726Srpaulo const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */ 4082252726Srpaulo { aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 0 }; 4083189251Ssam 4084189251Ssam config = os_zalloc(sizeof(*config)); 4085189251Ssam if (config == NULL) 4086189251Ssam return NULL; 4087189251Ssam config->eapol_version = DEFAULT_EAPOL_VERSION; 4088189251Ssam config->ap_scan = DEFAULT_AP_SCAN; 4089281806Srpaulo config->user_mpm = DEFAULT_USER_MPM; 4090281806Srpaulo config->max_peer_links = DEFAULT_MAX_PEER_LINKS; 4091281806Srpaulo config->mesh_max_inactivity = DEFAULT_MESH_MAX_INACTIVITY; 4092289549Srpaulo config->dot11RSNASAERetransPeriod = 4093289549Srpaulo DEFAULT_DOT11_RSNA_SAE_RETRANS_PERIOD; 4094189251Ssam config->fast_reauth = DEFAULT_FAST_REAUTH; 4095252726Srpaulo config->p2p_go_intent = DEFAULT_P2P_GO_INTENT; 4096252726Srpaulo config->p2p_intra_bss = DEFAULT_P2P_INTRA_BSS; 4097289549Srpaulo config->p2p_go_freq_change_policy = DEFAULT_P2P_GO_FREQ_MOVE; 4098252726Srpaulo config->p2p_go_max_inactivity = DEFAULT_P2P_GO_MAX_INACTIVITY; 4099281806Srpaulo config->p2p_optimize_listen_chan = DEFAULT_P2P_OPTIMIZE_LISTEN_CHAN; 4100281806Srpaulo config->p2p_go_ctwindow = DEFAULT_P2P_GO_CTWINDOW; 4101214734Srpaulo config->bss_max_count = DEFAULT_BSS_MAX_COUNT; 4102252726Srpaulo config->bss_expiration_age = DEFAULT_BSS_EXPIRATION_AGE; 4103252726Srpaulo config->bss_expiration_scan_count = DEFAULT_BSS_EXPIRATION_SCAN_COUNT; 4104252726Srpaulo config->max_num_sta = DEFAULT_MAX_NUM_STA; 4105346981Scy config->ap_isolate = DEFAULT_AP_ISOLATE; 4106252726Srpaulo config->access_network_type = DEFAULT_ACCESS_NETWORK_TYPE; 4107281806Srpaulo config->scan_cur_freq = DEFAULT_SCAN_CUR_FREQ; 4108252726Srpaulo config->wmm_ac_params[0] = ac_be; 4109252726Srpaulo config->wmm_ac_params[1] = ac_bk; 4110252726Srpaulo config->wmm_ac_params[2] = ac_vi; 4111252726Srpaulo config->wmm_ac_params[3] = ac_vo; 4112281806Srpaulo config->p2p_search_delay = DEFAULT_P2P_SEARCH_DELAY; 4113281806Srpaulo config->rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME; 4114281806Srpaulo config->key_mgmt_offload = DEFAULT_KEY_MGMT_OFFLOAD; 4115281806Srpaulo config->cert_in_cb = DEFAULT_CERT_IN_CB; 4116337817Scy config->wpa_rsc_relaxation = DEFAULT_WPA_RSC_RELAXATION; 4117189251Ssam 4118337817Scy#ifdef CONFIG_MBO 4119337817Scy config->mbo_cell_capa = DEFAULT_MBO_CELL_CAPA; 4120346981Scy config->disassoc_imminent_rssi_threshold = 4121346981Scy DEFAULT_DISASSOC_IMMINENT_RSSI_THRESHOLD; 4122346981Scy config->oce = DEFAULT_OCE_SUPPORT; 4123337817Scy#endif /* CONFIG_MBO */ 4124337817Scy 4125189251Ssam if (ctrl_interface) 4126189251Ssam config->ctrl_interface = os_strdup(ctrl_interface); 4127189251Ssam if (driver_param) 4128189251Ssam config->driver_param = os_strdup(driver_param); 4129346981Scy config->gas_rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME; 4130189251Ssam 4131189251Ssam return config; 4132189251Ssam} 4133189251Ssam 4134189251Ssam 4135189251Ssam#ifndef CONFIG_NO_STDOUT_DEBUG 4136189251Ssam/** 4137189251Ssam * wpa_config_debug_dump_networks - Debug dump of configured networks 4138189251Ssam * @config: Configuration data from wpa_config_read() 4139189251Ssam */ 4140189251Ssamvoid wpa_config_debug_dump_networks(struct wpa_config *config) 4141189251Ssam{ 4142189251Ssam int prio; 4143189251Ssam struct wpa_ssid *ssid; 4144189251Ssam 4145189251Ssam for (prio = 0; prio < config->num_prio; prio++) { 4146189251Ssam ssid = config->pssid[prio]; 4147189251Ssam wpa_printf(MSG_DEBUG, "Priority group %d", 4148189251Ssam ssid->priority); 4149189251Ssam while (ssid) { 4150189251Ssam wpa_printf(MSG_DEBUG, " id=%d ssid='%s'", 4151189251Ssam ssid->id, 4152189251Ssam wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); 4153189251Ssam ssid = ssid->pnext; 4154189251Ssam } 4155189251Ssam } 4156189251Ssam} 4157189251Ssam#endif /* CONFIG_NO_STDOUT_DEBUG */ 4158252726Srpaulo 4159252726Srpaulo 4160252726Srpaulostruct global_parse_data { 4161252726Srpaulo char *name; 4162252726Srpaulo int (*parser)(const struct global_parse_data *data, 4163252726Srpaulo struct wpa_config *config, int line, const char *value); 4164281806Srpaulo int (*get)(const char *name, struct wpa_config *config, long offset, 4165281806Srpaulo char *buf, size_t buflen, int pretty_print); 4166252726Srpaulo void *param1, *param2, *param3; 4167252726Srpaulo unsigned int changed_flag; 4168252726Srpaulo}; 4169252726Srpaulo 4170252726Srpaulo 4171252726Srpaulostatic int wpa_global_config_parse_int(const struct global_parse_data *data, 4172252726Srpaulo struct wpa_config *config, int line, 4173252726Srpaulo const char *pos) 4174252726Srpaulo{ 4175281806Srpaulo int val, *dst; 4176281806Srpaulo char *end; 4177281806Srpaulo 4178252726Srpaulo dst = (int *) (((u8 *) config) + (long) data->param1); 4179281806Srpaulo val = strtol(pos, &end, 0); 4180281806Srpaulo if (*end) { 4181281806Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid number \"%s\"", 4182281806Srpaulo line, pos); 4183281806Srpaulo return -1; 4184281806Srpaulo } 4185281806Srpaulo *dst = val; 4186281806Srpaulo 4187252726Srpaulo wpa_printf(MSG_DEBUG, "%s=%d", data->name, *dst); 4188252726Srpaulo 4189252726Srpaulo if (data->param2 && *dst < (long) data->param2) { 4190252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d " 4191252726Srpaulo "min_value=%ld)", line, data->name, *dst, 4192252726Srpaulo (long) data->param2); 4193252726Srpaulo *dst = (long) data->param2; 4194252726Srpaulo return -1; 4195252726Srpaulo } 4196252726Srpaulo 4197252726Srpaulo if (data->param3 && *dst > (long) data->param3) { 4198252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d " 4199252726Srpaulo "max_value=%ld)", line, data->name, *dst, 4200252726Srpaulo (long) data->param3); 4201252726Srpaulo *dst = (long) data->param3; 4202252726Srpaulo return -1; 4203252726Srpaulo } 4204252726Srpaulo 4205252726Srpaulo return 0; 4206252726Srpaulo} 4207252726Srpaulo 4208252726Srpaulo 4209252726Srpaulostatic int wpa_global_config_parse_str(const struct global_parse_data *data, 4210252726Srpaulo struct wpa_config *config, int line, 4211252726Srpaulo const char *pos) 4212252726Srpaulo{ 4213252726Srpaulo size_t len; 4214252726Srpaulo char **dst, *tmp; 4215252726Srpaulo 4216252726Srpaulo len = os_strlen(pos); 4217252726Srpaulo if (data->param2 && len < (size_t) data->param2) { 4218252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu " 4219252726Srpaulo "min_len=%ld)", line, data->name, 4220252726Srpaulo (unsigned long) len, (long) data->param2); 4221252726Srpaulo return -1; 4222252726Srpaulo } 4223252726Srpaulo 4224252726Srpaulo if (data->param3 && len > (size_t) data->param3) { 4225252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu " 4226252726Srpaulo "max_len=%ld)", line, data->name, 4227252726Srpaulo (unsigned long) len, (long) data->param3); 4228252726Srpaulo return -1; 4229252726Srpaulo } 4230252726Srpaulo 4231337817Scy if (has_newline(pos)) { 4232337817Scy wpa_printf(MSG_ERROR, "Line %d: invalid %s value with newline", 4233337817Scy line, data->name); 4234337817Scy return -1; 4235337817Scy } 4236337817Scy 4237252726Srpaulo tmp = os_strdup(pos); 4238252726Srpaulo if (tmp == NULL) 4239252726Srpaulo return -1; 4240252726Srpaulo 4241252726Srpaulo dst = (char **) (((u8 *) config) + (long) data->param1); 4242252726Srpaulo os_free(*dst); 4243252726Srpaulo *dst = tmp; 4244252726Srpaulo wpa_printf(MSG_DEBUG, "%s='%s'", data->name, *dst); 4245252726Srpaulo 4246252726Srpaulo return 0; 4247252726Srpaulo} 4248252726Srpaulo 4249252726Srpaulo 4250281806Srpaulostatic int wpa_config_process_bgscan(const struct global_parse_data *data, 4251281806Srpaulo struct wpa_config *config, int line, 4252281806Srpaulo const char *pos) 4253281806Srpaulo{ 4254281806Srpaulo size_t len; 4255281806Srpaulo char *tmp; 4256281806Srpaulo int res; 4257281806Srpaulo 4258281806Srpaulo tmp = wpa_config_parse_string(pos, &len); 4259281806Srpaulo if (tmp == NULL) { 4260281806Srpaulo wpa_printf(MSG_ERROR, "Line %d: failed to parse %s", 4261281806Srpaulo line, data->name); 4262281806Srpaulo return -1; 4263281806Srpaulo } 4264281806Srpaulo 4265281806Srpaulo res = wpa_global_config_parse_str(data, config, line, tmp); 4266281806Srpaulo os_free(tmp); 4267281806Srpaulo return res; 4268281806Srpaulo} 4269281806Srpaulo 4270281806Srpaulo 4271252726Srpaulostatic int wpa_global_config_parse_bin(const struct global_parse_data *data, 4272252726Srpaulo struct wpa_config *config, int line, 4273252726Srpaulo const char *pos) 4274252726Srpaulo{ 4275252726Srpaulo struct wpabuf **dst, *tmp; 4276252726Srpaulo 4277337817Scy tmp = wpabuf_parse_bin(pos); 4278337817Scy if (!tmp) 4279252726Srpaulo return -1; 4280252726Srpaulo 4281252726Srpaulo dst = (struct wpabuf **) (((u8 *) config) + (long) data->param1); 4282252726Srpaulo wpabuf_free(*dst); 4283252726Srpaulo *dst = tmp; 4284252726Srpaulo wpa_printf(MSG_DEBUG, "%s", data->name); 4285252726Srpaulo 4286252726Srpaulo return 0; 4287252726Srpaulo} 4288252726Srpaulo 4289252726Srpaulo 4290281806Srpaulostatic int wpa_config_process_freq_list(const struct global_parse_data *data, 4291281806Srpaulo struct wpa_config *config, int line, 4292281806Srpaulo const char *value) 4293281806Srpaulo{ 4294281806Srpaulo int *freqs; 4295281806Srpaulo 4296281806Srpaulo freqs = wpa_config_parse_int_array(value); 4297281806Srpaulo if (freqs == NULL) 4298281806Srpaulo return -1; 4299281806Srpaulo if (freqs[0] == 0) { 4300281806Srpaulo os_free(freqs); 4301281806Srpaulo freqs = NULL; 4302281806Srpaulo } 4303281806Srpaulo os_free(config->freq_list); 4304281806Srpaulo config->freq_list = freqs; 4305281806Srpaulo return 0; 4306281806Srpaulo} 4307281806Srpaulo 4308281806Srpaulo 4309281806Srpaulo#ifdef CONFIG_P2P 4310281806Srpaulostatic int wpa_global_config_parse_ipv4(const struct global_parse_data *data, 4311281806Srpaulo struct wpa_config *config, int line, 4312281806Srpaulo const char *pos) 4313281806Srpaulo{ 4314281806Srpaulo u32 *dst; 4315281806Srpaulo struct hostapd_ip_addr addr; 4316281806Srpaulo 4317281806Srpaulo if (hostapd_parse_ip_addr(pos, &addr) < 0) 4318281806Srpaulo return -1; 4319281806Srpaulo if (addr.af != AF_INET) 4320281806Srpaulo return -1; 4321281806Srpaulo 4322281806Srpaulo dst = (u32 *) (((u8 *) config) + (long) data->param1); 4323281806Srpaulo os_memcpy(dst, &addr.u.v4.s_addr, 4); 4324281806Srpaulo wpa_printf(MSG_DEBUG, "%s = 0x%x", data->name, 4325281806Srpaulo WPA_GET_BE32((u8 *) dst)); 4326281806Srpaulo 4327281806Srpaulo return 0; 4328281806Srpaulo} 4329281806Srpaulo#endif /* CONFIG_P2P */ 4330281806Srpaulo 4331281806Srpaulo 4332252726Srpaulostatic int wpa_config_process_country(const struct global_parse_data *data, 4333252726Srpaulo struct wpa_config *config, int line, 4334252726Srpaulo const char *pos) 4335252726Srpaulo{ 4336252726Srpaulo if (!pos[0] || !pos[1]) { 4337252726Srpaulo wpa_printf(MSG_DEBUG, "Invalid country set"); 4338252726Srpaulo return -1; 4339252726Srpaulo } 4340252726Srpaulo config->country[0] = pos[0]; 4341252726Srpaulo config->country[1] = pos[1]; 4342252726Srpaulo wpa_printf(MSG_DEBUG, "country='%c%c'", 4343252726Srpaulo config->country[0], config->country[1]); 4344252726Srpaulo return 0; 4345252726Srpaulo} 4346252726Srpaulo 4347252726Srpaulo 4348252726Srpaulostatic int wpa_config_process_load_dynamic_eap( 4349252726Srpaulo const struct global_parse_data *data, struct wpa_config *config, 4350252726Srpaulo int line, const char *so) 4351252726Srpaulo{ 4352252726Srpaulo int ret; 4353252726Srpaulo wpa_printf(MSG_DEBUG, "load_dynamic_eap=%s", so); 4354252726Srpaulo ret = eap_peer_method_load(so); 4355252726Srpaulo if (ret == -2) { 4356252726Srpaulo wpa_printf(MSG_DEBUG, "This EAP type was already loaded - not " 4357252726Srpaulo "reloading."); 4358252726Srpaulo } else if (ret) { 4359252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: Failed to load dynamic EAP " 4360252726Srpaulo "method '%s'.", line, so); 4361252726Srpaulo return -1; 4362252726Srpaulo } 4363252726Srpaulo 4364252726Srpaulo return 0; 4365252726Srpaulo} 4366252726Srpaulo 4367252726Srpaulo 4368252726Srpaulo#ifdef CONFIG_WPS 4369252726Srpaulo 4370252726Srpaulostatic int wpa_config_process_uuid(const struct global_parse_data *data, 4371252726Srpaulo struct wpa_config *config, int line, 4372252726Srpaulo const char *pos) 4373252726Srpaulo{ 4374252726Srpaulo char buf[40]; 4375252726Srpaulo if (uuid_str2bin(pos, config->uuid)) { 4376252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid UUID", line); 4377252726Srpaulo return -1; 4378252726Srpaulo } 4379252726Srpaulo uuid_bin2str(config->uuid, buf, sizeof(buf)); 4380252726Srpaulo wpa_printf(MSG_DEBUG, "uuid=%s", buf); 4381252726Srpaulo return 0; 4382252726Srpaulo} 4383252726Srpaulo 4384252726Srpaulo 4385252726Srpaulostatic int wpa_config_process_device_type( 4386252726Srpaulo const struct global_parse_data *data, 4387252726Srpaulo struct wpa_config *config, int line, const char *pos) 4388252726Srpaulo{ 4389252726Srpaulo return wps_dev_type_str2bin(pos, config->device_type); 4390252726Srpaulo} 4391252726Srpaulo 4392252726Srpaulo 4393252726Srpaulostatic int wpa_config_process_os_version(const struct global_parse_data *data, 4394252726Srpaulo struct wpa_config *config, int line, 4395252726Srpaulo const char *pos) 4396252726Srpaulo{ 4397252726Srpaulo if (hexstr2bin(pos, config->os_version, 4)) { 4398252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid os_version", line); 4399252726Srpaulo return -1; 4400252726Srpaulo } 4401252726Srpaulo wpa_printf(MSG_DEBUG, "os_version=%08x", 4402252726Srpaulo WPA_GET_BE32(config->os_version)); 4403252726Srpaulo return 0; 4404252726Srpaulo} 4405252726Srpaulo 4406252726Srpaulo 4407252726Srpaulostatic int wpa_config_process_wps_vendor_ext_m1( 4408252726Srpaulo const struct global_parse_data *data, 4409252726Srpaulo struct wpa_config *config, int line, const char *pos) 4410252726Srpaulo{ 4411252726Srpaulo struct wpabuf *tmp; 4412252726Srpaulo int len = os_strlen(pos) / 2; 4413252726Srpaulo u8 *p; 4414252726Srpaulo 4415252726Srpaulo if (!len) { 4416252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: " 4417252726Srpaulo "invalid wps_vendor_ext_m1", line); 4418252726Srpaulo return -1; 4419252726Srpaulo } 4420252726Srpaulo 4421252726Srpaulo tmp = wpabuf_alloc(len); 4422252726Srpaulo if (tmp) { 4423252726Srpaulo p = wpabuf_put(tmp, len); 4424252726Srpaulo 4425252726Srpaulo if (hexstr2bin(pos, p, len)) { 4426252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: " 4427252726Srpaulo "invalid wps_vendor_ext_m1", line); 4428252726Srpaulo wpabuf_free(tmp); 4429252726Srpaulo return -1; 4430252726Srpaulo } 4431252726Srpaulo 4432252726Srpaulo wpabuf_free(config->wps_vendor_ext_m1); 4433252726Srpaulo config->wps_vendor_ext_m1 = tmp; 4434252726Srpaulo } else { 4435252726Srpaulo wpa_printf(MSG_ERROR, "Can not allocate " 4436252726Srpaulo "memory for wps_vendor_ext_m1"); 4437252726Srpaulo return -1; 4438252726Srpaulo } 4439252726Srpaulo 4440252726Srpaulo return 0; 4441252726Srpaulo} 4442252726Srpaulo 4443252726Srpaulo#endif /* CONFIG_WPS */ 4444252726Srpaulo 4445252726Srpaulo#ifdef CONFIG_P2P 4446252726Srpaulostatic int wpa_config_process_sec_device_type( 4447252726Srpaulo const struct global_parse_data *data, 4448252726Srpaulo struct wpa_config *config, int line, const char *pos) 4449252726Srpaulo{ 4450252726Srpaulo int idx; 4451252726Srpaulo 4452252726Srpaulo if (config->num_sec_device_types >= MAX_SEC_DEVICE_TYPES) { 4453252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: too many sec_device_type " 4454252726Srpaulo "items", line); 4455252726Srpaulo return -1; 4456252726Srpaulo } 4457252726Srpaulo 4458252726Srpaulo idx = config->num_sec_device_types; 4459252726Srpaulo 4460252726Srpaulo if (wps_dev_type_str2bin(pos, config->sec_device_type[idx])) 4461252726Srpaulo return -1; 4462252726Srpaulo 4463252726Srpaulo config->num_sec_device_types++; 4464252726Srpaulo return 0; 4465252726Srpaulo} 4466252726Srpaulo 4467252726Srpaulo 4468252726Srpaulostatic int wpa_config_process_p2p_pref_chan( 4469252726Srpaulo const struct global_parse_data *data, 4470252726Srpaulo struct wpa_config *config, int line, const char *pos) 4471252726Srpaulo{ 4472252726Srpaulo struct p2p_channel *pref = NULL, *n; 4473252726Srpaulo unsigned int num = 0; 4474252726Srpaulo const char *pos2; 4475252726Srpaulo u8 op_class, chan; 4476252726Srpaulo 4477252726Srpaulo /* format: class:chan,class:chan,... */ 4478252726Srpaulo 4479252726Srpaulo while (*pos) { 4480252726Srpaulo op_class = atoi(pos); 4481252726Srpaulo pos2 = os_strchr(pos, ':'); 4482252726Srpaulo if (pos2 == NULL) 4483252726Srpaulo goto fail; 4484252726Srpaulo pos2++; 4485252726Srpaulo chan = atoi(pos2); 4486252726Srpaulo 4487252726Srpaulo n = os_realloc_array(pref, num + 1, 4488252726Srpaulo sizeof(struct p2p_channel)); 4489252726Srpaulo if (n == NULL) 4490252726Srpaulo goto fail; 4491252726Srpaulo pref = n; 4492252726Srpaulo pref[num].op_class = op_class; 4493252726Srpaulo pref[num].chan = chan; 4494252726Srpaulo num++; 4495252726Srpaulo 4496252726Srpaulo pos = os_strchr(pos2, ','); 4497252726Srpaulo if (pos == NULL) 4498252726Srpaulo break; 4499252726Srpaulo pos++; 4500252726Srpaulo } 4501252726Srpaulo 4502252726Srpaulo os_free(config->p2p_pref_chan); 4503252726Srpaulo config->p2p_pref_chan = pref; 4504252726Srpaulo config->num_p2p_pref_chan = num; 4505252726Srpaulo wpa_hexdump(MSG_DEBUG, "P2P: Preferred class/channel pairs", 4506252726Srpaulo (u8 *) config->p2p_pref_chan, 4507252726Srpaulo config->num_p2p_pref_chan * sizeof(struct p2p_channel)); 4508252726Srpaulo 4509252726Srpaulo return 0; 4510252726Srpaulo 4511252726Srpaulofail: 4512252726Srpaulo os_free(pref); 4513252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid p2p_pref_chan list", line); 4514252726Srpaulo return -1; 4515252726Srpaulo} 4516281806Srpaulo 4517281806Srpaulo 4518281806Srpaulostatic int wpa_config_process_p2p_no_go_freq( 4519281806Srpaulo const struct global_parse_data *data, 4520281806Srpaulo struct wpa_config *config, int line, const char *pos) 4521281806Srpaulo{ 4522281806Srpaulo int ret; 4523281806Srpaulo 4524281806Srpaulo ret = freq_range_list_parse(&config->p2p_no_go_freq, pos); 4525281806Srpaulo if (ret < 0) { 4526281806Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid p2p_no_go_freq", line); 4527281806Srpaulo return -1; 4528281806Srpaulo } 4529281806Srpaulo 4530281806Srpaulo wpa_printf(MSG_DEBUG, "P2P: p2p_no_go_freq with %u items", 4531281806Srpaulo config->p2p_no_go_freq.num); 4532281806Srpaulo 4533281806Srpaulo return 0; 4534281806Srpaulo} 4535281806Srpaulo 4536346981Scy 4537346981Scystatic int wpa_config_process_p2p_device_persistent_mac_addr( 4538346981Scy const struct global_parse_data *data, 4539346981Scy struct wpa_config *config, int line, const char *pos) 4540346981Scy{ 4541346981Scy if (hwaddr_aton2(pos, config->p2p_device_persistent_mac_addr) < 0) { 4542346981Scy wpa_printf(MSG_ERROR, 4543346981Scy "Line %d: Invalid p2p_device_persistent_mac_addr '%s'", 4544346981Scy line, pos); 4545346981Scy return -1; 4546346981Scy } 4547346981Scy 4548346981Scy return 0; 4549346981Scy} 4550346981Scy 4551252726Srpaulo#endif /* CONFIG_P2P */ 4552252726Srpaulo 4553252726Srpaulo 4554252726Srpaulostatic int wpa_config_process_hessid( 4555252726Srpaulo const struct global_parse_data *data, 4556252726Srpaulo struct wpa_config *config, int line, const char *pos) 4557252726Srpaulo{ 4558252726Srpaulo if (hwaddr_aton2(pos, config->hessid) < 0) { 4559252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid hessid '%s'", 4560252726Srpaulo line, pos); 4561252726Srpaulo return -1; 4562252726Srpaulo } 4563252726Srpaulo 4564252726Srpaulo return 0; 4565252726Srpaulo} 4566252726Srpaulo 4567252726Srpaulo 4568281806Srpaulostatic int wpa_config_process_sae_groups( 4569281806Srpaulo const struct global_parse_data *data, 4570281806Srpaulo struct wpa_config *config, int line, const char *pos) 4571281806Srpaulo{ 4572281806Srpaulo int *groups = wpa_config_parse_int_array(pos); 4573281806Srpaulo if (groups == NULL) { 4574281806Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid sae_groups '%s'", 4575281806Srpaulo line, pos); 4576281806Srpaulo return -1; 4577281806Srpaulo } 4578281806Srpaulo 4579281806Srpaulo os_free(config->sae_groups); 4580281806Srpaulo config->sae_groups = groups; 4581281806Srpaulo 4582281806Srpaulo return 0; 4583281806Srpaulo} 4584281806Srpaulo 4585281806Srpaulo 4586281806Srpaulostatic int wpa_config_process_ap_vendor_elements( 4587281806Srpaulo const struct global_parse_data *data, 4588281806Srpaulo struct wpa_config *config, int line, const char *pos) 4589281806Srpaulo{ 4590281806Srpaulo struct wpabuf *tmp; 4591281806Srpaulo int len = os_strlen(pos) / 2; 4592281806Srpaulo u8 *p; 4593281806Srpaulo 4594281806Srpaulo if (!len) { 4595281806Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid ap_vendor_elements", 4596281806Srpaulo line); 4597281806Srpaulo return -1; 4598281806Srpaulo } 4599281806Srpaulo 4600281806Srpaulo tmp = wpabuf_alloc(len); 4601281806Srpaulo if (tmp) { 4602281806Srpaulo p = wpabuf_put(tmp, len); 4603281806Srpaulo 4604281806Srpaulo if (hexstr2bin(pos, p, len)) { 4605281806Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid " 4606281806Srpaulo "ap_vendor_elements", line); 4607281806Srpaulo wpabuf_free(tmp); 4608281806Srpaulo return -1; 4609281806Srpaulo } 4610281806Srpaulo 4611281806Srpaulo wpabuf_free(config->ap_vendor_elements); 4612281806Srpaulo config->ap_vendor_elements = tmp; 4613281806Srpaulo } else { 4614281806Srpaulo wpa_printf(MSG_ERROR, "Cannot allocate memory for " 4615281806Srpaulo "ap_vendor_elements"); 4616281806Srpaulo return -1; 4617281806Srpaulo } 4618281806Srpaulo 4619281806Srpaulo return 0; 4620281806Srpaulo} 4621281806Srpaulo 4622281806Srpaulo 4623281806Srpaulo#ifdef CONFIG_CTRL_IFACE 4624281806Srpaulostatic int wpa_config_process_no_ctrl_interface( 4625281806Srpaulo const struct global_parse_data *data, 4626281806Srpaulo struct wpa_config *config, int line, const char *pos) 4627281806Srpaulo{ 4628281806Srpaulo wpa_printf(MSG_DEBUG, "no_ctrl_interface -> ctrl_interface=NULL"); 4629281806Srpaulo os_free(config->ctrl_interface); 4630281806Srpaulo config->ctrl_interface = NULL; 4631281806Srpaulo return 0; 4632281806Srpaulo} 4633281806Srpaulo#endif /* CONFIG_CTRL_IFACE */ 4634281806Srpaulo 4635281806Srpaulo 4636281806Srpaulostatic int wpa_config_get_int(const char *name, struct wpa_config *config, 4637281806Srpaulo long offset, char *buf, size_t buflen, 4638281806Srpaulo int pretty_print) 4639281806Srpaulo{ 4640281806Srpaulo int *val = (int *) (((u8 *) config) + (long) offset); 4641281806Srpaulo 4642281806Srpaulo if (pretty_print) 4643281806Srpaulo return os_snprintf(buf, buflen, "%s=%d\n", name, *val); 4644281806Srpaulo return os_snprintf(buf, buflen, "%d", *val); 4645281806Srpaulo} 4646281806Srpaulo 4647281806Srpaulo 4648281806Srpaulostatic int wpa_config_get_str(const char *name, struct wpa_config *config, 4649281806Srpaulo long offset, char *buf, size_t buflen, 4650281806Srpaulo int pretty_print) 4651281806Srpaulo{ 4652281806Srpaulo char **val = (char **) (((u8 *) config) + (long) offset); 4653281806Srpaulo int res; 4654281806Srpaulo 4655281806Srpaulo if (pretty_print) 4656281806Srpaulo res = os_snprintf(buf, buflen, "%s=%s\n", name, 4657281806Srpaulo *val ? *val : "null"); 4658281806Srpaulo else if (!*val) 4659281806Srpaulo return -1; 4660281806Srpaulo else 4661281806Srpaulo res = os_snprintf(buf, buflen, "%s", *val); 4662281806Srpaulo if (os_snprintf_error(buflen, res)) 4663281806Srpaulo res = -1; 4664281806Srpaulo 4665281806Srpaulo return res; 4666281806Srpaulo} 4667281806Srpaulo 4668281806Srpaulo 4669289549Srpaulo#ifdef CONFIG_P2P 4670289549Srpaulostatic int wpa_config_get_ipv4(const char *name, struct wpa_config *config, 4671289549Srpaulo long offset, char *buf, size_t buflen, 4672289549Srpaulo int pretty_print) 4673289549Srpaulo{ 4674289549Srpaulo void *val = ((u8 *) config) + (long) offset; 4675289549Srpaulo int res; 4676289549Srpaulo char addr[INET_ADDRSTRLEN]; 4677289549Srpaulo 4678289549Srpaulo if (!val || !inet_ntop(AF_INET, val, addr, sizeof(addr))) 4679289549Srpaulo return -1; 4680289549Srpaulo 4681289549Srpaulo if (pretty_print) 4682289549Srpaulo res = os_snprintf(buf, buflen, "%s=%s\n", name, addr); 4683289549Srpaulo else 4684289549Srpaulo res = os_snprintf(buf, buflen, "%s", addr); 4685289549Srpaulo 4686289549Srpaulo if (os_snprintf_error(buflen, res)) 4687289549Srpaulo res = -1; 4688289549Srpaulo 4689289549Srpaulo return res; 4690289549Srpaulo} 4691289549Srpaulo#endif /* CONFIG_P2P */ 4692289549Srpaulo 4693289549Srpaulo 4694252726Srpaulo#ifdef OFFSET 4695252726Srpaulo#undef OFFSET 4696252726Srpaulo#endif /* OFFSET */ 4697252726Srpaulo/* OFFSET: Get offset of a variable within the wpa_config structure */ 4698252726Srpaulo#define OFFSET(v) ((void *) &((struct wpa_config *) 0)->v) 4699252726Srpaulo 4700281806Srpaulo#define FUNC(f) #f, wpa_config_process_ ## f, NULL, OFFSET(f), NULL, NULL 4701281806Srpaulo#define FUNC_NO_VAR(f) #f, wpa_config_process_ ## f, NULL, NULL, NULL, NULL 4702281806Srpaulo#define _INT(f) #f, wpa_global_config_parse_int, wpa_config_get_int, OFFSET(f) 4703252726Srpaulo#define INT(f) _INT(f), NULL, NULL 4704252726Srpaulo#define INT_RANGE(f, min, max) _INT(f), (void *) min, (void *) max 4705281806Srpaulo#define _STR(f) #f, wpa_global_config_parse_str, wpa_config_get_str, OFFSET(f) 4706252726Srpaulo#define STR(f) _STR(f), NULL, NULL 4707252726Srpaulo#define STR_RANGE(f, min, max) _STR(f), (void *) min, (void *) max 4708281806Srpaulo#define BIN(f) #f, wpa_global_config_parse_bin, NULL, OFFSET(f), NULL, NULL 4709289549Srpaulo#define IPV4(f) #f, wpa_global_config_parse_ipv4, wpa_config_get_ipv4, \ 4710289549Srpaulo OFFSET(f), NULL, NULL 4711252726Srpaulo 4712252726Srpaulostatic const struct global_parse_data global_fields[] = { 4713252726Srpaulo#ifdef CONFIG_CTRL_IFACE 4714252726Srpaulo { STR(ctrl_interface), 0 }, 4715281806Srpaulo { FUNC_NO_VAR(no_ctrl_interface), 0 }, 4716252726Srpaulo { STR(ctrl_interface_group), 0 } /* deprecated */, 4717252726Srpaulo#endif /* CONFIG_CTRL_IFACE */ 4718281806Srpaulo#ifdef CONFIG_MACSEC 4719281806Srpaulo { INT_RANGE(eapol_version, 1, 3), 0 }, 4720281806Srpaulo#else /* CONFIG_MACSEC */ 4721252726Srpaulo { INT_RANGE(eapol_version, 1, 2), 0 }, 4722281806Srpaulo#endif /* CONFIG_MACSEC */ 4723252726Srpaulo { INT(ap_scan), 0 }, 4724281806Srpaulo { FUNC(bgscan), 0 }, 4725281806Srpaulo#ifdef CONFIG_MESH 4726281806Srpaulo { INT(user_mpm), 0 }, 4727281806Srpaulo { INT_RANGE(max_peer_links, 0, 255), 0 }, 4728281806Srpaulo { INT(mesh_max_inactivity), 0 }, 4729289549Srpaulo { INT(dot11RSNASAERetransPeriod), 0 }, 4730281806Srpaulo#endif /* CONFIG_MESH */ 4731252726Srpaulo { INT(disable_scan_offload), 0 }, 4732252726Srpaulo { INT(fast_reauth), 0 }, 4733252726Srpaulo { STR(opensc_engine_path), 0 }, 4734252726Srpaulo { STR(pkcs11_engine_path), 0 }, 4735252726Srpaulo { STR(pkcs11_module_path), 0 }, 4736281806Srpaulo { STR(openssl_ciphers), 0 }, 4737252726Srpaulo { STR(pcsc_reader), 0 }, 4738252726Srpaulo { STR(pcsc_pin), 0 }, 4739281806Srpaulo { INT(external_sim), 0 }, 4740252726Srpaulo { STR(driver_param), 0 }, 4741252726Srpaulo { INT(dot11RSNAConfigPMKLifetime), 0 }, 4742252726Srpaulo { INT(dot11RSNAConfigPMKReauthThreshold), 0 }, 4743252726Srpaulo { INT(dot11RSNAConfigSATimeout), 0 }, 4744252726Srpaulo#ifndef CONFIG_NO_CONFIG_WRITE 4745252726Srpaulo { INT(update_config), 0 }, 4746252726Srpaulo#endif /* CONFIG_NO_CONFIG_WRITE */ 4747252726Srpaulo { FUNC_NO_VAR(load_dynamic_eap), 0 }, 4748252726Srpaulo#ifdef CONFIG_WPS 4749252726Srpaulo { FUNC(uuid), CFG_CHANGED_UUID }, 4750346981Scy { INT_RANGE(auto_uuid, 0, 1), 0 }, 4751289549Srpaulo { STR_RANGE(device_name, 0, WPS_DEV_NAME_MAX_LEN), 4752289549Srpaulo CFG_CHANGED_DEVICE_NAME }, 4753252726Srpaulo { STR_RANGE(manufacturer, 0, 64), CFG_CHANGED_WPS_STRING }, 4754252726Srpaulo { STR_RANGE(model_name, 0, 32), CFG_CHANGED_WPS_STRING }, 4755252726Srpaulo { STR_RANGE(model_number, 0, 32), CFG_CHANGED_WPS_STRING }, 4756252726Srpaulo { STR_RANGE(serial_number, 0, 32), CFG_CHANGED_WPS_STRING }, 4757252726Srpaulo { FUNC(device_type), CFG_CHANGED_DEVICE_TYPE }, 4758252726Srpaulo { FUNC(os_version), CFG_CHANGED_OS_VERSION }, 4759252726Srpaulo { STR(config_methods), CFG_CHANGED_CONFIG_METHODS }, 4760252726Srpaulo { INT_RANGE(wps_cred_processing, 0, 2), 0 }, 4761346981Scy { INT_RANGE(wps_cred_add_sae, 0, 1), 0 }, 4762252726Srpaulo { FUNC(wps_vendor_ext_m1), CFG_CHANGED_VENDOR_EXTENSION }, 4763252726Srpaulo#endif /* CONFIG_WPS */ 4764252726Srpaulo#ifdef CONFIG_P2P 4765252726Srpaulo { FUNC(sec_device_type), CFG_CHANGED_SEC_DEVICE_TYPE }, 4766289549Srpaulo { INT(p2p_listen_reg_class), CFG_CHANGED_P2P_LISTEN_CHANNEL }, 4767289549Srpaulo { INT(p2p_listen_channel), CFG_CHANGED_P2P_LISTEN_CHANNEL }, 4768281806Srpaulo { INT(p2p_oper_reg_class), CFG_CHANGED_P2P_OPER_CHANNEL }, 4769281806Srpaulo { INT(p2p_oper_channel), CFG_CHANGED_P2P_OPER_CHANNEL }, 4770252726Srpaulo { INT_RANGE(p2p_go_intent, 0, 15), 0 }, 4771252726Srpaulo { STR(p2p_ssid_postfix), CFG_CHANGED_P2P_SSID_POSTFIX }, 4772252726Srpaulo { INT_RANGE(persistent_reconnect, 0, 1), 0 }, 4773252726Srpaulo { INT_RANGE(p2p_intra_bss, 0, 1), CFG_CHANGED_P2P_INTRA_BSS }, 4774252726Srpaulo { INT(p2p_group_idle), 0 }, 4775289549Srpaulo { INT_RANGE(p2p_go_freq_change_policy, 0, P2P_GO_FREQ_MOVE_MAX), 0 }, 4776281806Srpaulo { INT_RANGE(p2p_passphrase_len, 8, 63), 4777281806Srpaulo CFG_CHANGED_P2P_PASSPHRASE_LEN }, 4778252726Srpaulo { FUNC(p2p_pref_chan), CFG_CHANGED_P2P_PREF_CHAN }, 4779281806Srpaulo { FUNC(p2p_no_go_freq), CFG_CHANGED_P2P_PREF_CHAN }, 4780281806Srpaulo { INT_RANGE(p2p_add_cli_chan, 0, 1), 0 }, 4781281806Srpaulo { INT_RANGE(p2p_optimize_listen_chan, 0, 1), 0 }, 4782252726Srpaulo { INT(p2p_go_ht40), 0 }, 4783281806Srpaulo { INT(p2p_go_vht), 0 }, 4784346981Scy { INT(p2p_go_he), 0 }, 4785252726Srpaulo { INT(p2p_disabled), 0 }, 4786281806Srpaulo { INT_RANGE(p2p_go_ctwindow, 0, 127), 0 }, 4787252726Srpaulo { INT(p2p_no_group_iface), 0 }, 4788281806Srpaulo { INT_RANGE(p2p_ignore_shared_freq, 0, 1), 0 }, 4789281806Srpaulo { IPV4(ip_addr_go), 0 }, 4790281806Srpaulo { IPV4(ip_addr_mask), 0 }, 4791281806Srpaulo { IPV4(ip_addr_start), 0 }, 4792281806Srpaulo { IPV4(ip_addr_end), 0 }, 4793289549Srpaulo { INT_RANGE(p2p_cli_probe, 0, 1), 0 }, 4794346981Scy { INT(p2p_device_random_mac_addr), 0 }, 4795346981Scy { FUNC(p2p_device_persistent_mac_addr), 0 }, 4796346981Scy { INT(p2p_interface_random_mac_addr), 0 }, 4797252726Srpaulo#endif /* CONFIG_P2P */ 4798252726Srpaulo { FUNC(country), CFG_CHANGED_COUNTRY }, 4799252726Srpaulo { INT(bss_max_count), 0 }, 4800252726Srpaulo { INT(bss_expiration_age), 0 }, 4801252726Srpaulo { INT(bss_expiration_scan_count), 0 }, 4802252726Srpaulo { INT_RANGE(filter_ssids, 0, 1), 0 }, 4803252726Srpaulo { INT_RANGE(filter_rssi, -100, 0), 0 }, 4804252726Srpaulo { INT(max_num_sta), 0 }, 4805346981Scy { INT_RANGE(ap_isolate, 0, 1), 0 }, 4806252726Srpaulo { INT_RANGE(disassoc_low_ack, 0, 1), 0 }, 4807252726Srpaulo#ifdef CONFIG_HS20 4808252726Srpaulo { INT_RANGE(hs20, 0, 1), 0 }, 4809252726Srpaulo#endif /* CONFIG_HS20 */ 4810252726Srpaulo { INT_RANGE(interworking, 0, 1), 0 }, 4811252726Srpaulo { FUNC(hessid), 0 }, 4812252726Srpaulo { INT_RANGE(access_network_type, 0, 15), 0 }, 4813346981Scy { INT_RANGE(go_interworking, 0, 1), 0 }, 4814346981Scy { INT_RANGE(go_access_network_type, 0, 15), 0 }, 4815346981Scy { INT_RANGE(go_internet, 0, 1), 0 }, 4816346981Scy { INT_RANGE(go_venue_group, 0, 255), 0 }, 4817346981Scy { INT_RANGE(go_venue_type, 0, 255), 0 }, 4818252726Srpaulo { INT_RANGE(pbc_in_m1, 0, 1), 0 }, 4819252726Srpaulo { STR(autoscan), 0 }, 4820281806Srpaulo { INT_RANGE(wps_nfc_dev_pw_id, 0x10, 0xffff), 4821281806Srpaulo CFG_CHANGED_NFC_PASSWORD_TOKEN }, 4822281806Srpaulo { BIN(wps_nfc_dh_pubkey), CFG_CHANGED_NFC_PASSWORD_TOKEN }, 4823281806Srpaulo { BIN(wps_nfc_dh_privkey), CFG_CHANGED_NFC_PASSWORD_TOKEN }, 4824281806Srpaulo { BIN(wps_nfc_dev_pw), CFG_CHANGED_NFC_PASSWORD_TOKEN }, 4825252726Srpaulo { STR(ext_password_backend), CFG_CHANGED_EXT_PW_BACKEND }, 4826252726Srpaulo { INT(p2p_go_max_inactivity), 0 }, 4827252726Srpaulo { INT_RANGE(auto_interworking, 0, 1), 0 }, 4828252726Srpaulo { INT(okc), 0 }, 4829252726Srpaulo { INT(pmf), 0 }, 4830281806Srpaulo { FUNC(sae_groups), 0 }, 4831281806Srpaulo { INT(dtim_period), 0 }, 4832281806Srpaulo { INT(beacon_int), 0 }, 4833281806Srpaulo { FUNC(ap_vendor_elements), 0 }, 4834281806Srpaulo { INT_RANGE(ignore_old_scan_res, 0, 1), 0 }, 4835281806Srpaulo { FUNC(freq_list), 0 }, 4836281806Srpaulo { INT(scan_cur_freq), 0 }, 4837281806Srpaulo { INT(sched_scan_interval), 0 }, 4838346981Scy { INT(sched_scan_start_delay), 0 }, 4839281806Srpaulo { INT(tdls_external_control), 0}, 4840281806Srpaulo { STR(osu_dir), 0 }, 4841346981Scy { STR(wowlan_triggers), CFG_CHANGED_WOWLAN_TRIGGERS }, 4842281806Srpaulo { INT(p2p_search_delay), 0}, 4843281806Srpaulo { INT(mac_addr), 0 }, 4844281806Srpaulo { INT(rand_addr_lifetime), 0 }, 4845281806Srpaulo { INT(preassoc_mac_addr), 0 }, 4846281806Srpaulo { INT(key_mgmt_offload), 0}, 4847281806Srpaulo { INT(passive_scan), 0 }, 4848281806Srpaulo { INT(reassoc_same_bss_optim), 0 }, 4849289549Srpaulo { INT(wps_priority), 0}, 4850289549Srpaulo#ifdef CONFIG_FST 4851289549Srpaulo { STR_RANGE(fst_group_id, 1, FST_MAX_GROUP_ID_LEN), 0 }, 4852289549Srpaulo { INT_RANGE(fst_priority, 1, FST_MAX_PRIO_VALUE), 0 }, 4853289549Srpaulo { INT_RANGE(fst_llt, 1, FST_MAX_LLT_MS), 0 }, 4854289549Srpaulo#endif /* CONFIG_FST */ 4855346981Scy { INT_RANGE(cert_in_cb, 0, 1), 0 }, 4856337817Scy { INT_RANGE(wpa_rsc_relaxation, 0, 1), 0 }, 4857337817Scy { STR(sched_scan_plans), CFG_CHANGED_SCHED_SCAN_PLANS }, 4858337817Scy#ifdef CONFIG_MBO 4859337817Scy { STR(non_pref_chan), 0 }, 4860337817Scy { INT_RANGE(mbo_cell_capa, MBO_CELL_CAPA_AVAILABLE, 4861337817Scy MBO_CELL_CAPA_NOT_SUPPORTED), 0 }, 4862346981Scy { INT_RANGE(disassoc_imminent_rssi_threshold, -120, 0), 0 }, 4863346981Scy { INT_RANGE(oce, 0, 3), 0 }, 4864346981Scy#endif /* CONFIG_MBO */ 4865337817Scy { INT(gas_address3), 0 }, 4866337817Scy { INT_RANGE(ftm_responder, 0, 1), 0 }, 4867337817Scy { INT_RANGE(ftm_initiator, 0, 1), 0 }, 4868346981Scy { INT(gas_rand_addr_lifetime), 0 }, 4869346981Scy { INT_RANGE(gas_rand_mac_addr, 0, 2), 0 }, 4870346981Scy { INT_RANGE(dpp_config_processing, 0, 2), 0 }, 4871346981Scy { INT_RANGE(coloc_intf_reporting, 0, 1), 0 }, 4872351611Scy#ifdef CONFIG_WNM 4873351611Scy { INT_RANGE(disable_btm, 0, 1), CFG_CHANGED_DISABLE_BTM }, 4874351611Scy#endif /* CONFIG_WNM */ 4875252726Srpaulo}; 4876252726Srpaulo 4877252726Srpaulo#undef FUNC 4878252726Srpaulo#undef _INT 4879252726Srpaulo#undef INT 4880252726Srpaulo#undef INT_RANGE 4881252726Srpaulo#undef _STR 4882252726Srpaulo#undef STR 4883252726Srpaulo#undef STR_RANGE 4884252726Srpaulo#undef BIN 4885281806Srpaulo#undef IPV4 4886281806Srpaulo#define NUM_GLOBAL_FIELDS ARRAY_SIZE(global_fields) 4887252726Srpaulo 4888252726Srpaulo 4889281806Srpauloint wpa_config_dump_values(struct wpa_config *config, char *buf, size_t buflen) 4890281806Srpaulo{ 4891281806Srpaulo int result = 0; 4892281806Srpaulo size_t i; 4893281806Srpaulo 4894281806Srpaulo for (i = 0; i < NUM_GLOBAL_FIELDS; i++) { 4895281806Srpaulo const struct global_parse_data *field = &global_fields[i]; 4896281806Srpaulo int tmp; 4897281806Srpaulo 4898281806Srpaulo if (!field->get) 4899281806Srpaulo continue; 4900281806Srpaulo 4901281806Srpaulo tmp = field->get(field->name, config, (long) field->param1, 4902281806Srpaulo buf, buflen, 1); 4903281806Srpaulo if (tmp < 0) 4904281806Srpaulo return -1; 4905281806Srpaulo buf += tmp; 4906281806Srpaulo buflen -= tmp; 4907281806Srpaulo result += tmp; 4908281806Srpaulo } 4909281806Srpaulo return result; 4910281806Srpaulo} 4911281806Srpaulo 4912281806Srpaulo 4913281806Srpauloint wpa_config_get_value(const char *name, struct wpa_config *config, 4914281806Srpaulo char *buf, size_t buflen) 4915281806Srpaulo{ 4916281806Srpaulo size_t i; 4917281806Srpaulo 4918281806Srpaulo for (i = 0; i < NUM_GLOBAL_FIELDS; i++) { 4919281806Srpaulo const struct global_parse_data *field = &global_fields[i]; 4920281806Srpaulo 4921281806Srpaulo if (os_strcmp(name, field->name) != 0) 4922281806Srpaulo continue; 4923281806Srpaulo if (!field->get) 4924281806Srpaulo break; 4925281806Srpaulo return field->get(name, config, (long) field->param1, 4926281806Srpaulo buf, buflen, 0); 4927281806Srpaulo } 4928281806Srpaulo 4929281806Srpaulo return -1; 4930281806Srpaulo} 4931281806Srpaulo 4932281806Srpaulo 4933337817Scyint wpa_config_get_num_global_field_names(void) 4934337817Scy{ 4935337817Scy return NUM_GLOBAL_FIELDS; 4936337817Scy} 4937337817Scy 4938337817Scy 4939337817Scyconst char * wpa_config_get_global_field_name(unsigned int i, int *no_var) 4940337817Scy{ 4941337817Scy if (i >= NUM_GLOBAL_FIELDS) 4942337817Scy return NULL; 4943337817Scy 4944337817Scy if (no_var) 4945337817Scy *no_var = !global_fields[i].param1; 4946337817Scy return global_fields[i].name; 4947337817Scy} 4948337817Scy 4949337817Scy 4950252726Srpauloint wpa_config_process_global(struct wpa_config *config, char *pos, int line) 4951252726Srpaulo{ 4952252726Srpaulo size_t i; 4953252726Srpaulo int ret = 0; 4954252726Srpaulo 4955252726Srpaulo for (i = 0; i < NUM_GLOBAL_FIELDS; i++) { 4956252726Srpaulo const struct global_parse_data *field = &global_fields[i]; 4957252726Srpaulo size_t flen = os_strlen(field->name); 4958252726Srpaulo if (os_strncmp(pos, field->name, flen) != 0 || 4959252726Srpaulo pos[flen] != '=') 4960252726Srpaulo continue; 4961252726Srpaulo 4962252726Srpaulo if (field->parser(field, config, line, pos + flen + 1)) { 4963252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: failed to " 4964252726Srpaulo "parse '%s'.", line, pos); 4965252726Srpaulo ret = -1; 4966252726Srpaulo } 4967281806Srpaulo if (field->changed_flag == CFG_CHANGED_NFC_PASSWORD_TOKEN) 4968281806Srpaulo config->wps_nfc_pw_from_config = 1; 4969252726Srpaulo config->changed_parameters |= field->changed_flag; 4970252726Srpaulo break; 4971252726Srpaulo } 4972252726Srpaulo if (i == NUM_GLOBAL_FIELDS) { 4973252726Srpaulo#ifdef CONFIG_AP 4974252726Srpaulo if (os_strncmp(pos, "wmm_ac_", 7) == 0) { 4975252726Srpaulo char *tmp = os_strchr(pos, '='); 4976252726Srpaulo if (tmp == NULL) { 4977252726Srpaulo if (line < 0) 4978252726Srpaulo return -1; 4979252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid line " 4980252726Srpaulo "'%s'", line, pos); 4981252726Srpaulo return -1; 4982252726Srpaulo } 4983252726Srpaulo *tmp++ = '\0'; 4984252726Srpaulo if (hostapd_config_wmm_ac(config->wmm_ac_params, pos, 4985252726Srpaulo tmp)) { 4986252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid WMM " 4987252726Srpaulo "AC item", line); 4988252726Srpaulo return -1; 4989252726Srpaulo } 4990252726Srpaulo } 4991252726Srpaulo#endif /* CONFIG_AP */ 4992252726Srpaulo if (line < 0) 4993252726Srpaulo return -1; 4994252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: unknown global field '%s'.", 4995252726Srpaulo line, pos); 4996252726Srpaulo ret = -1; 4997252726Srpaulo } 4998252726Srpaulo 4999252726Srpaulo return ret; 5000252726Srpaulo} 5001