1 /* 2 * Interworking (IEEE 802.11u) 3 * Copyright (c) 2011, Qualcomm Atheros 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9 #include "includes.h" 10 11 #include "common.h" 12 #include "common/ieee802_11_defs.h" 13 #include "common/gas.h" 14 #include "common/wpa_ctrl.h" 15 #include "drivers/driver.h" 16 #include "eap_common/eap_defs.h" 17 #include "eap_peer/eap_methods.h" 18 #include "wpa_supplicant_i.h" 19 #include "config.h" 20 #include "bss.h" 21 #include "scan.h" 22 #include "notify.h" 23 #include "gas_query.h" 24 #include "interworking.h" 25 26 27 #if defined(EAP_SIM) | defined(EAP_SIM_DYNAMIC) 28 #define INTERWORKING_3GPP 29 #else 30 #if defined(EAP_AKA) | defined(EAP_AKA_DYNAMIC) 31 #define INTERWORKING_3GPP 32 #else 33 #if defined(EAP_AKA_PRIME) | defined(EAP_AKA_PRIME_DYNAMIC) 34 #define INTERWORKING_3GPP 35 #endif 36 #endif 37 #endif 38 39 static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s); 40 41 42 static struct wpabuf * anqp_build_req(u16 info_ids[], size_t num_ids, 43 struct wpabuf *extra) 44 { 45 struct wpabuf *buf; 46 size_t i; 47 u8 *len_pos; 48 49 buf = gas_anqp_build_initial_req(0, 4 + num_ids * 2 + 50 (extra ? wpabuf_len(extra) : 0)); 51 if (buf == NULL) 52 return NULL; 53 54 len_pos = gas_anqp_add_element(buf, ANQP_QUERY_LIST); 55 for (i = 0; i < num_ids; i++) 56 wpabuf_put_le16(buf, info_ids[i]); 57 gas_anqp_set_element_len(buf, len_pos); 58 if (extra) 59 wpabuf_put_buf(buf, extra); 60 61 gas_anqp_set_len(buf); 62 63 return buf; 64 } 65 66 67 static void interworking_anqp_resp_cb(void *ctx, const u8 *dst, 68 u8 dialog_token, 69 enum gas_query_result result, 70 const struct wpabuf *adv_proto, 71 const struct wpabuf *resp, 72 u16 status_code) 73 { 74 struct wpa_supplicant *wpa_s = ctx; 75 76 anqp_resp_cb(wpa_s, dst, dialog_token, result, adv_proto, resp, 77 status_code); 78 interworking_next_anqp_fetch(wpa_s); 79 } 80 81 82 static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s, 83 struct wpa_bss *bss) 84 { 85 struct wpabuf *buf; 86 int ret = 0; 87 int res; 88 u16 info_ids[] = { 89 ANQP_CAPABILITY_LIST, 90 ANQP_VENUE_NAME, 91 ANQP_NETWORK_AUTH_TYPE, 92 ANQP_ROAMING_CONSORTIUM, 93 ANQP_IP_ADDR_TYPE_AVAILABILITY, 94 ANQP_NAI_REALM, 95 ANQP_3GPP_CELLULAR_NETWORK, 96 ANQP_DOMAIN_NAME 97 }; 98 struct wpabuf *extra = NULL; 99 100 wpa_printf(MSG_DEBUG, "Interworking: ANQP Query Request to " MACSTR, 101 MAC2STR(bss->bssid)); 102 103 buf = anqp_build_req(info_ids, sizeof(info_ids) / sizeof(info_ids[0]), 104 extra); 105 wpabuf_free(extra); 106 if (buf == NULL) 107 return -1; 108 109 res = gas_query_req(wpa_s->gas, bss->bssid, bss->freq, buf, 110 interworking_anqp_resp_cb, wpa_s); 111 if (res < 0) { 112 wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request"); 113 ret = -1; 114 } else 115 wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token " 116 "%u", res); 117 118 wpabuf_free(buf); 119 return ret; 120 } 121 122 123 struct nai_realm_eap { 124 u8 method; 125 u8 inner_method; 126 enum nai_realm_eap_auth_inner_non_eap inner_non_eap; 127 u8 cred_type; 128 u8 tunneled_cred_type; 129 }; 130 131 struct nai_realm { 132 u8 encoding; 133 char *realm; 134 u8 eap_count; 135 struct nai_realm_eap *eap; 136 }; 137 138 139 static void nai_realm_free(struct nai_realm *realms, u16 count) 140 { 141 u16 i; 142 143 if (realms == NULL) 144 return; 145 for (i = 0; i < count; i++) { 146 os_free(realms[i].eap); 147 os_free(realms[i].realm); 148 } 149 os_free(realms); 150 } 151 152 153 static const u8 * nai_realm_parse_eap(struct nai_realm_eap *e, const u8 *pos, 154 const u8 *end) 155 { 156 u8 elen, auth_count, a; 157 const u8 *e_end; 158 159 if (pos + 3 > end) { 160 wpa_printf(MSG_DEBUG, "No room for EAP Method fixed fields"); 161 return NULL; 162 } 163 164 elen = *pos++; 165 if (pos + elen > end || elen < 2) { 166 wpa_printf(MSG_DEBUG, "No room for EAP Method subfield"); 167 return NULL; 168 } 169 e_end = pos + elen; 170 e->method = *pos++; 171 auth_count = *pos++; 172 wpa_printf(MSG_DEBUG, "EAP Method: len=%u method=%u auth_count=%u", 173 elen, e->method, auth_count); 174 175 for (a = 0; a < auth_count; a++) { 176 u8 id, len; 177 178 if (pos + 2 > end || pos + 2 + pos[1] > end) { 179 wpa_printf(MSG_DEBUG, "No room for Authentication " 180 "Parameter subfield"); 181 return NULL; 182 } 183 184 id = *pos++; 185 len = *pos++; 186 187 switch (id) { 188 case NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH: 189 if (len < 1) 190 break; 191 e->inner_non_eap = *pos; 192 if (e->method != EAP_TYPE_TTLS) 193 break; 194 switch (*pos) { 195 case NAI_REALM_INNER_NON_EAP_PAP: 196 wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP"); 197 break; 198 case NAI_REALM_INNER_NON_EAP_CHAP: 199 wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP"); 200 break; 201 case NAI_REALM_INNER_NON_EAP_MSCHAP: 202 wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP"); 203 break; 204 case NAI_REALM_INNER_NON_EAP_MSCHAPV2: 205 wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2"); 206 break; 207 } 208 break; 209 case NAI_REALM_EAP_AUTH_INNER_AUTH_EAP_METHOD: 210 if (len < 1) 211 break; 212 e->inner_method = *pos; 213 wpa_printf(MSG_DEBUG, "Inner EAP method: %u", 214 e->inner_method); 215 break; 216 case NAI_REALM_EAP_AUTH_CRED_TYPE: 217 if (len < 1) 218 break; 219 e->cred_type = *pos; 220 wpa_printf(MSG_DEBUG, "Credential Type: %u", 221 e->cred_type); 222 break; 223 case NAI_REALM_EAP_AUTH_TUNNELED_CRED_TYPE: 224 if (len < 1) 225 break; 226 e->tunneled_cred_type = *pos; 227 wpa_printf(MSG_DEBUG, "Tunneled EAP Method Credential " 228 "Type: %u", e->tunneled_cred_type); 229 break; 230 default: 231 wpa_printf(MSG_DEBUG, "Unsupported Authentication " 232 "Parameter: id=%u len=%u", id, len); 233 wpa_hexdump(MSG_DEBUG, "Authentication Parameter " 234 "Value", pos, len); 235 break; 236 } 237 238 pos += len; 239 } 240 241 return e_end; 242 } 243 244 245 static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos, 246 const u8 *end) 247 { 248 u16 len; 249 const u8 *f_end; 250 u8 realm_len, e; 251 252 if (end - pos < 4) { 253 wpa_printf(MSG_DEBUG, "No room for NAI Realm Data " 254 "fixed fields"); 255 return NULL; 256 } 257 258 len = WPA_GET_LE16(pos); /* NAI Realm Data field Length */ 259 pos += 2; 260 if (pos + len > end || len < 3) { 261 wpa_printf(MSG_DEBUG, "No room for NAI Realm Data " 262 "(len=%u; left=%u)", 263 len, (unsigned int) (end - pos)); 264 return NULL; 265 } 266 f_end = pos + len; 267 268 r->encoding = *pos++; 269 realm_len = *pos++; 270 if (pos + realm_len > f_end) { 271 wpa_printf(MSG_DEBUG, "No room for NAI Realm " 272 "(len=%u; left=%u)", 273 realm_len, (unsigned int) (f_end - pos)); 274 return NULL; 275 } 276 wpa_hexdump_ascii(MSG_DEBUG, "NAI Realm", pos, realm_len); 277 r->realm = os_malloc(realm_len + 1); 278 if (r->realm == NULL) 279 return NULL; 280 os_memcpy(r->realm, pos, realm_len); 281 r->realm[realm_len] = '\0'; 282 pos += realm_len; 283 284 if (pos + 1 > f_end) { 285 wpa_printf(MSG_DEBUG, "No room for EAP Method Count"); 286 return NULL; 287 } 288 r->eap_count = *pos++; 289 wpa_printf(MSG_DEBUG, "EAP Count: %u", r->eap_count); 290 if (pos + r->eap_count * 3 > f_end) { 291 wpa_printf(MSG_DEBUG, "No room for EAP Methods"); 292 return NULL; 293 } 294 r->eap = os_zalloc(r->eap_count * sizeof(struct nai_realm_eap)); 295 if (r->eap == NULL) 296 return NULL; 297 298 for (e = 0; e < r->eap_count; e++) { 299 pos = nai_realm_parse_eap(&r->eap[e], pos, f_end); 300 if (pos == NULL) 301 return NULL; 302 } 303 304 return f_end; 305 } 306 307 308 static struct nai_realm * nai_realm_parse(struct wpabuf *anqp, u16 *count) 309 { 310 struct nai_realm *realm; 311 const u8 *pos, *end; 312 u16 i, num; 313 314 if (anqp == NULL || wpabuf_len(anqp) < 2) 315 return NULL; 316 317 pos = wpabuf_head_u8(anqp); 318 end = pos + wpabuf_len(anqp); 319 num = WPA_GET_LE16(pos); 320 wpa_printf(MSG_DEBUG, "NAI Realm Count: %u", num); 321 pos += 2; 322 323 if (num * 5 > end - pos) { 324 wpa_printf(MSG_DEBUG, "Invalid NAI Realm Count %u - not " 325 "enough data (%u octets) for that many realms", 326 num, (unsigned int) (end - pos)); 327 return NULL; 328 } 329 330 realm = os_zalloc(num * sizeof(struct nai_realm)); 331 if (realm == NULL) 332 return NULL; 333 334 for (i = 0; i < num; i++) { 335 pos = nai_realm_parse_realm(&realm[i], pos, end); 336 if (pos == NULL) { 337 nai_realm_free(realm, num); 338 return NULL; 339 } 340 } 341 342 *count = num; 343 return realm; 344 } 345 346 347 static int nai_realm_match(struct nai_realm *realm, const char *home_realm) 348 { 349 char *tmp, *pos, *end; 350 int match = 0; 351 352 if (realm->realm == NULL || home_realm == NULL) 353 return 0; 354 355 if (os_strchr(realm->realm, ';') == NULL) 356 return os_strcasecmp(realm->realm, home_realm) == 0; 357 358 tmp = os_strdup(realm->realm); 359 if (tmp == NULL) 360 return 0; 361 362 pos = tmp; 363 while (*pos) { 364 end = os_strchr(pos, ';'); 365 if (end) 366 *end = '\0'; 367 if (os_strcasecmp(pos, home_realm) == 0) { 368 match = 1; 369 break; 370 } 371 if (end == NULL) 372 break; 373 pos = end + 1; 374 } 375 376 os_free(tmp); 377 378 return match; 379 } 380 381 382 static int nai_realm_cred_username(struct nai_realm_eap *eap) 383 { 384 if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL) 385 return 0; /* method not supported */ 386 387 if (eap->method != EAP_TYPE_TTLS && eap->method != EAP_TYPE_PEAP) { 388 /* Only tunneled methods with username/password supported */ 389 return 0; 390 } 391 392 if (eap->method == EAP_TYPE_PEAP && 393 eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL) 394 return 0; 395 396 if (eap->method == EAP_TYPE_TTLS) { 397 if (eap->inner_method == 0 && eap->inner_non_eap == 0) 398 return 0; 399 if (eap->inner_method && 400 eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL) 401 return 0; 402 if (eap->inner_non_eap && 403 eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_PAP && 404 eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_CHAP && 405 eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAP && 406 eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAPV2) 407 return 0; 408 } 409 410 if (eap->inner_method && 411 eap->inner_method != EAP_TYPE_GTC && 412 eap->inner_method != EAP_TYPE_MSCHAPV2) 413 return 0; 414 415 return 1; 416 } 417 418 419 static struct nai_realm_eap * nai_realm_find_eap(struct wpa_supplicant *wpa_s, 420 struct nai_realm *realm) 421 { 422 u8 e; 423 424 if (wpa_s->conf->home_username == NULL || 425 wpa_s->conf->home_username[0] == '\0' || 426 wpa_s->conf->home_password == NULL || 427 wpa_s->conf->home_password[0] == '\0') 428 return NULL; 429 430 for (e = 0; e < realm->eap_count; e++) { 431 struct nai_realm_eap *eap = &realm->eap[e]; 432 if (nai_realm_cred_username(eap)) 433 return eap; 434 } 435 436 return NULL; 437 } 438 439 440 #ifdef INTERWORKING_3GPP 441 442 static int plmn_id_match(struct wpabuf *anqp, const char *imsi) 443 { 444 const char *sep; 445 u8 plmn[3]; 446 const u8 *pos, *end; 447 u8 udhl; 448 449 sep = os_strchr(imsi, '-'); 450 if (sep == NULL || (sep - imsi != 5 && sep - imsi != 6)) 451 return 0; 452 453 /* See Annex A of 3GPP TS 24.234 v8.1.0 for description */ 454 plmn[0] = (imsi[0] - '0') | ((imsi[1] - '0') << 4); 455 plmn[1] = imsi[2] - '0'; 456 if (sep - imsi == 6) 457 plmn[1] |= (imsi[5] - '0') << 4; 458 else 459 plmn[1] |= 0xf0; 460 plmn[2] = (imsi[3] - '0') | ((imsi[4] - '0') << 4); 461 462 if (anqp == NULL) 463 return 0; 464 pos = wpabuf_head_u8(anqp); 465 end = pos + wpabuf_len(anqp); 466 if (pos + 2 > end) 467 return 0; 468 if (*pos != 0) { 469 wpa_printf(MSG_DEBUG, "Unsupported GUD version 0x%x", *pos); 470 return 0; 471 } 472 pos++; 473 udhl = *pos++; 474 if (pos + udhl > end) { 475 wpa_printf(MSG_DEBUG, "Invalid UDHL"); 476 return 0; 477 } 478 end = pos + udhl; 479 480 while (pos + 2 <= end) { 481 u8 iei, len; 482 const u8 *l_end; 483 iei = *pos++; 484 len = *pos++ & 0x7f; 485 if (pos + len > end) 486 break; 487 l_end = pos + len; 488 489 if (iei == 0 && len > 0) { 490 /* PLMN List */ 491 u8 num, i; 492 num = *pos++; 493 for (i = 0; i < num; i++) { 494 if (pos + 3 > end) 495 break; 496 if (os_memcmp(pos, plmn, 3) == 0) 497 return 1; /* Found matching PLMN */ 498 } 499 } 500 501 pos = l_end; 502 } 503 504 return 0; 505 } 506 507 508 static int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix) 509 { 510 const char *sep, *msin; 511 char nai[100], *end, *pos; 512 size_t msin_len, plmn_len; 513 514 /* 515 * TS 23.003, Clause 14 (3GPP to WLAN Interworking) 516 * Root NAI: 517 * <aka:0|sim:1><IMSI>@wlan.mnc<MNC>.mcc<MCC>.3gppnetwork.org 518 * <MNC> is zero-padded to three digits in case two-digit MNC is used 519 */ 520 521 if (imsi == NULL || os_strlen(imsi) > 16) { 522 wpa_printf(MSG_DEBUG, "No valid IMSI available"); 523 return -1; 524 } 525 sep = os_strchr(imsi, '-'); 526 if (sep == NULL) 527 return -1; 528 plmn_len = sep - imsi; 529 if (plmn_len != 5 && plmn_len != 6) 530 return -1; 531 msin = sep + 1; 532 msin_len = os_strlen(msin); 533 534 pos = nai; 535 end = pos + sizeof(nai); 536 *pos++ = prefix; 537 os_memcpy(pos, imsi, plmn_len); 538 pos += plmn_len; 539 os_memcpy(pos, msin, msin_len); 540 pos += msin_len; 541 pos += os_snprintf(pos, end - pos, "@wlan.mnc"); 542 if (plmn_len == 5) { 543 *pos++ = '0'; 544 *pos++ = imsi[3]; 545 *pos++ = imsi[4]; 546 } else { 547 *pos++ = imsi[3]; 548 *pos++ = imsi[4]; 549 *pos++ = imsi[5]; 550 } 551 pos += os_snprintf(pos, end - pos, ".mcc%c%c%c.3gppnetwork.org", 552 imsi[0], imsi[1], imsi[2]); 553 554 return wpa_config_set_quoted(ssid, "identity", nai); 555 } 556 557 #endif /* INTERWORKING_3GPP */ 558 559 560 static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s, 561 struct wpa_bss *bss) 562 { 563 #ifdef INTERWORKING_3GPP 564 struct wpa_ssid *ssid; 565 const u8 *ie; 566 567 ie = wpa_bss_get_ie(bss, WLAN_EID_SSID); 568 if (ie == NULL) 569 return -1; 570 wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " (3GPP)", 571 MAC2STR(bss->bssid)); 572 573 ssid = wpa_config_add_network(wpa_s->conf); 574 if (ssid == NULL) 575 return -1; 576 577 wpas_notify_network_added(wpa_s, ssid); 578 wpa_config_set_network_defaults(ssid); 579 ssid->temporary = 1; 580 ssid->ssid = os_zalloc(ie[1] + 1); 581 if (ssid->ssid == NULL) 582 goto fail; 583 os_memcpy(ssid->ssid, ie + 2, ie[1]); 584 ssid->ssid_len = ie[1]; 585 586 /* TODO: figure out whether to use EAP-SIM, EAP-AKA, or EAP-AKA' */ 587 if (wpa_config_set(ssid, "eap", "SIM", 0) < 0) { 588 wpa_printf(MSG_DEBUG, "EAP-SIM not supported"); 589 goto fail; 590 } 591 if (set_root_nai(ssid, wpa_s->conf->home_imsi, '1') < 0) { 592 wpa_printf(MSG_DEBUG, "Failed to set Root NAI"); 593 goto fail; 594 } 595 596 if (wpa_s->conf->home_milenage && wpa_s->conf->home_milenage[0]) { 597 if (wpa_config_set_quoted(ssid, "password", 598 wpa_s->conf->home_milenage) < 0) 599 goto fail; 600 } else { 601 /* TODO: PIN */ 602 if (wpa_config_set_quoted(ssid, "pcsc", "") < 0) 603 goto fail; 604 } 605 606 if (wpa_s->conf->home_password && wpa_s->conf->home_password[0] && 607 wpa_config_set_quoted(ssid, "password", wpa_s->conf->home_password) 608 < 0) 609 goto fail; 610 611 wpa_supplicant_select_network(wpa_s, ssid); 612 613 return 0; 614 615 fail: 616 wpas_notify_network_removed(wpa_s, ssid); 617 wpa_config_remove_network(wpa_s->conf, ssid->id); 618 #endif /* INTERWORKING_3GPP */ 619 return -1; 620 } 621 622 623 int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) 624 { 625 struct wpa_ssid *ssid; 626 struct nai_realm *realm; 627 struct nai_realm_eap *eap = NULL; 628 u16 count, i; 629 char buf[100]; 630 const u8 *ie; 631 632 if (bss == NULL) 633 return -1; 634 ie = wpa_bss_get_ie(bss, WLAN_EID_SSID); 635 if (ie == NULL || ie[1] == 0) { 636 wpa_printf(MSG_DEBUG, "Interworking: No SSID known for " 637 MACSTR, MAC2STR(bss->bssid)); 638 return -1; 639 } 640 641 realm = nai_realm_parse(bss->anqp_nai_realm, &count); 642 if (realm == NULL) { 643 wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI " 644 "Realm list from " MACSTR, MAC2STR(bss->bssid)); 645 count = 0; 646 } 647 648 for (i = 0; i < count; i++) { 649 if (!nai_realm_match(&realm[i], wpa_s->conf->home_realm)) 650 continue; 651 eap = nai_realm_find_eap(wpa_s, &realm[i]); 652 if (eap) 653 break; 654 } 655 656 if (!eap) { 657 if (interworking_connect_3gpp(wpa_s, bss) == 0) { 658 if (realm) 659 nai_realm_free(realm, count); 660 return 0; 661 } 662 663 wpa_printf(MSG_DEBUG, "Interworking: No matching credentials " 664 "and EAP method found for " MACSTR, 665 MAC2STR(bss->bssid)); 666 nai_realm_free(realm, count); 667 return -1; 668 } 669 670 wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR, 671 MAC2STR(bss->bssid)); 672 673 ssid = wpa_config_add_network(wpa_s->conf); 674 if (ssid == NULL) { 675 nai_realm_free(realm, count); 676 return -1; 677 } 678 wpas_notify_network_added(wpa_s, ssid); 679 wpa_config_set_network_defaults(ssid); 680 ssid->temporary = 1; 681 ssid->ssid = os_zalloc(ie[1] + 1); 682 if (ssid->ssid == NULL) 683 goto fail; 684 os_memcpy(ssid->ssid, ie + 2, ie[1]); 685 ssid->ssid_len = ie[1]; 686 687 if (wpa_config_set(ssid, "eap", eap_get_name(EAP_VENDOR_IETF, 688 eap->method), 0) < 0) 689 goto fail; 690 691 if (wpa_s->conf->home_username && wpa_s->conf->home_username[0] && 692 wpa_config_set_quoted(ssid, "identity", 693 wpa_s->conf->home_username) < 0) 694 goto fail; 695 696 if (wpa_s->conf->home_password && wpa_s->conf->home_password[0] && 697 wpa_config_set_quoted(ssid, "password", wpa_s->conf->home_password) 698 < 0) 699 goto fail; 700 701 switch (eap->method) { 702 case EAP_TYPE_TTLS: 703 if (eap->inner_method) { 704 os_snprintf(buf, sizeof(buf), "\"autheap=%s\"", 705 eap_get_name(EAP_VENDOR_IETF, 706 eap->inner_method)); 707 if (wpa_config_set(ssid, "phase2", buf, 0) < 0) 708 goto fail; 709 break; 710 } 711 switch (eap->inner_non_eap) { 712 case NAI_REALM_INNER_NON_EAP_PAP: 713 if (wpa_config_set(ssid, "phase2", "\"auth=PAP\"", 0) < 714 0) 715 goto fail; 716 break; 717 case NAI_REALM_INNER_NON_EAP_CHAP: 718 if (wpa_config_set(ssid, "phase2", "\"auth=CHAP\"", 0) 719 < 0) 720 goto fail; 721 break; 722 case NAI_REALM_INNER_NON_EAP_MSCHAP: 723 if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAP\"", 724 0) < 0) 725 goto fail; 726 break; 727 case NAI_REALM_INNER_NON_EAP_MSCHAPV2: 728 if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAPV2\"", 729 0) < 0) 730 goto fail; 731 break; 732 } 733 break; 734 case EAP_TYPE_PEAP: 735 os_snprintf(buf, sizeof(buf), "\"auth=%s\"", 736 eap_get_name(EAP_VENDOR_IETF, eap->inner_method)); 737 if (wpa_config_set(ssid, "phase2", buf, 0) < 0) 738 goto fail; 739 break; 740 } 741 742 if (wpa_s->conf->home_ca_cert && wpa_s->conf->home_ca_cert[0] && 743 wpa_config_set_quoted(ssid, "ca_cert", wpa_s->conf->home_ca_cert) < 744 0) 745 goto fail; 746 747 nai_realm_free(realm, count); 748 749 wpa_supplicant_select_network(wpa_s, ssid); 750 751 return 0; 752 753 fail: 754 wpas_notify_network_removed(wpa_s, ssid); 755 wpa_config_remove_network(wpa_s->conf, ssid->id); 756 nai_realm_free(realm, count); 757 return -1; 758 } 759 760 761 static int interworking_credentials_available_3gpp( 762 struct wpa_supplicant *wpa_s, struct wpa_bss *bss) 763 { 764 int ret = 0; 765 766 #ifdef INTERWORKING_3GPP 767 if (bss->anqp_3gpp == NULL) 768 return ret; 769 770 if (wpa_s->conf->home_imsi == NULL || !wpa_s->conf->home_imsi[0] || 771 wpa_s->conf->home_milenage == NULL || 772 !wpa_s->conf->home_milenage[0]) 773 return ret; 774 775 wpa_printf(MSG_DEBUG, "Interworking: Parsing 3GPP info from " MACSTR, 776 MAC2STR(bss->bssid)); 777 ret = plmn_id_match(bss->anqp_3gpp, wpa_s->conf->home_imsi); 778 wpa_printf(MSG_DEBUG, "PLMN match %sfound", ret ? "" : "not "); 779 #endif /* INTERWORKING_3GPP */ 780 return ret; 781 } 782 783 784 static int interworking_credentials_available_realm( 785 struct wpa_supplicant *wpa_s, struct wpa_bss *bss) 786 { 787 struct nai_realm *realm; 788 u16 count, i; 789 int found = 0; 790 791 if (bss->anqp_nai_realm == NULL) 792 return 0; 793 794 if (wpa_s->conf->home_realm == NULL) 795 return 0; 796 797 wpa_printf(MSG_DEBUG, "Interworking: Parsing NAI Realm list from " 798 MACSTR, MAC2STR(bss->bssid)); 799 realm = nai_realm_parse(bss->anqp_nai_realm, &count); 800 if (realm == NULL) { 801 wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI " 802 "Realm list from " MACSTR, MAC2STR(bss->bssid)); 803 return 0; 804 } 805 806 for (i = 0; i < count; i++) { 807 if (!nai_realm_match(&realm[i], wpa_s->conf->home_realm)) 808 continue; 809 if (nai_realm_find_eap(wpa_s, &realm[i])) { 810 found++; 811 break; 812 } 813 } 814 815 nai_realm_free(realm, count); 816 817 return found; 818 } 819 820 821 static int interworking_credentials_available(struct wpa_supplicant *wpa_s, 822 struct wpa_bss *bss) 823 { 824 return interworking_credentials_available_realm(wpa_s, bss) || 825 interworking_credentials_available_3gpp(wpa_s, bss); 826 } 827 828 829 static void interworking_select_network(struct wpa_supplicant *wpa_s) 830 { 831 struct wpa_bss *bss, *selected = NULL; 832 unsigned int count = 0; 833 834 wpa_s->network_select = 0; 835 836 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { 837 if (!interworking_credentials_available(wpa_s, bss)) 838 continue; 839 count++; 840 wpa_msg(wpa_s, MSG_INFO, INTERWORKING_AP MACSTR, 841 MAC2STR(bss->bssid)); 842 if (selected == NULL && wpa_s->auto_select) 843 selected = bss; 844 } 845 846 if (count == 0) { 847 wpa_msg(wpa_s, MSG_INFO, INTERWORKING_NO_MATCH "No network " 848 "with matching credentials found"); 849 } 850 851 if (selected) 852 interworking_connect(wpa_s, selected); 853 } 854 855 856 static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s) 857 { 858 struct wpa_bss *bss; 859 int found = 0; 860 const u8 *ie; 861 862 if (!wpa_s->fetch_anqp_in_progress) 863 return; 864 865 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { 866 if (!(bss->caps & IEEE80211_CAP_ESS)) 867 continue; 868 ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB); 869 if (ie == NULL || ie[1] < 4 || !(ie[5] & 0x80)) 870 continue; /* AP does not support Interworking */ 871 872 if (!(bss->flags & WPA_BSS_ANQP_FETCH_TRIED)) { 873 found++; 874 bss->flags |= WPA_BSS_ANQP_FETCH_TRIED; 875 wpa_msg(wpa_s, MSG_INFO, "Starting ANQP fetch for " 876 MACSTR, MAC2STR(bss->bssid)); 877 interworking_anqp_send_req(wpa_s, bss); 878 break; 879 } 880 } 881 882 if (found == 0) { 883 wpa_msg(wpa_s, MSG_INFO, "ANQP fetch completed"); 884 wpa_s->fetch_anqp_in_progress = 0; 885 if (wpa_s->network_select) 886 interworking_select_network(wpa_s); 887 } 888 } 889 890 891 static void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s) 892 { 893 struct wpa_bss *bss; 894 895 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) 896 bss->flags &= ~WPA_BSS_ANQP_FETCH_TRIED; 897 898 wpa_s->fetch_anqp_in_progress = 1; 899 interworking_next_anqp_fetch(wpa_s); 900 } 901 902 903 int interworking_fetch_anqp(struct wpa_supplicant *wpa_s) 904 { 905 if (wpa_s->fetch_anqp_in_progress || wpa_s->network_select) 906 return 0; 907 908 wpa_s->network_select = 0; 909 910 interworking_start_fetch_anqp(wpa_s); 911 912 return 0; 913 } 914 915 916 void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s) 917 { 918 if (!wpa_s->fetch_anqp_in_progress) 919 return; 920 921 wpa_s->fetch_anqp_in_progress = 0; 922 } 923 924 925 int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, 926 u16 info_ids[], size_t num_ids) 927 { 928 struct wpabuf *buf; 929 int ret = 0; 930 int freq; 931 struct wpa_bss *bss; 932 int res; 933 934 freq = wpa_s->assoc_freq; 935 bss = wpa_bss_get_bssid(wpa_s, dst); 936 if (bss) 937 freq = bss->freq; 938 if (freq <= 0) 939 return -1; 940 941 wpa_printf(MSG_DEBUG, "ANQP: Query Request to " MACSTR " for %u id(s)", 942 MAC2STR(dst), (unsigned int) num_ids); 943 944 buf = anqp_build_req(info_ids, num_ids, NULL); 945 if (buf == NULL) 946 return -1; 947 948 res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s); 949 if (res < 0) { 950 wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request"); 951 ret = -1; 952 } else 953 wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token " 954 "%u", res); 955 956 wpabuf_free(buf); 957 return ret; 958 } 959 960 961 static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, 962 const u8 *sa, u16 info_id, 963 const u8 *data, size_t slen) 964 { 965 const u8 *pos = data; 966 struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa); 967 968 switch (info_id) { 969 case ANQP_CAPABILITY_LIST: 970 wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR 971 " ANQP Capability list", MAC2STR(sa)); 972 break; 973 case ANQP_VENUE_NAME: 974 wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR 975 " Venue Name", MAC2STR(sa)); 976 wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Venue Name", pos, slen); 977 if (bss) { 978 wpabuf_free(bss->anqp_venue_name); 979 bss->anqp_venue_name = wpabuf_alloc_copy(pos, slen); 980 } 981 break; 982 case ANQP_NETWORK_AUTH_TYPE: 983 wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR 984 " Network Authentication Type information", 985 MAC2STR(sa)); 986 wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Network Authentication " 987 "Type", pos, slen); 988 if (bss) { 989 wpabuf_free(bss->anqp_network_auth_type); 990 bss->anqp_network_auth_type = 991 wpabuf_alloc_copy(pos, slen); 992 } 993 break; 994 case ANQP_ROAMING_CONSORTIUM: 995 wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR 996 " Roaming Consortium list", MAC2STR(sa)); 997 wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Roaming Consortium", 998 pos, slen); 999 if (bss) { 1000 wpabuf_free(bss->anqp_roaming_consortium); 1001 bss->anqp_roaming_consortium = 1002 wpabuf_alloc_copy(pos, slen); 1003 } 1004 break; 1005 case ANQP_IP_ADDR_TYPE_AVAILABILITY: 1006 wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR 1007 " IP Address Type Availability information", 1008 MAC2STR(sa)); 1009 wpa_hexdump(MSG_MSGDUMP, "ANQP: IP Address Availability", 1010 pos, slen); 1011 if (bss) { 1012 wpabuf_free(bss->anqp_ip_addr_type_availability); 1013 bss->anqp_ip_addr_type_availability = 1014 wpabuf_alloc_copy(pos, slen); 1015 } 1016 break; 1017 case ANQP_NAI_REALM: 1018 wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR 1019 " NAI Realm list", MAC2STR(sa)); 1020 wpa_hexdump_ascii(MSG_DEBUG, "ANQP: NAI Realm", pos, slen); 1021 if (bss) { 1022 wpabuf_free(bss->anqp_nai_realm); 1023 bss->anqp_nai_realm = wpabuf_alloc_copy(pos, slen); 1024 } 1025 break; 1026 case ANQP_3GPP_CELLULAR_NETWORK: 1027 wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR 1028 " 3GPP Cellular Network information", MAC2STR(sa)); 1029 wpa_hexdump_ascii(MSG_DEBUG, "ANQP: 3GPP Cellular Network", 1030 pos, slen); 1031 if (bss) { 1032 wpabuf_free(bss->anqp_3gpp); 1033 bss->anqp_3gpp = wpabuf_alloc_copy(pos, slen); 1034 } 1035 break; 1036 case ANQP_DOMAIN_NAME: 1037 wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR 1038 " Domain Name list", MAC2STR(sa)); 1039 wpa_hexdump_ascii(MSG_MSGDUMP, "ANQP: Domain Name", pos, slen); 1040 if (bss) { 1041 wpabuf_free(bss->anqp_domain_name); 1042 bss->anqp_domain_name = wpabuf_alloc_copy(pos, slen); 1043 } 1044 break; 1045 case ANQP_VENDOR_SPECIFIC: 1046 if (slen < 3) 1047 return; 1048 1049 switch (WPA_GET_BE24(pos)) { 1050 default: 1051 wpa_printf(MSG_DEBUG, "Interworking: Unsupported " 1052 "vendor-specific ANQP OUI %06x", 1053 WPA_GET_BE24(pos)); 1054 return; 1055 } 1056 break; 1057 default: 1058 wpa_printf(MSG_DEBUG, "Interworking: Unsupported ANQP Info ID " 1059 "%u", info_id); 1060 break; 1061 } 1062 } 1063 1064 1065 void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token, 1066 enum gas_query_result result, 1067 const struct wpabuf *adv_proto, 1068 const struct wpabuf *resp, u16 status_code) 1069 { 1070 struct wpa_supplicant *wpa_s = ctx; 1071 const u8 *pos; 1072 const u8 *end; 1073 u16 info_id; 1074 u16 slen; 1075 1076 if (result != GAS_QUERY_SUCCESS) 1077 return; 1078 1079 pos = wpabuf_head(adv_proto); 1080 if (wpabuf_len(adv_proto) < 4 || pos[0] != WLAN_EID_ADV_PROTO || 1081 pos[1] < 2 || pos[3] != ACCESS_NETWORK_QUERY_PROTOCOL) { 1082 wpa_printf(MSG_DEBUG, "ANQP: Unexpected Advertisement " 1083 "Protocol in response"); 1084 return; 1085 } 1086 1087 pos = wpabuf_head(resp); 1088 end = pos + wpabuf_len(resp); 1089 1090 while (pos < end) { 1091 if (pos + 4 > end) { 1092 wpa_printf(MSG_DEBUG, "ANQP: Invalid element"); 1093 break; 1094 } 1095 info_id = WPA_GET_LE16(pos); 1096 pos += 2; 1097 slen = WPA_GET_LE16(pos); 1098 pos += 2; 1099 if (pos + slen > end) { 1100 wpa_printf(MSG_DEBUG, "ANQP: Invalid element length " 1101 "for Info ID %u", info_id); 1102 break; 1103 } 1104 interworking_parse_rx_anqp_resp(wpa_s, dst, info_id, pos, 1105 slen); 1106 pos += slen; 1107 } 1108 } 1109 1110 1111 static void interworking_scan_res_handler(struct wpa_supplicant *wpa_s, 1112 struct wpa_scan_results *scan_res) 1113 { 1114 wpa_printf(MSG_DEBUG, "Interworking: Scan results available - start " 1115 "ANQP fetch"); 1116 interworking_start_fetch_anqp(wpa_s); 1117 } 1118 1119 1120 int interworking_select(struct wpa_supplicant *wpa_s, int auto_select) 1121 { 1122 interworking_stop_fetch_anqp(wpa_s); 1123 wpa_s->network_select = 1; 1124 wpa_s->auto_select = !!auto_select; 1125 wpa_printf(MSG_DEBUG, "Interworking: Start scan for network " 1126 "selection"); 1127 wpa_s->scan_res_handler = interworking_scan_res_handler; 1128 wpa_s->scan_req = 2; 1129 wpa_supplicant_req_scan(wpa_s, 0, 0); 1130 1131 return 0; 1132 } 1133