Only expire scanned BSSes based on new scan results
authorJouni Malinen <j@w1.fi>
Sat, 2 Jan 2010 11:57:44 +0000 (13:57 +0200)
committerJouni Malinen <j@w1.fi>
Sat, 2 Jan 2010 11:57:44 +0000 (13:57 +0200)
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
src/drivers/driver_nl80211.c
wpa_supplicant/bss.c
wpa_supplicant/bss.h
wpa_supplicant/ctrl_iface.c
wpa_supplicant/dbus/dbus_old.c
wpa_supplicant/dbus/dbus_old_handlers.c
wpa_supplicant/events.c
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpa_supplicant_i.h
wpa_supplicant/wpas_glue.c

index 8a45957..1ee43c6 100644 (file)
@@ -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;
 };
 
 /**
index 948efc2..9982c44 100644 (file)
@@ -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:
index 4d4e71e..a981f89 100644 (file)
@@ -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) {
index 8ef52bc..2242222 100644 (file)
@@ -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,
index 3bcf6e3..a82449a 100644 (file)
@@ -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;
index 0d47142..2d0fbb6 100644 (file)
@@ -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;
        }
index ca2d755..ac79440 100644 (file)
@@ -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.");
index b0dfe41..a80104a 100644 (file)
@@ -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:
index e2dd31c..df537da 100644 (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_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;
 }
index 4eedac0..c05eb14 100644 (file)
@@ -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);
index 34f7bb4..18f1bcd 100644 (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
         * 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;
        }