Only expire scanned BSSes based on new scan results

Get more information about scans when updating BSS table information.
This allows the missing-from-scans expiration rule to work properly
when only partial set of channels or SSIDs are being scanned.
This commit is contained in:
Jouni Malinen 2010-01-02 13:57:44 +02:00
parent 59f2caa925
commit 8d923a4acf
11 changed files with 133 additions and 24 deletions

View file

@ -1,6 +1,6 @@
/* /*
* WPA Supplicant - driver interface definition * WPA Supplicant - driver interface definition
* Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi> * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@ -1577,7 +1577,8 @@ typedef enum wpa_event_type {
* EVENT_SCAN_RESULTS call. If such event is not available from the * EVENT_SCAN_RESULTS call. If such event is not available from the
* driver, the driver wrapper code is expected to use a registered * driver, the driver wrapper code is expected to use a registered
* timeout to generate EVENT_SCAN_RESULTS call after the time that the * timeout to generate EVENT_SCAN_RESULTS call after the time that the
* scan is expected to be completed. * scan is expected to be completed. Optional information about
* completed scan can be provided with union wpa_event_data::scan_info.
*/ */
EVENT_SCAN_RESULTS, EVENT_SCAN_RESULTS,
@ -1948,6 +1949,23 @@ union wpa_event_data {
size_t frame_len; size_t frame_len;
struct hostapd_frame_info *fi; struct hostapd_frame_info *fi;
} rx_mgmt; } rx_mgmt;
/**
* struct scan_info - Optional data for EVENT_SCAN_RESULTS events
* @aborted: Whether the scan was aborted
* @freqs: Scanned frequencies in MHz (%NULL = all channels scanned)
* @num_freqs: Number of entries in freqs array
* @ssids: Scanned SSIDs (%NULL or zero-length SSID indicates wildcard
* SSID)
* @num_ssids: Number of entries in ssids array
*/
struct scan_info {
int aborted;
const int *freqs;
size_t num_freqs;
struct wpa_driver_scan_ssid ssids[WPAS_MAX_SCAN_SSIDS];
size_t num_ssids;
} scan_info;
}; };
/** /**

View file

@ -1,6 +1,6 @@
/* /*
* Driver interaction with Linux nl80211/cfg80211 * Driver interaction with Linux nl80211/cfg80211
* Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi> * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
* Copyright (c) 2003-2004, Instant802 Networks, Inc. * Copyright (c) 2003-2004, Instant802 Networks, Inc.
* Copyright (c) 2005-2006, Devicescape Software, Inc. * Copyright (c) 2005-2006, Devicescape Software, Inc.
* Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net> * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
@ -707,6 +707,47 @@ static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv,
} }
static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
struct nlattr *tb[])
{
union wpa_event_data event;
struct nlattr *nl;
int rem;
struct scan_info *info;
#define MAX_REPORT_FREQS 50
int freqs[MAX_REPORT_FREQS];
int num_freqs = 0;
os_memset(&event, 0, sizeof(event));
info = &event.scan_info;
info->aborted = aborted;
if (tb[NL80211_ATTR_SCAN_SSIDS]) {
nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_SSIDS], rem) {
struct wpa_driver_scan_ssid *s =
&info->ssids[info->num_ssids];
s->ssid = nla_data(nl);
s->ssid_len = nla_len(nl);
info->num_ssids++;
if (info->num_ssids == WPAS_MAX_SCAN_SSIDS)
break;
}
}
if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) {
nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem)
{
freqs[num_freqs] = nla_get_u32(nl);
num_freqs++;
if (num_freqs == MAX_REPORT_FREQS - 1)
break;
}
info->freqs = freqs;
info->num_freqs = num_freqs;
}
wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);
}
static int process_event(struct nl_msg *msg, void *arg) static int process_event(struct nl_msg *msg, void *arg)
{ {
struct wpa_driver_nl80211_data *drv = arg; struct wpa_driver_nl80211_data *drv = arg;
@ -742,7 +783,7 @@ static int process_event(struct nl_msg *msg, void *arg)
drv->scan_complete_events = 1; drv->scan_complete_events = 1;
eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
drv->ctx); drv->ctx);
wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL); send_scan_event(drv, 0, tb);
break; break;
case NL80211_CMD_SCAN_ABORTED: case NL80211_CMD_SCAN_ABORTED:
wpa_printf(MSG_DEBUG, "nl80211: Scan aborted"); wpa_printf(MSG_DEBUG, "nl80211: Scan aborted");
@ -752,7 +793,7 @@ static int process_event(struct nl_msg *msg, void *arg)
*/ */
eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
drv->ctx); drv->ctx);
wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL); send_scan_event(drv, 1, tb);
break; break;
case NL80211_CMD_AUTHENTICATE: case NL80211_CMD_AUTHENTICATE:
case NL80211_CMD_ASSOCIATE: case NL80211_CMD_ASSOCIATE:

