From 8d923a4acfb8c43527cc9fe9571ebf341b8e0502 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sat, 2 Jan 2010 13:57:44 +0200 Subject: [PATCH] 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. --- src/drivers/driver.h | 22 +++++++++- src/drivers/driver_nl80211.c | 47 +++++++++++++++++++-- wpa_supplicant/bss.c | 54 ++++++++++++++++++++++--- wpa_supplicant/bss.h | 5 ++- wpa_supplicant/ctrl_iface.c | 2 +- wpa_supplicant/dbus/dbus_old.c | 2 +- wpa_supplicant/dbus/dbus_old_handlers.c | 2 +- wpa_supplicant/events.c | 10 +++-- wpa_supplicant/wpa_supplicant.c | 7 +++- wpa_supplicant/wpa_supplicant_i.h | 4 +- wpa_supplicant/wpas_glue.c | 2 +- 11 files changed, 133 insertions(+), 24 deletions(-) diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 8a459571f..1ee43c627 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -1,6 +1,6 @@ /* * WPA Supplicant - driver interface definition - * Copyright (c) 2003-2009, Jouni Malinen + * Copyright (c) 2003-2010, Jouni Malinen * * 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; }; /** diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 948efc2b5..9982c449e 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -1,6 +1,6 @@ /* * Driver interaction with Linux nl80211/cfg80211 - * Copyright (c) 2002-2008, Jouni Malinen + * Copyright (c) 2002-2010, Jouni Malinen * Copyright (c) 2003-2004, Instant802 Networks, Inc. * Copyright (c) 2005-2006, Devicescape Software, Inc. * Copyright (c) 2007, Johannes Berg @@ -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: diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c index 4d4e71e79..a981f89cb 100644 --- a/wpa_supplicant/bss.c +++ b/wpa_supplicant/bss.c @@ -1,6 +1,6 @@ /* * BSS table - * Copyright (c) 2009, Jouni Malinen + * Copyright (c) 2009-2010, Jouni Malinen * * 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) { diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h index 8ef52bc24..2242222ed 100644 --- a/wpa_supplicant/bss.h +++ b/wpa_supplicant/bss.h @@ -1,6 +1,6 @@ /* * BSS table - * Copyright (c) 2009, Jouni Malinen + * Copyright (c) 2009-2010, Jouni Malinen * * 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, diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 3bcf6e304..a82449aac 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -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; diff --git a/wpa_supplicant/dbus/dbus_old.c b/wpa_supplicant/dbus/dbus_old.c index 0d47142e0..2d0fbb6ac 100644 --- a/wpa_supplicant/dbus/dbus_old.c +++ b/wpa_supplicant/dbus/dbus_old.c @@ -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; } diff --git a/wpa_supplicant/dbus/dbus_old_handlers.c b/wpa_supplicant/dbus/dbus_old_handlers.c index ca2d755ec..ac794403d 100644 --- a/wpa_supplicant/dbus/dbus_old_handlers.c +++ b/wpa_supplicant/dbus/dbus_old_handlers.c @@ -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."); diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index b0dfe4162..a80104abb 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -1,6 +1,6 @@ /* * WPA Supplicant - Driver event processing - * Copyright (c) 2003-2009, Jouni Malinen + * Copyright (c) 2003-2010, Jouni Malinen * * 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: diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index e2dd31cc7..df537da4d 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -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; } diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 4eedac079..c05eb1453 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -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); diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c index 34f7bb49d..18f1bcd2a 100644 --- a/wpa_supplicant/wpas_glue.c +++ b/wpa_supplicant/wpas_glue.c @@ -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; }