]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
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 5453962a5181b2f62e2c97d96030c8cec4233474..4c2322df8f0b25eff5a50079f354134172ef90e4 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 9f12a16d9f7c21aac06dd1c6172722253f9b2250..cddcce72dffcb9632cab629fe8129372cd6233c2 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 01ea87390be2b5b8aef2fab9976f4786cc870bff..632f6bc948a952e57f946e5755a5101510af1cd6 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 c72da1115934aa2ec096c81da5dc405ae48f4db8..3bb542757ce2db2194c69d9c6f79ea8e532ab465 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 5a49a8f2e9df8d49ee201e771b4e36ec1a788712..36f1e02184aee552145cef0c24cabef90ee0039f 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 */