WPS: Maintain more AP state during WPS PIN iteration
authorJouni Malinen <jouni@qca.qualcomm.com>
Mon, 27 Aug 2012 10:48:11 +0000 (13:48 +0300)
committerJouni Malinen <j@w1.fi>
Mon, 27 Aug 2012 10:48:11 +0000 (13:48 +0300)
Maintain state of WPS APs during iteration to find the correct AP for
WPS PIN operation when no specific BSSID is specified. This information
can be used for optimizing the order in which the APs are tried. This
commit is only adding the collection of the information and more
detailed debug information to make debug logs more helpful in figuring
out how the AP selection order could be improved.

Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>

src/wps/wps.c
wpa_supplicant/events.c
wpa_supplicant/wpa_supplicant_i.h
wpa_supplicant/wps_supplicant.c
wpa_supplicant/wps_supplicant.h

index 5453962..4c2322d 100644 (file)
@@ -287,7 +287,8 @@ int wps_is_selected_pin_registrar(const struct wpabuf *msg)
  * @msg: WPS IE contents from Beacon or Probe Response frame
  * @addr: MAC address to search for
  * @ver1_compat: Whether to use version 1 compatibility mode
- * Returns: 1 if address is authorized, 0 if not
+ * Returns: 2 if the specified address is explicit authorized, 1 if address is
+ * authorized (broadcast), 0 if not
  */
 int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr,
                           int ver1_compat)
@@ -313,8 +314,9 @@ int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr,
 
        pos = attr.authorized_macs;
        for (i = 0; i < attr.authorized_macs_len / ETH_ALEN; i++) {
-               if (os_memcmp(pos, addr, ETH_ALEN) == 0 ||
-                   os_memcmp(pos, bcast, ETH_ALEN) == 0)
+               if (os_memcmp(pos, addr, ETH_ALEN) == 0)
+                       return 2;
+               if (os_memcmp(pos, bcast, ETH_ALEN) == 0)
                        return 1;
                pos += ETH_ALEN;
        }
index 9f12a16..cddcce7 100644 (file)
@@ -1158,6 +1158,8 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
                return 0;
        }
 
+       wpas_wps_update_ap_info(wpa_s, scan_res);
+
        selected = wpa_supplicant_pick_network(wpa_s, scan_res, &ssid);
 
        if (selected) {
@@ -1732,6 +1734,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
                ibss_rsn_set_psk(wpa_s->ibss_rsn, wpa_s->current_ssid->psk);
        }
 #endif /* CONFIG_IBSS_RSN */
+
+       wpas_wps_notify_assoc(wpa_s, bssid);
 }
 
 
index 01ea873..632f6bc 100644 (file)
@@ -249,6 +249,17 @@ enum offchannel_send_action_result {
        OFFCHANNEL_SEND_ACTION_FAILED /* Frame was not sent due to a failure */
 };
 
+struct wps_ap_info {
+       u8 bssid[ETH_ALEN];
+       enum wps_ap_info_type {
+               WPS_AP_NOT_SEL_REG,
+               WPS_AP_SEL_REG,
+               WPS_AP_SEL_REG_OUR
+       } type;
+       unsigned int tries;
+       struct os_time last_attempt;
+};
+
 /**
  * struct wpa_supplicant - Internal data for wpa_supplicant interface
  *
@@ -538,6 +549,10 @@ struct wpa_supplicant {
 
        struct wpa_ssid *connect_without_scan;
 
+       struct wps_ap_info *wps_ap;
+       size_t num_wps_ap;
+       int wps_ap_iter;
+
        int after_wps;
        int known_wps_freq;
        unsigned int wps_freq;
index c72da11..3bb5427 100644 (file)
@@ -43,6 +43,15 @@ static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx);
 static void wpas_clear_wps(struct wpa_supplicant *wpa_s);
 
 
+static void wpas_wps_clear_ap_info(struct wpa_supplicant *wpa_s)
+{
+       os_free(wpa_s->wps_ap);
+       wpa_s->wps_ap = NULL;
+       wpa_s->num_wps_ap = 0;
+       wpa_s->wps_ap_iter = 0;
+}
+
+
 int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
 {
        if (!wpa_s->wps_success &&
@@ -66,6 +75,7 @@ int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
                return 1;
        }
 
+       wpas_wps_clear_ap_info(wpa_s);
        eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
        if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && !wpa_s->wps_success)
                wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_FAIL);
@@ -706,6 +716,8 @@ static void wpas_clear_wps(struct wpa_supplicant *wpa_s)
                        wpa_config_remove_network(wpa_s->conf, id);
                }
        }
+
+       wpas_wps_clear_ap_info(wpa_s);
 }
 
 
@@ -901,6 +913,7 @@ int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
                ssid->eap.fragment_size = wpa_s->wps_fragment_size;
        eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
                               wpa_s, NULL);
+       wpa_s->wps_ap_iter = 1;
        wpas_wps_reassoc(wpa_s, ssid, bssid);
        return rpin;
 }
@@ -927,7 +940,8 @@ int wpas_wps_cancel(struct wpa_supplicant *wpa_s)
                wpa_supplicant_deauthenticate(wpa_s,
                                              WLAN_REASON_DEAUTH_LEAVING);
                wpas_clear_wps(wpa_s);
-       }
+       } else
+               wpas_wps_clear_ap_info(wpa_s);
 
        return 0;
 }
@@ -1233,6 +1247,7 @@ int wpas_wps_init(struct wpa_supplicant *wpa_s)
 void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
 {
        eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
+       wpas_wps_clear_ap_info(wpa_s);
 
        if (wpa_s->wps == NULL)
                return;
@@ -1914,3 +1929,128 @@ int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s,
 }
 
 #endif /* CONFIG_WPS_NFC */
