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:
parent
59f2caa925
commit
8d923a4acf
11 changed files with 133 additions and 24 deletions
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* 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
|
||||
* 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
|
||||
* driver, the driver wrapper code is expected to use a registered
|
||||
* 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,
|
||||
|
||||
|
@ -1948,6 +1949,23 @@ union wpa_event_data {
|
|||
size_t frame_len;
|
||||
struct hostapd_frame_info *fi;
|
||||
} 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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* 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) 2005-2006, Devicescape Software, Inc.
|
||||
* 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)
|
||||
{
|
||||
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;
|
||||
eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
|
||||
drv->ctx);
|
||||
wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL);
|
||||
send_scan_event(drv, 0, tb);
|
||||
break;
|
||||
case NL80211_CMD_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,
|
||||
drv->ctx);
|
||||
wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL);
|
||||
send_scan_event(drv, 1, tb);
|
||||
break;
|
||||
case NL80211_CMD_AUTHENTICATE:
|
||||
case NL80211_CMD_ASSOCIATE:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* 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
|
||||
* 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;
|
||||
|
||||
/* TODO: expire only entries that were on the scanned frequencies/SSIDs
|
||||
* list; need to get info from driver about scanned frequencies and
|
||||
* SSIDs to be able to figure out which entries should be expired based
|
||||
* on this */
|
||||
if (!new_scan)
|
||||
return; /* do not expire entries without new scan */
|
||||
|
||||
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)
|
||||
bss->scan_miss_count++;
|
||||
if (bss->scan_miss_count >= WPA_BSS_EXPIRATION_SCAN_COUNT) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* 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
|
||||
* 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_scan_res(struct wpa_supplicant *wpa_s,
|
||||
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);
|
||||
void wpa_bss_deinit(struct wpa_supplicant *wpa_s);
|
||||
struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
|
||||
|
|
|
@ -882,7 +882,7 @@ static int wpa_supplicant_ctrl_iface_scan_results(
|
|||
size_t i;
|
||||
|
||||
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;
|
||||
|
||||
pos = buf;
|
||||
|
|
|
@ -185,7 +185,7 @@ static DBusMessage * wpas_dispatch_bssid_method(DBusMessage *message,
|
|||
|
||||
/* Ensure we actually have scan data */
|
||||
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);
|
||||
goto out;
|
||||
}
|
||||
|
|
|
@ -361,7 +361,7 @@ DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message,
|
|||
|
||||
/* Ensure we've actually got scan results to return */
|
||||
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,
|
||||
"An error ocurred getting scan "
|
||||
"results.");
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* 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
|
||||
* 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_ssid *ssid = NULL;
|
||||
|
||||
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)
|
||||
return;
|
||||
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;
|
||||
#ifndef CONFIG_NO_SCAN_PROCESSING
|
||||
case EVENT_SCAN_RESULTS:
|
||||
wpa_supplicant_event_scan_results(wpa_s);
|
||||
wpa_supplicant_event_scan_results(wpa_s, data);
|
||||
break;
|
||||
#endif /* CONFIG_NO_SCAN_PROCESSING */
|
||||
case EVENT_ASSOCINFO:
|
||||
|
|
|
@ -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_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
|
||||
*
|
||||
* This function request the current scan results from the driver and updates
|
||||
* 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;
|
||||
|
||||
|
@ -1594,7 +1597,7 @@ int wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s)
|
|||
wpa_bss_update_start(wpa_s);
|
||||
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_end(wpa_s);
|
||||
wpa_bss_update_end(wpa_s, info, new_scan);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ struct wpa_scan_res;
|
|||
struct wpa_sm;
|
||||
struct wpa_supplicant;
|
||||
struct ibss_rsn;
|
||||
struct scan_info;
|
||||
|
||||
/*
|
||||
* 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,
|
||||
struct wpa_ssid *ssid);
|
||||
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_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
|
||||
int sec, int usec);
|
||||
|
|
|
@ -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
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue