From cfadab269f78e1f7f197d07dded70c138f651be1 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sat, 3 Dec 2016 19:26:47 +0200 Subject: [PATCH] nl80211: Move duplicate scan result removal to bss.c The way the removal of duplicated (one per frequency) BSS entries in the cfg80211 scan results were removed in driver_nl80211_scan.c bss_info_handler() depended on having the full scan results available to allow iteration through the other entries. This is problematic for the goal of being able to optimize memory allocations for scan result fetching in a manner that would not build the full result buffer in memory. Move this duplicate removal into bss.c since it has sufficient information available for doing the same determination of which one of two BSS entries is more current. Signed-off-by: Jouni Malinen --- src/drivers/driver_nl80211_scan.c | 41 ------------------------------- wpa_supplicant/bss.c | 36 +++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 41 deletions(-) diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c index 4d16428f7..f07ef874e 100644 --- a/src/drivers/driver_nl80211_scan.c +++ b/src/drivers/driver_nl80211_scan.c @@ -651,7 +651,6 @@ int bss_info_handler(struct nl_msg *msg, void *arg) const u8 *ie, *beacon_ie; size_t ie_len, beacon_ie_len; u8 *pos; - size_t i; nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); @@ -759,46 +758,6 @@ int bss_info_handler(struct nl_msg *msg, void *arg) } } - /* - * cfg80211 maintains separate BSS table entries for APs if the same - * BSSID,SSID pair is seen on multiple channels. wpa_supplicant does - * not use frequency as a separate key in the BSS table, so filter out - * duplicated entries. Prefer associated BSS entry in such a case in - * order to get the correct frequency into the BSS table. Similarly, - * prefer newer entries over older. - */ - for (i = 0; i < res->num; i++) { - const u8 *s1, *s2; - if (os_memcmp(res->res[i]->bssid, r->bssid, ETH_ALEN) != 0) - continue; - - s1 = get_ie((u8 *) (res->res[i] + 1), - res->res[i]->ie_len, WLAN_EID_SSID); - s2 = get_ie((u8 *) (r + 1), r->ie_len, WLAN_EID_SSID); - if (s1 == NULL || s2 == NULL || s1[1] != s2[1] || - os_memcmp(s1, s2, 2 + s1[1]) != 0) - continue; - - /* Same BSSID,SSID was already included in scan results */ - wpa_printf(MSG_DEBUG, - "nl80211: Remove duplicated scan result for " MACSTR - " (assoc/age/freq prev=%d/%d/%d new=%d/%d/%d)", - MAC2STR(r->bssid), - !!(res->res[i]->flags & WPA_SCAN_ASSOCIATED), - res->res[i]->age, res->res[i]->freq, - !!(r->flags & WPA_SCAN_ASSOCIATED), - r->age, r->freq); - - if (((r->flags & WPA_SCAN_ASSOCIATED) && - !(res->res[i]->flags & WPA_SCAN_ASSOCIATED)) || - r->age < res->res[i]->age) { - os_free(res->res[i]); - res->res[i] = r; - } else - os_free(r); - return NL_SKIP; - } - tmp = os_realloc_array(res->res, res->num + 1, sizeof(struct wpa_scan_res *)); if (tmp == NULL) { diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c index 3a8778db9..44a9a7b2c 100644 --- a/wpa_supplicant/bss.c +++ b/wpa_supplicant/bss.c @@ -595,6 +595,42 @@ wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, { u32 changes; + if (bss->last_update_idx == wpa_s->bss_update_idx) { + struct os_reltime update_time; + + /* + * Some drivers (e.g., cfg80211) include multiple BSS entries + * for the same BSS if that BSS's channel changes. The BSS list + * implementation in wpa_supplicant does not do that and we need + * to filter out the obsolete results here to make sure only the + * most current BSS information remains in the table. + */ + wpa_printf(MSG_DEBUG, "BSS: " MACSTR + " has multiple entries in the scan results - select the most current one", + MAC2STR(bss->bssid)); + calculate_update_time(fetch_time, res->age, &update_time); + wpa_printf(MSG_DEBUG, + "Previous last_update: %u.%06u (freq %d%s)", + (unsigned int) bss->last_update.sec, + (unsigned int) bss->last_update.usec, + bss->freq, + (bss->flags & WPA_BSS_ASSOCIATED) ? " assoc" : ""); + wpa_printf(MSG_DEBUG, "New last_update: %u.%06u (freq %d%s)", + (unsigned int) update_time.sec, + (unsigned int) update_time.usec, + res->freq, + (res->flags & WPA_SCAN_ASSOCIATED) ? " assoc" : ""); + if ((bss->flags & WPA_BSS_ASSOCIATED) || + (!(res->flags & WPA_SCAN_ASSOCIATED) && + !os_reltime_before(&bss->last_update, &update_time))) { + wpa_printf(MSG_DEBUG, + "Ignore this BSS entry since the previous update looks more current"); + return bss; + } + wpa_printf(MSG_DEBUG, + "Accept this BSS entry since it looks more current than the previous update"); + } + changes = wpa_bss_compare_res(bss, res); if (changes & WPA_BSS_FREQ_CHANGED_FLAG) wpa_printf(MSG_DEBUG, "BSS: " MACSTR " changed freq %d --> %d",