+
+
+extern int wpa_debug_level;
+
+static void wpas_wps_dump_ap_info(struct wpa_supplicant *wpa_s)
+{
+       size_t i;
+       struct os_time now;
+
+       if (wpa_debug_level > MSG_DEBUG)
+               return;
+
+       if (wpa_s->wps_ap == NULL)
+               return;
+
+       os_get_time(&now);
+
+       for (i = 0; i < wpa_s->num_wps_ap; i++) {
+               struct wps_ap_info *ap = &wpa_s->wps_ap[i];
+               struct wpa_blacklist *e = wpa_blacklist_get(wpa_s, ap->bssid);
+
+               wpa_printf(MSG_DEBUG, "WPS: AP[%d] " MACSTR " type=%d "
+                          "tries=%d last_attempt=%d sec ago blacklist=%d",
+                          (int) i, MAC2STR(ap->bssid), ap->type, ap->tries,
+                          ap->last_attempt.sec > 0 ?
+                          (int) now.sec - (int) ap->last_attempt.sec : -1,
+                          e ? e->count : 0);
+       }
+}
+
+
+static struct wps_ap_info * wpas_wps_get_ap_info(struct wpa_supplicant *wpa_s,
+                                                const u8 *bssid)
+{
+       size_t i;
+
+       if (wpa_s->wps_ap == NULL)
+               return NULL;
+
+       for (i = 0; i < wpa_s->num_wps_ap; i++) {
+               struct wps_ap_info *ap = &wpa_s->wps_ap[i];
+               if (os_memcmp(ap->bssid, bssid, ETH_ALEN) == 0)
+                       return ap;
+       }
+
+       return NULL;
+}
+
+
+static void wpas_wps_update_ap_info_bss(struct wpa_supplicant *wpa_s,
+                                       struct wpa_scan_res *res)
+{
+       struct wpabuf *wps;
+       enum wps_ap_info_type type;
+       struct wps_ap_info *ap;
+       int r;
+
+       if (wpa_scan_get_vendor_ie(res, WPS_IE_VENDOR_TYPE) == NULL)
+               return;
+
+       wps = wpa_scan_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE);
+       if (wps == NULL)
+               return;
+
+       r = wps_is_addr_authorized(wps, wpa_s->own_addr, 1);
+       if (r == 2)
+               type = WPS_AP_SEL_REG_OUR;
+       else if (r == 1)
+               type = WPS_AP_SEL_REG;
+       else
+               type = WPS_AP_NOT_SEL_REG;
+
+       wpabuf_free(wps);
+
+       ap = wpas_wps_get_ap_info(wpa_s, res->bssid);
+       if (ap) {
+               if (ap->type != type) {
+                       wpa_printf(MSG_DEBUG, "WPS: AP " MACSTR
+                                  " changed type %d -> %d",
+                                  MAC2STR(res->bssid), ap->type, type);
+                       ap->type = type;
+               }
+               return;
+       }
+
+       ap = os_realloc_array(wpa_s->wps_ap, wpa_s->num_wps_ap + 1,
+                             sizeof(struct wps_ap_info));
+       if (ap == NULL)
+               return;
+
+       wpa_s->wps_ap = ap;
+       ap = &wpa_s->wps_ap[wpa_s->num_wps_ap];
+       wpa_s->num_wps_ap++;
+
+       os_memset(ap, 0, sizeof(*ap));
+       os_memcpy(ap->bssid, res->bssid, ETH_ALEN);
+       ap->type = type;
+       wpa_printf(MSG_DEBUG, "WPS: AP " MACSTR " type %d added",
+                  MAC2STR(ap->bssid), ap->type);
+}
+
+
+void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
+                            struct wpa_scan_results *scan_res)
+{
+       size_t i;
+
+       for (i = 0; i < scan_res->num; i++)
+               wpas_wps_update_ap_info_bss(wpa_s, scan_res->res[i]);
+
+       wpas_wps_dump_ap_info(wpa_s);
+}
+
+
+void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+       struct wps_ap_info *ap;
+       if (!wpa_s->wps_ap_iter)
+               return;
+       ap = wpas_wps_get_ap_info(wpa_s, bssid);
+       if (ap == NULL)
+               return;
+       ap->tries++;
+       os_get_time(&ap->last_attempt);
+}
index 5a49a8f..36f1e02 100644 (file)
@@ -10,6 +10,7 @@
 #define WPS_SUPPLICANT_H
 
 struct wpa_scan_res;
+struct wpa_scan_results;
 
 #ifdef CONFIG_WPS
 
@@ -68,6 +69,9 @@ struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef);
 int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid);
 int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s,
                          const struct wpabuf *data);
+void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
+                            struct wpa_scan_results *scan_res);
+void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid);
 
 #else /* CONFIG_WPS */
 
@@ -120,6 +124,16 @@ static inline int wpas_wps_searching(struct wpa_supplicant *wpa_s)
        return 0;
 }
 
+static inline void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
+                                          struct wpa_scan_results *scan_res)
+{
+}
+
+static inline void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s,
+                                        const u8 *bssid)
+{
+}
+
 #endif /* CONFIG_WPS */
 
 #endif /* WPS_SUPPLICANT_H */