#endif
static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s);
+static struct wpa_cred * interworking_credentials_available_realm(
+ struct wpa_supplicant *wpa_s, struct wpa_bss *bss);
+static struct wpa_cred * interworking_credentials_available_3gpp(
+ struct wpa_supplicant *wpa_s, struct wpa_bss *bss);
static void interworking_reconnect(struct wpa_supplicant *wpa_s)
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
- if (wpa_s->last_scan_res_used > 0) {
- struct os_time now;
- os_get_time(&now);
- if (now.sec - wpa_s->last_scan.sec <= 5) {
- wpa_printf(MSG_DEBUG, "Interworking: Old scan results "
- "are fresh - connect without new scan");
- if (wpas_select_network_from_last_scan(wpa_s) >= 0)
- return;
- }
- }
+ if (wpa_supplicant_fast_associate(wpa_s) >= 0)
+ return;
wpa_supplicant_req_scan(wpa_s, 0, 0);
}
wpa_printf(MSG_DEBUG, "Interworking: ANQP Query Request to " MACSTR,
MAC2STR(bss->bssid));
+ wpa_s->interworking_gas_bss = bss;
info_ids[num_info_ids++] = ANQP_CAPABILITY_LIST;
if (all) {
return NULL;
}
wpa_hexdump_ascii(MSG_DEBUG, "NAI Realm", pos, realm_len);
- r->realm = os_malloc(realm_len + 1);
+ r->realm = dup_binstr(pos, realm_len);
if (r->realm == NULL)
return NULL;
- os_memcpy(r->realm, pos, realm_len);
- r->realm[realm_len] = '\0';
pos += realm_len;
if (pos + 1 > f_end) {
static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
+ struct wpa_cred *cred,
struct wpa_bss *bss)
{
#ifdef INTERWORKING_3GPP
- struct wpa_cred *cred;
struct wpa_ssid *ssid;
const u8 *ie;
int eap_type;
if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
return -1;
- for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
- char *sep;
- const char *imsi;
- int mnc_len;
-
-#ifdef PCSC_FUNCS
- if (cred->pcsc && wpa_s->conf->pcsc_reader && wpa_s->scard &&
- wpa_s->imsi[0]) {
- imsi = wpa_s->imsi;
- mnc_len = wpa_s->mnc_len;
- goto compare;
- }
-#endif /* PCSC_FUNCS */
-
- if (cred->imsi == NULL || !cred->imsi[0] ||
- cred->milenage == NULL || !cred->milenage[0])
- continue;
-
- sep = os_strchr(cred->imsi, '-');
- if (sep == NULL ||
- (sep - cred->imsi != 5 && sep - cred->imsi != 6))
- continue;
- mnc_len = sep - cred->imsi - 3;
- imsi = cred->imsi;
-
-#ifdef PCSC_FUNCS
- compare:
-#endif /* PCSC_FUNCS */
- if (plmn_id_match(bss->anqp->anqp_3gpp, imsi, mnc_len))
- break;
- }
- if (cred == NULL)
- return -1;
-
ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
if (ie == NULL)
return -1;
int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
{
- struct wpa_cred *cred;
+ struct wpa_cred *cred, *cred_rc, *cred_3gpp;
struct wpa_ssid *ssid;
struct nai_realm *realm;
struct nai_realm_eap *eap = NULL;
return -1;
}
- cred = interworking_credentials_available_roaming_consortium(wpa_s,
- bss);
- if (cred)
- return interworking_connect_roaming_consortium(wpa_s, cred,
+ cred_rc = interworking_credentials_available_roaming_consortium(wpa_s,
+ bss);
+ if (cred_rc) {
+ wpa_printf(MSG_DEBUG, "Interworking: Highest roaming "
+ "consortium matching credential priority %d",
+ cred_rc->priority);
+ }
+
+ cred = interworking_credentials_available_realm(wpa_s, bss);
+ if (cred) {
+ wpa_printf(MSG_DEBUG, "Interworking: Highest NAI Realm list "
+ "matching credential priority %d",
+ cred->priority);
+ }
+
+ cred_3gpp = interworking_credentials_available_3gpp(wpa_s, bss);
+ if (cred_3gpp) {
+ wpa_printf(MSG_DEBUG, "Interworking: Highest 3GPP matching "
+ "credential priority %d", cred_3gpp->priority);
+ }
+
+ if (cred_rc &&
+ (cred == NULL || cred_rc->priority >= cred->priority) &&
+ (cred_3gpp == NULL || cred_rc->priority >= cred_3gpp->priority))
+ return interworking_connect_roaming_consortium(wpa_s, cred_rc,
bss, ie);
+ if (cred_3gpp &&
+ (cred == NULL || cred_3gpp->priority >= cred->priority)) {
+ return interworking_connect_3gpp(wpa_s, cred_3gpp, bss);
+ }
+
+ if (cred == NULL) {
+ wpa_printf(MSG_DEBUG, "Interworking: No matching credentials "
+ "found for " MACSTR, MAC2STR(bss->bssid));
+ return -1;
+ }
+
realm = nai_realm_parse(bss->anqp ? bss->anqp->nai_realm : NULL,
&count);
if (realm == NULL) {
wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
"Realm list from " MACSTR, MAC2STR(bss->bssid));
- count = 0;
+ return -1;
}
- for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
- for (i = 0; i < count; i++) {
- if (!nai_realm_match(&realm[i], cred->realm))
- continue;
- eap = nai_realm_find_eap(cred, &realm[i]);
- if (eap)
- break;
- }
+ for (i = 0; i < count; i++) {
+ if (!nai_realm_match(&realm[i], cred->realm))
+ continue;
+ eap = nai_realm_find_eap(cred, &realm[i]);
if (eap)
break;
}
if (!eap) {
- if (interworking_connect_3gpp(wpa_s, bss) == 0) {
- if (realm)
- nai_realm_free(realm, count);
- return 0;
- }
-
wpa_printf(MSG_DEBUG, "Interworking: No matching credentials "
"and EAP method found for " MACSTR,
MAC2STR(bss->bssid));
static struct wpa_cred * interworking_credentials_available_3gpp(
struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
{
- struct wpa_cred *cred, *selected = NULL;
+ struct wpa_cred *selected = NULL;
+#ifdef INTERWORKING_3GPP
+ struct wpa_cred *cred;
int ret;
-#ifdef INTERWORKING_3GPP
if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
return NULL;
goto compare;
}
#endif /* PCSC_FUNCS */
+#ifdef CONFIG_EAP_PROXY
+ if (cred->pcsc && wpa_s->mnc_len > 0 && wpa_s->imsi[0]) {
+ imsi = wpa_s->imsi;
+ mnc_len = wpa_s->mnc_len;
+ goto compare;
+ }
+#endif /* CONFIG_EAP_PROXY */
if (cred->imsi == NULL || !cred->imsi[0] ||
cred->milenage == NULL || !cred->milenage[0])
mnc_len = sep - cred->imsi - 3;
imsi = cred->imsi;
-#ifdef PCSC_FUNCS
+#if defined(PCSC_FUNCS) || defined(CONFIG_EAP_PROXY)
compare:
-#endif /* PCSC_FUNCS */
+#endif /* PCSC_FUNCS || CONFIG_EAP_PROXY */
wpa_printf(MSG_DEBUG, "Interworking: Parsing 3GPP info from "
MACSTR, MAC2STR(bss->bssid));
ret = plmn_id_match(bss->anqp->anqp_3gpp, imsi, mnc_len);
static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
- const u8 *sa, u16 info_id,
+ struct wpa_bss *bss, const u8 *sa,
+ u16 info_id,
const u8 *data, size_t slen)
{
const u8 *pos = data;
- struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa);
struct wpa_bss_anqp *anqp = NULL;
#ifdef CONFIG_HS20
u8 type;
const u8 *end;
u16 info_id;
u16 slen;
+ struct wpa_bss *bss = NULL, *tmp;
if (result != GAS_QUERY_SUCCESS)
return;
return;
}
+ /*
+ * If possible, select the BSS entry based on which BSS entry was used
+ * for the request. This can help in cases where multiple BSS entries
+ * may exist for the same AP.
+ */
+ dl_list_for_each_reverse(tmp, &wpa_s->bss, struct wpa_bss, list) {
+ if (tmp == wpa_s->interworking_gas_bss &&
+ os_memcmp(tmp->bssid, dst, ETH_ALEN) == 0) {
+ bss = tmp;
+ break;
+ }
+ }
+ if (bss == NULL)
+ bss = wpa_bss_get_bssid(wpa_s, dst);
+
pos = wpabuf_head(resp);
end = pos + wpabuf_len(resp);
"for Info ID %u", info_id);
break;
}
- interworking_parse_rx_anqp_resp(wpa_s, dst, info_id, pos,
+ interworking_parse_rx_anqp_resp(wpa_s, bss, dst, info_id, pos,
slen);
pos += slen;
}