Allow WPS APs for PIN enrollment even without Selected Registrar
authorJouni Malinen <jouni.malinen@atheros.com>
Fri, 23 Jan 2009 11:10:58 +0000 (13:10 +0200)
committerJouni Malinen <j@w1.fi>
Fri, 23 Jan 2009 11:10:58 +0000 (13:10 +0200)
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.

src/common/wpa_ctrl.h
wpa_supplicant/events.c
wpa_supplicant/scan.c
wpa_supplicant/wpa_supplicant_i.h
wpa_supplicant/wps_supplicant.c
wpa_supplicant/wps_supplicant.h

index 87a4c6b..f7cad57 100644 (file)
@@ -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 "
index e169949..703106c 100644 (file)
@@ -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;
                }
index afc3411..67e2282 100644 (file)
@@ -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++;
 }
 
 
index c629a7e..b49f23a 100644 (file)
@@ -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;
 };
index 14f1f86..2dd22f2 100644 (file)
 #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;
                }
index 2993049..8f81dc4 100644 (file)
@@ -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;