1 /* 2 * Interworking (IEEE 802.11u) 3 * Copyright (c) 2011-2012, Qualcomm Atheros, Inc. 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9 #include "includes.h" 10 11 #include "common.h" 12 #include "common/ieee802_11_defs.h" 13 #include "common/gas.h" 14 #include "common/wpa_ctrl.h" 15 #include "utils/pcsc_funcs.h" 16 #include "drivers/driver.h" 17 #include "eap_common/eap_defs.h" 18 #include "eap_peer/eap.h" 19 #include "eap_peer/eap_methods.h" 20 #include "wpa_supplicant_i.h" 21 #include "config.h" 22 #include "config_ssid.h" 23 #include "bss.h" 24 #include "scan.h" 25 #include "notify.h" 26 #include "gas_query.h" 27 #include "hs20_supplicant.h" 28 #include "interworking.h" 29 30 31 #if defined(EAP_SIM) | defined(EAP_SIM_DYNAMIC) 32 #define INTERWORKING_3GPP 33 #else 34 #if defined(EAP_AKA) | defined(EAP_AKA_DYNAMIC) 35 #define INTERWORKING_3GPP 36 #else 37 #if defined(EAP_AKA_PRIME) | defined(EAP_AKA_PRIME_DYNAMIC) 38 #define INTERWORKING_3GPP 39 #endif 40 #endif 41 #endif 42 43 static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s); 44 45 46 static void interworking_reconnect(struct wpa_supplicant *wpa_s) 47 { 48 if (wpa_s->wpa_state >= WPA_AUTHENTICATING) { 49 wpa_supplicant_cancel_sched_scan(wpa_s); 50 wpa_supplicant_deauthenticate(wpa_s, 51 WLAN_REASON_DEAUTH_LEAVING); 52 } 53 wpa_s->disconnected = 0; 54 wpa_s->reassociate = 1; 55 56 if (wpa_s->last_scan_res_used > 0) { 57 struct os_time now; 58 os_get_time(&now); 59 if (now.sec - wpa_s->last_scan.sec <= 5) { 60 wpa_printf(MSG_DEBUG, "Interworking: Old scan results " 61 "are fresh - connect without new scan"); 62 if (wpas_select_network_from_last_scan(wpa_s) >= 0) 63 return; 64 } 65 } 66 67 wpa_supplicant_req_scan(wpa_s, 0, 0); 68 } 69 70 71 static struct wpabuf * anqp_build_req(u16 info_ids[], size_t num_ids, 72 struct wpabuf *extra) 73 { 74 struct wpabuf *buf; 75 size_t i; 76 u8 *len_pos; 77 78 buf = gas_anqp_build_initial_req(0, 4 + num_ids * 2 + 79 (extra ? wpabuf_len(extra) : 0)); 80 if (buf == NULL) 81 return NULL; 82 83 len_pos = gas_anqp_add_element(buf, ANQP_QUERY_LIST); 84 for (i = 0; i < num_ids; i++) 85 wpabuf_put_le16(buf, info_ids[i]); 86 gas_anqp_set_element_len(buf, len_pos); 87 if (extra) 88 wpabuf_put_buf(buf, extra); 89 90 gas_anqp_set_len(buf); 91 92 return buf; 93 } 94 95 96 static void interworking_anqp_resp_cb(void *ctx, const u8 *dst, 97 u8 dialog_token, 98 enum gas_query_result result, 99 const struct wpabuf *adv_proto, 100 const struct wpabuf *resp, 101 u16 status_code) 102 { 103 struct wpa_supplicant *wpa_s = ctx; 104 105 anqp_resp_cb(wpa_s, dst, dialog_token, result, adv_proto, resp, 106 status_code); 107 interworking_next_anqp_fetch(wpa_s); 108 } 109 110 111 static int cred_with_roaming_consortium(struct wpa_supplicant *wpa_s) 112 { 113 struct wpa_cred *cred; 114 115 for (cred = wpa_s->conf->cred; cred; cred = cred->next) { 116 if (cred->roaming_consortium_len) 117 return 1; 118 } 119 return 0; 120 } 121 122 123 static int cred_with_3gpp(struct wpa_supplicant *wpa_s) 124 { 125 struct wpa_cred *cred; 126 127 for (cred = wpa_s->conf->cred; cred; cred = cred->next) { 128 if (cred->pcsc || cred->imsi) 129 return 1; 130 } 131 return 0; 132 } 133 134 135 static int cred_with_nai_realm(struct wpa_supplicant *wpa_s) 136 { 137 struct wpa_cred *cred; 138 139 for (cred = wpa_s->conf->cred; cred; cred = cred->next) { 140 if (cred->pcsc || cred->imsi) 141 continue; 142 if (!cred->eap_method) 143 return 1; 144 if (cred->realm && cred->roaming_consortium_len == 0) 145 return 1; 146 } 147 return 0; 148 } 149 150 151 static int cred_with_domain(struct wpa_supplicant *wpa_s) 152 { 153 struct wpa_cred *cred; 154 155 for (cred = wpa_s->conf->cred; cred; cred = cred->next) { 156 if (cred->domain || cred->pcsc || cred->imsi) 157 return 1; 158 } 159 return 0; 160 } 161 162 163 static int additional_roaming_consortiums(struct wpa_bss *bss) 164 { 165 const u8 *ie; 166 ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM); 167 if (ie == NULL || ie[1] == 0) 168 return 0; 169 return ie[2]; /* Number of ANQP OIs */ 170 } 171 172 173 static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s, 174 struct wpa_bss *bss) 175 { 176 struct wpabuf *buf; 177 int ret = 0; 178 int res; 179 u16 info_ids[8]; 180 size_t num_info_ids = 0; 181 struct wpabuf *extra = NULL; 182 int all = wpa_s->fetch_all_anqp; 183 184 wpa_printf(MSG_DEBUG, "Interworking: ANQP Query Request to " MACSTR, 185 MAC2STR(bss->bssid)); 186 187 info_ids[num_info_ids++] = ANQP_CAPABILITY_LIST; 188 if (all) { 189 info_ids[num_info_ids++] = ANQP_VENUE_NAME; 190 info_ids[num_info_ids++] = ANQP_NETWORK_AUTH_TYPE; 191 } 192 if (all || (cred_with_roaming_consortium(wpa_s) && 193 additional_roaming_consortiums(bss))) 194 info_ids[num_info_ids++] = ANQP_ROAMING_CONSORTIUM; 195 if (all) 196 info_ids[num_info_ids++] = ANQP_IP_ADDR_TYPE_AVAILABILITY; 197 if (all || cred_with_nai_realm(wpa_s)) 198 info_ids[num_info_ids++] = ANQP_NAI_REALM; 199 if (all || cred_with_3gpp(wpa_s)) 200 info_ids[num_info_ids++] = ANQP_3GPP_CELLULAR_NETWORK; 201 if (all || cred_with_domain(wpa_s)) 202 info_ids[num_info_ids++] = ANQP_DOMAIN_NAME; 203 wpa_hexdump(MSG_DEBUG, "Interworking: ANQP Query info", 204 (u8 *) info_ids, num_info_ids * 2); 205 206 #ifdef CONFIG_HS20 207 if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) { 208 u8 *len_pos; 209 210 extra = wpabuf_alloc(100); 211 if (!extra) 212 return -1; 213 214 len_pos = gas_anqp_add_element(extra, ANQP_VENDOR_SPECIFIC); 215 wpabuf_put_be24(extra, OUI_WFA); 216 wpabuf_put_u8(extra, HS20_ANQP_OUI_TYPE); 217 wpabuf_put_u8(extra, HS20_STYPE_QUERY_LIST); 218 wpabuf_put_u8(extra, 0); /* Reserved */ 219 wpabuf_put_u8(extra, HS20_STYPE_CAPABILITY_LIST); 220 if (all) { 221 wpabuf_put_u8(extra, 222 HS20_STYPE_OPERATOR_FRIENDLY_NAME); 223 wpabuf_put_u8(extra, HS20_STYPE_WAN_METRICS); 224 wpabuf_put_u8(extra, HS20_STYPE_CONNECTION_CAPABILITY); 225 wpabuf_put_u8(extra, HS20_STYPE_OPERATING_CLASS); 226 } 227 gas_anqp_set_element_len(extra, len_pos); 228 } 229 #endif /* CONFIG_HS20 */ 230 231 buf = anqp_build_req(info_ids, num_info_ids, extra); 232 wpabuf_free(extra); 233 if (buf == NULL) 234 return -1; 235 236 res = gas_query_req(wpa_s->gas, bss->bssid, bss->freq, buf, 237 interworking_anqp_resp_cb, wpa_s); 238 if (res < 0) { 239 wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request"); 240 ret = -1; 241 } else 242 wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token " 243 "%u", res); 244 245 wpabuf_free(buf); 246 return ret; 247 } 248 249 250 struct nai_realm_eap { 251 u8 method; 252 u8 inner_method; 253 enum nai_realm_eap_auth_inner_non_eap inner_non_eap; 254 u8 cred_type; 255 u8 tunneled_cred_type; 256 }; 257 258 struct nai_realm { 259 u8 encoding; 260 char *realm; 261 u8 eap_count; 262 struct nai_realm_eap *eap; 263 }; 264 265 266 static void nai_realm_free(struct nai_realm *realms, u16 count) 267 { 268 u16 i; 269 270 if (realms == NULL) 271 return; 272 for (i = 0; i < count; i++) { 273 os_free(realms[i].eap); 274 os_free(realms[i].realm); 275 } 276 os_free(realms); 277 } 278 279 280 static const u8 * nai_realm_parse_eap(struct nai_realm_eap *e, const u8 *pos, 281 const u8 *end) 282 { 283 u8 elen, auth_count, a; 284 const u8 *e_end; 285 286 if (pos + 3 > end) { 287 wpa_printf(MSG_DEBUG, "No room for EAP Method fixed fields"); 288 return NULL; 289 } 290 291 elen = *pos++; 292 if (pos + elen > end || elen < 2) { 293 wpa_printf(MSG_DEBUG, "No room for EAP Method subfield"); 294 return NULL; 295 } 296 e_end = pos + elen; 297 e->method = *pos++; 298 auth_count = *pos++; 299 wpa_printf(MSG_DEBUG, "EAP Method: len=%u method=%u auth_count=%u", 300 elen, e->method, auth_count); 301 302 for (a = 0; a < auth_count; a++) { 303 u8 id, len; 304 305 if (pos + 2 > end || pos + 2 + pos[1] > end) { 306 wpa_printf(MSG_DEBUG, "No room for Authentication " 307 "Parameter subfield"); 308 return NULL; 309 } 310 311 id = *pos++; 312 len = *pos++; 313 314 switch (id) { 315 case NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH: 316 if (len < 1) 317 break; 318 e->inner_non_eap = *pos; 319 if (e->method != EAP_TYPE_TTLS) 320 break; 321 switch (*pos) { 322 case NAI_REALM_INNER_NON_EAP_PAP: 323 wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP"); 324 break; 325 case NAI_REALM_INNER_NON_EAP_CHAP: 326 wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP"); 327 break; 328 case NAI_REALM_INNER_NON_EAP_MSCHAP: 329 wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP"); 330 break; 331 case NAI_REALM_INNER_NON_EAP_MSCHAPV2: 332 wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2"); 333 break; 334 } 335 break; 336 case NAI_REALM_EAP_AUTH_INNER_AUTH_EAP_METHOD: 337 if (len < 1) 338 break; 339 e->inner_method = *pos; 340 wpa_printf(MSG_DEBUG, "Inner EAP method: %u", 341 e->inner_method); 342 break; 343 case NAI_REALM_EAP_AUTH_CRED_TYPE: 344 if (len < 1) 345 break; 346 e->cred_type = *pos; 347 wpa_printf(MSG_DEBUG, "Credential Type: %u", 348 e->cred_type); 349 break; 350 case NAI_REALM_EAP_AUTH_TUNNELED_CRED_TYPE: 351 if (len < 1) 352 break; 353 e->tunneled_cred_type = *pos; 354 wpa_printf(MSG_DEBUG, "Tunneled EAP Method Credential " 355 "Type: %u", e->tunneled_cred_type); 356 break; 357 default: 358 wpa_printf(MSG_DEBUG, "Unsupported Authentication " 359 "Parameter: id=%u len=%u", id, len); 360 wpa_hexdump(MSG_DEBUG, "Authentication Parameter " 361 "Value", pos, len); 362 break; 363 } 364 365 pos += len; 366 } 367 368 return e_end; 369 } 370 371 372 static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos, 373 const u8 *end) 374 { 375 u16 len; 376 const u8 *f_end; 377 u8 realm_len, e; 378 379 if (end - pos < 4) { 380 wpa_printf(MSG_DEBUG, "No room for NAI Realm Data " 381 "fixed fields"); 382 return NULL; 383 } 384 385 len = WPA_GET_LE16(pos); /* NAI Realm Data field Length */ 386 pos += 2; 387 if (pos + len > end || len < 3) { 388 wpa_printf(MSG_DEBUG, "No room for NAI Realm Data " 389 "(len=%u; left=%u)", 390 len, (unsigned int) (end - pos)); 391 return NULL; 392 } 393 f_end = pos + len; 394 395 r->encoding = *pos++; 396 realm_len = *pos++; 397 if (pos + realm_len > f_end) { 398 wpa_printf(MSG_DEBUG, "No room for NAI Realm " 399 "(len=%u; left=%u)", 400 realm_len, (unsigned int) (f_end - pos)); 401 return NULL; 402 } 403 wpa_hexdump_ascii(MSG_DEBUG, "NAI Realm", pos, realm_len); 404 r->realm = os_malloc(realm_len + 1); 405 if (r->realm == NULL) 406 return NULL; 407 os_memcpy(r->realm, pos, realm_len); 408 r->realm[realm_len] = '\0'; 409 pos += realm_len; 410 411 if (pos + 1 > f_end) { 412 wpa_printf(MSG_DEBUG, "No room for EAP Method Count"); 413 return NULL; 414 } 415 r->eap_count = *pos++; 416 wpa_printf(MSG_DEBUG, "EAP Count: %u", r->eap_count); 417 if (pos + r->eap_count * 3 > f_end) { 418 wpa_printf(MSG_DEBUG, "No room for EAP Methods"); 419 return NULL; 420 } 421 r->eap = os_calloc(r->eap_count, sizeof(struct nai_realm_eap)); 422 if (r->eap == NULL) 423 return NULL; 424 425 for (e = 0; e < r->eap_count; e++) { 426 pos = nai_realm_parse_eap(&r->eap[e], pos, f_end); 427 if (pos == NULL) 428 return NULL; 429 } 430 431 return f_end; 432 } 433 434 435 static struct nai_realm * nai_realm_parse(struct wpabuf *anqp, u16 *count) 436 { 437 struct nai_realm *realm; 438 const u8 *pos, *end; 439 u16 i, num; 440 441 if (anqp == NULL || wpabuf_len(anqp) < 2) 442 return NULL; 443 444 pos = wpabuf_head_u8(anqp); 445 end = pos + wpabuf_len(anqp); 446 num = WPA_GET_LE16(pos); 447 wpa_printf(MSG_DEBUG, "NAI Realm Count: %u", num); 448 pos += 2; 449 450 if (num * 5 > end - pos) { 451 wpa_printf(MSG_DEBUG, "Invalid NAI Realm Count %u - not " 452 "enough data (%u octets) for that many realms", 453 num, (unsigned int) (end - pos)); 454 return NULL; 455 } 456 457 realm = os_calloc(num, sizeof(struct nai_realm)); 458 if (realm == NULL) 459 return NULL; 460 461 for (i = 0; i < num; i++) { 462 pos = nai_realm_parse_realm(&realm[i], pos, end); 463 if (pos == NULL) { 464 nai_realm_free(realm, num); 465 return NULL; 466 } 467 } 468 469 *count = num; 470 return realm; 471 } 472 473 474 static int nai_realm_match(struct nai_realm *realm, const char *home_realm) 475 { 476 char *tmp, *pos, *end; 477 int match = 0; 478 479 if (realm->realm == NULL || home_realm == NULL) 480 return 0; 481 482 if (os_strchr(realm->realm, ';') == NULL) 483 return os_strcasecmp(realm->realm, home_realm) == 0; 484 485 tmp = os_strdup(realm->realm); 486 if (tmp == NULL) 487 return 0; 488 489 pos = tmp; 490 while (*pos) { 491 end = os_strchr(pos, ';'); 492 if (end) 493 *end = '\0'; 494 if (os_strcasecmp(pos, home_realm) == 0) { 495 match = 1; 496 break; 497 } 498 if (end == NULL) 499 break; 500 pos = end + 1; 501 } 502 503 os_free(tmp); 504 505 return match; 506 } 507 508 509 static int nai_realm_cred_username(struct nai_realm_eap *eap) 510 { 511 if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL) 512 return 0; /* method not supported */ 513 514 if (eap->method != EAP_TYPE_TTLS && eap->method != EAP_TYPE_PEAP) { 515 /* Only tunneled methods with username/password supported */ 516 return 0; 517 } 518 519 if (eap->method == EAP_TYPE_PEAP && 520 eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL) 521 return 0; 522 523 if (eap->method == EAP_TYPE_TTLS) { 524 if (eap->inner_method == 0 && eap->inner_non_eap == 0) 525 return 0; 526 if (eap->inner_method && 527 eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL) 528 return 0; 529 if (eap->inner_non_eap && 530 eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_PAP && 531 eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_CHAP && 532 eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAP && 533 eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAPV2) 534 return 0; 535 } 536 537 if (eap->inner_method && 538 eap->inner_method != EAP_TYPE_GTC && 539 eap->inner_method != EAP_TYPE_MSCHAPV2) 540 return 0; 541 542 return 1; 543 } 544 545 546 static int nai_realm_cred_cert(struct nai_realm_eap *eap) 547 { 548 if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL) 549 return 0; /* method not supported */ 550 551 if (eap->method != EAP_TYPE_TLS) { 552 /* Only EAP-TLS supported for credential authentication */ 553 return 0; 554 } 555 556 return 1; 557 } 558 559 560 static struct nai_realm_eap * nai_realm_find_eap(struct wpa_cred *cred, 561 struct nai_realm *realm) 562 { 563 u8 e; 564 565 if (cred == NULL || 566 cred->username == NULL || 567 cred->username[0] == '\0' || 568 ((cred->password == NULL || 569 cred->password[0] == '\0') && 570 (cred->private_key == NULL || 571 cred->private_key[0] == '\0'))) 572 return NULL; 573 574 for (e = 0; e < realm->eap_count; e++) { 575 struct nai_realm_eap *eap = &realm->eap[e]; 576 if (cred->password && cred->password[0] && 577 nai_realm_cred_username(eap)) 578 return eap; 579 if (cred->private_key && cred->private_key[0] && 580 nai_realm_cred_cert(eap)) 581 return eap; 582 } 583 584 return NULL; 585 } 586 587 588 #ifdef INTERWORKING_3GPP 589 590 static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len) 591 { 592 u8 plmn[3]; 593 const u8 *pos, *end; 594 u8 udhl; 595 596 /* See Annex A of 3GPP TS 24.234 v8.1.0 for description */ 597 plmn[0] = (imsi[0] - '0') | ((imsi[1] - '0') << 4); 598 plmn[1] = imsi[2] - '0'; 599 /* default to MNC length 3 if unknown */ 600 if (mnc_len != 2) 601 plmn[1] |= (imsi[5] - '0') << 4; 602 else 603 plmn[1] |= 0xf0; 604 plmn[2] = (imsi[3] - '0') | ((imsi[4] - '0') << 4); 605 606 if (anqp == NULL) 607 return 0; 608 pos = wpabuf_head_u8(anqp); 609 end = pos + wpabuf_len(anqp); 610 if (pos + 2 > end) 611 return 0; 612 if (*pos != 0) { 613 wpa_printf(MSG_DEBUG, "Unsupported GUD version 0x%x", *pos); 614 return 0; 615 } 616 pos++; 617 udhl = *pos++; 618 if (pos + udhl > end) { 619 wpa_printf(MSG_DEBUG, "Invalid UDHL"); 620 return 0; 621 } 622 end = pos + udhl; 623 624 while (pos + 2 <= end) { 625 u8 iei, len; 626 const u8 *l_end; 627 iei = *pos++; 628 len = *pos++ & 0x7f; 629 if (pos + len > end) 630 break; 631 l_end = pos + len; 632 633 if (iei == 0 && len > 0) { 634 /* PLMN List */ 635 u8 num, i; 636 num = *pos++; 637 for (i = 0; i < num; i++) { 638 if (pos + 3 > end) 639 break; 640 if (os_memcmp(pos, plmn, 3) == 0) 641 return 1; /* Found matching PLMN */ 642 pos += 3; 643 } 644 } 645 646 pos = l_end; 647 } 648 649 return 0; 650 } 651 652 653 static int build_root_nai(char *nai, size_t nai_len, const char *imsi, 654 size_t mnc_len, char prefix) 655 { 656 const char *sep, *msin; 657 char *end, *pos; 658 size_t msin_len, plmn_len; 659 660 /* 661 * TS 23.003, Clause 14 (3GPP to WLAN Interworking) 662 * Root NAI: 663 * <aka:0|sim:1><IMSI>@wlan.mnc<MNC>.mcc<MCC>.3gppnetwork.org 664 * <MNC> is zero-padded to three digits in case two-digit MNC is used 665 */ 666 667 if (imsi == NULL || os_strlen(imsi) > 16) { 668 wpa_printf(MSG_DEBUG, "No valid IMSI available"); 669 return -1; 670 } 671 sep = os_strchr(imsi, '-'); 672 if (sep) { 673 plmn_len = sep - imsi; 674 msin = sep + 1; 675 } else if (mnc_len && os_strlen(imsi) >= 3 + mnc_len) { 676 plmn_len = 3 + mnc_len; 677 msin = imsi + plmn_len; 678 } else 679 return -1; 680 if (plmn_len != 5 && plmn_len != 6) 681 return -1; 682 msin_len = os_strlen(msin); 683 684 pos = nai; 685 end = nai + nai_len; 686 if (prefix) 687 *pos++ = prefix; 688 os_memcpy(pos, imsi, plmn_len); 689 pos += plmn_len; 690 os_memcpy(pos, msin, msin_len); 691 pos += msin_len; 692 pos += os_snprintf(pos, end - pos, "@wlan.mnc"); 693 if (plmn_len == 5) { 694 *pos++ = '0'; 695 *pos++ = imsi[3]; 696 *pos++ = imsi[4]; 697 } else { 698 *pos++ = imsi[3]; 699 *pos++ = imsi[4]; 700 *pos++ = imsi[5]; 701 } 702 pos += os_snprintf(pos, end - pos, ".mcc%c%c%c.3gppnetwork.org", 703 imsi[0], imsi[1], imsi[2]); 704 705 return 0; 706 } 707 708 709 static int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix) 710 { 711 char nai[100]; 712 if (build_root_nai(nai, sizeof(nai), imsi, 0, prefix) < 0) 713 return -1; 714 return wpa_config_set_quoted(ssid, "identity", nai); 715 } 716 717 #endif /* INTERWORKING_3GPP */ 718 719 720 static int interworking_set_hs20_params(struct wpa_ssid *ssid) 721 { 722 if (wpa_config_set(ssid, "key_mgmt", "WPA-EAP", 0) < 0) 723 return -1; 724 if (wpa_config_set(ssid, "proto", "RSN", 0) < 0) 725 return -1; 726 if (wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0) 727 return -1; 728 return 0; 729 } 730 731 732 static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s, 733 struct wpa_bss *bss) 734 { 735 #ifdef INTERWORKING_3GPP 736 struct wpa_cred *cred; 737 struct wpa_ssid *ssid; 738 const u8 *ie; 739 int eap_type; 740 int res; 741 char prefix; 742 743 if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL) 744 return -1; 745 746 for (cred = wpa_s->conf->cred; cred; cred = cred->next) { 747 char *sep; 748 const char *imsi; 749 int mnc_len; 750 751 #ifdef PCSC_FUNCS 752 if (cred->pcsc && wpa_s->conf->pcsc_reader && wpa_s->scard && 753 wpa_s->imsi[0]) { 754 imsi = wpa_s->imsi; 755 mnc_len = wpa_s->mnc_len; 756 goto compare; 757 } 758 #endif /* PCSC_FUNCS */ 759 760 if (cred->imsi == NULL || !cred->imsi[0] || 761 cred->milenage == NULL || !cred->milenage[0]) 762 continue; 763 764 sep = os_strchr(cred->imsi, '-'); 765 if (sep == NULL || 766 (sep - cred->imsi != 5 && sep - cred->imsi != 6)) 767 continue; 768 mnc_len = sep - cred->imsi - 3; 769 imsi = cred->imsi; 770 771 #ifdef PCSC_FUNCS 772 compare: 773 #endif /* PCSC_FUNCS */ 774 if (plmn_id_match(bss->anqp->anqp_3gpp, imsi, mnc_len)) 775 break; 776 } 777 if (cred == NULL) 778 return -1; 779 780 ie = wpa_bss_get_ie(bss, WLAN_EID_SSID); 781 if (ie == NULL) 782 return -1; 783 wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " (3GPP)", 784 MAC2STR(bss->bssid)); 785 786 ssid = wpa_config_add_network(wpa_s->conf); 787 if (ssid == NULL) 788 return -1; 789 790 wpas_notify_network_added(wpa_s, ssid); 791 wpa_config_set_network_defaults(ssid); 792 ssid->priority = cred->priority; 793 ssid->temporary = 1; 794 ssid->ssid = os_zalloc(ie[1] + 1); 795 if (ssid->ssid == NULL) 796 goto fail; 797 os_memcpy(ssid->ssid, ie + 2, ie[1]); 798 ssid->ssid_len = ie[1]; 799 800 if (interworking_set_hs20_params(ssid) < 0) 801 goto fail; 802 803 eap_type = EAP_TYPE_SIM; 804 if (cred->pcsc && wpa_s->scard && scard_supports_umts(wpa_s->scard)) 805 eap_type = EAP_TYPE_AKA; 806 if (cred->eap_method && cred->eap_method[0].vendor == EAP_VENDOR_IETF) { 807 if (cred->eap_method[0].method == EAP_TYPE_SIM || 808 cred->eap_method[0].method == EAP_TYPE_AKA || 809 cred->eap_method[0].method == EAP_TYPE_AKA_PRIME) 810 eap_type = cred->eap_method[0].method; 811 } 812 813 switch (eap_type) { 814 case EAP_TYPE_SIM: 815 prefix = '1'; 816 res = wpa_config_set(ssid, "eap", "SIM", 0); 817 break; 818 case EAP_TYPE_AKA: 819 prefix = '0'; 820 res = wpa_config_set(ssid, "eap", "AKA", 0); 821 break; 822 case EAP_TYPE_AKA_PRIME: 823 prefix = '6'; 824 res = wpa_config_set(ssid, "eap", "AKA'", 0); 825 break; 826 default: 827 res = -1; 828 break; 829 } 830 if (res < 0) { 831 wpa_printf(MSG_DEBUG, "Selected EAP method (%d) not supported", 832 eap_type); 833 goto fail; 834 } 835 836 if (!cred->pcsc && set_root_nai(ssid, cred->imsi, prefix) < 0) { 837 wpa_printf(MSG_DEBUG, "Failed to set Root NAI"); 838 goto fail; 839 } 840 841 if (cred->milenage && cred->milenage[0]) { 842 if (wpa_config_set_quoted(ssid, "password", 843 cred->milenage) < 0) 844 goto fail; 845 } else if (cred->pcsc) { 846 if (wpa_config_set_quoted(ssid, "pcsc", "") < 0) 847 goto fail; 848 if (wpa_s->conf->pcsc_pin && 849 wpa_config_set_quoted(ssid, "pin", wpa_s->conf->pcsc_pin) 850 < 0) 851 goto fail; 852 } 853 854 if (cred->password && cred->password[0] && 855 wpa_config_set_quoted(ssid, "password", cred->password) < 0) 856 goto fail; 857 858 wpa_config_update_prio_list(wpa_s->conf); 859 interworking_reconnect(wpa_s); 860 861 return 0; 862 863 fail: 864 wpas_notify_network_removed(wpa_s, ssid); 865 wpa_config_remove_network(wpa_s->conf, ssid->id); 866 #endif /* INTERWORKING_3GPP */ 867 return -1; 868 } 869 870 871 static int roaming_consortium_element_match(const u8 *ie, const u8 *rc_id, 872 size_t rc_len) 873 { 874 const u8 *pos, *end; 875 u8 lens; 876 877 if (ie == NULL) 878 return 0; 879 880 pos = ie + 2; 881 end = ie + 2 + ie[1]; 882 883 /* Roaming Consortium element: 884 * Number of ANQP OIs 885 * OI #1 and #2 lengths 886 * OI #1, [OI #2], [OI #3] 887 */ 888 889 if (pos + 2 > end) 890 return 0; 891 892 pos++; /* skip Number of ANQP OIs */ 893 lens = *pos++; 894 if (pos + (lens & 0x0f) + (lens >> 4) > end) 895 return 0; 896 897 if ((lens & 0x0f) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0) 898 return 1; 899 pos += lens & 0x0f; 900 901 if ((lens >> 4) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0) 902 return 1; 903 pos += lens >> 4; 904 905 if (pos < end && (size_t) (end - pos) == rc_len && 906 os_memcmp(pos, rc_id, rc_len) == 0) 907 return 1; 908 909 return 0; 910 } 911 912 913 static int roaming_consortium_anqp_match(const struct wpabuf *anqp, 914 const u8 *rc_id, size_t rc_len) 915 { 916 const u8 *pos, *end; 917 u8 len; 918 919 if (anqp == NULL) 920 return 0; 921 922 pos = wpabuf_head(anqp); 923 end = pos + wpabuf_len(anqp); 924 925 /* Set of <OI Length, OI> duples */ 926 while (pos < end) { 927 len = *pos++; 928 if (pos + len > end) 929 break; 930 if (len == rc_len && os_memcmp(pos, rc_id, rc_len) == 0) 931 return 1; 932 pos += len; 933 } 934 935 return 0; 936 } 937 938 939 static int roaming_consortium_match(const u8 *ie, const struct wpabuf *anqp, 940 const u8 *rc_id, size_t rc_len) 941 { 942 return roaming_consortium_element_match(ie, rc_id, rc_len) || 943 roaming_consortium_anqp_match(anqp, rc_id, rc_len); 944 } 945 946 947 static struct wpa_cred * interworking_credentials_available_roaming_consortium( 948 struct wpa_supplicant *wpa_s, struct wpa_bss *bss) 949 { 950 struct wpa_cred *cred, *selected = NULL; 951 const u8 *ie; 952 953 ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM); 954 955 if (ie == NULL && 956 (bss->anqp == NULL || bss->anqp->roaming_consortium == NULL)) 957 return NULL; 958 959 if (wpa_s->conf->cred == NULL) 960 return NULL; 961 962 for (cred = wpa_s->conf->cred; cred; cred = cred->next) { 963 if (cred->roaming_consortium_len == 0) 964 continue; 965 966 if (!roaming_consortium_match(ie, 967 bss->anqp ? 968 bss->anqp->roaming_consortium : 969 NULL, 970 cred->roaming_consortium, 971 cred->roaming_consortium_len)) 972 continue; 973 974 if (selected == NULL || 975 selected->priority < cred->priority) 976 selected = cred; 977 } 978 979 return selected; 980 } 981 982 983 static int interworking_set_eap_params(struct wpa_ssid *ssid, 984 struct wpa_cred *cred, int ttls) 985 { 986 if (cred->eap_method) { 987 ttls = cred->eap_method->vendor == EAP_VENDOR_IETF && 988 cred->eap_method->method == EAP_TYPE_TTLS; 989 990 os_free(ssid->eap.eap_methods); 991 ssid->eap.eap_methods = 992 os_malloc(sizeof(struct eap_method_type) * 2); 993 if (ssid->eap.eap_methods == NULL) 994 return -1; 995 os_memcpy(ssid->eap.eap_methods, cred->eap_method, 996 sizeof(*cred->eap_method)); 997 ssid->eap.eap_methods[1].vendor = EAP_VENDOR_IETF; 998 ssid->eap.eap_methods[1].method = EAP_TYPE_NONE; 999 } 1000 1001 if (ttls && cred->username && cred->username[0]) { 1002 const char *pos; 1003 char *anon; 1004 /* Use anonymous NAI in Phase 1 */ 1005 pos = os_strchr(cred->username, '@'); 1006 if (pos) { 1007 size_t buflen = 9 + os_strlen(pos) + 1; 1008 anon = os_malloc(buflen); 1009 if (anon == NULL) 1010 return -1; 1011 os_snprintf(anon, buflen, "anonymous%s", pos); 1012 } else if (cred->realm) { 1013 size_t buflen = 10 + os_strlen(cred->realm) + 1; 1014 anon = os_malloc(buflen); 1015 if (anon == NULL) 1016 return -1; 1017 os_snprintf(anon, buflen, "anonymous@%s", cred->realm); 1018 } else { 1019 anon = os_strdup("anonymous"); 1020 if (anon == NULL) 1021 return -1; 1022 } 1023 if (wpa_config_set_quoted(ssid, "anonymous_identity", anon) < 1024 0) { 1025 os_free(anon); 1026 return -1; 1027 } 1028 os_free(anon); 1029 } 1030 1031 if (cred->username && cred->username[0] && 1032 wpa_config_set_quoted(ssid, "identity", cred->username) < 0) 1033 return -1; 1034 1035 if (cred->password && cred->password[0]) { 1036 if (cred->ext_password && 1037 wpa_config_set(ssid, "password", cred->password, 0) < 0) 1038 return -1; 1039 if (!cred->ext_password && 1040 wpa_config_set_quoted(ssid, "password", cred->password) < 1041 0) 1042 return -1; 1043 } 1044 1045 if (cred->client_cert && cred->client_cert[0] && 1046 wpa_config_set_quoted(ssid, "client_cert", cred->client_cert) < 0) 1047 return -1; 1048 1049 if (cred->private_key && cred->private_key[0] && 1050 wpa_config_set_quoted(ssid, "private_key", cred->private_key) < 0) 1051 return -1; 1052 1053 if (cred->private_key_passwd && cred->private_key_passwd[0] && 1054 wpa_config_set_quoted(ssid, "private_key_passwd", 1055 cred->private_key_passwd) < 0) 1056 return -1; 1057 1058 if (cred->phase1) { 1059 os_free(ssid->eap.phase1); 1060 ssid->eap.phase1 = os_strdup(cred->phase1); 1061 } 1062 if (cred->phase2) { 1063 os_free(ssid->eap.phase2); 1064 ssid->eap.phase2 = os_strdup(cred->phase2); 1065 } 1066 1067 if (cred->ca_cert && cred->ca_cert[0] && 1068 wpa_config_set_quoted(ssid, "ca_cert", cred->ca_cert) < 0) 1069 return -1; 1070 1071 return 0; 1072 } 1073 1074 1075 static int interworking_connect_roaming_consortium( 1076 struct wpa_supplicant *wpa_s, struct wpa_cred *cred, 1077 struct wpa_bss *bss, const u8 *ssid_ie) 1078 { 1079 struct wpa_ssid *ssid; 1080 1081 wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " based on " 1082 "roaming consortium match", MAC2STR(bss->bssid)); 1083 1084 ssid = wpa_config_add_network(wpa_s->conf); 1085 if (ssid == NULL) 1086 return -1; 1087 wpas_notify_network_added(wpa_s, ssid); 1088 wpa_config_set_network_defaults(ssid); 1089 ssid->priority = cred->priority; 1090 ssid->temporary = 1; 1091 ssid->ssid = os_zalloc(ssid_ie[1] + 1); 1092 if (ssid->ssid == NULL) 1093 goto fail; 1094 os_memcpy(ssid->ssid, ssid_ie + 2, ssid_ie[1]); 1095 ssid->ssid_len = ssid_ie[1]; 1096 1097 if (interworking_set_hs20_params(ssid) < 0) 1098 goto fail; 1099 1100 if (cred->eap_method == NULL) { 1101 wpa_printf(MSG_DEBUG, "Interworking: No EAP method set for " 1102 "credential using roaming consortium"); 1103 goto fail; 1104 } 1105 1106 if (interworking_set_eap_params( 1107 ssid, cred, 1108 cred->eap_method->vendor == EAP_VENDOR_IETF && 1109 cred->eap_method->method == EAP_TYPE_TTLS) < 0) 1110 goto fail; 1111 1112 wpa_config_update_prio_list(wpa_s->conf); 1113 interworking_reconnect(wpa_s); 1114 1115 return 0; 1116 1117 fail: 1118 wpas_notify_network_removed(wpa_s, ssid); 1119 wpa_config_remove_network(wpa_s->conf, ssid->id); 1120 return -1; 1121 } 1122 1123 1124 int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) 1125 { 1126 struct wpa_cred *cred; 1127 struct wpa_ssid *ssid; 1128 struct nai_realm *realm; 1129 struct nai_realm_eap *eap = NULL; 1130 u16 count, i; 1131 char buf[100]; 1132 const u8 *ie; 1133 1134 if (wpa_s->conf->cred == NULL || bss == NULL) 1135 return -1; 1136 ie = wpa_bss_get_ie(bss, WLAN_EID_SSID); 1137 if (ie == NULL || ie[1] == 0) { 1138 wpa_printf(MSG_DEBUG, "Interworking: No SSID known for " 1139 MACSTR, MAC2STR(bss->bssid)); 1140 return -1; 1141 } 1142 1143 if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) { 1144 /* 1145 * We currently support only HS 2.0 networks and those are 1146 * required to use WPA2-Enterprise. 1147 */ 1148 wpa_printf(MSG_DEBUG, "Interworking: Network does not use " 1149 "RSN"); 1150 return -1; 1151 } 1152 1153 cred = interworking_credentials_available_roaming_consortium(wpa_s, 1154 bss); 1155 if (cred) 1156 return interworking_connect_roaming_consortium(wpa_s, cred, 1157 bss, ie); 1158 1159 realm = nai_realm_parse(bss->anqp ? bss->anqp->nai_realm : NULL, 1160 &count); 1161 if (realm == NULL) { 1162 wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI " 1163 "Realm list from " MACSTR, MAC2STR(bss->bssid)); 1164 count = 0; 1165 } 1166 1167 for (cred = wpa_s->conf->cred; cred; cred = cred->next) { 1168 for (i = 0; i < count; i++) { 1169 if (!nai_realm_match(&realm[i], cred->realm)) 1170 continue; 1171 eap = nai_realm_find_eap(cred, &realm[i]); 1172 if (eap) 1173 break; 1174 } 1175 if (eap) 1176 break; 1177 } 1178 1179 if (!eap) { 1180 if (interworking_connect_3gpp(wpa_s, bss) == 0) { 1181 if (realm) 1182 nai_realm_free(realm, count); 1183 return 0; 1184 } 1185 1186 wpa_printf(MSG_DEBUG, "Interworking: No matching credentials " 1187 "and EAP method found for " MACSTR, 1188 MAC2STR(bss->bssid)); 1189 nai_realm_free(realm, count); 1190 return -1; 1191 } 1192 1193 wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR, 1194 MAC2STR(bss->bssid)); 1195 1196 ssid = wpa_config_add_network(wpa_s->conf); 1197 if (ssid == NULL) { 1198 nai_realm_free(realm, count); 1199 return -1; 1200 } 1201 wpas_notify_network_added(wpa_s, ssid); 1202 wpa_config_set_network_defaults(ssid); 1203 ssid->priority = cred->priority; 1204 ssid->temporary = 1; 1205 ssid->ssid = os_zalloc(ie[1] + 1); 1206 if (ssid->ssid == NULL) 1207 goto fail; 1208 os_memcpy(ssid->ssid, ie + 2, ie[1]); 1209 ssid->ssid_len = ie[1]; 1210 1211 if (interworking_set_hs20_params(ssid) < 0) 1212 goto fail; 1213 1214 if (wpa_config_set(ssid, "eap", eap_get_name(EAP_VENDOR_IETF, 1215 eap->method), 0) < 0) 1216 goto fail; 1217 1218 switch (eap->method) { 1219 case EAP_TYPE_TTLS: 1220 if (eap->inner_method) { 1221 os_snprintf(buf, sizeof(buf), "\"autheap=%s\"", 1222 eap_get_name(EAP_VENDOR_IETF, 1223 eap->inner_method)); 1224 if (wpa_config_set(ssid, "phase2", buf, 0) < 0) 1225 goto fail; 1226 break; 1227 } 1228 switch (eap->inner_non_eap) { 1229 case NAI_REALM_INNER_NON_EAP_PAP: 1230 if (wpa_config_set(ssid, "phase2", "\"auth=PAP\"", 0) < 1231 0) 1232 goto fail; 1233 break; 1234 case NAI_REALM_INNER_NON_EAP_CHAP: 1235 if (wpa_config_set(ssid, "phase2", "\"auth=CHAP\"", 0) 1236 < 0) 1237 goto fail; 1238 break; 1239 case NAI_REALM_INNER_NON_EAP_MSCHAP: 1240 if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAP\"", 1241 0) < 0) 1242 goto fail; 1243 break; 1244 case NAI_REALM_INNER_NON_EAP_MSCHAPV2: 1245 if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAPV2\"", 1246 0) < 0) 1247 goto fail; 1248 break; 1249 } 1250 break; 1251 case EAP_TYPE_PEAP: 1252 os_snprintf(buf, sizeof(buf), "\"auth=%s\"", 1253 eap_get_name(EAP_VENDOR_IETF, eap->inner_method)); 1254 if (wpa_config_set(ssid, "phase2", buf, 0) < 0) 1255 goto fail; 1256 break; 1257 case EAP_TYPE_TLS: 1258 break; 1259 } 1260 1261 if (interworking_set_eap_params(ssid, cred, 1262 eap->method == EAP_TYPE_TTLS) < 0) 1263 goto fail; 1264 1265 nai_realm_free(realm, count); 1266 1267 wpa_config_update_prio_list(wpa_s->conf); 1268 interworking_reconnect(wpa_s); 1269 1270 return 0; 1271 1272 fail: 1273 wpas_notify_network_removed(wpa_s, ssid); 1274 wpa_config_remove_network(wpa_s->conf, ssid->id); 1275 nai_realm_free(realm, count); 1276 return -1; 1277 } 1278 1279 1280 static struct wpa_cred * interworking_credentials_available_3gpp( 1281 struct wpa_supplicant *wpa_s, struct wpa_bss *bss) 1282 { 1283 struct wpa_cred *cred, *selected = NULL; 1284 int ret; 1285 1286 #ifdef INTERWORKING_3GPP 1287 if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL) 1288 return NULL; 1289 1290 for (cred = wpa_s->conf->cred; cred; cred = cred->next) { 1291 char *sep; 1292 const char *imsi; 1293 int mnc_len; 1294 1295 #ifdef PCSC_FUNCS 1296 if (cred->pcsc && wpa_s->conf->pcsc_reader && wpa_s->scard && 1297 wpa_s->imsi[0]) { 1298 imsi = wpa_s->imsi; 1299 mnc_len = wpa_s->mnc_len; 1300 goto compare; 1301 } 1302 #endif /* PCSC_FUNCS */ 1303 1304 if (cred->imsi == NULL || !cred->imsi[0] || 1305 cred->milenage == NULL || !cred->milenage[0]) 1306 continue; 1307 1308 sep = os_strchr(cred->imsi, '-'); 1309 if (sep == NULL || 1310 (sep - cred->imsi != 5 && sep - cred->imsi != 6)) 1311 continue; 1312 mnc_len = sep - cred->imsi - 3; 1313 imsi = cred->imsi; 1314 1315 #ifdef PCSC_FUNCS 1316 compare: 1317 #endif /* PCSC_FUNCS */ 1318 wpa_printf(MSG_DEBUG, "Interworking: Parsing 3GPP info from " 1319 MACSTR, MAC2STR(bss->bssid)); 1320 ret = plmn_id_match(bss->anqp->anqp_3gpp, imsi, mnc_len); 1321 wpa_printf(MSG_DEBUG, "PLMN match %sfound", ret ? "" : "not "); 1322 if (ret) { 1323 if (selected == NULL || 1324 selected->priority < cred->priority) 1325 selected = cred; 1326 } 1327 } 1328 #endif /* INTERWORKING_3GPP */ 1329 return selected; 1330 } 1331 1332 1333 static struct wpa_cred * interworking_credentials_available_realm( 1334 struct wpa_supplicant *wpa_s, struct wpa_bss *bss) 1335 { 1336 struct wpa_cred *cred, *selected = NULL; 1337 struct nai_realm *realm; 1338 u16 count, i; 1339 1340 if (bss->anqp == NULL || bss->anqp->nai_realm == NULL) 1341 return NULL; 1342 1343 if (wpa_s->conf->cred == NULL) 1344 return NULL; 1345 1346 wpa_printf(MSG_DEBUG, "Interworking: Parsing NAI Realm list from " 1347 MACSTR, MAC2STR(bss->bssid)); 1348 realm = nai_realm_parse(bss->anqp->nai_realm, &count); 1349 if (realm == NULL) { 1350 wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI " 1351 "Realm list from " MACSTR, MAC2STR(bss->bssid)); 1352 return NULL; 1353 } 1354 1355 for (cred = wpa_s->conf->cred; cred; cred = cred->next) { 1356 if (cred->realm == NULL) 1357 continue; 1358 1359 for (i = 0; i < count; i++) { 1360 if (!nai_realm_match(&realm[i], cred->realm)) 1361 continue; 1362 if (nai_realm_find_eap(cred, &realm[i])) { 1363 if (selected == NULL || 1364 selected->priority < cred->priority) 1365 selected = cred; 1366 break; 1367 } 1368 } 1369 } 1370 1371 nai_realm_free(realm, count); 1372 1373 return selected; 1374 } 1375 1376 1377 static struct wpa_cred * interworking_credentials_available( 1378 struct wpa_supplicant *wpa_s, struct wpa_bss *bss) 1379 { 1380 struct wpa_cred *cred, *cred2; 1381 1382 cred = interworking_credentials_available_realm(wpa_s, bss); 1383 cred2 = interworking_credentials_available_3gpp(wpa_s, bss); 1384 if (cred && cred2 && cred2->priority >= cred->priority) 1385 cred = cred2; 1386 if (!cred) 1387 cred = cred2; 1388 1389 cred2 = interworking_credentials_available_roaming_consortium(wpa_s, 1390 bss); 1391 if (cred && cred2 && cred2->priority >= cred->priority) 1392 cred = cred2; 1393 if (!cred) 1394 cred = cred2; 1395 1396 return cred; 1397 } 1398 1399 1400 static int domain_name_list_contains(struct wpabuf *domain_names, 1401 const char *domain) 1402 { 1403 const u8 *pos, *end; 1404 size_t len; 1405 1406 len = os_strlen(domain); 1407 pos = wpabuf_head(domain_names); 1408 end = pos + wpabuf_len(domain_names); 1409 1410 while (pos + 1 < end) { 1411 if (pos + 1 + pos[0] > end) 1412 break; 1413 1414 wpa_hexdump_ascii(MSG_DEBUG, "Interworking: AP domain name", 1415 pos + 1, pos[0]); 1416 if (pos[0] == len && 1417 os_strncasecmp(domain, (const char *) (pos + 1), len) == 0) 1418 return 1; 1419 1420 pos += 1 + pos[0]; 1421 } 1422 1423 return 0; 1424 } 1425 1426 1427 static int interworking_home_sp(struct wpa_supplicant *wpa_s, 1428 struct wpabuf *domain_names) 1429 { 1430 struct wpa_cred *cred; 1431 #ifdef INTERWORKING_3GPP 1432 char nai[100], *realm; 1433 #endif /* INTERWORKING_3GPP */ 1434 1435 if (domain_names == NULL || wpa_s->conf->cred == NULL) 1436 return -1; 1437 1438 for (cred = wpa_s->conf->cred; cred; cred = cred->next) { 1439 #ifdef INTERWORKING_3GPP 1440 char *imsi = NULL; 1441 int mnc_len = 0; 1442 if (cred->imsi) 1443 imsi = cred->imsi; 1444 #ifdef CONFIG_PCSC 1445 else if (cred->pcsc && wpa_s->conf->pcsc_reader && 1446 wpa_s->scard && wpa_s->imsi[0]) { 1447 imsi = wpa_s->imsi; 1448 mnc_len = wpa_s->mnc_len; 1449 } 1450 #endif /* CONFIG_PCSC */ 1451 if (imsi && build_root_nai(nai, sizeof(nai), imsi, mnc_len, 0) 1452 == 0) { 1453 realm = os_strchr(nai, '@'); 1454 if (realm) 1455 realm++; 1456 wpa_printf(MSG_DEBUG, "Interworking: Search for match " 1457 "with SIM/USIM domain %s", realm); 1458 if (realm && 1459 domain_name_list_contains(domain_names, realm)) 1460 return 1; 1461 } 1462 #endif /* INTERWORKING_3GPP */ 1463 1464 if (cred->domain == NULL) 1465 continue; 1466 1467 wpa_printf(MSG_DEBUG, "Interworking: Search for match with " 1468 "home SP FQDN %s", cred->domain); 1469 if (domain_name_list_contains(domain_names, cred->domain)) 1470 return 1; 1471 } 1472 1473 return 0; 1474 } 1475 1476 1477 static int interworking_find_network_match(struct wpa_supplicant *wpa_s) 1478 { 1479 struct wpa_bss *bss; 1480 struct wpa_ssid *ssid; 1481 1482 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { 1483 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { 1484 if (wpas_network_disabled(wpa_s, ssid) || 1485 ssid->mode != WPAS_MODE_INFRA) 1486 continue; 1487 if (ssid->ssid_len != bss->ssid_len || 1488 os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) != 1489 0) 1490 continue; 1491 /* 1492 * TODO: Consider more accurate matching of security 1493 * configuration similarly to what is done in events.c 1494 */ 1495 return 1; 1496 } 1497 } 1498 1499 return 0; 1500 } 1501 1502 1503 static void interworking_select_network(struct wpa_supplicant *wpa_s) 1504 { 1505 struct wpa_bss *bss, *selected = NULL, *selected_home = NULL; 1506 int selected_prio = -999999, selected_home_prio = -999999; 1507 unsigned int count = 0; 1508 const char *type; 1509 int res; 1510 struct wpa_cred *cred; 1511 1512 wpa_s->network_select = 0; 1513 1514 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { 1515 cred = interworking_credentials_available(wpa_s, bss); 1516 if (!cred) 1517 continue; 1518 if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) { 1519 /* 1520 * We currently support only HS 2.0 networks and those 1521 * are required to use WPA2-Enterprise. 1522 */ 1523 wpa_printf(MSG_DEBUG, "Interworking: Credential match " 1524 "with " MACSTR " but network does not use " 1525 "RSN", MAC2STR(bss->bssid)); 1526 continue; 1527 } 1528 count++; 1529 res = interworking_home_sp(wpa_s, bss->anqp ? 1530 bss->anqp->domain_name : NULL); 1531 if (res > 0) 1532 type = "home"; 1533 else if (res == 0) 1534 type = "roaming"; 1535 else 1536 type = "unknown"; 1537 wpa_msg(wpa_s, MSG_INFO, INTERWORKING_AP MACSTR " type=%s", 1538 MAC2STR(bss->bssid), type); 1539 if (wpa_s->auto_select || 1540 (wpa_s->conf->auto_interworking && 1541 wpa_s->auto_network_select)) { 1542 if (selected == NULL || 1543 cred->priority > selected_prio) { 1544 selected = bss; 1545 selected_prio = cred->priority; 1546 } 1547 if (res > 0 && 1548 (selected_home == NULL || 1549 cred->priority > selected_home_prio)) { 1550 selected_home = bss; 1551 selected_home_prio = cred->priority; 1552 } 1553 } 1554 } 1555 1556 if (selected_home && selected_home != selected && 1557 selected_home_prio >= selected_prio) { 1558 /* Prefer network operated by the Home SP */ 1559 selected = selected_home; 1560 } 1561 1562 if (count == 0) { 1563 /* 1564 * No matching network was found based on configured 1565 * credentials. Check whether any of the enabled network blocks 1566 * have matching APs. 1567 */ 1568 if (interworking_find_network_match(wpa_s)) { 1569 wpa_printf(MSG_DEBUG, "Interworking: Possible BSS " 1570 "match for enabled network configurations"); 1571 if (wpa_s->auto_select) 1572 interworking_reconnect(wpa_s); 1573 return; 1574 } 1575 1576 if (wpa_s->auto_network_select) { 1577 wpa_printf(MSG_DEBUG, "Interworking: Continue " 1578 "scanning after ANQP fetch"); 1579 wpa_supplicant_req_scan(wpa_s, wpa_s->scan_interval, 1580 0); 1581 return; 1582 } 1583 1584 wpa_msg(wpa_s, MSG_INFO, INTERWORKING_NO_MATCH "No network " 1585 "with matching credentials found"); 1586 } 1587 1588 if (selected) 1589 interworking_connect(wpa_s, selected); 1590 } 1591 1592 1593 static struct wpa_bss_anqp * 1594 interworking_match_anqp_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) 1595 { 1596 struct wpa_bss *other; 1597 1598 if (is_zero_ether_addr(bss->hessid)) 1599 return NULL; /* Cannot be in the same homegenous ESS */ 1600 1601 dl_list_for_each(other, &wpa_s->bss, struct wpa_bss, list) { 1602 if (other == bss) 1603 continue; 1604 if (other->anqp == NULL) 1605 continue; 1606 if (!(other->flags & WPA_BSS_ANQP_FETCH_TRIED)) 1607 continue; 1608 if (os_memcmp(bss->hessid, other->hessid, ETH_ALEN) != 0) 1609 continue; 1610 if (bss->ssid_len != other->ssid_len || 1611 os_memcmp(bss->ssid, other->ssid, bss->ssid_len) != 0) 1612 continue; 1613 1614 wpa_printf(MSG_DEBUG, "Interworking: Share ANQP data with " 1615 "already fetched BSSID " MACSTR " and " MACSTR, 1616 MAC2STR(other->bssid), MAC2STR(bss->bssid)); 1617 other->anqp->users++; 1618 return other->anqp; 1619 } 1620 1621 return NULL; 1622 } 1623 1624 1625 static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s) 1626 { 1627 struct wpa_bss *bss; 1628 int found = 0; 1629 const u8 *ie; 1630 1631 if (!wpa_s->fetch_anqp_in_progress) 1632 return; 1633 1634 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { 1635 if (!(bss->caps & IEEE80211_CAP_ESS)) 1636 continue; 1637 ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB); 1638 if (ie == NULL || ie[1] < 4 || !(ie[5] & 0x80)) 1639 continue; /* AP does not support Interworking */ 1640 1641 if (!(bss->flags & WPA_BSS_ANQP_FETCH_TRIED)) { 1642 if (bss->anqp == NULL) { 1643 bss->anqp = interworking_match_anqp_info(wpa_s, 1644 bss); 1645 if (bss->anqp) { 1646 /* Shared data already fetched */ 1647 continue; 1648 } 1649 bss->anqp = wpa_bss_anqp_alloc(); 1650 if (bss->anqp == NULL) 1651 break; 1652 } 1653 found++; 1654 bss->flags |= WPA_BSS_ANQP_FETCH_TRIED; 1655 wpa_msg(wpa_s, MSG_INFO, "Starting ANQP fetch for " 1656 MACSTR, MAC2STR(bss->bssid)); 1657 interworking_anqp_send_req(wpa_s, bss); 1658 break; 1659 } 1660 } 1661 1662 if (found == 0) { 1663 wpa_msg(wpa_s, MSG_INFO, "ANQP fetch completed"); 1664 wpa_s->fetch_anqp_in_progress = 0; 1665 if (wpa_s->network_select) 1666 interworking_select_network(wpa_s); 1667 } 1668 } 1669 1670 1671 void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s) 1672 { 1673 struct wpa_bss *bss; 1674 1675 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) 1676 bss->flags &= ~WPA_BSS_ANQP_FETCH_TRIED; 1677 1678 wpa_s->fetch_anqp_in_progress = 1; 1679 interworking_next_anqp_fetch(wpa_s); 1680 } 1681 1682 1683 int interworking_fetch_anqp(struct wpa_supplicant *wpa_s) 1684 { 1685 if (wpa_s->fetch_anqp_in_progress || wpa_s->network_select) 1686 return 0; 1687 1688 wpa_s->network_select = 0; 1689 wpa_s->fetch_all_anqp = 1; 1690 1691 interworking_start_fetch_anqp(wpa_s); 1692 1693 return 0; 1694 } 1695 1696 1697 void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s) 1698 { 1699 if (!wpa_s->fetch_anqp_in_progress) 1700 return; 1701 1702 wpa_s->fetch_anqp_in_progress = 0; 1703 } 1704 1705 1706 int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, 1707 u16 info_ids[], size_t num_ids) 1708 { 1709 struct wpabuf *buf; 1710 int ret = 0; 1711 int freq; 1712 struct wpa_bss *bss; 1713 int res; 1714 1715 freq = wpa_s->assoc_freq; 1716 bss = wpa_bss_get_bssid(wpa_s, dst); 1717 if (bss) 1718 freq = bss->freq; 1719 if (freq <= 0) 1720 return -1; 1721 1722 wpa_printf(MSG_DEBUG, "ANQP: Query Request to " MACSTR " for %u id(s)", 1723 MAC2STR(dst), (unsigned int) num_ids); 1724 1725 buf = anqp_build_req(info_ids, num_ids, NULL); 1726 if (buf == NULL) 1727 return -1; 1728 1729 res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s); 1730 if (res < 0) { 1731 wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request"); 1732 ret = -1; 1733 } else 1734 wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token " 1735 "%u", res); 1736 1737 wpabuf_free(buf); 1738 return ret; 1739 } 1740 1741 1742 static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, 1743 const u8 *sa, u16 info_id, 1744 const u8 *data, size_t slen) 1745 { 1746 const u8 *pos = data; 1747 struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa); 1748 struct wpa_bss_anqp *anqp = NULL; 1749 #ifdef CONFIG_HS20 1750 u8 type; 1751 #endif /* CONFIG_HS20 */ 1752 1753 if (bss) 1754 anqp = bss->anqp; 1755 1756 switch (info_id) { 1757 case ANQP_CAPABILITY_LIST: 1758 wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR 1759 " ANQP Capability list", MAC2STR(sa)); 1760 break; 1761 case ANQP_VENUE_NAME: 1762 wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR 1763 " Venue Name", MAC2STR(sa)); 1764 wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Venue Name", pos, slen); 1765 if (anqp) { 1766 wpabuf_free(anqp->venue_name); 1767 anqp->venue_name = wpabuf_alloc_copy(pos, slen); 1768 } 1769 break; 1770 case ANQP_NETWORK_AUTH_TYPE: 1771 wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR 1772 " Network Authentication Type information", 1773 MAC2STR(sa)); 1774 wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Network Authentication " 1775 "Type", pos, slen); 1776 if (anqp) { 1777 wpabuf_free(anqp->network_auth_type); 1778 anqp->network_auth_type = wpabuf_alloc_copy(pos, slen); 1779 } 1780 break; 1781 case ANQP_ROAMING_CONSORTIUM: 1782 wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR 1783 " Roaming Consortium list", MAC2STR(sa)); 1784 wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Roaming Consortium", 1785 pos, slen); 1786 if (anqp) { 1787 wpabuf_free(anqp->roaming_consortium); 1788 anqp->roaming_consortium = wpabuf_alloc_copy(pos, slen); 1789 } 1790 break; 1791 case ANQP_IP_ADDR_TYPE_AVAILABILITY: 1792 wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR 1793 " IP Address Type Availability information", 1794 MAC2STR(sa)); 1795 wpa_hexdump(MSG_MSGDUMP, "ANQP: IP Address Availability", 1796 pos, slen); 1797 if (anqp) { 1798 wpabuf_free(anqp->ip_addr_type_availability); 1799 anqp->ip_addr_type_availability = 1800 wpabuf_alloc_copy(pos, slen); 1801 } 1802 break; 1803 case ANQP_NAI_REALM: 1804 wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR 1805 " NAI Realm list", MAC2STR(sa)); 1806 wpa_hexdump_ascii(MSG_DEBUG, "ANQP: NAI Realm", pos, slen); 1807 if (anqp) { 1808 wpabuf_free(anqp->nai_realm); 1809 anqp->nai_realm = wpabuf_alloc_copy(pos, slen); 1810 } 1811 break; 1812 case ANQP_3GPP_CELLULAR_NETWORK: 1813 wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR 1814 " 3GPP Cellular Network information", MAC2STR(sa)); 1815 wpa_hexdump_ascii(MSG_DEBUG, "ANQP: 3GPP Cellular Network", 1816 pos, slen); 1817 if (anqp) { 1818 wpabuf_free(anqp->anqp_3gpp); 1819 anqp->anqp_3gpp = wpabuf_alloc_copy(pos, slen); 1820 } 1821 break; 1822 case ANQP_DOMAIN_NAME: 1823 wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR 1824 " Domain Name list", MAC2STR(sa)); 1825 wpa_hexdump_ascii(MSG_MSGDUMP, "ANQP: Domain Name", pos, slen); 1826 if (anqp) { 1827 wpabuf_free(anqp->domain_name); 1828 anqp->domain_name = wpabuf_alloc_copy(pos, slen); 1829 } 1830 break; 1831 case ANQP_VENDOR_SPECIFIC: 1832 if (slen < 3) 1833 return; 1834 1835 switch (WPA_GET_BE24(pos)) { 1836 #ifdef CONFIG_HS20 1837 case OUI_WFA: 1838 pos += 3; 1839 slen -= 3; 1840 1841 if (slen < 1) 1842 return; 1843 type = *pos++; 1844 slen--; 1845 1846 switch (type) { 1847 case HS20_ANQP_OUI_TYPE: 1848 hs20_parse_rx_hs20_anqp_resp(wpa_s, sa, pos, 1849 slen); 1850 break; 1851 default: 1852 wpa_printf(MSG_DEBUG, "HS20: Unsupported ANQP " 1853 "vendor type %u", type); 1854 break; 1855 } 1856 break; 1857 #endif /* CONFIG_HS20 */ 1858 default: 1859 wpa_printf(MSG_DEBUG, "Interworking: Unsupported " 1860 "vendor-specific ANQP OUI %06x", 1861 WPA_GET_BE24(pos)); 1862 return; 1863 } 1864 break; 1865 default: 1866 wpa_printf(MSG_DEBUG, "Interworking: Unsupported ANQP Info ID " 1867 "%u", info_id); 1868 break; 1869 } 1870 } 1871 1872 1873 void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token, 1874 enum gas_query_result result, 1875 const struct wpabuf *adv_proto, 1876 const struct wpabuf *resp, u16 status_code) 1877 { 1878 struct wpa_supplicant *wpa_s = ctx; 1879 const u8 *pos; 1880 const u8 *end; 1881 u16 info_id; 1882 u16 slen; 1883 1884 if (result != GAS_QUERY_SUCCESS) 1885 return; 1886 1887 pos = wpabuf_head(adv_proto); 1888 if (wpabuf_len(adv_proto) < 4 || pos[0] != WLAN_EID_ADV_PROTO || 1889 pos[1] < 2 || pos[3] != ACCESS_NETWORK_QUERY_PROTOCOL) { 1890 wpa_printf(MSG_DEBUG, "ANQP: Unexpected Advertisement " 1891 "Protocol in response"); 1892 return; 1893 } 1894 1895 pos = wpabuf_head(resp); 1896 end = pos + wpabuf_len(resp); 1897 1898 while (pos < end) { 1899 if (pos + 4 > end) { 1900 wpa_printf(MSG_DEBUG, "ANQP: Invalid element"); 1901 break; 1902 } 1903 info_id = WPA_GET_LE16(pos); 1904 pos += 2; 1905 slen = WPA_GET_LE16(pos); 1906 pos += 2; 1907 if (pos + slen > end) { 1908 wpa_printf(MSG_DEBUG, "ANQP: Invalid element length " 1909 "for Info ID %u", info_id); 1910 break; 1911 } 1912 interworking_parse_rx_anqp_resp(wpa_s, dst, info_id, pos, 1913 slen); 1914 pos += slen; 1915 } 1916 } 1917 1918 1919 static void interworking_scan_res_handler(struct wpa_supplicant *wpa_s, 1920 struct wpa_scan_results *scan_res) 1921 { 1922 wpa_printf(MSG_DEBUG, "Interworking: Scan results available - start " 1923 "ANQP fetch"); 1924 interworking_start_fetch_anqp(wpa_s); 1925 } 1926 1927 1928 int interworking_select(struct wpa_supplicant *wpa_s, int auto_select) 1929 { 1930 interworking_stop_fetch_anqp(wpa_s); 1931 wpa_s->network_select = 1; 1932 wpa_s->auto_network_select = 0; 1933 wpa_s->auto_select = !!auto_select; 1934 wpa_s->fetch_all_anqp = 0; 1935 wpa_printf(MSG_DEBUG, "Interworking: Start scan for network " 1936 "selection"); 1937 wpa_s->scan_res_handler = interworking_scan_res_handler; 1938 wpa_s->scan_req = 2; 1939 wpa_supplicant_req_scan(wpa_s, 0, 0); 1940 1941 return 0; 1942 } 1943 1944 1945 static void gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, 1946 enum gas_query_result result, 1947 const struct wpabuf *adv_proto, 1948 const struct wpabuf *resp, u16 status_code) 1949 { 1950 struct wpa_supplicant *wpa_s = ctx; 1951 1952 wpa_msg(wpa_s, MSG_INFO, GAS_RESPONSE_INFO "addr=" MACSTR 1953 " dialog_token=%d status_code=%d resp_len=%d", 1954 MAC2STR(addr), dialog_token, status_code, 1955 resp ? (int) wpabuf_len(resp) : -1); 1956 if (!resp) 1957 return; 1958 1959 wpabuf_free(wpa_s->last_gas_resp); 1960 wpa_s->last_gas_resp = wpabuf_dup(resp); 1961 if (wpa_s->last_gas_resp == NULL) 1962 return; 1963 os_memcpy(wpa_s->last_gas_addr, addr, ETH_ALEN); 1964 wpa_s->last_gas_dialog_token = dialog_token; 1965 } 1966 1967 1968 int gas_send_request(struct wpa_supplicant *wpa_s, const u8 *dst, 1969 const struct wpabuf *adv_proto, 1970 const struct wpabuf *query) 1971 { 1972 struct wpabuf *buf; 1973 int ret = 0; 1974 int freq; 1975 struct wpa_bss *bss; 1976 int res; 1977 size_t len; 1978 u8 query_resp_len_limit = 0, pame_bi = 0; 1979 1980 freq = wpa_s->assoc_freq; 1981 bss = wpa_bss_get_bssid(wpa_s, dst); 1982 if (bss) 1983 freq = bss->freq; 1984 if (freq <= 0) 1985 return -1; 1986 1987 wpa_printf(MSG_DEBUG, "GAS request to " MACSTR " (freq %d MHz)", 1988 MAC2STR(dst), freq); 1989 wpa_hexdump_buf(MSG_DEBUG, "Advertisement Protocol ID", adv_proto); 1990 wpa_hexdump_buf(MSG_DEBUG, "GAS Query", query); 1991 1992 len = 3 + wpabuf_len(adv_proto) + 2; 1993 if (query) 1994 len += wpabuf_len(query); 1995 buf = gas_build_initial_req(0, len); 1996 if (buf == NULL) 1997 return -1; 1998 1999 /* Advertisement Protocol IE */ 2000 wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO); 2001 wpabuf_put_u8(buf, 1 + wpabuf_len(adv_proto)); /* Length */ 2002 wpabuf_put_u8(buf, (query_resp_len_limit & 0x7f) | 2003 (pame_bi ? 0x80 : 0)); 2004 wpabuf_put_buf(buf, adv_proto); 2005 2006 /* GAS Query */ 2007 if (query) { 2008 wpabuf_put_le16(buf, wpabuf_len(query)); 2009 wpabuf_put_buf(buf, query); 2010 } else 2011 wpabuf_put_le16(buf, 0); 2012 2013 res = gas_query_req(wpa_s->gas, dst, freq, buf, gas_resp_cb, wpa_s); 2014 if (res < 0) { 2015 wpa_printf(MSG_DEBUG, "GAS: Failed to send Query Request"); 2016 ret = -1; 2017 } else 2018 wpa_printf(MSG_DEBUG, "GAS: Query started with dialog token " 2019 "%u", res); 2020 2021 wpabuf_free(buf); 2022 return ret; 2023 } 2024