diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c index 580a82aa8..434fb08a7 100644 --- a/wpa_supplicant/bss.c +++ b/wpa_supplicant/bss.c @@ -38,6 +38,19 @@ static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, const char *reason) { + if (wpa_s->last_scan_res) { + unsigned int i; + for (i = 0; i < wpa_s->last_scan_res_used; i++) { + if (wpa_s->last_scan_res[i] == bss) { + os_memmove(&wpa_s->last_scan_res[i], + &wpa_s->last_scan_res[i + 1], + (wpa_s->last_scan_res_used - i - 1) + * sizeof(struct wpa_bss *)); + wpa_s->last_scan_res_used--; + break; + } + } + } dl_list_del(&bss->list); dl_list_del(&bss->list_id); wpa_s->num_bss--; @@ -169,15 +182,15 @@ static int wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s) } -static void wpa_bss_add(struct wpa_supplicant *wpa_s, - const u8 *ssid, size_t ssid_len, - struct wpa_scan_res *res) +static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s, + const u8 *ssid, size_t ssid_len, + struct wpa_scan_res *res) { struct wpa_bss *bss; bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len); if (bss == NULL) - return; + return NULL; bss->id = wpa_s->bss_next_id++; bss->last_update_idx = wpa_s->bss_update_idx; wpa_bss_copy_res(bss, res); @@ -201,6 +214,7 @@ static void wpa_bss_add(struct wpa_supplicant *wpa_s, "not get here!", (int) wpa_s->num_bss); wpa_s->conf->bss_max_count = wpa_s->num_bss; } + return bss; } @@ -376,6 +390,7 @@ void wpa_bss_update_start(struct wpa_supplicant *wpa_s) wpa_s->bss_update_idx++; wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Start scan result update %u", wpa_s->bss_update_idx); + wpa_s->last_scan_res_used = 0; } @@ -418,9 +433,28 @@ void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s, * (to save memory) */ bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]); if (bss == NULL) - wpa_bss_add(wpa_s, ssid + 2, ssid[1], res); + bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res); else wpa_bss_update(wpa_s, bss, res); + + if (bss == NULL) + return; + if (wpa_s->last_scan_res_used >= wpa_s->last_scan_res_size) { + struct wpa_bss **n; + unsigned int siz; + if (wpa_s->last_scan_res_size == 0) + siz = 32; + else + siz = wpa_s->last_scan_res_size * 2; + n = os_realloc_array(wpa_s->last_scan_res, siz, + sizeof(struct wpa_bss *)); + if (n == NULL) + return; + wpa_s->last_scan_res = n; + wpa_s->last_scan_res_size = siz; + } + + wpa_s->last_scan_res[wpa_s->last_scan_res_used++] = bss; } @@ -470,9 +504,26 @@ void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info, { struct wpa_bss *bss, *n; + wpa_s->last_scan_full = 0; + os_get_time(&wpa_s->last_scan); if (!new_scan) return; /* do not expire entries without new scan */ + if (info && !info->aborted && !info->freqs) { + size_t i; + if (info->num_ssids == 0) { + wpa_s->last_scan_full = 1; + } else { + for (i = 0; i < info->num_ssids; i++) { + if (info->ssids[i].ssid == NULL || + info->ssids[i].ssid_len == 0) { + wpa_s->last_scan_full = 1; + break; + } + } + } + } + dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) { if (wpa_bss_in_use(wpa_s, bss)) continue; @@ -485,6 +536,11 @@ void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info, wpa_bss_remove(wpa_s, bss, "no match in scan"); } } + + wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%u/%u " + "last_scan_full=%d", + wpa_s->last_scan_res_used, wpa_s->last_scan_res_size, + wpa_s->last_scan_full); } diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 820cd5ec6..fdd322e27 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -476,6 +476,9 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) wpa_s->ext_pw = NULL; wpabuf_free(wpa_s->last_gas_resp); + + os_free(wpa_s->last_scan_res); + wpa_s->last_scan_res = NULL; } diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index fb8dba8c2..42055ec76 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -347,6 +347,16 @@ struct wpa_supplicant { unsigned int bss_update_idx; unsigned int bss_next_id; + /* + * Pointers to BSS entries in the order they were in the last scan + * results. + */ + struct wpa_bss **last_scan_res; + unsigned int last_scan_res_used; + unsigned int last_scan_res_size; + int last_scan_full; + struct os_time last_scan; + struct wpa_driver_ops *driver; int interface_removed; /* whether the network interface has been * removed */