11f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt/*
21f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * Interworking (IEEE 802.11u)
35460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt * Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
4fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt * Copyright (c) 2011-2014, Jouni Malinen <j@w1.fi>
51f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt *
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
7c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details.
81f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt */
91f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "includes.h"
111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "common.h"
131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "common/ieee802_11_defs.h"
141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "common/gas.h"
151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "common/wpa_ctrl.h"
1604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "utils/pcsc_funcs.h"
17a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt#include "utils/eloop.h"
181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "drivers/driver.h"
191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "eap_common/eap_defs.h"
2061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include "eap_peer/eap.h"
211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "eap_peer/eap_methods.h"
22b96dad47218788efffa3db0fe7f1b54a7d19e366Dmitry Shmidt#include "eapol_supp/eapol_supp_sm.h"
235460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt#include "rsn_supp/wpa.h"
241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "wpa_supplicant_i.h"
251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "config.h"
2604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "config_ssid.h"
271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "bss.h"
281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "scan.h"
291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "notify.h"
305a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt#include "driver_i.h"
311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "gas_query.h"
3204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "hs20_supplicant.h"
331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "interworking.h"
341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#if defined(EAP_SIM) | defined(EAP_SIM_DYNAMIC)
371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#define INTERWORKING_3GPP
381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#else
391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#if defined(EAP_AKA) | defined(EAP_AKA_DYNAMIC)
401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#define INTERWORKING_3GPP
411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#else
421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#if defined(EAP_AKA_PRIME) | defined(EAP_AKA_PRIME_DYNAMIC)
431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#define INTERWORKING_3GPP
441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif
451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif
461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif
471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s);
49f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtstatic struct wpa_cred * interworking_credentials_available_realm(
50f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int ignore_bw,
51f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	int *excluded);
52f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtstatic struct wpa_cred * interworking_credentials_available_3gpp(
53f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int ignore_bw,
54f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	int *excluded);
55f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
56f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
57f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtstatic int cred_prio_cmp(const struct wpa_cred *a, const struct wpa_cred *b)
58f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{
59f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (a->priority > b->priority)
60f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		return 1;
61f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (a->priority < b->priority)
62f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		return -1;
63f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (a->provisioning_sp == NULL || b->provisioning_sp == NULL ||
64f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	    os_strcmp(a->provisioning_sp, b->provisioning_sp) != 0)
65f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		return 0;
66f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (a->sp_priority < b->sp_priority)
67f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		return 1;
68f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (a->sp_priority > b->sp_priority)
69f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		return -1;
70f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	return 0;
71f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt}
721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
7404949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void interworking_reconnect(struct wpa_supplicant *wpa_s)
7504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
7604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
7704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpa_supplicant_cancel_sched_scan(wpa_s);
7804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpa_supplicant_deauthenticate(wpa_s,
7904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt					      WLAN_REASON_DEAUTH_LEAVING);
8004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
8104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	wpa_s->disconnected = 0;
8204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	wpa_s->reassociate = 1;
834530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
844b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	if (wpa_supplicant_fast_associate(wpa_s) >= 0)
854b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt		return;
864530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
8704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	wpa_supplicant_req_scan(wpa_s, 0, 0);
8804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
8904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
9004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic struct wpabuf * anqp_build_req(u16 info_ids[], size_t num_ids,
921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				      struct wpabuf *extra)
931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpabuf *buf;
951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	size_t i;
961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u8 *len_pos;
971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	buf = gas_anqp_build_initial_req(0, 4 + num_ids * 2 +
991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					 (extra ? wpabuf_len(extra) : 0));
1001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (buf == NULL)
1011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
1021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	len_pos = gas_anqp_add_element(buf, ANQP_QUERY_LIST);
1041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	for (i = 0; i < num_ids; i++)
1051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpabuf_put_le16(buf, info_ids[i]);
1061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	gas_anqp_set_element_len(buf, len_pos);
1071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (extra)
1081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpabuf_put_buf(buf, extra);
1091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	gas_anqp_set_len(buf);
1111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return buf;
1131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
1141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void interworking_anqp_resp_cb(void *ctx, const u8 *dst,
1171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				      u8 dialog_token,
1181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				      enum gas_query_result result,
1191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				      const struct wpabuf *adv_proto,
1201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				      const struct wpabuf *resp,
1211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				      u16 status_code)
1221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
1231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_supplicant *wpa_s = ctx;
1241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
125f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	wpa_printf(MSG_DEBUG, "ANQP: Response callback dst=" MACSTR
126f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		   " dialog_token=%u result=%d status_code=%u",
127f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		   MAC2STR(dst), dialog_token, result, status_code);
1281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	anqp_resp_cb(wpa_s, dst, dialog_token, result, adv_proto, resp,
1291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		     status_code);
1301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	interworking_next_anqp_fetch(wpa_s);
1311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
1321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1344530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidtstatic int cred_with_roaming_consortium(struct wpa_supplicant *wpa_s)
1354530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt{
1364530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	struct wpa_cred *cred;
1374530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
1384530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
1394530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		if (cred->roaming_consortium_len)
1404530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			return 1;
141051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (cred->required_roaming_consortium_len)
142051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			return 1;
1434530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	}
1444530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	return 0;
1454530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt}
1464530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
1474530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
1484530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidtstatic int cred_with_3gpp(struct wpa_supplicant *wpa_s)
1494530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt{
1504530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	struct wpa_cred *cred;
1514530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
1524530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
1534530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		if (cred->pcsc || cred->imsi)
1544530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			return 1;
1554530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	}
1564530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	return 0;
1574530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt}
1584530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
1594530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
1604530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidtstatic int cred_with_nai_realm(struct wpa_supplicant *wpa_s)
1614530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt{
1624530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	struct wpa_cred *cred;
1634530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
1644530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
1654530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		if (cred->pcsc || cred->imsi)
1664530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			continue;
1674530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		if (!cred->eap_method)
1684530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			return 1;
1694530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		if (cred->realm && cred->roaming_consortium_len == 0)
1704530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			return 1;
1714530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	}
1724530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	return 0;
1734530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt}
1744530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
1754530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
1764530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidtstatic int cred_with_domain(struct wpa_supplicant *wpa_s)
1774530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt{
1784530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	struct wpa_cred *cred;
1794530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
1804530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
181f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (cred->domain || cred->pcsc || cred->imsi ||
182f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		    cred->roaming_partner)
183f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			return 1;
184f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	}
185f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	return 0;
186f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt}
187f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
188f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
189f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#ifdef CONFIG_HS20
190f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
191f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtstatic int cred_with_min_backhaul(struct wpa_supplicant *wpa_s)
192f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{
193f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	struct wpa_cred *cred;
194f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
195f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
196f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (cred->min_dl_bandwidth_home ||
197f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		    cred->min_ul_bandwidth_home ||
198f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		    cred->min_dl_bandwidth_roaming ||
199f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		    cred->min_ul_bandwidth_roaming)
2004530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			return 1;
2014530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	}
2024530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	return 0;
2034530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt}
2044530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
2054530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
206f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtstatic int cred_with_conn_capab(struct wpa_supplicant *wpa_s)
207f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{
208f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	struct wpa_cred *cred;
209f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
210f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
211f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (cred->num_req_conn_capab)
212f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			return 1;
213f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	}
214f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	return 0;
215f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt}
216f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
217f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#endif /* CONFIG_HS20 */
218f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
219f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
2204530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidtstatic int additional_roaming_consortiums(struct wpa_bss *bss)
2214530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt{
2224530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	const u8 *ie;
2234530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
2244530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (ie == NULL || ie[1] == 0)
2254530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		return 0;
2264530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	return ie[2]; /* Number of ANQP OIs */
2274530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt}
2284530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
2294530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
230a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtstatic void interworking_continue_anqp(void *eloop_ctx, void *sock_ctx)
231a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{
232a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	struct wpa_supplicant *wpa_s = eloop_ctx;
233a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	interworking_next_anqp_fetch(wpa_s);
234a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt}
235a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
236a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
2371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int interworking_anqp_send_req(struct wpa_supplicant *wpa_s,
2381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				      struct wpa_bss *bss)
2391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
2401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpabuf *buf;
2411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int ret = 0;
2421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int res;
2434530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	u16 info_ids[8];
2444530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	size_t num_info_ids = 0;
2451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpabuf *extra = NULL;
2464530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	int all = wpa_s->fetch_all_anqp;
2471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_printf(MSG_DEBUG, "Interworking: ANQP Query Request to " MACSTR,
2491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		   MAC2STR(bss->bssid));
250444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	wpa_s->interworking_gas_bss = bss;
2511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2524530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	info_ids[num_info_ids++] = ANQP_CAPABILITY_LIST;
2534530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (all) {
2544530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		info_ids[num_info_ids++] = ANQP_VENUE_NAME;
2554530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		info_ids[num_info_ids++] = ANQP_NETWORK_AUTH_TYPE;
2564530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	}
2574530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (all || (cred_with_roaming_consortium(wpa_s) &&
2584530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		    additional_roaming_consortiums(bss)))
2594530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		info_ids[num_info_ids++] = ANQP_ROAMING_CONSORTIUM;
2604530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (all)
2614530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		info_ids[num_info_ids++] = ANQP_IP_ADDR_TYPE_AVAILABILITY;
2624530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (all || cred_with_nai_realm(wpa_s))
2634530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		info_ids[num_info_ids++] = ANQP_NAI_REALM;
264df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	if (all || cred_with_3gpp(wpa_s)) {
2654530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		info_ids[num_info_ids++] = ANQP_3GPP_CELLULAR_NETWORK;
266df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		wpa_supplicant_scard_init(wpa_s, NULL);
267df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	}
2684530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (all || cred_with_domain(wpa_s))
2694530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		info_ids[num_info_ids++] = ANQP_DOMAIN_NAME;
2704530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "Interworking: ANQP Query info",
2714530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		    (u8 *) info_ids, num_info_ids * 2);
2724530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
27304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#ifdef CONFIG_HS20
27404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) {
27504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		u8 *len_pos;
27604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
27704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		extra = wpabuf_alloc(100);
27804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		if (!extra)
27904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			return -1;
28004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
28104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		len_pos = gas_anqp_add_element(extra, ANQP_VENDOR_SPECIFIC);
28204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpabuf_put_be24(extra, OUI_WFA);
28304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpabuf_put_u8(extra, HS20_ANQP_OUI_TYPE);
28404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpabuf_put_u8(extra, HS20_STYPE_QUERY_LIST);
28504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpabuf_put_u8(extra, 0); /* Reserved */
28604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpabuf_put_u8(extra, HS20_STYPE_CAPABILITY_LIST);
287f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (all)
2884530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			wpabuf_put_u8(extra,
2894530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt				      HS20_STYPE_OPERATOR_FRIENDLY_NAME);
290f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (all || cred_with_min_backhaul(wpa_s))
2914530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			wpabuf_put_u8(extra, HS20_STYPE_WAN_METRICS);
292f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (all || cred_with_conn_capab(wpa_s))
2934530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			wpabuf_put_u8(extra, HS20_STYPE_CONNECTION_CAPABILITY);
294f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (all)
2954530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			wpabuf_put_u8(extra, HS20_STYPE_OPERATING_CLASS);
296f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (all)
297f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			wpabuf_put_u8(extra, HS20_STYPE_OSU_PROVIDERS_LIST);
29804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		gas_anqp_set_element_len(extra, len_pos);
29904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
30004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#endif /* CONFIG_HS20 */
30104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
3024530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	buf = anqp_build_req(info_ids, num_info_ids, extra);
3031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpabuf_free(extra);
3041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (buf == NULL)
3051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
3061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	res = gas_query_req(wpa_s->gas, bss->bssid, bss->freq, buf,
3081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			    interworking_anqp_resp_cb, wpa_s);
3091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (res < 0) {
3101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
311051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpabuf_free(buf);
3121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		ret = -1;
313a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		eloop_register_timeout(0, 0, interworking_continue_anqp, wpa_s,
314a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt				       NULL);
3151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	} else
3161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
3171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "%u", res);
3181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return ret;
3201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
3211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstruct nai_realm_eap {
3241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u8 method;
3251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u8 inner_method;
3261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	enum nai_realm_eap_auth_inner_non_eap inner_non_eap;
3271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u8 cred_type;
3281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u8 tunneled_cred_type;
3291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt};
3301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstruct nai_realm {
3321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u8 encoding;
3331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	char *realm;
3341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u8 eap_count;
3351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nai_realm_eap *eap;
3361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt};
3371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void nai_realm_free(struct nai_realm *realms, u16 count)
3401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
3411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u16 i;
3421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (realms == NULL)
3441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
3451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	for (i = 0; i < count; i++) {
3461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		os_free(realms[i].eap);
3471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		os_free(realms[i].realm);
3481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
3491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_free(realms);
3501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
3511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic const u8 * nai_realm_parse_eap(struct nai_realm_eap *e, const u8 *pos,
3541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				      const u8 *end)
3551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
3561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u8 elen, auth_count, a;
3571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	const u8 *e_end;
3581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (pos + 3 > end) {
3601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "No room for EAP Method fixed fields");
3611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
3621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
3631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	elen = *pos++;
3651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (pos + elen > end || elen < 2) {
3661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "No room for EAP Method subfield");
3671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
3681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
3691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	e_end = pos + elen;
3701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	e->method = *pos++;
3711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	auth_count = *pos++;
3721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP Method: len=%u method=%u auth_count=%u",
3731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		   elen, e->method, auth_count);
3741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	for (a = 0; a < auth_count; a++) {
3761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		u8 id, len;
3771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (pos + 2 > end || pos + 2 + pos[1] > end) {
3791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_printf(MSG_DEBUG, "No room for Authentication "
3801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   "Parameter subfield");
3811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			return NULL;
3821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
3831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		id = *pos++;
3851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		len = *pos++;
3861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		switch (id) {
3881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		case NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH:
3891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (len < 1)
3901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				break;
3911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			e->inner_non_eap = *pos;
3921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (e->method != EAP_TYPE_TTLS)
3931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				break;
3941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			switch (*pos) {
3951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			case NAI_REALM_INNER_NON_EAP_PAP:
3961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP");
3971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				break;
3981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			case NAI_REALM_INNER_NON_EAP_CHAP:
3991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP");
4001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				break;
4011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			case NAI_REALM_INNER_NON_EAP_MSCHAP:
4021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP");
4031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				break;
4041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			case NAI_REALM_INNER_NON_EAP_MSCHAPV2:
4051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2");
4061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				break;
4071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			}
4081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
4091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		case NAI_REALM_EAP_AUTH_INNER_AUTH_EAP_METHOD:
4101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (len < 1)
4111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				break;
4121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			e->inner_method = *pos;
4131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_printf(MSG_DEBUG, "Inner EAP method: %u",
4141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   e->inner_method);
4151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
4161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		case NAI_REALM_EAP_AUTH_CRED_TYPE:
4171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (len < 1)
4181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				break;
4191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			e->cred_type = *pos;
4201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_printf(MSG_DEBUG, "Credential Type: %u",
4211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   e->cred_type);
4221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
4231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		case NAI_REALM_EAP_AUTH_TUNNELED_CRED_TYPE:
4241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (len < 1)
4251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				break;
4261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			e->tunneled_cred_type = *pos;
4271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_printf(MSG_DEBUG, "Tunneled EAP Method Credential "
4281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   "Type: %u", e->tunneled_cred_type);
4291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
4301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		default:
4311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_printf(MSG_DEBUG, "Unsupported Authentication "
4321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   "Parameter: id=%u len=%u", id, len);
4331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_hexdump(MSG_DEBUG, "Authentication Parameter "
4341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				    "Value", pos, len);
4351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
4361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
4371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
4381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		pos += len;
4391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
4401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
4411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return e_end;
4421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
4431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
4441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
4451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos,
4461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					const u8 *end)
4471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
4481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u16 len;
4491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	const u8 *f_end;
4501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u8 realm_len, e;
4511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
4521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (end - pos < 4) {
4531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "No room for NAI Realm Data "
4541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "fixed fields");
4551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
4561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
4571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
4581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	len = WPA_GET_LE16(pos); /* NAI Realm Data field Length */
4591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	pos += 2;
4601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (pos + len > end || len < 3) {
4611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "No room for NAI Realm Data "
4621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "(len=%u; left=%u)",
4631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   len, (unsigned int) (end - pos));
4641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
4651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
4661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	f_end = pos + len;
4671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
4681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	r->encoding = *pos++;
4691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	realm_len = *pos++;
4701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (pos + realm_len > f_end) {
4711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "No room for NAI Realm "
4721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "(len=%u; left=%u)",
4731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   realm_len, (unsigned int) (f_end - pos));
4741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
4751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
4761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_hexdump_ascii(MSG_DEBUG, "NAI Realm", pos, realm_len);
4774b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt	r->realm = dup_binstr(pos, realm_len);
4781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (r->realm == NULL)
4791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
4801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	pos += realm_len;
4811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
4821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (pos + 1 > f_end) {
4831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "No room for EAP Method Count");
4841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
4851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
4861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	r->eap_count = *pos++;
4871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP Count: %u", r->eap_count);
4881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (pos + r->eap_count * 3 > f_end) {
4891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "No room for EAP Methods");
4901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
4911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
49261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	r->eap = os_calloc(r->eap_count, sizeof(struct nai_realm_eap));
4931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (r->eap == NULL)
4941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
4951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
4961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	for (e = 0; e < r->eap_count; e++) {
4971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		pos = nai_realm_parse_eap(&r->eap[e], pos, f_end);
4981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (pos == NULL)
4991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			return NULL;
5001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
5011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return f_end;
5031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
5041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic struct nai_realm * nai_realm_parse(struct wpabuf *anqp, u16 *count)
5071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
5081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nai_realm *realm;
5091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	const u8 *pos, *end;
5101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u16 i, num;
5111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (anqp == NULL || wpabuf_len(anqp) < 2)
5131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
5141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	pos = wpabuf_head_u8(anqp);
5161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	end = pos + wpabuf_len(anqp);
5171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	num = WPA_GET_LE16(pos);
5181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_printf(MSG_DEBUG, "NAI Realm Count: %u", num);
5191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	pos += 2;
5201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (num * 5 > end - pos) {
5221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "Invalid NAI Realm Count %u - not "
5231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "enough data (%u octets) for that many realms",
5241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   num, (unsigned int) (end - pos));
5251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
5261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
5271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
52861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	realm = os_calloc(num, sizeof(struct nai_realm));
5291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (realm == NULL)
5301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
5311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	for (i = 0; i < num; i++) {
5331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		pos = nai_realm_parse_realm(&realm[i], pos, end);
5341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (pos == NULL) {
5351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			nai_realm_free(realm, num);
5361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			return NULL;
5371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
5381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
5391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	*count = num;
5411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return realm;
5421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
5431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int nai_realm_match(struct nai_realm *realm, const char *home_realm)
5461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
5471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	char *tmp, *pos, *end;
5481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int match = 0;
5491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (realm->realm == NULL || home_realm == NULL)
5511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return 0;
5521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (os_strchr(realm->realm, ';') == NULL)
5541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return os_strcasecmp(realm->realm, home_realm) == 0;
5551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	tmp = os_strdup(realm->realm);
5571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (tmp == NULL)
5581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return 0;
5591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	pos = tmp;
5611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	while (*pos) {
5621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		end = os_strchr(pos, ';');
5631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (end)
5641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			*end = '\0';
5651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (os_strcasecmp(pos, home_realm) == 0) {
5661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			match = 1;
5671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
5681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
5691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (end == NULL)
5701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
5711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		pos = end + 1;
5721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
5731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_free(tmp);
5751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return match;
5771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
5781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int nai_realm_cred_username(struct nai_realm_eap *eap)
5811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
5821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL)
5831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return 0; /* method not supported */
5841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
585fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (eap->method != EAP_TYPE_TTLS && eap->method != EAP_TYPE_PEAP &&
586fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	    eap->method != EAP_TYPE_FAST) {
5871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		/* Only tunneled methods with username/password supported */
5881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return 0;
5891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
5901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
591fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (eap->method == EAP_TYPE_PEAP || eap->method == EAP_TYPE_FAST) {
592a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		if (eap->inner_method &&
593a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		    eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL)
594a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			return 0;
595a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		if (!eap->inner_method &&
596a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		    eap_get_name(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2) == NULL)
597a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			return 0;
598a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	}
5991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (eap->method == EAP_TYPE_TTLS) {
6011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (eap->inner_method == 0 && eap->inner_non_eap == 0)
602a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			return 1; /* Assume TTLS/MSCHAPv2 is used */
6031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (eap->inner_method &&
6041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		    eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL)
6051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			return 0;
6061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (eap->inner_non_eap &&
6071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		    eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_PAP &&
6081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		    eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_CHAP &&
6091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		    eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAP &&
6101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		    eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAPV2)
6111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			return 0;
6121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
6131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (eap->inner_method &&
6151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	    eap->inner_method != EAP_TYPE_GTC &&
6161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	    eap->inner_method != EAP_TYPE_MSCHAPV2)
6171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return 0;
6181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return 1;
6201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
6211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
62304949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic int nai_realm_cred_cert(struct nai_realm_eap *eap)
62404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
62504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL)
62604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return 0; /* method not supported */
62704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
62804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (eap->method != EAP_TYPE_TLS) {
62904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		/* Only EAP-TLS supported for credential authentication */
63004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return 0;
63104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
63204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
63304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	return 1;
63404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
63504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
63604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
63704949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic struct nai_realm_eap * nai_realm_find_eap(struct wpa_cred *cred,
6381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt						 struct nai_realm *realm)
6391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
6401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u8 e;
6411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
64204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (cred == NULL ||
64304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	    cred->username == NULL ||
64404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	    cred->username[0] == '\0' ||
64504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	    ((cred->password == NULL ||
64604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	      cred->password[0] == '\0') &&
64704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	     (cred->private_key == NULL ||
64804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	      cred->private_key[0] == '\0')))
6491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
6501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	for (e = 0; e < realm->eap_count; e++) {
6521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		struct nai_realm_eap *eap = &realm->eap[e];
65304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		if (cred->password && cred->password[0] &&
65404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		    nai_realm_cred_username(eap))
65504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			return eap;
65604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		if (cred->private_key && cred->private_key[0] &&
65704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		    nai_realm_cred_cert(eap))
6581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			return eap;
6591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
6601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return NULL;
6621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
6631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#ifdef INTERWORKING_3GPP
6661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
66704949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
6681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
66934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u8 plmn[3], plmn2[3];
6701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	const u8 *pos, *end;
6711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u8 udhl;
6721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
67334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	/*
67434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	 * See Annex A of 3GPP TS 24.234 v8.1.0 for description. The network
67534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	 * operator is allowed to include only two digits of the MNC, so allow
67634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	 * matches based on both two and three digit MNC assumptions. Since some
67734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	 * SIM/USIM cards may not expose MNC length conveniently, we may be
67834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	 * provided the default MNC length 3 here and as such, checking with MNC
67934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	 * length 2 is justifiable even though 3GPP TS 24.234 does not mention
68034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	 * that case. Anyway, MCC/MNC pair where both 2 and 3 digit MNC is used
68134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	 * with otherwise matching values would not be good idea in general, so
68234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	 * this should not result in selecting incorrect networks.
68334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	 */
68434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	/* Match with 3 digit MNC */
6851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	plmn[0] = (imsi[0] - '0') | ((imsi[1] - '0') << 4);
68634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	plmn[1] = (imsi[2] - '0') | ((imsi[5] - '0') << 4);
6871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	plmn[2] = (imsi[3] - '0') | ((imsi[4] - '0') << 4);
68834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	/* Match with 2 digit MNC */
68934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	plmn2[0] = (imsi[0] - '0') | ((imsi[1] - '0') << 4);
69034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	plmn2[1] = (imsi[2] - '0') | 0xf0;
69134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	plmn2[2] = (imsi[3] - '0') | ((imsi[4] - '0') << 4);
6921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (anqp == NULL)
6941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return 0;
6951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	pos = wpabuf_head_u8(anqp);
6961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	end = pos + wpabuf_len(anqp);
6971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (pos + 2 > end)
6981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return 0;
6991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (*pos != 0) {
7001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "Unsupported GUD version 0x%x", *pos);
7011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return 0;
7021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
7031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	pos++;
7041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	udhl = *pos++;
7051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (pos + udhl > end) {
7061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "Invalid UDHL");
7071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return 0;
7081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
7091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	end = pos + udhl;
7101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
71134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_printf(MSG_DEBUG, "Interworking: Matching against MCC/MNC alternatives: %02x:%02x:%02x or %02x:%02x:%02x (IMSI %s, MNC length %d)",
71234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		   plmn[0], plmn[1], plmn[2], plmn2[0], plmn2[1], plmn2[2],
71334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		   imsi, mnc_len);
71434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
7151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	while (pos + 2 <= end) {
7161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		u8 iei, len;
7171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		const u8 *l_end;
7181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		iei = *pos++;
7191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		len = *pos++ & 0x7f;
7201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (pos + len > end)
7211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
7221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		l_end = pos + len;
7231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
7241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (iei == 0 && len > 0) {
7251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			/* PLMN List */
7261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			u8 num, i;
72734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			wpa_hexdump(MSG_DEBUG, "Interworking: PLMN List information element",
72834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				    pos, len);
7291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			num = *pos++;
7301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			for (i = 0; i < num; i++) {
73134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				if (pos + 3 > l_end)
7321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					break;
73334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				if (os_memcmp(pos, plmn, 3) == 0 ||
73434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				    os_memcmp(pos, plmn2, 3) == 0)
7351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					return 1; /* Found matching PLMN */
73661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				pos += 3;
7371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			}
73834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		} else {
73934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			wpa_hexdump(MSG_DEBUG, "Interworking: Unrecognized 3GPP information element",
74034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				    pos, len);
7411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
7421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
7431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		pos = l_end;
7441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
7451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
7461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return 0;
7471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
7481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
7491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
75004949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic int build_root_nai(char *nai, size_t nai_len, const char *imsi,
75161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			  size_t mnc_len, char prefix)
7521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
7531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	const char *sep, *msin;
75404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	char *end, *pos;
7551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	size_t msin_len, plmn_len;
7561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
7571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/*
7581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * TS 23.003, Clause 14 (3GPP to WLAN Interworking)
7591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * Root NAI:
7601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * <aka:0|sim:1><IMSI>@wlan.mnc<MNC>.mcc<MCC>.3gppnetwork.org
7611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * <MNC> is zero-padded to three digits in case two-digit MNC is used
7621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 */
7631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
7641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (imsi == NULL || os_strlen(imsi) > 16) {
7651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "No valid IMSI available");
7661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
7671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
7681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	sep = os_strchr(imsi, '-');
76961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (sep) {
77061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		plmn_len = sep - imsi;
77161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		msin = sep + 1;
77261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	} else if (mnc_len && os_strlen(imsi) >= 3 + mnc_len) {
77361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		plmn_len = 3 + mnc_len;
77461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		msin = imsi + plmn_len;
77561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	} else
7761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
7771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (plmn_len != 5 && plmn_len != 6)
7781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
7791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msin_len = os_strlen(msin);
7801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
7811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	pos = nai;
78204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	end = nai + nai_len;
78304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (prefix)
78404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		*pos++ = prefix;
7851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_memcpy(pos, imsi, plmn_len);
7861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	pos += plmn_len;
7871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_memcpy(pos, msin, msin_len);
7881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	pos += msin_len;
7891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	pos += os_snprintf(pos, end - pos, "@wlan.mnc");
7901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (plmn_len == 5) {
7911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		*pos++ = '0';
7921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		*pos++ = imsi[3];
7931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		*pos++ = imsi[4];
7941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	} else {
7951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		*pos++ = imsi[3];
7961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		*pos++ = imsi[4];
7971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		*pos++ = imsi[5];
7981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
799c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt	os_snprintf(pos, end - pos, ".mcc%c%c%c.3gppnetwork.org",
800c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt		    imsi[0], imsi[1], imsi[2]);
8011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
80204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	return 0;
80304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
80404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
80504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
80604949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix)
80704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
80804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	char nai[100];
80961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (build_root_nai(nai, sizeof(nai), imsi, 0, prefix) < 0)
81004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return -1;
8111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return wpa_config_set_quoted(ssid, "identity", nai);
8121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
8131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
8141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif /* INTERWORKING_3GPP */
8151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
8161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
8175460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidtstatic int already_connected(struct wpa_supplicant *wpa_s,
8185460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt			     struct wpa_cred *cred, struct wpa_bss *bss)
8195460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt{
8204582d2a5dd8180c52eb95b1100fb183b9a289708Dmitry Shmidt	struct wpa_ssid *ssid, *sel_ssid;
8214582d2a5dd8180c52eb95b1100fb183b9a289708Dmitry Shmidt	struct wpa_bss *selected;
8225460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt
8235460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	if (wpa_s->wpa_state < WPA_ASSOCIATED || wpa_s->current_ssid == NULL)
8245460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt		return 0;
8255460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt
8265460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	ssid = wpa_s->current_ssid;
8275460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	if (ssid->parent_cred != cred)
8285460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt		return 0;
8295460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt
8305460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	if (ssid->ssid_len != bss->ssid_len ||
8315460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	    os_memcmp(ssid->ssid, bss->ssid, bss->ssid_len) != 0)
8325460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt		return 0;
8335460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt
8344582d2a5dd8180c52eb95b1100fb183b9a289708Dmitry Shmidt	sel_ssid = NULL;
8354582d2a5dd8180c52eb95b1100fb183b9a289708Dmitry Shmidt	selected = wpa_supplicant_pick_network(wpa_s, &sel_ssid);
8364582d2a5dd8180c52eb95b1100fb183b9a289708Dmitry Shmidt	if (selected && sel_ssid && sel_ssid->priority > ssid->priority)
8374582d2a5dd8180c52eb95b1100fb183b9a289708Dmitry Shmidt		return 0; /* higher priority network in scan results */
8384582d2a5dd8180c52eb95b1100fb183b9a289708Dmitry Shmidt
8395460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	return 1;
8405460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt}
8415460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt
8425460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt
8435460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidtstatic void remove_duplicate_network(struct wpa_supplicant *wpa_s,
8445460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt				     struct wpa_cred *cred,
8455460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt				     struct wpa_bss *bss)
8465460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt{
8475460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	struct wpa_ssid *ssid;
8485460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt
8495460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
8505460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt		if (ssid->parent_cred != cred)
8515460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt			continue;
8525460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt		if (ssid->ssid_len != bss->ssid_len ||
8535460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt		    os_memcmp(ssid->ssid, bss->ssid, bss->ssid_len) != 0)
8545460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt			continue;
8555460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt
8565460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt		break;
8575460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	}
8585460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt
8595460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	if (ssid == NULL)
8605460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt		return;
8615460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt
8625460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	wpa_printf(MSG_DEBUG, "Interworking: Remove duplicate network entry for the same credential");
8635460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt
8645460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	if (ssid == wpa_s->current_ssid) {
8655460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt		wpa_sm_set_config(wpa_s->wpa, NULL);
8665460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt		eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
8675460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt		wpa_supplicant_deauthenticate(wpa_s,
8685460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt					      WLAN_REASON_DEAUTH_LEAVING);
8695460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	}
8705460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt
8715460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	wpas_notify_network_removed(wpa_s, ssid);
8725460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	wpa_config_remove_network(wpa_s->conf, ssid->id);
8735460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt}
8745460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt
8755460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt
876d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidtstatic int interworking_set_hs20_params(struct wpa_supplicant *wpa_s,
877d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt					struct wpa_ssid *ssid)
87861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
8795a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt	const char *key_mgmt = NULL;
8805a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt#ifdef CONFIG_IEEE80211R
8815a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt	int res;
8825a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt	struct wpa_driver_capa capa;
8835a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt
8845a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt	res = wpa_drv_get_capa(wpa_s, &capa);
8855a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt	if (res == 0 && capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT) {
8865a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt		key_mgmt = wpa_s->conf->pmf != NO_MGMT_FRAME_PROTECTION ?
8875a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt			"WPA-EAP WPA-EAP-SHA256 FT-EAP" :
8885a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt			"WPA-EAP FT-EAP";
8895a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt	}
8905a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt#endif /* CONFIG_IEEE80211R */
8915a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt
8925a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt	if (!key_mgmt)
8935a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt		key_mgmt = wpa_s->conf->pmf != NO_MGMT_FRAME_PROTECTION ?
8945a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt			"WPA-EAP WPA-EAP-SHA256" : "WPA-EAP";
8955a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt	if (wpa_config_set(ssid, "key_mgmt", key_mgmt, 0) < 0)
89661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return -1;
89761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (wpa_config_set(ssid, "proto", "RSN", 0) < 0)
89861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return -1;
89961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0)
90061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return -1;
90161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	return 0;
90261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
90361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
90461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
9051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
906f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt				     struct wpa_cred *cred,
9071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				     struct wpa_bss *bss)
9081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
9091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#ifdef INTERWORKING_3GPP
9101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_ssid *ssid;
9114530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	int eap_type;
9124530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	int res;
9134530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	char prefix;
9141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
9154530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
91604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return -1;
91704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
9181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " (3GPP)",
9191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		   MAC2STR(bss->bssid));
9201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
9215460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	if (already_connected(wpa_s, cred, bss)) {
9225460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt		wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
9235460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt			MAC2STR(bss->bssid));
9245460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt		return 0;
9255460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	}
9265460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt
9275460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	remove_duplicate_network(wpa_s, cred, bss);
9285460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt
9291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ssid = wpa_config_add_network(wpa_s->conf);
9301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (ssid == NULL)
9311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
932d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	ssid->parent_cred = cred;
9331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
9341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpas_notify_network_added(wpa_s, ssid);
9351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_config_set_network_defaults(ssid);
93604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	ssid->priority = cred->priority;
9371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ssid->temporary = 1;
9385460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	ssid->ssid = os_zalloc(bss->ssid_len + 1);
9391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (ssid->ssid == NULL)
9401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto fail;
9415460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len);
9425460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	ssid->ssid_len = bss->ssid_len;
943f9bdef99ce3b2858f2812c745a3d6bb093fb0e5dDmitry Shmidt	ssid->eap.sim_num = cred->sim_num;
9441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
945d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	if (interworking_set_hs20_params(wpa_s, ssid) < 0)
94661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		goto fail;
94761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
9484530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	eap_type = EAP_TYPE_SIM;
9494530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (cred->pcsc && wpa_s->scard && scard_supports_umts(wpa_s->scard))
9504530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		eap_type = EAP_TYPE_AKA;
9514530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (cred->eap_method && cred->eap_method[0].vendor == EAP_VENDOR_IETF) {
9524530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		if (cred->eap_method[0].method == EAP_TYPE_SIM ||
9534530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		    cred->eap_method[0].method == EAP_TYPE_AKA ||
9544530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		    cred->eap_method[0].method == EAP_TYPE_AKA_PRIME)
9554530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			eap_type = cred->eap_method[0].method;
9564530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	}
9574530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
9584530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	switch (eap_type) {
9594530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	case EAP_TYPE_SIM:
9604530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		prefix = '1';
9614530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		res = wpa_config_set(ssid, "eap", "SIM", 0);
9624530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		break;
9634530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	case EAP_TYPE_AKA:
9644530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		prefix = '0';
9654530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		res = wpa_config_set(ssid, "eap", "AKA", 0);
9664530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		break;
9674530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	case EAP_TYPE_AKA_PRIME:
9684530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		prefix = '6';
9694530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		res = wpa_config_set(ssid, "eap", "AKA'", 0);
9704530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		break;
9714530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	default:
9724530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		res = -1;
9734530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		break;
9744530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	}
9754530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (res < 0) {
9764530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Selected EAP method (%d) not supported",
9774530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			   eap_type);
9781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto fail;
9791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
9804530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
9814530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (!cred->pcsc && set_root_nai(ssid, cred->imsi, prefix) < 0) {
9821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "Failed to set Root NAI");
9831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto fail;
9841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
9851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
98604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (cred->milenage && cred->milenage[0]) {
9871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (wpa_config_set_quoted(ssid, "password",
98804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt					  cred->milenage) < 0)
9891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			goto fail;
99004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	} else if (cred->pcsc) {
9911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (wpa_config_set_quoted(ssid, "pcsc", "") < 0)
9921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			goto fail;
99304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		if (wpa_s->conf->pcsc_pin &&
99404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		    wpa_config_set_quoted(ssid, "pin", wpa_s->conf->pcsc_pin)
99504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		    < 0)
99604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			goto fail;
9971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
9981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
999f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	wpa_s->next_ssid = ssid;
100004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	wpa_config_update_prio_list(wpa_s->conf);
100104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	interworking_reconnect(wpa_s);
10021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
10031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return 0;
10041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
10051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtfail:
10061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpas_notify_network_removed(wpa_s, ssid);
10071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_config_remove_network(wpa_s->conf, ssid->id);
10081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif /* INTERWORKING_3GPP */
10091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return -1;
10101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
10111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
10121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
101361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic int roaming_consortium_element_match(const u8 *ie, const u8 *rc_id,
101461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					    size_t rc_len)
101561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
101661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	const u8 *pos, *end;
101761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	u8 lens;
101861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
101961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (ie == NULL)
102061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return 0;
102161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
102261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	pos = ie + 2;
102361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	end = ie + 2 + ie[1];
102461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
102561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	/* Roaming Consortium element:
102661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * Number of ANQP OIs
102761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * OI #1 and #2 lengths
102861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * OI #1, [OI #2], [OI #3]
102961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 */
103061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
103161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (pos + 2 > end)
103261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return 0;
103361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
103461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	pos++; /* skip Number of ANQP OIs */
103561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	lens = *pos++;
103661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (pos + (lens & 0x0f) + (lens >> 4) > end)
103761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return 0;
103861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
103961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if ((lens & 0x0f) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
104061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return 1;
104161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	pos += lens & 0x0f;
104261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
104361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if ((lens >> 4) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
104461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return 1;
104561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	pos += lens >> 4;
104661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
104761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (pos < end && (size_t) (end - pos) == rc_len &&
104861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	    os_memcmp(pos, rc_id, rc_len) == 0)
104961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return 1;
105061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
105161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	return 0;
105261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
105361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
105461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
105561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic int roaming_consortium_anqp_match(const struct wpabuf *anqp,
105661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					 const u8 *rc_id, size_t rc_len)
105761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
105861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	const u8 *pos, *end;
105961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	u8 len;
106061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
106161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (anqp == NULL)
106261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return 0;
106361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
106461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	pos = wpabuf_head(anqp);
106561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	end = pos + wpabuf_len(anqp);
106661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
106761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	/* Set of <OI Length, OI> duples */
106861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	while (pos < end) {
106961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		len = *pos++;
107061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		if (pos + len > end)
107161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			break;
107261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		if (len == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
107361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			return 1;
107461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		pos += len;
107561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
107661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
107761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	return 0;
107861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
107961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
108061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
108161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic int roaming_consortium_match(const u8 *ie, const struct wpabuf *anqp,
108261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				    const u8 *rc_id, size_t rc_len)
108361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
108461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	return roaming_consortium_element_match(ie, rc_id, rc_len) ||
108561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		roaming_consortium_anqp_match(anqp, rc_id, rc_len);
108661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
108761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
108861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
1089051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidtstatic int cred_no_required_oi_match(struct wpa_cred *cred, struct wpa_bss *bss)
1090051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
1091051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	const u8 *ie;
1092051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
1093051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (cred->required_roaming_consortium_len == 0)
1094051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return 0;
1095051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
1096051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
1097051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
1098051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (ie == NULL &&
1099051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	    (bss->anqp == NULL || bss->anqp->roaming_consortium == NULL))
1100051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return 1;
1101051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
1102051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return !roaming_consortium_match(ie,
1103051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt					 bss->anqp ?
1104051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt					 bss->anqp->roaming_consortium : NULL,
1105051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt					 cred->required_roaming_consortium,
1106051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt					 cred->required_roaming_consortium_len);
1107051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
1108051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
1109051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
1110a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtstatic int cred_excluded_ssid(struct wpa_cred *cred, struct wpa_bss *bss)
1111a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{
1112a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	size_t i;
1113a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1114a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (!cred->excluded_ssid)
1115a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		return 0;
1116a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1117a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	for (i = 0; i < cred->num_excluded_ssid; i++) {
1118a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		struct excluded_ssid *e = &cred->excluded_ssid[i];
1119a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		if (bss->ssid_len == e->ssid_len &&
1120a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		    os_memcmp(bss->ssid, e->ssid, e->ssid_len) == 0)
1121a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			return 1;
1122a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	}
1123a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1124a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	return 0;
1125a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt}
1126a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1127a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1128f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtstatic int cred_below_min_backhaul(struct wpa_supplicant *wpa_s,
1129f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				   struct wpa_cred *cred, struct wpa_bss *bss)
1130f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{
1131f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	int res;
1132f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	unsigned int dl_bandwidth, ul_bandwidth;
1133f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	const u8 *wan;
1134f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	u8 wan_info, dl_load, ul_load;
1135f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	u16 lmd;
1136f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	u32 ul_speed, dl_speed;
1137f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1138f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (!cred->min_dl_bandwidth_home &&
1139f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	    !cred->min_ul_bandwidth_home &&
1140f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	    !cred->min_dl_bandwidth_roaming &&
1141f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	    !cred->min_ul_bandwidth_roaming)
1142f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		return 0; /* No bandwidth constraint specified */
1143f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1144f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (bss->anqp == NULL || bss->anqp->hs20_wan_metrics == NULL)
1145f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		return 0; /* No WAN Metrics known - ignore constraint */
1146f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1147f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	wan = wpabuf_head(bss->anqp->hs20_wan_metrics);
1148f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	wan_info = wan[0];
1149f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (wan_info & BIT(3))
1150f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		return 1; /* WAN link at capacity */
1151f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	lmd = WPA_GET_LE16(wan + 11);
1152f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (lmd == 0)
1153f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		return 0; /* Downlink/Uplink Load was not measured */
1154f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	dl_speed = WPA_GET_LE32(wan + 1);
1155f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	ul_speed = WPA_GET_LE32(wan + 5);
1156f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	dl_load = wan[9];
1157f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	ul_load = wan[10];
1158f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1159f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (dl_speed >= 0xffffff)
1160f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		dl_bandwidth = dl_speed / 255 * (255 - dl_load);
1161f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	else
1162f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		dl_bandwidth = dl_speed * (255 - dl_load) / 255;
1163f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1164f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (ul_speed >= 0xffffff)
1165f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		ul_bandwidth = ul_speed / 255 * (255 - ul_load);
1166f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	else
1167f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		ul_bandwidth = ul_speed * (255 - ul_load) / 255;
1168f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1169f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	res = interworking_home_sp_cred(wpa_s, cred, bss->anqp ?
1170f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					bss->anqp->domain_name : NULL);
1171f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (res > 0) {
1172f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (cred->min_dl_bandwidth_home > dl_bandwidth)
1173f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			return 1;
1174f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (cred->min_ul_bandwidth_home > ul_bandwidth)
1175f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			return 1;
1176f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	} else {
1177f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (cred->min_dl_bandwidth_roaming > dl_bandwidth)
1178f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			return 1;
1179f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (cred->min_ul_bandwidth_roaming > ul_bandwidth)
1180f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			return 1;
1181f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	}
1182f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1183f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	return 0;
1184f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt}
1185f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1186f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1187f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtstatic int cred_over_max_bss_load(struct wpa_supplicant *wpa_s,
1188f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				  struct wpa_cred *cred, struct wpa_bss *bss)
1189f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{
1190f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	const u8 *ie;
1191f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	int res;
1192f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1193f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (!cred->max_bss_load)
1194f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		return 0; /* No BSS Load constraint specified */
1195f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1196f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	ie = wpa_bss_get_ie(bss, WLAN_EID_BSS_LOAD);
1197f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (ie == NULL || ie[1] < 3)
1198f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		return 0; /* No BSS Load advertised */
1199f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1200f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	res = interworking_home_sp_cred(wpa_s, cred, bss->anqp ?
1201f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					bss->anqp->domain_name : NULL);
1202f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (res <= 0)
1203f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		return 0; /* Not a home network */
1204f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1205f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	return ie[4] > cred->max_bss_load;
1206f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt}
1207f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1208f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1209f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtstatic int has_proto_match(const u8 *pos, const u8 *end, u8 proto)
1210f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{
1211f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	while (pos + 4 <= end) {
1212f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (pos[0] == proto && pos[3] == 1 /* Open */)
1213f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			return 1;
1214f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		pos += 4;
1215f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	}
1216f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1217f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	return 0;
1218f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt}
1219f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1220f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1221f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtstatic int has_proto_port_match(const u8 *pos, const u8 *end, u8 proto,
1222f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				u16 port)
1223f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{
1224f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	while (pos + 4 <= end) {
1225f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (pos[0] == proto && WPA_GET_LE16(&pos[1]) == port &&
1226f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		    pos[3] == 1 /* Open */)
1227f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			return 1;
1228f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		pos += 4;
1229f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	}
1230f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1231f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	return 0;
1232f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt}
1233f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1234f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1235f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtstatic int cred_conn_capab_missing(struct wpa_supplicant *wpa_s,
1236f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				   struct wpa_cred *cred, struct wpa_bss *bss)
1237f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{
1238f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	int res;
1239f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	const u8 *capab, *end;
1240f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	unsigned int i, j;
1241f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	int *ports;
1242f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1243f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (!cred->num_req_conn_capab)
1244f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		return 0; /* No connection capability constraint specified */
1245f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1246f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (bss->anqp == NULL || bss->anqp->hs20_connection_capability == NULL)
1247f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		return 0; /* No Connection Capability known - ignore constraint
1248f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			   */
1249f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1250f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	res = interworking_home_sp_cred(wpa_s, cred, bss->anqp ?
1251f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					bss->anqp->domain_name : NULL);
1252f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (res > 0)
1253f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		return 0; /* No constraint in home network */
1254f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1255f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	capab = wpabuf_head(bss->anqp->hs20_connection_capability);
1256f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	end = capab + wpabuf_len(bss->anqp->hs20_connection_capability);
1257f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1258f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	for (i = 0; i < cred->num_req_conn_capab; i++) {
1259f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		ports = cred->req_conn_capab_port[i];
1260f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (!ports) {
1261f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			if (!has_proto_match(capab, end,
1262f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					     cred->req_conn_capab_proto[i]))
1263f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				return 1;
1264f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		} else {
1265f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			for (j = 0; ports[j] > -1; j++) {
1266f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				if (!has_proto_port_match(
1267f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					    capab, end,
1268f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					    cred->req_conn_capab_proto[i],
1269f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					    ports[j]))
1270f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					return 1;
1271f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			}
1272f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		}
1273f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	}
1274f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1275f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	return 0;
1276f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt}
1277f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1278f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
127961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic struct wpa_cred * interworking_credentials_available_roaming_consortium(
1280f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int ignore_bw,
1281f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	int *excluded)
128261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
128361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	struct wpa_cred *cred, *selected = NULL;
128461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	const u8 *ie;
1285f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	int is_excluded = 0;
128661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
128761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
128861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
12894530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (ie == NULL &&
12904530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	    (bss->anqp == NULL || bss->anqp->roaming_consortium == NULL))
129161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return NULL;
129261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
129361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (wpa_s->conf->cred == NULL)
129461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return NULL;
129561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
129661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
129761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		if (cred->roaming_consortium_len == 0)
129861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			continue;
129961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
13004530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		if (!roaming_consortium_match(ie,
13014530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt					      bss->anqp ?
13024530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt					      bss->anqp->roaming_consortium :
13034530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt					      NULL,
130461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					      cred->roaming_consortium,
130561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					      cred->roaming_consortium_len))
130661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			continue;
130761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
1308051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (cred_no_required_oi_match(cred, bss))
1309051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			continue;
1310f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (!ignore_bw && cred_below_min_backhaul(wpa_s, cred, bss))
1311f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			continue;
1312f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (!ignore_bw && cred_over_max_bss_load(wpa_s, cred, bss))
1313f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			continue;
1314f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (!ignore_bw && cred_conn_capab_missing(wpa_s, cred, bss))
1315f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			continue;
1316f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (cred_excluded_ssid(cred, bss)) {
1317f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			if (excluded == NULL)
1318f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				continue;
1319f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			if (selected == NULL) {
1320f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				selected = cred;
1321f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				is_excluded = 1;
1322f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			}
1323f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		} else {
1324f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			if (selected == NULL || is_excluded ||
1325f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			    cred_prio_cmp(selected, cred) < 0) {
1326f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				selected = cred;
1327f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				is_excluded = 0;
1328f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			}
1329f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		}
133061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
133161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
1332f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (excluded)
1333f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		*excluded = is_excluded;
1334f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
133561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	return selected;
133661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
133761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
133861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
133961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic int interworking_set_eap_params(struct wpa_ssid *ssid,
134061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				       struct wpa_cred *cred, int ttls)
134161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
134261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (cred->eap_method) {
134361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		ttls = cred->eap_method->vendor == EAP_VENDOR_IETF &&
134461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			cred->eap_method->method == EAP_TYPE_TTLS;
134561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
134661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		os_free(ssid->eap.eap_methods);
134761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		ssid->eap.eap_methods =
134861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			os_malloc(sizeof(struct eap_method_type) * 2);
134961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		if (ssid->eap.eap_methods == NULL)
135061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			return -1;
135161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		os_memcpy(ssid->eap.eap_methods, cred->eap_method,
135261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			  sizeof(*cred->eap_method));
135361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		ssid->eap.eap_methods[1].vendor = EAP_VENDOR_IETF;
135461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		ssid->eap.eap_methods[1].method = EAP_TYPE_NONE;
135561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
135661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
135761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (ttls && cred->username && cred->username[0]) {
135861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		const char *pos;
135961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		char *anon;
136061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		/* Use anonymous NAI in Phase 1 */
136161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		pos = os_strchr(cred->username, '@');
136261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		if (pos) {
136361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			size_t buflen = 9 + os_strlen(pos) + 1;
136461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			anon = os_malloc(buflen);
136561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			if (anon == NULL)
136661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				return -1;
136761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			os_snprintf(anon, buflen, "anonymous%s", pos);
136861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		} else if (cred->realm) {
136961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			size_t buflen = 10 + os_strlen(cred->realm) + 1;
137061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			anon = os_malloc(buflen);
137161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			if (anon == NULL)
137261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				return -1;
137361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			os_snprintf(anon, buflen, "anonymous@%s", cred->realm);
137461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		} else {
137561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			anon = os_strdup("anonymous");
137661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			if (anon == NULL)
137761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				return -1;
137861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		}
137961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		if (wpa_config_set_quoted(ssid, "anonymous_identity", anon) <
138061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		    0) {
138161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			os_free(anon);
138261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			return -1;
138361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		}
138461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		os_free(anon);
138561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
138661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
138761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (cred->username && cred->username[0] &&
138861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	    wpa_config_set_quoted(ssid, "identity", cred->username) < 0)
138961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return -1;
139061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
139161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (cred->password && cred->password[0]) {
139261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		if (cred->ext_password &&
139361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		    wpa_config_set(ssid, "password", cred->password, 0) < 0)
139461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			return -1;
139561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		if (!cred->ext_password &&
139661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		    wpa_config_set_quoted(ssid, "password", cred->password) <
139761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		    0)
139861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			return -1;
139961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
140061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
140161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (cred->client_cert && cred->client_cert[0] &&
140261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	    wpa_config_set_quoted(ssid, "client_cert", cred->client_cert) < 0)
140361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return -1;
140461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
1405d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt#ifdef ANDROID
1406d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	if (cred->private_key &&
1407d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	    os_strncmp(cred->private_key, "keystore://", 11) == 0) {
1408d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		/* Use OpenSSL engine configuration for Android keystore */
1409d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		if (wpa_config_set_quoted(ssid, "engine_id", "keystore") < 0 ||
1410d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		    wpa_config_set_quoted(ssid, "key_id",
1411d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt					  cred->private_key + 11) < 0 ||
1412d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		    wpa_config_set(ssid, "engine", "1", 0) < 0)
1413d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			return -1;
1414d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	} else
1415d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt#endif /* ANDROID */
141661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (cred->private_key && cred->private_key[0] &&
141761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	    wpa_config_set_quoted(ssid, "private_key", cred->private_key) < 0)
141861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return -1;
141961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
142061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (cred->private_key_passwd && cred->private_key_passwd[0] &&
142161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	    wpa_config_set_quoted(ssid, "private_key_passwd",
142261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				  cred->private_key_passwd) < 0)
142361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return -1;
142461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
142561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (cred->phase1) {
142661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		os_free(ssid->eap.phase1);
142761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		ssid->eap.phase1 = os_strdup(cred->phase1);
142861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
142961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (cred->phase2) {
143061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		os_free(ssid->eap.phase2);
143161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		ssid->eap.phase2 = os_strdup(cred->phase2);
143261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
143361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
143461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (cred->ca_cert && cred->ca_cert[0] &&
143561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	    wpa_config_set_quoted(ssid, "ca_cert", cred->ca_cert) < 0)
143661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return -1;
143761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
1438051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (cred->domain_suffix_match && cred->domain_suffix_match[0] &&
1439051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	    wpa_config_set_quoted(ssid, "domain_suffix_match",
1440051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				  cred->domain_suffix_match) < 0)
1441051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return -1;
1442051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
1443f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	ssid->eap.ocsp = cred->ocsp;
1444f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
144561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	return 0;
144661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
144761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
144861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
144961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic int interworking_connect_roaming_consortium(
145061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	struct wpa_supplicant *wpa_s, struct wpa_cred *cred,
14515460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	struct wpa_bss *bss)
145261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
145361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	struct wpa_ssid *ssid;
145461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
145561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " based on "
145661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		   "roaming consortium match", MAC2STR(bss->bssid));
145761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
14585460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	if (already_connected(wpa_s, cred, bss)) {
14595460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt		wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
14605460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt			MAC2STR(bss->bssid));
14615460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt		return 0;
14625460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	}
14635460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt
14645460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	remove_duplicate_network(wpa_s, cred, bss);
14655460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt
146661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	ssid = wpa_config_add_network(wpa_s->conf);
146761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (ssid == NULL)
146861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return -1;
1469d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	ssid->parent_cred = cred;
147061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpas_notify_network_added(wpa_s, ssid);
147161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpa_config_set_network_defaults(ssid);
147261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	ssid->priority = cred->priority;
147361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	ssid->temporary = 1;
14745460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	ssid->ssid = os_zalloc(bss->ssid_len + 1);
147561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (ssid->ssid == NULL)
147661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		goto fail;
14775460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len);
14785460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	ssid->ssid_len = bss->ssid_len;
147961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
1480d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	if (interworking_set_hs20_params(wpa_s, ssid) < 0)
148161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		goto fail;
148261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
148361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (cred->eap_method == NULL) {
148461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Interworking: No EAP method set for "
148561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			   "credential using roaming consortium");
148661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		goto fail;
148761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
148861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
148961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (interworking_set_eap_params(
149061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		    ssid, cred,
149161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		    cred->eap_method->vendor == EAP_VENDOR_IETF &&
149261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		    cred->eap_method->method == EAP_TYPE_TTLS) < 0)
149361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		goto fail;
149461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
1495f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	wpa_s->next_ssid = ssid;
149661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpa_config_update_prio_list(wpa_s->conf);
149761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	interworking_reconnect(wpa_s);
149861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
149961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	return 0;
150061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
150161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtfail:
150261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpas_notify_network_removed(wpa_s, ssid);
150361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpa_config_remove_network(wpa_s->conf, ssid->id);
150461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	return -1;
150561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
150661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
150761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
1508f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtstatic int interworking_connect_helper(struct wpa_supplicant *wpa_s,
1509f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				       struct wpa_bss *bss, int allow_excluded)
15101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
1511f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	struct wpa_cred *cred, *cred_rc, *cred_3gpp;
15121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_ssid *ssid;
15131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nai_realm *realm;
15141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nai_realm_eap *eap = NULL;
15151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u16 count, i;
15161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	char buf[100];
1517f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	int excluded = 0, *excl = allow_excluded ? &excluded : NULL;
151809f57babfc1e4473db20ced4f58a4c9f082c8ed8Dmitry Shmidt	const char *name;
15191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
152004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (wpa_s->conf->cred == NULL || bss == NULL)
15211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
15225460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	if (disallowed_bssid(wpa_s, bss->bssid) ||
15235460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	    disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) {
15245460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Interworking: Reject connection to disallowed BSS "
15251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   MACSTR, MAC2STR(bss->bssid));
15261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
15271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
15281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1529f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	wpa_printf(MSG_DEBUG, "Interworking: Considering BSS " MACSTR
1530f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		   " for connection (allow_excluded=%d)",
1531f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		   MAC2STR(bss->bssid), allow_excluded);
1532f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
153361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) {
153461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		/*
153561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		 * We currently support only HS 2.0 networks and those are
153661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		 * required to use WPA2-Enterprise.
153761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		 */
153861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Interworking: Network does not use "
153961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			   "RSN");
154061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return -1;
154161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
154261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
1543f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	cred_rc = interworking_credentials_available_roaming_consortium(
1544f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpa_s, bss, 0, excl);
1545f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	if (cred_rc) {
1546f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Interworking: Highest roaming "
1547f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			   "consortium matching credential priority %d "
1548f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			   "sp_priority %d",
1549f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			   cred_rc->priority, cred_rc->sp_priority);
1550f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (allow_excluded && excl && !(*excl))
1551f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			excl = NULL;
1552f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	}
1553f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
1554f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	cred = interworking_credentials_available_realm(wpa_s, bss, 0, excl);
1555f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	if (cred) {
1556f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Interworking: Highest NAI Realm list "
1557f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			   "matching credential priority %d sp_priority %d",
1558f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			   cred->priority, cred->sp_priority);
1559f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (allow_excluded && excl && !(*excl))
1560f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			excl = NULL;
1561f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	}
1562f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
1563f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	cred_3gpp = interworking_credentials_available_3gpp(wpa_s, bss, 0,
1564f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt							    excl);
1565f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	if (cred_3gpp) {
1566f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Interworking: Highest 3GPP matching "
1567f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			   "credential priority %d sp_priority %d",
1568f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			   cred_3gpp->priority, cred_3gpp->sp_priority);
1569f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (allow_excluded && excl && !(*excl))
1570f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			excl = NULL;
1571f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	}
1572f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1573f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (!cred_rc && !cred && !cred_3gpp) {
1574f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Interworking: No full credential matches - consider options without BW(etc.) limits");
1575f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		cred_rc = interworking_credentials_available_roaming_consortium(
1576f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			wpa_s, bss, 1, excl);
1577f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (cred_rc) {
1578f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Interworking: Highest roaming "
1579f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				   "consortium matching credential priority %d "
1580f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				   "sp_priority %d (ignore BW)",
1581f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				   cred_rc->priority, cred_rc->sp_priority);
1582f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			if (allow_excluded && excl && !(*excl))
1583f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				excl = NULL;
1584f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		}
1585f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1586f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		cred = interworking_credentials_available_realm(wpa_s, bss, 1,
1587f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt								excl);
1588f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (cred) {
1589f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Interworking: Highest NAI Realm "
1590f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				   "list matching credential priority %d "
1591f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				   "sp_priority %d (ignore BW)",
1592f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				   cred->priority, cred->sp_priority);
1593f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			if (allow_excluded && excl && !(*excl))
1594f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				excl = NULL;
1595f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		}
1596f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1597f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		cred_3gpp = interworking_credentials_available_3gpp(wpa_s, bss,
1598f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt								    1, excl);
1599f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (cred_3gpp) {
1600f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Interworking: Highest 3GPP "
1601f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				   "matching credential priority %d "
1602f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				   "sp_priority %d (ignore BW)",
1603f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				   cred_3gpp->priority, cred_3gpp->sp_priority);
1604f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			if (allow_excluded && excl && !(*excl))
1605f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				excl = NULL;
1606f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		}
1607f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	}
1608f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
1609f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	if (cred_rc &&
1610f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	    (cred == NULL || cred_prio_cmp(cred_rc, cred) >= 0) &&
1611f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	    (cred_3gpp == NULL || cred_prio_cmp(cred_rc, cred_3gpp) >= 0))
1612f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		return interworking_connect_roaming_consortium(wpa_s, cred_rc,
16135460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt							       bss);
161461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
1615f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	if (cred_3gpp &&
1616f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	    (cred == NULL || cred_prio_cmp(cred_3gpp, cred) >= 0)) {
1617f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		return interworking_connect_3gpp(wpa_s, cred_3gpp, bss);
1618f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	}
1619f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
1620f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	if (cred == NULL) {
1621f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Interworking: No matching credentials "
1622f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt			   "found for " MACSTR, MAC2STR(bss->bssid));
1623f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		return -1;
1624f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	}
1625f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
16264530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	realm = nai_realm_parse(bss->anqp ? bss->anqp->nai_realm : NULL,
16274530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt				&count);
16281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (realm == NULL) {
16291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
16301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "Realm list from " MACSTR, MAC2STR(bss->bssid));
1631f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		return -1;
16321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
16331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1634f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	for (i = 0; i < count; i++) {
1635f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		if (!nai_realm_match(&realm[i], cred->realm))
1636f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt			continue;
1637f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		eap = nai_realm_find_eap(cred, &realm[i]);
16381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (eap)
16391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
16401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
16411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
16421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!eap) {
16431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "Interworking: No matching credentials "
16441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "and EAP method found for " MACSTR,
16451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   MAC2STR(bss->bssid));
16461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nai_realm_free(realm, count);
16471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
16481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
16491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
16501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR,
16511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		   MAC2STR(bss->bssid));
16521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
16535460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	if (already_connected(wpa_s, cred, bss)) {
16545460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt		wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
16555460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt			MAC2STR(bss->bssid));
16565460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt		nai_realm_free(realm, count);
16575460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt		return 0;
16585460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	}
16595460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt
16605460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	remove_duplicate_network(wpa_s, cred, bss);
16615460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt
16621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ssid = wpa_config_add_network(wpa_s->conf);
16631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (ssid == NULL) {
16641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nai_realm_free(realm, count);
16651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
16661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
1667d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	ssid->parent_cred = cred;
16681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpas_notify_network_added(wpa_s, ssid);
16691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_config_set_network_defaults(ssid);
167004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	ssid->priority = cred->priority;
16711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ssid->temporary = 1;
16725460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	ssid->ssid = os_zalloc(bss->ssid_len + 1);
16731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (ssid->ssid == NULL)
16741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto fail;
16755460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len);
16765460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	ssid->ssid_len = bss->ssid_len;
16771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1678d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	if (interworking_set_hs20_params(wpa_s, ssid) < 0)
167904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		goto fail;
168004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
168161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (wpa_config_set(ssid, "eap", eap_get_name(EAP_VENDOR_IETF,
168261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt						     eap->method), 0) < 0)
16831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto fail;
16841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
16851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	switch (eap->method) {
16861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case EAP_TYPE_TTLS:
16871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (eap->inner_method) {
16881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			os_snprintf(buf, sizeof(buf), "\"autheap=%s\"",
16891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				    eap_get_name(EAP_VENDOR_IETF,
16901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt						 eap->inner_method));
16911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (wpa_config_set(ssid, "phase2", buf, 0) < 0)
16921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				goto fail;
16931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
16941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
16951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		switch (eap->inner_non_eap) {
16961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		case NAI_REALM_INNER_NON_EAP_PAP:
16971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (wpa_config_set(ssid, "phase2", "\"auth=PAP\"", 0) <
16981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			    0)
16991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				goto fail;
17001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
17011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		case NAI_REALM_INNER_NON_EAP_CHAP:
17021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (wpa_config_set(ssid, "phase2", "\"auth=CHAP\"", 0)
17031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			    < 0)
17041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				goto fail;
17051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
17061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		case NAI_REALM_INNER_NON_EAP_MSCHAP:
1707c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAP\"",
1708c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt					   0) < 0)
17091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				goto fail;
17101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
17111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		case NAI_REALM_INNER_NON_EAP_MSCHAPV2:
17121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAPV2\"",
17131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					   0) < 0)
17141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				goto fail;
17151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
1716a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		default:
1717a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			/* EAP params were not set - assume TTLS/MSCHAPv2 */
1718a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAPV2\"",
1719a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt					   0) < 0)
1720a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt				goto fail;
1721a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			break;
17221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
17231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
17241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case EAP_TYPE_PEAP:
1725fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	case EAP_TYPE_FAST:
1726fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		if (wpa_config_set(ssid, "phase1", "\"fast_provisioning=2\"",
1727fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt				   0) < 0)
1728fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			goto fail;
1729fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		if (wpa_config_set(ssid, "pac_file",
1730fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt				   "\"blob://pac_interworking\"", 0) < 0)
1731fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			goto fail;
173209f57babfc1e4473db20ced4f58a4c9f082c8ed8Dmitry Shmidt		name = eap_get_name(EAP_VENDOR_IETF,
173309f57babfc1e4473db20ced4f58a4c9f082c8ed8Dmitry Shmidt				    eap->inner_method ? eap->inner_method :
173409f57babfc1e4473db20ced4f58a4c9f082c8ed8Dmitry Shmidt				    EAP_TYPE_MSCHAPV2);
173509f57babfc1e4473db20ced4f58a4c9f082c8ed8Dmitry Shmidt		if (name == NULL)
173609f57babfc1e4473db20ced4f58a4c9f082c8ed8Dmitry Shmidt			goto fail;
173709f57babfc1e4473db20ced4f58a4c9f082c8ed8Dmitry Shmidt		os_snprintf(buf, sizeof(buf), "\"auth=%s\"", name);
17381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (wpa_config_set(ssid, "phase2", buf, 0) < 0)
17391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			goto fail;
17401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
174104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	case EAP_TYPE_TLS:
174204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		break;
17431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
17441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
174561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (interworking_set_eap_params(ssid, cred,
174661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					eap->method == EAP_TYPE_TTLS) < 0)
17471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto fail;
17481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
17491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nai_realm_free(realm, count);
17501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1751f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	wpa_s->next_ssid = ssid;
175204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	wpa_config_update_prio_list(wpa_s->conf);
175304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	interworking_reconnect(wpa_s);
17541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
17551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return 0;
17561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
17571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtfail:
17581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpas_notify_network_removed(wpa_s, ssid);
17591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_config_remove_network(wpa_s->conf, ssid->id);
17601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nai_realm_free(realm, count);
17611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return -1;
17621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
17631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
17641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1765f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtint interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
1766f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{
1767f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	return interworking_connect_helper(wpa_s, bss, 1);
1768f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt}
1769f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1770f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1771df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt#ifdef PCSC_FUNCS
1772df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidtstatic int interworking_pcsc_read_imsi(struct wpa_supplicant *wpa_s)
1773df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt{
1774df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	size_t len;
1775df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
1776df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	if (wpa_s->imsi[0] && wpa_s->mnc_len)
1777df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		return 0;
1778df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
1779df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	len = sizeof(wpa_s->imsi) - 1;
1780df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	if (scard_get_imsi(wpa_s->scard, wpa_s->imsi, &len)) {
1781df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		scard_deinit(wpa_s->scard);
1782df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		wpa_s->scard = NULL;
1783df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		wpa_msg(wpa_s, MSG_ERROR, "Could not read IMSI");
1784df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		return -1;
1785df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	}
1786df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	wpa_s->imsi[len] = '\0';
1787df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	wpa_s->mnc_len = scard_get_mnc_len(wpa_s->scard);
1788df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	wpa_printf(MSG_DEBUG, "SCARD: IMSI %s (MNC length %d)",
1789df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		   wpa_s->imsi, wpa_s->mnc_len);
1790df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
1791df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	return 0;
1792df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt}
1793df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt#endif /* PCSC_FUNCS */
1794df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
1795df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
179604949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic struct wpa_cred * interworking_credentials_available_3gpp(
1797f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int ignore_bw,
1798f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	int *excluded)
17991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
18002f3b8dec59373945c5feef8a78ced8967a80cc66Dmitry Shmidt	struct wpa_cred *selected = NULL;
18012f3b8dec59373945c5feef8a78ced8967a80cc66Dmitry Shmidt#ifdef INTERWORKING_3GPP
18022f3b8dec59373945c5feef8a78ced8967a80cc66Dmitry Shmidt	struct wpa_cred *cred;
180304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	int ret;
1804f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	int is_excluded = 0;
18051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
18064530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
180704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return NULL;
18081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1809b96dad47218788efffa3db0fe7f1b54a7d19e366Dmitry Shmidt#ifdef CONFIG_EAP_PROXY
1810b96dad47218788efffa3db0fe7f1b54a7d19e366Dmitry Shmidt	if (!wpa_s->imsi[0]) {
1811b96dad47218788efffa3db0fe7f1b54a7d19e366Dmitry Shmidt		size_t len;
1812b96dad47218788efffa3db0fe7f1b54a7d19e366Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Interworking: IMSI not available - try to read again through eap_proxy");
1813b96dad47218788efffa3db0fe7f1b54a7d19e366Dmitry Shmidt		wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol,
1814b96dad47218788efffa3db0fe7f1b54a7d19e366Dmitry Shmidt							     wpa_s->imsi,
1815b96dad47218788efffa3db0fe7f1b54a7d19e366Dmitry Shmidt							     &len);
1816b96dad47218788efffa3db0fe7f1b54a7d19e366Dmitry Shmidt		if (wpa_s->mnc_len > 0) {
1817b96dad47218788efffa3db0fe7f1b54a7d19e366Dmitry Shmidt			wpa_s->imsi[len] = '\0';
1818b96dad47218788efffa3db0fe7f1b54a7d19e366Dmitry Shmidt			wpa_printf(MSG_DEBUG, "eap_proxy: IMSI %s (MNC length %d)",
1819b96dad47218788efffa3db0fe7f1b54a7d19e366Dmitry Shmidt				   wpa_s->imsi, wpa_s->mnc_len);
1820b96dad47218788efffa3db0fe7f1b54a7d19e366Dmitry Shmidt		} else {
1821b96dad47218788efffa3db0fe7f1b54a7d19e366Dmitry Shmidt			wpa_printf(MSG_DEBUG, "eap_proxy: IMSI not available");
1822b96dad47218788efffa3db0fe7f1b54a7d19e366Dmitry Shmidt		}
1823b96dad47218788efffa3db0fe7f1b54a7d19e366Dmitry Shmidt	}
1824b96dad47218788efffa3db0fe7f1b54a7d19e366Dmitry Shmidt#endif /* CONFIG_EAP_PROXY */
1825b96dad47218788efffa3db0fe7f1b54a7d19e366Dmitry Shmidt
182604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
182704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		char *sep;
182804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		const char *imsi;
182904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		int mnc_len;
183034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		char imsi_buf[16];
183134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		size_t msin_len;
183204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
183304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#ifdef PCSC_FUNCS
1834df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		if (cred->pcsc && wpa_s->scard) {
1835df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt			if (interworking_pcsc_read_imsi(wpa_s) < 0)
1836df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt				continue;
183704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			imsi = wpa_s->imsi;
183804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			mnc_len = wpa_s->mnc_len;
183904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			goto compare;
184004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		}
184104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#endif /* PCSC_FUNCS */
184234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt#ifdef CONFIG_EAP_PROXY
184334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		if (cred->pcsc && wpa_s->mnc_len > 0 && wpa_s->imsi[0]) {
184434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			imsi = wpa_s->imsi;
184534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			mnc_len = wpa_s->mnc_len;
184634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			goto compare;
184734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		}
184834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt#endif /* CONFIG_EAP_PROXY */
18491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
185004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		if (cred->imsi == NULL || !cred->imsi[0] ||
1851051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		    (!wpa_s->conf->external_sim &&
1852051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		     (cred->milenage == NULL || !cred->milenage[0])))
185304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			continue;
185404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
185504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		sep = os_strchr(cred->imsi, '-');
185604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		if (sep == NULL ||
185704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		    (sep - cred->imsi != 5 && sep - cred->imsi != 6))
185804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			continue;
185904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		mnc_len = sep - cred->imsi - 3;
186034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		os_memcpy(imsi_buf, cred->imsi, 3 + mnc_len);
186134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		sep++;
186234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		msin_len = os_strlen(cred->imsi);
186334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		if (3 + mnc_len + msin_len >= sizeof(imsi_buf) - 1)
186434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			msin_len = sizeof(imsi_buf) - 3 - mnc_len - 1;
186534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		os_memcpy(&imsi_buf[3 + mnc_len], sep, msin_len);
186634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		imsi_buf[3 + mnc_len + msin_len] = '\0';
186734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		imsi = imsi_buf;
186834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
186934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt#if defined(PCSC_FUNCS) || defined(CONFIG_EAP_PROXY)
187004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	compare:
187134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt#endif /* PCSC_FUNCS || CONFIG_EAP_PROXY */
187204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpa_printf(MSG_DEBUG, "Interworking: Parsing 3GPP info from "
187304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			   MACSTR, MAC2STR(bss->bssid));
18744530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		ret = plmn_id_match(bss->anqp->anqp_3gpp, imsi, mnc_len);
187504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpa_printf(MSG_DEBUG, "PLMN match %sfound", ret ? "" : "not ");
187604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		if (ret) {
1877051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			if (cred_no_required_oi_match(cred, bss))
1878051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				continue;
1879f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			if (!ignore_bw &&
1880f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			    cred_below_min_backhaul(wpa_s, cred, bss))
1881f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				continue;
1882f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			if (!ignore_bw &&
1883f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			    cred_over_max_bss_load(wpa_s, cred, bss))
1884f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				continue;
1885f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			if (!ignore_bw &&
1886f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			    cred_conn_capab_missing(wpa_s, cred, bss))
1887f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				continue;
1888f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			if (cred_excluded_ssid(cred, bss)) {
1889f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				if (excluded == NULL)
1890f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					continue;
1891f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				if (selected == NULL) {
1892f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					selected = cred;
1893f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					is_excluded = 1;
1894f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				}
1895f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			} else {
1896f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				if (selected == NULL || is_excluded ||
1897f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				    cred_prio_cmp(selected, cred) < 0) {
1898f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					selected = cred;
1899f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					is_excluded = 0;
1900f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				}
1901f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			}
190204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		}
190304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
1904f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1905f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (excluded)
1906f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		*excluded = is_excluded;
19071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif /* INTERWORKING_3GPP */
190804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	return selected;
19091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
19101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
19111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
191204949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic struct wpa_cred * interworking_credentials_available_realm(
1913f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int ignore_bw,
1914f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	int *excluded)
19151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
191604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct wpa_cred *cred, *selected = NULL;
19171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nai_realm *realm;
19181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u16 count, i;
1919f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	int is_excluded = 0;
19201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
19214530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (bss->anqp == NULL || bss->anqp->nai_realm == NULL)
192204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return NULL;
19231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
192404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (wpa_s->conf->cred == NULL)
192504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return NULL;
19261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
19271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_printf(MSG_DEBUG, "Interworking: Parsing NAI Realm list from "
19281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		   MACSTR, MAC2STR(bss->bssid));
19294530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	realm = nai_realm_parse(bss->anqp->nai_realm, &count);
19301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (realm == NULL) {
19311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
19321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "Realm list from " MACSTR, MAC2STR(bss->bssid));
193304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return NULL;
19341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
19351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
193604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
193704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		if (cred->realm == NULL)
19381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			continue;
193904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
194004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		for (i = 0; i < count; i++) {
194104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			if (!nai_realm_match(&realm[i], cred->realm))
194204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				continue;
194304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			if (nai_realm_find_eap(cred, &realm[i])) {
1944051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				if (cred_no_required_oi_match(cred, bss))
1945051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt					continue;
1946f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				if (!ignore_bw &&
1947f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				    cred_below_min_backhaul(wpa_s, cred, bss))
1948f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					continue;
1949f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				if (!ignore_bw &&
1950f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				    cred_over_max_bss_load(wpa_s, cred, bss))
1951f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					continue;
1952f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				if (!ignore_bw &&
1953f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				    cred_conn_capab_missing(wpa_s, cred, bss))
1954f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					continue;
1955f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				if (cred_excluded_ssid(cred, bss)) {
1956f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					if (excluded == NULL)
1957f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt						continue;
1958f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					if (selected == NULL) {
1959f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt						selected = cred;
1960f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt						is_excluded = 1;
1961f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					}
1962f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				} else {
1963f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					if (selected == NULL || is_excluded ||
1964f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					    cred_prio_cmp(selected, cred) < 0)
1965f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					{
1966f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt						selected = cred;
1967f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt						is_excluded = 0;
1968f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					}
1969f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				}
197004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				break;
197104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			}
19721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
19731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
19741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
19751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nai_realm_free(realm, count);
19761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1977f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (excluded)
1978f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		*excluded = is_excluded;
1979f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
198004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	return selected;
198104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
198204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
198304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
1984f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtstatic struct wpa_cred * interworking_credentials_available_helper(
1985f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int ignore_bw,
1986f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	int *excluded)
198704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
198804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct wpa_cred *cred, *cred2;
1989f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	int excluded1, excluded2;
199004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
19915460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	if (disallowed_bssid(wpa_s, bss->bssid) ||
19925460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	    disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) {
19935460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Interworking: Ignore disallowed BSS "
19945460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt			   MACSTR, MAC2STR(bss->bssid));
19955460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt		return NULL;
19965460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	}
19975460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt
1998f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	cred = interworking_credentials_available_realm(wpa_s, bss, ignore_bw,
1999f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt							&excluded1);
2000f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	cred2 = interworking_credentials_available_3gpp(wpa_s, bss, ignore_bw,
2001f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt							&excluded2);
2002f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (cred && cred2 &&
2003f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	    (cred_prio_cmp(cred2, cred) >= 0 || (!excluded2 && excluded1))) {
200404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		cred = cred2;
2005f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		excluded1 = excluded2;
2006f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	}
2007f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (!cred) {
200804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		cred = cred2;
2009f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		excluded1 = excluded2;
2010f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	}
201104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
2012f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	cred2 = interworking_credentials_available_roaming_consortium(
2013f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpa_s, bss, ignore_bw, &excluded2);
2014f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (cred && cred2 &&
2015f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	    (cred_prio_cmp(cred2, cred) >= 0 || (!excluded2 && excluded1))) {
201661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		cred = cred2;
2017f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		excluded1 = excluded2;
2018f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	}
2019f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (!cred) {
202061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		cred = cred2;
2021f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		excluded1 = excluded2;
2022f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	}
202361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
2024f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (excluded)
2025f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		*excluded = excluded1;
202604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	return cred;
20271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
20281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
20291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2030f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtstatic struct wpa_cred * interworking_credentials_available(
2031f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int *excluded)
2032f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{
2033f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	struct wpa_cred *cred;
2034f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
2035f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (excluded)
2036f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		*excluded = 0;
2037f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	cred = interworking_credentials_available_helper(wpa_s, bss, 0,
2038f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt							 excluded);
2039f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (cred)
2040f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		return cred;
2041f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	return interworking_credentials_available_helper(wpa_s, bss, 1,
2042f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt							 excluded);
2043f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt}
2044f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
2045f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
2046f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtint domain_name_list_contains(struct wpabuf *domain_names,
2047f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			      const char *domain, int exact_match)
20481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
204904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	const u8 *pos, *end;
205004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	size_t len;
205104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
205204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	len = os_strlen(domain);
205304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	pos = wpabuf_head(domain_names);
205404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	end = pos + wpabuf_len(domain_names);
205504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
205604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	while (pos + 1 < end) {
205704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		if (pos + 1 + pos[0] > end)
205804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			break;
205904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
206004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpa_hexdump_ascii(MSG_DEBUG, "Interworking: AP domain name",
206104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				  pos + 1, pos[0]);
206204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		if (pos[0] == len &&
206304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		    os_strncasecmp(domain, (const char *) (pos + 1), len) == 0)
206404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			return 1;
2065f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (!exact_match && pos[0] > len && pos[pos[0] - len] == '.') {
2066f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			const char *ap = (const char *) (pos + 1);
2067f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			int offset = pos[0] - len;
2068f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			if (os_strncasecmp(domain, ap + offset, len) == 0)
2069f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				return 1;
2070f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		}
207104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
207204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		pos += 1 + pos[0];
207304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
207404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
207504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	return 0;
207604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
207704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
207804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
2079d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidtint interworking_home_sp_cred(struct wpa_supplicant *wpa_s,
2080d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			      struct wpa_cred *cred,
2081d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			      struct wpabuf *domain_names)
208204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
2083051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	size_t i;
208468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	int ret = -1;
208504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#ifdef INTERWORKING_3GPP
208604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	char nai[100], *realm;
208704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
2088d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	char *imsi = NULL;
2089d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	int mnc_len = 0;
2090d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	if (cred->imsi)
2091d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		imsi = cred->imsi;
2092df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt#ifdef PCSC_FUNCS
2093df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	else if (cred->pcsc && wpa_s->scard) {
2094df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		if (interworking_pcsc_read_imsi(wpa_s) < 0)
2095df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt			return -1;
2096d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		imsi = wpa_s->imsi;
2097d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		mnc_len = wpa_s->mnc_len;
2098d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	}
2099df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt#endif /* PCSC_FUNCS */
2100051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#ifdef CONFIG_EAP_PROXY
2101051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	else if (cred->pcsc && wpa_s->mnc_len > 0 && wpa_s->imsi[0]) {
2102051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		imsi = wpa_s->imsi;
2103051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		mnc_len = wpa_s->mnc_len;
2104051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
2105051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#endif /* CONFIG_EAP_PROXY */
2106a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (domain_names &&
2107a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	    imsi && build_root_nai(nai, sizeof(nai), imsi, mnc_len, 0) == 0) {
2108d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		realm = os_strchr(nai, '@');
2109d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		if (realm)
2110d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			realm++;
2111d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		wpa_printf(MSG_DEBUG, "Interworking: Search for match "
2112d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			   "with SIM/USIM domain %s", realm);
2113d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		if (realm &&
2114f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		    domain_name_list_contains(domain_names, realm, 1))
2115d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			return 1;
211668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		if (realm)
211768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt			ret = 0;
2118d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	}
211904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#endif /* INTERWORKING_3GPP */
212004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
2121a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (domain_names == NULL || cred->domain == NULL)
212268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		return ret;
212304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
2124051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	for (i = 0; i < cred->num_domain; i++) {
2125051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Interworking: Search for match with "
2126051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			   "home SP FQDN %s", cred->domain[i]);
2127f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (domain_name_list_contains(domain_names, cred->domain[i], 1))
2128051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			return 1;
2129051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
2130d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
2131d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	return 0;
2132d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt}
2133d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
2134d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
2135d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidtstatic int interworking_home_sp(struct wpa_supplicant *wpa_s,
2136d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt				struct wpabuf *domain_names)
2137d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt{
2138d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	struct wpa_cred *cred;
2139d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
2140d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	if (domain_names == NULL || wpa_s->conf->cred == NULL)
2141d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		return -1;
2142d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
2143d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
2144d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		int res = interworking_home_sp_cred(wpa_s, cred, domain_names);
2145d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		if (res)
2146d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			return res;
214704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
214804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
214904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	return 0;
215004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
215104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
215204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
215304949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic int interworking_find_network_match(struct wpa_supplicant *wpa_s)
215404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
215504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct wpa_bss *bss;
215604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct wpa_ssid *ssid;
215704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
215804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
215904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
216004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			if (wpas_network_disabled(wpa_s, ssid) ||
216104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			    ssid->mode != WPAS_MODE_INFRA)
216204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				continue;
216304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			if (ssid->ssid_len != bss->ssid_len ||
216404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			    os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) !=
216504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			    0)
216604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				continue;
216704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			/*
216804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			 * TODO: Consider more accurate matching of security
216904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			 * configuration similarly to what is done in events.c
217004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			 */
217104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			return 1;
217204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		}
217304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
217404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
217504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	return 0;
21761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
21771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
21781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2179f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtstatic int roaming_partner_match(struct wpa_supplicant *wpa_s,
2180f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				 struct roaming_partner *partner,
2181f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				 struct wpabuf *domain_names)
2182f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{
2183f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	wpa_printf(MSG_DEBUG, "Interworking: Comparing roaming_partner info fqdn='%s' exact_match=%d priority=%u country='%s'",
2184f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		   partner->fqdn, partner->exact_match, partner->priority,
2185f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		   partner->country);
2186f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	wpa_hexdump_ascii(MSG_DEBUG, "Interworking: Domain names",
2187f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			  wpabuf_head(domain_names),
2188f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			  wpabuf_len(domain_names));
2189f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (!domain_name_list_contains(domain_names, partner->fqdn,
2190f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				       partner->exact_match))
2191f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		return 0;
2192f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	/* TODO: match Country */
2193f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	return 1;
2194f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt}
2195f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
2196f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
2197f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtstatic u8 roaming_prio(struct wpa_supplicant *wpa_s, struct wpa_cred *cred,
2198f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		       struct wpa_bss *bss)
2199f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{
2200f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	size_t i;
2201f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
2202f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (bss->anqp == NULL || bss->anqp->domain_name == NULL) {
2203f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Interworking: No ANQP domain name info -> use default roaming partner priority 128");
2204f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		return 128; /* cannot check preference with domain name */
2205f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	}
2206f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
2207f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (interworking_home_sp_cred(wpa_s, cred, bss->anqp->domain_name) > 0)
2208f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	{
2209f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Interworking: Determined to be home SP -> use maximum preference 0 as roaming partner priority");
2210f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		return 0; /* max preference for home SP network */
2211f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	}
2212f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
2213f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	for (i = 0; i < cred->num_roaming_partner; i++) {
2214f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (roaming_partner_match(wpa_s, &cred->roaming_partner[i],
2215f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					  bss->anqp->domain_name)) {
2216f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Interworking: Roaming partner preference match - priority %u",
2217f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				   cred->roaming_partner[i].priority);
2218f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			return cred->roaming_partner[i].priority;
2219f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		}
2220f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	}
2221f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
2222f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	wpa_printf(MSG_DEBUG, "Interworking: No roaming partner preference match - use default roaming partner priority 128");
2223f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	return 128;
2224f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt}
2225f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
2226f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
2227f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtstatic struct wpa_bss * pick_best_roaming_partner(struct wpa_supplicant *wpa_s,
2228f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt						  struct wpa_bss *selected,
2229f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt						  struct wpa_cred *cred)
2230f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{
2231f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	struct wpa_bss *bss;
2232f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	u8 best_prio, prio;
2233f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	struct wpa_cred *cred2;
2234f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
2235f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	/*
2236f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	 * Check if any other BSS is operated by a more preferred roaming
2237f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	 * partner.
2238f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	 */
2239f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
2240f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	best_prio = roaming_prio(wpa_s, cred, selected);
2241f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	wpa_printf(MSG_DEBUG, "Interworking: roaming_prio=%u for selected BSS "
2242f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		   MACSTR " (cred=%d)", best_prio, MAC2STR(selected->bssid),
2243f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		   cred->id);
2244f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
2245f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
2246f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (bss == selected)
2247f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			continue;
2248f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		cred2 = interworking_credentials_available(wpa_s, bss, NULL);
2249f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (!cred2)
2250f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			continue;
2251f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (!wpa_bss_get_ie(bss, WLAN_EID_RSN))
2252f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			continue;
2253f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		prio = roaming_prio(wpa_s, cred2, bss);
2254f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Interworking: roaming_prio=%u for BSS "
2255f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			   MACSTR " (cred=%d)", prio, MAC2STR(bss->bssid),
2256f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			   cred2->id);
2257f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (prio < best_prio) {
2258f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			int bh1, bh2, load1, load2, conn1, conn2;
2259f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			bh1 = cred_below_min_backhaul(wpa_s, cred, selected);
2260f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			load1 = cred_over_max_bss_load(wpa_s, cred, selected);
2261f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			conn1 = cred_conn_capab_missing(wpa_s, cred, selected);
2262f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			bh2 = cred_below_min_backhaul(wpa_s, cred2, bss);
2263f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			load2 = cred_over_max_bss_load(wpa_s, cred2, bss);
2264f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			conn2 = cred_conn_capab_missing(wpa_s, cred2, bss);
2265f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Interworking: old: %d %d %d  new: %d %d %d",
2266f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				   bh1, load1, conn1, bh2, load2, conn2);
2267f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			if (bh1 || load1 || conn1 || !(bh2 || load2 || conn2)) {
2268f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				wpa_printf(MSG_DEBUG, "Interworking: Better roaming partner " MACSTR " selected", MAC2STR(bss->bssid));
2269f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				best_prio = prio;
2270f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				selected = bss;
2271f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			}
2272f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		}
2273f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	}
2274f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
2275f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	return selected;
2276f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt}
2277f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
2278f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
22791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void interworking_select_network(struct wpa_supplicant *wpa_s)
22801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
228104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct wpa_bss *bss, *selected = NULL, *selected_home = NULL;
2282f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	struct wpa_bss *selected2 = NULL, *selected2_home = NULL;
22831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	unsigned int count = 0;
228404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	const char *type;
228504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	int res;
2286f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	struct wpa_cred *cred, *selected_cred = NULL;
2287f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	struct wpa_cred *selected_home_cred = NULL;
2288f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	struct wpa_cred *selected2_cred = NULL;
2289f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	struct wpa_cred *selected2_home_cred = NULL;
22901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
22911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_s->network_select = 0;
22921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2293f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	wpa_printf(MSG_DEBUG, "Interworking: Select network (auto_select=%d)",
2294f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		   wpa_s->auto_select);
22951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
2296f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		int excluded = 0;
2297f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		int bh, bss_load, conn_capab;
2298f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		cred = interworking_credentials_available(wpa_s, bss,
2299f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt							  &excluded);
230004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		if (!cred)
23011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			continue;
230261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) {
230361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			/*
230461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			 * We currently support only HS 2.0 networks and those
230561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			 * are required to use WPA2-Enterprise.
230661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			 */
230761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Interworking: Credential match "
230861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				   "with " MACSTR " but network does not use "
230961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				   "RSN", MAC2STR(bss->bssid));
231061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			continue;
231161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		}
2312f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (!excluded)
2313f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			count++;
23144530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		res = interworking_home_sp(wpa_s, bss->anqp ?
23154530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt					   bss->anqp->domain_name : NULL);
231604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		if (res > 0)
231704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			type = "home";
231804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		else if (res == 0)
231904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			type = "roaming";
232004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		else
232104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			type = "unknown";
2322f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		bh = cred_below_min_backhaul(wpa_s, cred, bss);
2323f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		bss_load = cred_over_max_bss_load(wpa_s, cred, bss);
2324f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		conn_capab = cred_conn_capab_missing(wpa_s, cred, bss);
2325f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpa_msg(wpa_s, MSG_INFO, "%s" MACSTR " type=%s%s%s%s id=%d priority=%d sp_priority=%d",
2326f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			excluded ? INTERWORKING_BLACKLISTED : INTERWORKING_AP,
2327f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			MAC2STR(bss->bssid), type,
2328f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			bh ? " below_min_backhaul=1" : "",
2329f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			bss_load ? " over_max_bss_load=1" : "",
2330f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			conn_capab ? " conn_capab_missing=1" : "",
2331f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			cred->id, cred->priority, cred->sp_priority);
2332f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (excluded)
2333f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			continue;
233461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		if (wpa_s->auto_select ||
233561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		    (wpa_s->conf->auto_interworking &&
233661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		     wpa_s->auto_network_select)) {
2337f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			if (bh || bss_load || conn_capab) {
2338f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				if (selected2_cred == NULL ||
2339f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				    cred_prio_cmp(cred, selected2_cred) > 0) {
2340f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					wpa_printf(MSG_DEBUG, "Interworking: Mark as selected2");
2341f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					selected2 = bss;
2342f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					selected2_cred = cred;
2343f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				}
2344f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				if (res > 0 &&
2345f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				    (selected2_home_cred == NULL ||
2346f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				     cred_prio_cmp(cred, selected2_home_cred) >
2347f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				     0)) {
2348f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					wpa_printf(MSG_DEBUG, "Interworking: Mark as selected2_home");
2349f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					selected2_home = bss;
2350f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					selected2_home_cred = cred;
2351f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				}
2352f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			} else {
2353f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				if (selected_cred == NULL ||
2354f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				    cred_prio_cmp(cred, selected_cred) > 0) {
2355f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					wpa_printf(MSG_DEBUG, "Interworking: Mark as selected");
2356f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					selected = bss;
2357f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					selected_cred = cred;
2358f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				}
2359f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				if (res > 0 &&
2360f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				    (selected_home_cred == NULL ||
2361f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				     cred_prio_cmp(cred, selected_home_cred) >
2362f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				     0)) {
2363f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					wpa_printf(MSG_DEBUG, "Interworking: Mark as selected_home");
2364f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					selected_home = bss;
2365f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					selected_home_cred = cred;
2366f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				}
236704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			}
236804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		}
236904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
237004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
237104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (selected_home && selected_home != selected &&
2372f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	    selected_home_cred &&
2373f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	    (selected_cred == NULL ||
2374f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	     cred_prio_cmp(selected_home_cred, selected_cred) >= 0)) {
237504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		/* Prefer network operated by the Home SP */
2376f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Interworking: Overrided selected with selected_home");
237704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		selected = selected_home;
2378f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		selected_cred = selected_home_cred;
2379f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	}
2380f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
2381f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (!selected) {
2382f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (selected2_home) {
2383f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Interworking: Use home BSS with BW limit mismatch since no other network could be selected");
2384f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			selected = selected2_home;
2385f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			selected_cred = selected2_home_cred;
2386f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		} else if (selected2) {
2387f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Interworking: Use visited BSS with BW limit mismatch since no other network could be selected");
2388f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			selected = selected2;
2389f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			selected_cred = selected2_cred;
2390f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		}
23911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
23921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
23931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (count == 0) {
239404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		/*
239504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		 * No matching network was found based on configured
239604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		 * credentials. Check whether any of the enabled network blocks
239704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		 * have matching APs.
239804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		 */
239904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		if (interworking_find_network_match(wpa_s)) {
240004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			wpa_printf(MSG_DEBUG, "Interworking: Possible BSS "
240104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				   "match for enabled network configurations");
2402717574375e969e8272c6d1a26137286eac158abbDmitry Shmidt			if (wpa_s->auto_select) {
240361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				interworking_reconnect(wpa_s);
2404717574375e969e8272c6d1a26137286eac158abbDmitry Shmidt				return;
2405717574375e969e8272c6d1a26137286eac158abbDmitry Shmidt			}
240661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		}
240761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
240861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		if (wpa_s->auto_network_select) {
240961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Interworking: Continue "
241061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				   "scanning after ANQP fetch");
241161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			wpa_supplicant_req_scan(wpa_s, wpa_s->scan_interval,
241261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt						0);
241304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			return;
241404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		}
241504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
24161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_msg(wpa_s, MSG_INFO, INTERWORKING_NO_MATCH "No network "
24171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			"with matching credentials found");
24181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
24191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2420f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (selected) {
2421f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Interworking: Selected " MACSTR,
2422f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			   MAC2STR(selected->bssid));
2423f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		selected = pick_best_roaming_partner(wpa_s, selected,
2424f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt						     selected_cred);
2425f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Interworking: Selected " MACSTR
2426f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			   " (after best roaming partner selection)",
2427f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			   MAC2STR(selected->bssid));
2428f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpa_msg(wpa_s, MSG_INFO, INTERWORKING_SELECTED MACSTR,
2429f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			MAC2STR(selected->bssid));
24301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		interworking_connect(wpa_s, selected);
2431f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	}
24321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
24331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
24341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
24354530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidtstatic struct wpa_bss_anqp *
24364530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidtinterworking_match_anqp_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
24374530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt{
24384530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	struct wpa_bss *other;
24394530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
24404530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (is_zero_ether_addr(bss->hessid))
24414530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		return NULL; /* Cannot be in the same homegenous ESS */
24424530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
24434530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	dl_list_for_each(other, &wpa_s->bss, struct wpa_bss, list) {
24444530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		if (other == bss)
24454530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			continue;
24464530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		if (other->anqp == NULL)
24474530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			continue;
2448a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		if (other->anqp->roaming_consortium == NULL &&
2449a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		    other->anqp->nai_realm == NULL &&
2450a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		    other->anqp->anqp_3gpp == NULL &&
2451a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		    other->anqp->domain_name == NULL)
2452a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			continue;
24534530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		if (!(other->flags & WPA_BSS_ANQP_FETCH_TRIED))
24544530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			continue;
24554530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		if (os_memcmp(bss->hessid, other->hessid, ETH_ALEN) != 0)
24564530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			continue;
24574530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		if (bss->ssid_len != other->ssid_len ||
24584530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		    os_memcmp(bss->ssid, other->ssid, bss->ssid_len) != 0)
24594530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			continue;
24604530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
24614530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Interworking: Share ANQP data with "
24624530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			   "already fetched BSSID " MACSTR " and " MACSTR,
24634530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			   MAC2STR(other->bssid), MAC2STR(bss->bssid));
24644530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		other->anqp->users++;
24654530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		return other->anqp;
24664530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	}
24674530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
24684530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	return NULL;
24694530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt}
24704530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
24714530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
24721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
24731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
24741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_bss *bss;
24751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int found = 0;
24761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	const u8 *ie;
24771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2478f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	wpa_printf(MSG_DEBUG, "Interworking: next_anqp_fetch - "
2479f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		   "fetch_anqp_in_progress=%d fetch_osu_icon_in_progress=%d",
2480f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		   wpa_s->fetch_anqp_in_progress,
2481f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		   wpa_s->fetch_osu_icon_in_progress);
2482f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
2483f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (eloop_terminated() || !wpa_s->fetch_anqp_in_progress) {
2484f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Interworking: Stop next-ANQP-fetch");
2485f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		return;
2486f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	}
2487f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
2488f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (wpa_s->fetch_osu_icon_in_progress) {
2489f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Interworking: Next icon (in progress)");
2490f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		hs20_next_osu_icon(wpa_s);
24911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
2492f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	}
24931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
24941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
24951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (!(bss->caps & IEEE80211_CAP_ESS))
24961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			continue;
24971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB);
24981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (ie == NULL || ie[1] < 4 || !(ie[5] & 0x80))
24991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			continue; /* AP does not support Interworking */
25005460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt		if (disallowed_bssid(wpa_s, bss->bssid) ||
25015460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt		    disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len))
25025460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt			continue; /* Disallowed BSS */
25031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
25041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (!(bss->flags & WPA_BSS_ANQP_FETCH_TRIED)) {
25054530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			if (bss->anqp == NULL) {
25064530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt				bss->anqp = interworking_match_anqp_info(wpa_s,
25074530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt									 bss);
25084530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt				if (bss->anqp) {
25094530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt					/* Shared data already fetched */
25104530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt					continue;
25114530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt				}
25124530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt				bss->anqp = wpa_bss_anqp_alloc();
25134530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt				if (bss->anqp == NULL)
25144530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt					break;
25154530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			}
25161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			found++;
25171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			bss->flags |= WPA_BSS_ANQP_FETCH_TRIED;
25181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_msg(wpa_s, MSG_INFO, "Starting ANQP fetch for "
25191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				MACSTR, MAC2STR(bss->bssid));
25201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			interworking_anqp_send_req(wpa_s, bss);
25211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
25221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
25231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
25241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
25251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (found == 0) {
2526f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (wpa_s->fetch_osu_info) {
2527f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			if (wpa_s->num_prov_found == 0 &&
2528f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			    wpa_s->num_osu_scans < 3) {
2529f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				wpa_printf(MSG_DEBUG, "HS 2.0: No OSU providers seen - try to scan again");
2530f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				hs20_start_osu_scan(wpa_s);
2531f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				return;
2532f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			}
2533f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Interworking: Next icon");
2534f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			hs20_osu_icon_fetch(wpa_s);
2535f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			return;
2536f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		}
25371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_msg(wpa_s, MSG_INFO, "ANQP fetch completed");
25381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_s->fetch_anqp_in_progress = 0;
25391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (wpa_s->network_select)
25401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			interworking_select_network(wpa_s);
25411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
25421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
25431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
25441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
254561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtvoid interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s)
25461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
25471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_bss *bss;
25481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
25491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list)
25501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		bss->flags &= ~WPA_BSS_ANQP_FETCH_TRIED;
25511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
25521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_s->fetch_anqp_in_progress = 1;
25531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	interworking_next_anqp_fetch(wpa_s);
25541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
25551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
25561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
25571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtint interworking_fetch_anqp(struct wpa_supplicant *wpa_s)
25581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
25591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (wpa_s->fetch_anqp_in_progress || wpa_s->network_select)
25601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return 0;
25611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
25621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_s->network_select = 0;
25634530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	wpa_s->fetch_all_anqp = 1;
2564f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	wpa_s->fetch_osu_info = 0;
25651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
25661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	interworking_start_fetch_anqp(wpa_s);
25671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
25681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return 0;
25691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
25701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
25711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
25721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtvoid interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s)
25731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
25741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!wpa_s->fetch_anqp_in_progress)
25751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
25761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
25771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_s->fetch_anqp_in_progress = 0;
25781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
25791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
25801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
25811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtint anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
258215907098d1f67c24bb000e593e279af173cf57d7Dmitry Shmidt		  u16 info_ids[], size_t num_ids, u32 subtypes)
25831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
25841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpabuf *buf;
258515907098d1f67c24bb000e593e279af173cf57d7Dmitry Shmidt	struct wpabuf *hs20_buf = NULL;
25861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int ret = 0;
25871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int freq;
25881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_bss *bss;
25891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int res;
25901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
25911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	freq = wpa_s->assoc_freq;
25921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	bss = wpa_bss_get_bssid(wpa_s, dst);
2593d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	if (bss) {
2594d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		wpa_bss_anqp_unshare_alloc(bss);
25951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		freq = bss->freq;
2596d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	}
25971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (freq <= 0)
25981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
25991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
26001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_printf(MSG_DEBUG, "ANQP: Query Request to " MACSTR " for %u id(s)",
26011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		   MAC2STR(dst), (unsigned int) num_ids);
26021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
260315907098d1f67c24bb000e593e279af173cf57d7Dmitry Shmidt#ifdef CONFIG_HS20
260415907098d1f67c24bb000e593e279af173cf57d7Dmitry Shmidt	if (subtypes != 0) {
260515907098d1f67c24bb000e593e279af173cf57d7Dmitry Shmidt		hs20_buf = wpabuf_alloc(100);
260615907098d1f67c24bb000e593e279af173cf57d7Dmitry Shmidt		if (hs20_buf == NULL)
260715907098d1f67c24bb000e593e279af173cf57d7Dmitry Shmidt			return -1;
260815907098d1f67c24bb000e593e279af173cf57d7Dmitry Shmidt		hs20_put_anqp_req(subtypes, NULL, 0, hs20_buf);
260915907098d1f67c24bb000e593e279af173cf57d7Dmitry Shmidt	}
261015907098d1f67c24bb000e593e279af173cf57d7Dmitry Shmidt#endif /* CONFIG_HS20 */
261115907098d1f67c24bb000e593e279af173cf57d7Dmitry Shmidt
261215907098d1f67c24bb000e593e279af173cf57d7Dmitry Shmidt	buf = anqp_build_req(info_ids, num_ids, hs20_buf);
261315907098d1f67c24bb000e593e279af173cf57d7Dmitry Shmidt	wpabuf_free(hs20_buf);
26141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (buf == NULL)
26151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
26161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
26171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
26181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (res < 0) {
26191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
2620051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpabuf_free(buf);
26211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		ret = -1;
26221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	} else
26231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
26241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "%u", res);
26251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
26261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return ret;
26271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
26281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
26291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
26301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
2631444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt					    struct wpa_bss *bss, const u8 *sa,
2632444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt					    u16 info_id,
26331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					    const u8 *data, size_t slen)
26341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
26351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	const u8 *pos = data;
26364530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	struct wpa_bss_anqp *anqp = NULL;
263704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#ifdef CONFIG_HS20
263804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	u8 type;
263904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#endif /* CONFIG_HS20 */
26401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
26414530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (bss)
26424530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		anqp = bss->anqp;
26434530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
26441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	switch (info_id) {
26451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case ANQP_CAPABILITY_LIST:
26461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
26471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			" ANQP Capability list", MAC2STR(sa));
26481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
26491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case ANQP_VENUE_NAME:
26501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
26511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			" Venue Name", MAC2STR(sa));
26521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Venue Name", pos, slen);
26534530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		if (anqp) {
26544530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			wpabuf_free(anqp->venue_name);
26554530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			anqp->venue_name = wpabuf_alloc_copy(pos, slen);
26561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
26571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
26581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case ANQP_NETWORK_AUTH_TYPE:
26591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
26601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			" Network Authentication Type information",
26611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			MAC2STR(sa));
26621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Network Authentication "
26631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				  "Type", pos, slen);
26644530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		if (anqp) {
26654530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			wpabuf_free(anqp->network_auth_type);
26664530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			anqp->network_auth_type = wpabuf_alloc_copy(pos, slen);
26671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
26681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
26691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case ANQP_ROAMING_CONSORTIUM:
26701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
26711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			" Roaming Consortium list", MAC2STR(sa));
26721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Roaming Consortium",
26731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				  pos, slen);
26744530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		if (anqp) {
26754530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			wpabuf_free(anqp->roaming_consortium);
26764530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			anqp->roaming_consortium = wpabuf_alloc_copy(pos, slen);
26771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
26781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
26791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case ANQP_IP_ADDR_TYPE_AVAILABILITY:
26801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
26811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			" IP Address Type Availability information",
26821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			MAC2STR(sa));
26831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_hexdump(MSG_MSGDUMP, "ANQP: IP Address Availability",
26841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			    pos, slen);
26854530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		if (anqp) {
26864530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			wpabuf_free(anqp->ip_addr_type_availability);
26874530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			anqp->ip_addr_type_availability =
26881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				wpabuf_alloc_copy(pos, slen);
26891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
26901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
26911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case ANQP_NAI_REALM:
26921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
26931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			" NAI Realm list", MAC2STR(sa));
26941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_hexdump_ascii(MSG_DEBUG, "ANQP: NAI Realm", pos, slen);
26954530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		if (anqp) {
26964530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			wpabuf_free(anqp->nai_realm);
26974530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			anqp->nai_realm = wpabuf_alloc_copy(pos, slen);
26981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
26991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
27001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case ANQP_3GPP_CELLULAR_NETWORK:
27011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
27021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			" 3GPP Cellular Network information", MAC2STR(sa));
27031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_hexdump_ascii(MSG_DEBUG, "ANQP: 3GPP Cellular Network",
27041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				  pos, slen);
27054530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		if (anqp) {
27064530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			wpabuf_free(anqp->anqp_3gpp);
27074530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			anqp->anqp_3gpp = wpabuf_alloc_copy(pos, slen);
27081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
27091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
27101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case ANQP_DOMAIN_NAME:
27111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
27121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			" Domain Name list", MAC2STR(sa));
27131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_hexdump_ascii(MSG_MSGDUMP, "ANQP: Domain Name", pos, slen);
27144530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		if (anqp) {
27154530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			wpabuf_free(anqp->domain_name);
27164530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			anqp->domain_name = wpabuf_alloc_copy(pos, slen);
27171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
27181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
27191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case ANQP_VENDOR_SPECIFIC:
27201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (slen < 3)
27211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			return;
27221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
27231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		switch (WPA_GET_BE24(pos)) {
272404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#ifdef CONFIG_HS20
272504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		case OUI_WFA:
272604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			pos += 3;
272704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			slen -= 3;
272804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
272904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			if (slen < 1)
273004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				return;
273104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			type = *pos++;
273204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			slen--;
273304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
273404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			switch (type) {
273504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			case HS20_ANQP_OUI_TYPE:
273604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				hs20_parse_rx_hs20_anqp_resp(wpa_s, sa, pos,
273704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt							     slen);
273804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				break;
273904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			default:
274004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				wpa_printf(MSG_DEBUG, "HS20: Unsupported ANQP "
274104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt					   "vendor type %u", type);
274204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				break;
274304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			}
274404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			break;
274504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#endif /* CONFIG_HS20 */
27461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		default:
27471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_printf(MSG_DEBUG, "Interworking: Unsupported "
27481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   "vendor-specific ANQP OUI %06x",
27491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   WPA_GET_BE24(pos));
27501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			return;
27511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
27521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
27531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	default:
27541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "Interworking: Unsupported ANQP Info ID "
27551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "%u", info_id);
27561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
27571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
27581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
27591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
27601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
27611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtvoid anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
27621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		  enum gas_query_result result,
27631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		  const struct wpabuf *adv_proto,
27641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		  const struct wpabuf *resp, u16 status_code)
27651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
27661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_supplicant *wpa_s = ctx;
27671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	const u8 *pos;
27681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	const u8 *end;
27691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u16 info_id;
27701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u16 slen;
2771444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	struct wpa_bss *bss = NULL, *tmp;
27721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2773f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	wpa_printf(MSG_DEBUG, "Interworking: anqp_resp_cb dst=" MACSTR
2774f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		   " dialog_token=%u result=%d status_code=%u",
2775f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		   MAC2STR(dst), dialog_token, result, status_code);
2776f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (result != GAS_QUERY_SUCCESS) {
2777f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (wpa_s->fetch_osu_icon_in_progress)
2778f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			hs20_icon_fetch_failed(wpa_s);
27791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
2780f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	}
27811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
27821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	pos = wpabuf_head(adv_proto);
27831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (wpabuf_len(adv_proto) < 4 || pos[0] != WLAN_EID_ADV_PROTO ||
27841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	    pos[1] < 2 || pos[3] != ACCESS_NETWORK_QUERY_PROTOCOL) {
27851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "ANQP: Unexpected Advertisement "
27861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "Protocol in response");
2787f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (wpa_s->fetch_osu_icon_in_progress)
2788f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			hs20_icon_fetch_failed(wpa_s);
27891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
27901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
27911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2792444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	/*
2793444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	 * If possible, select the BSS entry based on which BSS entry was used
2794444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	 * for the request. This can help in cases where multiple BSS entries
2795444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	 * may exist for the same AP.
2796444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	 */
2797444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	dl_list_for_each_reverse(tmp, &wpa_s->bss, struct wpa_bss, list) {
2798444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt		if (tmp == wpa_s->interworking_gas_bss &&
2799444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt		    os_memcmp(tmp->bssid, dst, ETH_ALEN) == 0) {
2800444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt			bss = tmp;
2801444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt			break;
2802444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt		}
2803444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	}
2804444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	if (bss == NULL)
2805444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt		bss = wpa_bss_get_bssid(wpa_s, dst);
2806444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt
28071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	pos = wpabuf_head(resp);
28081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	end = pos + wpabuf_len(resp);
28091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
28101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	while (pos < end) {
28111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (pos + 4 > end) {
28121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_printf(MSG_DEBUG, "ANQP: Invalid element");
28131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
28141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
28151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		info_id = WPA_GET_LE16(pos);
28161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		pos += 2;
28171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		slen = WPA_GET_LE16(pos);
28181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		pos += 2;
28191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (pos + slen > end) {
28201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_printf(MSG_DEBUG, "ANQP: Invalid element length "
28211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   "for Info ID %u", info_id);
28221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
28231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
2824444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt		interworking_parse_rx_anqp_resp(wpa_s, bss, dst, info_id, pos,
28251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt						slen);
28261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		pos += slen;
28271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
2828f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
2829f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	hs20_notify_parse_done(wpa_s);
28301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
28311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
28321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
28331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void interworking_scan_res_handler(struct wpa_supplicant *wpa_s,
28341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					  struct wpa_scan_results *scan_res)
28351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
28361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_printf(MSG_DEBUG, "Interworking: Scan results available - start "
28371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		   "ANQP fetch");
28381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	interworking_start_fetch_anqp(wpa_s);
28391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
28401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
28411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2842fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidtint interworking_select(struct wpa_supplicant *wpa_s, int auto_select,
2843fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			int *freqs)
28441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
28451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	interworking_stop_fetch_anqp(wpa_s);
28461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_s->network_select = 1;
284761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpa_s->auto_network_select = 0;
28481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_s->auto_select = !!auto_select;
28494530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	wpa_s->fetch_all_anqp = 0;
2850f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	wpa_s->fetch_osu_info = 0;
28511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_printf(MSG_DEBUG, "Interworking: Start scan for network "
28521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		   "selection");
28531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_s->scan_res_handler = interworking_scan_res_handler;
285468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	wpa_s->normal_scans = 0;
2855d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	wpa_s->scan_req = MANUAL_SCAN_REQ;
2856fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	os_free(wpa_s->manual_scan_freqs);
2857fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	wpa_s->manual_scan_freqs = freqs;
285868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	wpa_s->after_wps = 0;
285968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	wpa_s->known_wps_freq = 0;
28601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_supplicant_req_scan(wpa_s, 0, 0);
28611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
28621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return 0;
28631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
286461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
286561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
286661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
286761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			enum gas_query_result result,
286861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			const struct wpabuf *adv_proto,
286961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			const struct wpabuf *resp, u16 status_code)
287061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
287161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	struct wpa_supplicant *wpa_s = ctx;
2872fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	struct wpabuf *n;
287361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
287461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpa_msg(wpa_s, MSG_INFO, GAS_RESPONSE_INFO "addr=" MACSTR
287561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		" dialog_token=%d status_code=%d resp_len=%d",
287661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		MAC2STR(addr), dialog_token, status_code,
287761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		resp ? (int) wpabuf_len(resp) : -1);
287861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (!resp)
287961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return;
288061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
2881fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	n = wpabuf_dup(resp);
2882fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (n == NULL)
288361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return;
2884fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	wpabuf_free(wpa_s->prev_gas_resp);
2885fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	wpa_s->prev_gas_resp = wpa_s->last_gas_resp;
2886fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	os_memcpy(wpa_s->prev_gas_addr, wpa_s->last_gas_addr, ETH_ALEN);
2887fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	wpa_s->prev_gas_dialog_token = wpa_s->last_gas_dialog_token;
2888fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	wpa_s->last_gas_resp = n;
288961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	os_memcpy(wpa_s->last_gas_addr, addr, ETH_ALEN);
289061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpa_s->last_gas_dialog_token = dialog_token;
289161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
289261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
289361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
289461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtint gas_send_request(struct wpa_supplicant *wpa_s, const u8 *dst,
289561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		     const struct wpabuf *adv_proto,
289661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		     const struct wpabuf *query)
289761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
289861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	struct wpabuf *buf;
289961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	int ret = 0;
290061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	int freq;
290161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	struct wpa_bss *bss;
290261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	int res;
290361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	size_t len;
29047f0b69e88015ca077ef7a417fde0a76c10df23a5Dmitry Shmidt	u8 query_resp_len_limit = 0;
290561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
290661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	freq = wpa_s->assoc_freq;
290761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	bss = wpa_bss_get_bssid(wpa_s, dst);
290861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (bss)
290961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		freq = bss->freq;
291061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (freq <= 0)
291161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return -1;
291261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
291361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpa_printf(MSG_DEBUG, "GAS request to " MACSTR " (freq %d MHz)",
291461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		   MAC2STR(dst), freq);
291561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpa_hexdump_buf(MSG_DEBUG, "Advertisement Protocol ID", adv_proto);
291661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpa_hexdump_buf(MSG_DEBUG, "GAS Query", query);
291761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
291861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	len = 3 + wpabuf_len(adv_proto) + 2;
291961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (query)
292061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		len += wpabuf_len(query);
292161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	buf = gas_build_initial_req(0, len);
292261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (buf == NULL)
292361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return -1;
292461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
292561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	/* Advertisement Protocol IE */
292661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
292761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpabuf_put_u8(buf, 1 + wpabuf_len(adv_proto)); /* Length */
29287f0b69e88015ca077ef7a417fde0a76c10df23a5Dmitry Shmidt	wpabuf_put_u8(buf, query_resp_len_limit & 0x7f);
292961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpabuf_put_buf(buf, adv_proto);
293061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
293161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	/* GAS Query */
293261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (query) {
293361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_le16(buf, wpabuf_len(query));
293461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_buf(buf, query);
293561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	} else
293661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_le16(buf, 0);
293761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
293861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	res = gas_query_req(wpa_s->gas, dst, freq, buf, gas_resp_cb, wpa_s);
293961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (res < 0) {
294061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpa_printf(MSG_DEBUG, "GAS: Failed to send Query Request");
2941051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpabuf_free(buf);
294261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		ret = -1;
294361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	} else
294461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpa_printf(MSG_DEBUG, "GAS: Query started with dialog token "
294561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			   "%u", res);
294661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
294761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	return ret;
294861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
2949