Home | History | Annotate | Download | only in wpa_supplicant
      1 /*
      2  * Interworking (IEEE 802.11u)
      3  * Copyright (c) 2011, Qualcomm Atheros
      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 "drivers/driver.h"
     16 #include "eap_common/eap_defs.h"
     17 #include "eap_peer/eap_methods.h"
     18 #include "wpa_supplicant_i.h"
     19 #include "config.h"
     20 #include "bss.h"
     21 #include "scan.h"
     22 #include "notify.h"
     23 #include "gas_query.h"
     24 #include "interworking.h"
     25 
     26 
     27 #if defined(EAP_SIM) | defined(EAP_SIM_DYNAMIC)
     28 #define INTERWORKING_3GPP
     29 #else
     30 #if defined(EAP_AKA) | defined(EAP_AKA_DYNAMIC)
     31 #define INTERWORKING_3GPP
     32 #else
     33 #if defined(EAP_AKA_PRIME) | defined(EAP_AKA_PRIME_DYNAMIC)
     34 #define INTERWORKING_3GPP
     35 #endif
     36 #endif
     37 #endif
     38 
     39 static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s);
     40 
     41 
     42 static struct wpabuf * anqp_build_req(u16 info_ids[], size_t num_ids,
     43 				      struct wpabuf *extra)
     44 {
     45 	struct wpabuf *buf;
     46 	size_t i;
     47 	u8 *len_pos;
     48 
     49 	buf = gas_anqp_build_initial_req(0, 4 + num_ids * 2 +
     50 					 (extra ? wpabuf_len(extra) : 0));
     51 	if (buf == NULL)
     52 		return NULL;
     53 
     54 	len_pos = gas_anqp_add_element(buf, ANQP_QUERY_LIST);
     55 	for (i = 0; i < num_ids; i++)
     56 		wpabuf_put_le16(buf, info_ids[i]);
     57 	gas_anqp_set_element_len(buf, len_pos);
     58 	if (extra)
     59 		wpabuf_put_buf(buf, extra);
     60 
     61 	gas_anqp_set_len(buf);
     62 
     63 	return buf;
     64 }
     65 
     66 
     67 static void interworking_anqp_resp_cb(void *ctx, const u8 *dst,
     68 				      u8 dialog_token,
     69 				      enum gas_query_result result,
     70 				      const struct wpabuf *adv_proto,
     71 				      const struct wpabuf *resp,
     72 				      u16 status_code)
     73 {
     74 	struct wpa_supplicant *wpa_s = ctx;
     75 
     76 	anqp_resp_cb(wpa_s, dst, dialog_token, result, adv_proto, resp,
     77 		     status_code);
     78 	interworking_next_anqp_fetch(wpa_s);
     79 }
     80 
     81 
     82 static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s,
     83 				      struct wpa_bss *bss)
     84 {
     85 	struct wpabuf *buf;
     86 	int ret = 0;
     87 	int res;
     88 	u16 info_ids[] = {
     89 		ANQP_CAPABILITY_LIST,
     90 		ANQP_VENUE_NAME,
     91 		ANQP_NETWORK_AUTH_TYPE,
     92 		ANQP_ROAMING_CONSORTIUM,
     93 		ANQP_IP_ADDR_TYPE_AVAILABILITY,
     94 		ANQP_NAI_REALM,
     95 		ANQP_3GPP_CELLULAR_NETWORK,
     96 		ANQP_DOMAIN_NAME
     97 	};
     98 	struct wpabuf *extra = NULL;
     99 
    100 	wpa_printf(MSG_DEBUG, "Interworking: ANQP Query Request to " MACSTR,
    101 		   MAC2STR(bss->bssid));
    102 
    103 	buf = anqp_build_req(info_ids, sizeof(info_ids) / sizeof(info_ids[0]),
    104 			     extra);
    105 	wpabuf_free(extra);
    106 	if (buf == NULL)
    107 		return -1;
    108 
    109 	res = gas_query_req(wpa_s->gas, bss->bssid, bss->freq, buf,
    110 			    interworking_anqp_resp_cb, wpa_s);
    111 	if (res < 0) {
    112 		wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
    113 		ret = -1;
    114 	} else
    115 		wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
    116 			   "%u", res);
    117 
    118 	wpabuf_free(buf);
    119 	return ret;
    120 }
    121 
    122 
    123 struct nai_realm_eap {
    124 	u8 method;
    125 	u8 inner_method;
    126 	enum nai_realm_eap_auth_inner_non_eap inner_non_eap;
    127 	u8 cred_type;
    128 	u8 tunneled_cred_type;
    129 };
    130 
    131 struct nai_realm {
    132 	u8 encoding;
    133 	char *realm;
    134 	u8 eap_count;
    135 	struct nai_realm_eap *eap;
    136 };
    137 
    138 
    139 static void nai_realm_free(struct nai_realm *realms, u16 count)
    140 {
    141 	u16 i;
    142 
    143 	if (realms == NULL)
    144 		return;
    145 	for (i = 0; i < count; i++) {
    146 		os_free(realms[i].eap);
    147 		os_free(realms[i].realm);
    148 	}
    149 	os_free(realms);
    150 }
    151 
    152 
    153 static const u8 * nai_realm_parse_eap(struct nai_realm_eap *e, const u8 *pos,
    154 				      const u8 *end)
    155 {
    156 	u8 elen, auth_count, a;
    157 	const u8 *e_end;
    158 
    159 	if (pos + 3 > end) {
    160 		wpa_printf(MSG_DEBUG, "No room for EAP Method fixed fields");
    161 		return NULL;
    162 	}
    163 
    164 	elen = *pos++;
    165 	if (pos + elen > end || elen < 2) {
    166 		wpa_printf(MSG_DEBUG, "No room for EAP Method subfield");
    167 		return NULL;
    168 	}
    169 	e_end = pos + elen;
    170 	e->method = *pos++;
    171 	auth_count = *pos++;
    172 	wpa_printf(MSG_DEBUG, "EAP Method: len=%u method=%u auth_count=%u",
    173 		   elen, e->method, auth_count);
    174 
    175 	for (a = 0; a < auth_count; a++) {
    176 		u8 id, len;
    177 
    178 		if (pos + 2 > end || pos + 2 + pos[1] > end) {
    179 			wpa_printf(MSG_DEBUG, "No room for Authentication "
    180 				   "Parameter subfield");
    181 			return NULL;
    182 		}
    183 
    184 		id = *pos++;
    185 		len = *pos++;
    186 
    187 		switch (id) {
    188 		case NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH:
    189 			if (len < 1)
    190 				break;
    191 			e->inner_non_eap = *pos;
    192 			if (e->method != EAP_TYPE_TTLS)
    193 				break;
    194 			switch (*pos) {
    195 			case NAI_REALM_INNER_NON_EAP_PAP:
    196 				wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP");
    197 				break;
    198 			case NAI_REALM_INNER_NON_EAP_CHAP:
    199 				wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP");
    200 				break;
    201 			case NAI_REALM_INNER_NON_EAP_MSCHAP:
    202 				wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP");
    203 				break;
    204 			case NAI_REALM_INNER_NON_EAP_MSCHAPV2:
    205 				wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2");
    206 				break;
    207 			}
    208 			break;
    209 		case NAI_REALM_EAP_AUTH_INNER_AUTH_EAP_METHOD:
    210 			if (len < 1)
    211 				break;
    212 			e->inner_method = *pos;
    213 			wpa_printf(MSG_DEBUG, "Inner EAP method: %u",
    214 				   e->inner_method);
    215 			break;
    216 		case NAI_REALM_EAP_AUTH_CRED_TYPE:
    217 			if (len < 1)
    218 				break;
    219 			e->cred_type = *pos;
    220 			wpa_printf(MSG_DEBUG, "Credential Type: %u",
    221 				   e->cred_type);
    222 			break;
    223 		case NAI_REALM_EAP_AUTH_TUNNELED_CRED_TYPE:
    224 			if (len < 1)
    225 				break;
    226 			e->tunneled_cred_type = *pos;
    227 			wpa_printf(MSG_DEBUG, "Tunneled EAP Method Credential "
    228 				   "Type: %u", e->tunneled_cred_type);
    229 			break;
    230 		default:
    231 			wpa_printf(MSG_DEBUG, "Unsupported Authentication "
    232 				   "Parameter: id=%u len=%u", id, len);
    233 			wpa_hexdump(MSG_DEBUG, "Authentication Parameter "
    234 				    "Value", pos, len);
    235 			break;
    236 		}
    237 
    238 		pos += len;
    239 	}
    240 
    241 	return e_end;
    242 }
    243 
    244 
    245 static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos,
    246 					const u8 *end)
    247 {
    248 	u16 len;
    249 	const u8 *f_end;
    250 	u8 realm_len, e;
    251 
    252 	if (end - pos < 4) {
    253 		wpa_printf(MSG_DEBUG, "No room for NAI Realm Data "
    254 			   "fixed fields");
    255 		return NULL;
    256 	}
    257 
    258 	len = WPA_GET_LE16(pos); /* NAI Realm Data field Length */
    259 	pos += 2;
    260 	if (pos + len > end || len < 3) {
    261 		wpa_printf(MSG_DEBUG, "No room for NAI Realm Data "
    262 			   "(len=%u; left=%u)",
    263 			   len, (unsigned int) (end - pos));
    264 		return NULL;
    265 	}
    266 	f_end = pos + len;
    267 
    268 	r->encoding = *pos++;
    269 	realm_len = *pos++;
    270 	if (pos + realm_len > f_end) {
    271 		wpa_printf(MSG_DEBUG, "No room for NAI Realm "
    272 			   "(len=%u; left=%u)",
    273 			   realm_len, (unsigned int) (f_end - pos));
    274 		return NULL;
    275 	}
    276 	wpa_hexdump_ascii(MSG_DEBUG, "NAI Realm", pos, realm_len);
    277 	r->realm = os_malloc(realm_len + 1);
    278 	if (r->realm == NULL)
    279 		return NULL;
    280 	os_memcpy(r->realm, pos, realm_len);
    281 	r->realm[realm_len] = '\0';
    282 	pos += realm_len;
    283 
    284 	if (pos + 1 > f_end) {
    285 		wpa_printf(MSG_DEBUG, "No room for EAP Method Count");
    286 		return NULL;
    287 	}
    288 	r->eap_count = *pos++;
    289 	wpa_printf(MSG_DEBUG, "EAP Count: %u", r->eap_count);
    290 	if (pos + r->eap_count * 3 > f_end) {
    291 		wpa_printf(MSG_DEBUG, "No room for EAP Methods");
    292 		return NULL;
    293 	}
    294 	r->eap = os_zalloc(r->eap_count * sizeof(struct nai_realm_eap));
    295 	if (r->eap == NULL)
    296 		return NULL;
    297 
    298 	for (e = 0; e < r->eap_count; e++) {
    299 		pos = nai_realm_parse_eap(&r->eap[e], pos, f_end);
    300 		if (pos == NULL)
    301 			return NULL;
    302 	}
    303 
    304 	return f_end;
    305 }
    306 
    307 
    308 static struct nai_realm * nai_realm_parse(struct wpabuf *anqp, u16 *count)
    309 {
    310 	struct nai_realm *realm;
    311 	const u8 *pos, *end;
    312 	u16 i, num;
    313 
    314 	if (anqp == NULL || wpabuf_len(anqp) < 2)
    315 		return NULL;
    316 
    317 	pos = wpabuf_head_u8(anqp);
    318 	end = pos + wpabuf_len(anqp);
    319 	num = WPA_GET_LE16(pos);
    320 	wpa_printf(MSG_DEBUG, "NAI Realm Count: %u", num);
    321 	pos += 2;
    322 
    323 	if (num * 5 > end - pos) {
    324 		wpa_printf(MSG_DEBUG, "Invalid NAI Realm Count %u - not "
    325 			   "enough data (%u octets) for that many realms",
    326 			   num, (unsigned int) (end - pos));
    327 		return NULL;
    328 	}
    329 
    330 	realm = os_zalloc(num * sizeof(struct nai_realm));
    331 	if (realm == NULL)
    332 		return NULL;
    333 
    334 	for (i = 0; i < num; i++) {
    335 		pos = nai_realm_parse_realm(&realm[i], pos, end);
    336 		if (pos == NULL) {
    337 			nai_realm_free(realm, num);
    338 			return NULL;
    339 		}
    340 	}
    341 
    342 	*count = num;
    343 	return realm;
    344 }
    345 
    346 
    347 static int nai_realm_match(struct nai_realm *realm, const char *home_realm)
    348 {
    349 	char *tmp, *pos, *end;
    350 	int match = 0;
    351 
    352 	if (realm->realm == NULL || home_realm == NULL)
    353 		return 0;
    354 
    355 	if (os_strchr(realm->realm, ';') == NULL)
    356 		return os_strcasecmp(realm->realm, home_realm) == 0;
    357 
    358 	tmp = os_strdup(realm->realm);
    359 	if (tmp == NULL)
    360 		return 0;
    361 
    362 	pos = tmp;
    363 	while (*pos) {
    364 		end = os_strchr(pos, ';');
    365 		if (end)
    366 			*end = '\0';
    367 		if (os_strcasecmp(pos, home_realm) == 0) {
    368 			match = 1;
    369 			break;
    370 		}
    371 		if (end == NULL)
    372 			break;
    373 		pos = end + 1;
    374 	}
    375 
    376 	os_free(tmp);
    377 
    378 	return match;
    379 }
    380 
    381 
    382 static int nai_realm_cred_username(struct nai_realm_eap *eap)
    383 {
    384 	if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL)
    385 		return 0; /* method not supported */
    386 
    387 	if (eap->method != EAP_TYPE_TTLS && eap->method != EAP_TYPE_PEAP) {
    388 		/* Only tunneled methods with username/password supported */
    389 		return 0;
    390 	}
    391 
    392 	if (eap->method == EAP_TYPE_PEAP &&
    393 	    eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL)
    394 		return 0;
    395 
    396 	if (eap->method == EAP_TYPE_TTLS) {
    397 		if (eap->inner_method == 0 && eap->inner_non_eap == 0)
    398 			return 0;
    399 		if (eap->inner_method &&
    400 		    eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL)
    401 			return 0;
    402 		if (eap->inner_non_eap &&
    403 		    eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_PAP &&
    404 		    eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_CHAP &&
    405 		    eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAP &&
    406 		    eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAPV2)
    407 			return 0;
    408 	}
    409 
    410 	if (eap->inner_method &&
    411 	    eap->inner_method != EAP_TYPE_GTC &&
    412 	    eap->inner_method != EAP_TYPE_MSCHAPV2)
    413 		return 0;
    414 
    415 	return 1;
    416 }
    417 
    418 
    419 static struct nai_realm_eap * nai_realm_find_eap(struct wpa_supplicant *wpa_s,
    420 						 struct nai_realm *realm)
    421 {
    422 	u8 e;
    423 
    424 	if (wpa_s->conf->home_username == NULL ||
    425 	    wpa_s->conf->home_username[0] == '\0' ||
    426 	    wpa_s->conf->home_password == NULL ||
    427 	    wpa_s->conf->home_password[0] == '\0')
    428 		return NULL;
    429 
    430 	for (e = 0; e < realm->eap_count; e++) {
    431 		struct nai_realm_eap *eap = &realm->eap[e];
    432 		if (nai_realm_cred_username(eap))
    433 			return eap;
    434 	}
    435 
    436 	return NULL;
    437 }
    438 
    439 
    440 #ifdef INTERWORKING_3GPP
    441 
    442 static int plmn_id_match(struct wpabuf *anqp, const char *imsi)
    443 {
    444 	const char *sep;
    445 	u8 plmn[3];
    446 	const u8 *pos, *end;
    447 	u8 udhl;
    448 
    449 	sep = os_strchr(imsi, '-');
    450 	if (sep == NULL || (sep - imsi != 5 && sep - imsi != 6))
    451 		return 0;
    452 
    453 	/* See Annex A of 3GPP TS 24.234 v8.1.0 for description */
    454 	plmn[0] = (imsi[0] - '0') | ((imsi[1] - '0') << 4);
    455 	plmn[1] = imsi[2] - '0';
    456 	if (sep - imsi == 6)
    457 		plmn[1] |= (imsi[5] - '0') << 4;
    458 	else
    459 		plmn[1] |= 0xf0;
    460 	plmn[2] = (imsi[3] - '0') | ((imsi[4] - '0') << 4);
    461 
    462 	if (anqp == NULL)
    463 		return 0;
    464 	pos = wpabuf_head_u8(anqp);
    465 	end = pos + wpabuf_len(anqp);
    466 	if (pos + 2 > end)
    467 		return 0;
    468 	if (*pos != 0) {
    469 		wpa_printf(MSG_DEBUG, "Unsupported GUD version 0x%x", *pos);
    470 		return 0;
    471 	}
    472 	pos++;
    473 	udhl = *pos++;
    474 	if (pos + udhl > end) {
    475 		wpa_printf(MSG_DEBUG, "Invalid UDHL");
    476 		return 0;
    477 	}
    478 	end = pos + udhl;
    479 
    480 	while (pos + 2 <= end) {
    481 		u8 iei, len;
    482 		const u8 *l_end;
    483 		iei = *pos++;
    484 		len = *pos++ & 0x7f;
    485 		if (pos + len > end)
    486 			break;
    487 		l_end = pos + len;
    488 
    489 		if (iei == 0 && len > 0) {
    490 			/* PLMN List */
    491 			u8 num, i;
    492 			num = *pos++;
    493 			for (i = 0; i < num; i++) {
    494 				if (pos + 3 > end)
    495 					break;
    496 				if (os_memcmp(pos, plmn, 3) == 0)
    497 					return 1; /* Found matching PLMN */
    498 			}
    499 		}
    500 
    501 		pos = l_end;
    502 	}
    503 
    504 	return 0;
    505 }
    506 
    507 
    508 static int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix)
    509 {
    510 	const char *sep, *msin;
    511 	char nai[100], *end, *pos;
    512 	size_t msin_len, plmn_len;
    513 
    514 	/*
    515 	 * TS 23.003, Clause 14 (3GPP to WLAN Interworking)
    516 	 * Root NAI:
    517 	 * <aka:0|sim:1><IMSI>@wlan.mnc<MNC>.mcc<MCC>.3gppnetwork.org
    518 	 * <MNC> is zero-padded to three digits in case two-digit MNC is used
    519 	 */
    520 
    521 	if (imsi == NULL || os_strlen(imsi) > 16) {
    522 		wpa_printf(MSG_DEBUG, "No valid IMSI available");
    523 		return -1;
    524 	}
    525 	sep = os_strchr(imsi, '-');
    526 	if (sep == NULL)
    527 		return -1;
    528 	plmn_len = sep - imsi;
    529 	if (plmn_len != 5 && plmn_len != 6)
    530 		return -1;
    531 	msin = sep + 1;
    532 	msin_len = os_strlen(msin);
    533 
    534 	pos = nai;
    535 	end = pos + sizeof(nai);
    536 	*pos++ = prefix;
    537 	os_memcpy(pos, imsi, plmn_len);
    538 	pos += plmn_len;
    539 	os_memcpy(pos, msin, msin_len);
    540 	pos += msin_len;
    541 	pos += os_snprintf(pos, end - pos, "@wlan.mnc");
    542 	if (plmn_len == 5) {
    543 		*pos++ = '0';
    544 		*pos++ = imsi[3];
    545 		*pos++ = imsi[4];
    546 	} else {
    547 		*pos++ = imsi[3];
    548 		*pos++ = imsi[4];
    549 		*pos++ = imsi[5];
    550 	}
    551 	pos += os_snprintf(pos, end - pos, ".mcc%c%c%c.3gppnetwork.org",
    552 			   imsi[0], imsi[1], imsi[2]);
    553 
    554 	return wpa_config_set_quoted(ssid, "identity", nai);
    555 }
    556 
    557 #endif /* INTERWORKING_3GPP */
    558 
    559 
    560 static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
    561 				     struct wpa_bss *bss)
    562 {
    563 #ifdef INTERWORKING_3GPP
    564 	struct wpa_ssid *ssid;
    565 	const u8 *ie;
    566 
    567 	ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
    568 	if (ie == NULL)
    569 		return -1;
    570 	wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " (3GPP)",
    571 		   MAC2STR(bss->bssid));
    572 
    573 	ssid = wpa_config_add_network(wpa_s->conf);
    574 	if (ssid == NULL)
    575 		return -1;
    576 
    577 	wpas_notify_network_added(wpa_s, ssid);
    578 	wpa_config_set_network_defaults(ssid);
    579 	ssid->temporary = 1;
    580 	ssid->ssid = os_zalloc(ie[1] + 1);
    581 	if (ssid->ssid == NULL)
    582 		goto fail;
    583 	os_memcpy(ssid->ssid, ie + 2, ie[1]);
    584 	ssid->ssid_len = ie[1];
    585 
    586 	/* TODO: figure out whether to use EAP-SIM, EAP-AKA, or EAP-AKA' */
    587 	if (wpa_config_set(ssid, "eap", "SIM", 0) < 0) {
    588 		wpa_printf(MSG_DEBUG, "EAP-SIM not supported");
    589 		goto fail;
    590 	}
    591 	if (set_root_nai(ssid, wpa_s->conf->home_imsi, '1') < 0) {
    592 		wpa_printf(MSG_DEBUG, "Failed to set Root NAI");
    593 		goto fail;
    594 	}
    595 
    596 	if (wpa_s->conf->home_milenage && wpa_s->conf->home_milenage[0]) {
    597 		if (wpa_config_set_quoted(ssid, "password",
    598 					  wpa_s->conf->home_milenage) < 0)
    599 			goto fail;
    600 	} else {
    601 		/* TODO: PIN */
    602 		if (wpa_config_set_quoted(ssid, "pcsc", "") < 0)
    603 			goto fail;
    604 	}
    605 
    606 	if (wpa_s->conf->home_password && wpa_s->conf->home_password[0] &&
    607 	    wpa_config_set_quoted(ssid, "password", wpa_s->conf->home_password)
    608 	    < 0)
    609 		goto fail;
    610 
    611 	wpa_supplicant_select_network(wpa_s, ssid);
    612 
    613 	return 0;
    614 
    615 fail:
    616 	wpas_notify_network_removed(wpa_s, ssid);
    617 	wpa_config_remove_network(wpa_s->conf, ssid->id);
    618 #endif /* INTERWORKING_3GPP */
    619 	return -1;
    620 }
    621 
    622 
    623 int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
    624 {
    625 	struct wpa_ssid *ssid;
    626 	struct nai_realm *realm;
    627 	struct nai_realm_eap *eap = NULL;
    628 	u16 count, i;
    629 	char buf[100];
    630 	const u8 *ie;
    631 
    632 	if (bss == NULL)
    633 		return -1;
    634 	ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
    635 	if (ie == NULL || ie[1] == 0) {
    636 		wpa_printf(MSG_DEBUG, "Interworking: No SSID known for "
    637 			   MACSTR, MAC2STR(bss->bssid));
    638 		return -1;
    639 	}
    640 
    641 	realm = nai_realm_parse(bss->anqp_nai_realm, &count);
    642 	if (realm == NULL) {
    643 		wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
    644 			   "Realm list from " MACSTR, MAC2STR(bss->bssid));
    645 		count = 0;
    646 	}
    647 
    648 	for (i = 0; i < count; i++) {
    649 		if (!nai_realm_match(&realm[i], wpa_s->conf->home_realm))
    650 			continue;
    651 		eap = nai_realm_find_eap(wpa_s, &realm[i]);
    652 		if (eap)
    653 			break;
    654 	}
    655 
    656 	if (!eap) {
    657 		if (interworking_connect_3gpp(wpa_s, bss) == 0) {
    658 			if (realm)
    659 				nai_realm_free(realm, count);
    660 			return 0;
    661 		}
    662 
    663 		wpa_printf(MSG_DEBUG, "Interworking: No matching credentials "
    664 			   "and EAP method found for " MACSTR,
    665 			   MAC2STR(bss->bssid));
    666 		nai_realm_free(realm, count);
    667 		return -1;
    668 	}
    669 
    670 	wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR,
    671 		   MAC2STR(bss->bssid));
    672 
    673 	ssid = wpa_config_add_network(wpa_s->conf);
    674 	if (ssid == NULL) {
    675 		nai_realm_free(realm, count);
    676 		return -1;
    677 	}
    678 	wpas_notify_network_added(wpa_s, ssid);
    679 	wpa_config_set_network_defaults(ssid);
    680 	ssid->temporary = 1;
    681 	ssid->ssid = os_zalloc(ie[1] + 1);
    682 	if (ssid->ssid == NULL)
    683 		goto fail;
    684 	os_memcpy(ssid->ssid, ie + 2, ie[1]);
    685 	ssid->ssid_len = ie[1];
    686 
    687 	if (wpa_config_set(ssid, "eap", eap_get_name(EAP_VENDOR_IETF,
    688 						     eap->method), 0) < 0)
    689 		goto fail;
    690 
    691 	if (wpa_s->conf->home_username && wpa_s->conf->home_username[0] &&
    692 	    wpa_config_set_quoted(ssid, "identity",
    693 				  wpa_s->conf->home_username) < 0)
    694 		goto fail;
    695 
    696 	if (wpa_s->conf->home_password && wpa_s->conf->home_password[0] &&
    697 	    wpa_config_set_quoted(ssid, "password", wpa_s->conf->home_password)
    698 	    < 0)
    699 		goto fail;
    700 
    701 	switch (eap->method) {
    702 	case EAP_TYPE_TTLS:
    703 		if (eap->inner_method) {
    704 			os_snprintf(buf, sizeof(buf), "\"autheap=%s\"",
    705 				    eap_get_name(EAP_VENDOR_IETF,
    706 						 eap->inner_method));
    707 			if (wpa_config_set(ssid, "phase2", buf, 0) < 0)
    708 				goto fail;
    709 			break;
    710 		}
    711 		switch (eap->inner_non_eap) {
    712 		case NAI_REALM_INNER_NON_EAP_PAP:
    713 			if (wpa_config_set(ssid, "phase2", "\"auth=PAP\"", 0) <
    714 			    0)
    715 				goto fail;
    716 			break;
    717 		case NAI_REALM_INNER_NON_EAP_CHAP:
    718 			if (wpa_config_set(ssid, "phase2", "\"auth=CHAP\"", 0)
    719 			    < 0)
    720 				goto fail;
    721 			break;
    722 		case NAI_REALM_INNER_NON_EAP_MSCHAP:
    723 			if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAP\"",
    724 					   0) < 0)
    725 				goto fail;
    726 			break;
    727 		case NAI_REALM_INNER_NON_EAP_MSCHAPV2:
    728 			if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAPV2\"",
    729 					   0) < 0)
    730 				goto fail;
    731 			break;
    732 		}
    733 		break;
    734 	case EAP_TYPE_PEAP:
    735 		os_snprintf(buf, sizeof(buf), "\"auth=%s\"",
    736 			    eap_get_name(EAP_VENDOR_IETF, eap->inner_method));
    737 		if (wpa_config_set(ssid, "phase2", buf, 0) < 0)
    738 			goto fail;
    739 		break;
    740 	}
    741 
    742 	if (wpa_s->conf->home_ca_cert && wpa_s->conf->home_ca_cert[0] &&
    743 	    wpa_config_set_quoted(ssid, "ca_cert", wpa_s->conf->home_ca_cert) <
    744 	    0)
    745 		goto fail;
    746 
    747 	nai_realm_free(realm, count);
    748 
    749 	wpa_supplicant_select_network(wpa_s, ssid);
    750 
    751 	return 0;
    752 
    753 fail:
    754 	wpas_notify_network_removed(wpa_s, ssid);
    755 	wpa_config_remove_network(wpa_s->conf, ssid->id);
    756 	nai_realm_free(realm, count);
    757 	return -1;
    758 }
    759 
    760 
    761 static int interworking_credentials_available_3gpp(
    762 	struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
    763 {
    764 	int ret = 0;
    765 
    766 #ifdef INTERWORKING_3GPP
    767 	if (bss->anqp_3gpp == NULL)
    768 		return ret;
    769 
    770 	if (wpa_s->conf->home_imsi == NULL || !wpa_s->conf->home_imsi[0] ||
    771 	    wpa_s->conf->home_milenage == NULL ||
    772 	    !wpa_s->conf->home_milenage[0])
    773 		return ret;
    774 
    775 	wpa_printf(MSG_DEBUG, "Interworking: Parsing 3GPP info from " MACSTR,
    776 		   MAC2STR(bss->bssid));
    777 	ret = plmn_id_match(bss->anqp_3gpp, wpa_s->conf->home_imsi);
    778 	wpa_printf(MSG_DEBUG, "PLMN match %sfound", ret ? "" : "not ");
    779 #endif /* INTERWORKING_3GPP */
    780 	return ret;
    781 }
    782 
    783 
    784 static int interworking_credentials_available_realm(
    785 	struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
    786 {
    787 	struct nai_realm *realm;
    788 	u16 count, i;
    789 	int found = 0;
    790 
    791 	if (bss->anqp_nai_realm == NULL)
    792 		return 0;
    793 
    794 	if (wpa_s->conf->home_realm == NULL)
    795 		return 0;
    796 
    797 	wpa_printf(MSG_DEBUG, "Interworking: Parsing NAI Realm list from "
    798 		   MACSTR, MAC2STR(bss->bssid));
    799 	realm = nai_realm_parse(bss->anqp_nai_realm, &count);
    800 	if (realm == NULL) {
    801 		wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
    802 			   "Realm list from " MACSTR, MAC2STR(bss->bssid));
    803 		return 0;
    804 	}
    805 
    806 	for (i = 0; i < count; i++) {
    807 		if (!nai_realm_match(&realm[i], wpa_s->conf->home_realm))
    808 			continue;
    809 		if (nai_realm_find_eap(wpa_s, &realm[i])) {
    810 			found++;
    811 			break;
    812 		}
    813 	}
    814 
    815 	nai_realm_free(realm, count);
    816 
    817 	return found;
    818 }
    819 
    820 
    821 static int interworking_credentials_available(struct wpa_supplicant *wpa_s,
    822 					      struct wpa_bss *bss)
    823 {
    824 	return interworking_credentials_available_realm(wpa_s, bss) ||
    825 		interworking_credentials_available_3gpp(wpa_s, bss);
    826 }
    827 
    828 
    829 static void interworking_select_network(struct wpa_supplicant *wpa_s)
    830 {
    831 	struct wpa_bss *bss, *selected = NULL;
    832 	unsigned int count = 0;
    833 
    834 	wpa_s->network_select = 0;
    835 
    836 	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
    837 		if (!interworking_credentials_available(wpa_s, bss))
    838 			continue;
    839 		count++;
    840 		wpa_msg(wpa_s, MSG_INFO, INTERWORKING_AP MACSTR,
    841 			MAC2STR(bss->bssid));
    842 		if (selected == NULL && wpa_s->auto_select)
    843 			selected = bss;
    844 	}
    845 
    846 	if (count == 0) {
    847 		wpa_msg(wpa_s, MSG_INFO, INTERWORKING_NO_MATCH "No network "
    848 			"with matching credentials found");
    849 	}
    850 
    851 	if (selected)
    852 		interworking_connect(wpa_s, selected);
    853 }
    854 
    855 
    856 static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
    857 {
    858 	struct wpa_bss *bss;
    859 	int found = 0;
    860 	const u8 *ie;
    861 
    862 	if (!wpa_s->fetch_anqp_in_progress)
    863 		return;
    864 
    865 	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
    866 		if (!(bss->caps & IEEE80211_CAP_ESS))
    867 			continue;
    868 		ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB);
    869 		if (ie == NULL || ie[1] < 4 || !(ie[5] & 0x80))
    870 			continue; /* AP does not support Interworking */
    871 
    872 		if (!(bss->flags & WPA_BSS_ANQP_FETCH_TRIED)) {
    873 			found++;
    874 			bss->flags |= WPA_BSS_ANQP_FETCH_TRIED;
    875 			wpa_msg(wpa_s, MSG_INFO, "Starting ANQP fetch for "
    876 				MACSTR, MAC2STR(bss->bssid));
    877 			interworking_anqp_send_req(wpa_s, bss);
    878 			break;
    879 		}
    880 	}
    881 
    882 	if (found == 0) {
    883 		wpa_msg(wpa_s, MSG_INFO, "ANQP fetch completed");
    884 		wpa_s->fetch_anqp_in_progress = 0;
    885 		if (wpa_s->network_select)
    886 			interworking_select_network(wpa_s);
    887 	}
    888 }
    889 
    890 
    891 static void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s)
    892 {
    893 	struct wpa_bss *bss;
    894 
    895 	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list)
    896 		bss->flags &= ~WPA_BSS_ANQP_FETCH_TRIED;
    897 
    898 	wpa_s->fetch_anqp_in_progress = 1;
    899 	interworking_next_anqp_fetch(wpa_s);
    900 }
    901 
    902 
    903 int interworking_fetch_anqp(struct wpa_supplicant *wpa_s)
    904 {
    905 	if (wpa_s->fetch_anqp_in_progress || wpa_s->network_select)
    906 		return 0;
    907 
    908 	wpa_s->network_select = 0;
    909 
    910 	interworking_start_fetch_anqp(wpa_s);
    911 
    912 	return 0;
    913 }
    914 
    915 
    916 void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s)
    917 {
    918 	if (!wpa_s->fetch_anqp_in_progress)
    919 		return;
    920 
    921 	wpa_s->fetch_anqp_in_progress = 0;
    922 }
    923 
    924 
    925 int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
    926 		  u16 info_ids[], size_t num_ids)
    927 {
    928 	struct wpabuf *buf;
    929 	int ret = 0;
    930 	int freq;
    931 	struct wpa_bss *bss;
    932 	int res;
    933 
    934 	freq = wpa_s->assoc_freq;
    935 	bss = wpa_bss_get_bssid(wpa_s, dst);
    936 	if (bss)
    937 		freq = bss->freq;
    938 	if (freq <= 0)
    939 		return -1;
    940 
    941 	wpa_printf(MSG_DEBUG, "ANQP: Query Request to " MACSTR " for %u id(s)",
    942 		   MAC2STR(dst), (unsigned int) num_ids);
    943 
    944 	buf = anqp_build_req(info_ids, num_ids, NULL);
    945 	if (buf == NULL)
    946 		return -1;
    947 
    948 	res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
    949 	if (res < 0) {
    950 		wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
    951 		ret = -1;
    952 	} else
    953 		wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
    954 			   "%u", res);
    955 
    956 	wpabuf_free(buf);
    957 	return ret;
    958 }
    959 
    960 
    961 static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
    962 					    const u8 *sa, u16 info_id,
    963 					    const u8 *data, size_t slen)
    964 {
    965 	const u8 *pos = data;
    966 	struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa);
    967 
    968 	switch (info_id) {
    969 	case ANQP_CAPABILITY_LIST:
    970 		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
    971 			" ANQP Capability list", MAC2STR(sa));
    972 		break;
    973 	case ANQP_VENUE_NAME:
    974 		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
    975 			" Venue Name", MAC2STR(sa));
    976 		wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Venue Name", pos, slen);
    977 		if (bss) {
    978 			wpabuf_free(bss->anqp_venue_name);
    979 			bss->anqp_venue_name = wpabuf_alloc_copy(pos, slen);
    980 		}
    981 		break;
    982 	case ANQP_NETWORK_AUTH_TYPE:
    983 		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
    984 			" Network Authentication Type information",
    985 			MAC2STR(sa));
    986 		wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Network Authentication "
    987 				  "Type", pos, slen);
    988 		if (bss) {
    989 			wpabuf_free(bss->anqp_network_auth_type);
    990 			bss->anqp_network_auth_type =
    991 				wpabuf_alloc_copy(pos, slen);
    992 		}
    993 		break;
    994 	case ANQP_ROAMING_CONSORTIUM:
    995 		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
    996 			" Roaming Consortium list", MAC2STR(sa));
    997 		wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Roaming Consortium",
    998 				  pos, slen);
    999 		if (bss) {
   1000 			wpabuf_free(bss->anqp_roaming_consortium);
   1001 			bss->anqp_roaming_consortium =
   1002 				wpabuf_alloc_copy(pos, slen);
   1003 		}
   1004 		break;
   1005 	case ANQP_IP_ADDR_TYPE_AVAILABILITY:
   1006 		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
   1007 			" IP Address Type Availability information",
   1008 			MAC2STR(sa));
   1009 		wpa_hexdump(MSG_MSGDUMP, "ANQP: IP Address Availability",
   1010 			    pos, slen);
   1011 		if (bss) {
   1012 			wpabuf_free(bss->anqp_ip_addr_type_availability);
   1013 			bss->anqp_ip_addr_type_availability =
   1014 				wpabuf_alloc_copy(pos, slen);
   1015 		}
   1016 		break;
   1017 	case ANQP_NAI_REALM:
   1018 		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
   1019 			" NAI Realm list", MAC2STR(sa));
   1020 		wpa_hexdump_ascii(MSG_DEBUG, "ANQP: NAI Realm", pos, slen);
   1021 		if (bss) {
   1022 			wpabuf_free(bss->anqp_nai_realm);
   1023 			bss->anqp_nai_realm = wpabuf_alloc_copy(pos, slen);
   1024 		}
   1025 		break;
   1026 	case ANQP_3GPP_CELLULAR_NETWORK:
   1027 		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
   1028 			" 3GPP Cellular Network information", MAC2STR(sa));
   1029 		wpa_hexdump_ascii(MSG_DEBUG, "ANQP: 3GPP Cellular Network",
   1030 				  pos, slen);
   1031 		if (bss) {
   1032 			wpabuf_free(bss->anqp_3gpp);
   1033 			bss->anqp_3gpp = wpabuf_alloc_copy(pos, slen);
   1034 		}
   1035 		break;
   1036 	case ANQP_DOMAIN_NAME:
   1037 		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
   1038 			" Domain Name list", MAC2STR(sa));
   1039 		wpa_hexdump_ascii(MSG_MSGDUMP, "ANQP: Domain Name", pos, slen);
   1040 		if (bss) {
   1041 			wpabuf_free(bss->anqp_domain_name);
   1042 			bss->anqp_domain_name = wpabuf_alloc_copy(pos, slen);
   1043 		}
   1044 		break;
   1045 	case ANQP_VENDOR_SPECIFIC:
   1046 		if (slen < 3)
   1047 			return;
   1048 
   1049 		switch (WPA_GET_BE24(pos)) {
   1050 		default:
   1051 			wpa_printf(MSG_DEBUG, "Interworking: Unsupported "
   1052 				   "vendor-specific ANQP OUI %06x",
   1053 				   WPA_GET_BE24(pos));
   1054 			return;
   1055 		}
   1056 		break;
   1057 	default:
   1058 		wpa_printf(MSG_DEBUG, "Interworking: Unsupported ANQP Info ID "
   1059 			   "%u", info_id);
   1060 		break;
   1061 	}
   1062 }
   1063 
   1064 
   1065 void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
   1066 		  enum gas_query_result result,
   1067 		  const struct wpabuf *adv_proto,
   1068 		  const struct wpabuf *resp, u16 status_code)
   1069 {
   1070 	struct wpa_supplicant *wpa_s = ctx;
   1071 	const u8 *pos;
   1072 	const u8 *end;
   1073 	u16 info_id;
   1074 	u16 slen;
   1075 
   1076 	if (result != GAS_QUERY_SUCCESS)
   1077 		return;
   1078 
   1079 	pos = wpabuf_head(adv_proto);
   1080 	if (wpabuf_len(adv_proto) < 4 || pos[0] != WLAN_EID_ADV_PROTO ||
   1081 	    pos[1] < 2 || pos[3] != ACCESS_NETWORK_QUERY_PROTOCOL) {
   1082 		wpa_printf(MSG_DEBUG, "ANQP: Unexpected Advertisement "
   1083 			   "Protocol in response");
   1084 		return;
   1085 	}
   1086 
   1087 	pos = wpabuf_head(resp);
   1088 	end = pos + wpabuf_len(resp);
   1089 
   1090 	while (pos < end) {
   1091 		if (pos + 4 > end) {
   1092 			wpa_printf(MSG_DEBUG, "ANQP: Invalid element");
   1093 			break;
   1094 		}
   1095 		info_id = WPA_GET_LE16(pos);
   1096 		pos += 2;
   1097 		slen = WPA_GET_LE16(pos);
   1098 		pos += 2;
   1099 		if (pos + slen > end) {
   1100 			wpa_printf(MSG_DEBUG, "ANQP: Invalid element length "
   1101 				   "for Info ID %u", info_id);
   1102 			break;
   1103 		}
   1104 		interworking_parse_rx_anqp_resp(wpa_s, dst, info_id, pos,
   1105 						slen);
   1106 		pos += slen;
   1107 	}
   1108 }
   1109 
   1110 
   1111 static void interworking_scan_res_handler(struct wpa_supplicant *wpa_s,
   1112 					  struct wpa_scan_results *scan_res)
   1113 {
   1114 	wpa_printf(MSG_DEBUG, "Interworking: Scan results available - start "
   1115 		   "ANQP fetch");
   1116 	interworking_start_fetch_anqp(wpa_s);
   1117 }
   1118 
   1119 
   1120 int interworking_select(struct wpa_supplicant *wpa_s, int auto_select)
   1121 {
   1122 	interworking_stop_fetch_anqp(wpa_s);
   1123 	wpa_s->network_select = 1;
   1124 	wpa_s->auto_select = !!auto_select;
   1125 	wpa_printf(MSG_DEBUG, "Interworking: Start scan for network "
   1126 		   "selection");
   1127 	wpa_s->scan_res_handler = interworking_scan_res_handler;
   1128 	wpa_s->scan_req = 2;
   1129 	wpa_supplicant_req_scan(wpa_s, 0, 0);
   1130 
   1131 	return 0;
   1132 }
   1133