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