diff options
Diffstat (limited to 'wpa_supplicant/interworking.c')
-rw-r--r-- | wpa_supplicant/interworking.c | 163 |
1 files changed, 133 insertions, 30 deletions
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c index 1fb40c74e5cf9..60c8be9a6c6a5 100644 --- a/wpa_supplicant/interworking.c +++ b/wpa_supplicant/interworking.c @@ -106,10 +106,12 @@ static struct wpabuf * anqp_build_req(u16 info_ids[], size_t num_ids, if (buf == NULL) return NULL; - len_pos = gas_anqp_add_element(buf, ANQP_QUERY_LIST); - for (i = 0; i < num_ids; i++) - wpabuf_put_le16(buf, info_ids[i]); - gas_anqp_set_element_len(buf, len_pos); + if (num_ids > 0) { + len_pos = gas_anqp_add_element(buf, ANQP_QUERY_LIST); + for (i = 0; i < num_ids; i++) + wpabuf_put_le16(buf, info_ids[i]); + gas_anqp_set_element_len(buf, len_pos); + } if (extra) wpabuf_put_buf(buf, extra); @@ -146,6 +148,8 @@ static int cred_with_roaming_consortium(struct wpa_supplicant *wpa_s) return 1; if (cred->required_roaming_consortium_len) return 1; + if (cred->num_roaming_consortiums) + return 1; } return 0; } @@ -299,8 +303,10 @@ static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s, wpabuf_put_u8(extra, HS20_STYPE_CONNECTION_CAPABILITY); if (all) wpabuf_put_u8(extra, HS20_STYPE_OPERATING_CLASS); - if (all) + if (all) { wpabuf_put_u8(extra, HS20_STYPE_OSU_PROVIDERS_LIST); + wpabuf_put_u8(extra, HS20_STYPE_OSU_PROVIDERS_NAI_LIST); + } gas_anqp_set_element_len(extra, len_pos); } #endif /* CONFIG_HS20 */ @@ -310,7 +316,7 @@ static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s, if (buf == NULL) return -1; - res = gas_query_req(wpa_s->gas, bss->bssid, bss->freq, buf, + res = gas_query_req(wpa_s->gas, bss->bssid, bss->freq, 0, buf, interworking_anqp_resp_cb, wpa_s); if (res < 0) { wpa_msg(wpa_s, MSG_DEBUG, "ANQP: Failed to send Query Request"); @@ -1143,6 +1149,23 @@ static int roaming_consortium_match(const u8 *ie, const struct wpabuf *anqp, } +static int cred_roaming_consortiums_match(const u8 *ie, + const struct wpabuf *anqp, + const struct wpa_cred *cred) +{ + unsigned int i; + + for (i = 0; i < cred->num_roaming_consortiums; i++) { + if (roaming_consortium_match(ie, anqp, + cred->roaming_consortiums[i], + cred->roaming_consortiums_len[i])) + return 1; + } + + return 0; +} + + static int cred_no_required_oi_match(struct wpa_cred *cred, struct wpa_bss *bss) { const u8 *ie; @@ -1347,27 +1370,28 @@ static struct wpa_cred * interworking_credentials_available_roaming_consortium( { struct wpa_cred *cred, *selected = NULL; const u8 *ie; + const struct wpabuf *anqp; int is_excluded = 0; ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM); + anqp = bss->anqp ? bss->anqp->roaming_consortium : NULL; - if (ie == NULL && - (bss->anqp == NULL || bss->anqp->roaming_consortium == NULL)) + if (!ie && !anqp) return NULL; if (wpa_s->conf->cred == NULL) return NULL; for (cred = wpa_s->conf->cred; cred; cred = cred->next) { - if (cred->roaming_consortium_len == 0) + if (cred->roaming_consortium_len == 0 && + cred->num_roaming_consortiums == 0) continue; - if (!roaming_consortium_match(ie, - bss->anqp ? - bss->anqp->roaming_consortium : - NULL, - cred->roaming_consortium, - cred->roaming_consortium_len)) + if ((cred->roaming_consortium_len == 0 || + !roaming_consortium_match(ie, anqp, + cred->roaming_consortium, + cred->roaming_consortium_len)) && + !cred_roaming_consortiums_match(ie, anqp, cred)) continue; if (cred_no_required_oi_match(cred, bss)) @@ -1533,6 +1557,9 @@ static int interworking_connect_roaming_consortium( struct wpa_bss *bss, int only_add) { struct wpa_ssid *ssid; + const u8 *ie; + const struct wpabuf *anqp; + unsigned int i; wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Connect with " MACSTR " based on roaming consortium match", MAC2STR(bss->bssid)); @@ -1562,6 +1589,26 @@ static int interworking_connect_roaming_consortium( if (interworking_set_hs20_params(wpa_s, ssid) < 0) goto fail; + ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM); + anqp = bss->anqp ? bss->anqp->roaming_consortium : NULL; + for (i = 0; (ie || anqp) && i < cred->num_roaming_consortiums; i++) { + if (!roaming_consortium_match( + ie, anqp, cred->roaming_consortiums[i], + cred->roaming_consortiums_len[i])) + continue; + + ssid->roaming_consortium_selection = + os_malloc(cred->roaming_consortiums_len[i]); + if (!ssid->roaming_consortium_selection) + goto fail; + os_memcpy(ssid->roaming_consortium_selection, + cred->roaming_consortiums[i], + cred->roaming_consortiums_len[i]); + ssid->roaming_consortium_selection_len = + cred->roaming_consortiums_len[i]; + break; + } + if (cred->eap_method == NULL) { wpa_msg(wpa_s, MSG_DEBUG, "Interworking: No EAP method set for credential using roaming consortium"); @@ -1769,9 +1816,10 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, switch (eap->method) { case EAP_TYPE_TTLS: if (eap->inner_method) { - os_snprintf(buf, sizeof(buf), "\"autheap=%s\"", - eap_get_name(EAP_VENDOR_IETF, - eap->inner_method)); + name = eap_get_name(EAP_VENDOR_IETF, eap->inner_method); + if (!name) + goto fail; + os_snprintf(buf, sizeof(buf), "\"autheap=%s\"", name); if (wpa_config_set(ssid, "phase2", buf, 0) < 0) goto fail; break; @@ -1894,7 +1942,7 @@ static struct wpa_cred * interworking_credentials_available_3gpp( size_t len; wpa_msg(wpa_s, MSG_DEBUG, "Interworking: IMSI not available - try to read again through eap_proxy"); - wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol, + wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol, -1, wpa_s->imsi, &len); if (wpa_s->mnc_len > 0) { @@ -2530,7 +2578,8 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s) wpa_msg(wpa_s, MSG_INFO, INTERWORKING_SELECTED MACSTR, MAC2STR(selected->bssid)); interworking_connect(wpa_s, selected, 0); - } + } else if (wpa_s->wpa_state == WPA_SCANNING) + wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); } @@ -2693,7 +2742,7 @@ void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s) int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u16 info_ids[], size_t num_ids, u32 subtypes, - int get_cell_pref) + u32 mbo_subtypes) { struct wpabuf *buf; struct wpabuf *extra_buf = NULL; @@ -2727,13 +2776,14 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, #endif /* CONFIG_HS20 */ #ifdef CONFIG_MBO - if (get_cell_pref) { + if (mbo_subtypes) { struct wpabuf *mbo; - mbo = mbo_build_anqp_buf(wpa_s, bss); + mbo = mbo_build_anqp_buf(wpa_s, bss, mbo_subtypes); if (mbo) { if (wpabuf_resize(&extra_buf, wpabuf_len(mbo))) { wpabuf_free(extra_buf); + wpabuf_free(mbo); return -1; } wpabuf_put_buf(extra_buf, mbo); @@ -2747,7 +2797,7 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, if (buf == NULL) return -1; - res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s); + res = gas_query_req(wpa_s->gas, dst, freq, 0, buf, anqp_resp_cb, wpa_s); if (res < 0) { wpa_msg(wpa_s, MSG_DEBUG, "ANQP: Failed to send Query Request"); wpabuf_free(buf); @@ -2796,6 +2846,31 @@ static void anqp_add_extra(struct wpa_supplicant *wpa_s, } +static void interworking_parse_venue_url(struct wpa_supplicant *wpa_s, + const u8 *data, size_t len) +{ + const u8 *pos = data, *end = data + len; + char url[255]; + + while (end - pos >= 2) { + u8 slen, num; + + slen = *pos++; + if (slen < 1 || slen > end - pos) { + wpa_printf(MSG_DEBUG, + "ANQP: Truncated Venue URL Duple field"); + return; + } + + num = *pos++; + os_memcpy(url, pos, slen - 1); + url[slen - 1] = '\0'; + wpa_msg(wpa_s, MSG_INFO, RX_VENUE_URL "%u %s", num, url); + pos += slen - 1; + } +} + + static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, const u8 *sa, u16 info_id, @@ -2804,9 +2879,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, { const u8 *pos = data; struct wpa_bss_anqp *anqp = NULL; -#ifdef CONFIG_HS20 u8 type; -#endif /* CONFIG_HS20 */ if (bss) anqp = bss->anqp; @@ -2892,12 +2965,35 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, anqp->domain_name = wpabuf_alloc_copy(pos, slen); } break; +#ifdef CONFIG_FILS + case ANQP_FILS_REALM_INFO: + wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR + " FILS Realm Information", MAC2STR(sa)); + wpa_hexdump_ascii(MSG_MSGDUMP, "ANQP: FILS Realm Information", + pos, slen); + if (anqp) { + wpabuf_free(anqp->fils_realm_info); + anqp->fils_realm_info = wpabuf_alloc_copy(pos, slen); + } + break; +#endif /* CONFIG_FILS */ + case ANQP_VENUE_URL: + wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR " Venue URL", + MAC2STR(sa)); + anqp_add_extra(wpa_s, anqp, info_id, pos, slen); + + if (!wpa_sm_pmf_enabled(wpa_s->wpa)) { + wpa_printf(MSG_DEBUG, + "ANQP: Ignore Venue URL since PMF was not enabled"); + break; + } + interworking_parse_venue_url(wpa_s, pos, slen); + break; case ANQP_VENDOR_SPECIFIC: if (slen < 3) return; switch (WPA_GET_BE24(pos)) { -#ifdef CONFIG_HS20 case OUI_WFA: pos += 3; slen -= 3; @@ -2908,19 +3004,26 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, slen--; switch (type) { +#ifdef CONFIG_HS20 case HS20_ANQP_OUI_TYPE: hs20_parse_rx_hs20_anqp_resp(wpa_s, bss, sa, pos, slen, dialog_token); break; +#endif /* CONFIG_HS20 */ +#ifdef CONFIG_MBO + case MBO_ANQP_OUI_TYPE: + mbo_parse_rx_anqp_resp(wpa_s, bss, sa, + pos, slen); + break; +#endif /* CONFIG_MBO */ default: wpa_msg(wpa_s, MSG_DEBUG, - "HS20: Unsupported ANQP vendor type %u", + "ANQP: Unsupported ANQP vendor type %u", type); break; } break; -#endif /* CONFIG_HS20 */ default: wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Unsupported vendor-specific ANQP OUI %06x", @@ -3133,7 +3236,7 @@ int gas_send_request(struct wpa_supplicant *wpa_s, const u8 *dst, } else wpabuf_put_le16(buf, 0); - res = gas_query_req(wpa_s->gas, dst, freq, buf, gas_resp_cb, wpa_s); + res = gas_query_req(wpa_s->gas, dst, freq, 0, buf, gas_resp_cb, wpa_s); if (res < 0) { wpa_msg(wpa_s, MSG_DEBUG, "GAS: Failed to send Query Request"); wpabuf_free(buf); |