interworking.c revision f9bdef99ce3b2858f2812c745a3d6bb093fb0e5d
1/* 2 * Interworking (IEEE 802.11u) 3 * Copyright (c) 2011-2013, Qualcomm Atheros, Inc. 4 * Copyright (c) 2011-2014, Jouni Malinen <j@w1.fi> 5 * 6 * This software may be distributed under the terms of the BSD license. 7 * See README for more details. 8 */ 9 10#include "includes.h" 11 12#include "common.h" 13#include "common/ieee802_11_defs.h" 14#include "common/gas.h" 15#include "common/wpa_ctrl.h" 16#include "utils/pcsc_funcs.h" 17#include "utils/eloop.h" 18#include "drivers/driver.h" 19#include "eap_common/eap_defs.h" 20#include "eap_peer/eap.h" 21#include "eap_peer/eap_methods.h" 22#include "eapol_supp/eapol_supp_sm.h" 23#include "rsn_supp/wpa.h" 24#include "wpa_supplicant_i.h" 25#include "config.h" 26#include "config_ssid.h" 27#include "bss.h" 28#include "scan.h" 29#include "notify.h" 30#include "gas_query.h" 31#include "hs20_supplicant.h" 32#include "interworking.h" 33 34 35#if defined(EAP_SIM) | defined(EAP_SIM_DYNAMIC) 36#define INTERWORKING_3GPP 37#else 38#if defined(EAP_AKA) | defined(EAP_AKA_DYNAMIC) 39#define INTERWORKING_3GPP 40#else 41#if defined(EAP_AKA_PRIME) | defined(EAP_AKA_PRIME_DYNAMIC) 42#define INTERWORKING_3GPP 43#endif 44#endif 45#endif 46 47static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s); 48static struct wpa_cred * interworking_credentials_available_realm( 49 struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int ignore_bw, 50 int *excluded); 51static struct wpa_cred * interworking_credentials_available_3gpp( 52 struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int ignore_bw, 53 int *excluded); 54 55 56static int cred_prio_cmp(const struct wpa_cred *a, const struct wpa_cred *b) 57{ 58 if (a->priority > b->priority) 59 return 1; 60 if (a->priority < b->priority) 61 return -1; 62 if (a->provisioning_sp == NULL || b->provisioning_sp == NULL || 63 os_strcmp(a->provisioning_sp, b->provisioning_sp) != 0) 64 return 0; 65 if (a->sp_priority < b->sp_priority) 66 return 1; 67 if (a->sp_priority > b->sp_priority) 68 return -1; 69 return 0; 70} 71 72 73static void interworking_reconnect(struct wpa_supplicant *wpa_s) 74{ 75 if (wpa_s->wpa_state >= WPA_AUTHENTICATING) { 76 wpa_supplicant_cancel_sched_scan(wpa_s); 77 wpa_supplicant_deauthenticate(wpa_s, 78 WLAN_REASON_DEAUTH_LEAVING); 79 } 80 wpa_s->disconnected = 0; 81 wpa_s->reassociate = 1; 82 83 if (wpa_supplicant_fast_associate(wpa_s) >= 0) 84 return; 85 86 wpa_supplicant_req_scan(wpa_s, 0, 0); 87} 88 89 90static struct wpabuf * anqp_build_req(u16 info_ids[], size_t num_ids, 91 struct wpabuf *extra) 92{ 93 struct wpabuf *buf; 94 size_t i; 95 u8 *len_pos; 96 97 buf = gas_anqp_build_initial_req(0, 4 + num_ids * 2 + 98 (extra ? wpabuf_len(extra) : 0)); 99 if (buf == NULL) 100 return NULL; 101 102 len_pos = gas_anqp_add_element(buf, ANQP_QUERY_LIST); 103 for (i = 0; i < num_ids; i++) 104 wpabuf_put_le16(buf, info_ids[i]); 105 gas_anqp_set_element_len(buf, len_pos); 106 if (extra) 107 wpabuf_put_buf(buf, extra); 108 109 gas_anqp_set_len(buf); 110 111 return buf; 112} 113 114 115static void interworking_anqp_resp_cb(void *ctx, const u8 *dst, 116 u8 dialog_token, 117 enum gas_query_result result, 118 const struct wpabuf *adv_proto, 119 const struct wpabuf *resp, 120 u16 status_code) 121{ 122 struct wpa_supplicant *wpa_s = ctx; 123 124 wpa_printf(MSG_DEBUG, "ANQP: Response callback dst=" MACSTR 125 " dialog_token=%u result=%d status_code=%u", 126 MAC2STR(dst), dialog_token, result, status_code); 127 anqp_resp_cb(wpa_s, dst, dialog_token, result, adv_proto, resp, 128 status_code); 129 interworking_next_anqp_fetch(wpa_s); 130} 131 132 133static int cred_with_roaming_consortium(struct wpa_supplicant *wpa_s) 134{ 135 struct wpa_cred *cred; 136 137 for (cred = wpa_s->conf->cred; cred; cred = cred->next) { 138 if (cred->roaming_consortium_len) 139 return 1; 140 if (cred->required_roaming_consortium_len) 141 return 1; 142 } 143 return 0; 144} 145 146 147static int cred_with_3gpp(struct wpa_supplicant *wpa_s) 148{ 149 struct wpa_cred *cred; 150 151 for (cred = wpa_s->conf->cred; cred; cred = cred->next) { 152 if (cred->pcsc || cred->imsi) 153 return 1; 154 } 155 return 0; 156} 157 158 159static int cred_with_nai_realm(struct wpa_supplicant *wpa_s) 160{ 161 struct wpa_cred *cred; 162 163 for (cred = wpa_s->conf->cred; cred; cred = cred->next) { 164 if (cred->pcsc || cred->imsi) 165 continue; 166 if (!cred->eap_method) 167 return 1; 168 if (cred->realm && cred->roaming_consortium_len == 0) 169 return 1; 170 } 171 return 0; 172} 173 174 175static int cred_with_domain(struct wpa_supplicant *wpa_s) 176{ 177 struct wpa_cred *cred; 178 179 for (cred = wpa_s->conf->cred; cred; cred = cred->next) { 180 if (cred->domain || cred->pcsc || cred->imsi || 181 cred->roaming_partner) 182 return 1; 183 } 184 return 0; 185} 186 187 188#ifdef CONFIG_HS20 189 190static int cred_with_min_backhaul(struct wpa_supplicant *wpa_s) 191{ 192 struct wpa_cred *cred; 193 194 for (cred = wpa_s->conf->cred; cred; cred = cred->next) { 195 if (cred->min_dl_bandwidth_home || 196 cred->min_ul_bandwidth_home || 197 cred->min_dl_bandwidth_roaming || 198 cred->min_ul_bandwidth_roaming) 199 return 1; 200 } 201 return 0; 202} 203 204 205static int cred_with_conn_capab(struct wpa_supplicant *wpa_s) 206{ 207 struct wpa_cred *cred; 208 209 for (cred = wpa_s->conf->cred; cred; cred = cred->next) { 210 if (cred->num_req_conn_capab) 211 return 1; 212 } 213 return 0; 214} 215 216#endif /* CONFIG_HS20 */ 217 218 219static int additional_roaming_consortiums(struct wpa_bss *bss) 220{ 221 const u8 *ie; 222 ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM); 223 if (ie == NULL || ie[1] == 0) 224 return 0; 225 return ie[2]; /* Number of ANQP OIs */ 226} 227 228 229static void interworking_continue_anqp(void *eloop_ctx, void *sock_ctx) 230{ 231 struct wpa_supplicant *wpa_s = eloop_ctx; 232 interworking_next_anqp_fetch(wpa_s); 233} 234 235 236static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s, 237 struct wpa_bss *bss) 238{ 239 struct wpabuf *buf; 240 int ret = 0; 241 int res; 242 u16 info_ids[8]; 243 size_t num_info_ids = 0; 244 struct wpabuf *extra = NULL; 245 int all = wpa_s->fetch_all_anqp; 246 247 wpa_printf(MSG_DEBUG, "Interworking: ANQP Query Request to " MACSTR, 248 MAC2STR(bss->bssid)); 249 wpa_s->interworking_gas_bss = bss; 250 251 info_ids[num_info_ids++] = ANQP_CAPABILITY_LIST; 252 if (all) { 253 info_ids[num_info_ids++] = ANQP_VENUE_NAME; 254 info_ids[num_info_ids++] = ANQP_NETWORK_AUTH_TYPE; 255 } 256 if (all || (cred_with_roaming_consortium(wpa_s) && 257 additional_roaming_consortiums(bss))) 258 info_ids[num_info_ids++] = ANQP_ROAMING_CONSORTIUM; 259 if (all) 260 info_ids[num_info_ids++] = ANQP_IP_ADDR_TYPE_AVAILABILITY; 261 if (all || cred_with_nai_realm(wpa_s)) 262 info_ids[num_info_ids++] = ANQP_NAI_REALM; 263 if (all || cred_with_3gpp(wpa_s)) { 264 info_ids[num_info_ids++] = ANQP_3GPP_CELLULAR_NETWORK; 265 wpa_supplicant_scard_init(wpa_s, NULL); 266 } 267 if (all || cred_with_domain(wpa_s)) 268 info_ids[num_info_ids++] = ANQP_DOMAIN_NAME; 269 wpa_hexdump(MSG_DEBUG, "Interworking: ANQP Query info", 270 (u8 *) info_ids, num_info_ids * 2); 271 272#ifdef CONFIG_HS20 273 if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) { 274 u8 *len_pos; 275 276 extra = wpabuf_alloc(100); 277 if (!extra) 278 return -1; 279 280 len_pos = gas_anqp_add_element(extra, ANQP_VENDOR_SPECIFIC); 281 wpabuf_put_be24(extra, OUI_WFA); 282 wpabuf_put_u8(extra, HS20_ANQP_OUI_TYPE); 283 wpabuf_put_u8(extra, HS20_STYPE_QUERY_LIST); 284 wpabuf_put_u8(extra, 0); /* Reserved */ 285 wpabuf_put_u8(extra, HS20_STYPE_CAPABILITY_LIST); 286 if (all) 287 wpabuf_put_u8(extra, 288 HS20_STYPE_OPERATOR_FRIENDLY_NAME); 289 if (all || cred_with_min_backhaul(wpa_s)) 290 wpabuf_put_u8(extra, HS20_STYPE_WAN_METRICS); 291 if (all || cred_with_conn_capab(wpa_s)) 292 wpabuf_put_u8(extra, HS20_STYPE_CONNECTION_CAPABILITY); 293 if (all) 294 wpabuf_put_u8(extra, HS20_STYPE_OPERATING_CLASS); 295 if (all) 296 wpabuf_put_u8(extra, HS20_STYPE_OSU_PROVIDERS_LIST); 297 gas_anqp_set_element_len(extra, len_pos); 298 } 299#endif /* CONFIG_HS20 */ 300 301 buf = anqp_build_req(info_ids, num_info_ids, extra); 302 wpabuf_free(extra); 303 if (buf == NULL) 304 return -1; 305 306 res = gas_query_req(wpa_s->gas, bss->bssid, bss->freq, buf, 307 interworking_anqp_resp_cb, wpa_s); 308 if (res < 0) { 309 wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request"); 310 wpabuf_free(buf); 311 ret = -1; 312 eloop_register_timeout(0, 0, interworking_continue_anqp, wpa_s, 313 NULL); 314 } else 315 wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token " 316 "%u", res); 317 318 return ret; 319} 320 321 322struct nai_realm_eap { 323 u8 method; 324 u8 inner_method; 325 enum nai_realm_eap_auth_inner_non_eap inner_non_eap; 326 u8 cred_type; 327 u8 tunneled_cred_type; 328}; 329 330struct nai_realm { 331 u8 encoding; 332 char *realm; 333 u8 eap_count; 334 struct nai_realm_eap *eap; 335}; 336 337 338static void nai_realm_free(struct nai_realm *realms, u16 count) 339{ 340 u16 i; 341 342 if (realms == NULL) 343 return; 344 for (i = 0; i < count; i++) { 345 os_free(realms[i].eap); 346 os_free(realms[i].realm); 347 } 348 os_free(realms); 349} 350 351 352static const u8 * nai_realm_parse_eap(struct nai_realm_eap *e, const u8 *pos, 353 const u8 *end) 354{ 355 u8 elen, auth_count, a; 356 const u8 *e_end; 357 358 if (pos + 3 > end) { 359 wpa_printf(MSG_DEBUG, "No room for EAP Method fixed fields"); 360 return NULL; 361 } 362 363 elen = *pos++; 364 if (pos + elen > end || elen < 2) { 365 wpa_printf(MSG_DEBUG, "No room for EAP Method subfield"); 366 return NULL; 367 } 368 e_end = pos + elen; 369 e->method = *pos++; 370 auth_count = *pos++; 371 wpa_printf(MSG_DEBUG, "EAP Method: len=%u method=%u auth_count=%u", 372 elen, e->method, auth_count); 373 374 for (a = 0; a < auth_count; a++) { 375 u8 id, len; 376 377 if (pos + 2 > end || pos + 2 + pos[1] > end) { 378 wpa_printf(MSG_DEBUG, "No room for Authentication " 379 "Parameter subfield"); 380 return NULL; 381 } 382 383 id = *pos++; 384 len = *pos++; 385 386 switch (id) { 387 case NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH: 388 if (len < 1) 389 break; 390 e->inner_non_eap = *pos; 391 if (e->method != EAP_TYPE_TTLS) 392 break; 393 switch (*pos) { 394 case NAI_REALM_INNER_NON_EAP_PAP: 395 wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP"); 396 break; 397 case NAI_REALM_INNER_NON_EAP_CHAP: 398 wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP"); 399 break; 400 case NAI_REALM_INNER_NON_EAP_MSCHAP: 401 wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP"); 402 break; 403 case NAI_REALM_INNER_NON_EAP_MSCHAPV2: 404 wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2"); 405 break; 406 } 407 break; 408 case NAI_REALM_EAP_AUTH_INNER_AUTH_EAP_METHOD: 409 if (len < 1) 410 break; 411 e->inner_method = *pos; 412 wpa_printf(MSG_DEBUG, "Inner EAP method: %u", 413 e->inner_method); 414 break; 415 case NAI_REALM_EAP_AUTH_CRED_TYPE: 416 if (len < 1) 417 break; 418 e->cred_type = *pos; 419 wpa_printf(MSG_DEBUG, "Credential Type: %u", 420 e->cred_type); 421 break; 422 case NAI_REALM_EAP_AUTH_TUNNELED_CRED_TYPE: 423 if (len < 1) 424 break; 425 e->tunneled_cred_type = *pos; 426 wpa_printf(MSG_DEBUG, "Tunneled EAP Method Credential " 427 "Type: %u", e->tunneled_cred_type); 428 break; 429 default: 430 wpa_printf(MSG_DEBUG, "Unsupported Authentication " 431 "Parameter: id=%u len=%u", id, len); 432 wpa_hexdump(MSG_DEBUG, "Authentication Parameter " 433 "Value", pos, len); 434 break; 435 } 436 437 pos += len; 438 } 439 440 return e_end; 441} 442 443 444static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos, 445 const u8 *end) 446{ 447 u16 len; 448 const u8 *f_end; 449 u8 realm_len, e; 450 451 if (end - pos < 4) { 452 wpa_printf(MSG_DEBUG, "No room for NAI Realm Data " 453 "fixed fields"); 454 return NULL; 455 } 456 457 len = WPA_GET_LE16(pos); /* NAI Realm Data field Length */ 458 pos += 2; 459 if (pos + len > end || len < 3) { 460 wpa_printf(MSG_DEBUG, "No room for NAI Realm Data " 461 "(len=%u; left=%u)", 462 len, (unsigned int) (end - pos)); 463 return NULL; 464 } 465 f_end = pos + len; 466 467 r->encoding = *pos++; 468 realm_len = *pos++; 469 if (pos + realm_len > f_end) { 470 wpa_printf(MSG_DEBUG, "No room for NAI Realm " 471 "(len=%u; left=%u)", 472 realm_len, (unsigned int) (f_end - pos)); 473 return NULL; 474 } 475 wpa_hexdump_ascii(MSG_DEBUG, "NAI Realm", pos, realm_len); 476 r->realm = dup_binstr(pos, realm_len); 477 if (r->realm == NULL) 478 return NULL; 479 pos += realm_len; 480 481 if (pos + 1 > f_end) { 482 wpa_printf(MSG_DEBUG, "No room for EAP Method Count"); 483 return NULL; 484 } 485 r->eap_count = *pos++; 486 wpa_printf(MSG_DEBUG, "EAP Count: %u", r->eap_count); 487 if (pos + r->eap_count * 3 > f_end) { 488 wpa_printf(MSG_DEBUG, "No room for EAP Methods"); 489 return NULL; 490 } 491 r->eap = os_calloc(r->eap_count, sizeof(struct nai_realm_eap)); 492 if (r->eap == NULL) 493 return NULL; 494 495 for (e = 0; e < r->eap_count; e++) { 496 pos = nai_realm_parse_eap(&r->eap[e], pos, f_end); 497 if (pos == NULL) 498 return NULL; 499 } 500 501 return f_end; 502} 503 504 505static struct nai_realm * nai_realm_parse(struct wpabuf *anqp, u16 *count) 506{ 507 struct nai_realm *realm; 508 const u8 *pos, *end; 509 u16 i, num; 510 511 if (anqp == NULL || wpabuf_len(anqp) < 2) 512 return NULL; 513 514 pos = wpabuf_head_u8(anqp); 515 end = pos + wpabuf_len(anqp); 516 num = WPA_GET_LE16(pos); 517 wpa_printf(MSG_DEBUG, "NAI Realm Count: %u", num); 518 pos += 2; 519 520 if (num * 5 > end - pos) { 521 wpa_printf(MSG_DEBUG, "Invalid NAI Realm Count %u - not " 522 "enough data (%u octets) for that many realms", 523 num, (unsigned int) (end - pos)); 524 return NULL; 525 } 526 527 realm = os_calloc(num, sizeof(struct nai_realm)); 528 if (realm == NULL) 529 return NULL; 530 531 for (i = 0; i < num; i++) { 532 pos = nai_realm_parse_realm(&realm[i], pos, end); 533 if (pos == NULL) { 534 nai_realm_free(realm, num); 535 return NULL; 536 } 537 } 538 539 *count = num; 540 return realm; 541} 542 543 544static int nai_realm_match(struct nai_realm *realm, const char *home_realm) 545{ 546 char *tmp, *pos, *end; 547 int match = 0; 548 549 if (realm->realm == NULL || home_realm == NULL) 550 return 0; 551 552 if (os_strchr(realm->realm, ';') == NULL) 553 return os_strcasecmp(realm->realm, home_realm) == 0; 554 555 tmp = os_strdup(realm->realm); 556 if (tmp == NULL) 557 return 0; 558 559 pos = tmp; 560 while (*pos) { 561 end = os_strchr(pos, ';'); 562 if (end) 563 *end = '\0'; 564 if (os_strcasecmp(pos, home_realm) == 0) { 565 match = 1; 566 break; 567 } 568 if (end == NULL) 569 break; 570 pos = end + 1; 571 } 572 573 os_free(tmp); 574 575 return match; 576} 577 578 579static int nai_realm_cred_username(struct nai_realm_eap *eap) 580{ 581 if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL) 582 return 0; /* method not supported */ 583 584 if (eap->method != EAP_TYPE_TTLS && eap->method != EAP_TYPE_PEAP && 585 eap->method != EAP_TYPE_FAST) { 586 /* Only tunneled methods with username/password supported */ 587 return 0; 588 } 589 590 if (eap->method == EAP_TYPE_PEAP || eap->method == EAP_TYPE_FAST) { 591 if (eap->inner_method && 592 eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL) 593 return 0; 594 if (!eap->inner_method && 595 eap_get_name(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2) == NULL) 596 return 0; 597 } 598 599 if (eap->method == EAP_TYPE_TTLS) { 600 if (eap->inner_method == 0 && eap->inner_non_eap == 0) 601 return 1; /* Assume TTLS/MSCHAPv2 is used */ 602 if (eap->inner_method && 603 eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL) 604 return 0; 605 if (eap->inner_non_eap && 606 eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_PAP && 607 eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_CHAP && 608 eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAP && 609 eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAPV2) 610 return 0; 611 } 612 613 if (eap->inner_method && 614 eap->inner_method != EAP_TYPE_GTC && 615 eap->inner_method != EAP_TYPE_MSCHAPV2) 616 return 0; 617 618 return 1; 619} 620 621 622static int nai_realm_cred_cert(struct nai_realm_eap *eap) 623{ 624 if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL) 625 return 0; /* method not supported */ 626 627 if (eap->method != EAP_TYPE_TLS) { 628 /* Only EAP-TLS supported for credential authentication */ 629 return 0; 630 } 631 632 return 1; 633} 634 635 636static struct nai_realm_eap * nai_realm_find_eap(struct wpa_cred *cred, 637 struct nai_realm *realm) 638{ 639 u8 e; 640 641 if (cred == NULL || 642 cred->username == NULL || 643 cred->username[0] == '\0' || 644 ((cred->password == NULL || 645 cred->password[0] == '\0') && 646 (cred->private_key == NULL || 647 cred->private_key[0] == '\0'))) 648 return NULL; 649 650 for (e = 0; e < realm->eap_count; e++) { 651 struct nai_realm_eap *eap = &realm->eap[e]; 652 if (cred->password && cred->password[0] && 653 nai_realm_cred_username(eap)) 654 return eap; 655 if (cred->private_key && cred->private_key[0] && 656 nai_realm_cred_cert(eap)) 657 return eap; 658 } 659 660 return NULL; 661} 662 663 664#ifdef INTERWORKING_3GPP 665 666static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len) 667{ 668 u8 plmn[3], plmn2[3]; 669 const u8 *pos, *end; 670 u8 udhl; 671 672 /* 673 * See Annex A of 3GPP TS 24.234 v8.1.0 for description. The network 674 * operator is allowed to include only two digits of the MNC, so allow 675 * matches based on both two and three digit MNC assumptions. Since some 676 * SIM/USIM cards may not expose MNC length conveniently, we may be 677 * provided the default MNC length 3 here and as such, checking with MNC 678 * length 2 is justifiable even though 3GPP TS 24.234 does not mention 679 * that case. Anyway, MCC/MNC pair where both 2 and 3 digit MNC is used 680 * with otherwise matching values would not be good idea in general, so 681 * this should not result in selecting incorrect networks. 682 */ 683 /* Match with 3 digit MNC */ 684 plmn[0] = (imsi[0] - '0') | ((imsi[1] - '0') << 4); 685 plmn[1] = (imsi[2] - '0') | ((imsi[5] - '0') << 4); 686 plmn[2] = (imsi[3] - '0') | ((imsi[4] - '0') << 4); 687 /* Match with 2 digit MNC */ 688 plmn2[0] = (imsi[0] - '0') | ((imsi[1] - '0') << 4); 689 plmn2[1] = (imsi[2] - '0') | 0xf0; 690 plmn2[2] = (imsi[3] - '0') | ((imsi[4] - '0') << 4); 691 692 if (anqp == NULL) 693 return 0; 694 pos = wpabuf_head_u8(anqp); 695 end = pos + wpabuf_len(anqp); 696 if (pos + 2 > end) 697 return 0; 698 if (*pos != 0) { 699 wpa_printf(MSG_DEBUG, "Unsupported GUD version 0x%x", *pos); 700 return 0; 701 } 702 pos++; 703 udhl = *pos++; 704 if (pos + udhl > end) { 705 wpa_printf(MSG_DEBUG, "Invalid UDHL"); 706 return 0; 707 } 708 end = pos + udhl; 709 710 wpa_printf(MSG_DEBUG, "Interworking: Matching against MCC/MNC alternatives: %02x:%02x:%02x or %02x:%02x:%02x (IMSI %s, MNC length %d)", 711 plmn[0], plmn[1], plmn[2], plmn2[0], plmn2[1], plmn2[2], 712 imsi, mnc_len); 713 714 while (pos + 2 <= end) { 715 u8 iei, len; 716 const u8 *l_end; 717 iei = *pos++; 718 len = *pos++ & 0x7f; 719 if (pos + len > end) 720 break; 721 l_end = pos + len; 722 723 if (iei == 0 && len > 0) { 724 /* PLMN List */ 725 u8 num, i; 726 wpa_hexdump(MSG_DEBUG, "Interworking: PLMN List information element", 727 pos, len); 728 num = *pos++; 729 for (i = 0; i < num; i++) { 730 if (pos + 3 > l_end) 731 break; 732 if (os_memcmp(pos, plmn, 3) == 0 || 733 os_memcmp(pos, plmn2, 3) == 0) 734 return 1; /* Found matching PLMN */ 735 pos += 3; 736 } 737 } else { 738 wpa_hexdump(MSG_DEBUG, "Interworking: Unrecognized 3GPP information element", 739 pos, len); 740 } 741 742 pos = l_end; 743 } 744 745 return 0; 746} 747 748 749static int build_root_nai(char *nai, size_t nai_len, const char *imsi, 750 size_t mnc_len, char prefix) 751{ 752 const char *sep, *msin; 753 char *end, *pos; 754 size_t msin_len, plmn_len; 755 756 /* 757 * TS 23.003, Clause 14 (3GPP to WLAN Interworking) 758 * Root NAI: 759 * <aka:0|sim:1><IMSI>@wlan.mnc<MNC>.mcc<MCC>.3gppnetwork.org 760 * <MNC> is zero-padded to three digits in case two-digit MNC is used 761 */ 762 763 if (imsi == NULL || os_strlen(imsi) > 16) { 764 wpa_printf(MSG_DEBUG, "No valid IMSI available"); 765 return -1; 766 } 767 sep = os_strchr(imsi, '-'); 768 if (sep) { 769 plmn_len = sep - imsi; 770 msin = sep + 1; 771 } else if (mnc_len && os_strlen(imsi) >= 3 + mnc_len) { 772 plmn_len = 3 + mnc_len; 773 msin = imsi + plmn_len; 774 } else 775 return -1; 776 if (plmn_len != 5 && plmn_len != 6) 777 return -1; 778 msin_len = os_strlen(msin); 779 780 pos = nai; 781 end = nai + nai_len; 782 if (prefix) 783 *pos++ = prefix; 784 os_memcpy(pos, imsi, plmn_len); 785 pos += plmn_len; 786 os_memcpy(pos, msin, msin_len); 787 pos += msin_len; 788 pos += os_snprintf(pos, end - pos, "@wlan.mnc"); 789 if (plmn_len == 5) { 790 *pos++ = '0'; 791 *pos++ = imsi[3]; 792 *pos++ = imsi[4]; 793 } else { 794 *pos++ = imsi[3]; 795 *pos++ = imsi[4]; 796 *pos++ = imsi[5]; 797 } 798 pos += os_snprintf(pos, end - pos, ".mcc%c%c%c.3gppnetwork.org", 799 imsi[0], imsi[1], imsi[2]); 800 801 return 0; 802} 803 804 805static int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix) 806{ 807 char nai[100]; 808 if (build_root_nai(nai, sizeof(nai), imsi, 0, prefix) < 0) 809 return -1; 810 return wpa_config_set_quoted(ssid, "identity", nai); 811} 812 813#endif /* INTERWORKING_3GPP */ 814 815 816static int already_connected(struct wpa_supplicant *wpa_s, 817 struct wpa_cred *cred, struct wpa_bss *bss) 818{ 819 struct wpa_ssid *ssid, *sel_ssid; 820 struct wpa_bss *selected; 821 822 if (wpa_s->wpa_state < WPA_ASSOCIATED || wpa_s->current_ssid == NULL) 823 return 0; 824 825 ssid = wpa_s->current_ssid; 826 if (ssid->parent_cred != cred) 827 return 0; 828 829 if (ssid->ssid_len != bss->ssid_len || 830 os_memcmp(ssid->ssid, bss->ssid, bss->ssid_len) != 0) 831 return 0; 832 833 sel_ssid = NULL; 834 selected = wpa_supplicant_pick_network(wpa_s, &sel_ssid); 835 if (selected && sel_ssid && sel_ssid->priority > ssid->priority) 836 return 0; /* higher priority network in scan results */ 837 838 return 1; 839} 840 841 842static void remove_duplicate_network(struct wpa_supplicant *wpa_s, 843 struct wpa_cred *cred, 844 struct wpa_bss *bss) 845{ 846 struct wpa_ssid *ssid; 847 848 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { 849 if (ssid->parent_cred != cred) 850 continue; 851 if (ssid->ssid_len != bss->ssid_len || 852 os_memcmp(ssid->ssid, bss->ssid, bss->ssid_len) != 0) 853 continue; 854 855 break; 856 } 857 858 if (ssid == NULL) 859 return; 860 861 wpa_printf(MSG_DEBUG, "Interworking: Remove duplicate network entry for the same credential"); 862 863 if (ssid == wpa_s->current_ssid) { 864 wpa_sm_set_config(wpa_s->wpa, NULL); 865 eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); 866 wpa_supplicant_deauthenticate(wpa_s, 867 WLAN_REASON_DEAUTH_LEAVING); 868 } 869 870 wpas_notify_network_removed(wpa_s, ssid); 871 wpa_config_remove_network(wpa_s->conf, ssid->id); 872} 873 874 875static int interworking_set_hs20_params(struct wpa_supplicant *wpa_s, 876 struct wpa_ssid *ssid) 877{ 878 if (wpa_config_set(ssid, "key_mgmt", 879 wpa_s->conf->pmf != NO_MGMT_FRAME_PROTECTION ? 880 "WPA-EAP WPA-EAP-SHA256" : "WPA-EAP", 0) < 0) 881 return -1; 882 if (wpa_config_set(ssid, "proto", "RSN", 0) < 0) 883 return -1; 884 if (wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0) 885 return -1; 886 return 0; 887} 888 889 890static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s, 891 struct wpa_cred *cred, 892 struct wpa_bss *bss) 893{ 894#ifdef INTERWORKING_3GPP 895 struct wpa_ssid *ssid; 896 int eap_type; 897 int res; 898 char prefix; 899 900 if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL) 901 return -1; 902 903 wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " (3GPP)", 904 MAC2STR(bss->bssid)); 905 906 if (already_connected(wpa_s, cred, bss)) { 907 wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR, 908 MAC2STR(bss->bssid)); 909 return 0; 910 } 911 912 remove_duplicate_network(wpa_s, cred, bss); 913 914 ssid = wpa_config_add_network(wpa_s->conf); 915 if (ssid == NULL) 916 return -1; 917 ssid->parent_cred = cred; 918 919 wpas_notify_network_added(wpa_s, ssid); 920 wpa_config_set_network_defaults(ssid); 921 ssid->priority = cred->priority; 922 ssid->temporary = 1; 923 ssid->ssid = os_zalloc(bss->ssid_len + 1); 924 if (ssid->ssid == NULL) 925 goto fail; 926 os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len); 927 ssid->ssid_len = bss->ssid_len; 928 ssid->eap.sim_num = cred->sim_num; 929 930 if (interworking_set_hs20_params(wpa_s, ssid) < 0) 931 goto fail; 932 933 eap_type = EAP_TYPE_SIM; 934 if (cred->pcsc && wpa_s->scard && scard_supports_umts(wpa_s->scard)) 935 eap_type = EAP_TYPE_AKA; 936 if (cred->eap_method && cred->eap_method[0].vendor == EAP_VENDOR_IETF) { 937 if (cred->eap_method[0].method == EAP_TYPE_SIM || 938 cred->eap_method[0].method == EAP_TYPE_AKA || 939 cred->eap_method[0].method == EAP_TYPE_AKA_PRIME) 940 eap_type = cred->eap_method[0].method; 941 } 942 943 switch (eap_type) { 944 case EAP_TYPE_SIM: 945 prefix = '1'; 946 res = wpa_config_set(ssid, "eap", "SIM", 0); 947 break; 948 case EAP_TYPE_AKA: 949 prefix = '0'; 950 res = wpa_config_set(ssid, "eap", "AKA", 0); 951 break; 952 case EAP_TYPE_AKA_PRIME: 953 prefix = '6'; 954 res = wpa_config_set(ssid, "eap", "AKA'", 0); 955 break; 956 default: 957 res = -1; 958 break; 959 } 960 if (res < 0) { 961 wpa_printf(MSG_DEBUG, "Selected EAP method (%d) not supported", 962 eap_type); 963 goto fail; 964 } 965 966 if (!cred->pcsc && set_root_nai(ssid, cred->imsi, prefix) < 0) { 967 wpa_printf(MSG_DEBUG, "Failed to set Root NAI"); 968 goto fail; 969 } 970 971 if (cred->milenage && cred->milenage[0]) { 972 if (wpa_config_set_quoted(ssid, "password", 973 cred->milenage) < 0) 974 goto fail; 975 } else if (cred->pcsc) { 976 if (wpa_config_set_quoted(ssid, "pcsc", "") < 0) 977 goto fail; 978 if (wpa_s->conf->pcsc_pin && 979 wpa_config_set_quoted(ssid, "pin", wpa_s->conf->pcsc_pin) 980 < 0) 981 goto fail; 982 } 983 984 wpa_s->next_ssid = ssid; 985 wpa_config_update_prio_list(wpa_s->conf); 986 interworking_reconnect(wpa_s); 987 988 return 0; 989 990fail: 991 wpas_notify_network_removed(wpa_s, ssid); 992 wpa_config_remove_network(wpa_s->conf, ssid->id); 993#endif /* INTERWORKING_3GPP */ 994 return -1; 995} 996 997 998static int roaming_consortium_element_match(const u8 *ie, const u8 *rc_id, 999 size_t rc_len) 1000{ 1001 const u8 *pos, *end; 1002 u8 lens; 1003 1004 if (ie == NULL) 1005 return 0; 1006 1007 pos = ie + 2; 1008 end = ie + 2 + ie[1]; 1009 1010 /* Roaming Consortium element: 1011 * Number of ANQP OIs 1012 * OI #1 and #2 lengths 1013 * OI #1, [OI #2], [OI #3] 1014 */ 1015 1016 if (pos + 2 > end) 1017 return 0; 1018 1019 pos++; /* skip Number of ANQP OIs */ 1020 lens = *pos++; 1021 if (pos + (lens & 0x0f) + (lens >> 4) > end) 1022 return 0; 1023 1024 if ((lens & 0x0f) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0) 1025 return 1; 1026 pos += lens & 0x0f; 1027 1028 if ((lens >> 4) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0) 1029 return 1; 1030 pos += lens >> 4; 1031 1032 if (pos < end && (size_t) (end - pos) == rc_len && 1033 os_memcmp(pos, rc_id, rc_len) == 0) 1034 return 1; 1035 1036 return 0; 1037} 1038 1039 1040static int roaming_consortium_anqp_match(const struct wpabuf *anqp, 1041 const u8 *rc_id, size_t rc_len) 1042{ 1043 const u8 *pos, *end; 1044 u8 len; 1045 1046 if (anqp == NULL) 1047 return 0; 1048 1049 pos = wpabuf_head(anqp); 1050 end = pos + wpabuf_len(anqp); 1051 1052 /* Set of <OI Length, OI> duples */ 1053 while (pos < end) { 1054 len = *pos++; 1055 if (pos + len > end) 1056 break; 1057 if (len == rc_len && os_memcmp(pos, rc_id, rc_len) == 0) 1058 return 1; 1059 pos += len; 1060 } 1061 1062 return 0; 1063} 1064 1065 1066static int roaming_consortium_match(const u8 *ie, const struct wpabuf *anqp, 1067 const u8 *rc_id, size_t rc_len) 1068{ 1069 return roaming_consortium_element_match(ie, rc_id, rc_len) || 1070 roaming_consortium_anqp_match(anqp, rc_id, rc_len); 1071} 1072 1073 1074static int cred_no_required_oi_match(struct wpa_cred *cred, struct wpa_bss *bss) 1075{ 1076 const u8 *ie; 1077 1078 if (cred->required_roaming_consortium_len == 0) 1079 return 0; 1080 1081 ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM); 1082 1083 if (ie == NULL && 1084 (bss->anqp == NULL || bss->anqp->roaming_consortium == NULL)) 1085 return 1; 1086 1087 return !roaming_consortium_match(ie, 1088 bss->anqp ? 1089 bss->anqp->roaming_consortium : NULL, 1090 cred->required_roaming_consortium, 1091 cred->required_roaming_consortium_len); 1092} 1093 1094 1095static int cred_excluded_ssid(struct wpa_cred *cred, struct wpa_bss *bss) 1096{ 1097 size_t i; 1098 1099 if (!cred->excluded_ssid) 1100 return 0; 1101 1102 for (i = 0; i < cred->num_excluded_ssid; i++) { 1103 struct excluded_ssid *e = &cred->excluded_ssid[i]; 1104 if (bss->ssid_len == e->ssid_len && 1105 os_memcmp(bss->ssid, e->ssid, e->ssid_len) == 0) 1106 return 1; 1107 } 1108 1109 return 0; 1110} 1111 1112 1113static int cred_below_min_backhaul(struct wpa_supplicant *wpa_s, 1114 struct wpa_cred *cred, struct wpa_bss *bss) 1115{ 1116 int res; 1117 unsigned int dl_bandwidth, ul_bandwidth; 1118 const u8 *wan; 1119 u8 wan_info, dl_load, ul_load; 1120 u16 lmd; 1121 u32 ul_speed, dl_speed; 1122 1123 if (!cred->min_dl_bandwidth_home && 1124 !cred->min_ul_bandwidth_home && 1125 !cred->min_dl_bandwidth_roaming && 1126 !cred->min_ul_bandwidth_roaming) 1127 return 0; /* No bandwidth constraint specified */ 1128 1129 if (bss->anqp == NULL || bss->anqp->hs20_wan_metrics == NULL) 1130 return 0; /* No WAN Metrics known - ignore constraint */ 1131 1132 wan = wpabuf_head(bss->anqp->hs20_wan_metrics); 1133 wan_info = wan[0]; 1134 if (wan_info & BIT(3)) 1135 return 1; /* WAN link at capacity */ 1136 lmd = WPA_GET_LE16(wan + 11); 1137 if (lmd == 0) 1138 return 0; /* Downlink/Uplink Load was not measured */ 1139 dl_speed = WPA_GET_LE32(wan + 1); 1140 ul_speed = WPA_GET_LE32(wan + 5); 1141 dl_load = wan[9]; 1142 ul_load = wan[10]; 1143 1144 if (dl_speed >= 0xffffff) 1145 dl_bandwidth = dl_speed / 255 * (255 - dl_load); 1146 else 1147 dl_bandwidth = dl_speed * (255 - dl_load) / 255; 1148 1149 if (ul_speed >= 0xffffff) 1150 ul_bandwidth = ul_speed / 255 * (255 - ul_load); 1151 else 1152 ul_bandwidth = ul_speed * (255 - ul_load) / 255; 1153 1154 res = interworking_home_sp_cred(wpa_s, cred, bss->anqp ? 1155 bss->anqp->domain_name : NULL); 1156 if (res > 0) { 1157 if (cred->min_dl_bandwidth_home > dl_bandwidth) 1158 return 1; 1159 if (cred->min_ul_bandwidth_home > ul_bandwidth) 1160 return 1; 1161 } else { 1162 if (cred->min_dl_bandwidth_roaming > dl_bandwidth) 1163 return 1; 1164 if (cred->min_ul_bandwidth_roaming > ul_bandwidth) 1165 return 1; 1166 } 1167 1168 return 0; 1169} 1170 1171 1172static int cred_over_max_bss_load(struct wpa_supplicant *wpa_s, 1173 struct wpa_cred *cred, struct wpa_bss *bss) 1174{ 1175 const u8 *ie; 1176 int res; 1177 1178 if (!cred->max_bss_load) 1179 return 0; /* No BSS Load constraint specified */ 1180 1181 ie = wpa_bss_get_ie(bss, WLAN_EID_BSS_LOAD); 1182 if (ie == NULL || ie[1] < 3) 1183 return 0; /* No BSS Load advertised */ 1184 1185 res = interworking_home_sp_cred(wpa_s, cred, bss->anqp ? 1186 bss->anqp->domain_name : NULL); 1187 if (res <= 0) 1188 return 0; /* Not a home network */ 1189 1190 return ie[4] > cred->max_bss_load; 1191} 1192 1193 1194static int has_proto_match(const u8 *pos, const u8 *end, u8 proto) 1195{ 1196 while (pos + 4 <= end) { 1197 if (pos[0] == proto && pos[3] == 1 /* Open */) 1198 return 1; 1199 pos += 4; 1200 } 1201 1202 return 0; 1203} 1204 1205 1206static int has_proto_port_match(const u8 *pos, const u8 *end, u8 proto, 1207 u16 port) 1208{ 1209 while (pos + 4 <= end) { 1210 if (pos[0] == proto && WPA_GET_LE16(&pos[1]) == port && 1211 pos[3] == 1 /* Open */) 1212 return 1; 1213 pos += 4; 1214 } 1215 1216 return 0; 1217} 1218 1219 1220static int cred_conn_capab_missing(struct wpa_supplicant *wpa_s, 1221 struct wpa_cred *cred, struct wpa_bss *bss) 1222{ 1223 int res; 1224 const u8 *capab, *end; 1225 unsigned int i, j; 1226 int *ports; 1227 1228 if (!cred->num_req_conn_capab) 1229 return 0; /* No connection capability constraint specified */ 1230 1231 if (bss->anqp == NULL || bss->anqp->hs20_connection_capability == NULL) 1232 return 0; /* No Connection Capability known - ignore constraint 1233 */ 1234 1235 res = interworking_home_sp_cred(wpa_s, cred, bss->anqp ? 1236 bss->anqp->domain_name : NULL); 1237 if (res > 0) 1238 return 0; /* No constraint in home network */ 1239 1240 capab = wpabuf_head(bss->anqp->hs20_connection_capability); 1241 end = capab + wpabuf_len(bss->anqp->hs20_connection_capability); 1242 1243 for (i = 0; i < cred->num_req_conn_capab; i++) { 1244 ports = cred->req_conn_capab_port[i]; 1245 if (!ports) { 1246 if (!has_proto_match(capab, end, 1247 cred->req_conn_capab_proto[i])) 1248 return 1; 1249 } else { 1250 for (j = 0; ports[j] > -1; j++) { 1251 if (!has_proto_port_match( 1252 capab, end, 1253 cred->req_conn_capab_proto[i], 1254 ports[j])) 1255 return 1; 1256 } 1257 } 1258 } 1259 1260 return 0; 1261} 1262 1263 1264static struct wpa_cred * interworking_credentials_available_roaming_consortium( 1265 struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int ignore_bw, 1266 int *excluded) 1267{ 1268 struct wpa_cred *cred, *selected = NULL; 1269 const u8 *ie; 1270 int is_excluded = 0; 1271 1272 ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM); 1273 1274 if (ie == NULL && 1275 (bss->anqp == NULL || bss->anqp->roaming_consortium == NULL)) 1276 return NULL; 1277 1278 if (wpa_s->conf->cred == NULL) 1279 return NULL; 1280 1281 for (cred = wpa_s->conf->cred; cred; cred = cred->next) { 1282 if (cred->roaming_consortium_len == 0) 1283 continue; 1284 1285 if (!roaming_consortium_match(ie, 1286 bss->anqp ? 1287 bss->anqp->roaming_consortium : 1288 NULL, 1289 cred->roaming_consortium, 1290 cred->roaming_consortium_len)) 1291 continue; 1292 1293 if (cred_no_required_oi_match(cred, bss)) 1294 continue; 1295 if (!ignore_bw && cred_below_min_backhaul(wpa_s, cred, bss)) 1296 continue; 1297 if (!ignore_bw && cred_over_max_bss_load(wpa_s, cred, bss)) 1298 continue; 1299 if (!ignore_bw && cred_conn_capab_missing(wpa_s, cred, bss)) 1300 continue; 1301 if (cred_excluded_ssid(cred, bss)) { 1302 if (excluded == NULL) 1303 continue; 1304 if (selected == NULL) { 1305 selected = cred; 1306 is_excluded = 1; 1307 } 1308 } else { 1309 if (selected == NULL || is_excluded || 1310 cred_prio_cmp(selected, cred) < 0) { 1311 selected = cred; 1312 is_excluded = 0; 1313 } 1314 } 1315 } 1316 1317 if (excluded) 1318 *excluded = is_excluded; 1319 1320 return selected; 1321} 1322 1323 1324static int interworking_set_eap_params(struct wpa_ssid *ssid, 1325 struct wpa_cred *cred, int ttls) 1326{ 1327 if (cred->eap_method) { 1328 ttls = cred->eap_method->vendor == EAP_VENDOR_IETF && 1329 cred->eap_method->method == EAP_TYPE_TTLS; 1330 1331 os_free(ssid->eap.eap_methods); 1332 ssid->eap.eap_methods = 1333 os_malloc(sizeof(struct eap_method_type) * 2); 1334 if (ssid->eap.eap_methods == NULL) 1335 return -1; 1336 os_memcpy(ssid->eap.eap_methods, cred->eap_method, 1337 sizeof(*cred->eap_method)); 1338 ssid->eap.eap_methods[1].vendor = EAP_VENDOR_IETF; 1339 ssid->eap.eap_methods[1].method = EAP_TYPE_NONE; 1340 } 1341 1342 if (ttls && cred->username && cred->username[0]) { 1343 const char *pos; 1344 char *anon; 1345 /* Use anonymous NAI in Phase 1 */ 1346 pos = os_strchr(cred->username, '@'); 1347 if (pos) { 1348 size_t buflen = 9 + os_strlen(pos) + 1; 1349 anon = os_malloc(buflen); 1350 if (anon == NULL) 1351 return -1; 1352 os_snprintf(anon, buflen, "anonymous%s", pos); 1353 } else if (cred->realm) { 1354 size_t buflen = 10 + os_strlen(cred->realm) + 1; 1355 anon = os_malloc(buflen); 1356 if (anon == NULL) 1357 return -1; 1358 os_snprintf(anon, buflen, "anonymous@%s", cred->realm); 1359 } else { 1360 anon = os_strdup("anonymous"); 1361 if (anon == NULL) 1362 return -1; 1363 } 1364 if (wpa_config_set_quoted(ssid, "anonymous_identity", anon) < 1365 0) { 1366 os_free(anon); 1367 return -1; 1368 } 1369 os_free(anon); 1370 } 1371 1372 if (cred->username && cred->username[0] && 1373 wpa_config_set_quoted(ssid, "identity", cred->username) < 0) 1374 return -1; 1375 1376 if (cred->password && cred->password[0]) { 1377 if (cred->ext_password && 1378 wpa_config_set(ssid, "password", cred->password, 0) < 0) 1379 return -1; 1380 if (!cred->ext_password && 1381 wpa_config_set_quoted(ssid, "password", cred->password) < 1382 0) 1383 return -1; 1384 } 1385 1386 if (cred->client_cert && cred->client_cert[0] && 1387 wpa_config_set_quoted(ssid, "client_cert", cred->client_cert) < 0) 1388 return -1; 1389 1390#ifdef ANDROID 1391 if (cred->private_key && 1392 os_strncmp(cred->private_key, "keystore://", 11) == 0) { 1393 /* Use OpenSSL engine configuration for Android keystore */ 1394 if (wpa_config_set_quoted(ssid, "engine_id", "keystore") < 0 || 1395 wpa_config_set_quoted(ssid, "key_id", 1396 cred->private_key + 11) < 0 || 1397 wpa_config_set(ssid, "engine", "1", 0) < 0) 1398 return -1; 1399 } else 1400#endif /* ANDROID */ 1401 if (cred->private_key && cred->private_key[0] && 1402 wpa_config_set_quoted(ssid, "private_key", cred->private_key) < 0) 1403 return -1; 1404 1405 if (cred->private_key_passwd && cred->private_key_passwd[0] && 1406 wpa_config_set_quoted(ssid, "private_key_passwd", 1407 cred->private_key_passwd) < 0) 1408 return -1; 1409 1410 if (cred->phase1) { 1411 os_free(ssid->eap.phase1); 1412 ssid->eap.phase1 = os_strdup(cred->phase1); 1413 } 1414 if (cred->phase2) { 1415 os_free(ssid->eap.phase2); 1416 ssid->eap.phase2 = os_strdup(cred->phase2); 1417 } 1418 1419 if (cred->ca_cert && cred->ca_cert[0] && 1420 wpa_config_set_quoted(ssid, "ca_cert", cred->ca_cert) < 0) 1421 return -1; 1422 1423 if (cred->domain_suffix_match && cred->domain_suffix_match[0] && 1424 wpa_config_set_quoted(ssid, "domain_suffix_match", 1425 cred->domain_suffix_match) < 0) 1426 return -1; 1427 1428 ssid->eap.ocsp = cred->ocsp; 1429 1430 return 0; 1431} 1432 1433 1434static int interworking_connect_roaming_consortium( 1435 struct wpa_supplicant *wpa_s, struct wpa_cred *cred, 1436 struct wpa_bss *bss) 1437{ 1438 struct wpa_ssid *ssid; 1439 1440 wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " based on " 1441 "roaming consortium match", MAC2STR(bss->bssid)); 1442 1443 if (already_connected(wpa_s, cred, bss)) { 1444 wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR, 1445 MAC2STR(bss->bssid)); 1446 return 0; 1447 } 1448 1449 remove_duplicate_network(wpa_s, cred, bss); 1450 1451 ssid = wpa_config_add_network(wpa_s->conf); 1452 if (ssid == NULL) 1453 return -1; 1454 ssid->parent_cred = cred; 1455 wpas_notify_network_added(wpa_s, ssid); 1456 wpa_config_set_network_defaults(ssid); 1457 ssid->priority = cred->priority; 1458 ssid->temporary = 1; 1459 ssid->ssid = os_zalloc(bss->ssid_len + 1); 1460 if (ssid->ssid == NULL) 1461 goto fail; 1462 os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len); 1463 ssid->ssid_len = bss->ssid_len; 1464 1465 if (interworking_set_hs20_params(wpa_s, ssid) < 0) 1466 goto fail; 1467 1468 if (cred->eap_method == NULL) { 1469 wpa_printf(MSG_DEBUG, "Interworking: No EAP method set for " 1470 "credential using roaming consortium"); 1471 goto fail; 1472 } 1473 1474 if (interworking_set_eap_params( 1475 ssid, cred, 1476 cred->eap_method->vendor == EAP_VENDOR_IETF && 1477 cred->eap_method->method == EAP_TYPE_TTLS) < 0) 1478 goto fail; 1479 1480 wpa_s->next_ssid = ssid; 1481 wpa_config_update_prio_list(wpa_s->conf); 1482 interworking_reconnect(wpa_s); 1483 1484 return 0; 1485 1486fail: 1487 wpas_notify_network_removed(wpa_s, ssid); 1488 wpa_config_remove_network(wpa_s->conf, ssid->id); 1489 return -1; 1490} 1491 1492 1493static int interworking_connect_helper(struct wpa_supplicant *wpa_s, 1494 struct wpa_bss *bss, int allow_excluded) 1495{ 1496 struct wpa_cred *cred, *cred_rc, *cred_3gpp; 1497 struct wpa_ssid *ssid; 1498 struct nai_realm *realm; 1499 struct nai_realm_eap *eap = NULL; 1500 u16 count, i; 1501 char buf[100]; 1502 int excluded = 0, *excl = allow_excluded ? &excluded : NULL; 1503 1504 if (wpa_s->conf->cred == NULL || bss == NULL) 1505 return -1; 1506 if (disallowed_bssid(wpa_s, bss->bssid) || 1507 disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) { 1508 wpa_printf(MSG_DEBUG, "Interworking: Reject connection to disallowed BSS " 1509 MACSTR, MAC2STR(bss->bssid)); 1510 return -1; 1511 } 1512 1513 wpa_printf(MSG_DEBUG, "Interworking: Considering BSS " MACSTR 1514 " for connection (allow_excluded=%d)", 1515 MAC2STR(bss->bssid), allow_excluded); 1516 1517 if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) { 1518 /* 1519 * We currently support only HS 2.0 networks and those are 1520 * required to use WPA2-Enterprise. 1521 */ 1522 wpa_printf(MSG_DEBUG, "Interworking: Network does not use " 1523 "RSN"); 1524 return -1; 1525 } 1526 1527 cred_rc = interworking_credentials_available_roaming_consortium( 1528 wpa_s, bss, 0, excl); 1529 if (cred_rc) { 1530 wpa_printf(MSG_DEBUG, "Interworking: Highest roaming " 1531 "consortium matching credential priority %d " 1532 "sp_priority %d", 1533 cred_rc->priority, cred_rc->sp_priority); 1534 if (allow_excluded && excl && !(*excl)) 1535 excl = NULL; 1536 } 1537 1538 cred = interworking_credentials_available_realm(wpa_s, bss, 0, excl); 1539 if (cred) { 1540 wpa_printf(MSG_DEBUG, "Interworking: Highest NAI Realm list " 1541 "matching credential priority %d sp_priority %d", 1542 cred->priority, cred->sp_priority); 1543 if (allow_excluded && excl && !(*excl)) 1544 excl = NULL; 1545 } 1546 1547 cred_3gpp = interworking_credentials_available_3gpp(wpa_s, bss, 0, 1548 excl); 1549 if (cred_3gpp) { 1550 wpa_printf(MSG_DEBUG, "Interworking: Highest 3GPP matching " 1551 "credential priority %d sp_priority %d", 1552 cred_3gpp->priority, cred_3gpp->sp_priority); 1553 if (allow_excluded && excl && !(*excl)) 1554 excl = NULL; 1555 } 1556 1557 if (!cred_rc && !cred && !cred_3gpp) { 1558 wpa_printf(MSG_DEBUG, "Interworking: No full credential matches - consider options without BW(etc.) limits"); 1559 cred_rc = interworking_credentials_available_roaming_consortium( 1560 wpa_s, bss, 1, excl); 1561 if (cred_rc) { 1562 wpa_printf(MSG_DEBUG, "Interworking: Highest roaming " 1563 "consortium matching credential priority %d " 1564 "sp_priority %d (ignore BW)", 1565 cred_rc->priority, cred_rc->sp_priority); 1566 if (allow_excluded && excl && !(*excl)) 1567 excl = NULL; 1568 } 1569 1570 cred = interworking_credentials_available_realm(wpa_s, bss, 1, 1571 excl); 1572 if (cred) { 1573 wpa_printf(MSG_DEBUG, "Interworking: Highest NAI Realm " 1574 "list matching credential priority %d " 1575 "sp_priority %d (ignore BW)", 1576 cred->priority, cred->sp_priority); 1577 if (allow_excluded && excl && !(*excl)) 1578 excl = NULL; 1579 } 1580 1581 cred_3gpp = interworking_credentials_available_3gpp(wpa_s, bss, 1582 1, excl); 1583 if (cred_3gpp) { 1584 wpa_printf(MSG_DEBUG, "Interworking: Highest 3GPP " 1585 "matching credential priority %d " 1586 "sp_priority %d (ignore BW)", 1587 cred_3gpp->priority, cred_3gpp->sp_priority); 1588 if (allow_excluded && excl && !(*excl)) 1589 excl = NULL; 1590 } 1591 } 1592 1593 if (cred_rc && 1594 (cred == NULL || cred_prio_cmp(cred_rc, cred) >= 0) && 1595 (cred_3gpp == NULL || cred_prio_cmp(cred_rc, cred_3gpp) >= 0)) 1596 return interworking_connect_roaming_consortium(wpa_s, cred_rc, 1597 bss); 1598 1599 if (cred_3gpp && 1600 (cred == NULL || cred_prio_cmp(cred_3gpp, cred) >= 0)) { 1601 return interworking_connect_3gpp(wpa_s, cred_3gpp, bss); 1602 } 1603 1604 if (cred == NULL) { 1605 wpa_printf(MSG_DEBUG, "Interworking: No matching credentials " 1606 "found for " MACSTR, MAC2STR(bss->bssid)); 1607 return -1; 1608 } 1609 1610 realm = nai_realm_parse(bss->anqp ? bss->anqp->nai_realm : NULL, 1611 &count); 1612 if (realm == NULL) { 1613 wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI " 1614 "Realm list from " MACSTR, MAC2STR(bss->bssid)); 1615 return -1; 1616 } 1617 1618 for (i = 0; i < count; i++) { 1619 if (!nai_realm_match(&realm[i], cred->realm)) 1620 continue; 1621 eap = nai_realm_find_eap(cred, &realm[i]); 1622 if (eap) 1623 break; 1624 } 1625 1626 if (!eap) { 1627 wpa_printf(MSG_DEBUG, "Interworking: No matching credentials " 1628 "and EAP method found for " MACSTR, 1629 MAC2STR(bss->bssid)); 1630 nai_realm_free(realm, count); 1631 return -1; 1632 } 1633 1634 wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR, 1635 MAC2STR(bss->bssid)); 1636 1637 if (already_connected(wpa_s, cred, bss)) { 1638 wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR, 1639 MAC2STR(bss->bssid)); 1640 nai_realm_free(realm, count); 1641 return 0; 1642 } 1643 1644 remove_duplicate_network(wpa_s, cred, bss); 1645 1646 ssid = wpa_config_add_network(wpa_s->conf); 1647 if (ssid == NULL) { 1648 nai_realm_free(realm, count); 1649 return -1; 1650 } 1651 ssid->parent_cred = cred; 1652 wpas_notify_network_added(wpa_s, ssid); 1653 wpa_config_set_network_defaults(ssid); 1654 ssid->priority = cred->priority; 1655 ssid->temporary = 1; 1656 ssid->ssid = os_zalloc(bss->ssid_len + 1); 1657 if (ssid->ssid == NULL) 1658 goto fail; 1659 os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len); 1660 ssid->ssid_len = bss->ssid_len; 1661 1662 if (interworking_set_hs20_params(wpa_s, ssid) < 0) 1663 goto fail; 1664 1665 if (wpa_config_set(ssid, "eap", eap_get_name(EAP_VENDOR_IETF, 1666 eap->method), 0) < 0) 1667 goto fail; 1668 1669 switch (eap->method) { 1670 case EAP_TYPE_TTLS: 1671 if (eap->inner_method) { 1672 os_snprintf(buf, sizeof(buf), "\"autheap=%s\"", 1673 eap_get_name(EAP_VENDOR_IETF, 1674 eap->inner_method)); 1675 if (wpa_config_set(ssid, "phase2", buf, 0) < 0) 1676 goto fail; 1677 break; 1678 } 1679 switch (eap->inner_non_eap) { 1680 case NAI_REALM_INNER_NON_EAP_PAP: 1681 if (wpa_config_set(ssid, "phase2", "\"auth=PAP\"", 0) < 1682 0) 1683 goto fail; 1684 break; 1685 case NAI_REALM_INNER_NON_EAP_CHAP: 1686 if (wpa_config_set(ssid, "phase2", "\"auth=CHAP\"", 0) 1687 < 0) 1688 goto fail; 1689 break; 1690 case NAI_REALM_INNER_NON_EAP_MSCHAP: 1691 if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAP\"", 1692 0) < 0) 1693 goto fail; 1694 break; 1695 case NAI_REALM_INNER_NON_EAP_MSCHAPV2: 1696 if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAPV2\"", 1697 0) < 0) 1698 goto fail; 1699 break; 1700 default: 1701 /* EAP params were not set - assume TTLS/MSCHAPv2 */ 1702 if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAPV2\"", 1703 0) < 0) 1704 goto fail; 1705 break; 1706 } 1707 break; 1708 case EAP_TYPE_PEAP: 1709 case EAP_TYPE_FAST: 1710 if (wpa_config_set(ssid, "phase1", "\"fast_provisioning=2\"", 1711 0) < 0) 1712 goto fail; 1713 if (wpa_config_set(ssid, "pac_file", 1714 "\"blob://pac_interworking\"", 0) < 0) 1715 goto fail; 1716 os_snprintf(buf, sizeof(buf), "\"auth=%s\"", 1717 eap_get_name(EAP_VENDOR_IETF, 1718 eap->inner_method ? 1719 eap->inner_method : 1720 EAP_TYPE_MSCHAPV2)); 1721 if (wpa_config_set(ssid, "phase2", buf, 0) < 0) 1722 goto fail; 1723 break; 1724 case EAP_TYPE_TLS: 1725 break; 1726 } 1727 1728 if (interworking_set_eap_params(ssid, cred, 1729 eap->method == EAP_TYPE_TTLS) < 0) 1730 goto fail; 1731 1732 nai_realm_free(realm, count); 1733 1734 wpa_s->next_ssid = ssid; 1735 wpa_config_update_prio_list(wpa_s->conf); 1736 interworking_reconnect(wpa_s); 1737 1738 return 0; 1739 1740fail: 1741 wpas_notify_network_removed(wpa_s, ssid); 1742 wpa_config_remove_network(wpa_s->conf, ssid->id); 1743 nai_realm_free(realm, count); 1744 return -1; 1745} 1746 1747 1748int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) 1749{ 1750 return interworking_connect_helper(wpa_s, bss, 1); 1751} 1752 1753 1754#ifdef PCSC_FUNCS 1755static int interworking_pcsc_read_imsi(struct wpa_supplicant *wpa_s) 1756{ 1757 size_t len; 1758 1759 if (wpa_s->imsi[0] && wpa_s->mnc_len) 1760 return 0; 1761 1762 len = sizeof(wpa_s->imsi) - 1; 1763 if (scard_get_imsi(wpa_s->scard, wpa_s->imsi, &len)) { 1764 scard_deinit(wpa_s->scard); 1765 wpa_s->scard = NULL; 1766 wpa_msg(wpa_s, MSG_ERROR, "Could not read IMSI"); 1767 return -1; 1768 } 1769 wpa_s->imsi[len] = '\0'; 1770 wpa_s->mnc_len = scard_get_mnc_len(wpa_s->scard); 1771 wpa_printf(MSG_DEBUG, "SCARD: IMSI %s (MNC length %d)", 1772 wpa_s->imsi, wpa_s->mnc_len); 1773 1774 return 0; 1775} 1776#endif /* PCSC_FUNCS */ 1777 1778 1779static struct wpa_cred * interworking_credentials_available_3gpp( 1780 struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int ignore_bw, 1781 int *excluded) 1782{ 1783 struct wpa_cred *selected = NULL; 1784#ifdef INTERWORKING_3GPP 1785 struct wpa_cred *cred; 1786 int ret; 1787 int is_excluded = 0; 1788 1789 if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL) 1790 return NULL; 1791 1792#ifdef CONFIG_EAP_PROXY 1793 if (!wpa_s->imsi[0]) { 1794 size_t len; 1795 wpa_printf(MSG_DEBUG, "Interworking: IMSI not available - try to read again through eap_proxy"); 1796 wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol, 1797 wpa_s->imsi, 1798 &len); 1799 if (wpa_s->mnc_len > 0) { 1800 wpa_s->imsi[len] = '\0'; 1801 wpa_printf(MSG_DEBUG, "eap_proxy: IMSI %s (MNC length %d)", 1802 wpa_s->imsi, wpa_s->mnc_len); 1803 } else { 1804 wpa_printf(MSG_DEBUG, "eap_proxy: IMSI not available"); 1805 } 1806 } 1807#endif /* CONFIG_EAP_PROXY */ 1808 1809 for (cred = wpa_s->conf->cred; cred; cred = cred->next) { 1810 char *sep; 1811 const char *imsi; 1812 int mnc_len; 1813 char imsi_buf[16]; 1814 size_t msin_len; 1815 1816#ifdef PCSC_FUNCS 1817 if (cred->pcsc && wpa_s->scard) { 1818 if (interworking_pcsc_read_imsi(wpa_s) < 0) 1819 continue; 1820 imsi = wpa_s->imsi; 1821 mnc_len = wpa_s->mnc_len; 1822 goto compare; 1823 } 1824#endif /* PCSC_FUNCS */ 1825#ifdef CONFIG_EAP_PROXY 1826 if (cred->pcsc && wpa_s->mnc_len > 0 && wpa_s->imsi[0]) { 1827 imsi = wpa_s->imsi; 1828 mnc_len = wpa_s->mnc_len; 1829 goto compare; 1830 } 1831#endif /* CONFIG_EAP_PROXY */ 1832 1833 if (cred->imsi == NULL || !cred->imsi[0] || 1834 (!wpa_s->conf->external_sim && 1835 (cred->milenage == NULL || !cred->milenage[0]))) 1836 continue; 1837 1838 sep = os_strchr(cred->imsi, '-'); 1839 if (sep == NULL || 1840 (sep - cred->imsi != 5 && sep - cred->imsi != 6)) 1841 continue; 1842 mnc_len = sep - cred->imsi - 3; 1843 os_memcpy(imsi_buf, cred->imsi, 3 + mnc_len); 1844 sep++; 1845 msin_len = os_strlen(cred->imsi); 1846 if (3 + mnc_len + msin_len >= sizeof(imsi_buf) - 1) 1847 msin_len = sizeof(imsi_buf) - 3 - mnc_len - 1; 1848 os_memcpy(&imsi_buf[3 + mnc_len], sep, msin_len); 1849 imsi_buf[3 + mnc_len + msin_len] = '\0'; 1850 imsi = imsi_buf; 1851 1852#if defined(PCSC_FUNCS) || defined(CONFIG_EAP_PROXY) 1853 compare: 1854#endif /* PCSC_FUNCS || CONFIG_EAP_PROXY */ 1855 wpa_printf(MSG_DEBUG, "Interworking: Parsing 3GPP info from " 1856 MACSTR, MAC2STR(bss->bssid)); 1857 ret = plmn_id_match(bss->anqp->anqp_3gpp, imsi, mnc_len); 1858 wpa_printf(MSG_DEBUG, "PLMN match %sfound", ret ? "" : "not "); 1859 if (ret) { 1860 if (cred_no_required_oi_match(cred, bss)) 1861 continue; 1862 if (!ignore_bw && 1863 cred_below_min_backhaul(wpa_s, cred, bss)) 1864 continue; 1865 if (!ignore_bw && 1866 cred_over_max_bss_load(wpa_s, cred, bss)) 1867 continue; 1868 if (!ignore_bw && 1869 cred_conn_capab_missing(wpa_s, cred, bss)) 1870 continue; 1871 if (cred_excluded_ssid(cred, bss)) { 1872 if (excluded == NULL) 1873 continue; 1874 if (selected == NULL) { 1875 selected = cred; 1876 is_excluded = 1; 1877 } 1878 } else { 1879 if (selected == NULL || is_excluded || 1880 cred_prio_cmp(selected, cred) < 0) { 1881 selected = cred; 1882 is_excluded = 0; 1883 } 1884 } 1885 } 1886 } 1887 1888 if (excluded) 1889 *excluded = is_excluded; 1890#endif /* INTERWORKING_3GPP */ 1891 return selected; 1892} 1893 1894 1895static struct wpa_cred * interworking_credentials_available_realm( 1896 struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int ignore_bw, 1897 int *excluded) 1898{ 1899 struct wpa_cred *cred, *selected = NULL; 1900 struct nai_realm *realm; 1901 u16 count, i; 1902 int is_excluded = 0; 1903 1904 if (bss->anqp == NULL || bss->anqp->nai_realm == NULL) 1905 return NULL; 1906 1907 if (wpa_s->conf->cred == NULL) 1908 return NULL; 1909 1910 wpa_printf(MSG_DEBUG, "Interworking: Parsing NAI Realm list from " 1911 MACSTR, MAC2STR(bss->bssid)); 1912 realm = nai_realm_parse(bss->anqp->nai_realm, &count); 1913 if (realm == NULL) { 1914 wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI " 1915 "Realm list from " MACSTR, MAC2STR(bss->bssid)); 1916 return NULL; 1917 } 1918 1919 for (cred = wpa_s->conf->cred; cred; cred = cred->next) { 1920 if (cred->realm == NULL) 1921 continue; 1922 1923 for (i = 0; i < count; i++) { 1924 if (!nai_realm_match(&realm[i], cred->realm)) 1925 continue; 1926 if (nai_realm_find_eap(cred, &realm[i])) { 1927 if (cred_no_required_oi_match(cred, bss)) 1928 continue; 1929 if (!ignore_bw && 1930 cred_below_min_backhaul(wpa_s, cred, bss)) 1931 continue; 1932 if (!ignore_bw && 1933 cred_over_max_bss_load(wpa_s, cred, bss)) 1934 continue; 1935 if (!ignore_bw && 1936 cred_conn_capab_missing(wpa_s, cred, bss)) 1937 continue; 1938 if (cred_excluded_ssid(cred, bss)) { 1939 if (excluded == NULL) 1940 continue; 1941 if (selected == NULL) { 1942 selected = cred; 1943 is_excluded = 1; 1944 } 1945 } else { 1946 if (selected == NULL || is_excluded || 1947 cred_prio_cmp(selected, cred) < 0) 1948 { 1949 selected = cred; 1950 is_excluded = 0; 1951 } 1952 } 1953 break; 1954 } 1955 } 1956 } 1957 1958 nai_realm_free(realm, count); 1959 1960 if (excluded) 1961 *excluded = is_excluded; 1962 1963 return selected; 1964} 1965 1966 1967static struct wpa_cred * interworking_credentials_available_helper( 1968 struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int ignore_bw, 1969 int *excluded) 1970{ 1971 struct wpa_cred *cred, *cred2; 1972 int excluded1, excluded2; 1973 1974 if (disallowed_bssid(wpa_s, bss->bssid) || 1975 disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) { 1976 wpa_printf(MSG_DEBUG, "Interworking: Ignore disallowed BSS " 1977 MACSTR, MAC2STR(bss->bssid)); 1978 return NULL; 1979 } 1980 1981 cred = interworking_credentials_available_realm(wpa_s, bss, ignore_bw, 1982 &excluded1); 1983 cred2 = interworking_credentials_available_3gpp(wpa_s, bss, ignore_bw, 1984 &excluded2); 1985 if (cred && cred2 && 1986 (cred_prio_cmp(cred2, cred) >= 0 || (!excluded2 && excluded1))) { 1987 cred = cred2; 1988 excluded1 = excluded2; 1989 } 1990 if (!cred) { 1991 cred = cred2; 1992 excluded1 = excluded2; 1993 } 1994 1995 cred2 = interworking_credentials_available_roaming_consortium( 1996 wpa_s, bss, ignore_bw, &excluded2); 1997 if (cred && cred2 && 1998 (cred_prio_cmp(cred2, cred) >= 0 || (!excluded2 && excluded1))) { 1999 cred = cred2; 2000 excluded1 = excluded2; 2001 } 2002 if (!cred) { 2003 cred = cred2; 2004 excluded1 = excluded2; 2005 } 2006 2007 if (excluded) 2008 *excluded = excluded1; 2009 return cred; 2010} 2011 2012 2013static struct wpa_cred * interworking_credentials_available( 2014 struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int *excluded) 2015{ 2016 struct wpa_cred *cred; 2017 2018 if (excluded) 2019 *excluded = 0; 2020 cred = interworking_credentials_available_helper(wpa_s, bss, 0, 2021 excluded); 2022 if (cred) 2023 return cred; 2024 return interworking_credentials_available_helper(wpa_s, bss, 1, 2025 excluded); 2026} 2027 2028 2029int domain_name_list_contains(struct wpabuf *domain_names, 2030 const char *domain, int exact_match) 2031{ 2032 const u8 *pos, *end; 2033 size_t len; 2034 2035 len = os_strlen(domain); 2036 pos = wpabuf_head(domain_names); 2037 end = pos + wpabuf_len(domain_names); 2038 2039 while (pos + 1 < end) { 2040 if (pos + 1 + pos[0] > end) 2041 break; 2042 2043 wpa_hexdump_ascii(MSG_DEBUG, "Interworking: AP domain name", 2044 pos + 1, pos[0]); 2045 if (pos[0] == len && 2046 os_strncasecmp(domain, (const char *) (pos + 1), len) == 0) 2047 return 1; 2048 if (!exact_match && pos[0] > len && pos[pos[0] - len] == '.') { 2049 const char *ap = (const char *) (pos + 1); 2050 int offset = pos[0] - len; 2051 if (os_strncasecmp(domain, ap + offset, len) == 0) 2052 return 1; 2053 } 2054 2055 pos += 1 + pos[0]; 2056 } 2057 2058 return 0; 2059} 2060 2061 2062int interworking_home_sp_cred(struct wpa_supplicant *wpa_s, 2063 struct wpa_cred *cred, 2064 struct wpabuf *domain_names) 2065{ 2066 size_t i; 2067 int ret = -1; 2068#ifdef INTERWORKING_3GPP 2069 char nai[100], *realm; 2070 2071 char *imsi = NULL; 2072 int mnc_len = 0; 2073 if (cred->imsi) 2074 imsi = cred->imsi; 2075#ifdef PCSC_FUNCS 2076 else if (cred->pcsc && wpa_s->scard) { 2077 if (interworking_pcsc_read_imsi(wpa_s) < 0) 2078 return -1; 2079 imsi = wpa_s->imsi; 2080 mnc_len = wpa_s->mnc_len; 2081 } 2082#endif /* PCSC_FUNCS */ 2083#ifdef CONFIG_EAP_PROXY 2084 else if (cred->pcsc && wpa_s->mnc_len > 0 && wpa_s->imsi[0]) { 2085 imsi = wpa_s->imsi; 2086 mnc_len = wpa_s->mnc_len; 2087 } 2088#endif /* CONFIG_EAP_PROXY */ 2089 if (domain_names && 2090 imsi && build_root_nai(nai, sizeof(nai), imsi, mnc_len, 0) == 0) { 2091 realm = os_strchr(nai, '@'); 2092 if (realm) 2093 realm++; 2094 wpa_printf(MSG_DEBUG, "Interworking: Search for match " 2095 "with SIM/USIM domain %s", realm); 2096 if (realm && 2097 domain_name_list_contains(domain_names, realm, 1)) 2098 return 1; 2099 if (realm) 2100 ret = 0; 2101 } 2102#endif /* INTERWORKING_3GPP */ 2103 2104 if (domain_names == NULL || cred->domain == NULL) 2105 return ret; 2106 2107 for (i = 0; i < cred->num_domain; i++) { 2108 wpa_printf(MSG_DEBUG, "Interworking: Search for match with " 2109 "home SP FQDN %s", cred->domain[i]); 2110 if (domain_name_list_contains(domain_names, cred->domain[i], 1)) 2111 return 1; 2112 } 2113 2114 return 0; 2115} 2116 2117 2118static int interworking_home_sp(struct wpa_supplicant *wpa_s, 2119 struct wpabuf *domain_names) 2120{ 2121 struct wpa_cred *cred; 2122 2123 if (domain_names == NULL || wpa_s->conf->cred == NULL) 2124 return -1; 2125 2126 for (cred = wpa_s->conf->cred; cred; cred = cred->next) { 2127 int res = interworking_home_sp_cred(wpa_s, cred, domain_names); 2128 if (res) 2129 return res; 2130 } 2131 2132 return 0; 2133} 2134 2135 2136static int interworking_find_network_match(struct wpa_supplicant *wpa_s) 2137{ 2138 struct wpa_bss *bss; 2139 struct wpa_ssid *ssid; 2140 2141 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { 2142 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { 2143 if (wpas_network_disabled(wpa_s, ssid) || 2144 ssid->mode != WPAS_MODE_INFRA) 2145 continue; 2146 if (ssid->ssid_len != bss->ssid_len || 2147 os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) != 2148 0) 2149 continue; 2150 /* 2151 * TODO: Consider more accurate matching of security 2152 * configuration similarly to what is done in events.c 2153 */ 2154 return 1; 2155 } 2156 } 2157 2158 return 0; 2159} 2160 2161 2162static int roaming_partner_match(struct wpa_supplicant *wpa_s, 2163 struct roaming_partner *partner, 2164 struct wpabuf *domain_names) 2165{ 2166 wpa_printf(MSG_DEBUG, "Interworking: Comparing roaming_partner info fqdn='%s' exact_match=%d priority=%u country='%s'", 2167 partner->fqdn, partner->exact_match, partner->priority, 2168 partner->country); 2169 wpa_hexdump_ascii(MSG_DEBUG, "Interworking: Domain names", 2170 wpabuf_head(domain_names), 2171 wpabuf_len(domain_names)); 2172 if (!domain_name_list_contains(domain_names, partner->fqdn, 2173 partner->exact_match)) 2174 return 0; 2175 /* TODO: match Country */ 2176 return 1; 2177} 2178 2179 2180static u8 roaming_prio(struct wpa_supplicant *wpa_s, struct wpa_cred *cred, 2181 struct wpa_bss *bss) 2182{ 2183 size_t i; 2184 2185 if (bss->anqp == NULL || bss->anqp->domain_name == NULL) { 2186 wpa_printf(MSG_DEBUG, "Interworking: No ANQP domain name info -> use default roaming partner priority 128"); 2187 return 128; /* cannot check preference with domain name */ 2188 } 2189 2190 if (interworking_home_sp_cred(wpa_s, cred, bss->anqp->domain_name) > 0) 2191 { 2192 wpa_printf(MSG_DEBUG, "Interworking: Determined to be home SP -> use maximum preference 0 as roaming partner priority"); 2193 return 0; /* max preference for home SP network */ 2194 } 2195 2196 for (i = 0; i < cred->num_roaming_partner; i++) { 2197 if (roaming_partner_match(wpa_s, &cred->roaming_partner[i], 2198 bss->anqp->domain_name)) { 2199 wpa_printf(MSG_DEBUG, "Interworking: Roaming partner preference match - priority %u", 2200 cred->roaming_partner[i].priority); 2201 return cred->roaming_partner[i].priority; 2202 } 2203 } 2204 2205 wpa_printf(MSG_DEBUG, "Interworking: No roaming partner preference match - use default roaming partner priority 128"); 2206 return 128; 2207} 2208 2209 2210static struct wpa_bss * pick_best_roaming_partner(struct wpa_supplicant *wpa_s, 2211 struct wpa_bss *selected, 2212 struct wpa_cred *cred) 2213{ 2214 struct wpa_bss *bss; 2215 u8 best_prio, prio; 2216 struct wpa_cred *cred2; 2217 2218 /* 2219 * Check if any other BSS is operated by a more preferred roaming 2220 * partner. 2221 */ 2222 2223 best_prio = roaming_prio(wpa_s, cred, selected); 2224 wpa_printf(MSG_DEBUG, "Interworking: roaming_prio=%u for selected BSS " 2225 MACSTR " (cred=%d)", best_prio, MAC2STR(selected->bssid), 2226 cred->id); 2227 2228 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { 2229 if (bss == selected) 2230 continue; 2231 cred2 = interworking_credentials_available(wpa_s, bss, NULL); 2232 if (!cred2) 2233 continue; 2234 if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) 2235 continue; 2236 prio = roaming_prio(wpa_s, cred2, bss); 2237 wpa_printf(MSG_DEBUG, "Interworking: roaming_prio=%u for BSS " 2238 MACSTR " (cred=%d)", prio, MAC2STR(bss->bssid), 2239 cred2->id); 2240 if (prio < best_prio) { 2241 int bh1, bh2, load1, load2, conn1, conn2; 2242 bh1 = cred_below_min_backhaul(wpa_s, cred, selected); 2243 load1 = cred_over_max_bss_load(wpa_s, cred, selected); 2244 conn1 = cred_conn_capab_missing(wpa_s, cred, selected); 2245 bh2 = cred_below_min_backhaul(wpa_s, cred2, bss); 2246 load2 = cred_over_max_bss_load(wpa_s, cred2, bss); 2247 conn2 = cred_conn_capab_missing(wpa_s, cred2, bss); 2248 wpa_printf(MSG_DEBUG, "Interworking: old: %d %d %d new: %d %d %d", 2249 bh1, load1, conn1, bh2, load2, conn2); 2250 if (bh1 || load1 || conn1 || !(bh2 || load2 || conn2)) { 2251 wpa_printf(MSG_DEBUG, "Interworking: Better roaming partner " MACSTR " selected", MAC2STR(bss->bssid)); 2252 best_prio = prio; 2253 selected = bss; 2254 } 2255 } 2256 } 2257 2258 return selected; 2259} 2260 2261 2262static void interworking_select_network(struct wpa_supplicant *wpa_s) 2263{ 2264 struct wpa_bss *bss, *selected = NULL, *selected_home = NULL; 2265 struct wpa_bss *selected2 = NULL, *selected2_home = NULL; 2266 unsigned int count = 0; 2267 const char *type; 2268 int res; 2269 struct wpa_cred *cred, *selected_cred = NULL; 2270 struct wpa_cred *selected_home_cred = NULL; 2271 struct wpa_cred *selected2_cred = NULL; 2272 struct wpa_cred *selected2_home_cred = NULL; 2273 2274 wpa_s->network_select = 0; 2275 2276 wpa_printf(MSG_DEBUG, "Interworking: Select network (auto_select=%d)", 2277 wpa_s->auto_select); 2278 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { 2279 int excluded = 0; 2280 int bh, bss_load, conn_capab; 2281 cred = interworking_credentials_available(wpa_s, bss, 2282 &excluded); 2283 if (!cred) 2284 continue; 2285 if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) { 2286 /* 2287 * We currently support only HS 2.0 networks and those 2288 * are required to use WPA2-Enterprise. 2289 */ 2290 wpa_printf(MSG_DEBUG, "Interworking: Credential match " 2291 "with " MACSTR " but network does not use " 2292 "RSN", MAC2STR(bss->bssid)); 2293 continue; 2294 } 2295 if (!excluded) 2296 count++; 2297 res = interworking_home_sp(wpa_s, bss->anqp ? 2298 bss->anqp->domain_name : NULL); 2299 if (res > 0) 2300 type = "home"; 2301 else if (res == 0) 2302 type = "roaming"; 2303 else 2304 type = "unknown"; 2305 bh = cred_below_min_backhaul(wpa_s, cred, bss); 2306 bss_load = cred_over_max_bss_load(wpa_s, cred, bss); 2307 conn_capab = cred_conn_capab_missing(wpa_s, cred, bss); 2308 wpa_msg(wpa_s, MSG_INFO, "%s" MACSTR " type=%s%s%s%s id=%d priority=%d sp_priority=%d", 2309 excluded ? INTERWORKING_BLACKLISTED : INTERWORKING_AP, 2310 MAC2STR(bss->bssid), type, 2311 bh ? " below_min_backhaul=1" : "", 2312 bss_load ? " over_max_bss_load=1" : "", 2313 conn_capab ? " conn_capab_missing=1" : "", 2314 cred->id, cred->priority, cred->sp_priority); 2315 if (excluded) 2316 continue; 2317 if (wpa_s->auto_select || 2318 (wpa_s->conf->auto_interworking && 2319 wpa_s->auto_network_select)) { 2320 if (bh || bss_load || conn_capab) { 2321 if (selected2_cred == NULL || 2322 cred_prio_cmp(cred, selected2_cred) > 0) { 2323 wpa_printf(MSG_DEBUG, "Interworking: Mark as selected2"); 2324 selected2 = bss; 2325 selected2_cred = cred; 2326 } 2327 if (res > 0 && 2328 (selected2_home_cred == NULL || 2329 cred_prio_cmp(cred, selected2_home_cred) > 2330 0)) { 2331 wpa_printf(MSG_DEBUG, "Interworking: Mark as selected2_home"); 2332 selected2_home = bss; 2333 selected2_home_cred = cred; 2334 } 2335 } else { 2336 if (selected_cred == NULL || 2337 cred_prio_cmp(cred, selected_cred) > 0) { 2338 wpa_printf(MSG_DEBUG, "Interworking: Mark as selected"); 2339 selected = bss; 2340 selected_cred = cred; 2341 } 2342 if (res > 0 && 2343 (selected_home_cred == NULL || 2344 cred_prio_cmp(cred, selected_home_cred) > 2345 0)) { 2346 wpa_printf(MSG_DEBUG, "Interworking: Mark as selected_home"); 2347 selected_home = bss; 2348 selected_home_cred = cred; 2349 } 2350 } 2351 } 2352 } 2353 2354 if (selected_home && selected_home != selected && 2355 selected_home_cred && 2356 (selected_cred == NULL || 2357 cred_prio_cmp(selected_home_cred, selected_cred) >= 0)) { 2358 /* Prefer network operated by the Home SP */ 2359 wpa_printf(MSG_DEBUG, "Interworking: Overrided selected with selected_home"); 2360 selected = selected_home; 2361 selected_cred = selected_home_cred; 2362 } 2363 2364 if (!selected) { 2365 if (selected2_home) { 2366 wpa_printf(MSG_DEBUG, "Interworking: Use home BSS with BW limit mismatch since no other network could be selected"); 2367 selected = selected2_home; 2368 selected_cred = selected2_home_cred; 2369 } else if (selected2) { 2370 wpa_printf(MSG_DEBUG, "Interworking: Use visited BSS with BW limit mismatch since no other network could be selected"); 2371 selected = selected2; 2372 selected_cred = selected2_cred; 2373 } 2374 } 2375 2376 if (count == 0) { 2377 /* 2378 * No matching network was found based on configured 2379 * credentials. Check whether any of the enabled network blocks 2380 * have matching APs. 2381 */ 2382 if (interworking_find_network_match(wpa_s)) { 2383 wpa_printf(MSG_DEBUG, "Interworking: Possible BSS " 2384 "match for enabled network configurations"); 2385 if (wpa_s->auto_select) 2386 interworking_reconnect(wpa_s); 2387 return; 2388 } 2389 2390 if (wpa_s->auto_network_select) { 2391 wpa_printf(MSG_DEBUG, "Interworking: Continue " 2392 "scanning after ANQP fetch"); 2393 wpa_supplicant_req_scan(wpa_s, wpa_s->scan_interval, 2394 0); 2395 return; 2396 } 2397 2398 wpa_msg(wpa_s, MSG_INFO, INTERWORKING_NO_MATCH "No network " 2399 "with matching credentials found"); 2400 } 2401 2402 if (selected) { 2403 wpa_printf(MSG_DEBUG, "Interworking: Selected " MACSTR, 2404 MAC2STR(selected->bssid)); 2405 selected = pick_best_roaming_partner(wpa_s, selected, 2406 selected_cred); 2407 wpa_printf(MSG_DEBUG, "Interworking: Selected " MACSTR 2408 " (after best roaming partner selection)", 2409 MAC2STR(selected->bssid)); 2410 wpa_msg(wpa_s, MSG_INFO, INTERWORKING_SELECTED MACSTR, 2411 MAC2STR(selected->bssid)); 2412 interworking_connect(wpa_s, selected); 2413 } 2414} 2415 2416 2417static struct wpa_bss_anqp * 2418interworking_match_anqp_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) 2419{ 2420 struct wpa_bss *other; 2421 2422 if (is_zero_ether_addr(bss->hessid)) 2423 return NULL; /* Cannot be in the same homegenous ESS */ 2424 2425 dl_list_for_each(other, &wpa_s->bss, struct wpa_bss, list) { 2426 if (other == bss) 2427 continue; 2428 if (other->anqp == NULL) 2429 continue; 2430 if (other->anqp->roaming_consortium == NULL && 2431 other->anqp->nai_realm == NULL && 2432 other->anqp->anqp_3gpp == NULL && 2433 other->anqp->domain_name == NULL) 2434 continue; 2435 if (!(other->flags & WPA_BSS_ANQP_FETCH_TRIED)) 2436 continue; 2437 if (os_memcmp(bss->hessid, other->hessid, ETH_ALEN) != 0) 2438 continue; 2439 if (bss->ssid_len != other->ssid_len || 2440 os_memcmp(bss->ssid, other->ssid, bss->ssid_len) != 0) 2441 continue; 2442 2443 wpa_printf(MSG_DEBUG, "Interworking: Share ANQP data with " 2444 "already fetched BSSID " MACSTR " and " MACSTR, 2445 MAC2STR(other->bssid), MAC2STR(bss->bssid)); 2446 other->anqp->users++; 2447 return other->anqp; 2448 } 2449 2450 return NULL; 2451} 2452 2453 2454static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s) 2455{ 2456 struct wpa_bss *bss; 2457 int found = 0; 2458 const u8 *ie; 2459 2460 wpa_printf(MSG_DEBUG, "Interworking: next_anqp_fetch - " 2461 "fetch_anqp_in_progress=%d fetch_osu_icon_in_progress=%d", 2462 wpa_s->fetch_anqp_in_progress, 2463 wpa_s->fetch_osu_icon_in_progress); 2464 2465 if (eloop_terminated() || !wpa_s->fetch_anqp_in_progress) { 2466 wpa_printf(MSG_DEBUG, "Interworking: Stop next-ANQP-fetch"); 2467 return; 2468 } 2469 2470 if (wpa_s->fetch_osu_icon_in_progress) { 2471 wpa_printf(MSG_DEBUG, "Interworking: Next icon (in progress)"); 2472 hs20_next_osu_icon(wpa_s); 2473 return; 2474 } 2475 2476 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { 2477 if (!(bss->caps & IEEE80211_CAP_ESS)) 2478 continue; 2479 ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB); 2480 if (ie == NULL || ie[1] < 4 || !(ie[5] & 0x80)) 2481 continue; /* AP does not support Interworking */ 2482 if (disallowed_bssid(wpa_s, bss->bssid) || 2483 disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) 2484 continue; /* Disallowed BSS */ 2485 2486 if (!(bss->flags & WPA_BSS_ANQP_FETCH_TRIED)) { 2487 if (bss->anqp == NULL) { 2488 bss->anqp = interworking_match_anqp_info(wpa_s, 2489 bss); 2490 if (bss->anqp) { 2491 /* Shared data already fetched */ 2492 continue; 2493 } 2494 bss->anqp = wpa_bss_anqp_alloc(); 2495 if (bss->anqp == NULL) 2496 break; 2497 } 2498 found++; 2499 bss->flags |= WPA_BSS_ANQP_FETCH_TRIED; 2500 wpa_msg(wpa_s, MSG_INFO, "Starting ANQP fetch for " 2501 MACSTR, MAC2STR(bss->bssid)); 2502 interworking_anqp_send_req(wpa_s, bss); 2503 break; 2504 } 2505 } 2506 2507 if (found == 0) { 2508 if (wpa_s->fetch_osu_info) { 2509 if (wpa_s->num_prov_found == 0 && 2510 wpa_s->num_osu_scans < 3) { 2511 wpa_printf(MSG_DEBUG, "HS 2.0: No OSU providers seen - try to scan again"); 2512 hs20_start_osu_scan(wpa_s); 2513 return; 2514 } 2515 wpa_printf(MSG_DEBUG, "Interworking: Next icon"); 2516 hs20_osu_icon_fetch(wpa_s); 2517 return; 2518 } 2519 wpa_msg(wpa_s, MSG_INFO, "ANQP fetch completed"); 2520 wpa_s->fetch_anqp_in_progress = 0; 2521 if (wpa_s->network_select) 2522 interworking_select_network(wpa_s); 2523 } 2524} 2525 2526 2527void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s) 2528{ 2529 struct wpa_bss *bss; 2530 2531 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) 2532 bss->flags &= ~WPA_BSS_ANQP_FETCH_TRIED; 2533 2534 wpa_s->fetch_anqp_in_progress = 1; 2535 interworking_next_anqp_fetch(wpa_s); 2536} 2537 2538 2539int interworking_fetch_anqp(struct wpa_supplicant *wpa_s) 2540{ 2541 if (wpa_s->fetch_anqp_in_progress || wpa_s->network_select) 2542 return 0; 2543 2544 wpa_s->network_select = 0; 2545 wpa_s->fetch_all_anqp = 1; 2546 wpa_s->fetch_osu_info = 0; 2547 2548 interworking_start_fetch_anqp(wpa_s); 2549 2550 return 0; 2551} 2552 2553 2554void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s) 2555{ 2556 if (!wpa_s->fetch_anqp_in_progress) 2557 return; 2558 2559 wpa_s->fetch_anqp_in_progress = 0; 2560} 2561 2562 2563int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, 2564 u16 info_ids[], size_t num_ids, u32 subtypes) 2565{ 2566 struct wpabuf *buf; 2567 struct wpabuf *hs20_buf = NULL; 2568 int ret = 0; 2569 int freq; 2570 struct wpa_bss *bss; 2571 int res; 2572 2573 freq = wpa_s->assoc_freq; 2574 bss = wpa_bss_get_bssid(wpa_s, dst); 2575 if (bss) { 2576 wpa_bss_anqp_unshare_alloc(bss); 2577 freq = bss->freq; 2578 } 2579 if (freq <= 0) 2580 return -1; 2581 2582 wpa_printf(MSG_DEBUG, "ANQP: Query Request to " MACSTR " for %u id(s)", 2583 MAC2STR(dst), (unsigned int) num_ids); 2584 2585#ifdef CONFIG_HS20 2586 if (subtypes != 0) { 2587 hs20_buf = wpabuf_alloc(100); 2588 if (hs20_buf == NULL) 2589 return -1; 2590 hs20_put_anqp_req(subtypes, NULL, 0, hs20_buf); 2591 } 2592#endif /* CONFIG_HS20 */ 2593 2594 buf = anqp_build_req(info_ids, num_ids, hs20_buf); 2595 wpabuf_free(hs20_buf); 2596 if (buf == NULL) 2597 return -1; 2598 2599 res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s); 2600 if (res < 0) { 2601 wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request"); 2602 wpabuf_free(buf); 2603 ret = -1; 2604 } else 2605 wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token " 2606 "%u", res); 2607 2608 return ret; 2609} 2610 2611 2612static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, 2613 struct wpa_bss *bss, const u8 *sa, 2614 u16 info_id, 2615 const u8 *data, size_t slen) 2616{ 2617 const u8 *pos = data; 2618 struct wpa_bss_anqp *anqp = NULL; 2619#ifdef CONFIG_HS20 2620 u8 type; 2621#endif /* CONFIG_HS20 */ 2622 2623 if (bss) 2624 anqp = bss->anqp; 2625 2626 switch (info_id) { 2627 case ANQP_CAPABILITY_LIST: 2628 wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR 2629 " ANQP Capability list", MAC2STR(sa)); 2630 break; 2631 case ANQP_VENUE_NAME: 2632 wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR 2633 " Venue Name", MAC2STR(sa)); 2634 wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Venue Name", pos, slen); 2635 if (anqp) { 2636 wpabuf_free(anqp->venue_name); 2637 anqp->venue_name = wpabuf_alloc_copy(pos, slen); 2638 } 2639 break; 2640 case ANQP_NETWORK_AUTH_TYPE: 2641 wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR 2642 " Network Authentication Type information", 2643 MAC2STR(sa)); 2644 wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Network Authentication " 2645 "Type", pos, slen); 2646 if (anqp) { 2647 wpabuf_free(anqp->network_auth_type); 2648 anqp->network_auth_type = wpabuf_alloc_copy(pos, slen); 2649 } 2650 break; 2651 case ANQP_ROAMING_CONSORTIUM: 2652 wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR 2653 " Roaming Consortium list", MAC2STR(sa)); 2654 wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Roaming Consortium", 2655 pos, slen); 2656 if (anqp) { 2657 wpabuf_free(anqp->roaming_consortium); 2658 anqp->roaming_consortium = wpabuf_alloc_copy(pos, slen); 2659 } 2660 break; 2661 case ANQP_IP_ADDR_TYPE_AVAILABILITY: 2662 wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR 2663 " IP Address Type Availability information", 2664 MAC2STR(sa)); 2665 wpa_hexdump(MSG_MSGDUMP, "ANQP: IP Address Availability", 2666 pos, slen); 2667 if (anqp) { 2668 wpabuf_free(anqp->ip_addr_type_availability); 2669 anqp->ip_addr_type_availability = 2670 wpabuf_alloc_copy(pos, slen); 2671 } 2672 break; 2673 case ANQP_NAI_REALM: 2674 wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR 2675 " NAI Realm list", MAC2STR(sa)); 2676 wpa_hexdump_ascii(MSG_DEBUG, "ANQP: NAI Realm", pos, slen); 2677 if (anqp) { 2678 wpabuf_free(anqp->nai_realm); 2679 anqp->nai_realm = wpabuf_alloc_copy(pos, slen); 2680 } 2681 break; 2682 case ANQP_3GPP_CELLULAR_NETWORK: 2683 wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR 2684 " 3GPP Cellular Network information", MAC2STR(sa)); 2685 wpa_hexdump_ascii(MSG_DEBUG, "ANQP: 3GPP Cellular Network", 2686 pos, slen); 2687 if (anqp) { 2688 wpabuf_free(anqp->anqp_3gpp); 2689 anqp->anqp_3gpp = wpabuf_alloc_copy(pos, slen); 2690 } 2691 break; 2692 case ANQP_DOMAIN_NAME: 2693 wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR 2694 " Domain Name list", MAC2STR(sa)); 2695 wpa_hexdump_ascii(MSG_MSGDUMP, "ANQP: Domain Name", pos, slen); 2696 if (anqp) { 2697 wpabuf_free(anqp->domain_name); 2698 anqp->domain_name = wpabuf_alloc_copy(pos, slen); 2699 } 2700 break; 2701 case ANQP_VENDOR_SPECIFIC: 2702 if (slen < 3) 2703 return; 2704 2705 switch (WPA_GET_BE24(pos)) { 2706#ifdef CONFIG_HS20 2707 case OUI_WFA: 2708 pos += 3; 2709 slen -= 3; 2710 2711 if (slen < 1) 2712 return; 2713 type = *pos++; 2714 slen--; 2715 2716 switch (type) { 2717 case HS20_ANQP_OUI_TYPE: 2718 hs20_parse_rx_hs20_anqp_resp(wpa_s, sa, pos, 2719 slen); 2720 break; 2721 default: 2722 wpa_printf(MSG_DEBUG, "HS20: Unsupported ANQP " 2723 "vendor type %u", type); 2724 break; 2725 } 2726 break; 2727#endif /* CONFIG_HS20 */ 2728 default: 2729 wpa_printf(MSG_DEBUG, "Interworking: Unsupported " 2730 "vendor-specific ANQP OUI %06x", 2731 WPA_GET_BE24(pos)); 2732 return; 2733 } 2734 break; 2735 default: 2736 wpa_printf(MSG_DEBUG, "Interworking: Unsupported ANQP Info ID " 2737 "%u", info_id); 2738 break; 2739 } 2740} 2741 2742 2743void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token, 2744 enum gas_query_result result, 2745 const struct wpabuf *adv_proto, 2746 const struct wpabuf *resp, u16 status_code) 2747{ 2748 struct wpa_supplicant *wpa_s = ctx; 2749 const u8 *pos; 2750 const u8 *end; 2751 u16 info_id; 2752 u16 slen; 2753 struct wpa_bss *bss = NULL, *tmp; 2754 2755 wpa_printf(MSG_DEBUG, "Interworking: anqp_resp_cb dst=" MACSTR 2756 " dialog_token=%u result=%d status_code=%u", 2757 MAC2STR(dst), dialog_token, result, status_code); 2758 if (result != GAS_QUERY_SUCCESS) { 2759 if (wpa_s->fetch_osu_icon_in_progress) 2760 hs20_icon_fetch_failed(wpa_s); 2761 return; 2762 } 2763 2764 pos = wpabuf_head(adv_proto); 2765 if (wpabuf_len(adv_proto) < 4 || pos[0] != WLAN_EID_ADV_PROTO || 2766 pos[1] < 2 || pos[3] != ACCESS_NETWORK_QUERY_PROTOCOL) { 2767 wpa_printf(MSG_DEBUG, "ANQP: Unexpected Advertisement " 2768 "Protocol in response"); 2769 if (wpa_s->fetch_osu_icon_in_progress) 2770 hs20_icon_fetch_failed(wpa_s); 2771 return; 2772 } 2773 2774 /* 2775 * If possible, select the BSS entry based on which BSS entry was used 2776 * for the request. This can help in cases where multiple BSS entries 2777 * may exist for the same AP. 2778 */ 2779 dl_list_for_each_reverse(tmp, &wpa_s->bss, struct wpa_bss, list) { 2780 if (tmp == wpa_s->interworking_gas_bss && 2781 os_memcmp(tmp->bssid, dst, ETH_ALEN) == 0) { 2782 bss = tmp; 2783 break; 2784 } 2785 } 2786 if (bss == NULL) 2787 bss = wpa_bss_get_bssid(wpa_s, dst); 2788 2789 pos = wpabuf_head(resp); 2790 end = pos + wpabuf_len(resp); 2791 2792 while (pos < end) { 2793 if (pos + 4 > end) { 2794 wpa_printf(MSG_DEBUG, "ANQP: Invalid element"); 2795 break; 2796 } 2797 info_id = WPA_GET_LE16(pos); 2798 pos += 2; 2799 slen = WPA_GET_LE16(pos); 2800 pos += 2; 2801 if (pos + slen > end) { 2802 wpa_printf(MSG_DEBUG, "ANQP: Invalid element length " 2803 "for Info ID %u", info_id); 2804 break; 2805 } 2806 interworking_parse_rx_anqp_resp(wpa_s, bss, dst, info_id, pos, 2807 slen); 2808 pos += slen; 2809 } 2810 2811 hs20_notify_parse_done(wpa_s); 2812} 2813 2814 2815static void interworking_scan_res_handler(struct wpa_supplicant *wpa_s, 2816 struct wpa_scan_results *scan_res) 2817{ 2818 wpa_printf(MSG_DEBUG, "Interworking: Scan results available - start " 2819 "ANQP fetch"); 2820 interworking_start_fetch_anqp(wpa_s); 2821} 2822 2823 2824int interworking_select(struct wpa_supplicant *wpa_s, int auto_select, 2825 int *freqs) 2826{ 2827 interworking_stop_fetch_anqp(wpa_s); 2828 wpa_s->network_select = 1; 2829 wpa_s->auto_network_select = 0; 2830 wpa_s->auto_select = !!auto_select; 2831 wpa_s->fetch_all_anqp = 0; 2832 wpa_s->fetch_osu_info = 0; 2833 wpa_printf(MSG_DEBUG, "Interworking: Start scan for network " 2834 "selection"); 2835 wpa_s->scan_res_handler = interworking_scan_res_handler; 2836 wpa_s->normal_scans = 0; 2837 wpa_s->scan_req = MANUAL_SCAN_REQ; 2838 os_free(wpa_s->manual_scan_freqs); 2839 wpa_s->manual_scan_freqs = freqs; 2840 wpa_s->after_wps = 0; 2841 wpa_s->known_wps_freq = 0; 2842 wpa_supplicant_req_scan(wpa_s, 0, 0); 2843 2844 return 0; 2845} 2846 2847 2848static void gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, 2849 enum gas_query_result result, 2850 const struct wpabuf *adv_proto, 2851 const struct wpabuf *resp, u16 status_code) 2852{ 2853 struct wpa_supplicant *wpa_s = ctx; 2854 struct wpabuf *n; 2855 2856 wpa_msg(wpa_s, MSG_INFO, GAS_RESPONSE_INFO "addr=" MACSTR 2857 " dialog_token=%d status_code=%d resp_len=%d", 2858 MAC2STR(addr), dialog_token, status_code, 2859 resp ? (int) wpabuf_len(resp) : -1); 2860 if (!resp) 2861 return; 2862 2863 n = wpabuf_dup(resp); 2864 if (n == NULL) 2865 return; 2866 wpabuf_free(wpa_s->prev_gas_resp); 2867 wpa_s->prev_gas_resp = wpa_s->last_gas_resp; 2868 os_memcpy(wpa_s->prev_gas_addr, wpa_s->last_gas_addr, ETH_ALEN); 2869 wpa_s->prev_gas_dialog_token = wpa_s->last_gas_dialog_token; 2870 wpa_s->last_gas_resp = n; 2871 os_memcpy(wpa_s->last_gas_addr, addr, ETH_ALEN); 2872 wpa_s->last_gas_dialog_token = dialog_token; 2873} 2874 2875 2876int gas_send_request(struct wpa_supplicant *wpa_s, const u8 *dst, 2877 const struct wpabuf *adv_proto, 2878 const struct wpabuf *query) 2879{ 2880 struct wpabuf *buf; 2881 int ret = 0; 2882 int freq; 2883 struct wpa_bss *bss; 2884 int res; 2885 size_t len; 2886 u8 query_resp_len_limit = 0, pame_bi = 0; 2887 2888 freq = wpa_s->assoc_freq; 2889 bss = wpa_bss_get_bssid(wpa_s, dst); 2890 if (bss) 2891 freq = bss->freq; 2892 if (freq <= 0) 2893 return -1; 2894 2895 wpa_printf(MSG_DEBUG, "GAS request to " MACSTR " (freq %d MHz)", 2896 MAC2STR(dst), freq); 2897 wpa_hexdump_buf(MSG_DEBUG, "Advertisement Protocol ID", adv_proto); 2898 wpa_hexdump_buf(MSG_DEBUG, "GAS Query", query); 2899 2900 len = 3 + wpabuf_len(adv_proto) + 2; 2901 if (query) 2902 len += wpabuf_len(query); 2903 buf = gas_build_initial_req(0, len); 2904 if (buf == NULL) 2905 return -1; 2906 2907 /* Advertisement Protocol IE */ 2908 wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO); 2909 wpabuf_put_u8(buf, 1 + wpabuf_len(adv_proto)); /* Length */ 2910 wpabuf_put_u8(buf, (query_resp_len_limit & 0x7f) | 2911 (pame_bi ? 0x80 : 0)); 2912 wpabuf_put_buf(buf, adv_proto); 2913 2914 /* GAS Query */ 2915 if (query) { 2916 wpabuf_put_le16(buf, wpabuf_len(query)); 2917 wpabuf_put_buf(buf, query); 2918 } else 2919 wpabuf_put_le16(buf, 0); 2920 2921 res = gas_query_req(wpa_s->gas, dst, freq, buf, gas_resp_cb, wpa_s); 2922 if (res < 0) { 2923 wpa_printf(MSG_DEBUG, "GAS: Failed to send Query Request"); 2924 wpabuf_free(buf); 2925 ret = -1; 2926 } else 2927 wpa_printf(MSG_DEBUG, "GAS: Query started with dialog token " 2928 "%u", res); 2929 2930 return ret; 2931} 2932