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