diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 378042eee..53575984f 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -1244,6 +1244,8 @@ const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie); #define WPS_IE_VENDOR_TYPE 0x0050f204 const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res, u32 vendor_type); +struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res, + u32 vendor_type); int wpa_scan_get_max_rate(const struct wpa_scan_res *res); void wpa_scan_results_free(struct wpa_scan_results *res); void wpa_scan_sort_results(struct wpa_scan_results *res); diff --git a/src/drivers/scan_helpers.c b/src/drivers/scan_helpers.c index bd774c1bd..72e360f24 100644 --- a/src/drivers/scan_helpers.c +++ b/src/drivers/scan_helpers.c @@ -1,6 +1,6 @@ /* * WPA Supplicant - Helper functions for scan result processing - * Copyright (c) 2007, Jouni Malinen + * Copyright (c) 2007-2008, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -59,6 +59,37 @@ const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res, } +struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res, + u32 vendor_type) +{ + struct wpabuf *buf; + const u8 *end, *pos; + + buf = wpabuf_alloc(res->ie_len); + if (buf == NULL) + return NULL; + + pos = (const u8 *) (res + 1); + end = pos + res->ie_len; + + while (pos + 1 < end) { + if (pos + 2 + pos[1] > end) + break; + if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && + vendor_type == WPA_GET_BE32(&pos[2])) + wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4); + pos += 2 + pos[1]; + } + + if (wpabuf_len(buf) == 0) { + wpabuf_free(buf); + buf = NULL; + } + + return buf; +} + + int wpa_scan_get_max_rate(const struct wpa_scan_res *res) { int rate = 0; diff --git a/src/wps/wps.c b/src/wps/wps.c index 44cac3f49..add84416c 100644 --- a/src/wps/wps.c +++ b/src/wps/wps.c @@ -124,13 +124,11 @@ struct wpabuf * wps_get_msg(struct wps_data *wps, u8 *op_code) } -int wps_is_selected_pbc_registrar(const u8 *buf, size_t len) +int wps_is_selected_pbc_registrar(const struct wpabuf *msg) { struct wps_parse_attr attr; - struct wpabuf msg; - wpabuf_set(&msg, buf, len); - if (wps_parse_msg(&msg, &attr) < 0 || + if (wps_parse_msg(msg, &attr) < 0 || !attr.selected_registrar || *attr.selected_registrar == 0 || !attr.sel_reg_config_methods || !(WPA_GET_BE16(attr.sel_reg_config_methods) & @@ -143,13 +141,11 @@ int wps_is_selected_pbc_registrar(const u8 *buf, size_t len) } -int wps_is_selected_pin_registrar(const u8 *buf, size_t len) +int wps_is_selected_pin_registrar(const struct wpabuf *msg) { struct wps_parse_attr attr; - struct wpabuf msg; - wpabuf_set(&msg, buf, len); - if (wps_parse_msg(&msg, &attr) < 0 || + if (wps_parse_msg(msg, &attr) < 0 || !attr.selected_registrar || *attr.selected_registrar == 0 || !attr.sel_reg_config_methods || !(WPA_GET_BE16(attr.sel_reg_config_methods) & @@ -162,13 +158,11 @@ int wps_is_selected_pin_registrar(const u8 *buf, size_t len) } -const u8 * wps_get_uuid_e(const u8 *buf, size_t len) +const u8 * wps_get_uuid_e(const struct wpabuf *msg) { struct wps_parse_attr attr; - struct wpabuf msg; - wpabuf_set(&msg, buf, len); - if (wps_parse_msg(&msg, &attr) < 0) + if (wps_parse_msg(msg, &attr) < 0) return NULL; return attr.uuid_e; } diff --git a/src/wps/wps.h b/src/wps/wps.h index c0ea6946d..c1e8eb78f 100644 --- a/src/wps/wps.h +++ b/src/wps/wps.h @@ -76,9 +76,9 @@ enum wps_process_res wps_process_msg(struct wps_data *wps, u8 op_code, struct wpabuf * wps_get_msg(struct wps_data *wps, u8 *op_code); -int wps_is_selected_pbc_registrar(const u8 *buf, size_t len); -int wps_is_selected_pin_registrar(const u8 *buf, size_t len); -const u8 * wps_get_uuid_e(const u8 *buf, size_t len); +int wps_is_selected_pbc_registrar(const struct wpabuf *msg); +int wps_is_selected_pin_registrar(const struct wpabuf *msg); +const u8 * wps_get_uuid_e(const struct wpabuf *msg); struct wpabuf * wps_build_assoc_req_ie(u8 req_type); struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev, const u8 *uuid, u8 req_type); diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c index 7404eaf47..c3699a9b4 100644 --- a/src/wps/wps_registrar.c +++ b/src/wps/wps_registrar.c @@ -542,32 +542,55 @@ static int wps_cb_set_ie(struct wps_registrar *reg, } +/* Encapsulate WPS IE data with one (or more, if needed) IE headers */ +static struct wpabuf * wps_ie_encapsulate(struct wpabuf *data) +{ + struct wpabuf *ie; + const u8 *pos, *end; + + ie = wpabuf_alloc(wpabuf_len(data) + 100); + if (ie == NULL) { + wpabuf_free(data); + return NULL; + } + + pos = wpabuf_head(data); + end = pos + wpabuf_len(data); + + while (end > pos) { + size_t frag_len = end - pos; + if (frag_len > 251) + frag_len = 251; + wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); + wpabuf_put_u8(ie, 4 + frag_len); + wpabuf_put_be32(ie, WPS_DEV_OUI_WFA); + wpabuf_put_data(ie, pos, frag_len); + pos += frag_len; + } + + wpabuf_free(data); + + return ie; +} + + static int wps_set_ie(struct wps_registrar *reg) { struct wpabuf *beacon; struct wpabuf *probe; int ret; - u8 *blen, *plen; wpa_printf(MSG_DEBUG, "WPS: Build Beacon and Probe Response IEs"); beacon = wpabuf_alloc(300); if (beacon == NULL) return -1; - probe = wpabuf_alloc(300); + probe = wpabuf_alloc(400); if (probe == NULL) { wpabuf_free(beacon); return -1; } - wpabuf_put_u8(beacon, WLAN_EID_VENDOR_SPECIFIC); - blen = wpabuf_put(beacon, 1); - wpabuf_put_be32(beacon, WPS_DEV_OUI_WFA); - - wpabuf_put_u8(probe, WLAN_EID_VENDOR_SPECIFIC); - plen = wpabuf_put(probe, 1); - wpabuf_put_be32(probe, WPS_DEV_OUI_WFA); - if (wps_build_version(beacon) || wps_build_wps_state(reg->wps, beacon) || wps_build_ap_setup_locked(reg->wps, beacon) || @@ -590,8 +613,14 @@ static int wps_set_ie(struct wps_registrar *reg) return -1; } - *blen = wpabuf_len(beacon) - 2; - *plen = wpabuf_len(probe) - 2; + beacon = wps_ie_encapsulate(beacon); + probe = wps_ie_encapsulate(probe); + + if (!beacon || !probe) { + wpabuf_free(beacon); + wpabuf_free(probe); + return -1; + } ret = wps_cb_set_ie(reg, beacon, probe); wpabuf_free(beacon); diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 34b06e3d7..a1bd2ba17 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -31,7 +31,7 @@ #include "ieee802_11_defs.h" #include "blacklist.h" #include "wpas_glue.h" -#include "wps/wps.h" +#include "wps_supplicant.h" static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s) @@ -276,53 +276,11 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_ssid *ssid, struct wpa_ie_data ie; int proto_match = 0; const u8 *rsn_ie, *wpa_ie; + int ret; -#ifdef CONFIG_WPS - if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) { - const u8 *wps_ie; - wps_ie = wpa_scan_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE); - if (eap_is_wps_pbc_enrollee(&ssid->eap)) { - if (!wps_ie) { - wpa_printf(MSG_DEBUG, " skip - non-WPS AP"); - return 0; - } - - if (!wps_is_selected_pbc_registrar(wps_ie + 6, - wps_ie[1] - 4)) { - wpa_printf(MSG_DEBUG, " skip - WPS AP " - "without active PBC Registrar"); - return 0; - } - - /* TODO: overlap detection */ - wpa_printf(MSG_DEBUG, " selected based on WPS IE " - "(Active PBC)"); - return 1; - } - - if (eap_is_wps_pin_enrollee(&ssid->eap)) { - if (!wps_ie) { - wpa_printf(MSG_DEBUG, " skip - non-WPS AP"); - return 0; - } - - if (!wps_is_selected_pin_registrar(wps_ie + 6, - wps_ie[1] - 4)) { - wpa_printf(MSG_DEBUG, " skip - WPS AP " - "without active PIN Registrar"); - return 0; - } - wpa_printf(MSG_DEBUG, " selected based on WPS IE " - "(Active PIN)"); - return 1; - } - - if (wps_ie) { - wpa_printf(MSG_DEBUG, " selected based on WPS IE"); - return 1; - } - } -#endif /* CONFIG_WPS */ + ret = wpas_wps_ssid_bss_match(ssid, bss); + if (ret >= 0) + return ret; rsn_ie = wpa_scan_get_ie(bss, WLAN_EID_RSN); while ((ssid->proto & WPA_PROTO_RSN) && rsn_ie) { @@ -412,34 +370,6 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_ssid *ssid, } -#ifdef CONFIG_WPS -static int wps_ssid_wildcard_ok(struct wpa_ssid *ssid, - struct wpa_scan_res *bss) -{ - const u8 *wps_ie; - - if (eap_is_wps_pbc_enrollee(&ssid->eap)) { - wps_ie = wpa_scan_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE); - if (wps_ie && - wps_is_selected_pbc_registrar(wps_ie + 6, wps_ie[1] - 4)) { - /* allow wildcard SSID for WPS PBC */ - return 1; - } - } - - if (eap_is_wps_pin_enrollee(&ssid->eap)) { - wps_ie = wpa_scan_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE); - if (wps_ie && - wps_is_selected_pin_registrar(wps_ie + 6, wps_ie[1] - 4)) { - /* allow wildcard SSID for WPS PIN */ - return 1; - } - } - - return 0; -} -#endif /* CONFIG_WPS */ - static struct wpa_scan_res * wpa_supplicant_select_bss_wpa(struct wpa_supplicant *wpa_s, struct wpa_ssid *group, @@ -494,7 +424,7 @@ wpa_supplicant_select_bss_wpa(struct wpa_supplicant *wpa_s, #ifdef CONFIG_WPS if (ssid->ssid_len == 0 && - wps_ssid_wildcard_ok(ssid, bss)) + wpas_wps_ssid_wildcard_ok(ssid, bss)) check_ssid = 0; #endif /* CONFIG_WPS */ @@ -584,7 +514,7 @@ wpa_supplicant_select_bss_non_wpa(struct wpa_supplicant *wpa_s, * with our mode. */ check_ssid = 1; if (ssid->ssid_len == 0 && - wps_ssid_wildcard_ok(ssid, bss)) + wpas_wps_ssid_wildcard_ok(ssid, bss)) check_ssid = 0; } #endif /* CONFIG_WPS */ @@ -670,65 +600,6 @@ wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s, struct wpa_ssid *group, } -#ifdef CONFIG_WPS - -static int wpa_scan_pbc_overlap(struct wpa_supplicant *wpa_s, - struct wpa_scan_res *selected, - struct wpa_ssid *ssid) -{ - const u8 *sel_uuid, *uuid; - size_t i; - const u8 *wps_ie; - - if (!eap_is_wps_pbc_enrollee(&ssid->eap)) - return 0; - - /* Make sure that only one AP is in active PBC mode */ - wps_ie = wpa_scan_get_vendor_ie(selected, WPS_IE_VENDOR_TYPE); - if (wps_ie) - sel_uuid = wps_get_uuid_e(wps_ie + 6, wps_ie[1] - 4); - else - sel_uuid = NULL; - if (!sel_uuid) { - wpa_printf(MSG_DEBUG, "WPS: UUID-E not " - "available for PBC overlap " - "detection"); - return 1; - } - - for (i = 0; i < wpa_s->scan_res->num; i++) { - struct wpa_scan_res *bss = wpa_s->scan_res->res[i]; - if (bss == selected) - continue; - wps_ie = wpa_scan_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE); - if (!wps_ie) - continue; - if (!wps_is_selected_pbc_registrar(wps_ie + 6, - wps_ie[1] - 4)) - continue; - uuid = wps_get_uuid_e(wps_ie + 6, wps_ie[1] - 4); - if (uuid == NULL) { - wpa_printf(MSG_DEBUG, "WPS: UUID-E not " - "available for PBC overlap " - "detection (other BSS)"); - return 1; - } - if (os_memcmp(sel_uuid, uuid, 16) != 0) - return 1; /* PBC overlap */ - - /* TODO: verify that this is reasonable dual-band situation */ - } - - return 0; -} - -#else /* CONFIG_WPS */ - -#define wpa_scan_pbc_overlap(w, s, i) 0 - -#endif /* CONFIG_WPS */ - - static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s) { int prio, timeout; @@ -778,7 +649,7 @@ static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s) } if (selected) { - if (wpa_scan_pbc_overlap(wpa_s, selected, ssid)) { + if (wpas_wps_scan_pbc_overlap(wpa_s, selected, ssid)) { wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OVERLAP "PBC session overlap"); timeout = 10; diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c index 49869f9a4..2b1e6b8e7 100644 --- a/wpa_supplicant/wps_supplicant.c +++ b/wpa_supplicant/wps_supplicant.c @@ -391,3 +391,145 @@ void wpas_wps_deinit(struct wpa_supplicant *wpa_s) os_free(wpa_s->wps); wpa_s->wps = NULL; } + + +int wpas_wps_ssid_bss_match(struct wpa_ssid *ssid, struct wpa_scan_res *bss) +{ + struct wpabuf *wps_ie; + + if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS)) + return -1; + + wps_ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); + if (eap_is_wps_pbc_enrollee(&ssid->eap)) { + if (!wps_ie) { + wpa_printf(MSG_DEBUG, " skip - non-WPS AP"); + return 0; + } + + if (!wps_is_selected_pbc_registrar(wps_ie)) { + wpa_printf(MSG_DEBUG, " skip - WPS AP " + "without active PBC Registrar"); + wpabuf_free(wps_ie); + return 0; + } + + /* TODO: overlap detection */ + wpa_printf(MSG_DEBUG, " selected based on WPS IE " + "(Active PBC)"); + wpabuf_free(wps_ie); + return 1; + } + + if (eap_is_wps_pin_enrollee(&ssid->eap)) { + if (!wps_ie) { + wpa_printf(MSG_DEBUG, " skip - non-WPS AP"); + return 0; + } + + if (!wps_is_selected_pin_registrar(wps_ie)) { + wpa_printf(MSG_DEBUG, " skip - WPS AP " + "without active PIN Registrar"); + wpabuf_free(wps_ie); + return 0; + } + wpa_printf(MSG_DEBUG, " selected based on WPS IE " + "(Active PIN)"); + wpabuf_free(wps_ie); + return 1; + } + + if (wps_ie) { + wpa_printf(MSG_DEBUG, " selected based on WPS IE"); + wpabuf_free(wps_ie); + return 1; + } + + return -1; +} + + +int wpas_wps_ssid_wildcard_ok(struct wpa_ssid *ssid, + struct wpa_scan_res *bss) +{ + struct wpabuf *wps_ie = NULL; + int ret = 0; + + if (eap_is_wps_pbc_enrollee(&ssid->eap)) { + wps_ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); + if (wps_ie && wps_is_selected_pbc_registrar(wps_ie)) { + /* allow wildcard SSID for WPS PBC */ + ret = 1; + } + } else if (eap_is_wps_pin_enrollee(&ssid->eap)) { + wps_ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); + if (wps_ie && wps_is_selected_pin_registrar(wps_ie)) { + /* allow wildcard SSID for WPS PIN */ + ret = 1; + } + } + + wpabuf_free(wps_ie); + + return ret; +} + + +int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s, + struct wpa_scan_res *selected, + struct wpa_ssid *ssid) +{ + const u8 *sel_uuid, *uuid; + size_t i; + struct wpabuf *wps_ie; + int ret = 0; + + if (!eap_is_wps_pbc_enrollee(&ssid->eap)) + return 0; + + /* Make sure that only one AP is in active PBC mode */ + wps_ie = wpa_scan_get_vendor_ie_multi(selected, WPS_IE_VENDOR_TYPE); + if (wps_ie) + sel_uuid = wps_get_uuid_e(wps_ie); + else + sel_uuid = NULL; + if (!sel_uuid) { + wpa_printf(MSG_DEBUG, "WPS: UUID-E not available for PBC " + "overlap detection"); + wpabuf_free(wps_ie); + return 1; + } + + for (i = 0; i < wpa_s->scan_res->num; i++) { + struct wpa_scan_res *bss = wpa_s->scan_res->res[i]; + struct wpabuf *ie; + if (bss == selected) + continue; + ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); + if (!ie) + continue; + if (!wps_is_selected_pbc_registrar(ie)) { + wpabuf_free(ie); + continue; + } + uuid = wps_get_uuid_e(ie); + if (uuid == NULL) { + wpa_printf(MSG_DEBUG, "WPS: UUID-E not available for " + "PBC overlap detection (other BSS)"); + ret = 1; + wpabuf_free(ie); + break; + } + if (os_memcmp(sel_uuid, uuid, 16) != 0) { + ret = 1; /* PBC overlap */ + wpabuf_free(ie); + break; + } + + /* TODO: verify that this is reasonable dual-band situation */ + } + + wpabuf_free(wps_ie); + + return ret; +} diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h index 1e393e36c..bdde6abb7 100644 --- a/wpa_supplicant/wps_supplicant.h +++ b/wpa_supplicant/wps_supplicant.h @@ -26,6 +26,11 @@ int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid, const char *pin); int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid, const char *pin); +int wpas_wps_ssid_bss_match(struct wpa_ssid *ssid, struct wpa_scan_res *bss); +int wpas_wps_ssid_wildcard_ok(struct wpa_ssid *ssid, struct wpa_scan_res *bss); +int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s, + struct wpa_scan_res *selected, + struct wpa_ssid *ssid); #else /* CONFIG_WPS */ @@ -43,7 +48,26 @@ static inline int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s) return 0; } -u8 wpas_wps_get_req_type(struct wpa_ssid *ssid) +static inline u8 wpas_wps_get_req_type(struct wpa_ssid *ssid) +{ + return 0; +} + +static inline int wpas_wps_ssid_bss_match(struct wpa_ssid *ssid, + struct wpa_scan_res *bss) +{ + return -1; +} + +static inline int wpas_wps_ssid_wildcard_ok(struct wpa_ssid *ssid, + struct wpa_scan_res *bss) +{ + return 0; +} + +static inline int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s, + struct wpa_scan_res *selected, + struct wpa_ssid *ssid) { return 0; }