1189251Ssam/* 2189251Ssam * WPA Supplicant / Configuration parser and common functions 3281806Srpaulo * Copyright (c) 2003-2015, 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" 14214734Srpaulo#include "crypto/sha1.h" 15214734Srpaulo#include "rsn_supp/wpa.h" 16189251Ssam#include "eap_peer/eap.h" 17252726Srpaulo#include "p2p/p2p.h" 18289549Srpaulo#include "fst/fst.h" 19189251Ssam#include "config.h" 20189251Ssam 21189251Ssam 22189251Ssam#if !defined(CONFIG_CTRL_IFACE) && defined(CONFIG_NO_CONFIG_WRITE) 23189251Ssam#define NO_CONFIG_WRITE 24189251Ssam#endif 25189251Ssam 26189251Ssam/* 27189251Ssam * Structure for network configuration parsing. This data is used to implement 28189251Ssam * a generic parser for each network block variable. The table of configuration 29189251Ssam * variables is defined below in this file (ssid_fields[]). 30189251Ssam */ 31189251Ssamstruct parse_data { 32189251Ssam /* Configuration variable name */ 33189251Ssam char *name; 34189251Ssam 35189251Ssam /* Parser function for this variable */ 36189251Ssam int (*parser)(const struct parse_data *data, struct wpa_ssid *ssid, 37189251Ssam int line, const char *value); 38189251Ssam 39189251Ssam#ifndef NO_CONFIG_WRITE 40189251Ssam /* Writer function (i.e., to get the variable in text format from 41189251Ssam * internal presentation). */ 42189251Ssam char * (*writer)(const struct parse_data *data, struct wpa_ssid *ssid); 43189251Ssam#endif /* NO_CONFIG_WRITE */ 44189251Ssam 45189251Ssam /* Variable specific parameters for the parser. */ 46189251Ssam void *param1, *param2, *param3, *param4; 47189251Ssam 48189251Ssam /* 0 = this variable can be included in debug output and ctrl_iface 49189251Ssam * 1 = this variable contains key/private data and it must not be 50189251Ssam * included in debug output unless explicitly requested. In 51189251Ssam * addition, this variable will not be readable through the 52189251Ssam * ctrl_iface. 53189251Ssam */ 54189251Ssam int key_data; 55189251Ssam}; 56189251Ssam 57189251Ssam 58189251Ssamstatic int wpa_config_parse_str(const struct parse_data *data, 59189251Ssam struct wpa_ssid *ssid, 60189251Ssam int line, const char *value) 61189251Ssam{ 62189251Ssam size_t res_len, *dst_len; 63189251Ssam char **dst, *tmp; 64189251Ssam 65189251Ssam if (os_strcmp(value, "NULL") == 0) { 66189251Ssam wpa_printf(MSG_DEBUG, "Unset configuration string '%s'", 67189251Ssam data->name); 68189251Ssam tmp = NULL; 69189251Ssam res_len = 0; 70189251Ssam goto set; 71189251Ssam } 72189251Ssam 73189251Ssam tmp = wpa_config_parse_string(value, &res_len); 74189251Ssam if (tmp == NULL) { 75189251Ssam wpa_printf(MSG_ERROR, "Line %d: failed to parse %s '%s'.", 76189251Ssam line, data->name, 77189251Ssam data->key_data ? "[KEY DATA REMOVED]" : value); 78189251Ssam return -1; 79189251Ssam } 80189251Ssam 81189251Ssam if (data->key_data) { 82189251Ssam wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name, 83189251Ssam (u8 *) tmp, res_len); 84189251Ssam } else { 85189251Ssam wpa_hexdump_ascii(MSG_MSGDUMP, data->name, 86189251Ssam (u8 *) tmp, res_len); 87189251Ssam } 88189251Ssam 89189251Ssam if (data->param3 && res_len < (size_t) data->param3) { 90189251Ssam wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu " 91189251Ssam "min_len=%ld)", line, data->name, 92189251Ssam (unsigned long) res_len, (long) data->param3); 93189251Ssam os_free(tmp); 94189251Ssam return -1; 95189251Ssam } 96189251Ssam 97189251Ssam if (data->param4 && res_len > (size_t) data->param4) { 98189251Ssam wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu " 99189251Ssam "max_len=%ld)", line, data->name, 100189251Ssam (unsigned long) res_len, (long) data->param4); 101189251Ssam os_free(tmp); 102189251Ssam return -1; 103189251Ssam } 104189251Ssam 105189251Ssamset: 106189251Ssam dst = (char **) (((u8 *) ssid) + (long) data->param1); 107189251Ssam dst_len = (size_t *) (((u8 *) ssid) + (long) data->param2); 108189251Ssam os_free(*dst); 109189251Ssam *dst = tmp; 110189251Ssam if (data->param2) 111189251Ssam *dst_len = res_len; 112189251Ssam 113189251Ssam return 0; 114189251Ssam} 115189251Ssam 116189251Ssam 117189251Ssam#ifndef NO_CONFIG_WRITE 118189251Ssamstatic char * wpa_config_write_string_ascii(const u8 *value, size_t len) 119189251Ssam{ 120189251Ssam char *buf; 121189251Ssam 122189251Ssam buf = os_malloc(len + 3); 123189251Ssam if (buf == NULL) 124189251Ssam return NULL; 125189251Ssam buf[0] = '"'; 126189251Ssam os_memcpy(buf + 1, value, len); 127189251Ssam buf[len + 1] = '"'; 128189251Ssam buf[len + 2] = '\0'; 129189251Ssam 130189251Ssam return buf; 131189251Ssam} 132189251Ssam 133189251Ssam 134189251Ssamstatic char * wpa_config_write_string_hex(const u8 *value, size_t len) 135189251Ssam{ 136189251Ssam char *buf; 137189251Ssam 138189251Ssam buf = os_zalloc(2 * len + 1); 139189251Ssam if (buf == NULL) 140189251Ssam return NULL; 141189251Ssam wpa_snprintf_hex(buf, 2 * len + 1, value, len); 142189251Ssam 143189251Ssam return buf; 144189251Ssam} 145189251Ssam 146189251Ssam 147189251Ssamstatic char * wpa_config_write_string(const u8 *value, size_t len) 148189251Ssam{ 149189251Ssam if (value == NULL) 150189251Ssam return NULL; 151189251Ssam 152189251Ssam if (is_hex(value, len)) 153189251Ssam return wpa_config_write_string_hex(value, len); 154189251Ssam else 155189251Ssam return wpa_config_write_string_ascii(value, len); 156189251Ssam} 157189251Ssam 158189251Ssam 159189251Ssamstatic char * wpa_config_write_str(const struct parse_data *data, 160189251Ssam struct wpa_ssid *ssid) 161189251Ssam{ 162189251Ssam size_t len; 163189251Ssam char **src; 164189251Ssam 165189251Ssam src = (char **) (((u8 *) ssid) + (long) data->param1); 166189251Ssam if (*src == NULL) 167189251Ssam return NULL; 168189251Ssam 169189251Ssam if (data->param2) 170189251Ssam len = *((size_t *) (((u8 *) ssid) + (long) data->param2)); 171189251Ssam else 172189251Ssam len = os_strlen(*src); 173189251Ssam 174189251Ssam return wpa_config_write_string((const u8 *) *src, len); 175189251Ssam} 176189251Ssam#endif /* NO_CONFIG_WRITE */ 177189251Ssam 178189251Ssam 179189251Ssamstatic int wpa_config_parse_int(const struct parse_data *data, 180189251Ssam struct wpa_ssid *ssid, 181189251Ssam int line, const char *value) 182189251Ssam{ 183281806Srpaulo int val, *dst; 184281806Srpaulo char *end; 185189251Ssam 186189251Ssam dst = (int *) (((u8 *) ssid) + (long) data->param1); 187281806Srpaulo val = strtol(value, &end, 0); 188281806Srpaulo if (*end) { 189281806Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid number \"%s\"", 190281806Srpaulo line, value); 191281806Srpaulo return -1; 192281806Srpaulo } 193281806Srpaulo *dst = val; 194189251Ssam wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst); 195189251Ssam 196189251Ssam if (data->param3 && *dst < (long) data->param3) { 197189251Ssam wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d " 198189251Ssam "min_value=%ld)", line, data->name, *dst, 199189251Ssam (long) data->param3); 200189251Ssam *dst = (long) data->param3; 201189251Ssam return -1; 202189251Ssam } 203189251Ssam 204189251Ssam if (data->param4 && *dst > (long) data->param4) { 205189251Ssam wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d " 206189251Ssam "max_value=%ld)", line, data->name, *dst, 207189251Ssam (long) data->param4); 208189251Ssam *dst = (long) data->param4; 209189251Ssam return -1; 210189251Ssam } 211189251Ssam 212189251Ssam return 0; 213189251Ssam} 214189251Ssam 215189251Ssam 216189251Ssam#ifndef NO_CONFIG_WRITE 217189251Ssamstatic char * wpa_config_write_int(const struct parse_data *data, 218189251Ssam struct wpa_ssid *ssid) 219189251Ssam{ 220189251Ssam int *src, res; 221189251Ssam char *value; 222189251Ssam 223189251Ssam src = (int *) (((u8 *) ssid) + (long) data->param1); 224189251Ssam 225189251Ssam value = os_malloc(20); 226189251Ssam if (value == NULL) 227189251Ssam return NULL; 228189251Ssam res = os_snprintf(value, 20, "%d", *src); 229281806Srpaulo if (os_snprintf_error(20, res)) { 230189251Ssam os_free(value); 231189251Ssam return NULL; 232189251Ssam } 233189251Ssam value[20 - 1] = '\0'; 234189251Ssam return value; 235189251Ssam} 236189251Ssam#endif /* NO_CONFIG_WRITE */ 237189251Ssam 238189251Ssam 239281806Srpaulostatic int wpa_config_parse_addr_list(const struct parse_data *data, 240281806Srpaulo int line, const char *value, 241281806Srpaulo u8 **list, size_t *num, char *name, 242281806Srpaulo u8 abort_on_error, u8 masked) 243281806Srpaulo{ 244281806Srpaulo const char *pos; 245281806Srpaulo u8 *buf, *n, addr[2 * ETH_ALEN]; 246281806Srpaulo size_t count; 247281806Srpaulo 248281806Srpaulo buf = NULL; 249281806Srpaulo count = 0; 250281806Srpaulo 251281806Srpaulo pos = value; 252281806Srpaulo while (pos && *pos) { 253281806Srpaulo while (*pos == ' ') 254281806Srpaulo pos++; 255281806Srpaulo 256281806Srpaulo if (hwaddr_masked_aton(pos, addr, &addr[ETH_ALEN], masked)) { 257281806Srpaulo if (abort_on_error || count == 0) { 258281806Srpaulo wpa_printf(MSG_ERROR, 259281806Srpaulo "Line %d: Invalid %s address '%s'", 260281806Srpaulo line, name, value); 261281806Srpaulo os_free(buf); 262281806Srpaulo return -1; 263281806Srpaulo } 264281806Srpaulo /* continue anyway since this could have been from a 265281806Srpaulo * truncated configuration file line */ 266281806Srpaulo wpa_printf(MSG_INFO, 267281806Srpaulo "Line %d: Ignore likely truncated %s address '%s'", 268281806Srpaulo line, name, pos); 269281806Srpaulo } else { 270281806Srpaulo n = os_realloc_array(buf, count + 1, 2 * ETH_ALEN); 271281806Srpaulo if (n == NULL) { 272281806Srpaulo os_free(buf); 273281806Srpaulo return -1; 274281806Srpaulo } 275281806Srpaulo buf = n; 276281806Srpaulo os_memmove(buf + 2 * ETH_ALEN, buf, 277281806Srpaulo count * 2 * ETH_ALEN); 278281806Srpaulo os_memcpy(buf, addr, 2 * ETH_ALEN); 279281806Srpaulo count++; 280281806Srpaulo wpa_printf(MSG_MSGDUMP, 281281806Srpaulo "%s: addr=" MACSTR " mask=" MACSTR, 282281806Srpaulo name, MAC2STR(addr), 283281806Srpaulo MAC2STR(&addr[ETH_ALEN])); 284281806Srpaulo } 285281806Srpaulo 286281806Srpaulo pos = os_strchr(pos, ' '); 287281806Srpaulo } 288281806Srpaulo 289281806Srpaulo os_free(*list); 290281806Srpaulo *list = buf; 291281806Srpaulo *num = count; 292281806Srpaulo 293281806Srpaulo return 0; 294281806Srpaulo} 295281806Srpaulo 296281806Srpaulo 297281806Srpaulo#ifndef NO_CONFIG_WRITE 298281806Srpaulostatic char * wpa_config_write_addr_list(const struct parse_data *data, 299281806Srpaulo const u8 *list, size_t num, char *name) 300281806Srpaulo{ 301281806Srpaulo char *value, *end, *pos; 302281806Srpaulo int res; 303281806Srpaulo size_t i; 304281806Srpaulo 305281806Srpaulo if (list == NULL || num == 0) 306281806Srpaulo return NULL; 307281806Srpaulo 308281806Srpaulo value = os_malloc(2 * 20 * num); 309281806Srpaulo if (value == NULL) 310281806Srpaulo return NULL; 311281806Srpaulo pos = value; 312281806Srpaulo end = value + 2 * 20 * num; 313281806Srpaulo 314281806Srpaulo for (i = num; i > 0; i--) { 315281806Srpaulo const u8 *a = list + (i - 1) * 2 * ETH_ALEN; 316281806Srpaulo const u8 *m = a + ETH_ALEN; 317281806Srpaulo 318281806Srpaulo if (i < num) 319281806Srpaulo *pos++ = ' '; 320281806Srpaulo res = hwaddr_mask_txt(pos, end - pos, a, m); 321281806Srpaulo if (res < 0) { 322281806Srpaulo os_free(value); 323281806Srpaulo return NULL; 324281806Srpaulo } 325281806Srpaulo pos += res; 326281806Srpaulo } 327281806Srpaulo 328281806Srpaulo return value; 329281806Srpaulo} 330281806Srpaulo#endif /* NO_CONFIG_WRITE */ 331281806Srpaulo 332189251Ssamstatic int wpa_config_parse_bssid(const struct parse_data *data, 333189251Ssam struct wpa_ssid *ssid, int line, 334189251Ssam const char *value) 335189251Ssam{ 336252726Srpaulo if (value[0] == '\0' || os_strcmp(value, "\"\"") == 0 || 337252726Srpaulo os_strcmp(value, "any") == 0) { 338252726Srpaulo ssid->bssid_set = 0; 339252726Srpaulo wpa_printf(MSG_MSGDUMP, "BSSID any"); 340252726Srpaulo return 0; 341252726Srpaulo } 342189251Ssam if (hwaddr_aton(value, ssid->bssid)) { 343189251Ssam wpa_printf(MSG_ERROR, "Line %d: Invalid BSSID '%s'.", 344189251Ssam line, value); 345189251Ssam return -1; 346189251Ssam } 347189251Ssam ssid->bssid_set = 1; 348189251Ssam wpa_hexdump(MSG_MSGDUMP, "BSSID", ssid->bssid, ETH_ALEN); 349189251Ssam return 0; 350189251Ssam} 351189251Ssam 352189251Ssam 353189251Ssam#ifndef NO_CONFIG_WRITE 354189251Ssamstatic char * wpa_config_write_bssid(const struct parse_data *data, 355189251Ssam struct wpa_ssid *ssid) 356189251Ssam{ 357189251Ssam char *value; 358189251Ssam int res; 359189251Ssam 360189251Ssam if (!ssid->bssid_set) 361189251Ssam return NULL; 362189251Ssam 363189251Ssam value = os_malloc(20); 364189251Ssam if (value == NULL) 365189251Ssam return NULL; 366189251Ssam res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->bssid)); 367281806Srpaulo if (os_snprintf_error(20, res)) { 368189251Ssam os_free(value); 369189251Ssam return NULL; 370189251Ssam } 371189251Ssam value[20 - 1] = '\0'; 372189251Ssam return value; 373189251Ssam} 374189251Ssam#endif /* NO_CONFIG_WRITE */ 375189251Ssam 376189251Ssam 377281806Srpaulostatic int wpa_config_parse_bssid_blacklist(const struct parse_data *data, 378281806Srpaulo struct wpa_ssid *ssid, int line, 379281806Srpaulo const char *value) 380281806Srpaulo{ 381281806Srpaulo return wpa_config_parse_addr_list(data, line, value, 382281806Srpaulo &ssid->bssid_blacklist, 383281806Srpaulo &ssid->num_bssid_blacklist, 384281806Srpaulo "bssid_blacklist", 1, 1); 385281806Srpaulo} 386281806Srpaulo 387281806Srpaulo 388281806Srpaulo#ifndef NO_CONFIG_WRITE 389281806Srpaulostatic char * wpa_config_write_bssid_blacklist(const struct parse_data *data, 390281806Srpaulo struct wpa_ssid *ssid) 391281806Srpaulo{ 392281806Srpaulo return wpa_config_write_addr_list(data, ssid->bssid_blacklist, 393281806Srpaulo ssid->num_bssid_blacklist, 394281806Srpaulo "bssid_blacklist"); 395281806Srpaulo} 396281806Srpaulo#endif /* NO_CONFIG_WRITE */ 397281806Srpaulo 398281806Srpaulo 399281806Srpaulostatic int wpa_config_parse_bssid_whitelist(const struct parse_data *data, 400281806Srpaulo struct wpa_ssid *ssid, int line, 401281806Srpaulo const char *value) 402281806Srpaulo{ 403281806Srpaulo return wpa_config_parse_addr_list(data, line, value, 404281806Srpaulo &ssid->bssid_whitelist, 405281806Srpaulo &ssid->num_bssid_whitelist, 406281806Srpaulo "bssid_whitelist", 1, 1); 407281806Srpaulo} 408281806Srpaulo 409281806Srpaulo 410281806Srpaulo#ifndef NO_CONFIG_WRITE 411281806Srpaulostatic char * wpa_config_write_bssid_whitelist(const struct parse_data *data, 412281806Srpaulo struct wpa_ssid *ssid) 413281806Srpaulo{ 414281806Srpaulo return wpa_config_write_addr_list(data, ssid->bssid_whitelist, 415281806Srpaulo ssid->num_bssid_whitelist, 416281806Srpaulo "bssid_whitelist"); 417281806Srpaulo} 418281806Srpaulo#endif /* NO_CONFIG_WRITE */ 419281806Srpaulo 420281806Srpaulo 421189251Ssamstatic int wpa_config_parse_psk(const struct parse_data *data, 422189251Ssam struct wpa_ssid *ssid, int line, 423189251Ssam const char *value) 424189251Ssam{ 425252726Srpaulo#ifdef CONFIG_EXT_PASSWORD 426252726Srpaulo if (os_strncmp(value, "ext:", 4) == 0) { 427281806Srpaulo str_clear_free(ssid->passphrase); 428252726Srpaulo ssid->passphrase = NULL; 429252726Srpaulo ssid->psk_set = 0; 430252726Srpaulo os_free(ssid->ext_psk); 431252726Srpaulo ssid->ext_psk = os_strdup(value + 4); 432252726Srpaulo if (ssid->ext_psk == NULL) 433252726Srpaulo return -1; 434252726Srpaulo wpa_printf(MSG_DEBUG, "PSK: External password '%s'", 435252726Srpaulo ssid->ext_psk); 436252726Srpaulo return 0; 437252726Srpaulo } 438252726Srpaulo#endif /* CONFIG_EXT_PASSWORD */ 439252726Srpaulo 440189251Ssam if (*value == '"') { 441189251Ssam#ifndef CONFIG_NO_PBKDF2 442189251Ssam const char *pos; 443189251Ssam size_t len; 444189251Ssam 445189251Ssam value++; 446189251Ssam pos = os_strrchr(value, '"'); 447189251Ssam if (pos) 448189251Ssam len = pos - value; 449189251Ssam else 450189251Ssam len = os_strlen(value); 451189251Ssam if (len < 8 || len > 63) { 452189251Ssam wpa_printf(MSG_ERROR, "Line %d: Invalid passphrase " 453189251Ssam "length %lu (expected: 8..63) '%s'.", 454189251Ssam line, (unsigned long) len, value); 455189251Ssam return -1; 456189251Ssam } 457189251Ssam wpa_hexdump_ascii_key(MSG_MSGDUMP, "PSK (ASCII passphrase)", 458189251Ssam (u8 *) value, len); 459189251Ssam if (ssid->passphrase && os_strlen(ssid->passphrase) == len && 460189251Ssam os_memcmp(ssid->passphrase, value, len) == 0) 461189251Ssam return 0; 462189251Ssam ssid->psk_set = 0; 463281806Srpaulo str_clear_free(ssid->passphrase); 464281806Srpaulo ssid->passphrase = dup_binstr(value, len); 465189251Ssam if (ssid->passphrase == NULL) 466189251Ssam return -1; 467189251Ssam return 0; 468189251Ssam#else /* CONFIG_NO_PBKDF2 */ 469189251Ssam wpa_printf(MSG_ERROR, "Line %d: ASCII passphrase not " 470189251Ssam "supported.", line); 471189251Ssam return -1; 472189251Ssam#endif /* CONFIG_NO_PBKDF2 */ 473189251Ssam } 474189251Ssam 475189251Ssam if (hexstr2bin(value, ssid->psk, PMK_LEN) || 476189251Ssam value[PMK_LEN * 2] != '\0') { 477189251Ssam wpa_printf(MSG_ERROR, "Line %d: Invalid PSK '%s'.", 478189251Ssam line, value); 479189251Ssam return -1; 480189251Ssam } 481189251Ssam 482281806Srpaulo str_clear_free(ssid->passphrase); 483189251Ssam ssid->passphrase = NULL; 484189251Ssam 485189251Ssam ssid->psk_set = 1; 486189251Ssam wpa_hexdump_key(MSG_MSGDUMP, "PSK", ssid->psk, PMK_LEN); 487189251Ssam return 0; 488189251Ssam} 489189251Ssam 490189251Ssam 491189251Ssam#ifndef NO_CONFIG_WRITE 492189251Ssamstatic char * wpa_config_write_psk(const struct parse_data *data, 493189251Ssam struct wpa_ssid *ssid) 494189251Ssam{ 495252726Srpaulo#ifdef CONFIG_EXT_PASSWORD 496252726Srpaulo if (ssid->ext_psk) { 497252726Srpaulo size_t len = 4 + os_strlen(ssid->ext_psk) + 1; 498252726Srpaulo char *buf = os_malloc(len); 499281806Srpaulo int res; 500281806Srpaulo 501252726Srpaulo if (buf == NULL) 502252726Srpaulo return NULL; 503281806Srpaulo res = os_snprintf(buf, len, "ext:%s", ssid->ext_psk); 504281806Srpaulo if (os_snprintf_error(len, res)) { 505281806Srpaulo os_free(buf); 506281806Srpaulo buf = NULL; 507281806Srpaulo } 508252726Srpaulo return buf; 509252726Srpaulo } 510252726Srpaulo#endif /* CONFIG_EXT_PASSWORD */ 511252726Srpaulo 512189251Ssam if (ssid->passphrase) 513189251Ssam return wpa_config_write_string_ascii( 514189251Ssam (const u8 *) ssid->passphrase, 515189251Ssam os_strlen(ssid->passphrase)); 516189251Ssam 517189251Ssam if (ssid->psk_set) 518189251Ssam return wpa_config_write_string_hex(ssid->psk, PMK_LEN); 519189251Ssam 520189251Ssam return NULL; 521189251Ssam} 522189251Ssam#endif /* NO_CONFIG_WRITE */ 523189251Ssam 524189251Ssam 525189251Ssamstatic int wpa_config_parse_proto(const struct parse_data *data, 526189251Ssam struct wpa_ssid *ssid, int line, 527189251Ssam const char *value) 528189251Ssam{ 529189251Ssam int val = 0, last, errors = 0; 530189251Ssam char *start, *end, *buf; 531189251Ssam 532189251Ssam buf = os_strdup(value); 533189251Ssam if (buf == NULL) 534189251Ssam return -1; 535189251Ssam start = buf; 536189251Ssam 537189251Ssam while (*start != '\0') { 538189251Ssam while (*start == ' ' || *start == '\t') 539189251Ssam start++; 540189251Ssam if (*start == '\0') 541189251Ssam break; 542189251Ssam end = start; 543189251Ssam while (*end != ' ' && *end != '\t' && *end != '\0') 544189251Ssam end++; 545189251Ssam last = *end == '\0'; 546189251Ssam *end = '\0'; 547189251Ssam if (os_strcmp(start, "WPA") == 0) 548189251Ssam val |= WPA_PROTO_WPA; 549189251Ssam else if (os_strcmp(start, "RSN") == 0 || 550189251Ssam os_strcmp(start, "WPA2") == 0) 551189251Ssam val |= WPA_PROTO_RSN; 552281806Srpaulo else if (os_strcmp(start, "OSEN") == 0) 553281806Srpaulo val |= WPA_PROTO_OSEN; 554189251Ssam else { 555189251Ssam wpa_printf(MSG_ERROR, "Line %d: invalid proto '%s'", 556189251Ssam line, start); 557189251Ssam errors++; 558189251Ssam } 559189251Ssam 560189251Ssam if (last) 561189251Ssam break; 562189251Ssam start = end + 1; 563189251Ssam } 564189251Ssam os_free(buf); 565189251Ssam 566189251Ssam if (val == 0) { 567189251Ssam wpa_printf(MSG_ERROR, 568189251Ssam "Line %d: no proto values configured.", line); 569189251Ssam errors++; 570189251Ssam } 571189251Ssam 572189251Ssam wpa_printf(MSG_MSGDUMP, "proto: 0x%x", val); 573189251Ssam ssid->proto = val; 574189251Ssam return errors ? -1 : 0; 575189251Ssam} 576189251Ssam 577189251Ssam 578189251Ssam#ifndef NO_CONFIG_WRITE 579189251Ssamstatic char * wpa_config_write_proto(const struct parse_data *data, 580189251Ssam struct wpa_ssid *ssid) 581189251Ssam{ 582281806Srpaulo int ret; 583189251Ssam char *buf, *pos, *end; 584189251Ssam 585281806Srpaulo pos = buf = os_zalloc(20); 586189251Ssam if (buf == NULL) 587189251Ssam return NULL; 588281806Srpaulo end = buf + 20; 589189251Ssam 590189251Ssam if (ssid->proto & WPA_PROTO_WPA) { 591281806Srpaulo ret = os_snprintf(pos, end - pos, "%sWPA", 592281806Srpaulo pos == buf ? "" : " "); 593281806Srpaulo if (os_snprintf_error(end - pos, ret)) 594189251Ssam return buf; 595189251Ssam pos += ret; 596189251Ssam } 597189251Ssam 598189251Ssam if (ssid->proto & WPA_PROTO_RSN) { 599281806Srpaulo ret = os_snprintf(pos, end - pos, "%sRSN", 600281806Srpaulo pos == buf ? "" : " "); 601281806Srpaulo if (os_snprintf_error(end - pos, ret)) 602189251Ssam return buf; 603189251Ssam pos += ret; 604189251Ssam } 605189251Ssam 606281806Srpaulo if (ssid->proto & WPA_PROTO_OSEN) { 607281806Srpaulo ret = os_snprintf(pos, end - pos, "%sOSEN", 608281806Srpaulo pos == buf ? "" : " "); 609281806Srpaulo if (os_snprintf_error(end - pos, ret)) 610281806Srpaulo return buf; 611281806Srpaulo pos += ret; 612281806Srpaulo } 613281806Srpaulo 614281806Srpaulo if (pos == buf) { 615281806Srpaulo os_free(buf); 616281806Srpaulo buf = NULL; 617281806Srpaulo } 618281806Srpaulo 619189251Ssam return buf; 620189251Ssam} 621189251Ssam#endif /* NO_CONFIG_WRITE */ 622189251Ssam 623189251Ssam 624189251Ssamstatic int wpa_config_parse_key_mgmt(const struct parse_data *data, 625189251Ssam struct wpa_ssid *ssid, int line, 626189251Ssam const char *value) 627189251Ssam{ 628189251Ssam int val = 0, last, errors = 0; 629189251Ssam char *start, *end, *buf; 630189251Ssam 631189251Ssam buf = os_strdup(value); 632189251Ssam if (buf == NULL) 633189251Ssam return -1; 634189251Ssam start = buf; 635189251Ssam 636189251Ssam while (*start != '\0') { 637189251Ssam while (*start == ' ' || *start == '\t') 638189251Ssam start++; 639189251Ssam if (*start == '\0') 640189251Ssam break; 641189251Ssam end = start; 642189251Ssam while (*end != ' ' && *end != '\t' && *end != '\0') 643189251Ssam end++; 644189251Ssam last = *end == '\0'; 645189251Ssam *end = '\0'; 646189251Ssam if (os_strcmp(start, "WPA-PSK") == 0) 647189251Ssam val |= WPA_KEY_MGMT_PSK; 648189251Ssam else if (os_strcmp(start, "WPA-EAP") == 0) 649189251Ssam val |= WPA_KEY_MGMT_IEEE8021X; 650189251Ssam else if (os_strcmp(start, "IEEE8021X") == 0) 651189251Ssam val |= WPA_KEY_MGMT_IEEE8021X_NO_WPA; 652189251Ssam else if (os_strcmp(start, "NONE") == 0) 653189251Ssam val |= WPA_KEY_MGMT_NONE; 654189251Ssam else if (os_strcmp(start, "WPA-NONE") == 0) 655189251Ssam val |= WPA_KEY_MGMT_WPA_NONE; 656189251Ssam#ifdef CONFIG_IEEE80211R 657189251Ssam else if (os_strcmp(start, "FT-PSK") == 0) 658189251Ssam val |= WPA_KEY_MGMT_FT_PSK; 659189251Ssam else if (os_strcmp(start, "FT-EAP") == 0) 660189251Ssam val |= WPA_KEY_MGMT_FT_IEEE8021X; 661189251Ssam#endif /* CONFIG_IEEE80211R */ 662189251Ssam#ifdef CONFIG_IEEE80211W 663189251Ssam else if (os_strcmp(start, "WPA-PSK-SHA256") == 0) 664189251Ssam val |= WPA_KEY_MGMT_PSK_SHA256; 665189251Ssam else if (os_strcmp(start, "WPA-EAP-SHA256") == 0) 666189251Ssam val |= WPA_KEY_MGMT_IEEE8021X_SHA256; 667189251Ssam#endif /* CONFIG_IEEE80211W */ 668189251Ssam#ifdef CONFIG_WPS 669189251Ssam else if (os_strcmp(start, "WPS") == 0) 670189251Ssam val |= WPA_KEY_MGMT_WPS; 671189251Ssam#endif /* CONFIG_WPS */ 672252726Srpaulo#ifdef CONFIG_SAE 673252726Srpaulo else if (os_strcmp(start, "SAE") == 0) 674252726Srpaulo val |= WPA_KEY_MGMT_SAE; 675252726Srpaulo else if (os_strcmp(start, "FT-SAE") == 0) 676252726Srpaulo val |= WPA_KEY_MGMT_FT_SAE; 677252726Srpaulo#endif /* CONFIG_SAE */ 678281806Srpaulo#ifdef CONFIG_HS20 679281806Srpaulo else if (os_strcmp(start, "OSEN") == 0) 680281806Srpaulo val |= WPA_KEY_MGMT_OSEN; 681281806Srpaulo#endif /* CONFIG_HS20 */ 682281806Srpaulo#ifdef CONFIG_SUITEB 683281806Srpaulo else if (os_strcmp(start, "WPA-EAP-SUITE-B") == 0) 684281806Srpaulo val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B; 685281806Srpaulo#endif /* CONFIG_SUITEB */ 686281806Srpaulo#ifdef CONFIG_SUITEB192 687281806Srpaulo else if (os_strcmp(start, "WPA-EAP-SUITE-B-192") == 0) 688281806Srpaulo val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B_192; 689281806Srpaulo#endif /* CONFIG_SUITEB192 */ 690189251Ssam else { 691189251Ssam wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'", 692189251Ssam line, start); 693189251Ssam errors++; 694189251Ssam } 695189251Ssam 696189251Ssam if (last) 697189251Ssam break; 698189251Ssam start = end + 1; 699189251Ssam } 700189251Ssam os_free(buf); 701189251Ssam 702189251Ssam if (val == 0) { 703189251Ssam wpa_printf(MSG_ERROR, 704189251Ssam "Line %d: no key_mgmt values configured.", line); 705189251Ssam errors++; 706189251Ssam } 707189251Ssam 708189251Ssam wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", val); 709189251Ssam ssid->key_mgmt = val; 710189251Ssam return errors ? -1 : 0; 711189251Ssam} 712189251Ssam 713189251Ssam 714189251Ssam#ifndef NO_CONFIG_WRITE 715189251Ssamstatic char * wpa_config_write_key_mgmt(const struct parse_data *data, 716189251Ssam struct wpa_ssid *ssid) 717189251Ssam{ 718189251Ssam char *buf, *pos, *end; 719189251Ssam int ret; 720189251Ssam 721281806Srpaulo pos = buf = os_zalloc(100); 722189251Ssam if (buf == NULL) 723189251Ssam return NULL; 724281806Srpaulo end = buf + 100; 725189251Ssam 726189251Ssam if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) { 727189251Ssam ret = os_snprintf(pos, end - pos, "%sWPA-PSK", 728189251Ssam pos == buf ? "" : " "); 729281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 730189251Ssam end[-1] = '\0'; 731189251Ssam return buf; 732189251Ssam } 733189251Ssam pos += ret; 734189251Ssam } 735189251Ssam 736189251Ssam if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X) { 737189251Ssam ret = os_snprintf(pos, end - pos, "%sWPA-EAP", 738189251Ssam pos == buf ? "" : " "); 739281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 740189251Ssam end[-1] = '\0'; 741189251Ssam return buf; 742189251Ssam } 743189251Ssam pos += ret; 744189251Ssam } 745189251Ssam 746189251Ssam if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) { 747189251Ssam ret = os_snprintf(pos, end - pos, "%sIEEE8021X", 748189251Ssam pos == buf ? "" : " "); 749281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 750189251Ssam end[-1] = '\0'; 751189251Ssam return buf; 752189251Ssam } 753189251Ssam pos += ret; 754189251Ssam } 755189251Ssam 756189251Ssam if (ssid->key_mgmt & WPA_KEY_MGMT_NONE) { 757189251Ssam ret = os_snprintf(pos, end - pos, "%sNONE", 758189251Ssam pos == buf ? "" : " "); 759281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 760189251Ssam end[-1] = '\0'; 761189251Ssam return buf; 762189251Ssam } 763189251Ssam pos += ret; 764189251Ssam } 765189251Ssam 766189251Ssam if (ssid->key_mgmt & WPA_KEY_MGMT_WPA_NONE) { 767189251Ssam ret = os_snprintf(pos, end - pos, "%sWPA-NONE", 768189251Ssam pos == buf ? "" : " "); 769281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 770189251Ssam end[-1] = '\0'; 771189251Ssam return buf; 772189251Ssam } 773189251Ssam pos += ret; 774189251Ssam } 775189251Ssam 776189251Ssam#ifdef CONFIG_IEEE80211R 777281806Srpaulo if (ssid->key_mgmt & WPA_KEY_MGMT_FT_PSK) { 778281806Srpaulo ret = os_snprintf(pos, end - pos, "%sFT-PSK", 779281806Srpaulo pos == buf ? "" : " "); 780281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 781281806Srpaulo end[-1] = '\0'; 782281806Srpaulo return buf; 783281806Srpaulo } 784281806Srpaulo pos += ret; 785281806Srpaulo } 786189251Ssam 787281806Srpaulo if (ssid->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) { 788281806Srpaulo ret = os_snprintf(pos, end - pos, "%sFT-EAP", 789281806Srpaulo pos == buf ? "" : " "); 790281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 791281806Srpaulo end[-1] = '\0'; 792281806Srpaulo return buf; 793281806Srpaulo } 794281806Srpaulo pos += ret; 795281806Srpaulo } 796189251Ssam#endif /* CONFIG_IEEE80211R */ 797189251Ssam 798189251Ssam#ifdef CONFIG_IEEE80211W 799281806Srpaulo if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256) { 800281806Srpaulo ret = os_snprintf(pos, end - pos, "%sWPA-PSK-SHA256", 801281806Srpaulo pos == buf ? "" : " "); 802281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 803281806Srpaulo end[-1] = '\0'; 804281806Srpaulo return buf; 805189251Ssam } 806281806Srpaulo pos += ret; 807189251Ssam } 808189251Ssam 809281806Srpaulo if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) { 810281806Srpaulo ret = os_snprintf(pos, end - pos, "%sWPA-EAP-SHA256", 811281806Srpaulo pos == buf ? "" : " "); 812281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 813281806Srpaulo end[-1] = '\0'; 814281806Srpaulo return buf; 815281806Srpaulo } 816281806Srpaulo pos += ret; 817189251Ssam } 818281806Srpaulo#endif /* CONFIG_IEEE80211W */ 819189251Ssam 820281806Srpaulo#ifdef CONFIG_WPS 821281806Srpaulo if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) { 822281806Srpaulo ret = os_snprintf(pos, end - pos, "%sWPS", 823189251Ssam pos == buf ? "" : " "); 824281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 825189251Ssam end[-1] = '\0'; 826189251Ssam return buf; 827189251Ssam } 828189251Ssam pos += ret; 829189251Ssam } 830281806Srpaulo#endif /* CONFIG_WPS */ 831189251Ssam 832281806Srpaulo#ifdef CONFIG_SAE 833281806Srpaulo if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) { 834281806Srpaulo ret = os_snprintf(pos, end - pos, "%sSAE", 835252726Srpaulo pos == buf ? "" : " "); 836281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 837252726Srpaulo end[-1] = '\0'; 838252726Srpaulo return buf; 839252726Srpaulo } 840252726Srpaulo pos += ret; 841252726Srpaulo } 842252726Srpaulo 843281806Srpaulo if (ssid->key_mgmt & WPA_KEY_MGMT_FT_SAE) { 844281806Srpaulo ret = os_snprintf(pos, end - pos, "%sFT-SAE", 845189251Ssam pos == buf ? "" : " "); 846281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 847189251Ssam end[-1] = '\0'; 848189251Ssam return buf; 849189251Ssam } 850189251Ssam pos += ret; 851189251Ssam } 852281806Srpaulo#endif /* CONFIG_SAE */ 853189251Ssam 854281806Srpaulo#ifdef CONFIG_HS20 855281806Srpaulo if (ssid->key_mgmt & WPA_KEY_MGMT_OSEN) { 856281806Srpaulo ret = os_snprintf(pos, end - pos, "%sOSEN", 857189251Ssam pos == buf ? "" : " "); 858281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 859189251Ssam end[-1] = '\0'; 860189251Ssam return buf; 861189251Ssam } 862189251Ssam pos += ret; 863189251Ssam } 864281806Srpaulo#endif /* CONFIG_HS20 */ 865189251Ssam 866281806Srpaulo#ifdef CONFIG_SUITEB 867281806Srpaulo if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) { 868281806Srpaulo ret = os_snprintf(pos, end - pos, "%sWPA-EAP-SUITE-B", 869189251Ssam pos == buf ? "" : " "); 870281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 871189251Ssam end[-1] = '\0'; 872189251Ssam return buf; 873189251Ssam } 874189251Ssam pos += ret; 875189251Ssam } 876281806Srpaulo#endif /* CONFIG_SUITEB */ 877189251Ssam 878281806Srpaulo#ifdef CONFIG_SUITEB192 879281806Srpaulo if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) { 880281806Srpaulo ret = os_snprintf(pos, end - pos, "%sWPA-EAP-SUITE-B-192", 881189251Ssam pos == buf ? "" : " "); 882281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 883189251Ssam end[-1] = '\0'; 884189251Ssam return buf; 885189251Ssam } 886189251Ssam pos += ret; 887189251Ssam } 888281806Srpaulo#endif /* CONFIG_SUITEB192 */ 889189251Ssam 890281806Srpaulo if (pos == buf) { 891281806Srpaulo os_free(buf); 892281806Srpaulo buf = NULL; 893281806Srpaulo } 894281806Srpaulo 895189251Ssam return buf; 896189251Ssam} 897189251Ssam#endif /* NO_CONFIG_WRITE */ 898189251Ssam 899189251Ssam 900281806Srpaulostatic int wpa_config_parse_cipher(int line, const char *value) 901281806Srpaulo{ 902281806Srpaulo int val = wpa_parse_cipher(value); 903281806Srpaulo if (val < 0) { 904281806Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.", 905281806Srpaulo line, value); 906281806Srpaulo return -1; 907281806Srpaulo } 908281806Srpaulo if (val == 0) { 909281806Srpaulo wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.", 910281806Srpaulo line); 911281806Srpaulo return -1; 912281806Srpaulo } 913281806Srpaulo return val; 914281806Srpaulo} 915281806Srpaulo 916281806Srpaulo 917281806Srpaulo#ifndef NO_CONFIG_WRITE 918281806Srpaulostatic char * wpa_config_write_cipher(int cipher) 919281806Srpaulo{ 920281806Srpaulo char *buf = os_zalloc(50); 921281806Srpaulo if (buf == NULL) 922281806Srpaulo return NULL; 923281806Srpaulo 924281806Srpaulo if (wpa_write_ciphers(buf, buf + 50, cipher, " ") < 0) { 925281806Srpaulo os_free(buf); 926281806Srpaulo return NULL; 927281806Srpaulo } 928281806Srpaulo 929281806Srpaulo return buf; 930281806Srpaulo} 931281806Srpaulo#endif /* NO_CONFIG_WRITE */ 932281806Srpaulo 933281806Srpaulo 934189251Ssamstatic int wpa_config_parse_pairwise(const struct parse_data *data, 935189251Ssam struct wpa_ssid *ssid, int line, 936189251Ssam const char *value) 937189251Ssam{ 938189251Ssam int val; 939189251Ssam val = wpa_config_parse_cipher(line, value); 940189251Ssam if (val == -1) 941189251Ssam return -1; 942281806Srpaulo if (val & ~WPA_ALLOWED_PAIRWISE_CIPHERS) { 943189251Ssam wpa_printf(MSG_ERROR, "Line %d: not allowed pairwise cipher " 944189251Ssam "(0x%x).", line, val); 945189251Ssam return -1; 946189251Ssam } 947189251Ssam 948189251Ssam wpa_printf(MSG_MSGDUMP, "pairwise: 0x%x", val); 949189251Ssam ssid->pairwise_cipher = val; 950189251Ssam return 0; 951189251Ssam} 952189251Ssam 953189251Ssam 954189251Ssam#ifndef NO_CONFIG_WRITE 955189251Ssamstatic char * wpa_config_write_pairwise(const struct parse_data *data, 956189251Ssam struct wpa_ssid *ssid) 957189251Ssam{ 958189251Ssam return wpa_config_write_cipher(ssid->pairwise_cipher); 959189251Ssam} 960189251Ssam#endif /* NO_CONFIG_WRITE */ 961189251Ssam 962189251Ssam 963189251Ssamstatic int wpa_config_parse_group(const struct parse_data *data, 964189251Ssam struct wpa_ssid *ssid, int line, 965189251Ssam const char *value) 966189251Ssam{ 967189251Ssam int val; 968189251Ssam val = wpa_config_parse_cipher(line, value); 969189251Ssam if (val == -1) 970189251Ssam return -1; 971289549Srpaulo 972289549Srpaulo /* 973289549Srpaulo * Backwards compatibility - filter out WEP ciphers that were previously 974289549Srpaulo * allowed. 975289549Srpaulo */ 976289549Srpaulo val &= ~(WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40); 977289549Srpaulo 978281806Srpaulo if (val & ~WPA_ALLOWED_GROUP_CIPHERS) { 979189251Ssam wpa_printf(MSG_ERROR, "Line %d: not allowed group cipher " 980189251Ssam "(0x%x).", line, val); 981189251Ssam return -1; 982189251Ssam } 983189251Ssam 984189251Ssam wpa_printf(MSG_MSGDUMP, "group: 0x%x", val); 985189251Ssam ssid->group_cipher = val; 986189251Ssam return 0; 987189251Ssam} 988189251Ssam 989189251Ssam 990189251Ssam#ifndef NO_CONFIG_WRITE 991189251Ssamstatic char * wpa_config_write_group(const struct parse_data *data, 992189251Ssam struct wpa_ssid *ssid) 993189251Ssam{ 994189251Ssam return wpa_config_write_cipher(ssid->group_cipher); 995189251Ssam} 996189251Ssam#endif /* NO_CONFIG_WRITE */ 997189251Ssam 998189251Ssam 999189251Ssamstatic int wpa_config_parse_auth_alg(const struct parse_data *data, 1000189251Ssam struct wpa_ssid *ssid, int line, 1001189251Ssam const char *value) 1002189251Ssam{ 1003189251Ssam int val = 0, last, errors = 0; 1004189251Ssam char *start, *end, *buf; 1005189251Ssam 1006189251Ssam buf = os_strdup(value); 1007189251Ssam if (buf == NULL) 1008189251Ssam return -1; 1009189251Ssam start = buf; 1010189251Ssam 1011189251Ssam while (*start != '\0') { 1012189251Ssam while (*start == ' ' || *start == '\t') 1013189251Ssam start++; 1014189251Ssam if (*start == '\0') 1015189251Ssam break; 1016189251Ssam end = start; 1017189251Ssam while (*end != ' ' && *end != '\t' && *end != '\0') 1018189251Ssam end++; 1019189251Ssam last = *end == '\0'; 1020189251Ssam *end = '\0'; 1021189251Ssam if (os_strcmp(start, "OPEN") == 0) 1022189251Ssam val |= WPA_AUTH_ALG_OPEN; 1023189251Ssam else if (os_strcmp(start, "SHARED") == 0) 1024189251Ssam val |= WPA_AUTH_ALG_SHARED; 1025189251Ssam else if (os_strcmp(start, "LEAP") == 0) 1026189251Ssam val |= WPA_AUTH_ALG_LEAP; 1027189251Ssam else { 1028189251Ssam wpa_printf(MSG_ERROR, "Line %d: invalid auth_alg '%s'", 1029189251Ssam line, start); 1030189251Ssam errors++; 1031189251Ssam } 1032189251Ssam 1033189251Ssam if (last) 1034189251Ssam break; 1035189251Ssam start = end + 1; 1036189251Ssam } 1037189251Ssam os_free(buf); 1038189251Ssam 1039189251Ssam if (val == 0) { 1040189251Ssam wpa_printf(MSG_ERROR, 1041189251Ssam "Line %d: no auth_alg values configured.", line); 1042189251Ssam errors++; 1043189251Ssam } 1044189251Ssam 1045189251Ssam wpa_printf(MSG_MSGDUMP, "auth_alg: 0x%x", val); 1046189251Ssam ssid->auth_alg = val; 1047189251Ssam return errors ? -1 : 0; 1048189251Ssam} 1049189251Ssam 1050189251Ssam 1051189251Ssam#ifndef NO_CONFIG_WRITE 1052189251Ssamstatic char * wpa_config_write_auth_alg(const struct parse_data *data, 1053189251Ssam struct wpa_ssid *ssid) 1054189251Ssam{ 1055189251Ssam char *buf, *pos, *end; 1056189251Ssam int ret; 1057189251Ssam 1058189251Ssam pos = buf = os_zalloc(30); 1059189251Ssam if (buf == NULL) 1060189251Ssam return NULL; 1061189251Ssam end = buf + 30; 1062189251Ssam 1063189251Ssam if (ssid->auth_alg & WPA_AUTH_ALG_OPEN) { 1064189251Ssam ret = os_snprintf(pos, end - pos, "%sOPEN", 1065189251Ssam pos == buf ? "" : " "); 1066281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 1067189251Ssam end[-1] = '\0'; 1068189251Ssam return buf; 1069189251Ssam } 1070189251Ssam pos += ret; 1071189251Ssam } 1072189251Ssam 1073189251Ssam if (ssid->auth_alg & WPA_AUTH_ALG_SHARED) { 1074189251Ssam ret = os_snprintf(pos, end - pos, "%sSHARED", 1075189251Ssam pos == buf ? "" : " "); 1076281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 1077189251Ssam end[-1] = '\0'; 1078189251Ssam return buf; 1079189251Ssam } 1080189251Ssam pos += ret; 1081189251Ssam } 1082189251Ssam 1083189251Ssam if (ssid->auth_alg & WPA_AUTH_ALG_LEAP) { 1084189251Ssam ret = os_snprintf(pos, end - pos, "%sLEAP", 1085189251Ssam pos == buf ? "" : " "); 1086281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 1087189251Ssam end[-1] = '\0'; 1088189251Ssam return buf; 1089189251Ssam } 1090189251Ssam pos += ret; 1091189251Ssam } 1092189251Ssam 1093281806Srpaulo if (pos == buf) { 1094281806Srpaulo os_free(buf); 1095281806Srpaulo buf = NULL; 1096281806Srpaulo } 1097281806Srpaulo 1098189251Ssam return buf; 1099189251Ssam} 1100189251Ssam#endif /* NO_CONFIG_WRITE */ 1101189251Ssam 1102189251Ssam 1103281806Srpaulostatic int * wpa_config_parse_int_array(const char *value) 1104214734Srpaulo{ 1105214734Srpaulo int *freqs; 1106214734Srpaulo size_t used, len; 1107214734Srpaulo const char *pos; 1108214734Srpaulo 1109214734Srpaulo used = 0; 1110214734Srpaulo len = 10; 1111252726Srpaulo freqs = os_calloc(len + 1, sizeof(int)); 1112214734Srpaulo if (freqs == NULL) 1113214734Srpaulo return NULL; 1114214734Srpaulo 1115214734Srpaulo pos = value; 1116214734Srpaulo while (pos) { 1117214734Srpaulo while (*pos == ' ') 1118214734Srpaulo pos++; 1119214734Srpaulo if (used == len) { 1120214734Srpaulo int *n; 1121214734Srpaulo size_t i; 1122252726Srpaulo n = os_realloc_array(freqs, len * 2 + 1, sizeof(int)); 1123214734Srpaulo if (n == NULL) { 1124214734Srpaulo os_free(freqs); 1125214734Srpaulo return NULL; 1126214734Srpaulo } 1127214734Srpaulo for (i = len; i <= len * 2; i++) 1128214734Srpaulo n[i] = 0; 1129214734Srpaulo freqs = n; 1130214734Srpaulo len *= 2; 1131214734Srpaulo } 1132214734Srpaulo 1133214734Srpaulo freqs[used] = atoi(pos); 1134214734Srpaulo if (freqs[used] == 0) 1135214734Srpaulo break; 1136214734Srpaulo used++; 1137214734Srpaulo pos = os_strchr(pos + 1, ' '); 1138214734Srpaulo } 1139214734Srpaulo 1140214734Srpaulo return freqs; 1141214734Srpaulo} 1142214734Srpaulo 1143214734Srpaulo 1144214734Srpaulostatic int wpa_config_parse_scan_freq(const struct parse_data *data, 1145214734Srpaulo struct wpa_ssid *ssid, int line, 1146214734Srpaulo const char *value) 1147214734Srpaulo{ 1148214734Srpaulo int *freqs; 1149214734Srpaulo 1150281806Srpaulo freqs = wpa_config_parse_int_array(value); 1151214734Srpaulo if (freqs == NULL) 1152214734Srpaulo return -1; 1153281806Srpaulo if (freqs[0] == 0) { 1154281806Srpaulo os_free(freqs); 1155281806Srpaulo freqs = NULL; 1156281806Srpaulo } 1157214734Srpaulo os_free(ssid->scan_freq); 1158214734Srpaulo ssid->scan_freq = freqs; 1159214734Srpaulo 1160214734Srpaulo return 0; 1161214734Srpaulo} 1162214734Srpaulo 1163214734Srpaulo 1164214734Srpaulostatic int wpa_config_parse_freq_list(const struct parse_data *data, 1165214734Srpaulo struct wpa_ssid *ssid, int line, 1166214734Srpaulo const char *value) 1167214734Srpaulo{ 1168214734Srpaulo int *freqs; 1169214734Srpaulo 1170281806Srpaulo freqs = wpa_config_parse_int_array(value); 1171214734Srpaulo if (freqs == NULL) 1172214734Srpaulo return -1; 1173281806Srpaulo if (freqs[0] == 0) { 1174281806Srpaulo os_free(freqs); 1175281806Srpaulo freqs = NULL; 1176281806Srpaulo } 1177214734Srpaulo os_free(ssid->freq_list); 1178214734Srpaulo ssid->freq_list = freqs; 1179214734Srpaulo 1180214734Srpaulo return 0; 1181214734Srpaulo} 1182214734Srpaulo 1183214734Srpaulo 1184214734Srpaulo#ifndef NO_CONFIG_WRITE 1185214734Srpaulostatic char * wpa_config_write_freqs(const struct parse_data *data, 1186214734Srpaulo const int *freqs) 1187214734Srpaulo{ 1188214734Srpaulo char *buf, *pos, *end; 1189214734Srpaulo int i, ret; 1190214734Srpaulo size_t count; 1191214734Srpaulo 1192214734Srpaulo if (freqs == NULL) 1193214734Srpaulo return NULL; 1194214734Srpaulo 1195214734Srpaulo count = 0; 1196214734Srpaulo for (i = 0; freqs[i]; i++) 1197214734Srpaulo count++; 1198214734Srpaulo 1199214734Srpaulo pos = buf = os_zalloc(10 * count + 1); 1200214734Srpaulo if (buf == NULL) 1201214734Srpaulo return NULL; 1202214734Srpaulo end = buf + 10 * count + 1; 1203214734Srpaulo 1204214734Srpaulo for (i = 0; freqs[i]; i++) { 1205214734Srpaulo ret = os_snprintf(pos, end - pos, "%s%u", 1206214734Srpaulo i == 0 ? "" : " ", freqs[i]); 1207281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 1208214734Srpaulo end[-1] = '\0'; 1209214734Srpaulo return buf; 1210214734Srpaulo } 1211214734Srpaulo pos += ret; 1212214734Srpaulo } 1213214734Srpaulo 1214214734Srpaulo return buf; 1215214734Srpaulo} 1216214734Srpaulo 1217214734Srpaulo 1218214734Srpaulostatic char * wpa_config_write_scan_freq(const struct parse_data *data, 1219214734Srpaulo struct wpa_ssid *ssid) 1220214734Srpaulo{ 1221214734Srpaulo return wpa_config_write_freqs(data, ssid->scan_freq); 1222214734Srpaulo} 1223214734Srpaulo 1224214734Srpaulo 1225214734Srpaulostatic char * wpa_config_write_freq_list(const struct parse_data *data, 1226214734Srpaulo struct wpa_ssid *ssid) 1227214734Srpaulo{ 1228214734Srpaulo return wpa_config_write_freqs(data, ssid->freq_list); 1229214734Srpaulo} 1230214734Srpaulo#endif /* NO_CONFIG_WRITE */ 1231214734Srpaulo 1232214734Srpaulo 1233189251Ssam#ifdef IEEE8021X_EAPOL 1234189251Ssamstatic int wpa_config_parse_eap(const struct parse_data *data, 1235189251Ssam struct wpa_ssid *ssid, int line, 1236189251Ssam const char *value) 1237189251Ssam{ 1238189251Ssam int last, errors = 0; 1239189251Ssam char *start, *end, *buf; 1240189251Ssam struct eap_method_type *methods = NULL, *tmp; 1241189251Ssam size_t num_methods = 0; 1242189251Ssam 1243189251Ssam buf = os_strdup(value); 1244189251Ssam if (buf == NULL) 1245189251Ssam return -1; 1246189251Ssam start = buf; 1247189251Ssam 1248189251Ssam while (*start != '\0') { 1249189251Ssam while (*start == ' ' || *start == '\t') 1250189251Ssam start++; 1251189251Ssam if (*start == '\0') 1252189251Ssam break; 1253189251Ssam end = start; 1254189251Ssam while (*end != ' ' && *end != '\t' && *end != '\0') 1255189251Ssam end++; 1256189251Ssam last = *end == '\0'; 1257189251Ssam *end = '\0'; 1258189251Ssam tmp = methods; 1259252726Srpaulo methods = os_realloc_array(methods, num_methods + 1, 1260252726Srpaulo sizeof(*methods)); 1261189251Ssam if (methods == NULL) { 1262189251Ssam os_free(tmp); 1263189251Ssam os_free(buf); 1264189251Ssam return -1; 1265189251Ssam } 1266189251Ssam methods[num_methods].method = eap_peer_get_type( 1267189251Ssam start, &methods[num_methods].vendor); 1268189251Ssam if (methods[num_methods].vendor == EAP_VENDOR_IETF && 1269189251Ssam methods[num_methods].method == EAP_TYPE_NONE) { 1270189251Ssam wpa_printf(MSG_ERROR, "Line %d: unknown EAP method " 1271189251Ssam "'%s'", line, start); 1272189251Ssam wpa_printf(MSG_ERROR, "You may need to add support for" 1273189251Ssam " this EAP method during wpa_supplicant\n" 1274189251Ssam "build time configuration.\n" 1275189251Ssam "See README for more information."); 1276189251Ssam errors++; 1277189251Ssam } else if (methods[num_methods].vendor == EAP_VENDOR_IETF && 1278189251Ssam methods[num_methods].method == EAP_TYPE_LEAP) 1279189251Ssam ssid->leap++; 1280189251Ssam else 1281189251Ssam ssid->non_leap++; 1282189251Ssam num_methods++; 1283189251Ssam if (last) 1284189251Ssam break; 1285189251Ssam start = end + 1; 1286189251Ssam } 1287189251Ssam os_free(buf); 1288189251Ssam 1289189251Ssam tmp = methods; 1290252726Srpaulo methods = os_realloc_array(methods, num_methods + 1, sizeof(*methods)); 1291189251Ssam if (methods == NULL) { 1292189251Ssam os_free(tmp); 1293189251Ssam return -1; 1294189251Ssam } 1295189251Ssam methods[num_methods].vendor = EAP_VENDOR_IETF; 1296189251Ssam methods[num_methods].method = EAP_TYPE_NONE; 1297189251Ssam num_methods++; 1298189251Ssam 1299189251Ssam wpa_hexdump(MSG_MSGDUMP, "eap methods", 1300189251Ssam (u8 *) methods, num_methods * sizeof(*methods)); 1301252726Srpaulo os_free(ssid->eap.eap_methods); 1302189251Ssam ssid->eap.eap_methods = methods; 1303189251Ssam return errors ? -1 : 0; 1304189251Ssam} 1305189251Ssam 1306189251Ssam 1307289549Srpaulo#ifndef NO_CONFIG_WRITE 1308189251Ssamstatic char * wpa_config_write_eap(const struct parse_data *data, 1309189251Ssam struct wpa_ssid *ssid) 1310189251Ssam{ 1311189251Ssam int i, ret; 1312189251Ssam char *buf, *pos, *end; 1313189251Ssam const struct eap_method_type *eap_methods = ssid->eap.eap_methods; 1314189251Ssam const char *name; 1315189251Ssam 1316189251Ssam if (eap_methods == NULL) 1317189251Ssam return NULL; 1318189251Ssam 1319189251Ssam pos = buf = os_zalloc(100); 1320189251Ssam if (buf == NULL) 1321189251Ssam return NULL; 1322189251Ssam end = buf + 100; 1323189251Ssam 1324189251Ssam for (i = 0; eap_methods[i].vendor != EAP_VENDOR_IETF || 1325189251Ssam eap_methods[i].method != EAP_TYPE_NONE; i++) { 1326189251Ssam name = eap_get_name(eap_methods[i].vendor, 1327189251Ssam eap_methods[i].method); 1328189251Ssam if (name) { 1329189251Ssam ret = os_snprintf(pos, end - pos, "%s%s", 1330189251Ssam pos == buf ? "" : " ", name); 1331281806Srpaulo if (os_snprintf_error(end - pos, ret)) 1332189251Ssam break; 1333189251Ssam pos += ret; 1334189251Ssam } 1335189251Ssam } 1336189251Ssam 1337189251Ssam end[-1] = '\0'; 1338189251Ssam 1339189251Ssam return buf; 1340189251Ssam} 1341289549Srpaulo#endif /* NO_CONFIG_WRITE */ 1342189251Ssam 1343189251Ssam 1344189251Ssamstatic int wpa_config_parse_password(const struct parse_data *data, 1345189251Ssam struct wpa_ssid *ssid, int line, 1346189251Ssam const char *value) 1347189251Ssam{ 1348189251Ssam u8 *hash; 1349189251Ssam 1350189251Ssam if (os_strcmp(value, "NULL") == 0) { 1351189251Ssam wpa_printf(MSG_DEBUG, "Unset configuration string 'password'"); 1352281806Srpaulo bin_clear_free(ssid->eap.password, ssid->eap.password_len); 1353189251Ssam ssid->eap.password = NULL; 1354189251Ssam ssid->eap.password_len = 0; 1355189251Ssam return 0; 1356189251Ssam } 1357189251Ssam 1358252726Srpaulo#ifdef CONFIG_EXT_PASSWORD 1359252726Srpaulo if (os_strncmp(value, "ext:", 4) == 0) { 1360252726Srpaulo char *name = os_strdup(value + 4); 1361252726Srpaulo if (name == NULL) 1362252726Srpaulo return -1; 1363281806Srpaulo bin_clear_free(ssid->eap.password, ssid->eap.password_len); 1364252726Srpaulo ssid->eap.password = (u8 *) name; 1365252726Srpaulo ssid->eap.password_len = os_strlen(name); 1366252726Srpaulo ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH; 1367252726Srpaulo ssid->eap.flags |= EAP_CONFIG_FLAGS_EXT_PASSWORD; 1368252726Srpaulo return 0; 1369252726Srpaulo } 1370252726Srpaulo#endif /* CONFIG_EXT_PASSWORD */ 1371252726Srpaulo 1372189251Ssam if (os_strncmp(value, "hash:", 5) != 0) { 1373189251Ssam char *tmp; 1374189251Ssam size_t res_len; 1375189251Ssam 1376189251Ssam tmp = wpa_config_parse_string(value, &res_len); 1377189251Ssam if (tmp == NULL) { 1378189251Ssam wpa_printf(MSG_ERROR, "Line %d: failed to parse " 1379189251Ssam "password.", line); 1380189251Ssam return -1; 1381189251Ssam } 1382189251Ssam wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name, 1383189251Ssam (u8 *) tmp, res_len); 1384189251Ssam 1385281806Srpaulo bin_clear_free(ssid->eap.password, ssid->eap.password_len); 1386189251Ssam ssid->eap.password = (u8 *) tmp; 1387189251Ssam ssid->eap.password_len = res_len; 1388189251Ssam ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH; 1389252726Srpaulo ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD; 1390189251Ssam 1391189251Ssam return 0; 1392189251Ssam } 1393189251Ssam 1394189251Ssam 1395189251Ssam /* NtPasswordHash: hash:<32 hex digits> */ 1396189251Ssam if (os_strlen(value + 5) != 2 * 16) { 1397189251Ssam wpa_printf(MSG_ERROR, "Line %d: Invalid password hash length " 1398189251Ssam "(expected 32 hex digits)", line); 1399189251Ssam return -1; 1400189251Ssam } 1401189251Ssam 1402189251Ssam hash = os_malloc(16); 1403189251Ssam if (hash == NULL) 1404189251Ssam return -1; 1405189251Ssam 1406189251Ssam if (hexstr2bin(value + 5, hash, 16)) { 1407189251Ssam os_free(hash); 1408189251Ssam wpa_printf(MSG_ERROR, "Line %d: Invalid password hash", line); 1409189251Ssam return -1; 1410189251Ssam } 1411189251Ssam 1412189251Ssam wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16); 1413189251Ssam 1414281806Srpaulo bin_clear_free(ssid->eap.password, ssid->eap.password_len); 1415189251Ssam ssid->eap.password = hash; 1416189251Ssam ssid->eap.password_len = 16; 1417189251Ssam ssid->eap.flags |= EAP_CONFIG_FLAGS_PASSWORD_NTHASH; 1418252726Srpaulo ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD; 1419189251Ssam 1420189251Ssam return 0; 1421189251Ssam} 1422189251Ssam 1423189251Ssam 1424289549Srpaulo#ifndef NO_CONFIG_WRITE 1425189251Ssamstatic char * wpa_config_write_password(const struct parse_data *data, 1426189251Ssam struct wpa_ssid *ssid) 1427189251Ssam{ 1428189251Ssam char *buf; 1429189251Ssam 1430189251Ssam if (ssid->eap.password == NULL) 1431189251Ssam return NULL; 1432189251Ssam 1433252726Srpaulo#ifdef CONFIG_EXT_PASSWORD 1434252726Srpaulo if (ssid->eap.flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) { 1435252726Srpaulo buf = os_zalloc(4 + ssid->eap.password_len + 1); 1436252726Srpaulo if (buf == NULL) 1437252726Srpaulo return NULL; 1438252726Srpaulo os_memcpy(buf, "ext:", 4); 1439252726Srpaulo os_memcpy(buf + 4, ssid->eap.password, ssid->eap.password_len); 1440252726Srpaulo return buf; 1441252726Srpaulo } 1442252726Srpaulo#endif /* CONFIG_EXT_PASSWORD */ 1443252726Srpaulo 1444189251Ssam if (!(ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) { 1445189251Ssam return wpa_config_write_string( 1446189251Ssam ssid->eap.password, ssid->eap.password_len); 1447189251Ssam } 1448189251Ssam 1449189251Ssam buf = os_malloc(5 + 32 + 1); 1450189251Ssam if (buf == NULL) 1451189251Ssam return NULL; 1452189251Ssam 1453189251Ssam os_memcpy(buf, "hash:", 5); 1454189251Ssam wpa_snprintf_hex(buf + 5, 32 + 1, ssid->eap.password, 16); 1455189251Ssam 1456189251Ssam return buf; 1457189251Ssam} 1458289549Srpaulo#endif /* NO_CONFIG_WRITE */ 1459189251Ssam#endif /* IEEE8021X_EAPOL */ 1460189251Ssam 1461189251Ssam 1462189251Ssamstatic int wpa_config_parse_wep_key(u8 *key, size_t *len, int line, 1463189251Ssam const char *value, int idx) 1464189251Ssam{ 1465189251Ssam char *buf, title[20]; 1466189251Ssam int res; 1467189251Ssam 1468189251Ssam buf = wpa_config_parse_string(value, len); 1469189251Ssam if (buf == NULL) { 1470189251Ssam wpa_printf(MSG_ERROR, "Line %d: Invalid WEP key %d '%s'.", 1471189251Ssam line, idx, value); 1472189251Ssam return -1; 1473189251Ssam } 1474189251Ssam if (*len > MAX_WEP_KEY_LEN) { 1475189251Ssam wpa_printf(MSG_ERROR, "Line %d: Too long WEP key %d '%s'.", 1476189251Ssam line, idx, value); 1477189251Ssam os_free(buf); 1478189251Ssam return -1; 1479189251Ssam } 1480252726Srpaulo if (*len && *len != 5 && *len != 13 && *len != 16) { 1481252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid WEP key length %u - " 1482252726Srpaulo "this network block will be ignored", 1483252726Srpaulo line, (unsigned int) *len); 1484252726Srpaulo } 1485189251Ssam os_memcpy(key, buf, *len); 1486281806Srpaulo str_clear_free(buf); 1487189251Ssam res = os_snprintf(title, sizeof(title), "wep_key%d", idx); 1488281806Srpaulo if (!os_snprintf_error(sizeof(title), res)) 1489189251Ssam wpa_hexdump_key(MSG_MSGDUMP, title, key, *len); 1490189251Ssam return 0; 1491189251Ssam} 1492189251Ssam 1493189251Ssam 1494189251Ssamstatic int wpa_config_parse_wep_key0(const struct parse_data *data, 1495189251Ssam struct wpa_ssid *ssid, int line, 1496189251Ssam const char *value) 1497189251Ssam{ 1498189251Ssam return wpa_config_parse_wep_key(ssid->wep_key[0], 1499189251Ssam &ssid->wep_key_len[0], line, 1500189251Ssam value, 0); 1501189251Ssam} 1502189251Ssam 1503189251Ssam 1504189251Ssamstatic int wpa_config_parse_wep_key1(const struct parse_data *data, 1505189251Ssam struct wpa_ssid *ssid, int line, 1506189251Ssam const char *value) 1507189251Ssam{ 1508189251Ssam return wpa_config_parse_wep_key(ssid->wep_key[1], 1509189251Ssam &ssid->wep_key_len[1], line, 1510189251Ssam value, 1); 1511189251Ssam} 1512189251Ssam 1513189251Ssam 1514189251Ssamstatic int wpa_config_parse_wep_key2(const struct parse_data *data, 1515189251Ssam struct wpa_ssid *ssid, int line, 1516189251Ssam const char *value) 1517189251Ssam{ 1518189251Ssam return wpa_config_parse_wep_key(ssid->wep_key[2], 1519189251Ssam &ssid->wep_key_len[2], line, 1520189251Ssam value, 2); 1521189251Ssam} 1522189251Ssam 1523189251Ssam 1524189251Ssamstatic int wpa_config_parse_wep_key3(const struct parse_data *data, 1525189251Ssam struct wpa_ssid *ssid, int line, 1526189251Ssam const char *value) 1527189251Ssam{ 1528189251Ssam return wpa_config_parse_wep_key(ssid->wep_key[3], 1529189251Ssam &ssid->wep_key_len[3], line, 1530189251Ssam value, 3); 1531189251Ssam} 1532189251Ssam 1533189251Ssam 1534189251Ssam#ifndef NO_CONFIG_WRITE 1535189251Ssamstatic char * wpa_config_write_wep_key(struct wpa_ssid *ssid, int idx) 1536189251Ssam{ 1537189251Ssam if (ssid->wep_key_len[idx] == 0) 1538189251Ssam return NULL; 1539189251Ssam return wpa_config_write_string(ssid->wep_key[idx], 1540189251Ssam ssid->wep_key_len[idx]); 1541189251Ssam} 1542189251Ssam 1543189251Ssam 1544189251Ssamstatic char * wpa_config_write_wep_key0(const struct parse_data *data, 1545189251Ssam struct wpa_ssid *ssid) 1546189251Ssam{ 1547189251Ssam return wpa_config_write_wep_key(ssid, 0); 1548189251Ssam} 1549189251Ssam 1550189251Ssam 1551189251Ssamstatic char * wpa_config_write_wep_key1(const struct parse_data *data, 1552189251Ssam struct wpa_ssid *ssid) 1553189251Ssam{ 1554189251Ssam return wpa_config_write_wep_key(ssid, 1); 1555189251Ssam} 1556189251Ssam 1557189251Ssam 1558189251Ssamstatic char * wpa_config_write_wep_key2(const struct parse_data *data, 1559189251Ssam struct wpa_ssid *ssid) 1560189251Ssam{ 1561189251Ssam return wpa_config_write_wep_key(ssid, 2); 1562189251Ssam} 1563189251Ssam 1564189251Ssam 1565189251Ssamstatic char * wpa_config_write_wep_key3(const struct parse_data *data, 1566189251Ssam struct wpa_ssid *ssid) 1567189251Ssam{ 1568189251Ssam return wpa_config_write_wep_key(ssid, 3); 1569189251Ssam} 1570189251Ssam#endif /* NO_CONFIG_WRITE */ 1571189251Ssam 1572189251Ssam 1573252726Srpaulo#ifdef CONFIG_P2P 1574252726Srpaulo 1575281806Srpaulostatic int wpa_config_parse_go_p2p_dev_addr(const struct parse_data *data, 1576252726Srpaulo struct wpa_ssid *ssid, int line, 1577252726Srpaulo const char *value) 1578252726Srpaulo{ 1579281806Srpaulo if (value[0] == '\0' || os_strcmp(value, "\"\"") == 0 || 1580281806Srpaulo os_strcmp(value, "any") == 0) { 1581281806Srpaulo os_memset(ssid->go_p2p_dev_addr, 0, ETH_ALEN); 1582281806Srpaulo wpa_printf(MSG_MSGDUMP, "GO P2P Device Address any"); 1583281806Srpaulo return 0; 1584281806Srpaulo } 1585281806Srpaulo if (hwaddr_aton(value, ssid->go_p2p_dev_addr)) { 1586281806Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid GO P2P Device Address '%s'.", 1587281806Srpaulo line, value); 1588281806Srpaulo return -1; 1589281806Srpaulo } 1590281806Srpaulo ssid->bssid_set = 1; 1591281806Srpaulo wpa_printf(MSG_MSGDUMP, "GO P2P Device Address " MACSTR, 1592281806Srpaulo MAC2STR(ssid->go_p2p_dev_addr)); 1593281806Srpaulo return 0; 1594281806Srpaulo} 1595252726Srpaulo 1596252726Srpaulo 1597281806Srpaulo#ifndef NO_CONFIG_WRITE 1598281806Srpaulostatic char * wpa_config_write_go_p2p_dev_addr(const struct parse_data *data, 1599281806Srpaulo struct wpa_ssid *ssid) 1600281806Srpaulo{ 1601281806Srpaulo char *value; 1602281806Srpaulo int res; 1603252726Srpaulo 1604281806Srpaulo if (is_zero_ether_addr(ssid->go_p2p_dev_addr)) 1605281806Srpaulo return NULL; 1606252726Srpaulo 1607281806Srpaulo value = os_malloc(20); 1608281806Srpaulo if (value == NULL) 1609281806Srpaulo return NULL; 1610281806Srpaulo res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->go_p2p_dev_addr)); 1611281806Srpaulo if (os_snprintf_error(20, res)) { 1612281806Srpaulo os_free(value); 1613281806Srpaulo return NULL; 1614252726Srpaulo } 1615281806Srpaulo value[20 - 1] = '\0'; 1616281806Srpaulo return value; 1617281806Srpaulo} 1618281806Srpaulo#endif /* NO_CONFIG_WRITE */ 1619252726Srpaulo 1620252726Srpaulo 1621281806Srpaulostatic int wpa_config_parse_p2p_client_list(const struct parse_data *data, 1622281806Srpaulo struct wpa_ssid *ssid, int line, 1623281806Srpaulo const char *value) 1624281806Srpaulo{ 1625281806Srpaulo return wpa_config_parse_addr_list(data, line, value, 1626281806Srpaulo &ssid->p2p_client_list, 1627281806Srpaulo &ssid->num_p2p_clients, 1628281806Srpaulo "p2p_client_list", 0, 0); 1629252726Srpaulo} 1630252726Srpaulo 1631252726Srpaulo 1632252726Srpaulo#ifndef NO_CONFIG_WRITE 1633252726Srpaulostatic char * wpa_config_write_p2p_client_list(const struct parse_data *data, 1634252726Srpaulo struct wpa_ssid *ssid) 1635252726Srpaulo{ 1636281806Srpaulo return wpa_config_write_addr_list(data, ssid->p2p_client_list, 1637281806Srpaulo ssid->num_p2p_clients, 1638281806Srpaulo "p2p_client_list"); 1639281806Srpaulo} 1640281806Srpaulo#endif /* NO_CONFIG_WRITE */ 1641252726Srpaulo 1642252726Srpaulo 1643281806Srpaulostatic int wpa_config_parse_psk_list(const struct parse_data *data, 1644281806Srpaulo struct wpa_ssid *ssid, int line, 1645281806Srpaulo const char *value) 1646281806Srpaulo{ 1647281806Srpaulo struct psk_list_entry *p; 1648281806Srpaulo const char *pos; 1649281806Srpaulo 1650281806Srpaulo p = os_zalloc(sizeof(*p)); 1651281806Srpaulo if (p == NULL) 1652281806Srpaulo return -1; 1653281806Srpaulo 1654252726Srpaulo pos = value; 1655281806Srpaulo if (os_strncmp(pos, "P2P-", 4) == 0) { 1656281806Srpaulo p->p2p = 1; 1657281806Srpaulo pos += 4; 1658281806Srpaulo } 1659252726Srpaulo 1660281806Srpaulo if (hwaddr_aton(pos, p->addr)) { 1661281806Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid psk_list address '%s'", 1662281806Srpaulo line, pos); 1663281806Srpaulo os_free(p); 1664281806Srpaulo return -1; 1665252726Srpaulo } 1666281806Srpaulo pos += 17; 1667281806Srpaulo if (*pos != '-') { 1668281806Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid psk_list '%s'", 1669281806Srpaulo line, pos); 1670281806Srpaulo os_free(p); 1671281806Srpaulo return -1; 1672281806Srpaulo } 1673281806Srpaulo pos++; 1674252726Srpaulo 1675281806Srpaulo if (hexstr2bin(pos, p->psk, PMK_LEN) || pos[PMK_LEN * 2] != '\0') { 1676281806Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid psk_list PSK '%s'", 1677281806Srpaulo line, pos); 1678281806Srpaulo os_free(p); 1679281806Srpaulo return -1; 1680281806Srpaulo } 1681252726Srpaulo 1682281806Srpaulo dl_list_add(&ssid->psk_list, &p->list); 1683281806Srpaulo 1684281806Srpaulo return 0; 1685252726Srpaulo} 1686281806Srpaulo 1687281806Srpaulo 1688281806Srpaulo#ifndef NO_CONFIG_WRITE 1689281806Srpaulostatic char * wpa_config_write_psk_list(const struct parse_data *data, 1690281806Srpaulo struct wpa_ssid *ssid) 1691281806Srpaulo{ 1692281806Srpaulo return NULL; 1693281806Srpaulo} 1694252726Srpaulo#endif /* NO_CONFIG_WRITE */ 1695252726Srpaulo 1696252726Srpaulo#endif /* CONFIG_P2P */ 1697252726Srpaulo 1698281806Srpaulo 1699281806Srpaulo#ifdef CONFIG_MESH 1700281806Srpaulo 1701281806Srpaulostatic int wpa_config_parse_mesh_basic_rates(const struct parse_data *data, 1702281806Srpaulo struct wpa_ssid *ssid, int line, 1703281806Srpaulo const char *value) 1704281806Srpaulo{ 1705281806Srpaulo int *rates = wpa_config_parse_int_array(value); 1706281806Srpaulo 1707281806Srpaulo if (rates == NULL) { 1708281806Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid mesh_basic_rates '%s'", 1709281806Srpaulo line, value); 1710281806Srpaulo return -1; 1711281806Srpaulo } 1712281806Srpaulo if (rates[0] == 0) { 1713281806Srpaulo os_free(rates); 1714281806Srpaulo rates = NULL; 1715281806Srpaulo } 1716281806Srpaulo 1717281806Srpaulo os_free(ssid->mesh_basic_rates); 1718281806Srpaulo ssid->mesh_basic_rates = rates; 1719281806Srpaulo 1720281806Srpaulo return 0; 1721281806Srpaulo} 1722281806Srpaulo 1723281806Srpaulo 1724281806Srpaulo#ifndef NO_CONFIG_WRITE 1725281806Srpaulo 1726281806Srpaulostatic char * wpa_config_write_mesh_basic_rates(const struct parse_data *data, 1727281806Srpaulo struct wpa_ssid *ssid) 1728281806Srpaulo{ 1729281806Srpaulo return wpa_config_write_freqs(data, ssid->mesh_basic_rates); 1730281806Srpaulo} 1731281806Srpaulo 1732281806Srpaulo#endif /* NO_CONFIG_WRITE */ 1733281806Srpaulo 1734281806Srpaulo#endif /* CONFIG_MESH */ 1735281806Srpaulo 1736281806Srpaulo 1737189251Ssam/* Helper macros for network block parser */ 1738189251Ssam 1739189251Ssam#ifdef OFFSET 1740189251Ssam#undef OFFSET 1741189251Ssam#endif /* OFFSET */ 1742189251Ssam/* OFFSET: Get offset of a variable within the wpa_ssid structure */ 1743189251Ssam#define OFFSET(v) ((void *) &((struct wpa_ssid *) 0)->v) 1744189251Ssam 1745189251Ssam/* STR: Define a string variable for an ASCII string; f = field name */ 1746189251Ssam#ifdef NO_CONFIG_WRITE 1747189251Ssam#define _STR(f) #f, wpa_config_parse_str, OFFSET(f) 1748189251Ssam#define _STRe(f) #f, wpa_config_parse_str, OFFSET(eap.f) 1749189251Ssam#else /* NO_CONFIG_WRITE */ 1750189251Ssam#define _STR(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(f) 1751189251Ssam#define _STRe(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(eap.f) 1752189251Ssam#endif /* NO_CONFIG_WRITE */ 1753189251Ssam#define STR(f) _STR(f), NULL, NULL, NULL, 0 1754189251Ssam#define STRe(f) _STRe(f), NULL, NULL, NULL, 0 1755189251Ssam#define STR_KEY(f) _STR(f), NULL, NULL, NULL, 1 1756189251Ssam#define STR_KEYe(f) _STRe(f), NULL, NULL, NULL, 1 1757189251Ssam 1758189251Ssam/* STR_LEN: Define a string variable with a separate variable for storing the 1759189251Ssam * data length. Unlike STR(), this can be used to store arbitrary binary data 1760189251Ssam * (i.e., even nul termination character). */ 1761189251Ssam#define _STR_LEN(f) _STR(f), OFFSET(f ## _len) 1762189251Ssam#define _STR_LENe(f) _STRe(f), OFFSET(eap.f ## _len) 1763189251Ssam#define STR_LEN(f) _STR_LEN(f), NULL, NULL, 0 1764189251Ssam#define STR_LENe(f) _STR_LENe(f), NULL, NULL, 0 1765189251Ssam#define STR_LEN_KEY(f) _STR_LEN(f), NULL, NULL, 1 1766189251Ssam 1767189251Ssam/* STR_RANGE: Like STR_LEN(), but with minimum and maximum allowed length 1768189251Ssam * explicitly specified. */ 1769189251Ssam#define _STR_RANGE(f, min, max) _STR_LEN(f), (void *) (min), (void *) (max) 1770189251Ssam#define STR_RANGE(f, min, max) _STR_RANGE(f, min, max), 0 1771189251Ssam#define STR_RANGE_KEY(f, min, max) _STR_RANGE(f, min, max), 1 1772189251Ssam 1773189251Ssam#ifdef NO_CONFIG_WRITE 1774189251Ssam#define _INT(f) #f, wpa_config_parse_int, OFFSET(f), (void *) 0 1775189251Ssam#define _INTe(f) #f, wpa_config_parse_int, OFFSET(eap.f), (void *) 0 1776189251Ssam#else /* NO_CONFIG_WRITE */ 1777189251Ssam#define _INT(f) #f, wpa_config_parse_int, wpa_config_write_int, \ 1778189251Ssam OFFSET(f), (void *) 0 1779189251Ssam#define _INTe(f) #f, wpa_config_parse_int, wpa_config_write_int, \ 1780189251Ssam OFFSET(eap.f), (void *) 0 1781189251Ssam#endif /* NO_CONFIG_WRITE */ 1782189251Ssam 1783189251Ssam/* INT: Define an integer variable */ 1784189251Ssam#define INT(f) _INT(f), NULL, NULL, 0 1785189251Ssam#define INTe(f) _INTe(f), NULL, NULL, 0 1786189251Ssam 1787189251Ssam/* INT_RANGE: Define an integer variable with allowed value range */ 1788189251Ssam#define INT_RANGE(f, min, max) _INT(f), (void *) (min), (void *) (max), 0 1789189251Ssam 1790189251Ssam/* FUNC: Define a configuration variable that uses a custom function for 1791189251Ssam * parsing and writing the value. */ 1792189251Ssam#ifdef NO_CONFIG_WRITE 1793189251Ssam#define _FUNC(f) #f, wpa_config_parse_ ## f, NULL, NULL, NULL, NULL 1794189251Ssam#else /* NO_CONFIG_WRITE */ 1795189251Ssam#define _FUNC(f) #f, wpa_config_parse_ ## f, wpa_config_write_ ## f, \ 1796189251Ssam NULL, NULL, NULL, NULL 1797189251Ssam#endif /* NO_CONFIG_WRITE */ 1798189251Ssam#define FUNC(f) _FUNC(f), 0 1799189251Ssam#define FUNC_KEY(f) _FUNC(f), 1 1800189251Ssam 1801189251Ssam/* 1802189251Ssam * Table of network configuration variables. This table is used to parse each 1803189251Ssam * network configuration variable, e.g., each line in wpa_supplicant.conf file 1804189251Ssam * that is inside a network block. 1805189251Ssam * 1806189251Ssam * This table is generated using the helper macros defined above and with 1807189251Ssam * generous help from the C pre-processor. The field name is stored as a string 1808189251Ssam * into .name and for STR and INT types, the offset of the target buffer within 1809189251Ssam * struct wpa_ssid is stored in .param1. .param2 (if not NULL) is similar 1810189251Ssam * offset to the field containing the length of the configuration variable. 1811189251Ssam * .param3 and .param4 can be used to mark the allowed range (length for STR 1812189251Ssam * and value for INT). 1813189251Ssam * 1814189251Ssam * For each configuration line in wpa_supplicant.conf, the parser goes through 1815189251Ssam * this table and select the entry that matches with the field name. The parser 1816189251Ssam * function (.parser) is then called to parse the actual value of the field. 1817189251Ssam * 1818189251Ssam * This kind of mechanism makes it easy to add new configuration parameters, 1819189251Ssam * since only one line needs to be added into this table and into the 1820189251Ssam * struct wpa_ssid definition if the new variable is either a string or 1821189251Ssam * integer. More complex types will need to use their own parser and writer 1822189251Ssam * functions. 1823189251Ssam */ 1824189251Ssamstatic const struct parse_data ssid_fields[] = { 1825289549Srpaulo { STR_RANGE(ssid, 0, SSID_MAX_LEN) }, 1826189251Ssam { INT_RANGE(scan_ssid, 0, 1) }, 1827189251Ssam { FUNC(bssid) }, 1828281806Srpaulo { FUNC(bssid_blacklist) }, 1829281806Srpaulo { FUNC(bssid_whitelist) }, 1830189251Ssam { FUNC_KEY(psk) }, 1831289549Srpaulo { INT(mem_only_psk) }, 1832189251Ssam { FUNC(proto) }, 1833189251Ssam { FUNC(key_mgmt) }, 1834252726Srpaulo { INT(bg_scan_period) }, 1835189251Ssam { FUNC(pairwise) }, 1836189251Ssam { FUNC(group) }, 1837189251Ssam { FUNC(auth_alg) }, 1838214734Srpaulo { FUNC(scan_freq) }, 1839214734Srpaulo { FUNC(freq_list) }, 1840189251Ssam#ifdef IEEE8021X_EAPOL 1841189251Ssam { FUNC(eap) }, 1842189251Ssam { STR_LENe(identity) }, 1843189251Ssam { STR_LENe(anonymous_identity) }, 1844189251Ssam { FUNC_KEY(password) }, 1845189251Ssam { STRe(ca_cert) }, 1846189251Ssam { STRe(ca_path) }, 1847189251Ssam { STRe(client_cert) }, 1848189251Ssam { STRe(private_key) }, 1849189251Ssam { STR_KEYe(private_key_passwd) }, 1850189251Ssam { STRe(dh_file) }, 1851189251Ssam { STRe(subject_match) }, 1852189251Ssam { STRe(altsubject_match) }, 1853281806Srpaulo { STRe(domain_suffix_match) }, 1854281806Srpaulo { STRe(domain_match) }, 1855189251Ssam { STRe(ca_cert2) }, 1856189251Ssam { STRe(ca_path2) }, 1857189251Ssam { STRe(client_cert2) }, 1858189251Ssam { STRe(private_key2) }, 1859189251Ssam { STR_KEYe(private_key2_passwd) }, 1860189251Ssam { STRe(dh_file2) }, 1861189251Ssam { STRe(subject_match2) }, 1862189251Ssam { STRe(altsubject_match2) }, 1863281806Srpaulo { STRe(domain_suffix_match2) }, 1864281806Srpaulo { STRe(domain_match2) }, 1865189251Ssam { STRe(phase1) }, 1866189251Ssam { STRe(phase2) }, 1867189251Ssam { STRe(pcsc) }, 1868189251Ssam { STR_KEYe(pin) }, 1869189251Ssam { STRe(engine_id) }, 1870189251Ssam { STRe(key_id) }, 1871189251Ssam { STRe(cert_id) }, 1872189251Ssam { STRe(ca_cert_id) }, 1873189251Ssam { STR_KEYe(pin2) }, 1874189251Ssam { STRe(engine2_id) }, 1875189251Ssam { STRe(key2_id) }, 1876189251Ssam { STRe(cert2_id) }, 1877189251Ssam { STRe(ca_cert2_id) }, 1878189251Ssam { INTe(engine) }, 1879189251Ssam { INTe(engine2) }, 1880189251Ssam { INT(eapol_flags) }, 1881281806Srpaulo { INTe(sim_num) }, 1882281806Srpaulo { STRe(openssl_ciphers) }, 1883281806Srpaulo { INTe(erp) }, 1884189251Ssam#endif /* IEEE8021X_EAPOL */ 1885189251Ssam { FUNC_KEY(wep_key0) }, 1886189251Ssam { FUNC_KEY(wep_key1) }, 1887189251Ssam { FUNC_KEY(wep_key2) }, 1888189251Ssam { FUNC_KEY(wep_key3) }, 1889189251Ssam { INT(wep_tx_keyidx) }, 1890189251Ssam { INT(priority) }, 1891189251Ssam#ifdef IEEE8021X_EAPOL 1892189251Ssam { INT(eap_workaround) }, 1893189251Ssam { STRe(pac_file) }, 1894189251Ssam { INTe(fragment_size) }, 1895281806Srpaulo { INTe(ocsp) }, 1896189251Ssam#endif /* IEEE8021X_EAPOL */ 1897281806Srpaulo#ifdef CONFIG_MESH 1898281806Srpaulo { INT_RANGE(mode, 0, 5) }, 1899281806Srpaulo { INT_RANGE(no_auto_peer, 0, 1) }, 1900281806Srpaulo#else /* CONFIG_MESH */ 1901252726Srpaulo { INT_RANGE(mode, 0, 4) }, 1902281806Srpaulo#endif /* CONFIG_MESH */ 1903189251Ssam { INT_RANGE(proactive_key_caching, 0, 1) }, 1904252726Srpaulo { INT_RANGE(disabled, 0, 2) }, 1905189251Ssam { STR(id_str) }, 1906189251Ssam#ifdef CONFIG_IEEE80211W 1907189251Ssam { INT_RANGE(ieee80211w, 0, 2) }, 1908189251Ssam#endif /* CONFIG_IEEE80211W */ 1909189251Ssam { INT_RANGE(peerkey, 0, 1) }, 1910189251Ssam { INT_RANGE(mixed_cell, 0, 1) }, 1911252726Srpaulo { INT_RANGE(frequency, 0, 65000) }, 1912281806Srpaulo { INT_RANGE(fixed_freq, 0, 1) }, 1913281806Srpaulo#ifdef CONFIG_MESH 1914281806Srpaulo { FUNC(mesh_basic_rates) }, 1915281806Srpaulo { INT(dot11MeshMaxRetries) }, 1916281806Srpaulo { INT(dot11MeshRetryTimeout) }, 1917281806Srpaulo { INT(dot11MeshConfirmTimeout) }, 1918281806Srpaulo { INT(dot11MeshHoldingTimeout) }, 1919281806Srpaulo#endif /* CONFIG_MESH */ 1920214734Srpaulo { INT(wpa_ptk_rekey) }, 1921214734Srpaulo { STR(bgscan) }, 1922252726Srpaulo { INT_RANGE(ignore_broadcast_ssid, 0, 2) }, 1923252726Srpaulo#ifdef CONFIG_P2P 1924281806Srpaulo { FUNC(go_p2p_dev_addr) }, 1925252726Srpaulo { FUNC(p2p_client_list) }, 1926281806Srpaulo { FUNC(psk_list) }, 1927252726Srpaulo#endif /* CONFIG_P2P */ 1928252726Srpaulo#ifdef CONFIG_HT_OVERRIDES 1929252726Srpaulo { INT_RANGE(disable_ht, 0, 1) }, 1930252726Srpaulo { INT_RANGE(disable_ht40, -1, 1) }, 1931252726Srpaulo { INT_RANGE(disable_sgi, 0, 1) }, 1932281806Srpaulo { INT_RANGE(disable_ldpc, 0, 1) }, 1933281806Srpaulo { INT_RANGE(ht40_intolerant, 0, 1) }, 1934252726Srpaulo { INT_RANGE(disable_max_amsdu, -1, 1) }, 1935252726Srpaulo { INT_RANGE(ampdu_factor, -1, 3) }, 1936252726Srpaulo { INT_RANGE(ampdu_density, -1, 7) }, 1937252726Srpaulo { STR(ht_mcs) }, 1938252726Srpaulo#endif /* CONFIG_HT_OVERRIDES */ 1939281806Srpaulo#ifdef CONFIG_VHT_OVERRIDES 1940281806Srpaulo { INT_RANGE(disable_vht, 0, 1) }, 1941281806Srpaulo { INT(vht_capa) }, 1942281806Srpaulo { INT(vht_capa_mask) }, 1943281806Srpaulo { INT_RANGE(vht_rx_mcs_nss_1, -1, 3) }, 1944281806Srpaulo { INT_RANGE(vht_rx_mcs_nss_2, -1, 3) }, 1945281806Srpaulo { INT_RANGE(vht_rx_mcs_nss_3, -1, 3) }, 1946281806Srpaulo { INT_RANGE(vht_rx_mcs_nss_4, -1, 3) }, 1947281806Srpaulo { INT_RANGE(vht_rx_mcs_nss_5, -1, 3) }, 1948281806Srpaulo { INT_RANGE(vht_rx_mcs_nss_6, -1, 3) }, 1949281806Srpaulo { INT_RANGE(vht_rx_mcs_nss_7, -1, 3) }, 1950281806Srpaulo { INT_RANGE(vht_rx_mcs_nss_8, -1, 3) }, 1951281806Srpaulo { INT_RANGE(vht_tx_mcs_nss_1, -1, 3) }, 1952281806Srpaulo { INT_RANGE(vht_tx_mcs_nss_2, -1, 3) }, 1953281806Srpaulo { INT_RANGE(vht_tx_mcs_nss_3, -1, 3) }, 1954281806Srpaulo { INT_RANGE(vht_tx_mcs_nss_4, -1, 3) }, 1955281806Srpaulo { INT_RANGE(vht_tx_mcs_nss_5, -1, 3) }, 1956281806Srpaulo { INT_RANGE(vht_tx_mcs_nss_6, -1, 3) }, 1957281806Srpaulo { INT_RANGE(vht_tx_mcs_nss_7, -1, 3) }, 1958281806Srpaulo { INT_RANGE(vht_tx_mcs_nss_8, -1, 3) }, 1959281806Srpaulo#endif /* CONFIG_VHT_OVERRIDES */ 1960252726Srpaulo { INT(ap_max_inactivity) }, 1961252726Srpaulo { INT(dtim_period) }, 1962281806Srpaulo { INT(beacon_int) }, 1963281806Srpaulo#ifdef CONFIG_MACSEC 1964281806Srpaulo { INT_RANGE(macsec_policy, 0, 1) }, 1965281806Srpaulo#endif /* CONFIG_MACSEC */ 1966281806Srpaulo#ifdef CONFIG_HS20 1967281806Srpaulo { INT(update_identifier) }, 1968281806Srpaulo#endif /* CONFIG_HS20 */ 1969281806Srpaulo { INT_RANGE(mac_addr, 0, 2) }, 1970189251Ssam}; 1971189251Ssam 1972189251Ssam#undef OFFSET 1973189251Ssam#undef _STR 1974189251Ssam#undef STR 1975189251Ssam#undef STR_KEY 1976189251Ssam#undef _STR_LEN 1977189251Ssam#undef STR_LEN 1978189251Ssam#undef STR_LEN_KEY 1979189251Ssam#undef _STR_RANGE 1980189251Ssam#undef STR_RANGE 1981189251Ssam#undef STR_RANGE_KEY 1982189251Ssam#undef _INT 1983189251Ssam#undef INT 1984189251Ssam#undef INT_RANGE 1985189251Ssam#undef _FUNC 1986189251Ssam#undef FUNC 1987189251Ssam#undef FUNC_KEY 1988281806Srpaulo#define NUM_SSID_FIELDS ARRAY_SIZE(ssid_fields) 1989189251Ssam 1990189251Ssam 1991189251Ssam/** 1992189251Ssam * wpa_config_add_prio_network - Add a network to priority lists 1993189251Ssam * @config: Configuration data from wpa_config_read() 1994189251Ssam * @ssid: Pointer to the network configuration to be added to the list 1995189251Ssam * Returns: 0 on success, -1 on failure 1996189251Ssam * 1997189251Ssam * This function is used to add a network block to the priority list of 1998189251Ssam * networks. This must be called for each network when reading in the full 1999189251Ssam * configuration. In addition, this can be used indirectly when updating 2000189251Ssam * priorities by calling wpa_config_update_prio_list(). 2001189251Ssam */ 2002189251Ssamint wpa_config_add_prio_network(struct wpa_config *config, 2003189251Ssam struct wpa_ssid *ssid) 2004189251Ssam{ 2005189251Ssam int prio; 2006189251Ssam struct wpa_ssid *prev, **nlist; 2007189251Ssam 2008189251Ssam /* 2009189251Ssam * Add to an existing priority list if one is available for the 2010189251Ssam * configured priority level for this network. 2011189251Ssam */ 2012189251Ssam for (prio = 0; prio < config->num_prio; prio++) { 2013189251Ssam prev = config->pssid[prio]; 2014189251Ssam if (prev->priority == ssid->priority) { 2015189251Ssam while (prev->pnext) 2016189251Ssam prev = prev->pnext; 2017189251Ssam prev->pnext = ssid; 2018189251Ssam return 0; 2019189251Ssam } 2020189251Ssam } 2021189251Ssam 2022189251Ssam /* First network for this priority - add a new priority list */ 2023252726Srpaulo nlist = os_realloc_array(config->pssid, config->num_prio + 1, 2024252726Srpaulo sizeof(struct wpa_ssid *)); 2025189251Ssam if (nlist == NULL) 2026189251Ssam return -1; 2027189251Ssam 2028189251Ssam for (prio = 0; prio < config->num_prio; prio++) { 2029252726Srpaulo if (nlist[prio]->priority < ssid->priority) { 2030252726Srpaulo os_memmove(&nlist[prio + 1], &nlist[prio], 2031252726Srpaulo (config->num_prio - prio) * 2032252726Srpaulo sizeof(struct wpa_ssid *)); 2033189251Ssam break; 2034252726Srpaulo } 2035189251Ssam } 2036189251Ssam 2037189251Ssam nlist[prio] = ssid; 2038189251Ssam config->num_prio++; 2039189251Ssam config->pssid = nlist; 2040189251Ssam 2041189251Ssam return 0; 2042189251Ssam} 2043189251Ssam 2044189251Ssam 2045189251Ssam/** 2046189251Ssam * wpa_config_update_prio_list - Update network priority list 2047189251Ssam * @config: Configuration data from wpa_config_read() 2048189251Ssam * Returns: 0 on success, -1 on failure 2049189251Ssam * 2050189251Ssam * This function is called to update the priority list of networks in the 2051189251Ssam * configuration when a network is being added or removed. This is also called 2052189251Ssam * if a priority for a network is changed. 2053189251Ssam */ 2054214734Srpauloint wpa_config_update_prio_list(struct wpa_config *config) 2055189251Ssam{ 2056189251Ssam struct wpa_ssid *ssid; 2057189251Ssam int ret = 0; 2058189251Ssam 2059189251Ssam os_free(config->pssid); 2060189251Ssam config->pssid = NULL; 2061189251Ssam config->num_prio = 0; 2062189251Ssam 2063189251Ssam ssid = config->ssid; 2064189251Ssam while (ssid) { 2065189251Ssam ssid->pnext = NULL; 2066189251Ssam if (wpa_config_add_prio_network(config, ssid) < 0) 2067189251Ssam ret = -1; 2068189251Ssam ssid = ssid->next; 2069189251Ssam } 2070189251Ssam 2071189251Ssam return ret; 2072189251Ssam} 2073189251Ssam 2074189251Ssam 2075189251Ssam#ifdef IEEE8021X_EAPOL 2076189251Ssamstatic void eap_peer_config_free(struct eap_peer_config *eap) 2077189251Ssam{ 2078189251Ssam os_free(eap->eap_methods); 2079281806Srpaulo bin_clear_free(eap->identity, eap->identity_len); 2080189251Ssam os_free(eap->anonymous_identity); 2081281806Srpaulo bin_clear_free(eap->password, eap->password_len); 2082189251Ssam os_free(eap->ca_cert); 2083189251Ssam os_free(eap->ca_path); 2084189251Ssam os_free(eap->client_cert); 2085189251Ssam os_free(eap->private_key); 2086281806Srpaulo str_clear_free(eap->private_key_passwd); 2087189251Ssam os_free(eap->dh_file); 2088189251Ssam os_free(eap->subject_match); 2089189251Ssam os_free(eap->altsubject_match); 2090281806Srpaulo os_free(eap->domain_suffix_match); 2091281806Srpaulo os_free(eap->domain_match); 2092189251Ssam os_free(eap->ca_cert2); 2093189251Ssam os_free(eap->ca_path2); 2094189251Ssam os_free(eap->client_cert2); 2095189251Ssam os_free(eap->private_key2); 2096281806Srpaulo str_clear_free(eap->private_key2_passwd); 2097189251Ssam os_free(eap->dh_file2); 2098189251Ssam os_free(eap->subject_match2); 2099189251Ssam os_free(eap->altsubject_match2); 2100281806Srpaulo os_free(eap->domain_suffix_match2); 2101281806Srpaulo os_free(eap->domain_match2); 2102189251Ssam os_free(eap->phase1); 2103189251Ssam os_free(eap->phase2); 2104189251Ssam os_free(eap->pcsc); 2105281806Srpaulo str_clear_free(eap->pin); 2106189251Ssam os_free(eap->engine_id); 2107189251Ssam os_free(eap->key_id); 2108189251Ssam os_free(eap->cert_id); 2109189251Ssam os_free(eap->ca_cert_id); 2110189251Ssam os_free(eap->key2_id); 2111189251Ssam os_free(eap->cert2_id); 2112189251Ssam os_free(eap->ca_cert2_id); 2113281806Srpaulo str_clear_free(eap->pin2); 2114189251Ssam os_free(eap->engine2_id); 2115189251Ssam os_free(eap->otp); 2116189251Ssam os_free(eap->pending_req_otp); 2117189251Ssam os_free(eap->pac_file); 2118281806Srpaulo bin_clear_free(eap->new_password, eap->new_password_len); 2119281806Srpaulo str_clear_free(eap->external_sim_resp); 2120281806Srpaulo os_free(eap->openssl_ciphers); 2121189251Ssam} 2122189251Ssam#endif /* IEEE8021X_EAPOL */ 2123189251Ssam 2124189251Ssam 2125189251Ssam/** 2126189251Ssam * wpa_config_free_ssid - Free network/ssid configuration data 2127189251Ssam * @ssid: Configuration data for the network 2128189251Ssam * 2129189251Ssam * This function frees all resources allocated for the network configuration 2130189251Ssam * data. 2131189251Ssam */ 2132189251Ssamvoid wpa_config_free_ssid(struct wpa_ssid *ssid) 2133189251Ssam{ 2134281806Srpaulo struct psk_list_entry *psk; 2135281806Srpaulo 2136189251Ssam os_free(ssid->ssid); 2137281806Srpaulo str_clear_free(ssid->passphrase); 2138252726Srpaulo os_free(ssid->ext_psk); 2139189251Ssam#ifdef IEEE8021X_EAPOL 2140189251Ssam eap_peer_config_free(&ssid->eap); 2141189251Ssam#endif /* IEEE8021X_EAPOL */ 2142189251Ssam os_free(ssid->id_str); 2143214734Srpaulo os_free(ssid->scan_freq); 2144214734Srpaulo os_free(ssid->freq_list); 2145214734Srpaulo os_free(ssid->bgscan); 2146252726Srpaulo os_free(ssid->p2p_client_list); 2147281806Srpaulo os_free(ssid->bssid_blacklist); 2148281806Srpaulo os_free(ssid->bssid_whitelist); 2149252726Srpaulo#ifdef CONFIG_HT_OVERRIDES 2150252726Srpaulo os_free(ssid->ht_mcs); 2151252726Srpaulo#endif /* CONFIG_HT_OVERRIDES */ 2152281806Srpaulo#ifdef CONFIG_MESH 2153281806Srpaulo os_free(ssid->mesh_basic_rates); 2154281806Srpaulo#endif /* CONFIG_MESH */ 2155281806Srpaulo while ((psk = dl_list_first(&ssid->psk_list, struct psk_list_entry, 2156281806Srpaulo list))) { 2157281806Srpaulo dl_list_del(&psk->list); 2158281806Srpaulo bin_clear_free(psk, sizeof(*psk)); 2159281806Srpaulo } 2160281806Srpaulo bin_clear_free(ssid, sizeof(*ssid)); 2161189251Ssam} 2162189251Ssam 2163189251Ssam 2164252726Srpaulovoid wpa_config_free_cred(struct wpa_cred *cred) 2165252726Srpaulo{ 2166281806Srpaulo size_t i; 2167281806Srpaulo 2168252726Srpaulo os_free(cred->realm); 2169281806Srpaulo str_clear_free(cred->username); 2170281806Srpaulo str_clear_free(cred->password); 2171252726Srpaulo os_free(cred->ca_cert); 2172252726Srpaulo os_free(cred->client_cert); 2173252726Srpaulo os_free(cred->private_key); 2174281806Srpaulo str_clear_free(cred->private_key_passwd); 2175252726Srpaulo os_free(cred->imsi); 2176281806Srpaulo str_clear_free(cred->milenage); 2177281806Srpaulo for (i = 0; i < cred->num_domain; i++) 2178281806Srpaulo os_free(cred->domain[i]); 2179252726Srpaulo os_free(cred->domain); 2180281806Srpaulo os_free(cred->domain_suffix_match); 2181252726Srpaulo os_free(cred->eap_method); 2182252726Srpaulo os_free(cred->phase1); 2183252726Srpaulo os_free(cred->phase2); 2184252726Srpaulo os_free(cred->excluded_ssid); 2185281806Srpaulo os_free(cred->roaming_partner); 2186281806Srpaulo os_free(cred->provisioning_sp); 2187281806Srpaulo for (i = 0; i < cred->num_req_conn_capab; i++) 2188281806Srpaulo os_free(cred->req_conn_capab_port[i]); 2189281806Srpaulo os_free(cred->req_conn_capab_port); 2190281806Srpaulo os_free(cred->req_conn_capab_proto); 2191252726Srpaulo os_free(cred); 2192252726Srpaulo} 2193252726Srpaulo 2194252726Srpaulo 2195281806Srpaulovoid wpa_config_flush_blobs(struct wpa_config *config) 2196281806Srpaulo{ 2197281806Srpaulo#ifndef CONFIG_NO_CONFIG_BLOBS 2198281806Srpaulo struct wpa_config_blob *blob, *prev; 2199281806Srpaulo 2200281806Srpaulo blob = config->blobs; 2201281806Srpaulo config->blobs = NULL; 2202281806Srpaulo while (blob) { 2203281806Srpaulo prev = blob; 2204281806Srpaulo blob = blob->next; 2205281806Srpaulo wpa_config_free_blob(prev); 2206281806Srpaulo } 2207281806Srpaulo#endif /* CONFIG_NO_CONFIG_BLOBS */ 2208281806Srpaulo} 2209281806Srpaulo 2210281806Srpaulo 2211189251Ssam/** 2212189251Ssam * wpa_config_free - Free configuration data 2213189251Ssam * @config: Configuration data from wpa_config_read() 2214189251Ssam * 2215189251Ssam * This function frees all resources allocated for the configuration data by 2216189251Ssam * wpa_config_read(). 2217189251Ssam */ 2218189251Ssamvoid wpa_config_free(struct wpa_config *config) 2219189251Ssam{ 2220189251Ssam struct wpa_ssid *ssid, *prev = NULL; 2221252726Srpaulo struct wpa_cred *cred, *cprev; 2222281806Srpaulo int i; 2223252726Srpaulo 2224189251Ssam ssid = config->ssid; 2225189251Ssam while (ssid) { 2226189251Ssam prev = ssid; 2227189251Ssam ssid = ssid->next; 2228189251Ssam wpa_config_free_ssid(prev); 2229189251Ssam } 2230189251Ssam 2231252726Srpaulo cred = config->cred; 2232252726Srpaulo while (cred) { 2233252726Srpaulo cprev = cred; 2234252726Srpaulo cred = cred->next; 2235252726Srpaulo wpa_config_free_cred(cprev); 2236252726Srpaulo } 2237252726Srpaulo 2238281806Srpaulo wpa_config_flush_blobs(config); 2239189251Ssam 2240252726Srpaulo wpabuf_free(config->wps_vendor_ext_m1); 2241281806Srpaulo for (i = 0; i < MAX_WPS_VENDOR_EXT; i++) 2242281806Srpaulo wpabuf_free(config->wps_vendor_ext[i]); 2243189251Ssam os_free(config->ctrl_interface); 2244189251Ssam os_free(config->ctrl_interface_group); 2245189251Ssam os_free(config->opensc_engine_path); 2246189251Ssam os_free(config->pkcs11_engine_path); 2247189251Ssam os_free(config->pkcs11_module_path); 2248281806Srpaulo os_free(config->openssl_ciphers); 2249252726Srpaulo os_free(config->pcsc_reader); 2250281806Srpaulo str_clear_free(config->pcsc_pin); 2251189251Ssam os_free(config->driver_param); 2252189251Ssam os_free(config->device_name); 2253189251Ssam os_free(config->manufacturer); 2254189251Ssam os_free(config->model_name); 2255189251Ssam os_free(config->model_number); 2256189251Ssam os_free(config->serial_number); 2257214734Srpaulo os_free(config->config_methods); 2258252726Srpaulo os_free(config->p2p_ssid_postfix); 2259189251Ssam os_free(config->pssid); 2260252726Srpaulo os_free(config->p2p_pref_chan); 2261281806Srpaulo os_free(config->p2p_no_go_freq.range); 2262252726Srpaulo os_free(config->autoscan); 2263281806Srpaulo os_free(config->freq_list); 2264252726Srpaulo wpabuf_free(config->wps_nfc_dh_pubkey); 2265252726Srpaulo wpabuf_free(config->wps_nfc_dh_privkey); 2266252726Srpaulo wpabuf_free(config->wps_nfc_dev_pw); 2267252726Srpaulo os_free(config->ext_password_backend); 2268281806Srpaulo os_free(config->sae_groups); 2269281806Srpaulo wpabuf_free(config->ap_vendor_elements); 2270281806Srpaulo os_free(config->osu_dir); 2271281806Srpaulo os_free(config->bgscan); 2272281806Srpaulo os_free(config->wowlan_triggers); 2273289549Srpaulo os_free(config->fst_group_id); 2274189251Ssam os_free(config); 2275189251Ssam} 2276189251Ssam 2277189251Ssam 2278189251Ssam/** 2279252726Srpaulo * wpa_config_foreach_network - Iterate over each configured network 2280252726Srpaulo * @config: Configuration data from wpa_config_read() 2281252726Srpaulo * @func: Callback function to process each network 2282252726Srpaulo * @arg: Opaque argument to pass to callback function 2283252726Srpaulo * 2284252726Srpaulo * Iterate over the set of configured networks calling the specified 2285252726Srpaulo * function for each item. We guard against callbacks removing the 2286252726Srpaulo * supplied network. 2287252726Srpaulo */ 2288252726Srpaulovoid wpa_config_foreach_network(struct wpa_config *config, 2289252726Srpaulo void (*func)(void *, struct wpa_ssid *), 2290252726Srpaulo void *arg) 2291252726Srpaulo{ 2292252726Srpaulo struct wpa_ssid *ssid, *next; 2293252726Srpaulo 2294252726Srpaulo ssid = config->ssid; 2295252726Srpaulo while (ssid) { 2296252726Srpaulo next = ssid->next; 2297252726Srpaulo func(arg, ssid); 2298252726Srpaulo ssid = next; 2299252726Srpaulo } 2300252726Srpaulo} 2301252726Srpaulo 2302252726Srpaulo 2303252726Srpaulo/** 2304189251Ssam * wpa_config_get_network - Get configured network based on id 2305189251Ssam * @config: Configuration data from wpa_config_read() 2306189251Ssam * @id: Unique network id to search for 2307189251Ssam * Returns: Network configuration or %NULL if not found 2308189251Ssam */ 2309189251Ssamstruct wpa_ssid * wpa_config_get_network(struct wpa_config *config, int id) 2310189251Ssam{ 2311189251Ssam struct wpa_ssid *ssid; 2312189251Ssam 2313189251Ssam ssid = config->ssid; 2314189251Ssam while (ssid) { 2315189251Ssam if (id == ssid->id) 2316189251Ssam break; 2317189251Ssam ssid = ssid->next; 2318189251Ssam } 2319189251Ssam 2320189251Ssam return ssid; 2321189251Ssam} 2322189251Ssam 2323189251Ssam 2324189251Ssam/** 2325189251Ssam * wpa_config_add_network - Add a new network with empty configuration 2326189251Ssam * @config: Configuration data from wpa_config_read() 2327189251Ssam * Returns: The new network configuration or %NULL if operation failed 2328189251Ssam */ 2329189251Ssamstruct wpa_ssid * wpa_config_add_network(struct wpa_config *config) 2330189251Ssam{ 2331189251Ssam int id; 2332189251Ssam struct wpa_ssid *ssid, *last = NULL; 2333189251Ssam 2334189251Ssam id = -1; 2335189251Ssam ssid = config->ssid; 2336189251Ssam while (ssid) { 2337189251Ssam if (ssid->id > id) 2338189251Ssam id = ssid->id; 2339189251Ssam last = ssid; 2340189251Ssam ssid = ssid->next; 2341189251Ssam } 2342189251Ssam id++; 2343189251Ssam 2344189251Ssam ssid = os_zalloc(sizeof(*ssid)); 2345189251Ssam if (ssid == NULL) 2346189251Ssam return NULL; 2347189251Ssam ssid->id = id; 2348281806Srpaulo dl_list_init(&ssid->psk_list); 2349189251Ssam if (last) 2350189251Ssam last->next = ssid; 2351189251Ssam else 2352189251Ssam config->ssid = ssid; 2353189251Ssam 2354189251Ssam wpa_config_update_prio_list(config); 2355189251Ssam 2356189251Ssam return ssid; 2357189251Ssam} 2358189251Ssam 2359189251Ssam 2360189251Ssam/** 2361189251Ssam * wpa_config_remove_network - Remove a configured network based on id 2362189251Ssam * @config: Configuration data from wpa_config_read() 2363189251Ssam * @id: Unique network id to search for 2364189251Ssam * Returns: 0 on success, or -1 if the network was not found 2365189251Ssam */ 2366189251Ssamint wpa_config_remove_network(struct wpa_config *config, int id) 2367189251Ssam{ 2368189251Ssam struct wpa_ssid *ssid, *prev = NULL; 2369189251Ssam 2370189251Ssam ssid = config->ssid; 2371189251Ssam while (ssid) { 2372189251Ssam if (id == ssid->id) 2373189251Ssam break; 2374189251Ssam prev = ssid; 2375189251Ssam ssid = ssid->next; 2376189251Ssam } 2377189251Ssam 2378189251Ssam if (ssid == NULL) 2379189251Ssam return -1; 2380189251Ssam 2381189251Ssam if (prev) 2382189251Ssam prev->next = ssid->next; 2383189251Ssam else 2384189251Ssam config->ssid = ssid->next; 2385189251Ssam 2386189251Ssam wpa_config_update_prio_list(config); 2387189251Ssam wpa_config_free_ssid(ssid); 2388189251Ssam return 0; 2389189251Ssam} 2390189251Ssam 2391189251Ssam 2392189251Ssam/** 2393189251Ssam * wpa_config_set_network_defaults - Set network default values 2394189251Ssam * @ssid: Pointer to network configuration data 2395189251Ssam */ 2396189251Ssamvoid wpa_config_set_network_defaults(struct wpa_ssid *ssid) 2397189251Ssam{ 2398189251Ssam ssid->proto = DEFAULT_PROTO; 2399189251Ssam ssid->pairwise_cipher = DEFAULT_PAIRWISE; 2400189251Ssam ssid->group_cipher = DEFAULT_GROUP; 2401189251Ssam ssid->key_mgmt = DEFAULT_KEY_MGMT; 2402252726Srpaulo ssid->bg_scan_period = DEFAULT_BG_SCAN_PERIOD; 2403189251Ssam#ifdef IEEE8021X_EAPOL 2404189251Ssam ssid->eapol_flags = DEFAULT_EAPOL_FLAGS; 2405189251Ssam ssid->eap_workaround = DEFAULT_EAP_WORKAROUND; 2406189251Ssam ssid->eap.fragment_size = DEFAULT_FRAGMENT_SIZE; 2407281806Srpaulo ssid->eap.sim_num = DEFAULT_USER_SELECTED_SIM; 2408189251Ssam#endif /* IEEE8021X_EAPOL */ 2409281806Srpaulo#ifdef CONFIG_MESH 2410281806Srpaulo ssid->dot11MeshMaxRetries = DEFAULT_MESH_MAX_RETRIES; 2411281806Srpaulo ssid->dot11MeshRetryTimeout = DEFAULT_MESH_RETRY_TIMEOUT; 2412281806Srpaulo ssid->dot11MeshConfirmTimeout = DEFAULT_MESH_CONFIRM_TIMEOUT; 2413281806Srpaulo ssid->dot11MeshHoldingTimeout = DEFAULT_MESH_HOLDING_TIMEOUT; 2414281806Srpaulo#endif /* CONFIG_MESH */ 2415252726Srpaulo#ifdef CONFIG_HT_OVERRIDES 2416252726Srpaulo ssid->disable_ht = DEFAULT_DISABLE_HT; 2417252726Srpaulo ssid->disable_ht40 = DEFAULT_DISABLE_HT40; 2418252726Srpaulo ssid->disable_sgi = DEFAULT_DISABLE_SGI; 2419281806Srpaulo ssid->disable_ldpc = DEFAULT_DISABLE_LDPC; 2420252726Srpaulo ssid->disable_max_amsdu = DEFAULT_DISABLE_MAX_AMSDU; 2421252726Srpaulo ssid->ampdu_factor = DEFAULT_AMPDU_FACTOR; 2422252726Srpaulo ssid->ampdu_density = DEFAULT_AMPDU_DENSITY; 2423252726Srpaulo#endif /* CONFIG_HT_OVERRIDES */ 2424281806Srpaulo#ifdef CONFIG_VHT_OVERRIDES 2425281806Srpaulo ssid->vht_rx_mcs_nss_1 = -1; 2426281806Srpaulo ssid->vht_rx_mcs_nss_2 = -1; 2427281806Srpaulo ssid->vht_rx_mcs_nss_3 = -1; 2428281806Srpaulo ssid->vht_rx_mcs_nss_4 = -1; 2429281806Srpaulo ssid->vht_rx_mcs_nss_5 = -1; 2430281806Srpaulo ssid->vht_rx_mcs_nss_6 = -1; 2431281806Srpaulo ssid->vht_rx_mcs_nss_7 = -1; 2432281806Srpaulo ssid->vht_rx_mcs_nss_8 = -1; 2433281806Srpaulo ssid->vht_tx_mcs_nss_1 = -1; 2434281806Srpaulo ssid->vht_tx_mcs_nss_2 = -1; 2435281806Srpaulo ssid->vht_tx_mcs_nss_3 = -1; 2436281806Srpaulo ssid->vht_tx_mcs_nss_4 = -1; 2437281806Srpaulo ssid->vht_tx_mcs_nss_5 = -1; 2438281806Srpaulo ssid->vht_tx_mcs_nss_6 = -1; 2439281806Srpaulo ssid->vht_tx_mcs_nss_7 = -1; 2440281806Srpaulo ssid->vht_tx_mcs_nss_8 = -1; 2441281806Srpaulo#endif /* CONFIG_VHT_OVERRIDES */ 2442252726Srpaulo ssid->proactive_key_caching = -1; 2443252726Srpaulo#ifdef CONFIG_IEEE80211W 2444252726Srpaulo ssid->ieee80211w = MGMT_FRAME_PROTECTION_DEFAULT; 2445252726Srpaulo#endif /* CONFIG_IEEE80211W */ 2446281806Srpaulo ssid->mac_addr = -1; 2447189251Ssam} 2448189251Ssam 2449189251Ssam 2450189251Ssam/** 2451189251Ssam * wpa_config_set - Set a variable in network configuration 2452189251Ssam * @ssid: Pointer to network configuration data 2453189251Ssam * @var: Variable name, e.g., "ssid" 2454189251Ssam * @value: Variable value 2455189251Ssam * @line: Line number in configuration file or 0 if not used 2456189251Ssam * Returns: 0 on success, -1 on failure 2457189251Ssam * 2458189251Ssam * This function can be used to set network configuration variables based on 2459189251Ssam * both the configuration file and management interface input. The value 2460189251Ssam * parameter must be in the same format as the text-based configuration file is 2461189251Ssam * using. For example, strings are using double quotation marks. 2462189251Ssam */ 2463189251Ssamint wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value, 2464189251Ssam int line) 2465189251Ssam{ 2466189251Ssam size_t i; 2467189251Ssam int ret = 0; 2468189251Ssam 2469189251Ssam if (ssid == NULL || var == NULL || value == NULL) 2470189251Ssam return -1; 2471189251Ssam 2472189251Ssam for (i = 0; i < NUM_SSID_FIELDS; i++) { 2473189251Ssam const struct parse_data *field = &ssid_fields[i]; 2474189251Ssam if (os_strcmp(var, field->name) != 0) 2475189251Ssam continue; 2476189251Ssam 2477189251Ssam if (field->parser(field, ssid, line, value)) { 2478189251Ssam if (line) { 2479189251Ssam wpa_printf(MSG_ERROR, "Line %d: failed to " 2480189251Ssam "parse %s '%s'.", line, var, value); 2481189251Ssam } 2482189251Ssam ret = -1; 2483189251Ssam } 2484189251Ssam break; 2485189251Ssam } 2486189251Ssam if (i == NUM_SSID_FIELDS) { 2487189251Ssam if (line) { 2488189251Ssam wpa_printf(MSG_ERROR, "Line %d: unknown network field " 2489189251Ssam "'%s'.", line, var); 2490189251Ssam } 2491189251Ssam ret = -1; 2492189251Ssam } 2493189251Ssam 2494189251Ssam return ret; 2495189251Ssam} 2496189251Ssam 2497189251Ssam 2498252726Srpauloint wpa_config_set_quoted(struct wpa_ssid *ssid, const char *var, 2499252726Srpaulo const char *value) 2500252726Srpaulo{ 2501252726Srpaulo size_t len; 2502252726Srpaulo char *buf; 2503252726Srpaulo int ret; 2504252726Srpaulo 2505252726Srpaulo len = os_strlen(value); 2506252726Srpaulo buf = os_malloc(len + 3); 2507252726Srpaulo if (buf == NULL) 2508252726Srpaulo return -1; 2509252726Srpaulo buf[0] = '"'; 2510252726Srpaulo os_memcpy(buf + 1, value, len); 2511252726Srpaulo buf[len + 1] = '"'; 2512252726Srpaulo buf[len + 2] = '\0'; 2513252726Srpaulo ret = wpa_config_set(ssid, var, buf, 0); 2514252726Srpaulo os_free(buf); 2515252726Srpaulo return ret; 2516252726Srpaulo} 2517252726Srpaulo 2518252726Srpaulo 2519214734Srpaulo/** 2520214734Srpaulo * wpa_config_get_all - Get all options from network configuration 2521214734Srpaulo * @ssid: Pointer to network configuration data 2522214734Srpaulo * @get_keys: Determines if keys/passwords will be included in returned list 2523252726Srpaulo * (if they may be exported) 2524214734Srpaulo * Returns: %NULL terminated list of all set keys and their values in the form 2525214734Srpaulo * of [key1, val1, key2, val2, ... , NULL] 2526214734Srpaulo * 2527214734Srpaulo * This function can be used to get list of all configured network properties. 2528214734Srpaulo * The caller is responsible for freeing the returned list and all its 2529214734Srpaulo * elements. 2530214734Srpaulo */ 2531214734Srpaulochar ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys) 2532214734Srpaulo{ 2533289549Srpaulo#ifdef NO_CONFIG_WRITE 2534289549Srpaulo return NULL; 2535289549Srpaulo#else /* NO_CONFIG_WRITE */ 2536214734Srpaulo const struct parse_data *field; 2537214734Srpaulo char *key, *value; 2538214734Srpaulo size_t i; 2539214734Srpaulo char **props; 2540214734Srpaulo int fields_num; 2541214734Srpaulo 2542252726Srpaulo get_keys = get_keys && ssid->export_keys; 2543252726Srpaulo 2544252726Srpaulo props = os_calloc(2 * NUM_SSID_FIELDS + 1, sizeof(char *)); 2545214734Srpaulo if (!props) 2546214734Srpaulo return NULL; 2547214734Srpaulo 2548214734Srpaulo fields_num = 0; 2549214734Srpaulo for (i = 0; i < NUM_SSID_FIELDS; i++) { 2550214734Srpaulo field = &ssid_fields[i]; 2551214734Srpaulo if (field->key_data && !get_keys) 2552214734Srpaulo continue; 2553214734Srpaulo value = field->writer(field, ssid); 2554214734Srpaulo if (value == NULL) 2555214734Srpaulo continue; 2556214734Srpaulo if (os_strlen(value) == 0) { 2557214734Srpaulo os_free(value); 2558214734Srpaulo continue; 2559214734Srpaulo } 2560214734Srpaulo 2561214734Srpaulo key = os_strdup(field->name); 2562214734Srpaulo if (key == NULL) { 2563214734Srpaulo os_free(value); 2564214734Srpaulo goto err; 2565214734Srpaulo } 2566214734Srpaulo 2567214734Srpaulo props[fields_num * 2] = key; 2568214734Srpaulo props[fields_num * 2 + 1] = value; 2569214734Srpaulo 2570214734Srpaulo fields_num++; 2571214734Srpaulo } 2572214734Srpaulo 2573214734Srpaulo return props; 2574214734Srpaulo 2575214734Srpauloerr: 2576214734Srpaulo value = *props; 2577214734Srpaulo while (value) 2578214734Srpaulo os_free(value++); 2579214734Srpaulo os_free(props); 2580214734Srpaulo return NULL; 2581289549Srpaulo#endif /* NO_CONFIG_WRITE */ 2582214734Srpaulo} 2583214734Srpaulo 2584214734Srpaulo 2585189251Ssam#ifndef NO_CONFIG_WRITE 2586189251Ssam/** 2587189251Ssam * wpa_config_get - Get a variable in network configuration 2588189251Ssam * @ssid: Pointer to network configuration data 2589189251Ssam * @var: Variable name, e.g., "ssid" 2590189251Ssam * Returns: Value of the variable or %NULL on failure 2591189251Ssam * 2592189251Ssam * This function can be used to get network configuration variables. The 2593189251Ssam * returned value is a copy of the configuration variable in text format, i.e,. 2594189251Ssam * the same format that the text-based configuration file and wpa_config_set() 2595189251Ssam * are using for the value. The caller is responsible for freeing the returned 2596189251Ssam * value. 2597189251Ssam */ 2598189251Ssamchar * wpa_config_get(struct wpa_ssid *ssid, const char *var) 2599189251Ssam{ 2600189251Ssam size_t i; 2601189251Ssam 2602189251Ssam if (ssid == NULL || var == NULL) 2603189251Ssam return NULL; 2604189251Ssam 2605189251Ssam for (i = 0; i < NUM_SSID_FIELDS; i++) { 2606189251Ssam const struct parse_data *field = &ssid_fields[i]; 2607189251Ssam if (os_strcmp(var, field->name) == 0) 2608189251Ssam return field->writer(field, ssid); 2609189251Ssam } 2610189251Ssam 2611189251Ssam return NULL; 2612189251Ssam} 2613189251Ssam 2614189251Ssam 2615189251Ssam/** 2616189251Ssam * wpa_config_get_no_key - Get a variable in network configuration (no keys) 2617189251Ssam * @ssid: Pointer to network configuration data 2618189251Ssam * @var: Variable name, e.g., "ssid" 2619189251Ssam * Returns: Value of the variable or %NULL on failure 2620189251Ssam * 2621189251Ssam * This function can be used to get network configuration variable like 2622189251Ssam * wpa_config_get(). The only difference is that this functions does not expose 2623189251Ssam * key/password material from the configuration. In case a key/password field 2624189251Ssam * is requested, the returned value is an empty string or %NULL if the variable 2625189251Ssam * is not set or "*" if the variable is set (regardless of its value). The 2626189251Ssam * returned value is a copy of the configuration variable in text format, i.e,. 2627189251Ssam * the same format that the text-based configuration file and wpa_config_set() 2628189251Ssam * are using for the value. The caller is responsible for freeing the returned 2629189251Ssam * value. 2630189251Ssam */ 2631189251Ssamchar * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var) 2632189251Ssam{ 2633189251Ssam size_t i; 2634189251Ssam 2635189251Ssam if (ssid == NULL || var == NULL) 2636189251Ssam return NULL; 2637189251Ssam 2638189251Ssam for (i = 0; i < NUM_SSID_FIELDS; i++) { 2639189251Ssam const struct parse_data *field = &ssid_fields[i]; 2640189251Ssam if (os_strcmp(var, field->name) == 0) { 2641189251Ssam char *res = field->writer(field, ssid); 2642189251Ssam if (field->key_data) { 2643189251Ssam if (res && res[0]) { 2644189251Ssam wpa_printf(MSG_DEBUG, "Do not allow " 2645189251Ssam "key_data field to be " 2646189251Ssam "exposed"); 2647281806Srpaulo str_clear_free(res); 2648189251Ssam return os_strdup("*"); 2649189251Ssam } 2650189251Ssam 2651189251Ssam os_free(res); 2652189251Ssam return NULL; 2653189251Ssam } 2654189251Ssam return res; 2655189251Ssam } 2656189251Ssam } 2657189251Ssam 2658189251Ssam return NULL; 2659189251Ssam} 2660189251Ssam#endif /* NO_CONFIG_WRITE */ 2661189251Ssam 2662189251Ssam 2663189251Ssam/** 2664189251Ssam * wpa_config_update_psk - Update WPA PSK based on passphrase and SSID 2665189251Ssam * @ssid: Pointer to network configuration data 2666189251Ssam * 2667189251Ssam * This function must be called to update WPA PSK when either SSID or the 2668189251Ssam * passphrase has changed for the network configuration. 2669189251Ssam */ 2670189251Ssamvoid wpa_config_update_psk(struct wpa_ssid *ssid) 2671189251Ssam{ 2672189251Ssam#ifndef CONFIG_NO_PBKDF2 2673252726Srpaulo pbkdf2_sha1(ssid->passphrase, ssid->ssid, ssid->ssid_len, 4096, 2674189251Ssam ssid->psk, PMK_LEN); 2675189251Ssam wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)", 2676189251Ssam ssid->psk, PMK_LEN); 2677189251Ssam ssid->psk_set = 1; 2678189251Ssam#endif /* CONFIG_NO_PBKDF2 */ 2679189251Ssam} 2680189251Ssam 2681189251Ssam 2682281806Srpaulostatic int wpa_config_set_cred_req_conn_capab(struct wpa_cred *cred, 2683281806Srpaulo const char *value) 2684281806Srpaulo{ 2685281806Srpaulo u8 *proto; 2686281806Srpaulo int **port; 2687281806Srpaulo int *ports, *nports; 2688281806Srpaulo const char *pos; 2689281806Srpaulo unsigned int num_ports; 2690281806Srpaulo 2691281806Srpaulo proto = os_realloc_array(cred->req_conn_capab_proto, 2692281806Srpaulo cred->num_req_conn_capab + 1, sizeof(u8)); 2693281806Srpaulo if (proto == NULL) 2694281806Srpaulo return -1; 2695281806Srpaulo cred->req_conn_capab_proto = proto; 2696281806Srpaulo 2697281806Srpaulo port = os_realloc_array(cred->req_conn_capab_port, 2698281806Srpaulo cred->num_req_conn_capab + 1, sizeof(int *)); 2699281806Srpaulo if (port == NULL) 2700281806Srpaulo return -1; 2701281806Srpaulo cred->req_conn_capab_port = port; 2702281806Srpaulo 2703281806Srpaulo proto[cred->num_req_conn_capab] = atoi(value); 2704281806Srpaulo 2705281806Srpaulo pos = os_strchr(value, ':'); 2706281806Srpaulo if (pos == NULL) { 2707281806Srpaulo port[cred->num_req_conn_capab] = NULL; 2708281806Srpaulo cred->num_req_conn_capab++; 2709281806Srpaulo return 0; 2710281806Srpaulo } 2711281806Srpaulo pos++; 2712281806Srpaulo 2713281806Srpaulo ports = NULL; 2714281806Srpaulo num_ports = 0; 2715281806Srpaulo 2716281806Srpaulo while (*pos) { 2717281806Srpaulo nports = os_realloc_array(ports, num_ports + 1, sizeof(int)); 2718281806Srpaulo if (nports == NULL) { 2719281806Srpaulo os_free(ports); 2720281806Srpaulo return -1; 2721281806Srpaulo } 2722281806Srpaulo ports = nports; 2723281806Srpaulo ports[num_ports++] = atoi(pos); 2724281806Srpaulo 2725281806Srpaulo pos = os_strchr(pos, ','); 2726281806Srpaulo if (pos == NULL) 2727281806Srpaulo break; 2728281806Srpaulo pos++; 2729281806Srpaulo } 2730281806Srpaulo 2731281806Srpaulo nports = os_realloc_array(ports, num_ports + 1, sizeof(int)); 2732281806Srpaulo if (nports == NULL) { 2733281806Srpaulo os_free(ports); 2734281806Srpaulo return -1; 2735281806Srpaulo } 2736281806Srpaulo ports = nports; 2737281806Srpaulo ports[num_ports] = -1; 2738281806Srpaulo 2739281806Srpaulo port[cred->num_req_conn_capab] = ports; 2740281806Srpaulo cred->num_req_conn_capab++; 2741281806Srpaulo return 0; 2742281806Srpaulo} 2743281806Srpaulo 2744281806Srpaulo 2745252726Srpauloint wpa_config_set_cred(struct wpa_cred *cred, const char *var, 2746252726Srpaulo const char *value, int line) 2747252726Srpaulo{ 2748252726Srpaulo char *val; 2749252726Srpaulo size_t len; 2750252726Srpaulo 2751281806Srpaulo if (os_strcmp(var, "temporary") == 0) { 2752281806Srpaulo cred->temporary = atoi(value); 2753281806Srpaulo return 0; 2754281806Srpaulo } 2755281806Srpaulo 2756252726Srpaulo if (os_strcmp(var, "priority") == 0) { 2757252726Srpaulo cred->priority = atoi(value); 2758252726Srpaulo return 0; 2759252726Srpaulo } 2760252726Srpaulo 2761281806Srpaulo if (os_strcmp(var, "sp_priority") == 0) { 2762281806Srpaulo int prio = atoi(value); 2763281806Srpaulo if (prio < 0 || prio > 255) 2764281806Srpaulo return -1; 2765281806Srpaulo cred->sp_priority = prio; 2766281806Srpaulo return 0; 2767281806Srpaulo } 2768281806Srpaulo 2769252726Srpaulo if (os_strcmp(var, "pcsc") == 0) { 2770252726Srpaulo cred->pcsc = atoi(value); 2771252726Srpaulo return 0; 2772252726Srpaulo } 2773252726Srpaulo 2774252726Srpaulo if (os_strcmp(var, "eap") == 0) { 2775252726Srpaulo struct eap_method_type method; 2776252726Srpaulo method.method = eap_peer_get_type(value, &method.vendor); 2777252726Srpaulo if (method.vendor == EAP_VENDOR_IETF && 2778252726Srpaulo method.method == EAP_TYPE_NONE) { 2779252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: unknown EAP type '%s' " 2780252726Srpaulo "for a credential", line, value); 2781252726Srpaulo return -1; 2782252726Srpaulo } 2783252726Srpaulo os_free(cred->eap_method); 2784252726Srpaulo cred->eap_method = os_malloc(sizeof(*cred->eap_method)); 2785252726Srpaulo if (cred->eap_method == NULL) 2786252726Srpaulo return -1; 2787252726Srpaulo os_memcpy(cred->eap_method, &method, sizeof(method)); 2788252726Srpaulo return 0; 2789252726Srpaulo } 2790252726Srpaulo 2791252726Srpaulo if (os_strcmp(var, "password") == 0 && 2792252726Srpaulo os_strncmp(value, "ext:", 4) == 0) { 2793281806Srpaulo str_clear_free(cred->password); 2794252726Srpaulo cred->password = os_strdup(value); 2795252726Srpaulo cred->ext_password = 1; 2796252726Srpaulo return 0; 2797252726Srpaulo } 2798252726Srpaulo 2799281806Srpaulo if (os_strcmp(var, "update_identifier") == 0) { 2800281806Srpaulo cred->update_identifier = atoi(value); 2801281806Srpaulo return 0; 2802281806Srpaulo } 2803281806Srpaulo 2804281806Srpaulo if (os_strcmp(var, "min_dl_bandwidth_home") == 0) { 2805281806Srpaulo cred->min_dl_bandwidth_home = atoi(value); 2806281806Srpaulo return 0; 2807281806Srpaulo } 2808281806Srpaulo 2809281806Srpaulo if (os_strcmp(var, "min_ul_bandwidth_home") == 0) { 2810281806Srpaulo cred->min_ul_bandwidth_home = atoi(value); 2811281806Srpaulo return 0; 2812281806Srpaulo } 2813281806Srpaulo 2814281806Srpaulo if (os_strcmp(var, "min_dl_bandwidth_roaming") == 0) { 2815281806Srpaulo cred->min_dl_bandwidth_roaming = atoi(value); 2816281806Srpaulo return 0; 2817281806Srpaulo } 2818281806Srpaulo 2819281806Srpaulo if (os_strcmp(var, "min_ul_bandwidth_roaming") == 0) { 2820281806Srpaulo cred->min_ul_bandwidth_roaming = atoi(value); 2821281806Srpaulo return 0; 2822281806Srpaulo } 2823281806Srpaulo 2824281806Srpaulo if (os_strcmp(var, "max_bss_load") == 0) { 2825281806Srpaulo cred->max_bss_load = atoi(value); 2826281806Srpaulo return 0; 2827281806Srpaulo } 2828281806Srpaulo 2829281806Srpaulo if (os_strcmp(var, "req_conn_capab") == 0) 2830281806Srpaulo return wpa_config_set_cred_req_conn_capab(cred, value); 2831281806Srpaulo 2832281806Srpaulo if (os_strcmp(var, "ocsp") == 0) { 2833281806Srpaulo cred->ocsp = atoi(value); 2834281806Srpaulo return 0; 2835281806Srpaulo } 2836281806Srpaulo 2837281806Srpaulo if (os_strcmp(var, "sim_num") == 0) { 2838281806Srpaulo cred->sim_num = atoi(value); 2839281806Srpaulo return 0; 2840281806Srpaulo } 2841281806Srpaulo 2842252726Srpaulo val = wpa_config_parse_string(value, &len); 2843252726Srpaulo if (val == NULL) { 2844252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid field '%s' string " 2845252726Srpaulo "value '%s'.", line, var, value); 2846252726Srpaulo return -1; 2847252726Srpaulo } 2848252726Srpaulo 2849252726Srpaulo if (os_strcmp(var, "realm") == 0) { 2850252726Srpaulo os_free(cred->realm); 2851252726Srpaulo cred->realm = val; 2852252726Srpaulo return 0; 2853252726Srpaulo } 2854252726Srpaulo 2855252726Srpaulo if (os_strcmp(var, "username") == 0) { 2856281806Srpaulo str_clear_free(cred->username); 2857252726Srpaulo cred->username = val; 2858252726Srpaulo return 0; 2859252726Srpaulo } 2860252726Srpaulo 2861252726Srpaulo if (os_strcmp(var, "password") == 0) { 2862281806Srpaulo str_clear_free(cred->password); 2863252726Srpaulo cred->password = val; 2864252726Srpaulo cred->ext_password = 0; 2865252726Srpaulo return 0; 2866252726Srpaulo } 2867252726Srpaulo 2868252726Srpaulo if (os_strcmp(var, "ca_cert") == 0) { 2869252726Srpaulo os_free(cred->ca_cert); 2870252726Srpaulo cred->ca_cert = val; 2871252726Srpaulo return 0; 2872252726Srpaulo } 2873252726Srpaulo 2874252726Srpaulo if (os_strcmp(var, "client_cert") == 0) { 2875252726Srpaulo os_free(cred->client_cert); 2876252726Srpaulo cred->client_cert = val; 2877252726Srpaulo return 0; 2878252726Srpaulo } 2879252726Srpaulo 2880252726Srpaulo if (os_strcmp(var, "private_key") == 0) { 2881252726Srpaulo os_free(cred->private_key); 2882252726Srpaulo cred->private_key = val; 2883252726Srpaulo return 0; 2884252726Srpaulo } 2885252726Srpaulo 2886252726Srpaulo if (os_strcmp(var, "private_key_passwd") == 0) { 2887281806Srpaulo str_clear_free(cred->private_key_passwd); 2888252726Srpaulo cred->private_key_passwd = val; 2889252726Srpaulo return 0; 2890252726Srpaulo } 2891252726Srpaulo 2892252726Srpaulo if (os_strcmp(var, "imsi") == 0) { 2893252726Srpaulo os_free(cred->imsi); 2894252726Srpaulo cred->imsi = val; 2895252726Srpaulo return 0; 2896252726Srpaulo } 2897252726Srpaulo 2898252726Srpaulo if (os_strcmp(var, "milenage") == 0) { 2899281806Srpaulo str_clear_free(cred->milenage); 2900252726Srpaulo cred->milenage = val; 2901252726Srpaulo return 0; 2902252726Srpaulo } 2903252726Srpaulo 2904281806Srpaulo if (os_strcmp(var, "domain_suffix_match") == 0) { 2905281806Srpaulo os_free(cred->domain_suffix_match); 2906281806Srpaulo cred->domain_suffix_match = val; 2907281806Srpaulo return 0; 2908281806Srpaulo } 2909281806Srpaulo 2910252726Srpaulo if (os_strcmp(var, "domain") == 0) { 2911281806Srpaulo char **new_domain; 2912281806Srpaulo new_domain = os_realloc_array(cred->domain, 2913281806Srpaulo cred->num_domain + 1, 2914281806Srpaulo sizeof(char *)); 2915281806Srpaulo if (new_domain == NULL) { 2916281806Srpaulo os_free(val); 2917281806Srpaulo return -1; 2918281806Srpaulo } 2919281806Srpaulo new_domain[cred->num_domain++] = val; 2920281806Srpaulo cred->domain = new_domain; 2921252726Srpaulo return 0; 2922252726Srpaulo } 2923252726Srpaulo 2924252726Srpaulo if (os_strcmp(var, "phase1") == 0) { 2925252726Srpaulo os_free(cred->phase1); 2926252726Srpaulo cred->phase1 = val; 2927252726Srpaulo return 0; 2928252726Srpaulo } 2929252726Srpaulo 2930252726Srpaulo if (os_strcmp(var, "phase2") == 0) { 2931252726Srpaulo os_free(cred->phase2); 2932252726Srpaulo cred->phase2 = val; 2933252726Srpaulo return 0; 2934252726Srpaulo } 2935252726Srpaulo 2936252726Srpaulo if (os_strcmp(var, "roaming_consortium") == 0) { 2937252726Srpaulo if (len < 3 || len > sizeof(cred->roaming_consortium)) { 2938252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid " 2939252726Srpaulo "roaming_consortium length %d (3..15 " 2940252726Srpaulo "expected)", line, (int) len); 2941252726Srpaulo os_free(val); 2942252726Srpaulo return -1; 2943252726Srpaulo } 2944252726Srpaulo os_memcpy(cred->roaming_consortium, val, len); 2945252726Srpaulo cred->roaming_consortium_len = len; 2946252726Srpaulo os_free(val); 2947252726Srpaulo return 0; 2948252726Srpaulo } 2949252726Srpaulo 2950281806Srpaulo if (os_strcmp(var, "required_roaming_consortium") == 0) { 2951281806Srpaulo if (len < 3 || len > sizeof(cred->required_roaming_consortium)) 2952281806Srpaulo { 2953281806Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid " 2954281806Srpaulo "required_roaming_consortium length %d " 2955281806Srpaulo "(3..15 expected)", line, (int) len); 2956281806Srpaulo os_free(val); 2957281806Srpaulo return -1; 2958281806Srpaulo } 2959281806Srpaulo os_memcpy(cred->required_roaming_consortium, val, len); 2960281806Srpaulo cred->required_roaming_consortium_len = len; 2961281806Srpaulo os_free(val); 2962281806Srpaulo return 0; 2963281806Srpaulo } 2964281806Srpaulo 2965252726Srpaulo if (os_strcmp(var, "excluded_ssid") == 0) { 2966252726Srpaulo struct excluded_ssid *e; 2967252726Srpaulo 2968289549Srpaulo if (len > SSID_MAX_LEN) { 2969252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid " 2970252726Srpaulo "excluded_ssid length %d", line, (int) len); 2971252726Srpaulo os_free(val); 2972252726Srpaulo return -1; 2973252726Srpaulo } 2974252726Srpaulo 2975252726Srpaulo e = os_realloc_array(cred->excluded_ssid, 2976252726Srpaulo cred->num_excluded_ssid + 1, 2977252726Srpaulo sizeof(struct excluded_ssid)); 2978252726Srpaulo if (e == NULL) { 2979252726Srpaulo os_free(val); 2980252726Srpaulo return -1; 2981252726Srpaulo } 2982252726Srpaulo cred->excluded_ssid = e; 2983252726Srpaulo 2984252726Srpaulo e = &cred->excluded_ssid[cred->num_excluded_ssid++]; 2985252726Srpaulo os_memcpy(e->ssid, val, len); 2986252726Srpaulo e->ssid_len = len; 2987252726Srpaulo 2988252726Srpaulo os_free(val); 2989252726Srpaulo 2990252726Srpaulo return 0; 2991252726Srpaulo } 2992252726Srpaulo 2993281806Srpaulo if (os_strcmp(var, "roaming_partner") == 0) { 2994281806Srpaulo struct roaming_partner *p; 2995281806Srpaulo char *pos; 2996281806Srpaulo 2997281806Srpaulo p = os_realloc_array(cred->roaming_partner, 2998281806Srpaulo cred->num_roaming_partner + 1, 2999281806Srpaulo sizeof(struct roaming_partner)); 3000281806Srpaulo if (p == NULL) { 3001281806Srpaulo os_free(val); 3002281806Srpaulo return -1; 3003281806Srpaulo } 3004281806Srpaulo cred->roaming_partner = p; 3005281806Srpaulo 3006281806Srpaulo p = &cred->roaming_partner[cred->num_roaming_partner]; 3007281806Srpaulo 3008281806Srpaulo pos = os_strchr(val, ','); 3009281806Srpaulo if (pos == NULL) { 3010281806Srpaulo os_free(val); 3011281806Srpaulo return -1; 3012281806Srpaulo } 3013281806Srpaulo *pos++ = '\0'; 3014281806Srpaulo if (pos - val - 1 >= (int) sizeof(p->fqdn)) { 3015281806Srpaulo os_free(val); 3016281806Srpaulo return -1; 3017281806Srpaulo } 3018281806Srpaulo os_memcpy(p->fqdn, val, pos - val); 3019281806Srpaulo 3020281806Srpaulo p->exact_match = atoi(pos); 3021281806Srpaulo 3022281806Srpaulo pos = os_strchr(pos, ','); 3023281806Srpaulo if (pos == NULL) { 3024281806Srpaulo os_free(val); 3025281806Srpaulo return -1; 3026281806Srpaulo } 3027281806Srpaulo *pos++ = '\0'; 3028281806Srpaulo 3029281806Srpaulo p->priority = atoi(pos); 3030281806Srpaulo 3031281806Srpaulo pos = os_strchr(pos, ','); 3032281806Srpaulo if (pos == NULL) { 3033281806Srpaulo os_free(val); 3034281806Srpaulo return -1; 3035281806Srpaulo } 3036281806Srpaulo *pos++ = '\0'; 3037281806Srpaulo 3038281806Srpaulo if (os_strlen(pos) >= sizeof(p->country)) { 3039281806Srpaulo os_free(val); 3040281806Srpaulo return -1; 3041281806Srpaulo } 3042281806Srpaulo os_memcpy(p->country, pos, os_strlen(pos) + 1); 3043281806Srpaulo 3044281806Srpaulo cred->num_roaming_partner++; 3045281806Srpaulo os_free(val); 3046281806Srpaulo 3047281806Srpaulo return 0; 3048281806Srpaulo } 3049281806Srpaulo 3050281806Srpaulo if (os_strcmp(var, "provisioning_sp") == 0) { 3051281806Srpaulo os_free(cred->provisioning_sp); 3052281806Srpaulo cred->provisioning_sp = val; 3053281806Srpaulo return 0; 3054281806Srpaulo } 3055281806Srpaulo 3056252726Srpaulo if (line) { 3057252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: unknown cred field '%s'.", 3058252726Srpaulo line, var); 3059252726Srpaulo } 3060252726Srpaulo 3061252726Srpaulo os_free(val); 3062252726Srpaulo 3063252726Srpaulo return -1; 3064252726Srpaulo} 3065252726Srpaulo 3066252726Srpaulo 3067281806Srpaulostatic char * alloc_int_str(int val) 3068281806Srpaulo{ 3069281806Srpaulo const unsigned int bufsize = 20; 3070281806Srpaulo char *buf; 3071281806Srpaulo int res; 3072281806Srpaulo 3073281806Srpaulo buf = os_malloc(bufsize); 3074281806Srpaulo if (buf == NULL) 3075281806Srpaulo return NULL; 3076281806Srpaulo res = os_snprintf(buf, bufsize, "%d", val); 3077281806Srpaulo if (os_snprintf_error(bufsize, res)) { 3078281806Srpaulo os_free(buf); 3079281806Srpaulo buf = NULL; 3080281806Srpaulo } 3081281806Srpaulo return buf; 3082281806Srpaulo} 3083281806Srpaulo 3084281806Srpaulo 3085281806Srpaulostatic char * alloc_strdup(const char *str) 3086281806Srpaulo{ 3087281806Srpaulo if (str == NULL) 3088281806Srpaulo return NULL; 3089281806Srpaulo return os_strdup(str); 3090281806Srpaulo} 3091281806Srpaulo 3092281806Srpaulo 3093281806Srpaulochar * wpa_config_get_cred_no_key(struct wpa_cred *cred, const char *var) 3094281806Srpaulo{ 3095281806Srpaulo if (os_strcmp(var, "temporary") == 0) 3096281806Srpaulo return alloc_int_str(cred->temporary); 3097281806Srpaulo 3098281806Srpaulo if (os_strcmp(var, "priority") == 0) 3099281806Srpaulo return alloc_int_str(cred->priority); 3100281806Srpaulo 3101281806Srpaulo if (os_strcmp(var, "sp_priority") == 0) 3102281806Srpaulo return alloc_int_str(cred->sp_priority); 3103281806Srpaulo 3104281806Srpaulo if (os_strcmp(var, "pcsc") == 0) 3105281806Srpaulo return alloc_int_str(cred->pcsc); 3106281806Srpaulo 3107281806Srpaulo if (os_strcmp(var, "eap") == 0) { 3108281806Srpaulo if (!cred->eap_method) 3109281806Srpaulo return NULL; 3110281806Srpaulo return alloc_strdup(eap_get_name(cred->eap_method[0].vendor, 3111281806Srpaulo cred->eap_method[0].method)); 3112281806Srpaulo } 3113281806Srpaulo 3114281806Srpaulo if (os_strcmp(var, "update_identifier") == 0) 3115281806Srpaulo return alloc_int_str(cred->update_identifier); 3116281806Srpaulo 3117281806Srpaulo if (os_strcmp(var, "min_dl_bandwidth_home") == 0) 3118281806Srpaulo return alloc_int_str(cred->min_dl_bandwidth_home); 3119281806Srpaulo 3120281806Srpaulo if (os_strcmp(var, "min_ul_bandwidth_home") == 0) 3121281806Srpaulo return alloc_int_str(cred->min_ul_bandwidth_home); 3122281806Srpaulo 3123281806Srpaulo if (os_strcmp(var, "min_dl_bandwidth_roaming") == 0) 3124281806Srpaulo return alloc_int_str(cred->min_dl_bandwidth_roaming); 3125281806Srpaulo 3126281806Srpaulo if (os_strcmp(var, "min_ul_bandwidth_roaming") == 0) 3127281806Srpaulo return alloc_int_str(cred->min_ul_bandwidth_roaming); 3128281806Srpaulo 3129281806Srpaulo if (os_strcmp(var, "max_bss_load") == 0) 3130281806Srpaulo return alloc_int_str(cred->max_bss_load); 3131281806Srpaulo 3132281806Srpaulo if (os_strcmp(var, "req_conn_capab") == 0) { 3133281806Srpaulo unsigned int i; 3134281806Srpaulo char *buf, *end, *pos; 3135281806Srpaulo int ret; 3136281806Srpaulo 3137281806Srpaulo if (!cred->num_req_conn_capab) 3138281806Srpaulo return NULL; 3139281806Srpaulo 3140281806Srpaulo buf = os_malloc(4000); 3141281806Srpaulo if (buf == NULL) 3142281806Srpaulo return NULL; 3143281806Srpaulo pos = buf; 3144281806Srpaulo end = pos + 4000; 3145281806Srpaulo for (i = 0; i < cred->num_req_conn_capab; i++) { 3146281806Srpaulo int *ports; 3147281806Srpaulo 3148281806Srpaulo ret = os_snprintf(pos, end - pos, "%s%u", 3149281806Srpaulo i > 0 ? "\n" : "", 3150281806Srpaulo cred->req_conn_capab_proto[i]); 3151281806Srpaulo if (os_snprintf_error(end - pos, ret)) 3152281806Srpaulo return buf; 3153281806Srpaulo pos += ret; 3154281806Srpaulo 3155281806Srpaulo ports = cred->req_conn_capab_port[i]; 3156281806Srpaulo if (ports) { 3157281806Srpaulo int j; 3158281806Srpaulo for (j = 0; ports[j] != -1; j++) { 3159281806Srpaulo ret = os_snprintf(pos, end - pos, 3160281806Srpaulo "%s%d", 3161281806Srpaulo j > 0 ? "," : ":", 3162281806Srpaulo ports[j]); 3163281806Srpaulo if (os_snprintf_error(end - pos, ret)) 3164281806Srpaulo return buf; 3165281806Srpaulo pos += ret; 3166281806Srpaulo } 3167281806Srpaulo } 3168281806Srpaulo } 3169281806Srpaulo 3170281806Srpaulo return buf; 3171281806Srpaulo } 3172281806Srpaulo 3173281806Srpaulo if (os_strcmp(var, "ocsp") == 0) 3174281806Srpaulo return alloc_int_str(cred->ocsp); 3175281806Srpaulo 3176281806Srpaulo if (os_strcmp(var, "realm") == 0) 3177281806Srpaulo return alloc_strdup(cred->realm); 3178281806Srpaulo 3179281806Srpaulo if (os_strcmp(var, "username") == 0) 3180281806Srpaulo return alloc_strdup(cred->username); 3181281806Srpaulo 3182281806Srpaulo if (os_strcmp(var, "password") == 0) { 3183281806Srpaulo if (!cred->password) 3184281806Srpaulo return NULL; 3185281806Srpaulo return alloc_strdup("*"); 3186281806Srpaulo } 3187281806Srpaulo 3188281806Srpaulo if (os_strcmp(var, "ca_cert") == 0) 3189281806Srpaulo return alloc_strdup(cred->ca_cert); 3190281806Srpaulo 3191281806Srpaulo if (os_strcmp(var, "client_cert") == 0) 3192281806Srpaulo return alloc_strdup(cred->client_cert); 3193281806Srpaulo 3194281806Srpaulo if (os_strcmp(var, "private_key") == 0) 3195281806Srpaulo return alloc_strdup(cred->private_key); 3196281806Srpaulo 3197281806Srpaulo if (os_strcmp(var, "private_key_passwd") == 0) { 3198281806Srpaulo if (!cred->private_key_passwd) 3199281806Srpaulo return NULL; 3200281806Srpaulo return alloc_strdup("*"); 3201281806Srpaulo } 3202281806Srpaulo 3203281806Srpaulo if (os_strcmp(var, "imsi") == 0) 3204281806Srpaulo return alloc_strdup(cred->imsi); 3205281806Srpaulo 3206281806Srpaulo if (os_strcmp(var, "milenage") == 0) { 3207281806Srpaulo if (!(cred->milenage)) 3208281806Srpaulo return NULL; 3209281806Srpaulo return alloc_strdup("*"); 3210281806Srpaulo } 3211281806Srpaulo 3212281806Srpaulo if (os_strcmp(var, "domain_suffix_match") == 0) 3213281806Srpaulo return alloc_strdup(cred->domain_suffix_match); 3214281806Srpaulo 3215281806Srpaulo if (os_strcmp(var, "domain") == 0) { 3216281806Srpaulo unsigned int i; 3217281806Srpaulo char *buf, *end, *pos; 3218281806Srpaulo int ret; 3219281806Srpaulo 3220281806Srpaulo if (!cred->num_domain) 3221281806Srpaulo return NULL; 3222281806Srpaulo 3223281806Srpaulo buf = os_malloc(4000); 3224281806Srpaulo if (buf == NULL) 3225281806Srpaulo return NULL; 3226281806Srpaulo pos = buf; 3227281806Srpaulo end = pos + 4000; 3228281806Srpaulo 3229281806Srpaulo for (i = 0; i < cred->num_domain; i++) { 3230281806Srpaulo ret = os_snprintf(pos, end - pos, "%s%s", 3231281806Srpaulo i > 0 ? "\n" : "", cred->domain[i]); 3232281806Srpaulo if (os_snprintf_error(end - pos, ret)) 3233281806Srpaulo return buf; 3234281806Srpaulo pos += ret; 3235281806Srpaulo } 3236281806Srpaulo 3237281806Srpaulo return buf; 3238281806Srpaulo } 3239281806Srpaulo 3240281806Srpaulo if (os_strcmp(var, "phase1") == 0) 3241281806Srpaulo return alloc_strdup(cred->phase1); 3242281806Srpaulo 3243281806Srpaulo if (os_strcmp(var, "phase2") == 0) 3244281806Srpaulo return alloc_strdup(cred->phase2); 3245281806Srpaulo 3246281806Srpaulo if (os_strcmp(var, "roaming_consortium") == 0) { 3247281806Srpaulo size_t buflen; 3248281806Srpaulo char *buf; 3249281806Srpaulo 3250281806Srpaulo if (!cred->roaming_consortium_len) 3251281806Srpaulo return NULL; 3252281806Srpaulo buflen = cred->roaming_consortium_len * 2 + 1; 3253281806Srpaulo buf = os_malloc(buflen); 3254281806Srpaulo if (buf == NULL) 3255281806Srpaulo return NULL; 3256281806Srpaulo wpa_snprintf_hex(buf, buflen, cred->roaming_consortium, 3257281806Srpaulo cred->roaming_consortium_len); 3258281806Srpaulo return buf; 3259281806Srpaulo } 3260281806Srpaulo 3261281806Srpaulo if (os_strcmp(var, "required_roaming_consortium") == 0) { 3262281806Srpaulo size_t buflen; 3263281806Srpaulo char *buf; 3264281806Srpaulo 3265281806Srpaulo if (!cred->required_roaming_consortium_len) 3266281806Srpaulo return NULL; 3267281806Srpaulo buflen = cred->required_roaming_consortium_len * 2 + 1; 3268281806Srpaulo buf = os_malloc(buflen); 3269281806Srpaulo if (buf == NULL) 3270281806Srpaulo return NULL; 3271281806Srpaulo wpa_snprintf_hex(buf, buflen, cred->required_roaming_consortium, 3272281806Srpaulo cred->required_roaming_consortium_len); 3273281806Srpaulo return buf; 3274281806Srpaulo } 3275281806Srpaulo 3276281806Srpaulo if (os_strcmp(var, "excluded_ssid") == 0) { 3277281806Srpaulo unsigned int i; 3278281806Srpaulo char *buf, *end, *pos; 3279281806Srpaulo 3280281806Srpaulo if (!cred->num_excluded_ssid) 3281281806Srpaulo return NULL; 3282281806Srpaulo 3283281806Srpaulo buf = os_malloc(4000); 3284281806Srpaulo if (buf == NULL) 3285281806Srpaulo return NULL; 3286281806Srpaulo pos = buf; 3287281806Srpaulo end = pos + 4000; 3288281806Srpaulo 3289281806Srpaulo for (i = 0; i < cred->num_excluded_ssid; i++) { 3290281806Srpaulo struct excluded_ssid *e; 3291281806Srpaulo int ret; 3292281806Srpaulo 3293281806Srpaulo e = &cred->excluded_ssid[i]; 3294281806Srpaulo ret = os_snprintf(pos, end - pos, "%s%s", 3295281806Srpaulo i > 0 ? "\n" : "", 3296281806Srpaulo wpa_ssid_txt(e->ssid, e->ssid_len)); 3297281806Srpaulo if (os_snprintf_error(end - pos, ret)) 3298281806Srpaulo return buf; 3299281806Srpaulo pos += ret; 3300281806Srpaulo } 3301281806Srpaulo 3302281806Srpaulo return buf; 3303281806Srpaulo } 3304281806Srpaulo 3305281806Srpaulo if (os_strcmp(var, "roaming_partner") == 0) { 3306281806Srpaulo unsigned int i; 3307281806Srpaulo char *buf, *end, *pos; 3308281806Srpaulo 3309281806Srpaulo if (!cred->num_roaming_partner) 3310281806Srpaulo return NULL; 3311281806Srpaulo 3312281806Srpaulo buf = os_malloc(4000); 3313281806Srpaulo if (buf == NULL) 3314281806Srpaulo return NULL; 3315281806Srpaulo pos = buf; 3316281806Srpaulo end = pos + 4000; 3317281806Srpaulo 3318281806Srpaulo for (i = 0; i < cred->num_roaming_partner; i++) { 3319281806Srpaulo struct roaming_partner *p; 3320281806Srpaulo int ret; 3321281806Srpaulo 3322281806Srpaulo p = &cred->roaming_partner[i]; 3323281806Srpaulo ret = os_snprintf(pos, end - pos, "%s%s,%d,%u,%s", 3324281806Srpaulo i > 0 ? "\n" : "", 3325281806Srpaulo p->fqdn, p->exact_match, p->priority, 3326281806Srpaulo p->country); 3327281806Srpaulo if (os_snprintf_error(end - pos, ret)) 3328281806Srpaulo return buf; 3329281806Srpaulo pos += ret; 3330281806Srpaulo } 3331281806Srpaulo 3332281806Srpaulo return buf; 3333281806Srpaulo } 3334281806Srpaulo 3335281806Srpaulo if (os_strcmp(var, "provisioning_sp") == 0) 3336281806Srpaulo return alloc_strdup(cred->provisioning_sp); 3337281806Srpaulo 3338281806Srpaulo return NULL; 3339281806Srpaulo} 3340281806Srpaulo 3341281806Srpaulo 3342252726Srpaulostruct wpa_cred * wpa_config_get_cred(struct wpa_config *config, int id) 3343252726Srpaulo{ 3344252726Srpaulo struct wpa_cred *cred; 3345252726Srpaulo 3346252726Srpaulo cred = config->cred; 3347252726Srpaulo while (cred) { 3348252726Srpaulo if (id == cred->id) 3349252726Srpaulo break; 3350252726Srpaulo cred = cred->next; 3351252726Srpaulo } 3352252726Srpaulo 3353252726Srpaulo return cred; 3354252726Srpaulo} 3355252726Srpaulo 3356252726Srpaulo 3357252726Srpaulostruct wpa_cred * wpa_config_add_cred(struct wpa_config *config) 3358252726Srpaulo{ 3359252726Srpaulo int id; 3360252726Srpaulo struct wpa_cred *cred, *last = NULL; 3361252726Srpaulo 3362252726Srpaulo id = -1; 3363252726Srpaulo cred = config->cred; 3364252726Srpaulo while (cred) { 3365252726Srpaulo if (cred->id > id) 3366252726Srpaulo id = cred->id; 3367252726Srpaulo last = cred; 3368252726Srpaulo cred = cred->next; 3369252726Srpaulo } 3370252726Srpaulo id++; 3371252726Srpaulo 3372252726Srpaulo cred = os_zalloc(sizeof(*cred)); 3373252726Srpaulo if (cred == NULL) 3374252726Srpaulo return NULL; 3375252726Srpaulo cred->id = id; 3376281806Srpaulo cred->sim_num = DEFAULT_USER_SELECTED_SIM; 3377252726Srpaulo if (last) 3378252726Srpaulo last->next = cred; 3379252726Srpaulo else 3380252726Srpaulo config->cred = cred; 3381252726Srpaulo 3382252726Srpaulo return cred; 3383252726Srpaulo} 3384252726Srpaulo 3385252726Srpaulo 3386252726Srpauloint wpa_config_remove_cred(struct wpa_config *config, int id) 3387252726Srpaulo{ 3388252726Srpaulo struct wpa_cred *cred, *prev = NULL; 3389252726Srpaulo 3390252726Srpaulo cred = config->cred; 3391252726Srpaulo while (cred) { 3392252726Srpaulo if (id == cred->id) 3393252726Srpaulo break; 3394252726Srpaulo prev = cred; 3395252726Srpaulo cred = cred->next; 3396252726Srpaulo } 3397252726Srpaulo 3398252726Srpaulo if (cred == NULL) 3399252726Srpaulo return -1; 3400252726Srpaulo 3401252726Srpaulo if (prev) 3402252726Srpaulo prev->next = cred->next; 3403252726Srpaulo else 3404252726Srpaulo config->cred = cred->next; 3405252726Srpaulo 3406252726Srpaulo wpa_config_free_cred(cred); 3407252726Srpaulo return 0; 3408252726Srpaulo} 3409252726Srpaulo 3410252726Srpaulo 3411189251Ssam#ifndef CONFIG_NO_CONFIG_BLOBS 3412189251Ssam/** 3413189251Ssam * wpa_config_get_blob - Get a named configuration blob 3414189251Ssam * @config: Configuration data from wpa_config_read() 3415189251Ssam * @name: Name of the blob 3416189251Ssam * Returns: Pointer to blob data or %NULL if not found 3417189251Ssam */ 3418189251Ssamconst struct wpa_config_blob * wpa_config_get_blob(struct wpa_config *config, 3419189251Ssam const char *name) 3420189251Ssam{ 3421189251Ssam struct wpa_config_blob *blob = config->blobs; 3422189251Ssam 3423189251Ssam while (blob) { 3424189251Ssam if (os_strcmp(blob->name, name) == 0) 3425189251Ssam return blob; 3426189251Ssam blob = blob->next; 3427189251Ssam } 3428189251Ssam return NULL; 3429189251Ssam} 3430189251Ssam 3431189251Ssam 3432189251Ssam/** 3433189251Ssam * wpa_config_set_blob - Set or add a named configuration blob 3434189251Ssam * @config: Configuration data from wpa_config_read() 3435189251Ssam * @blob: New value for the blob 3436189251Ssam * 3437189251Ssam * Adds a new configuration blob or replaces the current value of an existing 3438189251Ssam * blob. 3439189251Ssam */ 3440189251Ssamvoid wpa_config_set_blob(struct wpa_config *config, 3441189251Ssam struct wpa_config_blob *blob) 3442189251Ssam{ 3443189251Ssam wpa_config_remove_blob(config, blob->name); 3444189251Ssam blob->next = config->blobs; 3445189251Ssam config->blobs = blob; 3446189251Ssam} 3447189251Ssam 3448189251Ssam 3449189251Ssam/** 3450189251Ssam * wpa_config_free_blob - Free blob data 3451189251Ssam * @blob: Pointer to blob to be freed 3452189251Ssam */ 3453189251Ssamvoid wpa_config_free_blob(struct wpa_config_blob *blob) 3454189251Ssam{ 3455189251Ssam if (blob) { 3456189251Ssam os_free(blob->name); 3457281806Srpaulo bin_clear_free(blob->data, blob->len); 3458189251Ssam os_free(blob); 3459189251Ssam } 3460189251Ssam} 3461189251Ssam 3462189251Ssam 3463189251Ssam/** 3464189251Ssam * wpa_config_remove_blob - Remove a named configuration blob 3465189251Ssam * @config: Configuration data from wpa_config_read() 3466189251Ssam * @name: Name of the blob to remove 3467189251Ssam * Returns: 0 if blob was removed or -1 if blob was not found 3468189251Ssam */ 3469189251Ssamint wpa_config_remove_blob(struct wpa_config *config, const char *name) 3470189251Ssam{ 3471189251Ssam struct wpa_config_blob *pos = config->blobs, *prev = NULL; 3472189251Ssam 3473189251Ssam while (pos) { 3474189251Ssam if (os_strcmp(pos->name, name) == 0) { 3475189251Ssam if (prev) 3476189251Ssam prev->next = pos->next; 3477189251Ssam else 3478189251Ssam config->blobs = pos->next; 3479189251Ssam wpa_config_free_blob(pos); 3480189251Ssam return 0; 3481189251Ssam } 3482189251Ssam prev = pos; 3483189251Ssam pos = pos->next; 3484189251Ssam } 3485189251Ssam 3486189251Ssam return -1; 3487189251Ssam} 3488189251Ssam#endif /* CONFIG_NO_CONFIG_BLOBS */ 3489189251Ssam 3490189251Ssam 3491189251Ssam/** 3492189251Ssam * wpa_config_alloc_empty - Allocate an empty configuration 3493189251Ssam * @ctrl_interface: Control interface parameters, e.g., path to UNIX domain 3494189251Ssam * socket 3495189251Ssam * @driver_param: Driver parameters 3496189251Ssam * Returns: Pointer to allocated configuration data or %NULL on failure 3497189251Ssam */ 3498189251Ssamstruct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface, 3499189251Ssam const char *driver_param) 3500189251Ssam{ 3501189251Ssam struct wpa_config *config; 3502252726Srpaulo const int aCWmin = 4, aCWmax = 10; 3503252726Srpaulo const struct hostapd_wmm_ac_params ac_bk = 3504252726Srpaulo { aCWmin, aCWmax, 7, 0, 0 }; /* background traffic */ 3505252726Srpaulo const struct hostapd_wmm_ac_params ac_be = 3506252726Srpaulo { aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */ 3507252726Srpaulo const struct hostapd_wmm_ac_params ac_vi = /* video traffic */ 3508252726Srpaulo { aCWmin - 1, aCWmin, 2, 3000 / 32, 0 }; 3509252726Srpaulo const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */ 3510252726Srpaulo { aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 0 }; 3511189251Ssam 3512189251Ssam config = os_zalloc(sizeof(*config)); 3513189251Ssam if (config == NULL) 3514189251Ssam return NULL; 3515189251Ssam config->eapol_version = DEFAULT_EAPOL_VERSION; 3516189251Ssam config->ap_scan = DEFAULT_AP_SCAN; 3517281806Srpaulo config->user_mpm = DEFAULT_USER_MPM; 3518281806Srpaulo config->max_peer_links = DEFAULT_MAX_PEER_LINKS; 3519281806Srpaulo config->mesh_max_inactivity = DEFAULT_MESH_MAX_INACTIVITY; 3520289549Srpaulo config->dot11RSNASAERetransPeriod = 3521289549Srpaulo DEFAULT_DOT11_RSNA_SAE_RETRANS_PERIOD; 3522189251Ssam config->fast_reauth = DEFAULT_FAST_REAUTH; 3523252726Srpaulo config->p2p_go_intent = DEFAULT_P2P_GO_INTENT; 3524252726Srpaulo config->p2p_intra_bss = DEFAULT_P2P_INTRA_BSS; 3525289549Srpaulo config->p2p_go_freq_change_policy = DEFAULT_P2P_GO_FREQ_MOVE; 3526252726Srpaulo config->p2p_go_max_inactivity = DEFAULT_P2P_GO_MAX_INACTIVITY; 3527281806Srpaulo config->p2p_optimize_listen_chan = DEFAULT_P2P_OPTIMIZE_LISTEN_CHAN; 3528281806Srpaulo config->p2p_go_ctwindow = DEFAULT_P2P_GO_CTWINDOW; 3529214734Srpaulo config->bss_max_count = DEFAULT_BSS_MAX_COUNT; 3530252726Srpaulo config->bss_expiration_age = DEFAULT_BSS_EXPIRATION_AGE; 3531252726Srpaulo config->bss_expiration_scan_count = DEFAULT_BSS_EXPIRATION_SCAN_COUNT; 3532252726Srpaulo config->max_num_sta = DEFAULT_MAX_NUM_STA; 3533252726Srpaulo config->access_network_type = DEFAULT_ACCESS_NETWORK_TYPE; 3534281806Srpaulo config->scan_cur_freq = DEFAULT_SCAN_CUR_FREQ; 3535252726Srpaulo config->wmm_ac_params[0] = ac_be; 3536252726Srpaulo config->wmm_ac_params[1] = ac_bk; 3537252726Srpaulo config->wmm_ac_params[2] = ac_vi; 3538252726Srpaulo config->wmm_ac_params[3] = ac_vo; 3539281806Srpaulo config->p2p_search_delay = DEFAULT_P2P_SEARCH_DELAY; 3540281806Srpaulo config->rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME; 3541281806Srpaulo config->key_mgmt_offload = DEFAULT_KEY_MGMT_OFFLOAD; 3542281806Srpaulo config->cert_in_cb = DEFAULT_CERT_IN_CB; 3543189251Ssam 3544189251Ssam if (ctrl_interface) 3545189251Ssam config->ctrl_interface = os_strdup(ctrl_interface); 3546189251Ssam if (driver_param) 3547189251Ssam config->driver_param = os_strdup(driver_param); 3548189251Ssam 3549189251Ssam return config; 3550189251Ssam} 3551189251Ssam 3552189251Ssam 3553189251Ssam#ifndef CONFIG_NO_STDOUT_DEBUG 3554189251Ssam/** 3555189251Ssam * wpa_config_debug_dump_networks - Debug dump of configured networks 3556189251Ssam * @config: Configuration data from wpa_config_read() 3557189251Ssam */ 3558189251Ssamvoid wpa_config_debug_dump_networks(struct wpa_config *config) 3559189251Ssam{ 3560189251Ssam int prio; 3561189251Ssam struct wpa_ssid *ssid; 3562189251Ssam 3563189251Ssam for (prio = 0; prio < config->num_prio; prio++) { 3564189251Ssam ssid = config->pssid[prio]; 3565189251Ssam wpa_printf(MSG_DEBUG, "Priority group %d", 3566189251Ssam ssid->priority); 3567189251Ssam while (ssid) { 3568189251Ssam wpa_printf(MSG_DEBUG, " id=%d ssid='%s'", 3569189251Ssam ssid->id, 3570189251Ssam wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); 3571189251Ssam ssid = ssid->pnext; 3572189251Ssam } 3573189251Ssam } 3574189251Ssam} 3575189251Ssam#endif /* CONFIG_NO_STDOUT_DEBUG */ 3576252726Srpaulo 3577252726Srpaulo 3578252726Srpaulostruct global_parse_data { 3579252726Srpaulo char *name; 3580252726Srpaulo int (*parser)(const struct global_parse_data *data, 3581252726Srpaulo struct wpa_config *config, int line, const char *value); 3582281806Srpaulo int (*get)(const char *name, struct wpa_config *config, long offset, 3583281806Srpaulo char *buf, size_t buflen, int pretty_print); 3584252726Srpaulo void *param1, *param2, *param3; 3585252726Srpaulo unsigned int changed_flag; 3586252726Srpaulo}; 3587252726Srpaulo 3588252726Srpaulo 3589252726Srpaulostatic int wpa_global_config_parse_int(const struct global_parse_data *data, 3590252726Srpaulo struct wpa_config *config, int line, 3591252726Srpaulo const char *pos) 3592252726Srpaulo{ 3593281806Srpaulo int val, *dst; 3594281806Srpaulo char *end; 3595281806Srpaulo 3596252726Srpaulo dst = (int *) (((u8 *) config) + (long) data->param1); 3597281806Srpaulo val = strtol(pos, &end, 0); 3598281806Srpaulo if (*end) { 3599281806Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid number \"%s\"", 3600281806Srpaulo line, pos); 3601281806Srpaulo return -1; 3602281806Srpaulo } 3603281806Srpaulo *dst = val; 3604281806Srpaulo 3605252726Srpaulo wpa_printf(MSG_DEBUG, "%s=%d", data->name, *dst); 3606252726Srpaulo 3607252726Srpaulo if (data->param2 && *dst < (long) data->param2) { 3608252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d " 3609252726Srpaulo "min_value=%ld)", line, data->name, *dst, 3610252726Srpaulo (long) data->param2); 3611252726Srpaulo *dst = (long) data->param2; 3612252726Srpaulo return -1; 3613252726Srpaulo } 3614252726Srpaulo 3615252726Srpaulo if (data->param3 && *dst > (long) data->param3) { 3616252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d " 3617252726Srpaulo "max_value=%ld)", line, data->name, *dst, 3618252726Srpaulo (long) data->param3); 3619252726Srpaulo *dst = (long) data->param3; 3620252726Srpaulo return -1; 3621252726Srpaulo } 3622252726Srpaulo 3623252726Srpaulo return 0; 3624252726Srpaulo} 3625252726Srpaulo 3626252726Srpaulo 3627252726Srpaulostatic int wpa_global_config_parse_str(const struct global_parse_data *data, 3628252726Srpaulo struct wpa_config *config, int line, 3629252726Srpaulo const char *pos) 3630252726Srpaulo{ 3631252726Srpaulo size_t len; 3632252726Srpaulo char **dst, *tmp; 3633252726Srpaulo 3634252726Srpaulo len = os_strlen(pos); 3635252726Srpaulo if (data->param2 && len < (size_t) data->param2) { 3636252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu " 3637252726Srpaulo "min_len=%ld)", line, data->name, 3638252726Srpaulo (unsigned long) len, (long) data->param2); 3639252726Srpaulo return -1; 3640252726Srpaulo } 3641252726Srpaulo 3642252726Srpaulo if (data->param3 && len > (size_t) data->param3) { 3643252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu " 3644252726Srpaulo "max_len=%ld)", line, data->name, 3645252726Srpaulo (unsigned long) len, (long) data->param3); 3646252726Srpaulo return -1; 3647252726Srpaulo } 3648252726Srpaulo 3649252726Srpaulo tmp = os_strdup(pos); 3650252726Srpaulo if (tmp == NULL) 3651252726Srpaulo return -1; 3652252726Srpaulo 3653252726Srpaulo dst = (char **) (((u8 *) config) + (long) data->param1); 3654252726Srpaulo os_free(*dst); 3655252726Srpaulo *dst = tmp; 3656252726Srpaulo wpa_printf(MSG_DEBUG, "%s='%s'", data->name, *dst); 3657252726Srpaulo 3658252726Srpaulo return 0; 3659252726Srpaulo} 3660252726Srpaulo 3661252726Srpaulo 3662281806Srpaulostatic int wpa_config_process_bgscan(const struct global_parse_data *data, 3663281806Srpaulo struct wpa_config *config, int line, 3664281806Srpaulo const char *pos) 3665281806Srpaulo{ 3666281806Srpaulo size_t len; 3667281806Srpaulo char *tmp; 3668281806Srpaulo int res; 3669281806Srpaulo 3670281806Srpaulo tmp = wpa_config_parse_string(pos, &len); 3671281806Srpaulo if (tmp == NULL) { 3672281806Srpaulo wpa_printf(MSG_ERROR, "Line %d: failed to parse %s", 3673281806Srpaulo line, data->name); 3674281806Srpaulo return -1; 3675281806Srpaulo } 3676281806Srpaulo 3677281806Srpaulo res = wpa_global_config_parse_str(data, config, line, tmp); 3678281806Srpaulo os_free(tmp); 3679281806Srpaulo return res; 3680281806Srpaulo} 3681281806Srpaulo 3682281806Srpaulo 3683252726Srpaulostatic int wpa_global_config_parse_bin(const struct global_parse_data *data, 3684252726Srpaulo struct wpa_config *config, int line, 3685252726Srpaulo const char *pos) 3686252726Srpaulo{ 3687252726Srpaulo size_t len; 3688252726Srpaulo struct wpabuf **dst, *tmp; 3689252726Srpaulo 3690252726Srpaulo len = os_strlen(pos); 3691252726Srpaulo if (len & 0x01) 3692252726Srpaulo return -1; 3693252726Srpaulo 3694252726Srpaulo tmp = wpabuf_alloc(len / 2); 3695252726Srpaulo if (tmp == NULL) 3696252726Srpaulo return -1; 3697252726Srpaulo 3698252726Srpaulo if (hexstr2bin(pos, wpabuf_put(tmp, len / 2), len / 2)) { 3699252726Srpaulo wpabuf_free(tmp); 3700252726Srpaulo return -1; 3701252726Srpaulo } 3702252726Srpaulo 3703252726Srpaulo dst = (struct wpabuf **) (((u8 *) config) + (long) data->param1); 3704252726Srpaulo wpabuf_free(*dst); 3705252726Srpaulo *dst = tmp; 3706252726Srpaulo wpa_printf(MSG_DEBUG, "%s", data->name); 3707252726Srpaulo 3708252726Srpaulo return 0; 3709252726Srpaulo} 3710252726Srpaulo 3711252726Srpaulo 3712281806Srpaulostatic int wpa_config_process_freq_list(const struct global_parse_data *data, 3713281806Srpaulo struct wpa_config *config, int line, 3714281806Srpaulo const char *value) 3715281806Srpaulo{ 3716281806Srpaulo int *freqs; 3717281806Srpaulo 3718281806Srpaulo freqs = wpa_config_parse_int_array(value); 3719281806Srpaulo if (freqs == NULL) 3720281806Srpaulo return -1; 3721281806Srpaulo if (freqs[0] == 0) { 3722281806Srpaulo os_free(freqs); 3723281806Srpaulo freqs = NULL; 3724281806Srpaulo } 3725281806Srpaulo os_free(config->freq_list); 3726281806Srpaulo config->freq_list = freqs; 3727281806Srpaulo return 0; 3728281806Srpaulo} 3729281806Srpaulo 3730281806Srpaulo 3731281806Srpaulo#ifdef CONFIG_P2P 3732281806Srpaulostatic int wpa_global_config_parse_ipv4(const struct global_parse_data *data, 3733281806Srpaulo struct wpa_config *config, int line, 3734281806Srpaulo const char *pos) 3735281806Srpaulo{ 3736281806Srpaulo u32 *dst; 3737281806Srpaulo struct hostapd_ip_addr addr; 3738281806Srpaulo 3739281806Srpaulo if (hostapd_parse_ip_addr(pos, &addr) < 0) 3740281806Srpaulo return -1; 3741281806Srpaulo if (addr.af != AF_INET) 3742281806Srpaulo return -1; 3743281806Srpaulo 3744281806Srpaulo dst = (u32 *) (((u8 *) config) + (long) data->param1); 3745281806Srpaulo os_memcpy(dst, &addr.u.v4.s_addr, 4); 3746281806Srpaulo wpa_printf(MSG_DEBUG, "%s = 0x%x", data->name, 3747281806Srpaulo WPA_GET_BE32((u8 *) dst)); 3748281806Srpaulo 3749281806Srpaulo return 0; 3750281806Srpaulo} 3751281806Srpaulo#endif /* CONFIG_P2P */ 3752281806Srpaulo 3753281806Srpaulo 3754252726Srpaulostatic int wpa_config_process_country(const struct global_parse_data *data, 3755252726Srpaulo struct wpa_config *config, int line, 3756252726Srpaulo const char *pos) 3757252726Srpaulo{ 3758252726Srpaulo if (!pos[0] || !pos[1]) { 3759252726Srpaulo wpa_printf(MSG_DEBUG, "Invalid country set"); 3760252726Srpaulo return -1; 3761252726Srpaulo } 3762252726Srpaulo config->country[0] = pos[0]; 3763252726Srpaulo config->country[1] = pos[1]; 3764252726Srpaulo wpa_printf(MSG_DEBUG, "country='%c%c'", 3765252726Srpaulo config->country[0], config->country[1]); 3766252726Srpaulo return 0; 3767252726Srpaulo} 3768252726Srpaulo 3769252726Srpaulo 3770252726Srpaulostatic int wpa_config_process_load_dynamic_eap( 3771252726Srpaulo const struct global_parse_data *data, struct wpa_config *config, 3772252726Srpaulo int line, const char *so) 3773252726Srpaulo{ 3774252726Srpaulo int ret; 3775252726Srpaulo wpa_printf(MSG_DEBUG, "load_dynamic_eap=%s", so); 3776252726Srpaulo ret = eap_peer_method_load(so); 3777252726Srpaulo if (ret == -2) { 3778252726Srpaulo wpa_printf(MSG_DEBUG, "This EAP type was already loaded - not " 3779252726Srpaulo "reloading."); 3780252726Srpaulo } else if (ret) { 3781252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: Failed to load dynamic EAP " 3782252726Srpaulo "method '%s'.", line, so); 3783252726Srpaulo return -1; 3784252726Srpaulo } 3785252726Srpaulo 3786252726Srpaulo return 0; 3787252726Srpaulo} 3788252726Srpaulo 3789252726Srpaulo 3790252726Srpaulo#ifdef CONFIG_WPS 3791252726Srpaulo 3792252726Srpaulostatic int wpa_config_process_uuid(const struct global_parse_data *data, 3793252726Srpaulo struct wpa_config *config, int line, 3794252726Srpaulo const char *pos) 3795252726Srpaulo{ 3796252726Srpaulo char buf[40]; 3797252726Srpaulo if (uuid_str2bin(pos, config->uuid)) { 3798252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid UUID", line); 3799252726Srpaulo return -1; 3800252726Srpaulo } 3801252726Srpaulo uuid_bin2str(config->uuid, buf, sizeof(buf)); 3802252726Srpaulo wpa_printf(MSG_DEBUG, "uuid=%s", buf); 3803252726Srpaulo return 0; 3804252726Srpaulo} 3805252726Srpaulo 3806252726Srpaulo 3807252726Srpaulostatic int wpa_config_process_device_type( 3808252726Srpaulo const struct global_parse_data *data, 3809252726Srpaulo struct wpa_config *config, int line, const char *pos) 3810252726Srpaulo{ 3811252726Srpaulo return wps_dev_type_str2bin(pos, config->device_type); 3812252726Srpaulo} 3813252726Srpaulo 3814252726Srpaulo 3815252726Srpaulostatic int wpa_config_process_os_version(const struct global_parse_data *data, 3816252726Srpaulo struct wpa_config *config, int line, 3817252726Srpaulo const char *pos) 3818252726Srpaulo{ 3819252726Srpaulo if (hexstr2bin(pos, config->os_version, 4)) { 3820252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid os_version", line); 3821252726Srpaulo return -1; 3822252726Srpaulo } 3823252726Srpaulo wpa_printf(MSG_DEBUG, "os_version=%08x", 3824252726Srpaulo WPA_GET_BE32(config->os_version)); 3825252726Srpaulo return 0; 3826252726Srpaulo} 3827252726Srpaulo 3828252726Srpaulo 3829252726Srpaulostatic int wpa_config_process_wps_vendor_ext_m1( 3830252726Srpaulo const struct global_parse_data *data, 3831252726Srpaulo struct wpa_config *config, int line, const char *pos) 3832252726Srpaulo{ 3833252726Srpaulo struct wpabuf *tmp; 3834252726Srpaulo int len = os_strlen(pos) / 2; 3835252726Srpaulo u8 *p; 3836252726Srpaulo 3837252726Srpaulo if (!len) { 3838252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: " 3839252726Srpaulo "invalid wps_vendor_ext_m1", line); 3840252726Srpaulo return -1; 3841252726Srpaulo } 3842252726Srpaulo 3843252726Srpaulo tmp = wpabuf_alloc(len); 3844252726Srpaulo if (tmp) { 3845252726Srpaulo p = wpabuf_put(tmp, len); 3846252726Srpaulo 3847252726Srpaulo if (hexstr2bin(pos, p, len)) { 3848252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: " 3849252726Srpaulo "invalid wps_vendor_ext_m1", line); 3850252726Srpaulo wpabuf_free(tmp); 3851252726Srpaulo return -1; 3852252726Srpaulo } 3853252726Srpaulo 3854252726Srpaulo wpabuf_free(config->wps_vendor_ext_m1); 3855252726Srpaulo config->wps_vendor_ext_m1 = tmp; 3856252726Srpaulo } else { 3857252726Srpaulo wpa_printf(MSG_ERROR, "Can not allocate " 3858252726Srpaulo "memory for wps_vendor_ext_m1"); 3859252726Srpaulo return -1; 3860252726Srpaulo } 3861252726Srpaulo 3862252726Srpaulo return 0; 3863252726Srpaulo} 3864252726Srpaulo 3865252726Srpaulo#endif /* CONFIG_WPS */ 3866252726Srpaulo 3867252726Srpaulo#ifdef CONFIG_P2P 3868252726Srpaulostatic int wpa_config_process_sec_device_type( 3869252726Srpaulo const struct global_parse_data *data, 3870252726Srpaulo struct wpa_config *config, int line, const char *pos) 3871252726Srpaulo{ 3872252726Srpaulo int idx; 3873252726Srpaulo 3874252726Srpaulo if (config->num_sec_device_types >= MAX_SEC_DEVICE_TYPES) { 3875252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: too many sec_device_type " 3876252726Srpaulo "items", line); 3877252726Srpaulo return -1; 3878252726Srpaulo } 3879252726Srpaulo 3880252726Srpaulo idx = config->num_sec_device_types; 3881252726Srpaulo 3882252726Srpaulo if (wps_dev_type_str2bin(pos, config->sec_device_type[idx])) 3883252726Srpaulo return -1; 3884252726Srpaulo 3885252726Srpaulo config->num_sec_device_types++; 3886252726Srpaulo return 0; 3887252726Srpaulo} 3888252726Srpaulo 3889252726Srpaulo 3890252726Srpaulostatic int wpa_config_process_p2p_pref_chan( 3891252726Srpaulo const struct global_parse_data *data, 3892252726Srpaulo struct wpa_config *config, int line, const char *pos) 3893252726Srpaulo{ 3894252726Srpaulo struct p2p_channel *pref = NULL, *n; 3895252726Srpaulo unsigned int num = 0; 3896252726Srpaulo const char *pos2; 3897252726Srpaulo u8 op_class, chan; 3898252726Srpaulo 3899252726Srpaulo /* format: class:chan,class:chan,... */ 3900252726Srpaulo 3901252726Srpaulo while (*pos) { 3902252726Srpaulo op_class = atoi(pos); 3903252726Srpaulo pos2 = os_strchr(pos, ':'); 3904252726Srpaulo if (pos2 == NULL) 3905252726Srpaulo goto fail; 3906252726Srpaulo pos2++; 3907252726Srpaulo chan = atoi(pos2); 3908252726Srpaulo 3909252726Srpaulo n = os_realloc_array(pref, num + 1, 3910252726Srpaulo sizeof(struct p2p_channel)); 3911252726Srpaulo if (n == NULL) 3912252726Srpaulo goto fail; 3913252726Srpaulo pref = n; 3914252726Srpaulo pref[num].op_class = op_class; 3915252726Srpaulo pref[num].chan = chan; 3916252726Srpaulo num++; 3917252726Srpaulo 3918252726Srpaulo pos = os_strchr(pos2, ','); 3919252726Srpaulo if (pos == NULL) 3920252726Srpaulo break; 3921252726Srpaulo pos++; 3922252726Srpaulo } 3923252726Srpaulo 3924252726Srpaulo os_free(config->p2p_pref_chan); 3925252726Srpaulo config->p2p_pref_chan = pref; 3926252726Srpaulo config->num_p2p_pref_chan = num; 3927252726Srpaulo wpa_hexdump(MSG_DEBUG, "P2P: Preferred class/channel pairs", 3928252726Srpaulo (u8 *) config->p2p_pref_chan, 3929252726Srpaulo config->num_p2p_pref_chan * sizeof(struct p2p_channel)); 3930252726Srpaulo 3931252726Srpaulo return 0; 3932252726Srpaulo 3933252726Srpaulofail: 3934252726Srpaulo os_free(pref); 3935252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid p2p_pref_chan list", line); 3936252726Srpaulo return -1; 3937252726Srpaulo} 3938281806Srpaulo 3939281806Srpaulo 3940281806Srpaulostatic int wpa_config_process_p2p_no_go_freq( 3941281806Srpaulo const struct global_parse_data *data, 3942281806Srpaulo struct wpa_config *config, int line, const char *pos) 3943281806Srpaulo{ 3944281806Srpaulo int ret; 3945281806Srpaulo 3946281806Srpaulo ret = freq_range_list_parse(&config->p2p_no_go_freq, pos); 3947281806Srpaulo if (ret < 0) { 3948281806Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid p2p_no_go_freq", line); 3949281806Srpaulo return -1; 3950281806Srpaulo } 3951281806Srpaulo 3952281806Srpaulo wpa_printf(MSG_DEBUG, "P2P: p2p_no_go_freq with %u items", 3953281806Srpaulo config->p2p_no_go_freq.num); 3954281806Srpaulo 3955281806Srpaulo return 0; 3956281806Srpaulo} 3957281806Srpaulo 3958252726Srpaulo#endif /* CONFIG_P2P */ 3959252726Srpaulo 3960252726Srpaulo 3961252726Srpaulostatic int wpa_config_process_hessid( 3962252726Srpaulo const struct global_parse_data *data, 3963252726Srpaulo struct wpa_config *config, int line, const char *pos) 3964252726Srpaulo{ 3965252726Srpaulo if (hwaddr_aton2(pos, config->hessid) < 0) { 3966252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid hessid '%s'", 3967252726Srpaulo line, pos); 3968252726Srpaulo return -1; 3969252726Srpaulo } 3970252726Srpaulo 3971252726Srpaulo return 0; 3972252726Srpaulo} 3973252726Srpaulo 3974252726Srpaulo 3975281806Srpaulostatic int wpa_config_process_sae_groups( 3976281806Srpaulo const struct global_parse_data *data, 3977281806Srpaulo struct wpa_config *config, int line, const char *pos) 3978281806Srpaulo{ 3979281806Srpaulo int *groups = wpa_config_parse_int_array(pos); 3980281806Srpaulo if (groups == NULL) { 3981281806Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid sae_groups '%s'", 3982281806Srpaulo line, pos); 3983281806Srpaulo return -1; 3984281806Srpaulo } 3985281806Srpaulo 3986281806Srpaulo os_free(config->sae_groups); 3987281806Srpaulo config->sae_groups = groups; 3988281806Srpaulo 3989281806Srpaulo return 0; 3990281806Srpaulo} 3991281806Srpaulo 3992281806Srpaulo 3993281806Srpaulostatic int wpa_config_process_ap_vendor_elements( 3994281806Srpaulo const struct global_parse_data *data, 3995281806Srpaulo struct wpa_config *config, int line, const char *pos) 3996281806Srpaulo{ 3997281806Srpaulo struct wpabuf *tmp; 3998281806Srpaulo int len = os_strlen(pos) / 2; 3999281806Srpaulo u8 *p; 4000281806Srpaulo 4001281806Srpaulo if (!len) { 4002281806Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid ap_vendor_elements", 4003281806Srpaulo line); 4004281806Srpaulo return -1; 4005281806Srpaulo } 4006281806Srpaulo 4007281806Srpaulo tmp = wpabuf_alloc(len); 4008281806Srpaulo if (tmp) { 4009281806Srpaulo p = wpabuf_put(tmp, len); 4010281806Srpaulo 4011281806Srpaulo if (hexstr2bin(pos, p, len)) { 4012281806Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid " 4013281806Srpaulo "ap_vendor_elements", line); 4014281806Srpaulo wpabuf_free(tmp); 4015281806Srpaulo return -1; 4016281806Srpaulo } 4017281806Srpaulo 4018281806Srpaulo wpabuf_free(config->ap_vendor_elements); 4019281806Srpaulo config->ap_vendor_elements = tmp; 4020281806Srpaulo } else { 4021281806Srpaulo wpa_printf(MSG_ERROR, "Cannot allocate memory for " 4022281806Srpaulo "ap_vendor_elements"); 4023281806Srpaulo return -1; 4024281806Srpaulo } 4025281806Srpaulo 4026281806Srpaulo return 0; 4027281806Srpaulo} 4028281806Srpaulo 4029281806Srpaulo 4030281806Srpaulo#ifdef CONFIG_CTRL_IFACE 4031281806Srpaulostatic int wpa_config_process_no_ctrl_interface( 4032281806Srpaulo const struct global_parse_data *data, 4033281806Srpaulo struct wpa_config *config, int line, const char *pos) 4034281806Srpaulo{ 4035281806Srpaulo wpa_printf(MSG_DEBUG, "no_ctrl_interface -> ctrl_interface=NULL"); 4036281806Srpaulo os_free(config->ctrl_interface); 4037281806Srpaulo config->ctrl_interface = NULL; 4038281806Srpaulo return 0; 4039281806Srpaulo} 4040281806Srpaulo#endif /* CONFIG_CTRL_IFACE */ 4041281806Srpaulo 4042281806Srpaulo 4043281806Srpaulostatic int wpa_config_get_int(const char *name, struct wpa_config *config, 4044281806Srpaulo long offset, char *buf, size_t buflen, 4045281806Srpaulo int pretty_print) 4046281806Srpaulo{ 4047281806Srpaulo int *val = (int *) (((u8 *) config) + (long) offset); 4048281806Srpaulo 4049281806Srpaulo if (pretty_print) 4050281806Srpaulo return os_snprintf(buf, buflen, "%s=%d\n", name, *val); 4051281806Srpaulo return os_snprintf(buf, buflen, "%d", *val); 4052281806Srpaulo} 4053281806Srpaulo 4054281806Srpaulo 4055281806Srpaulostatic int wpa_config_get_str(const char *name, struct wpa_config *config, 4056281806Srpaulo long offset, char *buf, size_t buflen, 4057281806Srpaulo int pretty_print) 4058281806Srpaulo{ 4059281806Srpaulo char **val = (char **) (((u8 *) config) + (long) offset); 4060281806Srpaulo int res; 4061281806Srpaulo 4062281806Srpaulo if (pretty_print) 4063281806Srpaulo res = os_snprintf(buf, buflen, "%s=%s\n", name, 4064281806Srpaulo *val ? *val : "null"); 4065281806Srpaulo else if (!*val) 4066281806Srpaulo return -1; 4067281806Srpaulo else 4068281806Srpaulo res = os_snprintf(buf, buflen, "%s", *val); 4069281806Srpaulo if (os_snprintf_error(buflen, res)) 4070281806Srpaulo res = -1; 4071281806Srpaulo 4072281806Srpaulo return res; 4073281806Srpaulo} 4074281806Srpaulo 4075281806Srpaulo 4076289549Srpaulo#ifdef CONFIG_P2P 4077289549Srpaulostatic int wpa_config_get_ipv4(const char *name, struct wpa_config *config, 4078289549Srpaulo long offset, char *buf, size_t buflen, 4079289549Srpaulo int pretty_print) 4080289549Srpaulo{ 4081289549Srpaulo void *val = ((u8 *) config) + (long) offset; 4082289549Srpaulo int res; 4083289549Srpaulo char addr[INET_ADDRSTRLEN]; 4084289549Srpaulo 4085289549Srpaulo if (!val || !inet_ntop(AF_INET, val, addr, sizeof(addr))) 4086289549Srpaulo return -1; 4087289549Srpaulo 4088289549Srpaulo if (pretty_print) 4089289549Srpaulo res = os_snprintf(buf, buflen, "%s=%s\n", name, addr); 4090289549Srpaulo else 4091289549Srpaulo res = os_snprintf(buf, buflen, "%s", addr); 4092289549Srpaulo 4093289549Srpaulo if (os_snprintf_error(buflen, res)) 4094289549Srpaulo res = -1; 4095289549Srpaulo 4096289549Srpaulo return res; 4097289549Srpaulo} 4098289549Srpaulo#endif /* CONFIG_P2P */ 4099289549Srpaulo 4100289549Srpaulo 4101252726Srpaulo#ifdef OFFSET 4102252726Srpaulo#undef OFFSET 4103252726Srpaulo#endif /* OFFSET */ 4104252726Srpaulo/* OFFSET: Get offset of a variable within the wpa_config structure */ 4105252726Srpaulo#define OFFSET(v) ((void *) &((struct wpa_config *) 0)->v) 4106252726Srpaulo 4107281806Srpaulo#define FUNC(f) #f, wpa_config_process_ ## f, NULL, OFFSET(f), NULL, NULL 4108281806Srpaulo#define FUNC_NO_VAR(f) #f, wpa_config_process_ ## f, NULL, NULL, NULL, NULL 4109281806Srpaulo#define _INT(f) #f, wpa_global_config_parse_int, wpa_config_get_int, OFFSET(f) 4110252726Srpaulo#define INT(f) _INT(f), NULL, NULL 4111252726Srpaulo#define INT_RANGE(f, min, max) _INT(f), (void *) min, (void *) max 4112281806Srpaulo#define _STR(f) #f, wpa_global_config_parse_str, wpa_config_get_str, OFFSET(f) 4113252726Srpaulo#define STR(f) _STR(f), NULL, NULL 4114252726Srpaulo#define STR_RANGE(f, min, max) _STR(f), (void *) min, (void *) max 4115281806Srpaulo#define BIN(f) #f, wpa_global_config_parse_bin, NULL, OFFSET(f), NULL, NULL 4116289549Srpaulo#define IPV4(f) #f, wpa_global_config_parse_ipv4, wpa_config_get_ipv4, \ 4117289549Srpaulo OFFSET(f), NULL, NULL 4118252726Srpaulo 4119252726Srpaulostatic const struct global_parse_data global_fields[] = { 4120252726Srpaulo#ifdef CONFIG_CTRL_IFACE 4121252726Srpaulo { STR(ctrl_interface), 0 }, 4122281806Srpaulo { FUNC_NO_VAR(no_ctrl_interface), 0 }, 4123252726Srpaulo { STR(ctrl_interface_group), 0 } /* deprecated */, 4124252726Srpaulo#endif /* CONFIG_CTRL_IFACE */ 4125281806Srpaulo#ifdef CONFIG_MACSEC 4126281806Srpaulo { INT_RANGE(eapol_version, 1, 3), 0 }, 4127281806Srpaulo#else /* CONFIG_MACSEC */ 4128252726Srpaulo { INT_RANGE(eapol_version, 1, 2), 0 }, 4129281806Srpaulo#endif /* CONFIG_MACSEC */ 4130252726Srpaulo { INT(ap_scan), 0 }, 4131281806Srpaulo { FUNC(bgscan), 0 }, 4132281806Srpaulo#ifdef CONFIG_MESH 4133281806Srpaulo { INT(user_mpm), 0 }, 4134281806Srpaulo { INT_RANGE(max_peer_links, 0, 255), 0 }, 4135281806Srpaulo { INT(mesh_max_inactivity), 0 }, 4136289549Srpaulo { INT(dot11RSNASAERetransPeriod), 0 }, 4137281806Srpaulo#endif /* CONFIG_MESH */ 4138252726Srpaulo { INT(disable_scan_offload), 0 }, 4139252726Srpaulo { INT(fast_reauth), 0 }, 4140252726Srpaulo { STR(opensc_engine_path), 0 }, 4141252726Srpaulo { STR(pkcs11_engine_path), 0 }, 4142252726Srpaulo { STR(pkcs11_module_path), 0 }, 4143281806Srpaulo { STR(openssl_ciphers), 0 }, 4144252726Srpaulo { STR(pcsc_reader), 0 }, 4145252726Srpaulo { STR(pcsc_pin), 0 }, 4146281806Srpaulo { INT(external_sim), 0 }, 4147252726Srpaulo { STR(driver_param), 0 }, 4148252726Srpaulo { INT(dot11RSNAConfigPMKLifetime), 0 }, 4149252726Srpaulo { INT(dot11RSNAConfigPMKReauthThreshold), 0 }, 4150252726Srpaulo { INT(dot11RSNAConfigSATimeout), 0 }, 4151252726Srpaulo#ifndef CONFIG_NO_CONFIG_WRITE 4152252726Srpaulo { INT(update_config), 0 }, 4153252726Srpaulo#endif /* CONFIG_NO_CONFIG_WRITE */ 4154252726Srpaulo { FUNC_NO_VAR(load_dynamic_eap), 0 }, 4155252726Srpaulo#ifdef CONFIG_WPS 4156252726Srpaulo { FUNC(uuid), CFG_CHANGED_UUID }, 4157289549Srpaulo { STR_RANGE(device_name, 0, WPS_DEV_NAME_MAX_LEN), 4158289549Srpaulo CFG_CHANGED_DEVICE_NAME }, 4159252726Srpaulo { STR_RANGE(manufacturer, 0, 64), CFG_CHANGED_WPS_STRING }, 4160252726Srpaulo { STR_RANGE(model_name, 0, 32), CFG_CHANGED_WPS_STRING }, 4161252726Srpaulo { STR_RANGE(model_number, 0, 32), CFG_CHANGED_WPS_STRING }, 4162252726Srpaulo { STR_RANGE(serial_number, 0, 32), CFG_CHANGED_WPS_STRING }, 4163252726Srpaulo { FUNC(device_type), CFG_CHANGED_DEVICE_TYPE }, 4164252726Srpaulo { FUNC(os_version), CFG_CHANGED_OS_VERSION }, 4165252726Srpaulo { STR(config_methods), CFG_CHANGED_CONFIG_METHODS }, 4166252726Srpaulo { INT_RANGE(wps_cred_processing, 0, 2), 0 }, 4167252726Srpaulo { FUNC(wps_vendor_ext_m1), CFG_CHANGED_VENDOR_EXTENSION }, 4168252726Srpaulo#endif /* CONFIG_WPS */ 4169252726Srpaulo#ifdef CONFIG_P2P 4170252726Srpaulo { FUNC(sec_device_type), CFG_CHANGED_SEC_DEVICE_TYPE }, 4171289549Srpaulo { INT(p2p_listen_reg_class), CFG_CHANGED_P2P_LISTEN_CHANNEL }, 4172289549Srpaulo { INT(p2p_listen_channel), CFG_CHANGED_P2P_LISTEN_CHANNEL }, 4173281806Srpaulo { INT(p2p_oper_reg_class), CFG_CHANGED_P2P_OPER_CHANNEL }, 4174281806Srpaulo { INT(p2p_oper_channel), CFG_CHANGED_P2P_OPER_CHANNEL }, 4175252726Srpaulo { INT_RANGE(p2p_go_intent, 0, 15), 0 }, 4176252726Srpaulo { STR(p2p_ssid_postfix), CFG_CHANGED_P2P_SSID_POSTFIX }, 4177252726Srpaulo { INT_RANGE(persistent_reconnect, 0, 1), 0 }, 4178252726Srpaulo { INT_RANGE(p2p_intra_bss, 0, 1), CFG_CHANGED_P2P_INTRA_BSS }, 4179252726Srpaulo { INT(p2p_group_idle), 0 }, 4180289549Srpaulo { INT_RANGE(p2p_go_freq_change_policy, 0, P2P_GO_FREQ_MOVE_MAX), 0 }, 4181281806Srpaulo { INT_RANGE(p2p_passphrase_len, 8, 63), 4182281806Srpaulo CFG_CHANGED_P2P_PASSPHRASE_LEN }, 4183252726Srpaulo { FUNC(p2p_pref_chan), CFG_CHANGED_P2P_PREF_CHAN }, 4184281806Srpaulo { FUNC(p2p_no_go_freq), CFG_CHANGED_P2P_PREF_CHAN }, 4185281806Srpaulo { INT_RANGE(p2p_add_cli_chan, 0, 1), 0 }, 4186281806Srpaulo { INT_RANGE(p2p_optimize_listen_chan, 0, 1), 0 }, 4187252726Srpaulo { INT(p2p_go_ht40), 0 }, 4188281806Srpaulo { INT(p2p_go_vht), 0 }, 4189252726Srpaulo { INT(p2p_disabled), 0 }, 4190281806Srpaulo { INT_RANGE(p2p_go_ctwindow, 0, 127), 0 }, 4191252726Srpaulo { INT(p2p_no_group_iface), 0 }, 4192281806Srpaulo { INT_RANGE(p2p_ignore_shared_freq, 0, 1), 0 }, 4193281806Srpaulo { IPV4(ip_addr_go), 0 }, 4194281806Srpaulo { IPV4(ip_addr_mask), 0 }, 4195281806Srpaulo { IPV4(ip_addr_start), 0 }, 4196281806Srpaulo { IPV4(ip_addr_end), 0 }, 4197289549Srpaulo { INT_RANGE(p2p_cli_probe, 0, 1), 0 }, 4198252726Srpaulo#endif /* CONFIG_P2P */ 4199252726Srpaulo { FUNC(country), CFG_CHANGED_COUNTRY }, 4200252726Srpaulo { INT(bss_max_count), 0 }, 4201252726Srpaulo { INT(bss_expiration_age), 0 }, 4202252726Srpaulo { INT(bss_expiration_scan_count), 0 }, 4203252726Srpaulo { INT_RANGE(filter_ssids, 0, 1), 0 }, 4204252726Srpaulo { INT_RANGE(filter_rssi, -100, 0), 0 }, 4205252726Srpaulo { INT(max_num_sta), 0 }, 4206252726Srpaulo { INT_RANGE(disassoc_low_ack, 0, 1), 0 }, 4207252726Srpaulo#ifdef CONFIG_HS20 4208252726Srpaulo { INT_RANGE(hs20, 0, 1), 0 }, 4209252726Srpaulo#endif /* CONFIG_HS20 */ 4210252726Srpaulo { INT_RANGE(interworking, 0, 1), 0 }, 4211252726Srpaulo { FUNC(hessid), 0 }, 4212252726Srpaulo { INT_RANGE(access_network_type, 0, 15), 0 }, 4213252726Srpaulo { INT_RANGE(pbc_in_m1, 0, 1), 0 }, 4214252726Srpaulo { STR(autoscan), 0 }, 4215281806Srpaulo { INT_RANGE(wps_nfc_dev_pw_id, 0x10, 0xffff), 4216281806Srpaulo CFG_CHANGED_NFC_PASSWORD_TOKEN }, 4217281806Srpaulo { BIN(wps_nfc_dh_pubkey), CFG_CHANGED_NFC_PASSWORD_TOKEN }, 4218281806Srpaulo { BIN(wps_nfc_dh_privkey), CFG_CHANGED_NFC_PASSWORD_TOKEN }, 4219281806Srpaulo { BIN(wps_nfc_dev_pw), CFG_CHANGED_NFC_PASSWORD_TOKEN }, 4220252726Srpaulo { STR(ext_password_backend), CFG_CHANGED_EXT_PW_BACKEND }, 4221252726Srpaulo { INT(p2p_go_max_inactivity), 0 }, 4222252726Srpaulo { INT_RANGE(auto_interworking, 0, 1), 0 }, 4223252726Srpaulo { INT(okc), 0 }, 4224252726Srpaulo { INT(pmf), 0 }, 4225281806Srpaulo { FUNC(sae_groups), 0 }, 4226281806Srpaulo { INT(dtim_period), 0 }, 4227281806Srpaulo { INT(beacon_int), 0 }, 4228281806Srpaulo { FUNC(ap_vendor_elements), 0 }, 4229281806Srpaulo { INT_RANGE(ignore_old_scan_res, 0, 1), 0 }, 4230281806Srpaulo { FUNC(freq_list), 0 }, 4231281806Srpaulo { INT(scan_cur_freq), 0 }, 4232281806Srpaulo { INT(sched_scan_interval), 0 }, 4233281806Srpaulo { INT(tdls_external_control), 0}, 4234281806Srpaulo { STR(osu_dir), 0 }, 4235281806Srpaulo { STR(wowlan_triggers), 0 }, 4236281806Srpaulo { INT(p2p_search_delay), 0}, 4237281806Srpaulo { INT(mac_addr), 0 }, 4238281806Srpaulo { INT(rand_addr_lifetime), 0 }, 4239281806Srpaulo { INT(preassoc_mac_addr), 0 }, 4240281806Srpaulo { INT(key_mgmt_offload), 0}, 4241281806Srpaulo { INT(passive_scan), 0 }, 4242281806Srpaulo { INT(reassoc_same_bss_optim), 0 }, 4243289549Srpaulo { INT(wps_priority), 0}, 4244289549Srpaulo#ifdef CONFIG_FST 4245289549Srpaulo { STR_RANGE(fst_group_id, 1, FST_MAX_GROUP_ID_LEN), 0 }, 4246289549Srpaulo { INT_RANGE(fst_priority, 1, FST_MAX_PRIO_VALUE), 0 }, 4247289549Srpaulo { INT_RANGE(fst_llt, 1, FST_MAX_LLT_MS), 0 }, 4248289549Srpaulo#endif /* CONFIG_FST */ 4249252726Srpaulo}; 4250252726Srpaulo 4251252726Srpaulo#undef FUNC 4252252726Srpaulo#undef _INT 4253252726Srpaulo#undef INT 4254252726Srpaulo#undef INT_RANGE 4255252726Srpaulo#undef _STR 4256252726Srpaulo#undef STR 4257252726Srpaulo#undef STR_RANGE 4258252726Srpaulo#undef BIN 4259281806Srpaulo#undef IPV4 4260281806Srpaulo#define NUM_GLOBAL_FIELDS ARRAY_SIZE(global_fields) 4261252726Srpaulo 4262252726Srpaulo 4263281806Srpauloint wpa_config_dump_values(struct wpa_config *config, char *buf, size_t buflen) 4264281806Srpaulo{ 4265281806Srpaulo int result = 0; 4266281806Srpaulo size_t i; 4267281806Srpaulo 4268281806Srpaulo for (i = 0; i < NUM_GLOBAL_FIELDS; i++) { 4269281806Srpaulo const struct global_parse_data *field = &global_fields[i]; 4270281806Srpaulo int tmp; 4271281806Srpaulo 4272281806Srpaulo if (!field->get) 4273281806Srpaulo continue; 4274281806Srpaulo 4275281806Srpaulo tmp = field->get(field->name, config, (long) field->param1, 4276281806Srpaulo buf, buflen, 1); 4277281806Srpaulo if (tmp < 0) 4278281806Srpaulo return -1; 4279281806Srpaulo buf += tmp; 4280281806Srpaulo buflen -= tmp; 4281281806Srpaulo result += tmp; 4282281806Srpaulo } 4283281806Srpaulo return result; 4284281806Srpaulo} 4285281806Srpaulo 4286281806Srpaulo 4287281806Srpauloint wpa_config_get_value(const char *name, struct wpa_config *config, 4288281806Srpaulo char *buf, size_t buflen) 4289281806Srpaulo{ 4290281806Srpaulo size_t i; 4291281806Srpaulo 4292281806Srpaulo for (i = 0; i < NUM_GLOBAL_FIELDS; i++) { 4293281806Srpaulo const struct global_parse_data *field = &global_fields[i]; 4294281806Srpaulo 4295281806Srpaulo if (os_strcmp(name, field->name) != 0) 4296281806Srpaulo continue; 4297281806Srpaulo if (!field->get) 4298281806Srpaulo break; 4299281806Srpaulo return field->get(name, config, (long) field->param1, 4300281806Srpaulo buf, buflen, 0); 4301281806Srpaulo } 4302281806Srpaulo 4303281806Srpaulo return -1; 4304281806Srpaulo} 4305281806Srpaulo 4306281806Srpaulo 4307252726Srpauloint wpa_config_process_global(struct wpa_config *config, char *pos, int line) 4308252726Srpaulo{ 4309252726Srpaulo size_t i; 4310252726Srpaulo int ret = 0; 4311252726Srpaulo 4312252726Srpaulo for (i = 0; i < NUM_GLOBAL_FIELDS; i++) { 4313252726Srpaulo const struct global_parse_data *field = &global_fields[i]; 4314252726Srpaulo size_t flen = os_strlen(field->name); 4315252726Srpaulo if (os_strncmp(pos, field->name, flen) != 0 || 4316252726Srpaulo pos[flen] != '=') 4317252726Srpaulo continue; 4318252726Srpaulo 4319252726Srpaulo if (field->parser(field, config, line, pos + flen + 1)) { 4320252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: failed to " 4321252726Srpaulo "parse '%s'.", line, pos); 4322252726Srpaulo ret = -1; 4323252726Srpaulo } 4324281806Srpaulo if (field->changed_flag == CFG_CHANGED_NFC_PASSWORD_TOKEN) 4325281806Srpaulo config->wps_nfc_pw_from_config = 1; 4326252726Srpaulo config->changed_parameters |= field->changed_flag; 4327252726Srpaulo break; 4328252726Srpaulo } 4329252726Srpaulo if (i == NUM_GLOBAL_FIELDS) { 4330252726Srpaulo#ifdef CONFIG_AP 4331252726Srpaulo if (os_strncmp(pos, "wmm_ac_", 7) == 0) { 4332252726Srpaulo char *tmp = os_strchr(pos, '='); 4333252726Srpaulo if (tmp == NULL) { 4334252726Srpaulo if (line < 0) 4335252726Srpaulo return -1; 4336252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid line " 4337252726Srpaulo "'%s'", line, pos); 4338252726Srpaulo return -1; 4339252726Srpaulo } 4340252726Srpaulo *tmp++ = '\0'; 4341252726Srpaulo if (hostapd_config_wmm_ac(config->wmm_ac_params, pos, 4342252726Srpaulo tmp)) { 4343252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid WMM " 4344252726Srpaulo "AC item", line); 4345252726Srpaulo return -1; 4346252726Srpaulo } 4347252726Srpaulo } 4348252726Srpaulo#endif /* CONFIG_AP */ 4349252726Srpaulo if (line < 0) 4350252726Srpaulo return -1; 4351252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: unknown global field '%s'.", 4352252726Srpaulo line, pos); 4353252726Srpaulo ret = -1; 4354252726Srpaulo } 4355252726Srpaulo 4356252726Srpaulo return ret; 4357252726Srpaulo} 4358