X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=wpa_supplicant%2Finterworking.c;h=1e42f437b61a5eac565634eb0203b5f423ef6df9;hb=f7c04e50bdadcfb15327ba3dbad199f54889f579;hp=5b66211a59be03df36195e6a4c7a1449d0138928;hpb=99805a0ea1d911a4f0bb08552b7a4a7e3745ff71;p=mech_eap.git diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c index 5b66211..1e42f43 100644 --- a/wpa_supplicant/interworking.c +++ b/wpa_supplicant/interworking.c @@ -77,6 +77,7 @@ static void interworking_reconnect(struct wpa_supplicant *wpa_s) if (wpa_s->wpa_state >= WPA_AUTHENTICATING) { wpa_supplicant_cancel_sched_scan(wpa_s); + wpa_s->own_disconnect_req = 1; wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); } @@ -361,13 +362,13 @@ static const u8 * nai_realm_parse_eap(struct nai_realm_eap *e, const u8 *pos, u8 elen, auth_count, a; const u8 *e_end; - if (pos + 3 > end) { + if (end - pos < 3) { wpa_printf(MSG_DEBUG, "No room for EAP Method fixed fields"); return NULL; } elen = *pos++; - if (pos + elen > end || elen < 2) { + if (elen > end - pos || elen < 2) { wpa_printf(MSG_DEBUG, "No room for EAP Method subfield"); return NULL; } @@ -380,14 +381,19 @@ static const u8 * nai_realm_parse_eap(struct nai_realm_eap *e, const u8 *pos, for (a = 0; a < auth_count; a++) { u8 id, len; - if (pos + 2 > end || pos + 2 + pos[1] > end) { - wpa_printf(MSG_DEBUG, "No room for Authentication " - "Parameter subfield"); + if (end - pos < 2) { + wpa_printf(MSG_DEBUG, + "No room for Authentication Parameter subfield header"); return NULL; } id = *pos++; len = *pos++; + if (len > end - pos) { + wpa_printf(MSG_DEBUG, + "No room for Authentication Parameter subfield"); + return NULL; + } switch (id) { case NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH: @@ -462,7 +468,7 @@ static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos, len = WPA_GET_LE16(pos); /* NAI Realm Data field Length */ pos += 2; - if (pos + len > end || len < 3) { + if (len > end - pos || len < 3) { wpa_printf(MSG_DEBUG, "No room for NAI Realm Data " "(len=%u; left=%u)", len, (unsigned int) (end - pos)); @@ -472,7 +478,7 @@ static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos, r->encoding = *pos++; realm_len = *pos++; - if (pos + realm_len > f_end) { + if (realm_len > f_end - pos) { wpa_printf(MSG_DEBUG, "No room for NAI Realm " "(len=%u; left=%u)", realm_len, (unsigned int) (f_end - pos)); @@ -484,13 +490,13 @@ static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos, return NULL; pos += realm_len; - if (pos + 1 > f_end) { + if (f_end - pos < 1) { wpa_printf(MSG_DEBUG, "No room for EAP Method Count"); return NULL; } r->eap_count = *pos++; wpa_printf(MSG_DEBUG, "EAP Count: %u", r->eap_count); - if (pos + r->eap_count * 3 > f_end) { + if (r->eap_count * 3 > f_end - pos) { wpa_printf(MSG_DEBUG, "No room for EAP Methods"); return NULL; } @@ -745,7 +751,7 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len) return 0; pos = wpabuf_head_u8(anqp); end = pos + wpabuf_len(anqp); - if (pos + 2 > end) + if (end - pos < 2) return 0; if (*pos != 0) { wpa_printf(MSG_DEBUG, "Unsupported GUD version 0x%x", *pos); @@ -753,7 +759,7 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len) } pos++; udhl = *pos++; - if (pos + udhl > end) { + if (udhl > end - pos) { wpa_printf(MSG_DEBUG, "Invalid UDHL"); return 0; } @@ -763,12 +769,12 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len) plmn[0], plmn[1], plmn[2], plmn2[0], plmn2[1], plmn2[2], imsi, mnc_len); - while (pos + 2 <= end) { + while (end - pos >= 2) { u8 iei, len; const u8 *l_end; iei = *pos++; len = *pos++ & 0x7f; - if (pos + len > end) + if (len > end - pos) break; l_end = pos + len; @@ -779,7 +785,7 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len) pos, len); num = *pos++; for (i = 0; i < num; i++) { - if (pos + 3 > l_end) + if (l_end - pos < 3) break; if (os_memcmp(pos, plmn, 3) == 0 || os_memcmp(pos, plmn2, 3) == 0) @@ -915,6 +921,7 @@ static void remove_duplicate_network(struct wpa_supplicant *wpa_s, if (ssid == wpa_s->current_ssid) { wpa_sm_set_config(wpa_s->wpa, NULL); eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); + wpa_s->own_disconnect_req = 1; wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); } @@ -943,11 +950,9 @@ static int interworking_set_hs20_params(struct wpa_supplicant *wpa_s, if (!key_mgmt) key_mgmt = wpa_s->conf->pmf != NO_MGMT_FRAME_PROTECTION ? "WPA-EAP WPA-EAP-SHA256" : "WPA-EAP"; - if (wpa_config_set(ssid, "key_mgmt", key_mgmt, 0) < 0) - return -1; - if (wpa_config_set(ssid, "proto", "RSN", 0) < 0) - return -1; - if (wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0) + if (wpa_config_set(ssid, "key_mgmt", key_mgmt, 0) < 0 || + wpa_config_set(ssid, "proto", "RSN", 0) < 0 || + wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0) return -1; return 0; } @@ -955,7 +960,7 @@ static int interworking_set_hs20_params(struct wpa_supplicant *wpa_s, static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s, struct wpa_cred *cred, - struct wpa_bss *bss) + struct wpa_bss *bss, int only_add) { #ifdef INTERWORKING_3GPP struct wpa_ssid *ssid; @@ -972,7 +977,7 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s, if (already_connected(wpa_s, cred, bss)) { wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR, MAC2STR(bss->bssid)); - return 0; + return wpa_s->current_ssid->id; } remove_duplicate_network(wpa_s, cred, bss); @@ -1049,9 +1054,10 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s, wpa_s->next_ssid = ssid; wpa_config_update_prio_list(wpa_s->conf); - interworking_reconnect(wpa_s); + if (!only_add) + interworking_reconnect(wpa_s); - return 0; + return ssid->id; fail: wpas_notify_network_removed(wpa_s, ssid); @@ -1079,12 +1085,12 @@ static int roaming_consortium_element_match(const u8 *ie, const u8 *rc_id, * OI #1, [OI #2], [OI #3] */ - if (pos + 2 > end) + if (end - pos < 2) return 0; pos++; /* skip Number of ANQP OIs */ lens = *pos++; - if (pos + (lens & 0x0f) + (lens >> 4) > end) + if ((lens & 0x0f) + (lens >> 4) > end - pos) return 0; if ((lens & 0x0f) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0) @@ -1118,7 +1124,7 @@ static int roaming_consortium_anqp_match(const struct wpabuf *anqp, /* Set of duples */ while (pos < end) { len = *pos++; - if (pos + len > end) + if (len > end - pos) break; if (len == rc_len && os_memcmp(pos, rc_id, rc_len) == 0) return 1; @@ -1179,6 +1185,7 @@ static int cred_excluded_ssid(struct wpa_cred *cred, struct wpa_bss *bss) static int cred_below_min_backhaul(struct wpa_supplicant *wpa_s, struct wpa_cred *cred, struct wpa_bss *bss) { +#ifdef CONFIG_HS20 int res; unsigned int dl_bandwidth, ul_bandwidth; const u8 *wan; @@ -1230,6 +1237,7 @@ static int cred_below_min_backhaul(struct wpa_supplicant *wpa_s, if (cred->min_ul_bandwidth_roaming > ul_bandwidth) return 1; } +#endif /* CONFIG_HS20 */ return 0; } @@ -1257,9 +1265,11 @@ static int cred_over_max_bss_load(struct wpa_supplicant *wpa_s, } +#ifdef CONFIG_HS20 + static int has_proto_match(const u8 *pos, const u8 *end, u8 proto) { - while (pos + 4 <= end) { + while (end - pos >= 4) { if (pos[0] == proto && pos[3] == 1 /* Open */) return 1; pos += 4; @@ -1272,7 +1282,7 @@ static int has_proto_match(const u8 *pos, const u8 *end, u8 proto) static int has_proto_port_match(const u8 *pos, const u8 *end, u8 proto, u16 port) { - while (pos + 4 <= end) { + while (end - pos >= 4) { if (pos[0] == proto && WPA_GET_LE16(&pos[1]) == port && pos[3] == 1 /* Open */) return 1; @@ -1282,10 +1292,13 @@ static int has_proto_port_match(const u8 *pos, const u8 *end, u8 proto, return 0; } +#endif /* CONFIG_HS20 */ + static int cred_conn_capab_missing(struct wpa_supplicant *wpa_s, struct wpa_cred *cred, struct wpa_bss *bss) { +#ifdef CONFIG_HS20 int res; const u8 *capab, *end; unsigned int i, j; @@ -1322,6 +1335,7 @@ static int cred_conn_capab_missing(struct wpa_supplicant *wpa_s, } } } +#endif /* CONFIG_HS20 */ return 0; } @@ -1435,7 +1449,24 @@ static int interworking_set_eap_params(struct wpa_ssid *ssid, os_free(anon); } - if (cred->username && cred->username[0] && + if (!ttls && cred->username && cred->username[0] && cred->realm && + !os_strchr(cred->username, '@')) { + char *id; + size_t buflen; + int res; + + buflen = os_strlen(cred->username) + 1 + + os_strlen(cred->realm) + 1; + + id = os_malloc(buflen); + if (!id) + return -1; + os_snprintf(id, buflen, "%s@%s", cred->username, cred->realm); + res = wpa_config_set_quoted(ssid, "identity", id); + os_free(id); + if (res < 0) + return -1; + } else if (cred->username && cred->username[0] && wpa_config_set_quoted(ssid, "identity", cred->username) < 0) return -1; @@ -1499,7 +1530,7 @@ static int interworking_set_eap_params(struct wpa_ssid *ssid, static int interworking_connect_roaming_consortium( struct wpa_supplicant *wpa_s, struct wpa_cred *cred, - struct wpa_bss *bss) + struct wpa_bss *bss, int only_add) { struct wpa_ssid *ssid; @@ -1509,7 +1540,7 @@ static int interworking_connect_roaming_consortium( if (already_connected(wpa_s, cred, bss)) { wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR, MAC2STR(bss->bssid)); - return 0; + return wpa_s->current_ssid->id; } remove_duplicate_network(wpa_s, cred, bss); @@ -1545,9 +1576,10 @@ static int interworking_connect_roaming_consortium( wpa_s->next_ssid = ssid; wpa_config_update_prio_list(wpa_s->conf); - interworking_reconnect(wpa_s); + if (!only_add) + interworking_reconnect(wpa_s); - return 0; + return ssid->id; fail: wpas_notify_network_removed(wpa_s, ssid); @@ -1557,7 +1589,8 @@ fail: static int interworking_connect_helper(struct wpa_supplicant *wpa_s, - struct wpa_bss *bss, int allow_excluded) + struct wpa_bss *bss, int allow_excluded, + int only_add) { struct wpa_cred *cred, *cred_rc, *cred_3gpp; struct wpa_ssid *ssid; @@ -1659,11 +1692,12 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s, (cred == NULL || cred_prio_cmp(cred_rc, cred) >= 0) && (cred_3gpp == NULL || cred_prio_cmp(cred_rc, cred_3gpp) >= 0)) return interworking_connect_roaming_consortium(wpa_s, cred_rc, - bss); + bss, only_add); if (cred_3gpp && (cred == NULL || cred_prio_cmp(cred_3gpp, cred) >= 0)) { - return interworking_connect_3gpp(wpa_s, cred_3gpp, bss); + return interworking_connect_3gpp(wpa_s, cred_3gpp, bss, + only_add); } if (cred == NULL) { @@ -1801,9 +1835,10 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s, wpa_s->next_ssid = ssid; wpa_config_update_prio_list(wpa_s->conf); - interworking_reconnect(wpa_s); + if (!only_add) + interworking_reconnect(wpa_s); - return 0; + return ssid->id; fail: wpas_notify_network_removed(wpa_s, ssid); @@ -1813,9 +1848,10 @@ fail: } -int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) +int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, + int only_add) { - return interworking_connect_helper(wpa_s, bss, 1); + return interworking_connect_helper(wpa_s, bss, 1, only_add); } @@ -2050,7 +2086,7 @@ static struct wpa_cred * interworking_credentials_available_helper( int *excluded) { struct wpa_cred *cred, *cred2; - int excluded1, excluded2; + int excluded1, excluded2 = 0; if (disallowed_bssid(wpa_s, bss->bssid) || disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) { @@ -2117,23 +2153,27 @@ int domain_name_list_contains(struct wpabuf *domain_names, pos = wpabuf_head(domain_names); end = pos + wpabuf_len(domain_names); - while (pos + 1 < end) { - if (pos + 1 + pos[0] > end) + while (end - pos > 1) { + u8 elen; + + elen = *pos++; + if (elen > end - pos) break; wpa_hexdump_ascii(MSG_DEBUG, "Interworking: AP domain name", - pos + 1, pos[0]); - if (pos[0] == len && - os_strncasecmp(domain, (const char *) (pos + 1), len) == 0) + pos, elen); + if (elen == len && + os_strncasecmp(domain, (const char *) pos, len) == 0) return 1; - if (!exact_match && pos[0] > len && pos[pos[0] - len] == '.') { - const char *ap = (const char *) (pos + 1); - int offset = pos[0] - len; + if (!exact_match && elen > len && pos[elen - len - 1] == '.') { + const char *ap = (const char *) pos; + int offset = elen - len; + if (os_strncasecmp(domain, ap + offset, len) == 0) return 1; } - pos += 1 + pos[0]; + pos += elen; } return 0; @@ -2483,6 +2523,8 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s) wpa_msg(wpa_s, MSG_INFO, INTERWORKING_NO_MATCH "No network " "with matching credentials found"); + if (wpa_s->wpa_state == WPA_SCANNING) + wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); } if (selected) { @@ -2495,7 +2537,7 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s) MAC2STR(selected->bssid)); wpa_msg(wpa_s, MSG_INFO, INTERWORKING_SELECTED MACSTR, MAC2STR(selected->bssid)); - interworking_connect(wpa_s, selected); + interworking_connect(wpa_s, selected, 0); } } @@ -2554,11 +2596,13 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s) return; } +#ifdef CONFIG_HS20 if (wpa_s->fetch_osu_icon_in_progress) { wpa_printf(MSG_DEBUG, "Interworking: Next icon (in progress)"); hs20_next_osu_icon(wpa_s); return; } +#endif /* CONFIG_HS20 */ dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { if (!(bss->caps & IEEE80211_CAP_ESS)) @@ -2592,6 +2636,7 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s) } if (found == 0) { +#ifdef CONFIG_HS20 if (wpa_s->fetch_osu_info) { if (wpa_s->num_prov_found == 0 && wpa_s->fetch_osu_waiting_scan && @@ -2604,6 +2649,7 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s) hs20_osu_icon_fetch(wpa_s); return; } +#endif /* CONFIG_HS20 */ wpa_msg(wpa_s, MSG_INFO, "ANQP fetch completed"); wpa_s->fetch_anqp_in_progress = 0; if (wpa_s->network_select) @@ -2663,14 +2709,16 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, struct wpa_bss *bss; int res; - freq = wpa_s->assoc_freq; bss = wpa_bss_get_bssid(wpa_s, dst); - if (bss) { - wpa_bss_anqp_unshare_alloc(bss); - freq = bss->freq; - } - if (freq <= 0) + if (!bss) { + wpa_printf(MSG_WARNING, + "ANQP: Cannot send query to unknown BSS " + MACSTR, MAC2STR(dst)); return -1; + } + + wpa_bss_anqp_unshare_alloc(bss); + freq = bss->freq; wpa_msg(wpa_s, MSG_DEBUG, "ANQP: Query Request to " MACSTR " for %u id(s)", @@ -2704,10 +2752,46 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, } +static void anqp_add_extra(struct wpa_supplicant *wpa_s, + struct wpa_bss_anqp *anqp, u16 info_id, + const u8 *data, size_t slen) +{ + struct wpa_bss_anqp_elem *tmp, *elem = NULL; + + if (!anqp) + return; + + dl_list_for_each(tmp, &anqp->anqp_elems, struct wpa_bss_anqp_elem, + list) { + if (tmp->infoid == info_id) { + elem = tmp; + break; + } + } + + if (!elem) { + elem = os_zalloc(sizeof(*elem)); + if (!elem) + return; + elem->infoid = info_id; + dl_list_add(&anqp->anqp_elems, &elem->list); + } else { + wpabuf_free(elem->payload); + } + + elem->payload = wpabuf_alloc_copy(data, slen); + if (!elem->payload) { + dl_list_del(&elem->list); + os_free(elem); + } +} + + static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, const u8 *sa, u16 info_id, - const u8 *data, size_t slen) + const u8 *data, size_t slen, + u8 dialog_token) { const u8 *pos = data; struct wpa_bss_anqp *anqp = NULL; @@ -2722,6 +2806,12 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, case ANQP_CAPABILITY_LIST: wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR " ANQP Capability list", MAC2STR(sa)); + wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Capability list", + pos, slen); + if (anqp) { + wpabuf_free(anqp->capability_list); + anqp->capability_list = wpabuf_alloc_copy(pos, slen); + } break; case ANQP_VENUE_NAME: wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR @@ -2811,7 +2901,8 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, switch (type) { case HS20_ANQP_OUI_TYPE: hs20_parse_rx_hs20_anqp_resp(wpa_s, bss, sa, - pos, slen); + pos, slen, + dialog_token); break; default: wpa_msg(wpa_s, MSG_DEBUG, @@ -2831,6 +2922,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, default: wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Unsupported ANQP Info ID %u", info_id); + anqp_add_extra(wpa_s, anqp, info_id, data, slen); break; } } @@ -2853,8 +2945,10 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token, " dialog_token=%u result=%d status_code=%u", MAC2STR(dst), dialog_token, result, status_code); if (result != GAS_QUERY_SUCCESS) { +#ifdef CONFIG_HS20 if (wpa_s->fetch_osu_icon_in_progress) hs20_icon_fetch_failed(wpa_s); +#endif /* CONFIG_HS20 */ anqp_result = "FAILURE"; goto out; } @@ -2864,8 +2958,10 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token, pos[1] < 2 || pos[3] != ACCESS_NETWORK_QUERY_PROTOCOL) { wpa_msg(wpa_s, MSG_DEBUG, "ANQP: Unexpected Advertisement Protocol in response"); +#ifdef CONFIG_HS20 if (wpa_s->fetch_osu_icon_in_progress) hs20_icon_fetch_failed(wpa_s); +#endif /* CONFIG_HS20 */ anqp_result = "INVALID_FRAME"; goto out; } @@ -2909,12 +3005,14 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token, goto out_parse_done; } interworking_parse_rx_anqp_resp(wpa_s, bss, dst, info_id, pos, - slen); + slen, dialog_token); pos += slen; } out_parse_done: +#ifdef CONFIG_HS20 hs20_notify_parse_done(wpa_s); +#endif /* CONFIG_HS20 */ out: wpa_msg(wpa_s, MSG_INFO, ANQP_QUERY_DONE "addr=" MACSTR " result=%s", MAC2STR(dst), anqp_result);