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