From a6b71f726a2c3223ea305bcf1bc6777635603827 Mon Sep 17 00:00:00 2001 From: Paul Stewart Date: Mon, 4 Jun 2012 21:52:08 +0300 Subject: [PATCH] bss: Don't remove a BSS that is in use When looking for a BSS to eject due to too many entries, never pick one that is in use. Otherwise, we run the risk of having pointers to freed data. Signed-hostap: Paul Stewart --- wpa_supplicant/bss.c | 63 +++++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c index a37311635..580a82aa8 100644 --- a/wpa_supplicant/bss.c +++ b/wpa_supplicant/bss.c @@ -35,14 +35,15 @@ #define WPA_BSS_IES_CHANGED_FLAG BIT(8) -static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) +static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, + const char *reason) { dl_list_del(&bss->list); dl_list_del(&bss->list_id); wpa_s->num_bss--; wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Remove id %u BSSID " MACSTR - " SSID '%s'", bss->id, MAC2STR(bss->bssid), - wpa_ssid_txt(bss->ssid, bss->ssid_len)); + " SSID '%s' due to %s", bss->id, MAC2STR(bss->bssid), + wpa_ssid_txt(bss->ssid, bss->ssid_len), reason); wpas_notify_bss_removed(wpa_s, bss->bssid, bss->id); #ifdef CONFIG_INTERWORKING wpabuf_free(bss->anqp_venue_name); @@ -120,13 +121,21 @@ static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) } +static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) +{ + return bss == wpa_s->current_bss || + os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 || + os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0; +} + + static int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s) { struct wpa_bss *bss; dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { if (!wpa_bss_known(wpa_s, bss)) { - wpa_bss_remove(wpa_s, bss); + wpa_bss_remove(wpa_s, bss, __func__); return 0; } } @@ -135,21 +144,28 @@ static int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s) } -static void wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s) +static int wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s) { + struct wpa_bss *bss; + /* * Remove the oldest entry that does not match with any configured * network. */ if (wpa_bss_remove_oldest_unknown(wpa_s) == 0) - return; + return 0; /* - * Remove the oldest entry since no better candidate for removal was - * found. + * Remove the oldest entry that isn't currently in use. */ - wpa_bss_remove(wpa_s, dl_list_first(&wpa_s->bss, - struct wpa_bss, list)); + dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { + if (!wpa_bss_in_use(wpa_s, bss)) { + wpa_bss_remove(wpa_s, bss, __func__); + return 0; + } + } + + return -1; } @@ -178,8 +194,13 @@ static void wpa_bss_add(struct wpa_supplicant *wpa_s, " SSID '%s'", bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len)); wpas_notify_bss_added(wpa_s, bss->bssid, bss->id); - if (wpa_s->num_bss > wpa_s->conf->bss_max_count) - wpa_bss_remove_oldest(wpa_s); + if (wpa_s->num_bss > wpa_s->conf->bss_max_count && + wpa_bss_remove_oldest(wpa_s) != 0) { + wpa_printf(MSG_ERROR, "Increasing the MAX BSS count to %d " + "because all BSSes are in use. We should normally " + "not get here!", (int) wpa_s->num_bss); + wpa_s->conf->bss_max_count = wpa_s->num_bss; + } } @@ -350,14 +371,6 @@ static void wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, } -static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) -{ - return bss == wpa_s->current_bss || - os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 || - os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0; -} - - void wpa_bss_update_start(struct wpa_supplicant *wpa_s) { wpa_s->bss_update_idx++; @@ -469,9 +482,7 @@ void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info, bss->scan_miss_count++; if (bss->scan_miss_count >= wpa_s->conf->bss_expiration_scan_count) { - wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Expire BSS %u due to " - "no match in scan", bss->id); - wpa_bss_remove(wpa_s, bss); + wpa_bss_remove(wpa_s, bss, "no match in scan"); } } } @@ -493,9 +504,7 @@ void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age) continue; if (os_time_before(&bss->last_update, &t)) { - wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Expire BSS %u due to " - "age", bss->id); - wpa_bss_remove(wpa_s, bss); + wpa_bss_remove(wpa_s, bss, __func__); } else break; } @@ -532,7 +541,7 @@ void wpa_bss_flush(struct wpa_supplicant *wpa_s) dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) { if (wpa_bss_in_use(wpa_s, bss)) continue; - wpa_bss_remove(wpa_s, bss); + wpa_bss_remove(wpa_s, bss, __func__); } }