View file

@ -1,6 +1,6 @@
/* /*
* BSS table * BSS table
* Copyright (c) 2009, Jouni Malinen <j@w1.fi> * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@ -195,16 +195,58 @@ void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
} }
void wpa_bss_update_end(struct wpa_supplicant *wpa_s) static int wpa_bss_included_in_scan(const struct wpa_bss *bss,
const struct scan_info *info)
{
int found;
size_t i;
if (info == NULL)
return 1;
if (info->num_freqs) {
found = 0;
for (i = 0; i < info->num_freqs; i++) {
if (bss->freq == info->freqs[i]) {
found = 1;
break;
}
}
if (!found)
return 0;
}
if (info->num_ssids) {
found = 0;
for (i = 0; i < info->num_ssids; i++) {
const struct wpa_driver_scan_ssid *s = &info->ssids[i];
if ((s->ssid == NULL || s->ssid_len == 0) ||
(s->ssid_len == bss->ssid_len &&
os_memcmp(s->ssid, bss->ssid, bss->ssid_len) ==
0)) {
found = 1;
break;
}
}
if (!found)
return 0;
}
return 1;
}
void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
int new_scan)
{ {
struct wpa_bss *bss, *n; struct wpa_bss *bss, *n;
/* TODO: expire only entries that were on the scanned frequencies/SSIDs if (!new_scan)
* list; need to get info from driver about scanned frequencies and return; /* do not expire entries without new scan */
* SSIDs to be able to figure out which entries should be expired based
* on this */
dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) { dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
if (!wpa_bss_included_in_scan(bss, info))
continue; /* expire only BSSes that were scanned */
if (bss->last_update_idx < wpa_s->bss_update_idx) if (bss->last_update_idx < wpa_s->bss_update_idx)
bss->scan_miss_count++; bss->scan_miss_count++;
if (bss->scan_miss_count >= WPA_BSS_EXPIRATION_SCAN_COUNT) { if (bss->scan_miss_count >= WPA_BSS_EXPIRATION_SCAN_COUNT) {

View file

@ -1,6 +1,6 @@
/* /*
* BSS table * BSS table
* Copyright (c) 2009, Jouni Malinen <j@w1.fi> * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@ -69,7 +69,8 @@ struct wpa_bss {
void wpa_bss_update_start(struct wpa_supplicant *wpa_s); void wpa_bss_update_start(struct wpa_supplicant *wpa_s);
void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s, void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
struct wpa_scan_res *res); struct wpa_scan_res *res);
void wpa_bss_update_end(struct wpa_supplicant *wpa_s); void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
int new_scan);
int wpa_bss_init(struct wpa_supplicant *wpa_s); int wpa_bss_init(struct wpa_supplicant *wpa_s);
void wpa_bss_deinit(struct wpa_supplicant *wpa_s); void wpa_bss_deinit(struct wpa_supplicant *wpa_s);
struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid, struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,

View file

@ -882,7 +882,7 @@ static int wpa_supplicant_ctrl_iface_scan_results(
size_t i; size_t i;
if (wpa_s->scan_res == NULL && if (wpa_s->scan_res == NULL &&
wpa_supplicant_get_scan_results(wpa_s) < 0) wpa_supplicant_get_scan_results(wpa_s, NULL, 0) < 0)
return 0; return 0;
pos = buf; pos = buf;

View file

@ -185,7 +185,7 @@ static DBusMessage * wpas_dispatch_bssid_method(DBusMessage *message,
/* Ensure we actually have scan data */ /* Ensure we actually have scan data */
if (wpa_s->scan_res == NULL && if (wpa_s->scan_res == NULL &&
wpa_supplicant_get_scan_results(wpa_s) < 0) { wpa_supplicant_get_scan_results(wpa_s, NULL, 0) < 0) {
reply = wpas_dbus_new_invalid_bssid_error(message); reply = wpas_dbus_new_invalid_bssid_error(message);
goto out; goto out;
} }

View file

@ -361,7 +361,7 @@ DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message,
/* Ensure we've actually got scan results to return */ /* Ensure we've actually got scan results to return */
if (wpa_s->scan_res == NULL && if (wpa_s->scan_res == NULL &&
wpa_supplicant_get_scan_results(wpa_s) < 0) { wpa_supplicant_get_scan_results(wpa_s, NULL, 0) < 0) {
return dbus_message_new_error(message, WPAS_ERROR_SCAN_ERROR, return dbus_message_new_error(message, WPAS_ERROR_SCAN_ERROR,
"An error ocurred getting scan " "An error ocurred getting scan "
"results."); "results.");

View file

@ -1,6 +1,6 @@
/* /*
* WPA Supplicant - Driver event processing * WPA Supplicant - Driver event processing
* Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi> * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@ -763,14 +763,16 @@ static void wpa_supplicant_rsn_preauth_scan_results(
} }
static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s) static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{ {
struct wpa_scan_res *selected; struct wpa_scan_res *selected;
struct wpa_ssid *ssid = NULL; struct wpa_ssid *ssid = NULL;
wpa_supplicant_notify_scanning(wpa_s, 0); wpa_supplicant_notify_scanning(wpa_s, 0);
if (wpa_supplicant_get_scan_results(wpa_s) < 0) { if (wpa_supplicant_get_scan_results(wpa_s, data ? &data->scan_info :
NULL, 1) < 0) {
if (wpa_s->conf->ap_scan == 2) if (wpa_s->conf->ap_scan == 2)
return; return;
wpa_printf(MSG_DEBUG, "Failed to get scan results - try " wpa_printf(MSG_DEBUG, "Failed to get scan results - try "
@ -1402,7 +1404,7 @@ void wpa_supplicant_event(void *ctx, wpa_event_type event,
break; break;
#ifndef CONFIG_NO_SCAN_PROCESSING #ifndef CONFIG_NO_SCAN_PROCESSING
case EVENT_SCAN_RESULTS: case EVENT_SCAN_RESULTS:
wpa_supplicant_event_scan_results(wpa_s); wpa_supplicant_event_scan_results(wpa_s, data);
break; break;
#endif /* CONFIG_NO_SCAN_PROCESSING */ #endif /* CONFIG_NO_SCAN_PROCESSING */
case EVENT_ASSOCINFO: case EVENT_ASSOCINFO:

View file

@ -1570,12 +1570,15 @@ int wpa_supplicant_set_debug_params(struct wpa_global *global, int debug_level,
/** /**
* wpa_supplicant_get_scan_results - Get scan results * wpa_supplicant_get_scan_results - Get scan results
* @wpa_s: Pointer to wpa_supplicant data * @wpa_s: Pointer to wpa_supplicant data
* @info: Information about what was scanned or %NULL if not available
* @new_scan: Whether a new scan was performed
* Returns: 0 on success, -1 on failure * Returns: 0 on success, -1 on failure
* *
* This function request the current scan results from the driver and updates * This function request the current scan results from the driver and updates
* the local BSS list wpa_s->bss. * the local BSS list wpa_s->bss.
*/ */
int wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s) int wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,
struct scan_info *info, int new_scan)
{ {
size_t i; size_t i;
@ -1594,7 +1597,7 @@ int wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s)
wpa_bss_update_start(wpa_s); wpa_bss_update_start(wpa_s);
for (i = 0; i < wpa_s->scan_res->num; i++) for (i = 0; i < wpa_s->scan_res->num; i++)
wpa_bss_update_scan_res(wpa_s, wpa_s->scan_res->res[i]); wpa_bss_update_scan_res(wpa_s, wpa_s->scan_res->res[i]);
wpa_bss_update_end(wpa_s); wpa_bss_update_end(wpa_s, info, new_scan);
return 0; return 0;
} }

View file

@ -33,6 +33,7 @@ struct wpa_scan_res;
struct wpa_sm; struct wpa_sm;
struct wpa_supplicant; struct wpa_supplicant;
struct ibss_rsn; struct ibss_rsn;
struct scan_info;
/* /*
* Forward declarations of private structures used within the ctrl_iface * Forward declarations of private structures used within the ctrl_iface
@ -445,7 +446,8 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s, void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid); struct wpa_ssid *ssid);
void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s); void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s);
int wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s); int wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,
struct scan_info *info, int new_scan);
void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr); void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr);
void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s, void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
int sec, int usec); int sec, int usec);

View file

@ -348,7 +348,7 @@ static int wpa_supplicant_get_beacon_ie(void *ctx)
/* No WPA/RSN IE found in the cached scan results. Try to get updated /* No WPA/RSN IE found in the cached scan results. Try to get updated
* scan results from the driver. */ * scan results from the driver. */
if (wpa_supplicant_get_scan_results(wpa_s) < 0) { if (wpa_supplicant_get_scan_results(wpa_s, NULL, 0) < 0) {
return -1; return -1;
} }