diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index 87a4c6b84..f7cad572e 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -66,6 +66,8 @@ extern "C" { #define WPS_EVENT_FAIL "WPS-FAIL " /** WPS registration completed successfully */ #define WPS_EVENT_SUCCESS "WPS-SUCCESS " +/** WPS enrollment attempt timed out and was terminated */ +#define WPS_EVENT_TIMEOUT "WPS-TIMEOUT " /* hostapd control interface - fixed message prefixes */ #define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED " diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index e169949d9..703106c5d 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -271,7 +271,8 @@ static int wpa_supplicant_match_privacy(struct wpa_scan_res *bss, } -static int wpa_supplicant_ssid_bss_match(struct wpa_ssid *ssid, +static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, struct wpa_scan_res *bss) { struct wpa_ie_data ie; @@ -279,7 +280,7 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_ssid *ssid, const u8 *rsn_ie, *wpa_ie; int ret; - ret = wpas_wps_ssid_bss_match(ssid, bss); + ret = wpas_wps_ssid_bss_match(wpa_s, ssid, bss); if (ret >= 0) return ret; @@ -425,7 +426,7 @@ wpa_supplicant_select_bss_wpa(struct wpa_supplicant *wpa_s, #ifdef CONFIG_WPS if (ssid->ssid_len == 0 && - wpas_wps_ssid_wildcard_ok(ssid, bss)) + wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss)) check_ssid = 0; #endif /* CONFIG_WPS */ @@ -445,7 +446,7 @@ wpa_supplicant_select_bss_wpa(struct wpa_supplicant *wpa_s, continue; } - if (!wpa_supplicant_ssid_bss_match(ssid, bss)) + if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss)) continue; wpa_printf(MSG_DEBUG, " selected WPA AP " @@ -515,7 +516,8 @@ wpa_supplicant_select_bss_non_wpa(struct wpa_supplicant *wpa_s, * with our mode. */ check_ssid = 1; if (ssid->ssid_len == 0 && - wpas_wps_ssid_wildcard_ok(ssid, bss)) + wpas_wps_ssid_wildcard_ok(wpa_s, ssid, + bss)) check_ssid = 0; } #endif /* CONFIG_WPS */ @@ -646,6 +648,7 @@ static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s) wpa_printf(MSG_DEBUG, "No APs found - clear blacklist " "and try again"); wpa_blacklist_clear(wpa_s); + wpa_s->blacklist_cleared++; } else if (selected == NULL) { break; } diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index afc341189..67e2282ef 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -204,7 +204,8 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) if (ret) { wpa_printf(MSG_WARNING, "Failed to initiate AP scan."); wpa_supplicant_req_scan(wpa_s, 10, 0); - } + } else + wpa_s->scan_runs++; } diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index c629a7e10..b49f23ae3 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -346,6 +346,7 @@ struct wpa_supplicant { * results without a new scan request; this is used * to speed up the first association if the driver * has already available scan results. */ + int scan_runs; /* number of scan runs since WPS was started */ struct wpa_client_mlme mlme; int use_client_mlme; @@ -356,6 +357,8 @@ struct wpa_supplicant { int mic_errors_seen; /* Michael MIC errors with the current PTK */ struct wps_context *wps; + int wps_success; /* WPS success event received */ + int blacklist_cleared; struct ibss_rsn *ibss_rsn; }; diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c index 14f1f86ff..2dd22f2e2 100644 --- a/wpa_supplicant/wps_supplicant.c +++ b/wpa_supplicant/wps_supplicant.c @@ -25,8 +25,10 @@ #include "wpa_ctrl.h" #include "ctrl_iface_dbus.h" #include "eap_common/eap_wsc_common.h" +#include "blacklist.h" #include "wps_supplicant.h" +#define WPS_PIN_SCAN_IGNORE_SEL_REG 3 static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx); static void wpas_clear_wps(struct wpa_supplicant *wpa_s); @@ -34,6 +36,27 @@ static void wpas_clear_wps(struct wpa_supplicant *wpa_s); int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s) { + if (!wpa_s->wps_success && + wpa_s->current_ssid && + eap_is_wps_pin_enrollee(&wpa_s->current_ssid->eap)) { + const u8 *bssid = wpa_s->bssid; + if (is_zero_ether_addr(bssid)) + bssid = wpa_s->pending_bssid; + + wpa_printf(MSG_DEBUG, "WPS: PIN registration with " MACSTR + " did not succeed - continue trying to find " + "suitable AP", MAC2STR(bssid)); + wpa_blacklist_add(wpa_s, bssid); + + wpa_supplicant_deauthenticate(wpa_s, + WLAN_REASON_DEAUTH_LEAVING); + wpa_s->reassociate = 1; + wpa_supplicant_req_scan(wpa_s, + wpa_s->blacklist_cleared ? 5 : 0, 0); + wpa_s->blacklist_cleared = 0; + return 1; + } + eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL); if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && wpa_s->current_ssid && @@ -234,6 +257,7 @@ static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s, static void wpa_supplicant_wps_event_success(struct wpa_supplicant *wpa_s) { wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_SUCCESS); + wpa_s->wps_success = 1; } @@ -291,7 +315,8 @@ static void wpas_clear_wps(struct wpa_supplicant *wpa_s) static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; - wpa_printf(MSG_DEBUG, "WPS: Requested operation timed out"); + wpa_printf(MSG_INFO, WPS_EVENT_TIMEOUT "Requested operation timed " + "out"); wpas_clear_wps(wpa_s); } @@ -363,6 +388,9 @@ static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s, } wpa_s->disconnected = 0; wpa_s->reassociate = 1; + wpa_s->scan_runs = 0; + wpa_s->wps_success = 0; + wpa_s->blacklist_cleared = 0; wpa_supplicant_req_scan(wpa_s, 0, 0); } @@ -550,7 +578,8 @@ void wpas_wps_deinit(struct wpa_supplicant *wpa_s) } -int wpas_wps_ssid_bss_match(struct wpa_ssid *ssid, struct wpa_scan_res *bss) +int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, struct wpa_scan_res *bss) { struct wpabuf *wps_ie; @@ -584,14 +613,24 @@ int wpas_wps_ssid_bss_match(struct wpa_ssid *ssid, struct wpa_scan_res *bss) return 0; } + /* + * Start with WPS APs that advertise active PIN Registrar and + * allow any WPS AP after third scan since some APs do not set + * Selected Registrar attribute properly when using external + * Registrar. + */ 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; + if (wpa_s->scan_runs < WPS_PIN_SCAN_IGNORE_SEL_REG) { + 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"); + } else { + wpa_printf(MSG_DEBUG, " selected based on WPS IE " + "(Active PIN)"); } - wpa_printf(MSG_DEBUG, " selected based on WPS IE " - "(Active PIN)"); wpabuf_free(wps_ie); return 1; } @@ -606,7 +645,8 @@ 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, +int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, struct wpa_scan_res *bss) { struct wpabuf *wps_ie = NULL; @@ -620,7 +660,9 @@ int wpas_wps_ssid_wildcard_ok(struct wpa_ssid *ssid, } } 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)) { + if (wps_ie && + (wps_is_selected_pin_registrar(wps_ie) || + wpa_s->scan_runs >= WPS_PIN_SCAN_IGNORE_SEL_REG)) { /* allow wildcard SSID for WPS PIN */ ret = 1; } diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h index 2993049d3..8f81dc4bd 100644 --- a/wpa_supplicant/wps_supplicant.h +++ b/wpa_supplicant/wps_supplicant.h @@ -29,8 +29,10 @@ 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_ssid_bss_match(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, struct wpa_scan_res *bss); +int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s, + 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); @@ -58,13 +60,15 @@ 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, +static inline int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, struct wpa_scan_res *bss) { return -1; } -static inline int wpas_wps_ssid_wildcard_ok(struct wpa_ssid *ssid, +static inline int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, struct wpa_scan_res *bss) { return 0;