WPS: Maintain more AP state during WPS PIN iteration

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>
This commit is contained in:
Jouni Malinen 2012-08-27 13:48:11 +03:00 committed by Jouni Malinen
parent 0d30cc240f
commit f9f0526bcd
5 changed files with 179 additions and 4 deletions

View 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;
}

View 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);
}

View 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;

View 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);
}

View 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 */