1189251Ssam/* 2189251Ssam * WPA Supplicant / Configuration backend: text file 3252726Srpaulo * Copyright (c) 2003-2012, 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 * This file implements a configuration backend for text files. All the 9189251Ssam * configuration information is stored in a text file that uses a format 10189251Ssam * described in the sample configuration file, wpa_supplicant.conf. 11189251Ssam */ 12189251Ssam 13189251Ssam#include "includes.h" 14281806Srpaulo#ifdef ANDROID 15281806Srpaulo#include <sys/stat.h> 16281806Srpaulo#endif /* ANDROID */ 17189251Ssam 18189251Ssam#include "common.h" 19189251Ssam#include "config.h" 20189251Ssam#include "base64.h" 21189251Ssam#include "uuid.h" 22346981Scy#include "common/ieee802_1x_defs.h" 23252726Srpaulo#include "p2p/p2p.h" 24189251Ssam#include "eap_peer/eap_methods.h" 25252726Srpaulo#include "eap_peer/eap.h" 26189251Ssam 27189251Ssam 28252726Srpaulostatic int newline_terminated(const char *buf, size_t buflen) 29252726Srpaulo{ 30252726Srpaulo size_t len = os_strlen(buf); 31252726Srpaulo if (len == 0) 32252726Srpaulo return 0; 33252726Srpaulo if (len == buflen - 1 && buf[buflen - 1] != '\r' && 34252726Srpaulo buf[len - 1] != '\n') 35252726Srpaulo return 0; 36252726Srpaulo return 1; 37252726Srpaulo} 38252726Srpaulo 39252726Srpaulo 40252726Srpaulostatic void skip_line_end(FILE *stream) 41252726Srpaulo{ 42252726Srpaulo char buf[100]; 43252726Srpaulo while (fgets(buf, sizeof(buf), stream)) { 44252726Srpaulo buf[sizeof(buf) - 1] = '\0'; 45252726Srpaulo if (newline_terminated(buf, sizeof(buf))) 46252726Srpaulo return; 47252726Srpaulo } 48252726Srpaulo} 49252726Srpaulo 50252726Srpaulo 51189251Ssam/** 52189251Ssam * wpa_config_get_line - Read the next configuration file line 53189251Ssam * @s: Buffer for the line 54189251Ssam * @size: The buffer length 55189251Ssam * @stream: File stream to read from 56189251Ssam * @line: Pointer to a variable storing the file line number 57189251Ssam * @_pos: Buffer for the pointer to the beginning of data on the text line or 58189251Ssam * %NULL if not needed (returned value used instead) 59189251Ssam * Returns: Pointer to the beginning of data on the text line or %NULL if no 60189251Ssam * more text lines are available. 61189251Ssam * 62189251Ssam * This function reads the next non-empty line from the configuration file and 63189251Ssam * removes comments. The returned string is guaranteed to be null-terminated. 64189251Ssam */ 65189251Ssamstatic char * wpa_config_get_line(char *s, int size, FILE *stream, int *line, 66189251Ssam char **_pos) 67189251Ssam{ 68189251Ssam char *pos, *end, *sstart; 69189251Ssam 70189251Ssam while (fgets(s, size, stream)) { 71189251Ssam (*line)++; 72189251Ssam s[size - 1] = '\0'; 73252726Srpaulo if (!newline_terminated(s, size)) { 74252726Srpaulo /* 75252726Srpaulo * The line was truncated - skip rest of it to avoid 76252726Srpaulo * confusing error messages. 77252726Srpaulo */ 78252726Srpaulo wpa_printf(MSG_INFO, "Long line in configuration file " 79252726Srpaulo "truncated"); 80252726Srpaulo skip_line_end(stream); 81252726Srpaulo } 82189251Ssam pos = s; 83189251Ssam 84189251Ssam /* Skip white space from the beginning of line. */ 85189251Ssam while (*pos == ' ' || *pos == '\t' || *pos == '\r') 86189251Ssam pos++; 87189251Ssam 88189251Ssam /* Skip comment lines and empty lines */ 89189251Ssam if (*pos == '#' || *pos == '\n' || *pos == '\0') 90189251Ssam continue; 91189251Ssam 92189251Ssam /* 93189251Ssam * Remove # comments unless they are within a double quoted 94189251Ssam * string. 95189251Ssam */ 96189251Ssam sstart = os_strchr(pos, '"'); 97189251Ssam if (sstart) 98189251Ssam sstart = os_strrchr(sstart + 1, '"'); 99189251Ssam if (!sstart) 100189251Ssam sstart = pos; 101189251Ssam end = os_strchr(sstart, '#'); 102189251Ssam if (end) 103189251Ssam *end-- = '\0'; 104189251Ssam else 105189251Ssam end = pos + os_strlen(pos) - 1; 106189251Ssam 107189251Ssam /* Remove trailing white space. */ 108189251Ssam while (end > pos && 109189251Ssam (*end == '\n' || *end == ' ' || *end == '\t' || 110189251Ssam *end == '\r')) 111189251Ssam *end-- = '\0'; 112189251Ssam 113189251Ssam if (*pos == '\0') 114189251Ssam continue; 115189251Ssam 116189251Ssam if (_pos) 117189251Ssam *_pos = pos; 118189251Ssam return pos; 119189251Ssam } 120189251Ssam 121189251Ssam if (_pos) 122189251Ssam *_pos = NULL; 123189251Ssam return NULL; 124189251Ssam} 125189251Ssam 126189251Ssam 127189251Ssamstatic int wpa_config_validate_network(struct wpa_ssid *ssid, int line) 128189251Ssam{ 129189251Ssam int errors = 0; 130189251Ssam 131189251Ssam if (ssid->passphrase) { 132189251Ssam if (ssid->psk_set) { 133189251Ssam wpa_printf(MSG_ERROR, "Line %d: both PSK and " 134189251Ssam "passphrase configured.", line); 135189251Ssam errors++; 136189251Ssam } 137189251Ssam wpa_config_update_psk(ssid); 138189251Ssam } 139189251Ssam 140346981Scy if (ssid->disabled == 2) 141346981Scy ssid->p2p_persistent_group = 1; 142346981Scy 143189251Ssam if ((ssid->group_cipher & WPA_CIPHER_CCMP) && 144346981Scy !(ssid->pairwise_cipher & (WPA_CIPHER_CCMP | WPA_CIPHER_CCMP_256 | 145346981Scy WPA_CIPHER_GCMP | WPA_CIPHER_GCMP_256 | 146346981Scy WPA_CIPHER_NONE))) { 147189251Ssam /* Group cipher cannot be stronger than the pairwise cipher. */ 148189251Ssam wpa_printf(MSG_DEBUG, "Line %d: removed CCMP from group cipher" 149189251Ssam " list since it was not allowed for pairwise " 150189251Ssam "cipher", line); 151189251Ssam ssid->group_cipher &= ~WPA_CIPHER_CCMP; 152189251Ssam } 153189251Ssam 154281806Srpaulo if (ssid->mode == WPAS_MODE_MESH && 155281806Srpaulo (ssid->key_mgmt != WPA_KEY_MGMT_NONE && 156281806Srpaulo ssid->key_mgmt != WPA_KEY_MGMT_SAE)) { 157281806Srpaulo wpa_printf(MSG_ERROR, 158281806Srpaulo "Line %d: key_mgmt for mesh network should be open or SAE", 159281806Srpaulo line); 160281806Srpaulo errors++; 161281806Srpaulo } 162281806Srpaulo 163346981Scy#ifdef CONFIG_OCV 164346981Scy if (ssid->ocv && ssid->ieee80211w == NO_MGMT_FRAME_PROTECTION) { 165346981Scy wpa_printf(MSG_ERROR, 166346981Scy "Line %d: PMF needs to be enabled whenever using OCV", 167346981Scy line); 168346981Scy errors++; 169346981Scy } 170346981Scy#endif /* CONFIG_OCV */ 171346981Scy 172189251Ssam return errors; 173189251Ssam} 174189251Ssam 175189251Ssam 176189251Ssamstatic struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id) 177189251Ssam{ 178189251Ssam struct wpa_ssid *ssid; 179189251Ssam int errors = 0, end = 0; 180252726Srpaulo char buf[2000], *pos, *pos2; 181189251Ssam 182189251Ssam wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new network block", 183189251Ssam *line); 184189251Ssam ssid = os_zalloc(sizeof(*ssid)); 185189251Ssam if (ssid == NULL) 186189251Ssam return NULL; 187281806Srpaulo dl_list_init(&ssid->psk_list); 188189251Ssam ssid->id = id; 189189251Ssam 190189251Ssam wpa_config_set_network_defaults(ssid); 191189251Ssam 192189251Ssam while (wpa_config_get_line(buf, sizeof(buf), f, line, &pos)) { 193189251Ssam if (os_strcmp(pos, "}") == 0) { 194189251Ssam end = 1; 195189251Ssam break; 196189251Ssam } 197189251Ssam 198189251Ssam pos2 = os_strchr(pos, '='); 199189251Ssam if (pos2 == NULL) { 200189251Ssam wpa_printf(MSG_ERROR, "Line %d: Invalid SSID line " 201189251Ssam "'%s'.", *line, pos); 202189251Ssam errors++; 203189251Ssam continue; 204189251Ssam } 205189251Ssam 206189251Ssam *pos2++ = '\0'; 207189251Ssam if (*pos2 == '"') { 208189251Ssam if (os_strchr(pos2 + 1, '"') == NULL) { 209189251Ssam wpa_printf(MSG_ERROR, "Line %d: invalid " 210189251Ssam "quotation '%s'.", *line, pos2); 211189251Ssam errors++; 212189251Ssam continue; 213189251Ssam } 214189251Ssam } 215189251Ssam 216189251Ssam if (wpa_config_set(ssid, pos, pos2, *line) < 0) 217189251Ssam errors++; 218189251Ssam } 219189251Ssam 220189251Ssam if (!end) { 221189251Ssam wpa_printf(MSG_ERROR, "Line %d: network block was not " 222189251Ssam "terminated properly.", *line); 223189251Ssam errors++; 224189251Ssam } 225189251Ssam 226189251Ssam errors += wpa_config_validate_network(ssid, *line); 227189251Ssam 228189251Ssam if (errors) { 229189251Ssam wpa_config_free_ssid(ssid); 230189251Ssam ssid = NULL; 231189251Ssam } 232189251Ssam 233189251Ssam return ssid; 234189251Ssam} 235189251Ssam 236189251Ssam 237252726Srpaulostatic struct wpa_cred * wpa_config_read_cred(FILE *f, int *line, int id) 238252726Srpaulo{ 239252726Srpaulo struct wpa_cred *cred; 240252726Srpaulo int errors = 0, end = 0; 241252726Srpaulo char buf[256], *pos, *pos2; 242252726Srpaulo 243252726Srpaulo wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new cred block", *line); 244252726Srpaulo cred = os_zalloc(sizeof(*cred)); 245252726Srpaulo if (cred == NULL) 246252726Srpaulo return NULL; 247252726Srpaulo cred->id = id; 248281806Srpaulo cred->sim_num = DEFAULT_USER_SELECTED_SIM; 249252726Srpaulo 250252726Srpaulo while (wpa_config_get_line(buf, sizeof(buf), f, line, &pos)) { 251252726Srpaulo if (os_strcmp(pos, "}") == 0) { 252252726Srpaulo end = 1; 253252726Srpaulo break; 254252726Srpaulo } 255252726Srpaulo 256252726Srpaulo pos2 = os_strchr(pos, '='); 257252726Srpaulo if (pos2 == NULL) { 258252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid cred line " 259252726Srpaulo "'%s'.", *line, pos); 260252726Srpaulo errors++; 261252726Srpaulo continue; 262252726Srpaulo } 263252726Srpaulo 264252726Srpaulo *pos2++ = '\0'; 265252726Srpaulo if (*pos2 == '"') { 266252726Srpaulo if (os_strchr(pos2 + 1, '"') == NULL) { 267252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid " 268252726Srpaulo "quotation '%s'.", *line, pos2); 269252726Srpaulo errors++; 270252726Srpaulo continue; 271252726Srpaulo } 272252726Srpaulo } 273252726Srpaulo 274252726Srpaulo if (wpa_config_set_cred(cred, pos, pos2, *line) < 0) 275252726Srpaulo errors++; 276252726Srpaulo } 277252726Srpaulo 278252726Srpaulo if (!end) { 279252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: cred block was not " 280252726Srpaulo "terminated properly.", *line); 281252726Srpaulo errors++; 282252726Srpaulo } 283252726Srpaulo 284252726Srpaulo if (errors) { 285252726Srpaulo wpa_config_free_cred(cred); 286252726Srpaulo cred = NULL; 287252726Srpaulo } 288252726Srpaulo 289252726Srpaulo return cred; 290252726Srpaulo} 291252726Srpaulo 292252726Srpaulo 293189251Ssam#ifndef CONFIG_NO_CONFIG_BLOBS 294189251Ssamstatic struct wpa_config_blob * wpa_config_read_blob(FILE *f, int *line, 295189251Ssam const char *name) 296189251Ssam{ 297189251Ssam struct wpa_config_blob *blob; 298189251Ssam char buf[256], *pos; 299189251Ssam unsigned char *encoded = NULL, *nencoded; 300189251Ssam int end = 0; 301189251Ssam size_t encoded_len = 0, len; 302189251Ssam 303189251Ssam wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new named blob '%s'", 304189251Ssam *line, name); 305189251Ssam 306189251Ssam while (wpa_config_get_line(buf, sizeof(buf), f, line, &pos)) { 307189251Ssam if (os_strcmp(pos, "}") == 0) { 308189251Ssam end = 1; 309189251Ssam break; 310189251Ssam } 311189251Ssam 312189251Ssam len = os_strlen(pos); 313189251Ssam nencoded = os_realloc(encoded, encoded_len + len); 314189251Ssam if (nencoded == NULL) { 315189251Ssam wpa_printf(MSG_ERROR, "Line %d: not enough memory for " 316189251Ssam "blob", *line); 317189251Ssam os_free(encoded); 318189251Ssam return NULL; 319189251Ssam } 320189251Ssam encoded = nencoded; 321189251Ssam os_memcpy(encoded + encoded_len, pos, len); 322189251Ssam encoded_len += len; 323189251Ssam } 324189251Ssam 325346981Scy if (!end || !encoded) { 326189251Ssam wpa_printf(MSG_ERROR, "Line %d: blob was not terminated " 327189251Ssam "properly", *line); 328189251Ssam os_free(encoded); 329189251Ssam return NULL; 330189251Ssam } 331189251Ssam 332189251Ssam blob = os_zalloc(sizeof(*blob)); 333189251Ssam if (blob == NULL) { 334189251Ssam os_free(encoded); 335189251Ssam return NULL; 336189251Ssam } 337189251Ssam blob->name = os_strdup(name); 338189251Ssam blob->data = base64_decode(encoded, encoded_len, &blob->len); 339189251Ssam os_free(encoded); 340189251Ssam 341189251Ssam if (blob->name == NULL || blob->data == NULL) { 342189251Ssam wpa_config_free_blob(blob); 343189251Ssam return NULL; 344189251Ssam } 345189251Ssam 346189251Ssam return blob; 347189251Ssam} 348189251Ssam 349189251Ssam 350189251Ssamstatic int wpa_config_process_blob(struct wpa_config *config, FILE *f, 351189251Ssam int *line, char *bname) 352189251Ssam{ 353189251Ssam char *name_end; 354189251Ssam struct wpa_config_blob *blob; 355189251Ssam 356189251Ssam name_end = os_strchr(bname, '='); 357189251Ssam if (name_end == NULL) { 358189251Ssam wpa_printf(MSG_ERROR, "Line %d: no blob name terminator", 359189251Ssam *line); 360189251Ssam return -1; 361189251Ssam } 362189251Ssam *name_end = '\0'; 363189251Ssam 364189251Ssam blob = wpa_config_read_blob(f, line, bname); 365189251Ssam if (blob == NULL) { 366189251Ssam wpa_printf(MSG_ERROR, "Line %d: failed to read blob %s", 367189251Ssam *line, bname); 368189251Ssam return -1; 369189251Ssam } 370189251Ssam wpa_config_set_blob(config, blob); 371189251Ssam return 0; 372189251Ssam} 373189251Ssam#endif /* CONFIG_NO_CONFIG_BLOBS */ 374189251Ssam 375189251Ssam 376281806Srpaulostruct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp) 377189251Ssam{ 378189251Ssam FILE *f; 379252726Srpaulo char buf[512], *pos; 380189251Ssam int errors = 0, line = 0; 381281806Srpaulo struct wpa_ssid *ssid, *tail, *head; 382281806Srpaulo struct wpa_cred *cred, *cred_tail, *cred_head; 383189251Ssam struct wpa_config *config; 384189251Ssam int id = 0; 385252726Srpaulo int cred_id = 0; 386189251Ssam 387281806Srpaulo if (name == NULL) 388281806Srpaulo return NULL; 389281806Srpaulo if (cfgp) 390281806Srpaulo config = cfgp; 391281806Srpaulo else 392281806Srpaulo config = wpa_config_alloc_empty(NULL, NULL); 393252726Srpaulo if (config == NULL) { 394252726Srpaulo wpa_printf(MSG_ERROR, "Failed to allocate config file " 395252726Srpaulo "structure"); 396189251Ssam return NULL; 397252726Srpaulo } 398281806Srpaulo tail = head = config->ssid; 399281806Srpaulo while (tail && tail->next) 400281806Srpaulo tail = tail->next; 401281806Srpaulo cred_tail = cred_head = config->cred; 402281806Srpaulo while (cred_tail && cred_tail->next) 403281806Srpaulo cred_tail = cred_tail->next; 404252726Srpaulo 405189251Ssam wpa_printf(MSG_DEBUG, "Reading configuration file '%s'", name); 406189251Ssam f = fopen(name, "r"); 407189251Ssam if (f == NULL) { 408252726Srpaulo wpa_printf(MSG_ERROR, "Failed to open config file '%s', " 409252726Srpaulo "error: %s", name, strerror(errno)); 410346981Scy if (config != cfgp) 411346981Scy os_free(config); 412189251Ssam return NULL; 413189251Ssam } 414189251Ssam 415189251Ssam while (wpa_config_get_line(buf, sizeof(buf), f, &line, &pos)) { 416189251Ssam if (os_strcmp(pos, "network={") == 0) { 417189251Ssam ssid = wpa_config_read_network(f, &line, id++); 418189251Ssam if (ssid == NULL) { 419189251Ssam wpa_printf(MSG_ERROR, "Line %d: failed to " 420189251Ssam "parse network block.", line); 421189251Ssam errors++; 422189251Ssam continue; 423189251Ssam } 424189251Ssam if (head == NULL) { 425189251Ssam head = tail = ssid; 426189251Ssam } else { 427189251Ssam tail->next = ssid; 428189251Ssam tail = ssid; 429189251Ssam } 430189251Ssam if (wpa_config_add_prio_network(config, ssid)) { 431189251Ssam wpa_printf(MSG_ERROR, "Line %d: failed to add " 432189251Ssam "network block to priority list.", 433189251Ssam line); 434189251Ssam errors++; 435189251Ssam continue; 436189251Ssam } 437252726Srpaulo } else if (os_strcmp(pos, "cred={") == 0) { 438252726Srpaulo cred = wpa_config_read_cred(f, &line, cred_id++); 439252726Srpaulo if (cred == NULL) { 440252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: failed to " 441252726Srpaulo "parse cred block.", line); 442252726Srpaulo errors++; 443252726Srpaulo continue; 444252726Srpaulo } 445252726Srpaulo if (cred_head == NULL) { 446252726Srpaulo cred_head = cred_tail = cred; 447252726Srpaulo } else { 448252726Srpaulo cred_tail->next = cred; 449252726Srpaulo cred_tail = cred; 450252726Srpaulo } 451189251Ssam#ifndef CONFIG_NO_CONFIG_BLOBS 452189251Ssam } else if (os_strncmp(pos, "blob-base64-", 12) == 0) { 453189251Ssam if (wpa_config_process_blob(config, f, &line, pos + 12) 454189251Ssam < 0) { 455252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: failed to " 456252726Srpaulo "process blob.", line); 457189251Ssam errors++; 458189251Ssam continue; 459189251Ssam } 460189251Ssam#endif /* CONFIG_NO_CONFIG_BLOBS */ 461189251Ssam } else if (wpa_config_process_global(config, pos, line) < 0) { 462189251Ssam wpa_printf(MSG_ERROR, "Line %d: Invalid configuration " 463189251Ssam "line '%s'.", line, pos); 464189251Ssam errors++; 465189251Ssam continue; 466189251Ssam } 467189251Ssam } 468189251Ssam 469189251Ssam fclose(f); 470189251Ssam 471189251Ssam config->ssid = head; 472189251Ssam wpa_config_debug_dump_networks(config); 473252726Srpaulo config->cred = cred_head; 474189251Ssam 475252726Srpaulo#ifndef WPA_IGNORE_CONFIG_ERRORS 476189251Ssam if (errors) { 477346981Scy if (config != cfgp) 478346981Scy wpa_config_free(config); 479189251Ssam config = NULL; 480189251Ssam head = NULL; 481189251Ssam } 482252726Srpaulo#endif /* WPA_IGNORE_CONFIG_ERRORS */ 483189251Ssam 484189251Ssam return config; 485189251Ssam} 486189251Ssam 487189251Ssam 488189251Ssam#ifndef CONFIG_NO_CONFIG_WRITE 489189251Ssam 490189251Ssamstatic void write_str(FILE *f, const char *field, struct wpa_ssid *ssid) 491189251Ssam{ 492189251Ssam char *value = wpa_config_get(ssid, field); 493189251Ssam if (value == NULL) 494189251Ssam return; 495189251Ssam fprintf(f, "\t%s=%s\n", field, value); 496346981Scy str_clear_free(value); 497189251Ssam} 498189251Ssam 499189251Ssam 500189251Ssamstatic void write_int(FILE *f, const char *field, int value, int def) 501189251Ssam{ 502189251Ssam if (value == def) 503189251Ssam return; 504189251Ssam fprintf(f, "\t%s=%d\n", field, value); 505189251Ssam} 506189251Ssam 507189251Ssam 508189251Ssamstatic void write_bssid(FILE *f, struct wpa_ssid *ssid) 509189251Ssam{ 510189251Ssam char *value = wpa_config_get(ssid, "bssid"); 511189251Ssam if (value == NULL) 512189251Ssam return; 513189251Ssam fprintf(f, "\tbssid=%s\n", value); 514189251Ssam os_free(value); 515189251Ssam} 516189251Ssam 517189251Ssam 518346981Scystatic void write_bssid_hint(FILE *f, struct wpa_ssid *ssid) 519346981Scy{ 520346981Scy char *value = wpa_config_get(ssid, "bssid_hint"); 521346981Scy 522346981Scy if (!value) 523346981Scy return; 524346981Scy fprintf(f, "\tbssid_hint=%s\n", value); 525346981Scy os_free(value); 526346981Scy} 527346981Scy 528346981Scy 529189251Ssamstatic void write_psk(FILE *f, struct wpa_ssid *ssid) 530189251Ssam{ 531289549Srpaulo char *value; 532289549Srpaulo 533289549Srpaulo if (ssid->mem_only_psk) 534289549Srpaulo return; 535289549Srpaulo 536289549Srpaulo value = wpa_config_get(ssid, "psk"); 537189251Ssam if (value == NULL) 538189251Ssam return; 539189251Ssam fprintf(f, "\tpsk=%s\n", value); 540189251Ssam os_free(value); 541189251Ssam} 542189251Ssam 543189251Ssam 544189251Ssamstatic void write_proto(FILE *f, struct wpa_ssid *ssid) 545189251Ssam{ 546189251Ssam char *value; 547189251Ssam 548189251Ssam if (ssid->proto == DEFAULT_PROTO) 549189251Ssam return; 550189251Ssam 551189251Ssam value = wpa_config_get(ssid, "proto"); 552189251Ssam if (value == NULL) 553189251Ssam return; 554189251Ssam if (value[0]) 555189251Ssam fprintf(f, "\tproto=%s\n", value); 556189251Ssam os_free(value); 557189251Ssam} 558189251Ssam 559189251Ssam 560189251Ssamstatic void write_key_mgmt(FILE *f, struct wpa_ssid *ssid) 561189251Ssam{ 562189251Ssam char *value; 563189251Ssam 564189251Ssam if (ssid->key_mgmt == DEFAULT_KEY_MGMT) 565189251Ssam return; 566189251Ssam 567189251Ssam value = wpa_config_get(ssid, "key_mgmt"); 568189251Ssam if (value == NULL) 569189251Ssam return; 570189251Ssam if (value[0]) 571189251Ssam fprintf(f, "\tkey_mgmt=%s\n", value); 572189251Ssam os_free(value); 573189251Ssam} 574189251Ssam 575189251Ssam 576189251Ssamstatic void write_pairwise(FILE *f, struct wpa_ssid *ssid) 577189251Ssam{ 578189251Ssam char *value; 579189251Ssam 580189251Ssam if (ssid->pairwise_cipher == DEFAULT_PAIRWISE) 581189251Ssam return; 582189251Ssam 583189251Ssam value = wpa_config_get(ssid, "pairwise"); 584189251Ssam if (value == NULL) 585189251Ssam return; 586189251Ssam if (value[0]) 587189251Ssam fprintf(f, "\tpairwise=%s\n", value); 588189251Ssam os_free(value); 589189251Ssam} 590189251Ssam 591189251Ssam 592189251Ssamstatic void write_group(FILE *f, struct wpa_ssid *ssid) 593189251Ssam{ 594189251Ssam char *value; 595189251Ssam 596189251Ssam if (ssid->group_cipher == DEFAULT_GROUP) 597189251Ssam return; 598189251Ssam 599189251Ssam value = wpa_config_get(ssid, "group"); 600189251Ssam if (value == NULL) 601189251Ssam return; 602189251Ssam if (value[0]) 603189251Ssam fprintf(f, "\tgroup=%s\n", value); 604189251Ssam os_free(value); 605189251Ssam} 606189251Ssam 607189251Ssam 608346981Scystatic void write_group_mgmt(FILE *f, struct wpa_ssid *ssid) 609346981Scy{ 610346981Scy char *value; 611346981Scy 612346981Scy if (!ssid->group_mgmt_cipher) 613346981Scy return; 614346981Scy 615346981Scy value = wpa_config_get(ssid, "group_mgmt"); 616346981Scy if (!value) 617346981Scy return; 618346981Scy if (value[0]) 619346981Scy fprintf(f, "\tgroup_mgmt=%s\n", value); 620346981Scy os_free(value); 621346981Scy} 622346981Scy 623346981Scy 624189251Ssamstatic void write_auth_alg(FILE *f, struct wpa_ssid *ssid) 625189251Ssam{ 626189251Ssam char *value; 627189251Ssam 628189251Ssam if (ssid->auth_alg == 0) 629189251Ssam return; 630189251Ssam 631189251Ssam value = wpa_config_get(ssid, "auth_alg"); 632189251Ssam if (value == NULL) 633189251Ssam return; 634189251Ssam if (value[0]) 635189251Ssam fprintf(f, "\tauth_alg=%s\n", value); 636189251Ssam os_free(value); 637189251Ssam} 638189251Ssam 639189251Ssam 640189251Ssam#ifdef IEEE8021X_EAPOL 641189251Ssamstatic void write_eap(FILE *f, struct wpa_ssid *ssid) 642189251Ssam{ 643189251Ssam char *value; 644189251Ssam 645189251Ssam value = wpa_config_get(ssid, "eap"); 646189251Ssam if (value == NULL) 647189251Ssam return; 648189251Ssam 649189251Ssam if (value[0]) 650189251Ssam fprintf(f, "\teap=%s\n", value); 651189251Ssam os_free(value); 652189251Ssam} 653189251Ssam#endif /* IEEE8021X_EAPOL */ 654189251Ssam 655189251Ssam 656189251Ssamstatic void write_wep_key(FILE *f, int idx, struct wpa_ssid *ssid) 657189251Ssam{ 658189251Ssam char field[20], *value; 659189251Ssam int res; 660189251Ssam 661189251Ssam res = os_snprintf(field, sizeof(field), "wep_key%d", idx); 662281806Srpaulo if (os_snprintf_error(sizeof(field), res)) 663189251Ssam return; 664189251Ssam value = wpa_config_get(ssid, field); 665189251Ssam if (value) { 666189251Ssam fprintf(f, "\t%s=%s\n", field, value); 667189251Ssam os_free(value); 668189251Ssam } 669189251Ssam} 670189251Ssam 671189251Ssam 672252726Srpaulo#ifdef CONFIG_P2P 673281806Srpaulo 674281806Srpaulostatic void write_go_p2p_dev_addr(FILE *f, struct wpa_ssid *ssid) 675281806Srpaulo{ 676281806Srpaulo char *value = wpa_config_get(ssid, "go_p2p_dev_addr"); 677281806Srpaulo if (value == NULL) 678281806Srpaulo return; 679281806Srpaulo fprintf(f, "\tgo_p2p_dev_addr=%s\n", value); 680281806Srpaulo os_free(value); 681281806Srpaulo} 682281806Srpaulo 683252726Srpaulostatic void write_p2p_client_list(FILE *f, struct wpa_ssid *ssid) 684252726Srpaulo{ 685252726Srpaulo char *value = wpa_config_get(ssid, "p2p_client_list"); 686252726Srpaulo if (value == NULL) 687252726Srpaulo return; 688252726Srpaulo fprintf(f, "\tp2p_client_list=%s\n", value); 689252726Srpaulo os_free(value); 690252726Srpaulo} 691281806Srpaulo 692281806Srpaulo 693281806Srpaulostatic void write_psk_list(FILE *f, struct wpa_ssid *ssid) 694281806Srpaulo{ 695281806Srpaulo struct psk_list_entry *psk; 696281806Srpaulo char hex[32 * 2 + 1]; 697281806Srpaulo 698281806Srpaulo dl_list_for_each(psk, &ssid->psk_list, struct psk_list_entry, list) { 699281806Srpaulo wpa_snprintf_hex(hex, sizeof(hex), psk->psk, sizeof(psk->psk)); 700281806Srpaulo fprintf(f, "\tpsk_list=%s" MACSTR "-%s\n", 701281806Srpaulo psk->p2p ? "P2P-" : "", MAC2STR(psk->addr), hex); 702281806Srpaulo } 703281806Srpaulo} 704281806Srpaulo 705252726Srpaulo#endif /* CONFIG_P2P */ 706252726Srpaulo 707252726Srpaulo 708346981Scy#ifdef CONFIG_MACSEC 709346981Scy 710346981Scystatic void write_mka_cak(FILE *f, struct wpa_ssid *ssid) 711346981Scy{ 712346981Scy char *value; 713346981Scy 714346981Scy if (!(ssid->mka_psk_set & MKA_PSK_SET_CAK)) 715346981Scy return; 716346981Scy 717346981Scy value = wpa_config_get(ssid, "mka_cak"); 718346981Scy if (!value) 719346981Scy return; 720346981Scy fprintf(f, "\tmka_cak=%s\n", value); 721346981Scy os_free(value); 722346981Scy} 723346981Scy 724346981Scy 725346981Scystatic void write_mka_ckn(FILE *f, struct wpa_ssid *ssid) 726346981Scy{ 727346981Scy char *value; 728346981Scy 729346981Scy if (!(ssid->mka_psk_set & MKA_PSK_SET_CKN)) 730346981Scy return; 731346981Scy 732346981Scy value = wpa_config_get(ssid, "mka_ckn"); 733346981Scy if (!value) 734346981Scy return; 735346981Scy fprintf(f, "\tmka_ckn=%s\n", value); 736346981Scy os_free(value); 737346981Scy} 738346981Scy 739346981Scy#endif /* CONFIG_MACSEC */ 740346981Scy 741346981Scy 742189251Ssamstatic void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) 743189251Ssam{ 744189251Ssam int i; 745189251Ssam 746189251Ssam#define STR(t) write_str(f, #t, ssid) 747189251Ssam#define INT(t) write_int(f, #t, ssid->t, 0) 748189251Ssam#define INTe(t) write_int(f, #t, ssid->eap.t, 0) 749189251Ssam#define INT_DEF(t, def) write_int(f, #t, ssid->t, def) 750189251Ssam#define INT_DEFe(t, def) write_int(f, #t, ssid->eap.t, def) 751189251Ssam 752189251Ssam STR(ssid); 753189251Ssam INT(scan_ssid); 754189251Ssam write_bssid(f, ssid); 755346981Scy write_bssid_hint(f, ssid); 756281806Srpaulo write_str(f, "bssid_blacklist", ssid); 757281806Srpaulo write_str(f, "bssid_whitelist", ssid); 758189251Ssam write_psk(f, ssid); 759289549Srpaulo INT(mem_only_psk); 760346981Scy STR(sae_password); 761346981Scy STR(sae_password_id); 762189251Ssam write_proto(f, ssid); 763189251Ssam write_key_mgmt(f, ssid); 764252726Srpaulo INT_DEF(bg_scan_period, DEFAULT_BG_SCAN_PERIOD); 765189251Ssam write_pairwise(f, ssid); 766189251Ssam write_group(f, ssid); 767346981Scy write_group_mgmt(f, ssid); 768189251Ssam write_auth_alg(f, ssid); 769252726Srpaulo STR(bgscan); 770252726Srpaulo STR(autoscan); 771281806Srpaulo STR(scan_freq); 772189251Ssam#ifdef IEEE8021X_EAPOL 773189251Ssam write_eap(f, ssid); 774189251Ssam STR(identity); 775189251Ssam STR(anonymous_identity); 776346981Scy STR(imsi_identity); 777189251Ssam STR(password); 778189251Ssam STR(ca_cert); 779189251Ssam STR(ca_path); 780189251Ssam STR(client_cert); 781189251Ssam STR(private_key); 782189251Ssam STR(private_key_passwd); 783189251Ssam STR(dh_file); 784189251Ssam STR(subject_match); 785346981Scy STR(check_cert_subject); 786189251Ssam STR(altsubject_match); 787281806Srpaulo STR(domain_suffix_match); 788281806Srpaulo STR(domain_match); 789189251Ssam STR(ca_cert2); 790189251Ssam STR(ca_path2); 791189251Ssam STR(client_cert2); 792189251Ssam STR(private_key2); 793189251Ssam STR(private_key2_passwd); 794189251Ssam STR(dh_file2); 795189251Ssam STR(subject_match2); 796346981Scy STR(check_cert_subject2); 797189251Ssam STR(altsubject_match2); 798281806Srpaulo STR(domain_suffix_match2); 799281806Srpaulo STR(domain_match2); 800189251Ssam STR(phase1); 801189251Ssam STR(phase2); 802189251Ssam STR(pcsc); 803189251Ssam STR(pin); 804189251Ssam STR(engine_id); 805189251Ssam STR(key_id); 806189251Ssam STR(cert_id); 807189251Ssam STR(ca_cert_id); 808189251Ssam STR(key2_id); 809189251Ssam STR(pin2); 810189251Ssam STR(engine2_id); 811189251Ssam STR(cert2_id); 812189251Ssam STR(ca_cert2_id); 813189251Ssam INTe(engine); 814189251Ssam INTe(engine2); 815189251Ssam INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS); 816281806Srpaulo STR(openssl_ciphers); 817281806Srpaulo INTe(erp); 818189251Ssam#endif /* IEEE8021X_EAPOL */ 819189251Ssam for (i = 0; i < 4; i++) 820189251Ssam write_wep_key(f, i, ssid); 821189251Ssam INT(wep_tx_keyidx); 822189251Ssam INT(priority); 823189251Ssam#ifdef IEEE8021X_EAPOL 824189251Ssam INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND); 825189251Ssam STR(pac_file); 826189251Ssam INT_DEFe(fragment_size, DEFAULT_FRAGMENT_SIZE); 827281806Srpaulo INTe(ocsp); 828281806Srpaulo INT_DEFe(sim_num, DEFAULT_USER_SELECTED_SIM); 829189251Ssam#endif /* IEEE8021X_EAPOL */ 830189251Ssam INT(mode); 831281806Srpaulo INT(no_auto_peer); 832252726Srpaulo INT(frequency); 833281806Srpaulo INT(fixed_freq); 834337817Scy#ifdef CONFIG_ACS 835337817Scy INT(acs); 836337817Scy#endif /* CONFIG_ACS */ 837252726Srpaulo write_int(f, "proactive_key_caching", ssid->proactive_key_caching, -1); 838189251Ssam INT(disabled); 839281806Srpaulo INT(mixed_cell); 840346981Scy INT(vht); 841346981Scy INT_DEF(ht, 1); 842346981Scy INT(ht40); 843346981Scy INT_DEF(max_oper_chwidth, DEFAULT_MAX_OPER_CHWIDTH); 844346981Scy INT(vht_center_freq1); 845346981Scy INT(vht_center_freq2); 846337817Scy INT(pbss); 847337817Scy INT(wps_disabled); 848346981Scy INT(fils_dh_group); 849189251Ssam#ifdef CONFIG_IEEE80211W 850252726Srpaulo write_int(f, "ieee80211w", ssid->ieee80211w, 851252726Srpaulo MGMT_FRAME_PROTECTION_DEFAULT); 852189251Ssam#endif /* CONFIG_IEEE80211W */ 853189251Ssam STR(id_str); 854252726Srpaulo#ifdef CONFIG_P2P 855281806Srpaulo write_go_p2p_dev_addr(f, ssid); 856252726Srpaulo write_p2p_client_list(f, ssid); 857281806Srpaulo write_psk_list(f, ssid); 858252726Srpaulo#endif /* CONFIG_P2P */ 859281806Srpaulo INT(ap_max_inactivity); 860281806Srpaulo INT(dtim_period); 861281806Srpaulo INT(beacon_int); 862281806Srpaulo#ifdef CONFIG_MACSEC 863281806Srpaulo INT(macsec_policy); 864346981Scy write_mka_cak(f, ssid); 865346981Scy write_mka_ckn(f, ssid); 866346981Scy INT(macsec_integ_only); 867346981Scy INT(macsec_replay_protect); 868346981Scy INT(macsec_replay_window); 869346981Scy INT(macsec_port); 870346981Scy INT_DEF(mka_priority, DEFAULT_PRIO_NOT_KEY_SERVER); 871281806Srpaulo#endif /* CONFIG_MACSEC */ 872281806Srpaulo#ifdef CONFIG_HS20 873281806Srpaulo INT(update_identifier); 874346981Scy STR(roaming_consortium_selection); 875281806Srpaulo#endif /* CONFIG_HS20 */ 876281806Srpaulo write_int(f, "mac_addr", ssid->mac_addr, -1); 877281806Srpaulo#ifdef CONFIG_MESH 878281806Srpaulo STR(mesh_basic_rates); 879281806Srpaulo INT_DEF(dot11MeshMaxRetries, DEFAULT_MESH_MAX_RETRIES); 880281806Srpaulo INT_DEF(dot11MeshRetryTimeout, DEFAULT_MESH_RETRY_TIMEOUT); 881281806Srpaulo INT_DEF(dot11MeshConfirmTimeout, DEFAULT_MESH_CONFIRM_TIMEOUT); 882281806Srpaulo INT_DEF(dot11MeshHoldingTimeout, DEFAULT_MESH_HOLDING_TIMEOUT); 883346981Scy INT_DEF(mesh_rssi_threshold, DEFAULT_MESH_RSSI_THRESHOLD); 884281806Srpaulo#endif /* CONFIG_MESH */ 885281806Srpaulo INT(wpa_ptk_rekey); 886337817Scy INT(group_rekey); 887281806Srpaulo INT(ignore_broadcast_ssid); 888346981Scy#ifdef CONFIG_DPP 889346981Scy STR(dpp_connector); 890346981Scy STR(dpp_netaccesskey); 891346981Scy INT(dpp_netaccesskey_expiry); 892346981Scy STR(dpp_csign); 893346981Scy#endif /* CONFIG_DPP */ 894346981Scy INT(owe_group); 895346981Scy INT(owe_only); 896346981Scy INT(multi_ap_backhaul_sta); 897351611Scy INT(ft_eap_pmksa_caching); 898281806Srpaulo#ifdef CONFIG_HT_OVERRIDES 899281806Srpaulo INT_DEF(disable_ht, DEFAULT_DISABLE_HT); 900281806Srpaulo INT_DEF(disable_ht40, DEFAULT_DISABLE_HT40); 901281806Srpaulo INT_DEF(disable_sgi, DEFAULT_DISABLE_SGI); 902281806Srpaulo INT_DEF(disable_ldpc, DEFAULT_DISABLE_LDPC); 903281806Srpaulo INT(ht40_intolerant); 904346981Scy INT_DEF(tx_stbc, DEFAULT_TX_STBC); 905346981Scy INT_DEF(rx_stbc, DEFAULT_RX_STBC); 906281806Srpaulo INT_DEF(disable_max_amsdu, DEFAULT_DISABLE_MAX_AMSDU); 907281806Srpaulo INT_DEF(ampdu_factor, DEFAULT_AMPDU_FACTOR); 908281806Srpaulo INT_DEF(ampdu_density, DEFAULT_AMPDU_DENSITY); 909281806Srpaulo STR(ht_mcs); 910281806Srpaulo#endif /* CONFIG_HT_OVERRIDES */ 911281806Srpaulo#ifdef CONFIG_VHT_OVERRIDES 912281806Srpaulo INT(disable_vht); 913281806Srpaulo INT(vht_capa); 914281806Srpaulo INT(vht_capa_mask); 915281806Srpaulo INT_DEF(vht_rx_mcs_nss_1, -1); 916281806Srpaulo INT_DEF(vht_rx_mcs_nss_2, -1); 917281806Srpaulo INT_DEF(vht_rx_mcs_nss_3, -1); 918281806Srpaulo INT_DEF(vht_rx_mcs_nss_4, -1); 919281806Srpaulo INT_DEF(vht_rx_mcs_nss_5, -1); 920281806Srpaulo INT_DEF(vht_rx_mcs_nss_6, -1); 921281806Srpaulo INT_DEF(vht_rx_mcs_nss_7, -1); 922281806Srpaulo INT_DEF(vht_rx_mcs_nss_8, -1); 923281806Srpaulo INT_DEF(vht_tx_mcs_nss_1, -1); 924281806Srpaulo INT_DEF(vht_tx_mcs_nss_2, -1); 925281806Srpaulo INT_DEF(vht_tx_mcs_nss_3, -1); 926281806Srpaulo INT_DEF(vht_tx_mcs_nss_4, -1); 927281806Srpaulo INT_DEF(vht_tx_mcs_nss_5, -1); 928281806Srpaulo INT_DEF(vht_tx_mcs_nss_6, -1); 929281806Srpaulo INT_DEF(vht_tx_mcs_nss_7, -1); 930281806Srpaulo INT_DEF(vht_tx_mcs_nss_8, -1); 931281806Srpaulo#endif /* CONFIG_VHT_OVERRIDES */ 932189251Ssam 933189251Ssam#undef STR 934189251Ssam#undef INT 935189251Ssam#undef INT_DEF 936189251Ssam} 937189251Ssam 938189251Ssam 939252726Srpaulostatic void wpa_config_write_cred(FILE *f, struct wpa_cred *cred) 940252726Srpaulo{ 941281806Srpaulo size_t i; 942281806Srpaulo 943252726Srpaulo if (cred->priority) 944252726Srpaulo fprintf(f, "\tpriority=%d\n", cred->priority); 945252726Srpaulo if (cred->pcsc) 946252726Srpaulo fprintf(f, "\tpcsc=%d\n", cred->pcsc); 947252726Srpaulo if (cred->realm) 948252726Srpaulo fprintf(f, "\trealm=\"%s\"\n", cred->realm); 949252726Srpaulo if (cred->username) 950252726Srpaulo fprintf(f, "\tusername=\"%s\"\n", cred->username); 951252726Srpaulo if (cred->password && cred->ext_password) 952252726Srpaulo fprintf(f, "\tpassword=ext:%s\n", cred->password); 953252726Srpaulo else if (cred->password) 954252726Srpaulo fprintf(f, "\tpassword=\"%s\"\n", cred->password); 955252726Srpaulo if (cred->ca_cert) 956252726Srpaulo fprintf(f, "\tca_cert=\"%s\"\n", cred->ca_cert); 957252726Srpaulo if (cred->client_cert) 958252726Srpaulo fprintf(f, "\tclient_cert=\"%s\"\n", cred->client_cert); 959252726Srpaulo if (cred->private_key) 960252726Srpaulo fprintf(f, "\tprivate_key=\"%s\"\n", cred->private_key); 961252726Srpaulo if (cred->private_key_passwd) 962252726Srpaulo fprintf(f, "\tprivate_key_passwd=\"%s\"\n", 963252726Srpaulo cred->private_key_passwd); 964252726Srpaulo if (cred->imsi) 965252726Srpaulo fprintf(f, "\timsi=\"%s\"\n", cred->imsi); 966252726Srpaulo if (cred->milenage) 967252726Srpaulo fprintf(f, "\tmilenage=\"%s\"\n", cred->milenage); 968281806Srpaulo for (i = 0; i < cred->num_domain; i++) 969281806Srpaulo fprintf(f, "\tdomain=\"%s\"\n", cred->domain[i]); 970281806Srpaulo if (cred->domain_suffix_match) 971281806Srpaulo fprintf(f, "\tdomain_suffix_match=\"%s\"\n", 972281806Srpaulo cred->domain_suffix_match); 973252726Srpaulo if (cred->roaming_consortium_len) { 974252726Srpaulo fprintf(f, "\troaming_consortium="); 975252726Srpaulo for (i = 0; i < cred->roaming_consortium_len; i++) 976252726Srpaulo fprintf(f, "%02x", cred->roaming_consortium[i]); 977252726Srpaulo fprintf(f, "\n"); 978252726Srpaulo } 979252726Srpaulo if (cred->eap_method) { 980252726Srpaulo const char *name; 981252726Srpaulo name = eap_get_name(cred->eap_method[0].vendor, 982252726Srpaulo cred->eap_method[0].method); 983281806Srpaulo if (name) 984281806Srpaulo fprintf(f, "\teap=%s\n", name); 985252726Srpaulo } 986252726Srpaulo if (cred->phase1) 987252726Srpaulo fprintf(f, "\tphase1=\"%s\"\n", cred->phase1); 988252726Srpaulo if (cred->phase2) 989252726Srpaulo fprintf(f, "\tphase2=\"%s\"\n", cred->phase2); 990252726Srpaulo if (cred->excluded_ssid) { 991281806Srpaulo size_t j; 992252726Srpaulo for (i = 0; i < cred->num_excluded_ssid; i++) { 993252726Srpaulo struct excluded_ssid *e = &cred->excluded_ssid[i]; 994252726Srpaulo fprintf(f, "\texcluded_ssid="); 995252726Srpaulo for (j = 0; j < e->ssid_len; j++) 996252726Srpaulo fprintf(f, "%02x", e->ssid[j]); 997252726Srpaulo fprintf(f, "\n"); 998252726Srpaulo } 999252726Srpaulo } 1000281806Srpaulo if (cred->roaming_partner) { 1001281806Srpaulo for (i = 0; i < cred->num_roaming_partner; i++) { 1002281806Srpaulo struct roaming_partner *p = &cred->roaming_partner[i]; 1003281806Srpaulo fprintf(f, "\troaming_partner=\"%s,%d,%u,%s\"\n", 1004281806Srpaulo p->fqdn, p->exact_match, p->priority, 1005281806Srpaulo p->country); 1006281806Srpaulo } 1007281806Srpaulo } 1008281806Srpaulo if (cred->update_identifier) 1009281806Srpaulo fprintf(f, "\tupdate_identifier=%d\n", cred->update_identifier); 1010281806Srpaulo 1011281806Srpaulo if (cred->provisioning_sp) 1012281806Srpaulo fprintf(f, "\tprovisioning_sp=\"%s\"\n", cred->provisioning_sp); 1013281806Srpaulo if (cred->sp_priority) 1014281806Srpaulo fprintf(f, "\tsp_priority=%d\n", cred->sp_priority); 1015281806Srpaulo 1016281806Srpaulo if (cred->min_dl_bandwidth_home) 1017281806Srpaulo fprintf(f, "\tmin_dl_bandwidth_home=%u\n", 1018281806Srpaulo cred->min_dl_bandwidth_home); 1019281806Srpaulo if (cred->min_ul_bandwidth_home) 1020281806Srpaulo fprintf(f, "\tmin_ul_bandwidth_home=%u\n", 1021281806Srpaulo cred->min_ul_bandwidth_home); 1022281806Srpaulo if (cred->min_dl_bandwidth_roaming) 1023281806Srpaulo fprintf(f, "\tmin_dl_bandwidth_roaming=%u\n", 1024281806Srpaulo cred->min_dl_bandwidth_roaming); 1025281806Srpaulo if (cred->min_ul_bandwidth_roaming) 1026281806Srpaulo fprintf(f, "\tmin_ul_bandwidth_roaming=%u\n", 1027281806Srpaulo cred->min_ul_bandwidth_roaming); 1028281806Srpaulo 1029281806Srpaulo if (cred->max_bss_load) 1030281806Srpaulo fprintf(f, "\tmax_bss_load=%u\n", 1031281806Srpaulo cred->max_bss_load); 1032281806Srpaulo 1033281806Srpaulo if (cred->ocsp) 1034281806Srpaulo fprintf(f, "\tocsp=%d\n", cred->ocsp); 1035281806Srpaulo 1036281806Srpaulo if (cred->num_req_conn_capab) { 1037281806Srpaulo for (i = 0; i < cred->num_req_conn_capab; i++) { 1038281806Srpaulo int *ports; 1039281806Srpaulo 1040281806Srpaulo fprintf(f, "\treq_conn_capab=%u", 1041281806Srpaulo cred->req_conn_capab_proto[i]); 1042281806Srpaulo ports = cred->req_conn_capab_port[i]; 1043281806Srpaulo if (ports) { 1044281806Srpaulo int j; 1045281806Srpaulo for (j = 0; ports[j] != -1; j++) { 1046281806Srpaulo fprintf(f, "%s%d", j > 0 ? "," : ":", 1047281806Srpaulo ports[j]); 1048281806Srpaulo } 1049281806Srpaulo } 1050281806Srpaulo fprintf(f, "\n"); 1051281806Srpaulo } 1052281806Srpaulo } 1053281806Srpaulo 1054281806Srpaulo if (cred->required_roaming_consortium_len) { 1055281806Srpaulo fprintf(f, "\trequired_roaming_consortium="); 1056281806Srpaulo for (i = 0; i < cred->required_roaming_consortium_len; i++) 1057281806Srpaulo fprintf(f, "%02x", 1058281806Srpaulo cred->required_roaming_consortium[i]); 1059281806Srpaulo fprintf(f, "\n"); 1060281806Srpaulo } 1061281806Srpaulo 1062346981Scy if (cred->num_roaming_consortiums) { 1063346981Scy size_t j; 1064346981Scy 1065346981Scy fprintf(f, "\troaming_consortiums=\""); 1066346981Scy for (i = 0; i < cred->num_roaming_consortiums; i++) { 1067346981Scy if (i > 0) 1068346981Scy fprintf(f, ","); 1069346981Scy for (j = 0; j < cred->roaming_consortiums_len[i]; j++) 1070346981Scy fprintf(f, "%02x", 1071346981Scy cred->roaming_consortiums[i][j]); 1072346981Scy } 1073346981Scy fprintf(f, "\"\n"); 1074346981Scy } 1075346981Scy 1076281806Srpaulo if (cred->sim_num != DEFAULT_USER_SELECTED_SIM) 1077281806Srpaulo fprintf(f, "\tsim_num=%d\n", cred->sim_num); 1078252726Srpaulo} 1079252726Srpaulo 1080252726Srpaulo 1081189251Ssam#ifndef CONFIG_NO_CONFIG_BLOBS 1082189251Ssamstatic int wpa_config_write_blob(FILE *f, struct wpa_config_blob *blob) 1083189251Ssam{ 1084189251Ssam unsigned char *encoded; 1085189251Ssam 1086189251Ssam encoded = base64_encode(blob->data, blob->len, NULL); 1087189251Ssam if (encoded == NULL) 1088189251Ssam return -1; 1089189251Ssam 1090189251Ssam fprintf(f, "\nblob-base64-%s={\n%s}\n", blob->name, encoded); 1091189251Ssam os_free(encoded); 1092189251Ssam return 0; 1093189251Ssam} 1094189251Ssam#endif /* CONFIG_NO_CONFIG_BLOBS */ 1095189251Ssam 1096189251Ssam 1097252726Srpaulostatic void write_global_bin(FILE *f, const char *field, 1098252726Srpaulo const struct wpabuf *val) 1099252726Srpaulo{ 1100252726Srpaulo size_t i; 1101252726Srpaulo const u8 *pos; 1102252726Srpaulo 1103252726Srpaulo if (val == NULL) 1104252726Srpaulo return; 1105252726Srpaulo 1106252726Srpaulo fprintf(f, "%s=", field); 1107252726Srpaulo pos = wpabuf_head(val); 1108252726Srpaulo for (i = 0; i < wpabuf_len(val); i++) 1109252726Srpaulo fprintf(f, "%02X", *pos++); 1110252726Srpaulo fprintf(f, "\n"); 1111252726Srpaulo} 1112252726Srpaulo 1113252726Srpaulo 1114189251Ssamstatic void wpa_config_write_global(FILE *f, struct wpa_config *config) 1115189251Ssam{ 1116189251Ssam#ifdef CONFIG_CTRL_IFACE 1117189251Ssam if (config->ctrl_interface) 1118189251Ssam fprintf(f, "ctrl_interface=%s\n", config->ctrl_interface); 1119189251Ssam if (config->ctrl_interface_group) 1120189251Ssam fprintf(f, "ctrl_interface_group=%s\n", 1121189251Ssam config->ctrl_interface_group); 1122189251Ssam#endif /* CONFIG_CTRL_IFACE */ 1123189251Ssam if (config->eapol_version != DEFAULT_EAPOL_VERSION) 1124189251Ssam fprintf(f, "eapol_version=%d\n", config->eapol_version); 1125189251Ssam if (config->ap_scan != DEFAULT_AP_SCAN) 1126189251Ssam fprintf(f, "ap_scan=%d\n", config->ap_scan); 1127252726Srpaulo if (config->disable_scan_offload) 1128252726Srpaulo fprintf(f, "disable_scan_offload=%d\n", 1129252726Srpaulo config->disable_scan_offload); 1130189251Ssam if (config->fast_reauth != DEFAULT_FAST_REAUTH) 1131189251Ssam fprintf(f, "fast_reauth=%d\n", config->fast_reauth); 1132189251Ssam if (config->opensc_engine_path) 1133189251Ssam fprintf(f, "opensc_engine_path=%s\n", 1134189251Ssam config->opensc_engine_path); 1135189251Ssam if (config->pkcs11_engine_path) 1136189251Ssam fprintf(f, "pkcs11_engine_path=%s\n", 1137189251Ssam config->pkcs11_engine_path); 1138189251Ssam if (config->pkcs11_module_path) 1139189251Ssam fprintf(f, "pkcs11_module_path=%s\n", 1140189251Ssam config->pkcs11_module_path); 1141281806Srpaulo if (config->openssl_ciphers) 1142281806Srpaulo fprintf(f, "openssl_ciphers=%s\n", config->openssl_ciphers); 1143252726Srpaulo if (config->pcsc_reader) 1144252726Srpaulo fprintf(f, "pcsc_reader=%s\n", config->pcsc_reader); 1145252726Srpaulo if (config->pcsc_pin) 1146252726Srpaulo fprintf(f, "pcsc_pin=%s\n", config->pcsc_pin); 1147189251Ssam if (config->driver_param) 1148189251Ssam fprintf(f, "driver_param=%s\n", config->driver_param); 1149189251Ssam if (config->dot11RSNAConfigPMKLifetime) 1150289549Srpaulo fprintf(f, "dot11RSNAConfigPMKLifetime=%u\n", 1151189251Ssam config->dot11RSNAConfigPMKLifetime); 1152189251Ssam if (config->dot11RSNAConfigPMKReauthThreshold) 1153289549Srpaulo fprintf(f, "dot11RSNAConfigPMKReauthThreshold=%u\n", 1154189251Ssam config->dot11RSNAConfigPMKReauthThreshold); 1155189251Ssam if (config->dot11RSNAConfigSATimeout) 1156289549Srpaulo fprintf(f, "dot11RSNAConfigSATimeout=%u\n", 1157189251Ssam config->dot11RSNAConfigSATimeout); 1158189251Ssam if (config->update_config) 1159189251Ssam fprintf(f, "update_config=%d\n", config->update_config); 1160189251Ssam#ifdef CONFIG_WPS 1161189251Ssam if (!is_nil_uuid(config->uuid)) { 1162189251Ssam char buf[40]; 1163189251Ssam uuid_bin2str(config->uuid, buf, sizeof(buf)); 1164189251Ssam fprintf(f, "uuid=%s\n", buf); 1165189251Ssam } 1166346981Scy if (config->auto_uuid) 1167346981Scy fprintf(f, "auto_uuid=%d\n", config->auto_uuid); 1168189251Ssam if (config->device_name) 1169189251Ssam fprintf(f, "device_name=%s\n", config->device_name); 1170189251Ssam if (config->manufacturer) 1171189251Ssam fprintf(f, "manufacturer=%s\n", config->manufacturer); 1172189251Ssam if (config->model_name) 1173189251Ssam fprintf(f, "model_name=%s\n", config->model_name); 1174189251Ssam if (config->model_number) 1175189251Ssam fprintf(f, "model_number=%s\n", config->model_number); 1176189251Ssam if (config->serial_number) 1177189251Ssam fprintf(f, "serial_number=%s\n", config->serial_number); 1178252726Srpaulo { 1179252726Srpaulo char _buf[WPS_DEV_TYPE_BUFSIZE], *buf; 1180252726Srpaulo buf = wps_dev_type_bin2str(config->device_type, 1181252726Srpaulo _buf, sizeof(_buf)); 1182252726Srpaulo if (os_strcmp(buf, "0-00000000-0") != 0) 1183252726Srpaulo fprintf(f, "device_type=%s\n", buf); 1184252726Srpaulo } 1185189251Ssam if (WPA_GET_BE32(config->os_version)) 1186189251Ssam fprintf(f, "os_version=%08x\n", 1187189251Ssam WPA_GET_BE32(config->os_version)); 1188214734Srpaulo if (config->config_methods) 1189214734Srpaulo fprintf(f, "config_methods=%s\n", config->config_methods); 1190189251Ssam if (config->wps_cred_processing) 1191189251Ssam fprintf(f, "wps_cred_processing=%d\n", 1192189251Ssam config->wps_cred_processing); 1193346981Scy if (config->wps_cred_add_sae) 1194346981Scy fprintf(f, "wps_cred_add_sae=%d\n", 1195346981Scy config->wps_cred_add_sae); 1196252726Srpaulo if (config->wps_vendor_ext_m1) { 1197252726Srpaulo int i, len = wpabuf_len(config->wps_vendor_ext_m1); 1198252726Srpaulo const u8 *p = wpabuf_head_u8(config->wps_vendor_ext_m1); 1199252726Srpaulo if (len > 0) { 1200252726Srpaulo fprintf(f, "wps_vendor_ext_m1="); 1201252726Srpaulo for (i = 0; i < len; i++) 1202252726Srpaulo fprintf(f, "%02x", *p++); 1203252726Srpaulo fprintf(f, "\n"); 1204252726Srpaulo } 1205252726Srpaulo } 1206189251Ssam#endif /* CONFIG_WPS */ 1207252726Srpaulo#ifdef CONFIG_P2P 1208346981Scy { 1209346981Scy int i; 1210346981Scy char _buf[WPS_DEV_TYPE_BUFSIZE], *buf; 1211346981Scy 1212346981Scy for (i = 0; i < config->num_sec_device_types; i++) { 1213346981Scy buf = wps_dev_type_bin2str(config->sec_device_type[i], 1214346981Scy _buf, sizeof(_buf)); 1215346981Scy if (buf) 1216346981Scy fprintf(f, "sec_device_type=%s\n", buf); 1217346981Scy } 1218346981Scy } 1219252726Srpaulo if (config->p2p_listen_reg_class) 1220289549Srpaulo fprintf(f, "p2p_listen_reg_class=%d\n", 1221252726Srpaulo config->p2p_listen_reg_class); 1222252726Srpaulo if (config->p2p_listen_channel) 1223289549Srpaulo fprintf(f, "p2p_listen_channel=%d\n", 1224252726Srpaulo config->p2p_listen_channel); 1225252726Srpaulo if (config->p2p_oper_reg_class) 1226289549Srpaulo fprintf(f, "p2p_oper_reg_class=%d\n", 1227252726Srpaulo config->p2p_oper_reg_class); 1228252726Srpaulo if (config->p2p_oper_channel) 1229289549Srpaulo fprintf(f, "p2p_oper_channel=%d\n", config->p2p_oper_channel); 1230252726Srpaulo if (config->p2p_go_intent != DEFAULT_P2P_GO_INTENT) 1231289549Srpaulo fprintf(f, "p2p_go_intent=%d\n", config->p2p_go_intent); 1232252726Srpaulo if (config->p2p_ssid_postfix) 1233252726Srpaulo fprintf(f, "p2p_ssid_postfix=%s\n", config->p2p_ssid_postfix); 1234252726Srpaulo if (config->persistent_reconnect) 1235289549Srpaulo fprintf(f, "persistent_reconnect=%d\n", 1236252726Srpaulo config->persistent_reconnect); 1237252726Srpaulo if (config->p2p_intra_bss != DEFAULT_P2P_INTRA_BSS) 1238289549Srpaulo fprintf(f, "p2p_intra_bss=%d\n", config->p2p_intra_bss); 1239252726Srpaulo if (config->p2p_group_idle) 1240289549Srpaulo fprintf(f, "p2p_group_idle=%d\n", config->p2p_group_idle); 1241281806Srpaulo if (config->p2p_passphrase_len) 1242281806Srpaulo fprintf(f, "p2p_passphrase_len=%u\n", 1243281806Srpaulo config->p2p_passphrase_len); 1244252726Srpaulo if (config->p2p_pref_chan) { 1245252726Srpaulo unsigned int i; 1246252726Srpaulo fprintf(f, "p2p_pref_chan="); 1247252726Srpaulo for (i = 0; i < config->num_p2p_pref_chan; i++) { 1248252726Srpaulo fprintf(f, "%s%u:%u", i > 0 ? "," : "", 1249252726Srpaulo config->p2p_pref_chan[i].op_class, 1250252726Srpaulo config->p2p_pref_chan[i].chan); 1251252726Srpaulo } 1252252726Srpaulo fprintf(f, "\n"); 1253252726Srpaulo } 1254281806Srpaulo if (config->p2p_no_go_freq.num) { 1255281806Srpaulo char *val = freq_range_list_str(&config->p2p_no_go_freq); 1256281806Srpaulo if (val) { 1257281806Srpaulo fprintf(f, "p2p_no_go_freq=%s\n", val); 1258281806Srpaulo os_free(val); 1259281806Srpaulo } 1260281806Srpaulo } 1261281806Srpaulo if (config->p2p_add_cli_chan) 1262281806Srpaulo fprintf(f, "p2p_add_cli_chan=%d\n", config->p2p_add_cli_chan); 1263281806Srpaulo if (config->p2p_optimize_listen_chan != 1264281806Srpaulo DEFAULT_P2P_OPTIMIZE_LISTEN_CHAN) 1265281806Srpaulo fprintf(f, "p2p_optimize_listen_chan=%d\n", 1266281806Srpaulo config->p2p_optimize_listen_chan); 1267252726Srpaulo if (config->p2p_go_ht40) 1268289549Srpaulo fprintf(f, "p2p_go_ht40=%d\n", config->p2p_go_ht40); 1269281806Srpaulo if (config->p2p_go_vht) 1270289549Srpaulo fprintf(f, "p2p_go_vht=%d\n", config->p2p_go_vht); 1271346981Scy if (config->p2p_go_he) 1272346981Scy fprintf(f, "p2p_go_he=%d\n", config->p2p_go_he); 1273281806Srpaulo if (config->p2p_go_ctwindow != DEFAULT_P2P_GO_CTWINDOW) 1274289549Srpaulo fprintf(f, "p2p_go_ctwindow=%d\n", config->p2p_go_ctwindow); 1275252726Srpaulo if (config->p2p_disabled) 1276289549Srpaulo fprintf(f, "p2p_disabled=%d\n", config->p2p_disabled); 1277252726Srpaulo if (config->p2p_no_group_iface) 1278289549Srpaulo fprintf(f, "p2p_no_group_iface=%d\n", 1279252726Srpaulo config->p2p_no_group_iface); 1280281806Srpaulo if (config->p2p_ignore_shared_freq) 1281289549Srpaulo fprintf(f, "p2p_ignore_shared_freq=%d\n", 1282281806Srpaulo config->p2p_ignore_shared_freq); 1283289549Srpaulo if (config->p2p_cli_probe) 1284289549Srpaulo fprintf(f, "p2p_cli_probe=%d\n", config->p2p_cli_probe); 1285289549Srpaulo if (config->p2p_go_freq_change_policy != DEFAULT_P2P_GO_FREQ_MOVE) 1286289549Srpaulo fprintf(f, "p2p_go_freq_change_policy=%u\n", 1287289549Srpaulo config->p2p_go_freq_change_policy); 1288337817Scy if (WPA_GET_BE32(config->ip_addr_go)) 1289337817Scy fprintf(f, "ip_addr_go=%u.%u.%u.%u\n", 1290337817Scy config->ip_addr_go[0], config->ip_addr_go[1], 1291337817Scy config->ip_addr_go[2], config->ip_addr_go[3]); 1292337817Scy if (WPA_GET_BE32(config->ip_addr_mask)) 1293337817Scy fprintf(f, "ip_addr_mask=%u.%u.%u.%u\n", 1294337817Scy config->ip_addr_mask[0], config->ip_addr_mask[1], 1295337817Scy config->ip_addr_mask[2], config->ip_addr_mask[3]); 1296337817Scy if (WPA_GET_BE32(config->ip_addr_start)) 1297337817Scy fprintf(f, "ip_addr_start=%u.%u.%u.%u\n", 1298337817Scy config->ip_addr_start[0], config->ip_addr_start[1], 1299337817Scy config->ip_addr_start[2], config->ip_addr_start[3]); 1300337817Scy if (WPA_GET_BE32(config->ip_addr_end)) 1301337817Scy fprintf(f, "ip_addr_end=%u.%u.%u.%u\n", 1302337817Scy config->ip_addr_end[0], config->ip_addr_end[1], 1303337817Scy config->ip_addr_end[2], config->ip_addr_end[3]); 1304252726Srpaulo#endif /* CONFIG_P2P */ 1305189251Ssam if (config->country[0] && config->country[1]) { 1306189251Ssam fprintf(f, "country=%c%c\n", 1307189251Ssam config->country[0], config->country[1]); 1308189251Ssam } 1309214734Srpaulo if (config->bss_max_count != DEFAULT_BSS_MAX_COUNT) 1310214734Srpaulo fprintf(f, "bss_max_count=%u\n", config->bss_max_count); 1311252726Srpaulo if (config->bss_expiration_age != DEFAULT_BSS_EXPIRATION_AGE) 1312252726Srpaulo fprintf(f, "bss_expiration_age=%u\n", 1313252726Srpaulo config->bss_expiration_age); 1314252726Srpaulo if (config->bss_expiration_scan_count != 1315252726Srpaulo DEFAULT_BSS_EXPIRATION_SCAN_COUNT) 1316252726Srpaulo fprintf(f, "bss_expiration_scan_count=%u\n", 1317252726Srpaulo config->bss_expiration_scan_count); 1318214734Srpaulo if (config->filter_ssids) 1319214734Srpaulo fprintf(f, "filter_ssids=%d\n", config->filter_ssids); 1320346981Scy if (config->filter_rssi) 1321346981Scy fprintf(f, "filter_rssi=%d\n", config->filter_rssi); 1322252726Srpaulo if (config->max_num_sta != DEFAULT_MAX_NUM_STA) 1323252726Srpaulo fprintf(f, "max_num_sta=%u\n", config->max_num_sta); 1324346981Scy if (config->ap_isolate != DEFAULT_AP_ISOLATE) 1325346981Scy fprintf(f, "ap_isolate=%u\n", config->ap_isolate); 1326252726Srpaulo if (config->disassoc_low_ack) 1327289549Srpaulo fprintf(f, "disassoc_low_ack=%d\n", config->disassoc_low_ack); 1328252726Srpaulo#ifdef CONFIG_HS20 1329252726Srpaulo if (config->hs20) 1330252726Srpaulo fprintf(f, "hs20=1\n"); 1331252726Srpaulo#endif /* CONFIG_HS20 */ 1332252726Srpaulo#ifdef CONFIG_INTERWORKING 1333252726Srpaulo if (config->interworking) 1334289549Srpaulo fprintf(f, "interworking=%d\n", config->interworking); 1335252726Srpaulo if (!is_zero_ether_addr(config->hessid)) 1336252726Srpaulo fprintf(f, "hessid=" MACSTR "\n", MAC2STR(config->hessid)); 1337252726Srpaulo if (config->access_network_type != DEFAULT_ACCESS_NETWORK_TYPE) 1338252726Srpaulo fprintf(f, "access_network_type=%d\n", 1339252726Srpaulo config->access_network_type); 1340346981Scy if (config->go_interworking) 1341346981Scy fprintf(f, "go_interworking=%d\n", config->go_interworking); 1342346981Scy if (config->go_access_network_type) 1343346981Scy fprintf(f, "go_access_network_type=%d\n", 1344346981Scy config->go_access_network_type); 1345346981Scy if (config->go_internet) 1346346981Scy fprintf(f, "go_internet=%d\n", config->go_internet); 1347346981Scy if (config->go_venue_group) 1348346981Scy fprintf(f, "go_venue_group=%d\n", config->go_venue_group); 1349346981Scy if (config->go_venue_type) 1350346981Scy fprintf(f, "go_venue_type=%d\n", config->go_venue_type); 1351252726Srpaulo#endif /* CONFIG_INTERWORKING */ 1352252726Srpaulo if (config->pbc_in_m1) 1353289549Srpaulo fprintf(f, "pbc_in_m1=%d\n", config->pbc_in_m1); 1354281806Srpaulo if (config->wps_nfc_pw_from_config) { 1355281806Srpaulo if (config->wps_nfc_dev_pw_id) 1356281806Srpaulo fprintf(f, "wps_nfc_dev_pw_id=%d\n", 1357281806Srpaulo config->wps_nfc_dev_pw_id); 1358281806Srpaulo write_global_bin(f, "wps_nfc_dh_pubkey", 1359281806Srpaulo config->wps_nfc_dh_pubkey); 1360281806Srpaulo write_global_bin(f, "wps_nfc_dh_privkey", 1361281806Srpaulo config->wps_nfc_dh_privkey); 1362281806Srpaulo write_global_bin(f, "wps_nfc_dev_pw", config->wps_nfc_dev_pw); 1363281806Srpaulo } 1364252726Srpaulo 1365252726Srpaulo if (config->ext_password_backend) 1366252726Srpaulo fprintf(f, "ext_password_backend=%s\n", 1367252726Srpaulo config->ext_password_backend); 1368252726Srpaulo if (config->p2p_go_max_inactivity != DEFAULT_P2P_GO_MAX_INACTIVITY) 1369252726Srpaulo fprintf(f, "p2p_go_max_inactivity=%d\n", 1370252726Srpaulo config->p2p_go_max_inactivity); 1371252726Srpaulo if (config->auto_interworking) 1372252726Srpaulo fprintf(f, "auto_interworking=%d\n", 1373252726Srpaulo config->auto_interworking); 1374252726Srpaulo if (config->okc) 1375252726Srpaulo fprintf(f, "okc=%d\n", config->okc); 1376252726Srpaulo if (config->pmf) 1377252726Srpaulo fprintf(f, "pmf=%d\n", config->pmf); 1378281806Srpaulo if (config->dtim_period) 1379281806Srpaulo fprintf(f, "dtim_period=%d\n", config->dtim_period); 1380281806Srpaulo if (config->beacon_int) 1381281806Srpaulo fprintf(f, "beacon_int=%d\n", config->beacon_int); 1382281806Srpaulo 1383281806Srpaulo if (config->sae_groups) { 1384281806Srpaulo int i; 1385281806Srpaulo fprintf(f, "sae_groups="); 1386346981Scy for (i = 0; config->sae_groups[i] > 0; i++) { 1387281806Srpaulo fprintf(f, "%s%d", i > 0 ? " " : "", 1388281806Srpaulo config->sae_groups[i]); 1389281806Srpaulo } 1390281806Srpaulo fprintf(f, "\n"); 1391281806Srpaulo } 1392281806Srpaulo 1393281806Srpaulo if (config->ap_vendor_elements) { 1394281806Srpaulo int i, len = wpabuf_len(config->ap_vendor_elements); 1395281806Srpaulo const u8 *p = wpabuf_head_u8(config->ap_vendor_elements); 1396281806Srpaulo if (len > 0) { 1397281806Srpaulo fprintf(f, "ap_vendor_elements="); 1398281806Srpaulo for (i = 0; i < len; i++) 1399281806Srpaulo fprintf(f, "%02x", *p++); 1400281806Srpaulo fprintf(f, "\n"); 1401281806Srpaulo } 1402281806Srpaulo } 1403281806Srpaulo 1404281806Srpaulo if (config->ignore_old_scan_res) 1405281806Srpaulo fprintf(f, "ignore_old_scan_res=%d\n", 1406281806Srpaulo config->ignore_old_scan_res); 1407281806Srpaulo 1408281806Srpaulo if (config->freq_list && config->freq_list[0]) { 1409281806Srpaulo int i; 1410281806Srpaulo fprintf(f, "freq_list="); 1411281806Srpaulo for (i = 0; config->freq_list[i]; i++) { 1412289549Srpaulo fprintf(f, "%s%d", i > 0 ? " " : "", 1413281806Srpaulo config->freq_list[i]); 1414281806Srpaulo } 1415281806Srpaulo fprintf(f, "\n"); 1416281806Srpaulo } 1417281806Srpaulo if (config->scan_cur_freq != DEFAULT_SCAN_CUR_FREQ) 1418281806Srpaulo fprintf(f, "scan_cur_freq=%d\n", config->scan_cur_freq); 1419281806Srpaulo 1420281806Srpaulo if (config->sched_scan_interval) 1421281806Srpaulo fprintf(f, "sched_scan_interval=%u\n", 1422281806Srpaulo config->sched_scan_interval); 1423281806Srpaulo 1424346981Scy if (config->sched_scan_start_delay) 1425346981Scy fprintf(f, "sched_scan_start_delay=%u\n", 1426346981Scy config->sched_scan_start_delay); 1427346981Scy 1428281806Srpaulo if (config->external_sim) 1429281806Srpaulo fprintf(f, "external_sim=%d\n", config->external_sim); 1430281806Srpaulo 1431281806Srpaulo if (config->tdls_external_control) 1432281806Srpaulo fprintf(f, "tdls_external_control=%d\n", 1433281806Srpaulo config->tdls_external_control); 1434281806Srpaulo 1435281806Srpaulo if (config->wowlan_triggers) 1436281806Srpaulo fprintf(f, "wowlan_triggers=%s\n", 1437281806Srpaulo config->wowlan_triggers); 1438281806Srpaulo 1439281806Srpaulo if (config->bgscan) 1440281806Srpaulo fprintf(f, "bgscan=\"%s\"\n", config->bgscan); 1441281806Srpaulo 1442346981Scy if (config->autoscan) 1443346981Scy fprintf(f, "autoscan=%s\n", config->autoscan); 1444346981Scy 1445281806Srpaulo if (config->p2p_search_delay != DEFAULT_P2P_SEARCH_DELAY) 1446281806Srpaulo fprintf(f, "p2p_search_delay=%u\n", 1447281806Srpaulo config->p2p_search_delay); 1448281806Srpaulo 1449281806Srpaulo if (config->mac_addr) 1450281806Srpaulo fprintf(f, "mac_addr=%d\n", config->mac_addr); 1451281806Srpaulo 1452281806Srpaulo if (config->rand_addr_lifetime != DEFAULT_RAND_ADDR_LIFETIME) 1453281806Srpaulo fprintf(f, "rand_addr_lifetime=%u\n", 1454281806Srpaulo config->rand_addr_lifetime); 1455281806Srpaulo 1456281806Srpaulo if (config->preassoc_mac_addr) 1457281806Srpaulo fprintf(f, "preassoc_mac_addr=%d\n", config->preassoc_mac_addr); 1458281806Srpaulo 1459281806Srpaulo if (config->key_mgmt_offload != DEFAULT_KEY_MGMT_OFFLOAD) 1460289549Srpaulo fprintf(f, "key_mgmt_offload=%d\n", config->key_mgmt_offload); 1461281806Srpaulo 1462281806Srpaulo if (config->user_mpm != DEFAULT_USER_MPM) 1463281806Srpaulo fprintf(f, "user_mpm=%d\n", config->user_mpm); 1464281806Srpaulo 1465281806Srpaulo if (config->max_peer_links != DEFAULT_MAX_PEER_LINKS) 1466281806Srpaulo fprintf(f, "max_peer_links=%d\n", config->max_peer_links); 1467281806Srpaulo 1468281806Srpaulo if (config->cert_in_cb != DEFAULT_CERT_IN_CB) 1469281806Srpaulo fprintf(f, "cert_in_cb=%d\n", config->cert_in_cb); 1470281806Srpaulo 1471281806Srpaulo if (config->mesh_max_inactivity != DEFAULT_MESH_MAX_INACTIVITY) 1472281806Srpaulo fprintf(f, "mesh_max_inactivity=%d\n", 1473281806Srpaulo config->mesh_max_inactivity); 1474281806Srpaulo 1475289549Srpaulo if (config->dot11RSNASAERetransPeriod != 1476289549Srpaulo DEFAULT_DOT11_RSNA_SAE_RETRANS_PERIOD) 1477289549Srpaulo fprintf(f, "dot11RSNASAERetransPeriod=%d\n", 1478289549Srpaulo config->dot11RSNASAERetransPeriod); 1479289549Srpaulo 1480281806Srpaulo if (config->passive_scan) 1481281806Srpaulo fprintf(f, "passive_scan=%d\n", config->passive_scan); 1482281806Srpaulo 1483281806Srpaulo if (config->reassoc_same_bss_optim) 1484281806Srpaulo fprintf(f, "reassoc_same_bss_optim=%d\n", 1485281806Srpaulo config->reassoc_same_bss_optim); 1486289549Srpaulo 1487289549Srpaulo if (config->wps_priority) 1488289549Srpaulo fprintf(f, "wps_priority=%d\n", config->wps_priority); 1489337817Scy 1490337817Scy if (config->wpa_rsc_relaxation != DEFAULT_WPA_RSC_RELAXATION) 1491337817Scy fprintf(f, "wpa_rsc_relaxation=%d\n", 1492337817Scy config->wpa_rsc_relaxation); 1493337817Scy 1494337817Scy if (config->sched_scan_plans) 1495337817Scy fprintf(f, "sched_scan_plans=%s\n", config->sched_scan_plans); 1496337817Scy 1497337817Scy#ifdef CONFIG_MBO 1498337817Scy if (config->non_pref_chan) 1499337817Scy fprintf(f, "non_pref_chan=%s\n", config->non_pref_chan); 1500337817Scy if (config->mbo_cell_capa != DEFAULT_MBO_CELL_CAPA) 1501337817Scy fprintf(f, "mbo_cell_capa=%u\n", config->mbo_cell_capa); 1502346981Scy if (config->disassoc_imminent_rssi_threshold != 1503346981Scy DEFAULT_DISASSOC_IMMINENT_RSSI_THRESHOLD) 1504346981Scy fprintf(f, "disassoc_imminent_rssi_threshold=%d\n", 1505346981Scy config->disassoc_imminent_rssi_threshold); 1506346981Scy if (config->oce != DEFAULT_OCE_SUPPORT) 1507346981Scy fprintf(f, "oce=%u\n", config->oce); 1508337817Scy#endif /* CONFIG_MBO */ 1509337817Scy 1510337817Scy if (config->gas_address3) 1511337817Scy fprintf(f, "gas_address3=%d\n", config->gas_address3); 1512337817Scy 1513337817Scy if (config->ftm_responder) 1514337817Scy fprintf(f, "ftm_responder=%d\n", config->ftm_responder); 1515337817Scy if (config->ftm_initiator) 1516337817Scy fprintf(f, "ftm_initiator=%d\n", config->ftm_initiator); 1517346981Scy 1518346981Scy if (config->osu_dir) 1519346981Scy fprintf(f, "osu_dir=%s\n", config->osu_dir); 1520346981Scy 1521346981Scy if (config->fst_group_id) 1522346981Scy fprintf(f, "fst_group_id=%s\n", config->fst_group_id); 1523346981Scy if (config->fst_priority) 1524346981Scy fprintf(f, "fst_priority=%d\n", config->fst_priority); 1525346981Scy if (config->fst_llt) 1526346981Scy fprintf(f, "fst_llt=%d\n", config->fst_llt); 1527346981Scy 1528346981Scy if (config->gas_rand_addr_lifetime != DEFAULT_RAND_ADDR_LIFETIME) 1529346981Scy fprintf(f, "gas_rand_addr_lifetime=%u\n", 1530346981Scy config->gas_rand_addr_lifetime); 1531346981Scy if (config->gas_rand_mac_addr) 1532346981Scy fprintf(f, "gas_rand_mac_addr=%d\n", config->gas_rand_mac_addr); 1533346981Scy if (config->dpp_config_processing) 1534346981Scy fprintf(f, "dpp_config_processing=%d\n", 1535346981Scy config->dpp_config_processing); 1536346981Scy if (config->coloc_intf_reporting) 1537346981Scy fprintf(f, "coloc_intf_reporting=%d\n", 1538346981Scy config->coloc_intf_reporting); 1539346981Scy if (config->p2p_device_random_mac_addr) 1540346981Scy fprintf(f, "p2p_device_random_mac_addr=%d\n", 1541346981Scy config->p2p_device_random_mac_addr); 1542346981Scy if (!is_zero_ether_addr(config->p2p_device_persistent_mac_addr)) 1543346981Scy fprintf(f, "p2p_device_persistent_mac_addr=" MACSTR "\n", 1544346981Scy MAC2STR(config->p2p_device_persistent_mac_addr)); 1545346981Scy if (config->p2p_interface_random_mac_addr) 1546346981Scy fprintf(f, "p2p_interface_random_mac_addr=%d\n", 1547346981Scy config->p2p_interface_random_mac_addr); 1548351611Scy if (config->disable_btm) 1549351611Scy fprintf(f, "disable_btm=1\n"); 1550189251Ssam} 1551189251Ssam 1552189251Ssam#endif /* CONFIG_NO_CONFIG_WRITE */ 1553189251Ssam 1554189251Ssam 1555189251Ssamint wpa_config_write(const char *name, struct wpa_config *config) 1556189251Ssam{ 1557189251Ssam#ifndef CONFIG_NO_CONFIG_WRITE 1558189251Ssam FILE *f; 1559189251Ssam struct wpa_ssid *ssid; 1560252726Srpaulo struct wpa_cred *cred; 1561189251Ssam#ifndef CONFIG_NO_CONFIG_BLOBS 1562189251Ssam struct wpa_config_blob *blob; 1563189251Ssam#endif /* CONFIG_NO_CONFIG_BLOBS */ 1564189251Ssam int ret = 0; 1565281806Srpaulo const char *orig_name = name; 1566281806Srpaulo int tmp_len = os_strlen(name) + 5; /* allow space for .tmp suffix */ 1567281806Srpaulo char *tmp_name = os_malloc(tmp_len); 1568189251Ssam 1569281806Srpaulo if (tmp_name) { 1570281806Srpaulo os_snprintf(tmp_name, tmp_len, "%s.tmp", name); 1571281806Srpaulo name = tmp_name; 1572281806Srpaulo } 1573281806Srpaulo 1574189251Ssam wpa_printf(MSG_DEBUG, "Writing configuration file '%s'", name); 1575189251Ssam 1576189251Ssam f = fopen(name, "w"); 1577189251Ssam if (f == NULL) { 1578189251Ssam wpa_printf(MSG_DEBUG, "Failed to open '%s' for writing", name); 1579281806Srpaulo os_free(tmp_name); 1580189251Ssam return -1; 1581189251Ssam } 1582189251Ssam 1583189251Ssam wpa_config_write_global(f, config); 1584189251Ssam 1585252726Srpaulo for (cred = config->cred; cred; cred = cred->next) { 1586281806Srpaulo if (cred->temporary) 1587281806Srpaulo continue; 1588252726Srpaulo fprintf(f, "\ncred={\n"); 1589252726Srpaulo wpa_config_write_cred(f, cred); 1590252726Srpaulo fprintf(f, "}\n"); 1591252726Srpaulo } 1592252726Srpaulo 1593189251Ssam for (ssid = config->ssid; ssid; ssid = ssid->next) { 1594252726Srpaulo if (ssid->key_mgmt == WPA_KEY_MGMT_WPS || ssid->temporary) 1595252726Srpaulo continue; /* do not save temporary networks */ 1596252726Srpaulo if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set && 1597252726Srpaulo !ssid->passphrase) 1598252726Srpaulo continue; /* do not save invalid network */ 1599189251Ssam fprintf(f, "\nnetwork={\n"); 1600189251Ssam wpa_config_write_network(f, ssid); 1601189251Ssam fprintf(f, "}\n"); 1602189251Ssam } 1603189251Ssam 1604189251Ssam#ifndef CONFIG_NO_CONFIG_BLOBS 1605189251Ssam for (blob = config->blobs; blob; blob = blob->next) { 1606189251Ssam ret = wpa_config_write_blob(f, blob); 1607189251Ssam if (ret) 1608189251Ssam break; 1609189251Ssam } 1610189251Ssam#endif /* CONFIG_NO_CONFIG_BLOBS */ 1611189251Ssam 1612289549Srpaulo os_fdatasync(f); 1613289549Srpaulo 1614189251Ssam fclose(f); 1615189251Ssam 1616281806Srpaulo if (tmp_name) { 1617281806Srpaulo int chmod_ret = 0; 1618281806Srpaulo 1619281806Srpaulo#ifdef ANDROID 1620281806Srpaulo chmod_ret = chmod(tmp_name, 1621281806Srpaulo S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); 1622281806Srpaulo#endif /* ANDROID */ 1623281806Srpaulo if (chmod_ret != 0 || rename(tmp_name, orig_name) != 0) 1624281806Srpaulo ret = -1; 1625281806Srpaulo 1626281806Srpaulo os_free(tmp_name); 1627281806Srpaulo } 1628281806Srpaulo 1629189251Ssam wpa_printf(MSG_DEBUG, "Configuration file '%s' written %ssuccessfully", 1630281806Srpaulo orig_name, ret ? "un" : ""); 1631189251Ssam return ret; 1632189251Ssam#else /* CONFIG_NO_CONFIG_WRITE */ 1633189251Ssam return -1; 1634189251Ssam#endif /* CONFIG_NO_CONFIG_WRITE */ 1635189251Ssam} 1636