diff --git a/src/wps/wps.c b/src/wps/wps.c index 5453962a5..4c2322df8 100644 --- a/src/wps/wps.c +++ b/src/wps/wps.c @@ -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; } diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 9f12a16d9..cddcce72d 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -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); } diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 01ea87390..632f6bc94 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -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; diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c index c72da1115..3bb542757 100644 --- a/wpa_supplicant/wps_supplicant.c +++ b/wpa_supplicant/wps_supplicant.c @@ -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); +} diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h index 5a49a8f2e..36f1e0218 100644 --- a/wpa_supplicant/wps_supplicant.h +++ b/wpa_supplicant/wps_supplicant.h @@ -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 */