Browse Source

Allow WPS APs for PIN enrollment even without Selected Registrar

Some WPS APs do not set Selected Registrar attribute to 1 properly when
using an external Registrar. Allow such an AP to be selected for PIN
registration after couple of scan runs that do not find APs marked with
Selected Registrar = 1. This allows wpa_supplicant to iterate through
all APs that advertise WPS support without delaying connection with
implementations that set Selected Registrar = 1 properly.
Jouni Malinen 16 years ago
parent
commit
a609915233

+ 2 - 0
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 "

+ 8 - 5
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;
 		}

+ 2 - 1
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++;
 }
 
 

+ 3 - 0
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;
 };

+ 52 - 10
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;
 		}

+ 8 - 4
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;