1 /* 2 * Copyright (c) 2009, Atheros Communications, Inc. 3 * Copyright (c) 2011-2013, 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 "eloop.h" 13 #include "common/ieee802_11_common.h" 14 #include "common/ieee802_11_defs.h" 15 #include "common/gas.h" 16 #include "common/wpa_ctrl.h" 17 #include "rsn_supp/wpa.h" 18 #include "wpa_supplicant_i.h" 19 #include "driver_i.h" 20 #include "config.h" 21 #include "scan.h" 22 #include "bss.h" 23 #include "blacklist.h" 24 #include "gas_query.h" 25 #include "interworking.h" 26 #include "hs20_supplicant.h" 27 28 29 #define OSU_MAX_ITEMS 10 30 31 struct osu_lang_string { 32 char lang[4]; 33 char text[253]; 34 }; 35 36 struct osu_icon { 37 u16 width; 38 u16 height; 39 char lang[4]; 40 char icon_type[256]; 41 char filename[256]; 42 unsigned int id; 43 unsigned int failed:1; 44 }; 45 46 struct osu_provider { 47 u8 bssid[ETH_ALEN]; 48 u8 osu_ssid[32]; 49 u8 osu_ssid_len; 50 char server_uri[256]; 51 u32 osu_methods; /* bit 0 = OMA-DM, bit 1 = SOAP-XML SPP */ 52 char osu_nai[256]; 53 struct osu_lang_string friendly_name[OSU_MAX_ITEMS]; 54 size_t friendly_name_count; 55 struct osu_lang_string serv_desc[OSU_MAX_ITEMS]; 56 size_t serv_desc_count; 57 struct osu_icon icon[OSU_MAX_ITEMS]; 58 size_t icon_count; 59 }; 60 61 62 void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id) 63 { 64 u8 conf; 65 66 wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); 67 wpabuf_put_u8(buf, pps_mo_id >= 0 ? 7 : 5); 68 wpabuf_put_be24(buf, OUI_WFA); 69 wpabuf_put_u8(buf, HS20_INDICATION_OUI_TYPE); 70 conf = HS20_VERSION; 71 if (pps_mo_id >= 0) 72 conf |= HS20_PPS_MO_ID_PRESENT; 73 wpabuf_put_u8(buf, conf); 74 if (pps_mo_id >= 0) 75 wpabuf_put_le16(buf, pps_mo_id); 76 } 77 78 79 int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, 80 struct wpa_bss *bss) 81 { 82 if (!wpa_s->conf->hs20 || !ssid) 83 return 0; 84 85 if (ssid->parent_cred) 86 return 1; 87 88 if (bss && !wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) 89 return 0; 90 91 /* 92 * This may catch some non-Hotspot 2.0 cases, but it is safer to do that 93 * than cause Hotspot 2.0 connections without indication element getting 94 * added. Non-Hotspot 2.0 APs should ignore the unknown vendor element. 95 */ 96 97 if (!(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X)) 98 return 0; 99 if (!(ssid->pairwise_cipher & WPA_CIPHER_CCMP)) 100 return 0; 101 if (ssid->proto != WPA_PROTO_RSN) 102 return 0; 103 104 return 1; 105 } 106 107 108 int hs20_get_pps_mo_id(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) 109 { 110 struct wpa_cred *cred; 111 112 if (ssid == NULL) 113 return 0; 114 115 if (ssid->update_identifier) 116 return ssid->update_identifier; 117 118 if (ssid->parent_cred == NULL) 119 return 0; 120 121 for (cred = wpa_s->conf->cred; cred; cred = cred->next) { 122 if (ssid->parent_cred == cred) 123 return cred->update_identifier; 124 } 125 126 return 0; 127 } 128 129 130 void hs20_put_anqp_req(u32 stypes, const u8 *payload, size_t payload_len, 131 struct wpabuf *buf) 132 { 133 u8 *len_pos; 134 135 if (buf == NULL) 136 return; 137 138 len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC); 139 wpabuf_put_be24(buf, OUI_WFA); 140 wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE); 141 if (stypes == BIT(HS20_STYPE_NAI_HOME_REALM_QUERY)) { 142 wpabuf_put_u8(buf, HS20_STYPE_NAI_HOME_REALM_QUERY); 143 wpabuf_put_u8(buf, 0); /* Reserved */ 144 if (payload) 145 wpabuf_put_data(buf, payload, payload_len); 146 } else if (stypes == BIT(HS20_STYPE_ICON_REQUEST)) { 147 wpabuf_put_u8(buf, HS20_STYPE_ICON_REQUEST); 148 wpabuf_put_u8(buf, 0); /* Reserved */ 149 if (payload) 150 wpabuf_put_data(buf, payload, payload_len); 151 } else { 152 u8 i; 153 wpabuf_put_u8(buf, HS20_STYPE_QUERY_LIST); 154 wpabuf_put_u8(buf, 0); /* Reserved */ 155 for (i = 0; i < 32; i++) { 156 if (stypes & BIT(i)) 157 wpabuf_put_u8(buf, i); 158 } 159 } 160 gas_anqp_set_element_len(buf, len_pos); 161 162 gas_anqp_set_len(buf); 163 } 164 165 166 struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload, 167 size_t payload_len) 168 { 169 struct wpabuf *buf; 170 171 buf = gas_anqp_build_initial_req(0, 100 + payload_len); 172 if (buf == NULL) 173 return NULL; 174 175 hs20_put_anqp_req(stypes, payload, payload_len, buf); 176 177 return buf; 178 } 179 180 181 int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes, 182 const u8 *payload, size_t payload_len) 183 { 184 struct wpabuf *buf; 185 int ret = 0; 186 int freq; 187 struct wpa_bss *bss; 188 int res; 189 190 freq = wpa_s->assoc_freq; 191 bss = wpa_bss_get_bssid(wpa_s, dst); 192 if (bss) { 193 wpa_bss_anqp_unshare_alloc(bss); 194 freq = bss->freq; 195 } 196 if (freq <= 0) 197 return -1; 198 199 wpa_printf(MSG_DEBUG, "HS20: ANQP Query Request to " MACSTR " for " 200 "subtypes 0x%x", MAC2STR(dst), stypes); 201 202 buf = hs20_build_anqp_req(stypes, payload, payload_len); 203 if (buf == NULL) 204 return -1; 205 206 res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s); 207 if (res < 0) { 208 wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request"); 209 wpabuf_free(buf); 210 ret = -1; 211 } else 212 wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token " 213 "%u", res); 214 215 return ret; 216 } 217 218 219 static int hs20_process_icon_binary_file(struct wpa_supplicant *wpa_s, 220 const u8 *sa, const u8 *pos, 221 size_t slen) 222 { 223 char fname[256]; 224 int png; 225 FILE *f; 226 u16 data_len; 227 228 wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR " Icon Binary File", 229 MAC2STR(sa)); 230 231 if (slen < 4) { 232 wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon Binary File " 233 "value from " MACSTR, MAC2STR(sa)); 234 return -1; 235 } 236 237 wpa_printf(MSG_DEBUG, "HS 2.0: Download Status Code %u", *pos); 238 if (*pos != 0) 239 return -1; 240 pos++; 241 slen--; 242 243 if ((size_t) 1 + pos[0] > slen) { 244 wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon Binary File " 245 "value from " MACSTR, MAC2STR(sa)); 246 return -1; 247 } 248 wpa_hexdump_ascii(MSG_DEBUG, "Icon Type", pos + 1, pos[0]); 249 png = os_strncasecmp((char *) pos + 1, "image/png", 9) == 0; 250 slen -= 1 + pos[0]; 251 pos += 1 + pos[0]; 252 253 if (slen < 2) { 254 wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon Binary File " 255 "value from " MACSTR, MAC2STR(sa)); 256 return -1; 257 } 258 data_len = WPA_GET_LE16(pos); 259 pos += 2; 260 slen -= 2; 261 262 if (data_len > slen) { 263 wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon Binary File " 264 "value from " MACSTR, MAC2STR(sa)); 265 return -1; 266 } 267 268 wpa_printf(MSG_DEBUG, "Icon Binary Data: %u bytes", data_len); 269 if (wpa_s->conf->osu_dir == NULL) 270 return -1; 271 272 wpa_s->osu_icon_id++; 273 if (wpa_s->osu_icon_id == 0) 274 wpa_s->osu_icon_id++; 275 snprintf(fname, sizeof(fname), "%s/osu-icon-%u.%s", 276 wpa_s->conf->osu_dir, wpa_s->osu_icon_id, 277 png ? "png" : "icon"); 278 f = fopen(fname, "wb"); 279 if (f == NULL) 280 return -1; 281 if (fwrite(pos, slen, 1, f) != 1) { 282 fclose(f); 283 unlink(fname); 284 return -1; 285 } 286 fclose(f); 287 288 wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP-ICON %s", fname); 289 return 0; 290 } 291 292 293 static void hs20_continue_icon_fetch(void *eloop_ctx, void *sock_ctx) 294 { 295 struct wpa_supplicant *wpa_s = eloop_ctx; 296 if (wpa_s->fetch_osu_icon_in_progress) 297 hs20_next_osu_icon(wpa_s); 298 } 299 300 301 static void hs20_osu_icon_fetch_result(struct wpa_supplicant *wpa_s, int res) 302 { 303 size_t i, j; 304 struct os_reltime now, tmp; 305 int dur; 306 307 os_get_reltime(&now); 308 os_reltime_sub(&now, &wpa_s->osu_icon_fetch_start, &tmp); 309 dur = tmp.sec * 1000 + tmp.usec / 1000; 310 wpa_printf(MSG_DEBUG, "HS 2.0: Icon fetch dur=%d ms res=%d", 311 dur, res); 312 313 for (i = 0; i < wpa_s->osu_prov_count; i++) { 314 struct osu_provider *osu = &wpa_s->osu_prov[i]; 315 for (j = 0; j < osu->icon_count; j++) { 316 struct osu_icon *icon = &osu->icon[j]; 317 if (icon->id || icon->failed) 318 continue; 319 if (res < 0) 320 icon->failed = 1; 321 else 322 icon->id = wpa_s->osu_icon_id; 323 return; 324 } 325 } 326 } 327 328 329 void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, 330 const u8 *sa, const u8 *data, size_t slen) 331 { 332 const u8 *pos = data; 333 u8 subtype; 334 struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa); 335 struct wpa_bss_anqp *anqp = NULL; 336 int ret; 337 338 if (slen < 2) 339 return; 340 341 if (bss) 342 anqp = bss->anqp; 343 344 subtype = *pos++; 345 slen--; 346 347 pos++; /* Reserved */ 348 slen--; 349 350 switch (subtype) { 351 case HS20_STYPE_CAPABILITY_LIST: 352 wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR 353 " HS Capability List", MAC2STR(sa)); 354 wpa_hexdump_ascii(MSG_DEBUG, "HS Capability List", pos, slen); 355 break; 356 case HS20_STYPE_OPERATOR_FRIENDLY_NAME: 357 wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR 358 " Operator Friendly Name", MAC2STR(sa)); 359 wpa_hexdump_ascii(MSG_DEBUG, "oper friendly name", pos, slen); 360 if (anqp) { 361 wpabuf_free(anqp->hs20_operator_friendly_name); 362 anqp->hs20_operator_friendly_name = 363 wpabuf_alloc_copy(pos, slen); 364 } 365 break; 366 case HS20_STYPE_WAN_METRICS: 367 wpa_hexdump(MSG_DEBUG, "WAN Metrics", pos, slen); 368 if (slen < 13) { 369 wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short WAN " 370 "Metrics value from " MACSTR, MAC2STR(sa)); 371 break; 372 } 373 wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR 374 " WAN Metrics %02x:%u:%u:%u:%u:%u", MAC2STR(sa), 375 pos[0], WPA_GET_LE32(pos + 1), WPA_GET_LE32(pos + 5), 376 pos[9], pos[10], WPA_GET_LE16(pos + 11)); 377 if (anqp) { 378 wpabuf_free(anqp->hs20_wan_metrics); 379 anqp->hs20_wan_metrics = wpabuf_alloc_copy(pos, slen); 380 } 381 break; 382 case HS20_STYPE_CONNECTION_CAPABILITY: 383 wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR 384 " Connection Capability", MAC2STR(sa)); 385 wpa_hexdump_ascii(MSG_DEBUG, "conn capability", pos, slen); 386 if (anqp) { 387 wpabuf_free(anqp->hs20_connection_capability); 388 anqp->hs20_connection_capability = 389 wpabuf_alloc_copy(pos, slen); 390 } 391 break; 392 case HS20_STYPE_OPERATING_CLASS: 393 wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR 394 " Operating Class", MAC2STR(sa)); 395 wpa_hexdump_ascii(MSG_DEBUG, "Operating Class", pos, slen); 396 if (anqp) { 397 wpabuf_free(anqp->hs20_operating_class); 398 anqp->hs20_operating_class = 399 wpabuf_alloc_copy(pos, slen); 400 } 401 break; 402 case HS20_STYPE_OSU_PROVIDERS_LIST: 403 wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR 404 " OSU Providers list", MAC2STR(sa)); 405 wpa_s->num_prov_found++; 406 if (anqp) { 407 wpabuf_free(anqp->hs20_osu_providers_list); 408 anqp->hs20_osu_providers_list = 409 wpabuf_alloc_copy(pos, slen); 410 } 411 break; 412 case HS20_STYPE_ICON_BINARY_FILE: 413 ret = hs20_process_icon_binary_file(wpa_s, sa, pos, slen); 414 if (wpa_s->fetch_osu_icon_in_progress) { 415 hs20_osu_icon_fetch_result(wpa_s, ret); 416 eloop_cancel_timeout(hs20_continue_icon_fetch, 417 wpa_s, NULL); 418 eloop_register_timeout(0, 0, hs20_continue_icon_fetch, 419 wpa_s, NULL); 420 } 421 break; 422 default: 423 wpa_printf(MSG_DEBUG, "HS20: Unsupported subtype %u", subtype); 424 break; 425 } 426 } 427 428 429 void hs20_notify_parse_done(struct wpa_supplicant *wpa_s) 430 { 431 if (!wpa_s->fetch_osu_icon_in_progress) 432 return; 433 if (eloop_is_timeout_registered(hs20_continue_icon_fetch, wpa_s, NULL)) 434 return; 435 /* 436 * We are going through icon fetch, but no icon response was received. 437 * Assume this means the current AP could not provide an answer to avoid 438 * getting stuck in fetch iteration. 439 */ 440 hs20_icon_fetch_failed(wpa_s); 441 } 442 443 444 static void hs20_free_osu_prov_entry(struct osu_provider *prov) 445 { 446 } 447 448 449 void hs20_free_osu_prov(struct wpa_supplicant *wpa_s) 450 { 451 size_t i; 452 for (i = 0; i < wpa_s->osu_prov_count; i++) 453 hs20_free_osu_prov_entry(&wpa_s->osu_prov[i]); 454 os_free(wpa_s->osu_prov); 455 wpa_s->osu_prov = NULL; 456 wpa_s->osu_prov_count = 0; 457 } 458 459 460 static void hs20_osu_fetch_done(struct wpa_supplicant *wpa_s) 461 { 462 char fname[256]; 463 FILE *f; 464 size_t i, j; 465 466 wpa_s->fetch_osu_info = 0; 467 wpa_s->fetch_osu_icon_in_progress = 0; 468 469 if (wpa_s->conf->osu_dir == NULL) { 470 hs20_free_osu_prov(wpa_s); 471 wpa_s->fetch_anqp_in_progress = 0; 472 return; 473 } 474 475 snprintf(fname, sizeof(fname), "%s/osu-providers.txt", 476 wpa_s->conf->osu_dir); 477 f = fopen(fname, "w"); 478 if (f == NULL) { 479 hs20_free_osu_prov(wpa_s); 480 return; 481 } 482 for (i = 0; i < wpa_s->osu_prov_count; i++) { 483 struct osu_provider *osu = &wpa_s->osu_prov[i]; 484 if (i > 0) 485 fprintf(f, "\n"); 486 fprintf(f, "OSU-PROVIDER " MACSTR "\n" 487 "uri=%s\n" 488 "methods=%08x\n", 489 MAC2STR(osu->bssid), osu->server_uri, osu->osu_methods); 490 if (osu->osu_ssid_len) { 491 fprintf(f, "osu_ssid=%s\n", 492 wpa_ssid_txt(osu->osu_ssid, 493 osu->osu_ssid_len)); 494 } 495 if (osu->osu_nai[0]) 496 fprintf(f, "osu_nai=%s\n", osu->osu_nai); 497 for (j = 0; j < osu->friendly_name_count; j++) { 498 fprintf(f, "friendly_name=%s:%s\n", 499 osu->friendly_name[j].lang, 500 osu->friendly_name[j].text); 501 } 502 for (j = 0; j < osu->serv_desc_count; j++) { 503 fprintf(f, "desc=%s:%s\n", 504 osu->serv_desc[j].lang, 505 osu->serv_desc[j].text); 506 } 507 for (j = 0; j < osu->icon_count; j++) { 508 struct osu_icon *icon = &osu->icon[j]; 509 if (icon->failed) 510 continue; /* could not fetch icon */ 511 fprintf(f, "icon=%u:%u:%u:%s:%s:%s\n", 512 icon->id, icon->width, icon->height, icon->lang, 513 icon->icon_type, icon->filename); 514 } 515 } 516 fclose(f); 517 hs20_free_osu_prov(wpa_s); 518 519 wpa_msg(wpa_s, MSG_INFO, "OSU provider fetch completed"); 520 wpa_s->fetch_anqp_in_progress = 0; 521 } 522 523 524 void hs20_next_osu_icon(struct wpa_supplicant *wpa_s) 525 { 526 size_t i, j; 527 528 wpa_printf(MSG_DEBUG, "HS 2.0: Ready to fetch next icon"); 529 530 for (i = 0; i < wpa_s->osu_prov_count; i++) { 531 struct osu_provider *osu = &wpa_s->osu_prov[i]; 532 for (j = 0; j < osu->icon_count; j++) { 533 struct osu_icon *icon = &osu->icon[j]; 534 if (icon->id || icon->failed) 535 continue; 536 537 wpa_printf(MSG_DEBUG, "HS 2.0: Try to fetch icon '%s' " 538 "from " MACSTR, icon->filename, 539 MAC2STR(osu->bssid)); 540 os_get_reltime(&wpa_s->osu_icon_fetch_start); 541 if (hs20_anqp_send_req(wpa_s, osu->bssid, 542 BIT(HS20_STYPE_ICON_REQUEST), 543 (u8 *) icon->filename, 544 os_strlen(icon->filename)) < 0) { 545 icon->failed = 1; 546 continue; 547 } 548 return; 549 } 550 } 551 552 wpa_printf(MSG_DEBUG, "HS 2.0: No more icons to fetch"); 553 hs20_osu_fetch_done(wpa_s); 554 } 555 556 557 static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, 558 const u8 *osu_ssid, u8 osu_ssid_len, 559 const u8 *pos, size_t len) 560 { 561 struct osu_provider *prov; 562 const u8 *end = pos + len; 563 u16 len2; 564 const u8 *pos2; 565 566 wpa_hexdump(MSG_DEBUG, "HS 2.0: Parsing OSU Provider", pos, len); 567 prov = os_realloc_array(wpa_s->osu_prov, 568 wpa_s->osu_prov_count + 1, 569 sizeof(*prov)); 570 if (prov == NULL) 571 return; 572 wpa_s->osu_prov = prov; 573 prov = &prov[wpa_s->osu_prov_count]; 574 os_memset(prov, 0, sizeof(*prov)); 575 576 os_memcpy(prov->bssid, bss->bssid, ETH_ALEN); 577 os_memcpy(prov->osu_ssid, osu_ssid, osu_ssid_len); 578 prov->osu_ssid_len = osu_ssid_len; 579 580 /* OSU Friendly Name Length */ 581 if (pos + 2 > end) { 582 wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU " 583 "Friendly Name Length"); 584 return; 585 } 586 len2 = WPA_GET_LE16(pos); 587 pos += 2; 588 if (pos + len2 > end) { 589 wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU " 590 "Friendly Name Duples"); 591 return; 592 } 593 pos2 = pos; 594 pos += len2; 595 596 /* OSU Friendly Name Duples */ 597 while (pos2 + 4 <= pos && prov->friendly_name_count < OSU_MAX_ITEMS) { 598 struct osu_lang_string *f; 599 if (pos2 + 1 + pos2[0] > pos || pos2[0] < 3) { 600 wpa_printf(MSG_DEBUG, "Invalid OSU Friendly Name"); 601 break; 602 } 603 f = &prov->friendly_name[prov->friendly_name_count++]; 604 os_memcpy(f->lang, pos2 + 1, 3); 605 os_memcpy(f->text, pos2 + 1 + 3, pos2[0] - 3); 606 pos2 += 1 + pos2[0]; 607 } 608 609 /* OSU Server URI */ 610 if (pos + 1 > end || pos + 1 + pos[0] > end) { 611 wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU Server " 612 "URI"); 613 return; 614 } 615 os_memcpy(prov->server_uri, pos + 1, pos[0]); 616 pos += 1 + pos[0]; 617 618 /* OSU Method list */ 619 if (pos + 1 > end || pos + 1 + pos[0] > end) { 620 wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU Method " 621 "list"); 622 return; 623 } 624 pos2 = pos + 1; 625 pos += 1 + pos[0]; 626 while (pos2 < pos) { 627 if (*pos2 < 32) 628 prov->osu_methods |= BIT(*pos2); 629 pos2++; 630 } 631 632 /* Icons Available Length */ 633 if (pos + 2 > end) { 634 wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for Icons " 635 "Available Length"); 636 return; 637 } 638 len2 = WPA_GET_LE16(pos); 639 pos += 2; 640 if (pos + len2 > end) { 641 wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for Icons " 642 "Available"); 643 return; 644 } 645 pos2 = pos; 646 pos += len2; 647 648 /* Icons Available */ 649 while (pos2 < pos) { 650 struct osu_icon *icon = &prov->icon[prov->icon_count]; 651 if (pos2 + 2 + 2 + 3 + 1 + 1 > pos) { 652 wpa_printf(MSG_DEBUG, "HS 2.0: Invalid Icon Metadata"); 653 break; 654 } 655 656 icon->width = WPA_GET_LE16(pos2); 657 pos2 += 2; 658 icon->height = WPA_GET_LE16(pos2); 659 pos2 += 2; 660 os_memcpy(icon->lang, pos2, 3); 661 pos2 += 3; 662 663 if (pos2 + 1 + pos2[0] > pos) { 664 wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon Type"); 665 break; 666 } 667 os_memcpy(icon->icon_type, pos2 + 1, pos2[0]); 668 pos2 += 1 + pos2[0]; 669 670 if (pos2 + 1 + pos2[0] > pos) { 671 wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon " 672 "Filename"); 673 break; 674 } 675 os_memcpy(icon->filename, pos2 + 1, pos2[0]); 676 pos2 += 1 + pos2[0]; 677 678 prov->icon_count++; 679 } 680 681 /* OSU_NAI */ 682 if (pos + 1 > end || pos + 1 + pos[0] > end) { 683 wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU_NAI"); 684 return; 685 } 686 os_memcpy(prov->osu_nai, pos + 1, pos[0]); 687 pos += 1 + pos[0]; 688 689 /* OSU Service Description Length */ 690 if (pos + 2 > end) { 691 wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU " 692 "Service Description Length"); 693 return; 694 } 695 len2 = WPA_GET_LE16(pos); 696 pos += 2; 697 if (pos + len2 > end) { 698 wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU " 699 "Service Description Duples"); 700 return; 701 } 702 pos2 = pos; 703 pos += len2; 704 705 /* OSU Service Description Duples */ 706 while (pos2 + 4 <= pos && prov->serv_desc_count < OSU_MAX_ITEMS) { 707 struct osu_lang_string *f; 708 if (pos2 + 1 + pos2[0] > pos || pos2[0] < 3) { 709 wpa_printf(MSG_DEBUG, "Invalid OSU Service " 710 "Description"); 711 break; 712 } 713 f = &prov->serv_desc[prov->serv_desc_count++]; 714 os_memcpy(f->lang, pos2 + 1, 3); 715 os_memcpy(f->text, pos2 + 1 + 3, pos2[0] - 3); 716 pos2 += 1 + pos2[0]; 717 } 718 719 wpa_printf(MSG_DEBUG, "HS 2.0: Added OSU Provider through " MACSTR, 720 MAC2STR(bss->bssid)); 721 wpa_s->osu_prov_count++; 722 } 723 724 725 void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s) 726 { 727 struct wpa_bss *bss; 728 struct wpabuf *prov_anqp; 729 const u8 *pos, *end; 730 u16 len; 731 const u8 *osu_ssid; 732 u8 osu_ssid_len; 733 u8 num_providers; 734 735 hs20_free_osu_prov(wpa_s); 736 737 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { 738 if (bss->anqp == NULL) 739 continue; 740 prov_anqp = bss->anqp->hs20_osu_providers_list; 741 if (prov_anqp == NULL) 742 continue; 743 wpa_printf(MSG_DEBUG, "HS 2.0: Parsing OSU Providers list from " 744 MACSTR, MAC2STR(bss->bssid)); 745 wpa_hexdump_buf(MSG_DEBUG, "HS 2.0: OSU Providers list", 746 prov_anqp); 747 pos = wpabuf_head(prov_anqp); 748 end = pos + wpabuf_len(prov_anqp); 749 750 /* OSU SSID */ 751 if (pos + 1 > end) 752 continue; 753 if (pos + 1 + pos[0] > end) { 754 wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for " 755 "OSU SSID"); 756 continue; 757 } 758 osu_ssid_len = *pos++; 759 if (osu_ssid_len > 32) { 760 wpa_printf(MSG_DEBUG, "HS 2.0: Invalid OSU SSID " 761 "Length %u", osu_ssid_len); 762 continue; 763 } 764 osu_ssid = pos; 765 pos += osu_ssid_len; 766 767 if (pos + 1 > end) { 768 wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for " 769 "Number of OSU Providers"); 770 continue; 771 } 772 num_providers = *pos++; 773 wpa_printf(MSG_DEBUG, "HS 2.0: Number of OSU Providers: %u", 774 num_providers); 775 776 /* OSU Providers */ 777 while (pos + 2 < end && num_providers > 0) { 778 num_providers--; 779 len = WPA_GET_LE16(pos); 780 pos += 2; 781 if (pos + len > end) 782 break; 783 hs20_osu_add_prov(wpa_s, bss, osu_ssid, 784 osu_ssid_len, pos, len); 785 pos += len; 786 } 787 788 if (pos != end) { 789 wpa_printf(MSG_DEBUG, "HS 2.0: Ignored %d bytes of " 790 "extra data after OSU Providers", 791 (int) (end - pos)); 792 } 793 } 794 795 wpa_s->fetch_osu_icon_in_progress = 1; 796 hs20_next_osu_icon(wpa_s); 797 } 798 799 800 static void hs20_osu_scan_res_handler(struct wpa_supplicant *wpa_s, 801 struct wpa_scan_results *scan_res) 802 { 803 wpa_printf(MSG_DEBUG, "OSU provisioning fetch scan completed"); 804 wpa_s->network_select = 0; 805 wpa_s->fetch_all_anqp = 1; 806 wpa_s->fetch_osu_info = 1; 807 wpa_s->fetch_osu_icon_in_progress = 0; 808 809 interworking_start_fetch_anqp(wpa_s); 810 } 811 812 813 int hs20_fetch_osu(struct wpa_supplicant *wpa_s) 814 { 815 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { 816 wpa_printf(MSG_DEBUG, "HS 2.0: Cannot start fetch_osu - " 817 "interface disabled"); 818 return -1; 819 } 820 821 if (wpa_s->scanning) { 822 wpa_printf(MSG_DEBUG, "HS 2.0: Cannot start fetch_osu - " 823 "scanning"); 824 return -1; 825 } 826 827 if (wpa_s->conf->osu_dir == NULL) { 828 wpa_printf(MSG_DEBUG, "HS 2.0: Cannot start fetch_osu - " 829 "osu_dir not configured"); 830 return -1; 831 } 832 833 if (wpa_s->fetch_anqp_in_progress || wpa_s->network_select) { 834 wpa_printf(MSG_DEBUG, "HS 2.0: Cannot start fetch_osu - " 835 "fetch in progress (%d, %d)", 836 wpa_s->fetch_anqp_in_progress, 837 wpa_s->network_select); 838 return -1; 839 } 840 841 wpa_msg(wpa_s, MSG_INFO, "Starting OSU provisioning information fetch"); 842 wpa_s->num_osu_scans = 0; 843 wpa_s->num_prov_found = 0; 844 hs20_start_osu_scan(wpa_s); 845 846 return 0; 847 } 848 849 850 void hs20_start_osu_scan(struct wpa_supplicant *wpa_s) 851 { 852 wpa_s->num_osu_scans++; 853 wpa_s->scan_req = MANUAL_SCAN_REQ; 854 wpa_s->scan_res_handler = hs20_osu_scan_res_handler; 855 wpa_supplicant_req_scan(wpa_s, 0, 0); 856 } 857 858 859 void hs20_cancel_fetch_osu(struct wpa_supplicant *wpa_s) 860 { 861 wpa_printf(MSG_DEBUG, "Cancel OSU fetch"); 862 interworking_stop_fetch_anqp(wpa_s); 863 wpa_s->network_select = 0; 864 wpa_s->fetch_osu_info = 0; 865 wpa_s->fetch_osu_icon_in_progress = 0; 866 } 867 868 869 void hs20_icon_fetch_failed(struct wpa_supplicant *wpa_s) 870 { 871 hs20_osu_icon_fetch_result(wpa_s, -1); 872 eloop_cancel_timeout(hs20_continue_icon_fetch, wpa_s, NULL); 873 eloop_register_timeout(0, 0, hs20_continue_icon_fetch, wpa_s, NULL); 874 } 875 876 877 void hs20_rx_subscription_remediation(struct wpa_supplicant *wpa_s, 878 const char *url, u8 osu_method) 879 { 880 if (url) 881 wpa_msg(wpa_s, MSG_INFO, HS20_SUBSCRIPTION_REMEDIATION "%u %s", 882 osu_method, url); 883 else 884 wpa_msg(wpa_s, MSG_INFO, HS20_SUBSCRIPTION_REMEDIATION); 885 } 886 887 888 void hs20_rx_deauth_imminent_notice(struct wpa_supplicant *wpa_s, u8 code, 889 u16 reauth_delay, const char *url) 890 { 891 if (!wpa_sm_pmf_enabled(wpa_s->wpa)) { 892 wpa_printf(MSG_DEBUG, "HS 2.0: Ignore deauthentication imminent notice since PMF was not enabled"); 893 return; 894 } 895 896 wpa_msg(wpa_s, MSG_INFO, HS20_DEAUTH_IMMINENT_NOTICE "%u %u %s", 897 code, reauth_delay, url); 898 899 if (code == HS20_DEAUTH_REASON_CODE_BSS) { 900 wpa_printf(MSG_DEBUG, "HS 2.0: Add BSS to blacklist"); 901 wpa_blacklist_add(wpa_s, wpa_s->bssid); 902 /* TODO: For now, disable full ESS since some drivers may not 903 * support disabling per BSS. */ 904 if (wpa_s->current_ssid) { 905 struct os_reltime now; 906 os_get_reltime(&now); 907 if (now.sec + reauth_delay <= 908 wpa_s->current_ssid->disabled_until.sec) 909 return; 910 wpa_printf(MSG_DEBUG, "HS 2.0: Disable network for %u seconds (BSS)", 911 reauth_delay); 912 wpa_s->current_ssid->disabled_until.sec = 913 now.sec + reauth_delay; 914 } 915 } 916 917 if (code == HS20_DEAUTH_REASON_CODE_ESS && wpa_s->current_ssid) { 918 struct os_reltime now; 919 os_get_reltime(&now); 920 if (now.sec + reauth_delay <= 921 wpa_s->current_ssid->disabled_until.sec) 922 return; 923 wpa_printf(MSG_DEBUG, "HS 2.0: Disable network for %u seconds", 924 reauth_delay); 925 wpa_s->current_ssid->disabled_until.sec = 926 now.sec + reauth_delay; 927 } 928 } 929 930 931 void hs20_deinit(struct wpa_supplicant *wpa_s) 932 { 933 eloop_cancel_timeout(hs20_continue_icon_fetch, wpa_s, NULL); 934 hs20_free_osu_prov(wpa_s); 935 } 936