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