1 /* 2 * WPA Supplicant / Configuration parser and common functions 3 * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 * Alternatively, this software may be distributed under the terms of BSD 10 * license. 11 * 12 * See README and COPYING for more details. 13 */ 14 15 #include "includes.h" 16 17 #include "common.h" 18 #include "crypto/sha1.h" 19 #include "rsn_supp/wpa.h" 20 #include "eap_peer/eap.h" 21 #include "config.h" 22 23 24 #if !defined(CONFIG_CTRL_IFACE) && defined(CONFIG_NO_CONFIG_WRITE) 25 #define NO_CONFIG_WRITE 26 #endif 27 28 /* 29 * Structure for network configuration parsing. This data is used to implement 30 * a generic parser for each network block variable. The table of configuration 31 * variables is defined below in this file (ssid_fields[]). 32 */ 33 struct parse_data { 34 /* Configuration variable name */ 35 char *name; 36 37 /* Parser function for this variable */ 38 int (*parser)(const struct parse_data *data, struct wpa_ssid *ssid, 39 int line, const char *value); 40 41 #ifndef NO_CONFIG_WRITE 42 /* Writer function (i.e., to get the variable in text format from 43 * internal presentation). */ 44 char * (*writer)(const struct parse_data *data, struct wpa_ssid *ssid); 45 #endif /* NO_CONFIG_WRITE */ 46 47 /* Variable specific parameters for the parser. */ 48 void *param1, *param2, *param3, *param4; 49 50 /* 0 = this variable can be included in debug output and ctrl_iface 51 * 1 = this variable contains key/private data and it must not be 52 * included in debug output unless explicitly requested. In 53 * addition, this variable will not be readable through the 54 * ctrl_iface. 55 */ 56 int key_data; 57 }; 58 59 60 static char * wpa_config_parse_string(const char *value, size_t *len) 61 { 62 if (*value == '"') { 63 const char *pos; 64 char *str; 65 value++; 66 pos = os_strrchr(value, '"'); 67 if (pos == NULL || pos[1] != '\0') 68 return NULL; 69 *len = pos - value; 70 str = os_malloc(*len + 1); 71 if (str == NULL) 72 return NULL; 73 os_memcpy(str, value, *len); 74 str[*len] = '\0'; 75 return str; 76 } else { 77 u8 *str; 78 size_t tlen, hlen = os_strlen(value); 79 if (hlen & 1) 80 return NULL; 81 tlen = hlen / 2; 82 str = os_malloc(tlen + 1); 83 if (str == NULL) 84 return NULL; 85 if (hexstr2bin(value, str, tlen)) { 86 os_free(str); 87 return NULL; 88 } 89 str[tlen] = '\0'; 90 *len = tlen; 91 return (char *) str; 92 } 93 } 94 95 96 static int wpa_config_parse_str(const struct parse_data *data, 97 struct wpa_ssid *ssid, 98 int line, const char *value) 99 { 100 size_t res_len, *dst_len; 101 char **dst, *tmp; 102 103 if (os_strcmp(value, "NULL") == 0) { 104 wpa_printf(MSG_DEBUG, "Unset configuration string '%s'", 105 data->name); 106 tmp = NULL; 107 res_len = 0; 108 goto set; 109 } 110 111 tmp = wpa_config_parse_string(value, &res_len); 112 if (tmp == NULL) { 113 wpa_printf(MSG_ERROR, "Line %d: failed to parse %s '%s'.", 114 line, data->name, 115 data->key_data ? "[KEY DATA REMOVED]" : value); 116 return -1; 117 } 118 119 if (data->key_data) { 120 wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name, 121 (u8 *) tmp, res_len); 122 } else { 123 wpa_hexdump_ascii(MSG_MSGDUMP, data->name, 124 (u8 *) tmp, res_len); 125 } 126 127 if (data->param3 && res_len < (size_t) data->param3) { 128 wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu " 129 "min_len=%ld)", line, data->name, 130 (unsigned long) res_len, (long) data->param3); 131 os_free(tmp); 132 return -1; 133 } 134 135 if (data->param4 && res_len > (size_t) data->param4) { 136 wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu " 137 "max_len=%ld)", line, data->name, 138 (unsigned long) res_len, (long) data->param4); 139 os_free(tmp); 140 return -1; 141 } 142 143 set: 144 dst = (char **) (((u8 *) ssid) + (long) data->param1); 145 dst_len = (size_t *) (((u8 *) ssid) + (long) data->param2); 146 os_free(*dst); 147 *dst = tmp; 148 if (data->param2) 149 *dst_len = res_len; 150 151 return 0; 152 } 153 154 155 #ifndef NO_CONFIG_WRITE 156 static int is_hex(const u8 *data, size_t len) 157 { 158 size_t i; 159 160 for (i = 0; i < len; i++) { 161 if (data[i] < 32 || data[i] >= 127) 162 return 1; 163 } 164 return 0; 165 } 166 167 168 static char * wpa_config_write_string_ascii(const u8 *value, size_t len) 169 { 170 char *buf; 171 172 buf = os_malloc(len + 3); 173 if (buf == NULL) 174 return NULL; 175 buf[0] = '"'; 176 os_memcpy(buf + 1, value, len); 177 buf[len + 1] = '"'; 178 buf[len + 2] = '\0'; 179 180 return buf; 181 } 182 183 184 static char * wpa_config_write_string_hex(const u8 *value, size_t len) 185 { 186 char *buf; 187 188 buf = os_zalloc(2 * len + 1); 189 if (buf == NULL) 190 return NULL; 191 wpa_snprintf_hex(buf, 2 * len + 1, value, len); 192 193 return buf; 194 } 195 196 197 static char * wpa_config_write_string(const u8 *value, size_t len) 198 { 199 if (value == NULL) 200 return NULL; 201 202 if (is_hex(value, len)) 203 return wpa_config_write_string_hex(value, len); 204 else 205 return wpa_config_write_string_ascii(value, len); 206 } 207 208 209 static char * wpa_config_write_str(const struct parse_data *data, 210 struct wpa_ssid *ssid) 211 { 212 size_t len; 213 char **src; 214 215 src = (char **) (((u8 *) ssid) + (long) data->param1); 216 if (*src == NULL) 217 return NULL; 218 219 if (data->param2) 220 len = *((size_t *) (((u8 *) ssid) + (long) data->param2)); 221 else 222 len = os_strlen(*src); 223 224 return wpa_config_write_string((const u8 *) *src, len); 225 } 226 #endif /* NO_CONFIG_WRITE */ 227 228 229 static int wpa_config_parse_int(const struct parse_data *data, 230 struct wpa_ssid *ssid, 231 int line, const char *value) 232 { 233 int *dst; 234 235 dst = (int *) (((u8 *) ssid) + (long) data->param1); 236 *dst = atoi(value); 237 wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst); 238 239 if (data->param3 && *dst < (long) data->param3) { 240 wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d " 241 "min_value=%ld)", line, data->name, *dst, 242 (long) data->param3); 243 *dst = (long) data->param3; 244 return -1; 245 } 246 247 if (data->param4 && *dst > (long) data->param4) { 248 wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d " 249 "max_value=%ld)", line, data->name, *dst, 250 (long) data->param4); 251 *dst = (long) data->param4; 252 return -1; 253 } 254 255 return 0; 256 } 257 258 259 #ifndef NO_CONFIG_WRITE 260 static char * wpa_config_write_int(const struct parse_data *data, 261 struct wpa_ssid *ssid) 262 { 263 int *src, res; 264 char *value; 265 266 src = (int *) (((u8 *) ssid) + (long) data->param1); 267 268 value = os_malloc(20); 269 if (value == NULL) 270 return NULL; 271 res = os_snprintf(value, 20, "%d", *src); 272 if (res < 0 || res >= 20) { 273 os_free(value); 274 return NULL; 275 } 276 value[20 - 1] = '\0'; 277 return value; 278 } 279 #endif /* NO_CONFIG_WRITE */ 280 281 282 static int wpa_config_parse_bssid(const struct parse_data *data, 283 struct wpa_ssid *ssid, int line, 284 const char *value) 285 { 286 if (hwaddr_aton(value, ssid->bssid)) { 287 wpa_printf(MSG_ERROR, "Line %d: Invalid BSSID '%s'.", 288 line, value); 289 return -1; 290 } 291 ssid->bssid_set = 1; 292 wpa_hexdump(MSG_MSGDUMP, "BSSID", ssid->bssid, ETH_ALEN); 293 return 0; 294 } 295 296 297 #ifndef NO_CONFIG_WRITE 298 static char * wpa_config_write_bssid(const struct parse_data *data, 299 struct wpa_ssid *ssid) 300 { 301 char *value; 302 int res; 303 304 if (!ssid->bssid_set) 305 return NULL; 306 307 value = os_malloc(20); 308 if (value == NULL) 309 return NULL; 310 res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->bssid)); 311 if (res < 0 || res >= 20) { 312 os_free(value); 313 return NULL; 314 } 315 value[20 - 1] = '\0'; 316 return value; 317 } 318 #endif /* NO_CONFIG_WRITE */ 319 320 321 static int wpa_config_parse_psk(const struct parse_data *data, 322 struct wpa_ssid *ssid, int line, 323 const char *value) 324 { 325 if (*value == '"') { 326 #ifndef CONFIG_NO_PBKDF2 327 const char *pos; 328 size_t len; 329 330 value++; 331 pos = os_strrchr(value, '"'); 332 if (pos) 333 len = pos - value; 334 else 335 len = os_strlen(value); 336 if (len < 8 || len > 63) { 337 wpa_printf(MSG_ERROR, "Line %d: Invalid passphrase " 338 "length %lu (expected: 8..63) '%s'.", 339 line, (unsigned long) len, value); 340 return -1; 341 } 342 wpa_hexdump_ascii_key(MSG_MSGDUMP, "PSK (ASCII passphrase)", 343 (u8 *) value, len); 344 if (ssid->passphrase && os_strlen(ssid->passphrase) == len && 345 os_memcmp(ssid->passphrase, value, len) == 0) 346 return 0; 347 ssid->psk_set = 0; 348 os_free(ssid->passphrase); 349 ssid->passphrase = os_malloc(len + 1); 350 if (ssid->passphrase == NULL) 351 return -1; 352 os_memcpy(ssid->passphrase, value, len); 353 ssid->passphrase[len] = '\0'; 354 return 0; 355 #else /* CONFIG_NO_PBKDF2 */ 356 wpa_printf(MSG_ERROR, "Line %d: ASCII passphrase not " 357 "supported.", line); 358 return -1; 359 #endif /* CONFIG_NO_PBKDF2 */ 360 } 361 362 if (hexstr2bin(value, ssid->psk, PMK_LEN) || 363 value[PMK_LEN * 2] != '\0') { 364 wpa_printf(MSG_ERROR, "Line %d: Invalid PSK '%s'.", 365 line, value); 366 return -1; 367 } 368 369 os_free(ssid->passphrase); 370 ssid->passphrase = NULL; 371 372 ssid->psk_set = 1; 373 wpa_hexdump_key(MSG_MSGDUMP, "PSK", ssid->psk, PMK_LEN); 374 return 0; 375 } 376 377 378 #ifndef NO_CONFIG_WRITE 379 static char * wpa_config_write_psk(const struct parse_data *data, 380 struct wpa_ssid *ssid) 381 { 382 if (ssid->passphrase) 383 return wpa_config_write_string_ascii( 384 (const u8 *) ssid->passphrase, 385 os_strlen(ssid->passphrase)); 386 387 if (ssid->psk_set) 388 return wpa_config_write_string_hex(ssid->psk, PMK_LEN); 389 390 return NULL; 391 } 392 #endif /* NO_CONFIG_WRITE */ 393 394 395 static int wpa_config_parse_proto(const struct parse_data *data, 396 struct wpa_ssid *ssid, int line, 397 const char *value) 398 { 399 int val = 0, last, errors = 0; 400 char *start, *end, *buf; 401 402 buf = os_strdup(value); 403 if (buf == NULL) 404 return -1; 405 start = buf; 406 407 while (*start != '\0') { 408 while (*start == ' ' || *start == '\t') 409 start++; 410 if (*start == '\0') 411 break; 412 end = start; 413 while (*end != ' ' && *end != '\t' && *end != '\0') 414 end++; 415 last = *end == '\0'; 416 *end = '\0'; 417 if (os_strcmp(start, "WPA") == 0) 418 val |= WPA_PROTO_WPA; 419 else if (os_strcmp(start, "RSN") == 0 || 420 os_strcmp(start, "WPA2") == 0) 421 val |= WPA_PROTO_RSN; 422 else { 423 wpa_printf(MSG_ERROR, "Line %d: invalid proto '%s'", 424 line, start); 425 errors++; 426 } 427 428 if (last) 429 break; 430 start = end + 1; 431 } 432 os_free(buf); 433 434 if (val == 0) { 435 wpa_printf(MSG_ERROR, 436 "Line %d: no proto values configured.", line); 437 errors++; 438 } 439 440 wpa_printf(MSG_MSGDUMP, "proto: 0x%x", val); 441 ssid->proto = val; 442 return errors ? -1 : 0; 443 } 444 445 446 #ifndef NO_CONFIG_WRITE 447 static char * wpa_config_write_proto(const struct parse_data *data, 448 struct wpa_ssid *ssid) 449 { 450 int first = 1, ret; 451 char *buf, *pos, *end; 452 453 pos = buf = os_zalloc(10); 454 if (buf == NULL) 455 return NULL; 456 end = buf + 10; 457 458 if (ssid->proto & WPA_PROTO_WPA) { 459 ret = os_snprintf(pos, end - pos, "%sWPA", first ? "" : " "); 460 if (ret < 0 || ret >= end - pos) 461 return buf; 462 pos += ret; 463 first = 0; 464 } 465 466 if (ssid->proto & WPA_PROTO_RSN) { 467 ret = os_snprintf(pos, end - pos, "%sRSN", first ? "" : " "); 468 if (ret < 0 || ret >= end - pos) 469 return buf; 470 pos += ret; 471 first = 0; 472 } 473 474 return buf; 475 } 476 #endif /* NO_CONFIG_WRITE */ 477 478 479 static int wpa_config_parse_key_mgmt(const struct parse_data *data, 480 struct wpa_ssid *ssid, int line, 481 const char *value) 482 { 483 int val = 0, last, errors = 0; 484 char *start, *end, *buf; 485 486 buf = os_strdup(value); 487 if (buf == NULL) 488 return -1; 489 start = buf; 490 491 while (*start != '\0') { 492 while (*start == ' ' || *start == '\t') 493 start++; 494 if (*start == '\0') 495 break; 496 end = start; 497 while (*end != ' ' && *end != '\t' && *end != '\0') 498 end++; 499 last = *end == '\0'; 500 *end = '\0'; 501 if (os_strcmp(start, "WPA-PSK") == 0) 502 val |= WPA_KEY_MGMT_PSK; 503 else if (os_strcmp(start, "WPA-EAP") == 0) 504 val |= WPA_KEY_MGMT_IEEE8021X; 505 else if (os_strcmp(start, "IEEE8021X") == 0) 506 val |= WPA_KEY_MGMT_IEEE8021X_NO_WPA; 507 else if (os_strcmp(start, "NONE") == 0) 508 val |= WPA_KEY_MGMT_NONE; 509 else if (os_strcmp(start, "WPA-NONE") == 0) 510 val |= WPA_KEY_MGMT_WPA_NONE; 511 #ifdef CONFIG_IEEE80211R 512 else if (os_strcmp(start, "FT-PSK") == 0) 513 val |= WPA_KEY_MGMT_FT_PSK; 514 else if (os_strcmp(start, "FT-EAP") == 0) 515 val |= WPA_KEY_MGMT_FT_IEEE8021X; 516 #endif /* CONFIG_IEEE80211R */ 517 #ifdef CONFIG_IEEE80211W 518 else if (os_strcmp(start, "WPA-PSK-SHA256") == 0) 519 val |= WPA_KEY_MGMT_PSK_SHA256; 520 else if (os_strcmp(start, "WPA-EAP-SHA256") == 0) 521 val |= WPA_KEY_MGMT_IEEE8021X_SHA256; 522 #endif /* CONFIG_IEEE80211W */ 523 #ifdef CONFIG_WPS 524 else if (os_strcmp(start, "WPS") == 0) 525 val |= WPA_KEY_MGMT_WPS; 526 #endif /* CONFIG_WPS */ 527 else { 528 wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'", 529 line, start); 530 errors++; 531 } 532 533 if (last) 534 break; 535 start = end + 1; 536 } 537 os_free(buf); 538 539 if (val == 0) { 540 wpa_printf(MSG_ERROR, 541 "Line %d: no key_mgmt values configured.", line); 542 errors++; 543 } 544 545 wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", val); 546 ssid->key_mgmt = val; 547 return errors ? -1 : 0; 548 } 549 550 551 #ifndef NO_CONFIG_WRITE 552 static char * wpa_config_write_key_mgmt(const struct parse_data *data, 553 struct wpa_ssid *ssid) 554 { 555 char *buf, *pos, *end; 556 int ret; 557 558 pos = buf = os_zalloc(50); 559 if (buf == NULL) 560 return NULL; 561 end = buf + 50; 562 563 if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) { 564 ret = os_snprintf(pos, end - pos, "%sWPA-PSK", 565 pos == buf ? "" : " "); 566 if (ret < 0 || ret >= end - pos) { 567 end[-1] = '\0'; 568 return buf; 569 } 570 pos += ret; 571 } 572 573 if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X) { 574 ret = os_snprintf(pos, end - pos, "%sWPA-EAP", 575 pos == buf ? "" : " "); 576 if (ret < 0 || ret >= end - pos) { 577 end[-1] = '\0'; 578 return buf; 579 } 580 pos += ret; 581 } 582 583 if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) { 584 ret = os_snprintf(pos, end - pos, "%sIEEE8021X", 585 pos == buf ? "" : " "); 586 if (ret < 0 || ret >= end - pos) { 587 end[-1] = '\0'; 588 return buf; 589 } 590 pos += ret; 591 } 592 593 if (ssid->key_mgmt & WPA_KEY_MGMT_NONE) { 594 ret = os_snprintf(pos, end - pos, "%sNONE", 595 pos == buf ? "" : " "); 596 if (ret < 0 || ret >= end - pos) { 597 end[-1] = '\0'; 598 return buf; 599 } 600 pos += ret; 601 } 602 603 if (ssid->key_mgmt & WPA_KEY_MGMT_WPA_NONE) { 604 ret = os_snprintf(pos, end - pos, "%sWPA-NONE", 605 pos == buf ? "" : " "); 606 if (ret < 0 || ret >= end - pos) { 607 end[-1] = '\0'; 608 return buf; 609 } 610 pos += ret; 611 } 612 613 #ifdef CONFIG_IEEE80211R 614 if (ssid->key_mgmt & WPA_KEY_MGMT_FT_PSK) 615 pos += os_snprintf(pos, end - pos, "%sFT-PSK", 616 pos == buf ? "" : " "); 617 618 if (ssid->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) 619 pos += os_snprintf(pos, end - pos, "%sFT-EAP", 620 pos == buf ? "" : " "); 621 #endif /* CONFIG_IEEE80211R */ 622 623 #ifdef CONFIG_IEEE80211W 624 if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256) 625 pos += os_snprintf(pos, end - pos, "%sWPA-PSK-SHA256", 626 pos == buf ? "" : " "); 627 628 if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) 629 pos += os_snprintf(pos, end - pos, "%sWPA-EAP-SHA256", 630 pos == buf ? "" : " "); 631 #endif /* CONFIG_IEEE80211W */ 632 633 #ifdef CONFIG_WPS 634 if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) 635 pos += os_snprintf(pos, end - pos, "%sWPS", 636 pos == buf ? "" : " "); 637 #endif /* CONFIG_WPS */ 638 639 return buf; 640 } 641 #endif /* NO_CONFIG_WRITE */ 642 643 644 static int wpa_config_parse_cipher(int line, const char *value) 645 { 646 int val = 0, last; 647 char *start, *end, *buf; 648 649 buf = os_strdup(value); 650 if (buf == NULL) 651 return -1; 652 start = buf; 653 654 while (*start != '\0') { 655 while (*start == ' ' || *start == '\t') 656 start++; 657 if (*start == '\0') 658 break; 659 end = start; 660 while (*end != ' ' && *end != '\t' && *end != '\0') 661 end++; 662 last = *end == '\0'; 663 *end = '\0'; 664 if (os_strcmp(start, "CCMP") == 0) 665 val |= WPA_CIPHER_CCMP; 666 else if (os_strcmp(start, "TKIP") == 0) 667 val |= WPA_CIPHER_TKIP; 668 else if (os_strcmp(start, "WEP104") == 0) 669 val |= WPA_CIPHER_WEP104; 670 else if (os_strcmp(start, "WEP40") == 0) 671 val |= WPA_CIPHER_WEP40; 672 else if (os_strcmp(start, "NONE") == 0) 673 val |= WPA_CIPHER_NONE; 674 else { 675 wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.", 676 line, start); 677 os_free(buf); 678 return -1; 679 } 680 681 if (last) 682 break; 683 start = end + 1; 684 } 685 os_free(buf); 686 687 if (val == 0) { 688 wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.", 689 line); 690 return -1; 691 } 692 return val; 693 } 694 695 696 #ifndef NO_CONFIG_WRITE 697 static char * wpa_config_write_cipher(int cipher) 698 { 699 char *buf, *pos, *end; 700 int ret; 701 702 pos = buf = os_zalloc(50); 703 if (buf == NULL) 704 return NULL; 705 end = buf + 50; 706 707 if (cipher & WPA_CIPHER_CCMP) { 708 ret = os_snprintf(pos, end - pos, "%sCCMP", 709 pos == buf ? "" : " "); 710 if (ret < 0 || ret >= end - pos) { 711 end[-1] = '\0'; 712 return buf; 713 } 714 pos += ret; 715 } 716 717 if (cipher & WPA_CIPHER_TKIP) { 718 ret = os_snprintf(pos, end - pos, "%sTKIP", 719 pos == buf ? "" : " "); 720 if (ret < 0 || ret >= end - pos) { 721 end[-1] = '\0'; 722 return buf; 723 } 724 pos += ret; 725 } 726 727 if (cipher & WPA_CIPHER_WEP104) { 728 ret = os_snprintf(pos, end - pos, "%sWEP104", 729 pos == buf ? "" : " "); 730 if (ret < 0 || ret >= end - pos) { 731 end[-1] = '\0'; 732 return buf; 733 } 734 pos += ret; 735 } 736 737 if (cipher & WPA_CIPHER_WEP40) { 738 ret = os_snprintf(pos, end - pos, "%sWEP40", 739 pos == buf ? "" : " "); 740 if (ret < 0 || ret >= end - pos) { 741 end[-1] = '\0'; 742 return buf; 743 } 744 pos += ret; 745 } 746 747 if (cipher & WPA_CIPHER_NONE) { 748 ret = os_snprintf(pos, end - pos, "%sNONE", 749 pos == buf ? "" : " "); 750 if (ret < 0 || ret >= end - pos) { 751 end[-1] = '\0'; 752 return buf; 753 } 754 pos += ret; 755 } 756 757 return buf; 758 } 759 #endif /* NO_CONFIG_WRITE */ 760 761 762 static int wpa_config_parse_pairwise(const struct parse_data *data, 763 struct wpa_ssid *ssid, int line, 764 const char *value) 765 { 766 int val; 767 val = wpa_config_parse_cipher(line, value); 768 if (val == -1) 769 return -1; 770 if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE)) { 771 wpa_printf(MSG_ERROR, "Line %d: not allowed pairwise cipher " 772 "(0x%x).", line, val); 773 return -1; 774 } 775 776 wpa_printf(MSG_MSGDUMP, "pairwise: 0x%x", val); 777 ssid->pairwise_cipher = val; 778 return 0; 779 } 780 781 782 #ifndef NO_CONFIG_WRITE 783 static char * wpa_config_write_pairwise(const struct parse_data *data, 784 struct wpa_ssid *ssid) 785 { 786 return wpa_config_write_cipher(ssid->pairwise_cipher); 787 } 788 #endif /* NO_CONFIG_WRITE */ 789 790 791 static int wpa_config_parse_group(const struct parse_data *data, 792 struct wpa_ssid *ssid, int line, 793 const char *value) 794 { 795 int val; 796 val = wpa_config_parse_cipher(line, value); 797 if (val == -1) 798 return -1; 799 if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | WPA_CIPHER_WEP104 | 800 WPA_CIPHER_WEP40)) { 801 wpa_printf(MSG_ERROR, "Line %d: not allowed group cipher " 802 "(0x%x).", line, val); 803 return -1; 804 } 805 806 wpa_printf(MSG_MSGDUMP, "group: 0x%x", val); 807 ssid->group_cipher = val; 808 return 0; 809 } 810 811 812 #ifndef NO_CONFIG_WRITE 813 static char * wpa_config_write_group(const struct parse_data *data, 814 struct wpa_ssid *ssid) 815 { 816 return wpa_config_write_cipher(ssid->group_cipher); 817 } 818 #endif /* NO_CONFIG_WRITE */ 819 820 821 static int wpa_config_parse_auth_alg(const struct parse_data *data, 822 struct wpa_ssid *ssid, int line, 823 const char *value) 824 { 825 int val = 0, last, errors = 0; 826 char *start, *end, *buf; 827 828 buf = os_strdup(value); 829 if (buf == NULL) 830 return -1; 831 start = buf; 832 833 while (*start != '\0') { 834 while (*start == ' ' || *start == '\t') 835 start++; 836 if (*start == '\0') 837 break; 838 end = start; 839 while (*end != ' ' && *end != '\t' && *end != '\0') 840 end++; 841 last = *end == '\0'; 842 *end = '\0'; 843 if (os_strcmp(start, "OPEN") == 0) 844 val |= WPA_AUTH_ALG_OPEN; 845 else if (os_strcmp(start, "SHARED") == 0) 846 val |= WPA_AUTH_ALG_SHARED; 847 else if (os_strcmp(start, "LEAP") == 0) 848 val |= WPA_AUTH_ALG_LEAP; 849 else { 850 wpa_printf(MSG_ERROR, "Line %d: invalid auth_alg '%s'", 851 line, start); 852 errors++; 853 } 854 855 if (last) 856 break; 857 start = end + 1; 858 } 859 os_free(buf); 860 861 if (val == 0) { 862 wpa_printf(MSG_ERROR, 863 "Line %d: no auth_alg values configured.", line); 864 errors++; 865 } 866 867 wpa_printf(MSG_MSGDUMP, "auth_alg: 0x%x", val); 868 ssid->auth_alg = val; 869 return errors ? -1 : 0; 870 } 871 872 873 #ifndef NO_CONFIG_WRITE 874 static char * wpa_config_write_auth_alg(const struct parse_data *data, 875 struct wpa_ssid *ssid) 876 { 877 char *buf, *pos, *end; 878 int ret; 879 880 pos = buf = os_zalloc(30); 881 if (buf == NULL) 882 return NULL; 883 end = buf + 30; 884 885 if (ssid->auth_alg & WPA_AUTH_ALG_OPEN) { 886 ret = os_snprintf(pos, end - pos, "%sOPEN", 887 pos == buf ? "" : " "); 888 if (ret < 0 || ret >= end - pos) { 889 end[-1] = '\0'; 890 return buf; 891 } 892 pos += ret; 893 } 894 895 if (ssid->auth_alg & WPA_AUTH_ALG_SHARED) { 896 ret = os_snprintf(pos, end - pos, "%sSHARED", 897 pos == buf ? "" : " "); 898 if (ret < 0 || ret >= end - pos) { 899 end[-1] = '\0'; 900 return buf; 901 } 902 pos += ret; 903 } 904 905 if (ssid->auth_alg & WPA_AUTH_ALG_LEAP) { 906 ret = os_snprintf(pos, end - pos, "%sLEAP", 907 pos == buf ? "" : " "); 908 if (ret < 0 || ret >= end - pos) { 909 end[-1] = '\0'; 910 return buf; 911 } 912 pos += ret; 913 } 914 915 return buf; 916 } 917 #endif /* NO_CONFIG_WRITE */ 918 919 920 static int * wpa_config_parse_freqs(const struct parse_data *data, 921 struct wpa_ssid *ssid, int line, 922 const char *value) 923 { 924 int *freqs; 925 size_t used, len; 926 const char *pos; 927 928 used = 0; 929 len = 10; 930 freqs = os_zalloc((len + 1) * sizeof(int)); 931 if (freqs == NULL) 932 return NULL; 933 934 pos = value; 935 while (pos) { 936 while (*pos == ' ') 937 pos++; 938 if (used == len) { 939 int *n; 940 size_t i; 941 n = os_realloc(freqs, (len * 2 + 1) * sizeof(int)); 942 if (n == NULL) { 943 os_free(freqs); 944 return NULL; 945 } 946 for (i = len; i <= len * 2; i++) 947 n[i] = 0; 948 freqs = n; 949 len *= 2; 950 } 951 952 freqs[used] = atoi(pos); 953 if (freqs[used] == 0) 954 break; 955 used++; 956 pos = os_strchr(pos + 1, ' '); 957 } 958 959 return freqs; 960 } 961 962 963 static int wpa_config_parse_scan_freq(const struct parse_data *data, 964 struct wpa_ssid *ssid, int line, 965 const char *value) 966 { 967 int *freqs; 968 969 freqs = wpa_config_parse_freqs(data, ssid, line, value); 970 if (freqs == NULL) 971 return -1; 972 os_free(ssid->scan_freq); 973 ssid->scan_freq = freqs; 974 975 return 0; 976 } 977 978 979 static int wpa_config_parse_freq_list(const struct parse_data *data, 980 struct wpa_ssid *ssid, int line, 981 const char *value) 982 { 983 int *freqs; 984 985 freqs = wpa_config_parse_freqs(data, ssid, line, value); 986 if (freqs == NULL) 987 return -1; 988 os_free(ssid->freq_list); 989 ssid->freq_list = freqs; 990 991 return 0; 992 } 993 994 995 #ifndef NO_CONFIG_WRITE 996 static char * wpa_config_write_freqs(const struct parse_data *data, 997 const int *freqs) 998 { 999 char *buf, *pos, *end; 1000 int i, ret; 1001 size_t count; 1002 1003 if (freqs == NULL) 1004 return NULL; 1005 1006 count = 0; 1007 for (i = 0; freqs[i]; i++) 1008 count++; 1009 1010 pos = buf = os_zalloc(10 * count + 1); 1011 if (buf == NULL) 1012 return NULL; 1013 end = buf + 10 * count + 1; 1014 1015 for (i = 0; freqs[i]; i++) { 1016 ret = os_snprintf(pos, end - pos, "%s%u", 1017 i == 0 ? "" : " ", freqs[i]); 1018 if (ret < 0 || ret >= end - pos) { 1019 end[-1] = '\0'; 1020 return buf; 1021 } 1022 pos += ret; 1023 } 1024 1025 return buf; 1026 } 1027 1028 1029 static char * wpa_config_write_scan_freq(const struct parse_data *data, 1030 struct wpa_ssid *ssid) 1031 { 1032 return wpa_config_write_freqs(data, ssid->scan_freq); 1033 } 1034 1035 1036 static char * wpa_config_write_freq_list(const struct parse_data *data, 1037 struct wpa_ssid *ssid) 1038 { 1039 return wpa_config_write_freqs(data, ssid->freq_list); 1040 } 1041 #endif /* NO_CONFIG_WRITE */ 1042 1043 1044 #ifdef IEEE8021X_EAPOL 1045 static int wpa_config_parse_eap(const struct parse_data *data, 1046 struct wpa_ssid *ssid, int line, 1047 const char *value) 1048 { 1049 int last, errors = 0; 1050 char *start, *end, *buf; 1051 struct eap_method_type *methods = NULL, *tmp; 1052 size_t num_methods = 0; 1053 1054 buf = os_strdup(value); 1055 if (buf == NULL) 1056 return -1; 1057 start = buf; 1058 1059 while (*start != '\0') { 1060 while (*start == ' ' || *start == '\t') 1061 start++; 1062 if (*start == '\0') 1063 break; 1064 end = start; 1065 while (*end != ' ' && *end != '\t' && *end != '\0') 1066 end++; 1067 last = *end == '\0'; 1068 *end = '\0'; 1069 tmp = methods; 1070 methods = os_realloc(methods, 1071 (num_methods + 1) * sizeof(*methods)); 1072 if (methods == NULL) { 1073 os_free(tmp); 1074 os_free(buf); 1075 return -1; 1076 } 1077 methods[num_methods].method = eap_peer_get_type( 1078 start, &methods[num_methods].vendor); 1079 if (methods[num_methods].vendor == EAP_VENDOR_IETF && 1080 methods[num_methods].method == EAP_TYPE_NONE) { 1081 wpa_printf(MSG_ERROR, "Line %d: unknown EAP method " 1082 "'%s'", line, start); 1083 wpa_printf(MSG_ERROR, "You may need to add support for" 1084 " this EAP method during wpa_supplicant\n" 1085 "build time configuration.\n" 1086 "See README for more information."); 1087 errors++; 1088 } else if (methods[num_methods].vendor == EAP_VENDOR_IETF && 1089 methods[num_methods].method == EAP_TYPE_LEAP) 1090 ssid->leap++; 1091 else 1092 ssid->non_leap++; 1093 num_methods++; 1094 if (last) 1095 break; 1096 start = end + 1; 1097 } 1098 os_free(buf); 1099 1100 tmp = methods; 1101 methods = os_realloc(methods, (num_methods + 1) * sizeof(*methods)); 1102 if (methods == NULL) { 1103 os_free(tmp); 1104 return -1; 1105 } 1106 methods[num_methods].vendor = EAP_VENDOR_IETF; 1107 methods[num_methods].method = EAP_TYPE_NONE; 1108 num_methods++; 1109 1110 wpa_hexdump(MSG_MSGDUMP, "eap methods", 1111 (u8 *) methods, num_methods * sizeof(*methods)); 1112 ssid->eap.eap_methods = methods; 1113 return errors ? -1 : 0; 1114 } 1115 1116 1117 static char * wpa_config_write_eap(const struct parse_data *data, 1118 struct wpa_ssid *ssid) 1119 { 1120 int i, ret; 1121 char *buf, *pos, *end; 1122 const struct eap_method_type *eap_methods = ssid->eap.eap_methods; 1123 const char *name; 1124 1125 if (eap_methods == NULL) 1126 return NULL; 1127 1128 pos = buf = os_zalloc(100); 1129 if (buf == NULL) 1130 return NULL; 1131 end = buf + 100; 1132 1133 for (i = 0; eap_methods[i].vendor != EAP_VENDOR_IETF || 1134 eap_methods[i].method != EAP_TYPE_NONE; i++) { 1135 name = eap_get_name(eap_methods[i].vendor, 1136 eap_methods[i].method); 1137 if (name) { 1138 ret = os_snprintf(pos, end - pos, "%s%s", 1139 pos == buf ? "" : " ", name); 1140 if (ret < 0 || ret >= end - pos) 1141 break; 1142 pos += ret; 1143 } 1144 } 1145 1146 end[-1] = '\0'; 1147 1148 return buf; 1149 } 1150 1151 1152 static int wpa_config_parse_password(const struct parse_data *data, 1153 struct wpa_ssid *ssid, int line, 1154 const char *value) 1155 { 1156 u8 *hash; 1157 1158 if (os_strcmp(value, "NULL") == 0) { 1159 wpa_printf(MSG_DEBUG, "Unset configuration string 'password'"); 1160 os_free(ssid->eap.password); 1161 ssid->eap.password = NULL; 1162 ssid->eap.password_len = 0; 1163 return 0; 1164 } 1165 1166 if (os_strncmp(value, "hash:", 5) != 0) { 1167 char *tmp; 1168 size_t res_len; 1169 1170 tmp = wpa_config_parse_string(value, &res_len); 1171 if (tmp == NULL) { 1172 wpa_printf(MSG_ERROR, "Line %d: failed to parse " 1173 "password.", line); 1174 return -1; 1175 } 1176 wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name, 1177 (u8 *) tmp, res_len); 1178 1179 os_free(ssid->eap.password); 1180 ssid->eap.password = (u8 *) tmp; 1181 ssid->eap.password_len = res_len; 1182 ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH; 1183 1184 return 0; 1185 } 1186 1187 1188 /* NtPasswordHash: hash:<32 hex digits> */ 1189 if (os_strlen(value + 5) != 2 * 16) { 1190 wpa_printf(MSG_ERROR, "Line %d: Invalid password hash length " 1191 "(expected 32 hex digits)", line); 1192 return -1; 1193 } 1194 1195 hash = os_malloc(16); 1196 if (hash == NULL) 1197 return -1; 1198 1199 if (hexstr2bin(value + 5, hash, 16)) { 1200 os_free(hash); 1201 wpa_printf(MSG_ERROR, "Line %d: Invalid password hash", line); 1202 return -1; 1203 } 1204 1205 wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16); 1206 1207 os_free(ssid->eap.password); 1208 ssid->eap.password = hash; 1209 ssid->eap.password_len = 16; 1210 ssid->eap.flags |= EAP_CONFIG_FLAGS_PASSWORD_NTHASH; 1211 1212 return 0; 1213 } 1214 1215 1216 static char * wpa_config_write_password(const struct parse_data *data, 1217 struct wpa_ssid *ssid) 1218 { 1219 char *buf; 1220 1221 if (ssid->eap.password == NULL) 1222 return NULL; 1223 1224 if (!(ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) { 1225 return wpa_config_write_string( 1226 ssid->eap.password, ssid->eap.password_len); 1227 } 1228 1229 buf = os_malloc(5 + 32 + 1); 1230 if (buf == NULL) 1231 return NULL; 1232 1233 os_memcpy(buf, "hash:", 5); 1234 wpa_snprintf_hex(buf + 5, 32 + 1, ssid->eap.password, 16); 1235 1236 return buf; 1237 } 1238 #endif /* IEEE8021X_EAPOL */ 1239 1240 1241 static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line, 1242 const char *value, int idx) 1243 { 1244 char *buf, title[20]; 1245 int res; 1246 1247 buf = wpa_config_parse_string(value, len); 1248 if (buf == NULL) { 1249 wpa_printf(MSG_ERROR, "Line %d: Invalid WEP key %d '%s'.", 1250 line, idx, value); 1251 return -1; 1252 } 1253 if (*len > MAX_WEP_KEY_LEN) { 1254 wpa_printf(MSG_ERROR, "Line %d: Too long WEP key %d '%s'.", 1255 line, idx, value); 1256 os_free(buf); 1257 return -1; 1258 } 1259 os_memcpy(key, buf, *len); 1260 os_free(buf); 1261 res = os_snprintf(title, sizeof(title), "wep_key%d", idx); 1262 if (res >= 0 && (size_t) res < sizeof(title)) 1263 wpa_hexdump_key(MSG_MSGDUMP, title, key, *len); 1264 return 0; 1265 } 1266 1267 1268 static int wpa_config_parse_wep_key0(const struct parse_data *data, 1269 struct wpa_ssid *ssid, int line, 1270 const char *value) 1271 { 1272 return wpa_config_parse_wep_key(ssid->wep_key[0], 1273 &ssid->wep_key_len[0], line, 1274 value, 0); 1275 } 1276 1277 1278 static int wpa_config_parse_wep_key1(const struct parse_data *data, 1279 struct wpa_ssid *ssid, int line, 1280 const char *value) 1281 { 1282 return wpa_config_parse_wep_key(ssid->wep_key[1], 1283 &ssid->wep_key_len[1], line, 1284 value, 1); 1285 } 1286 1287 1288 static int wpa_config_parse_wep_key2(const struct parse_data *data, 1289 struct wpa_ssid *ssid, int line, 1290 const char *value) 1291 { 1292 return wpa_config_parse_wep_key(ssid->wep_key[2], 1293 &ssid->wep_key_len[2], line, 1294 value, 2); 1295 } 1296 1297 1298 static int wpa_config_parse_wep_key3(const struct parse_data *data, 1299 struct wpa_ssid *ssid, int line, 1300 const char *value) 1301 { 1302 return wpa_config_parse_wep_key(ssid->wep_key[3], 1303 &ssid->wep_key_len[3], line, 1304 value, 3); 1305 } 1306 1307 1308 #ifndef NO_CONFIG_WRITE 1309 static char * wpa_config_write_wep_key(struct wpa_ssid *ssid, int idx) 1310 { 1311 if (ssid->wep_key_len[idx] == 0) 1312 return NULL; 1313 return wpa_config_write_string(ssid->wep_key[idx], 1314 ssid->wep_key_len[idx]); 1315 } 1316 1317 1318 static char * wpa_config_write_wep_key0(const struct parse_data *data, 1319 struct wpa_ssid *ssid) 1320 { 1321 return wpa_config_write_wep_key(ssid, 0); 1322 } 1323 1324 1325 static char * wpa_config_write_wep_key1(const struct parse_data *data, 1326 struct wpa_ssid *ssid) 1327 { 1328 return wpa_config_write_wep_key(ssid, 1); 1329 } 1330 1331 1332 static char * wpa_config_write_wep_key2(const struct parse_data *data, 1333 struct wpa_ssid *ssid) 1334 { 1335 return wpa_config_write_wep_key(ssid, 2); 1336 } 1337 1338 1339 static char * wpa_config_write_wep_key3(const struct parse_data *data, 1340 struct wpa_ssid *ssid) 1341 { 1342 return wpa_config_write_wep_key(ssid, 3); 1343 } 1344 #endif /* NO_CONFIG_WRITE */ 1345 1346 1347 /* Helper macros for network block parser */ 1348 1349 #ifdef OFFSET 1350 #undef OFFSET 1351 #endif /* OFFSET */ 1352 /* OFFSET: Get offset of a variable within the wpa_ssid structure */ 1353 #define OFFSET(v) ((void *) &((struct wpa_ssid *) 0)->v) 1354 1355 /* STR: Define a string variable for an ASCII string; f = field name */ 1356 #ifdef NO_CONFIG_WRITE 1357 #define _STR(f) #f, wpa_config_parse_str, OFFSET(f) 1358 #define _STRe(f) #f, wpa_config_parse_str, OFFSET(eap.f) 1359 #else /* NO_CONFIG_WRITE */ 1360 #define _STR(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(f) 1361 #define _STRe(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(eap.f) 1362 #endif /* NO_CONFIG_WRITE */ 1363 #define STR(f) _STR(f), NULL, NULL, NULL, 0 1364 #define STRe(f) _STRe(f), NULL, NULL, NULL, 0 1365 #define STR_KEY(f) _STR(f), NULL, NULL, NULL, 1 1366 #define STR_KEYe(f) _STRe(f), NULL, NULL, NULL, 1 1367 1368 /* STR_LEN: Define a string variable with a separate variable for storing the 1369 * data length. Unlike STR(), this can be used to store arbitrary binary data 1370 * (i.e., even nul termination character). */ 1371 #define _STR_LEN(f) _STR(f), OFFSET(f ## _len) 1372 #define _STR_LENe(f) _STRe(f), OFFSET(eap.f ## _len) 1373 #define STR_LEN(f) _STR_LEN(f), NULL, NULL, 0 1374 #define STR_LENe(f) _STR_LENe(f), NULL, NULL, 0 1375 #define STR_LEN_KEY(f) _STR_LEN(f), NULL, NULL, 1 1376 1377 /* STR_RANGE: Like STR_LEN(), but with minimum and maximum allowed length 1378 * explicitly specified. */ 1379 #define _STR_RANGE(f, min, max) _STR_LEN(f), (void *) (min), (void *) (max) 1380 #define STR_RANGE(f, min, max) _STR_RANGE(f, min, max), 0 1381 #define STR_RANGE_KEY(f, min, max) _STR_RANGE(f, min, max), 1 1382 1383 #ifdef NO_CONFIG_WRITE 1384 #define _INT(f) #f, wpa_config_parse_int, OFFSET(f), (void *) 0 1385 #define _INTe(f) #f, wpa_config_parse_int, OFFSET(eap.f), (void *) 0 1386 #else /* NO_CONFIG_WRITE */ 1387 #define _INT(f) #f, wpa_config_parse_int, wpa_config_write_int, \ 1388 OFFSET(f), (void *) 0 1389 #define _INTe(f) #f, wpa_config_parse_int, wpa_config_write_int, \ 1390 OFFSET(eap.f), (void *) 0 1391 #endif /* NO_CONFIG_WRITE */ 1392 1393 /* INT: Define an integer variable */ 1394 #define INT(f) _INT(f), NULL, NULL, 0 1395 #define INTe(f) _INTe(f), NULL, NULL, 0 1396 1397 /* INT_RANGE: Define an integer variable with allowed value range */ 1398 #define INT_RANGE(f, min, max) _INT(f), (void *) (min), (void *) (max), 0 1399 1400 /* FUNC: Define a configuration variable that uses a custom function for 1401 * parsing and writing the value. */ 1402 #ifdef NO_CONFIG_WRITE 1403 #define _FUNC(f) #f, wpa_config_parse_ ## f, NULL, NULL, NULL, NULL 1404 #else /* NO_CONFIG_WRITE */ 1405 #define _FUNC(f) #f, wpa_config_parse_ ## f, wpa_config_write_ ## f, \ 1406 NULL, NULL, NULL, NULL 1407 #endif /* NO_CONFIG_WRITE */ 1408 #define FUNC(f) _FUNC(f), 0 1409 #define FUNC_KEY(f) _FUNC(f), 1 1410 1411 /* 1412 * Table of network configuration variables. This table is used to parse each 1413 * network configuration variable, e.g., each line in wpa_supplicant.conf file 1414 * that is inside a network block. 1415 * 1416 * This table is generated using the helper macros defined above and with 1417 * generous help from the C pre-processor. The field name is stored as a string 1418 * into .name and for STR and INT types, the offset of the target buffer within 1419 * struct wpa_ssid is stored in .param1. .param2 (if not NULL) is similar 1420 * offset to the field containing the length of the configuration variable. 1421 * .param3 and .param4 can be used to mark the allowed range (length for STR 1422 * and value for INT). 1423 * 1424 * For each configuration line in wpa_supplicant.conf, the parser goes through 1425 * this table and select the entry that matches with the field name. The parser 1426 * function (.parser) is then called to parse the actual value of the field. 1427 * 1428 * This kind of mechanism makes it easy to add new configuration parameters, 1429 * since only one line needs to be added into this table and into the 1430 * struct wpa_ssid definition if the new variable is either a string or 1431 * integer. More complex types will need to use their own parser and writer 1432 * functions. 1433 */ 1434 static const struct parse_data ssid_fields[] = { 1435 { STR_RANGE(ssid, 0, MAX_SSID_LEN) }, 1436 { INT_RANGE(scan_ssid, 0, 1) }, 1437 { FUNC(bssid) }, 1438 { FUNC_KEY(psk) }, 1439 { FUNC(proto) }, 1440 { FUNC(key_mgmt) }, 1441 { FUNC(pairwise) }, 1442 { FUNC(group) }, 1443 { FUNC(auth_alg) }, 1444 { FUNC(scan_freq) }, 1445 { FUNC(freq_list) }, 1446 #ifdef IEEE8021X_EAPOL 1447 { FUNC(eap) }, 1448 { STR_LENe(identity) }, 1449 { STR_LENe(anonymous_identity) }, 1450 { FUNC_KEY(password) }, 1451 { STRe(ca_cert) }, 1452 { STRe(ca_path) }, 1453 { STRe(client_cert) }, 1454 { STRe(private_key) }, 1455 { STR_KEYe(private_key_passwd) }, 1456 { STRe(dh_file) }, 1457 { STRe(subject_match) }, 1458 { STRe(altsubject_match) }, 1459 { STRe(ca_cert2) }, 1460 { STRe(ca_path2) }, 1461 { STRe(client_cert2) }, 1462 { STRe(private_key2) }, 1463 { STR_KEYe(private_key2_passwd) }, 1464 { STRe(dh_file2) }, 1465 { STRe(subject_match2) }, 1466 { STRe(altsubject_match2) }, 1467 { STRe(phase1) }, 1468 { STRe(phase2) }, 1469 { STRe(pcsc) }, 1470 { STR_KEYe(pin) }, 1471 { STRe(engine_id) }, 1472 { STRe(key_id) }, 1473 { STRe(cert_id) }, 1474 { STRe(ca_cert_id) }, 1475 { STR_KEYe(pin2) }, 1476 { STRe(engine2_id) }, 1477 { STRe(key2_id) }, 1478 { STRe(cert2_id) }, 1479 { STRe(ca_cert2_id) }, 1480 { INTe(engine) }, 1481 { INTe(engine2) }, 1482 { INT(eapol_flags) }, 1483 #endif /* IEEE8021X_EAPOL */ 1484 { FUNC_KEY(wep_key0) }, 1485 { FUNC_KEY(wep_key1) }, 1486 { FUNC_KEY(wep_key2) }, 1487 { FUNC_KEY(wep_key3) }, 1488 { INT(wep_tx_keyidx) }, 1489 { INT(priority) }, 1490 #ifdef IEEE8021X_EAPOL 1491 { INT(eap_workaround) }, 1492 { STRe(pac_file) }, 1493 { INTe(fragment_size) }, 1494 #endif /* IEEE8021X_EAPOL */ 1495 { INT_RANGE(mode, 0, 2) }, 1496 { INT_RANGE(proactive_key_caching, 0, 1) }, 1497 { INT_RANGE(disabled, 0, 1) }, 1498 { STR(id_str) }, 1499 #ifdef CONFIG_IEEE80211W 1500 { INT_RANGE(ieee80211w, 0, 2) }, 1501 #endif /* CONFIG_IEEE80211W */ 1502 { INT_RANGE(peerkey, 0, 1) }, 1503 { INT_RANGE(mixed_cell, 0, 1) }, 1504 { INT_RANGE(frequency, 0, 10000) }, 1505 { INT(wpa_ptk_rekey) }, 1506 { STR(bgscan) }, 1507 }; 1508 1509 #undef OFFSET 1510 #undef _STR 1511 #undef STR 1512 #undef STR_KEY 1513 #undef _STR_LEN 1514 #undef STR_LEN 1515 #undef STR_LEN_KEY 1516 #undef _STR_RANGE 1517 #undef STR_RANGE 1518 #undef STR_RANGE_KEY 1519 #undef _INT 1520 #undef INT 1521 #undef INT_RANGE 1522 #undef _FUNC 1523 #undef FUNC 1524 #undef FUNC_KEY 1525 #define NUM_SSID_FIELDS (sizeof(ssid_fields) / sizeof(ssid_fields[0])) 1526 1527 1528 /** 1529 * wpa_config_add_prio_network - Add a network to priority lists 1530 * @config: Configuration data from wpa_config_read() 1531 * @ssid: Pointer to the network configuration to be added to the list 1532 * Returns: 0 on success, -1 on failure 1533 * 1534 * This function is used to add a network block to the priority list of 1535 * networks. This must be called for each network when reading in the full 1536 * configuration. In addition, this can be used indirectly when updating 1537 * priorities by calling wpa_config_update_prio_list(). 1538 */ 1539 int wpa_config_add_prio_network(struct wpa_config *config, 1540 struct wpa_ssid *ssid) 1541 { 1542 int prio; 1543 struct wpa_ssid *prev, **nlist; 1544 1545 /* 1546 * Add to an existing priority list if one is available for the 1547 * configured priority level for this network. 1548 */ 1549 for (prio = 0; prio < config->num_prio; prio++) { 1550 prev = config->pssid[prio]; 1551 if (prev->priority == ssid->priority) { 1552 while (prev->pnext) 1553 prev = prev->pnext; 1554 prev->pnext = ssid; 1555 return 0; 1556 } 1557 } 1558 1559 /* First network for this priority - add a new priority list */ 1560 nlist = os_realloc(config->pssid, 1561 (config->num_prio + 1) * sizeof(struct wpa_ssid *)); 1562 if (nlist == NULL) 1563 return -1; 1564 1565 for (prio = 0; prio < config->num_prio; prio++) { 1566 if (nlist[prio]->priority < ssid->priority) 1567 break; 1568 } 1569 1570 os_memmove(&nlist[prio + 1], &nlist[prio], 1571 (config->num_prio - prio) * sizeof(struct wpa_ssid *)); 1572 1573 nlist[prio] = ssid; 1574 config->num_prio++; 1575 config->pssid = nlist; 1576 1577 return 0; 1578 } 1579 1580 1581 /** 1582 * wpa_config_update_prio_list - Update network priority list 1583 * @config: Configuration data from wpa_config_read() 1584 * Returns: 0 on success, -1 on failure 1585 * 1586 * This function is called to update the priority list of networks in the 1587 * configuration when a network is being added or removed. This is also called 1588 * if a priority for a network is changed. 1589 */ 1590 int wpa_config_update_prio_list(struct wpa_config *config) 1591 { 1592 struct wpa_ssid *ssid; 1593 int ret = 0; 1594 1595 os_free(config->pssid); 1596 config->pssid = NULL; 1597 config->num_prio = 0; 1598 1599 ssid = config->ssid; 1600 while (ssid) { 1601 ssid->pnext = NULL; 1602 if (wpa_config_add_prio_network(config, ssid) < 0) 1603 ret = -1; 1604 ssid = ssid->next; 1605 } 1606 1607 return ret; 1608 } 1609 1610 1611 #ifdef IEEE8021X_EAPOL 1612 static void eap_peer_config_free(struct eap_peer_config *eap) 1613 { 1614 os_free(eap->eap_methods); 1615 os_free(eap->identity); 1616 os_free(eap->anonymous_identity); 1617 os_free(eap->password); 1618 os_free(eap->ca_cert); 1619 os_free(eap->ca_path); 1620 os_free(eap->client_cert); 1621 os_free(eap->private_key); 1622 os_free(eap->private_key_passwd); 1623 os_free(eap->dh_file); 1624 os_free(eap->subject_match); 1625 os_free(eap->altsubject_match); 1626 os_free(eap->ca_cert2); 1627 os_free(eap->ca_path2); 1628 os_free(eap->client_cert2); 1629 os_free(eap->private_key2); 1630 os_free(eap->private_key2_passwd); 1631 os_free(eap->dh_file2); 1632 os_free(eap->subject_match2); 1633 os_free(eap->altsubject_match2); 1634 os_free(eap->phase1); 1635 os_free(eap->phase2); 1636 os_free(eap->pcsc); 1637 os_free(eap->pin); 1638 os_free(eap->engine_id); 1639 os_free(eap->key_id); 1640 os_free(eap->cert_id); 1641 os_free(eap->ca_cert_id); 1642 os_free(eap->key2_id); 1643 os_free(eap->cert2_id); 1644 os_free(eap->ca_cert2_id); 1645 os_free(eap->pin2); 1646 os_free(eap->engine2_id); 1647 os_free(eap->otp); 1648 os_free(eap->pending_req_otp); 1649 os_free(eap->pac_file); 1650 os_free(eap->new_password); 1651 } 1652 #endif /* IEEE8021X_EAPOL */ 1653 1654 1655 /** 1656 * wpa_config_free_ssid - Free network/ssid configuration data 1657 * @ssid: Configuration data for the network 1658 * 1659 * This function frees all resources allocated for the network configuration 1660 * data. 1661 */ 1662 void wpa_config_free_ssid(struct wpa_ssid *ssid) 1663 { 1664 os_free(ssid->ssid); 1665 os_free(ssid->passphrase); 1666 #ifdef IEEE8021X_EAPOL 1667 eap_peer_config_free(&ssid->eap); 1668 #endif /* IEEE8021X_EAPOL */ 1669 os_free(ssid->id_str); 1670 os_free(ssid->scan_freq); 1671 os_free(ssid->freq_list); 1672 os_free(ssid->bgscan); 1673 os_free(ssid); 1674 } 1675 1676 1677 /** 1678 * wpa_config_free - Free configuration data 1679 * @config: Configuration data from wpa_config_read() 1680 * 1681 * This function frees all resources allocated for the configuration data by 1682 * wpa_config_read(). 1683 */ 1684 void wpa_config_free(struct wpa_config *config) 1685 { 1686 #ifndef CONFIG_NO_CONFIG_BLOBS 1687 struct wpa_config_blob *blob, *prevblob; 1688 #endif /* CONFIG_NO_CONFIG_BLOBS */ 1689 struct wpa_ssid *ssid, *prev = NULL; 1690 ssid = config->ssid; 1691 while (ssid) { 1692 prev = ssid; 1693 ssid = ssid->next; 1694 wpa_config_free_ssid(prev); 1695 } 1696 1697 #ifndef CONFIG_NO_CONFIG_BLOBS 1698 blob = config->blobs; 1699 prevblob = NULL; 1700 while (blob) { 1701 prevblob = blob; 1702 blob = blob->next; 1703 wpa_config_free_blob(prevblob); 1704 } 1705 #endif /* CONFIG_NO_CONFIG_BLOBS */ 1706 1707 os_free(config->ctrl_interface); 1708 os_free(config->ctrl_interface_group); 1709 os_free(config->opensc_engine_path); 1710 os_free(config->pkcs11_engine_path); 1711 os_free(config->pkcs11_module_path); 1712 os_free(config->driver_param); 1713 os_free(config->device_name); 1714 os_free(config->manufacturer); 1715 os_free(config->model_name); 1716 os_free(config->model_number); 1717 os_free(config->serial_number); 1718 os_free(config->device_type); 1719 os_free(config->config_methods); 1720 os_free(config->pssid); 1721 os_free(config); 1722 } 1723 1724 1725 /** 1726 * wpa_config_get_network - Get configured network based on id 1727 * @config: Configuration data from wpa_config_read() 1728 * @id: Unique network id to search for 1729 * Returns: Network configuration or %NULL if not found 1730 */ 1731 struct wpa_ssid * wpa_config_get_network(struct wpa_config *config, int id) 1732 { 1733 struct wpa_ssid *ssid; 1734 1735 ssid = config->ssid; 1736 while (ssid) { 1737 if (id == ssid->id) 1738 break; 1739 ssid = ssid->next; 1740 } 1741 1742 return ssid; 1743 } 1744 1745 1746 /** 1747 * wpa_config_add_network - Add a new network with empty configuration 1748 * @config: Configuration data from wpa_config_read() 1749 * Returns: The new network configuration or %NULL if operation failed 1750 */ 1751 struct wpa_ssid * wpa_config_add_network(struct wpa_config *config) 1752 { 1753 int id; 1754 struct wpa_ssid *ssid, *last = NULL; 1755 1756 id = -1; 1757 ssid = config->ssid; 1758 while (ssid) { 1759 if (ssid->id > id) 1760 id = ssid->id; 1761 last = ssid; 1762 ssid = ssid->next; 1763 } 1764 id++; 1765 1766 ssid = os_zalloc(sizeof(*ssid)); 1767 if (ssid == NULL) 1768 return NULL; 1769 ssid->id = id; 1770 if (last) 1771 last->next = ssid; 1772 else 1773 config->ssid = ssid; 1774 1775 wpa_config_update_prio_list(config); 1776 1777 return ssid; 1778 } 1779 1780 1781 /** 1782 * wpa_config_remove_network - Remove a configured network based on id 1783 * @config: Configuration data from wpa_config_read() 1784 * @id: Unique network id to search for 1785 * Returns: 0 on success, or -1 if the network was not found 1786 */ 1787 int wpa_config_remove_network(struct wpa_config *config, int id) 1788 { 1789 struct wpa_ssid *ssid, *prev = NULL; 1790 1791 ssid = config->ssid; 1792 while (ssid) { 1793 if (id == ssid->id) 1794 break; 1795 prev = ssid; 1796 ssid = ssid->next; 1797 } 1798 1799 if (ssid == NULL) 1800 return -1; 1801 1802 if (prev) 1803 prev->next = ssid->next; 1804 else 1805 config->ssid = ssid->next; 1806 1807 wpa_config_update_prio_list(config); 1808 wpa_config_free_ssid(ssid); 1809 return 0; 1810 } 1811 1812 1813 /** 1814 * wpa_config_set_network_defaults - Set network default values 1815 * @ssid: Pointer to network configuration data 1816 */ 1817 void wpa_config_set_network_defaults(struct wpa_ssid *ssid) 1818 { 1819 ssid->proto = DEFAULT_PROTO; 1820 ssid->pairwise_cipher = DEFAULT_PAIRWISE; 1821 ssid->group_cipher = DEFAULT_GROUP; 1822 ssid->key_mgmt = DEFAULT_KEY_MGMT; 1823 #ifdef IEEE8021X_EAPOL 1824 ssid->eapol_flags = DEFAULT_EAPOL_FLAGS; 1825 ssid->eap_workaround = DEFAULT_EAP_WORKAROUND; 1826 ssid->eap.fragment_size = DEFAULT_FRAGMENT_SIZE; 1827 #endif /* IEEE8021X_EAPOL */ 1828 } 1829 1830 1831 /** 1832 * wpa_config_set - Set a variable in network configuration 1833 * @ssid: Pointer to network configuration data 1834 * @var: Variable name, e.g., "ssid" 1835 * @value: Variable value 1836 * @line: Line number in configuration file or 0 if not used 1837 * Returns: 0 on success, -1 on failure 1838 * 1839 * This function can be used to set network configuration variables based on 1840 * both the configuration file and management interface input. The value 1841 * parameter must be in the same format as the text-based configuration file is 1842 * using. For example, strings are using double quotation marks. 1843 */ 1844 int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value, 1845 int line) 1846 { 1847 size_t i; 1848 int ret = 0; 1849 1850 if (ssid == NULL || var == NULL || value == NULL) 1851 return -1; 1852 1853 for (i = 0; i < NUM_SSID_FIELDS; i++) { 1854 const struct parse_data *field = &ssid_fields[i]; 1855 if (os_strcmp(var, field->name) != 0) 1856 continue; 1857 1858 if (field->parser(field, ssid, line, value)) { 1859 if (line) { 1860 wpa_printf(MSG_ERROR, "Line %d: failed to " 1861 "parse %s '%s'.", line, var, value); 1862 } 1863 ret = -1; 1864 } 1865 break; 1866 } 1867 if (i == NUM_SSID_FIELDS) { 1868 if (line) { 1869 wpa_printf(MSG_ERROR, "Line %d: unknown network field " 1870 "'%s'.", line, var); 1871 } 1872 ret = -1; 1873 } 1874 1875 return ret; 1876 } 1877 1878 1879 /** 1880 * wpa_config_get_all - Get all options from network configuration 1881 * @ssid: Pointer to network configuration data 1882 * @get_keys: Determines if keys/passwords will be included in returned list 1883 * Returns: %NULL terminated list of all set keys and their values in the form 1884 * of [key1, val1, key2, val2, ... , NULL] 1885 * 1886 * This function can be used to get list of all configured network properties. 1887 * The caller is responsible for freeing the returned list and all its 1888 * elements. 1889 */ 1890 char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys) 1891 { 1892 const struct parse_data *field; 1893 char *key, *value; 1894 size_t i; 1895 char **props; 1896 int fields_num; 1897 1898 props = os_zalloc(sizeof(char *) * ((2 * NUM_SSID_FIELDS) + 1)); 1899 if (!props) 1900 return NULL; 1901 1902 fields_num = 0; 1903 for (i = 0; i < NUM_SSID_FIELDS; i++) { 1904 field = &ssid_fields[i]; 1905 if (field->key_data && !get_keys) 1906 continue; 1907 value = field->writer(field, ssid); 1908 if (value == NULL) 1909 continue; 1910 if (os_strlen(value) == 0) { 1911 os_free(value); 1912 continue; 1913 } 1914 1915 key = os_strdup(field->name); 1916 if (key == NULL) { 1917 os_free(value); 1918 goto err; 1919 } 1920 1921 props[fields_num * 2] = key; 1922 props[fields_num * 2 + 1] = value; 1923 1924 fields_num++; 1925 } 1926 1927 return props; 1928 1929 err: 1930 value = *props; 1931 while (value) 1932 os_free(value++); 1933 os_free(props); 1934 return NULL; 1935 } 1936 1937 1938 #ifndef NO_CONFIG_WRITE 1939 /** 1940 * wpa_config_get - Get a variable in network configuration 1941 * @ssid: Pointer to network configuration data 1942 * @var: Variable name, e.g., "ssid" 1943 * Returns: Value of the variable or %NULL on failure 1944 * 1945 * This function can be used to get network configuration variables. The 1946 * returned value is a copy of the configuration variable in text format, i.e,. 1947 * the same format that the text-based configuration file and wpa_config_set() 1948 * are using for the value. The caller is responsible for freeing the returned 1949 * value. 1950 */ 1951 char * wpa_config_get(struct wpa_ssid *ssid, const char *var) 1952 { 1953 size_t i; 1954 1955 if (ssid == NULL || var == NULL) 1956 return NULL; 1957 1958 for (i = 0; i < NUM_SSID_FIELDS; i++) { 1959 const struct parse_data *field = &ssid_fields[i]; 1960 if (os_strcmp(var, field->name) == 0) 1961 return field->writer(field, ssid); 1962 } 1963 1964 return NULL; 1965 } 1966 1967 1968 /** 1969 * wpa_config_get_no_key - Get a variable in network configuration (no keys) 1970 * @ssid: Pointer to network configuration data 1971 * @var: Variable name, e.g., "ssid" 1972 * Returns: Value of the variable or %NULL on failure 1973 * 1974 * This function can be used to get network configuration variable like 1975 * wpa_config_get(). The only difference is that this functions does not expose 1976 * key/password material from the configuration. In case a key/password field 1977 * is requested, the returned value is an empty string or %NULL if the variable 1978 * is not set or "*" if the variable is set (regardless of its value). The 1979 * returned value is a copy of the configuration variable in text format, i.e,. 1980 * the same format that the text-based configuration file and wpa_config_set() 1981 * are using for the value. The caller is responsible for freeing the returned 1982 * value. 1983 */ 1984 char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var) 1985 { 1986 size_t i; 1987 1988 if (ssid == NULL || var == NULL) 1989 return NULL; 1990 1991 for (i = 0; i < NUM_SSID_FIELDS; i++) { 1992 const struct parse_data *field = &ssid_fields[i]; 1993 if (os_strcmp(var, field->name) == 0) { 1994 char *res = field->writer(field, ssid); 1995 if (field->key_data) { 1996 if (res && res[0]) { 1997 wpa_printf(MSG_DEBUG, "Do not allow " 1998 "key_data field to be " 1999 "exposed"); 2000 os_free(res); 2001 return os_strdup("*"); 2002 } 2003 2004 os_free(res); 2005 return NULL; 2006 } 2007 return res; 2008 } 2009 } 2010 2011 return NULL; 2012 } 2013 #endif /* NO_CONFIG_WRITE */ 2014 2015 2016 /** 2017 * wpa_config_update_psk - Update WPA PSK based on passphrase and SSID 2018 * @ssid: Pointer to network configuration data 2019 * 2020 * This function must be called to update WPA PSK when either SSID or the 2021 * passphrase has changed for the network configuration. 2022 */ 2023 void wpa_config_update_psk(struct wpa_ssid *ssid) 2024 { 2025 #ifndef CONFIG_NO_PBKDF2 2026 pbkdf2_sha1(ssid->passphrase, 2027 (char *) ssid->ssid, ssid->ssid_len, 4096, 2028 ssid->psk, PMK_LEN); 2029 wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)", 2030 ssid->psk, PMK_LEN); 2031 ssid->psk_set = 1; 2032 #endif /* CONFIG_NO_PBKDF2 */ 2033 } 2034 2035 2036 #ifndef CONFIG_NO_CONFIG_BLOBS 2037 /** 2038 * wpa_config_get_blob - Get a named configuration blob 2039 * @config: Configuration data from wpa_config_read() 2040 * @name: Name of the blob 2041 * Returns: Pointer to blob data or %NULL if not found 2042 */ 2043 const struct wpa_config_blob * wpa_config_get_blob(struct wpa_config *config, 2044 const char *name) 2045 { 2046 struct wpa_config_blob *blob = config->blobs; 2047 2048 while (blob) { 2049 if (os_strcmp(blob->name, name) == 0) 2050 return blob; 2051 blob = blob->next; 2052 } 2053 return NULL; 2054 } 2055 2056 2057 /** 2058 * wpa_config_set_blob - Set or add a named configuration blob 2059 * @config: Configuration data from wpa_config_read() 2060 * @blob: New value for the blob 2061 * 2062 * Adds a new configuration blob or replaces the current value of an existing 2063 * blob. 2064 */ 2065 void wpa_config_set_blob(struct wpa_config *config, 2066 struct wpa_config_blob *blob) 2067 { 2068 wpa_config_remove_blob(config, blob->name); 2069 blob->next = config->blobs; 2070 config->blobs = blob; 2071 } 2072 2073 2074 /** 2075 * wpa_config_free_blob - Free blob data 2076 * @blob: Pointer to blob to be freed 2077 */ 2078 void wpa_config_free_blob(struct wpa_config_blob *blob) 2079 { 2080 if (blob) { 2081 os_free(blob->name); 2082 os_free(blob->data); 2083 os_free(blob); 2084 } 2085 } 2086 2087 2088 /** 2089 * wpa_config_remove_blob - Remove a named configuration blob 2090 * @config: Configuration data from wpa_config_read() 2091 * @name: Name of the blob to remove 2092 * Returns: 0 if blob was removed or -1 if blob was not found 2093 */ 2094 int wpa_config_remove_blob(struct wpa_config *config, const char *name) 2095 { 2096 struct wpa_config_blob *pos = config->blobs, *prev = NULL; 2097 2098 while (pos) { 2099 if (os_strcmp(pos->name, name) == 0) { 2100 if (prev) 2101 prev->next = pos->next; 2102 else 2103 config->blobs = pos->next; 2104 wpa_config_free_blob(pos); 2105 return 0; 2106 } 2107 prev = pos; 2108 pos = pos->next; 2109 } 2110 2111 return -1; 2112 } 2113 #endif /* CONFIG_NO_CONFIG_BLOBS */ 2114 2115 2116 /** 2117 * wpa_config_alloc_empty - Allocate an empty configuration 2118 * @ctrl_interface: Control interface parameters, e.g., path to UNIX domain 2119 * socket 2120 * @driver_param: Driver parameters 2121 * Returns: Pointer to allocated configuration data or %NULL on failure 2122 */ 2123 struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface, 2124 const char *driver_param) 2125 { 2126 struct wpa_config *config; 2127 2128 config = os_zalloc(sizeof(*config)); 2129 if (config == NULL) 2130 return NULL; 2131 config->eapol_version = DEFAULT_EAPOL_VERSION; 2132 config->ap_scan = DEFAULT_AP_SCAN; 2133 config->fast_reauth = DEFAULT_FAST_REAUTH; 2134 config->bss_max_count = DEFAULT_BSS_MAX_COUNT; 2135 2136 if (ctrl_interface) 2137 config->ctrl_interface = os_strdup(ctrl_interface); 2138 if (driver_param) 2139 config->driver_param = os_strdup(driver_param); 2140 2141 return config; 2142 } 2143 2144 2145 #ifndef CONFIG_NO_STDOUT_DEBUG 2146 /** 2147 * wpa_config_debug_dump_networks - Debug dump of configured networks 2148 * @config: Configuration data from wpa_config_read() 2149 */ 2150 void wpa_config_debug_dump_networks(struct wpa_config *config) 2151 { 2152 int prio; 2153 struct wpa_ssid *ssid; 2154 2155 for (prio = 0; prio < config->num_prio; prio++) { 2156 ssid = config->pssid[prio]; 2157 wpa_printf(MSG_DEBUG, "Priority group %d", 2158 ssid->priority); 2159 while (ssid) { 2160 wpa_printf(MSG_DEBUG, " id=%d ssid='%s'", 2161 ssid->id, 2162 wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); 2163 ssid = ssid->pnext; 2164 } 2165 } 2166 } 2167 #endif /* CONFIG_NO_STDOUT_DEBUG */ 2168