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