diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c index cbed2e0f8..2a5bb852a 100644 --- a/wpa_supplicant/bss.c +++ b/wpa_supplicant/bss.c @@ -61,6 +61,8 @@ struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid, const u8 *ssid, size_t ssid_len) { struct wpa_bss *bss; + if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid)) + return NULL; dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 && bss->ssid_len == ssid_len && @@ -526,6 +528,8 @@ struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s, const u8 *bssid) { struct wpa_bss *bss; + if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid)) + return NULL; dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) { if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0) return bss; diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 2c8fd51b5..1cdb082ed 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -114,6 +114,41 @@ static int pno_stop(struct wpa_supplicant *wpa_s) } +static int set_bssid_filter(struct wpa_supplicant *wpa_s, char *val) +{ + char *pos; + u8 addr[ETH_ALEN], *filter = NULL, *n; + size_t count = 0; + + pos = val; + while (pos) { + if (*pos == '\0') + break; + if (hwaddr_aton(pos, addr)) + return -1; + n = os_realloc(filter, (count + 1) * ETH_ALEN); + if (n == NULL) { + os_free(filter); + return -1; + } + filter = n; + os_memcpy(filter + count * ETH_ALEN, addr, ETH_ALEN); + count++; + + pos = os_strchr(pos, ' '); + if (pos) + pos++; + } + + wpa_hexdump(MSG_DEBUG, "bssid_filter", filter, count * ETH_ALEN); + os_free(wpa_s->bssid_filter); + wpa_s->bssid_filter = filter; + wpa_s->bssid_filter_count = count; + + return 0; +} + + static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, char *cmd) { @@ -241,6 +276,8 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, } } else if (os_strcasecmp(cmd, "ps") == 0) { ret = wpa_drv_set_p2p_powersave(wpa_s, atoi(value), -1, -1); + } else if (os_strcasecmp(cmd, "bssid_filter") == 0) { + ret = set_bssid_filter(wpa_s, value); } else { value[-1] = '='; ret = wpa_config_process_global(wpa_s->conf, cmd, -1); diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index 7fddb74a9..5fe38650d 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -1235,6 +1235,50 @@ static void dump_scan_res(struct wpa_scan_results *scan_res) } +int wpa_supplicant_filter_bssid_match(struct wpa_supplicant *wpa_s, + const u8 *bssid) +{ + size_t i; + + if (wpa_s->bssid_filter == NULL) + return 1; + + for (i = 0; i < wpa_s->bssid_filter_count; i++) { + if (os_memcmp(wpa_s->bssid_filter + i * ETH_ALEN, bssid, + ETH_ALEN) == 0) + return 1; + } + + return 0; +} + + +static void filter_scan_res(struct wpa_supplicant *wpa_s, + struct wpa_scan_results *res) +{ + size_t i, j; + + if (wpa_s->bssid_filter == NULL) + return; + + for (i = 0, j = 0; i < res->num; i++) { + if (wpa_supplicant_filter_bssid_match(wpa_s, + res->res[i]->bssid)) { + res->res[j++] = res->res[i]; + } else { + os_free(res->res[i]); + res->res[i] = NULL; + } + } + + if (res->num != j) { + wpa_printf(MSG_DEBUG, "Filtered out %d scan results", + (int) (res->num - j)); + res->num = j; + } +} + + /** * wpa_supplicant_get_scan_results - Get scan results * @wpa_s: Pointer to wpa_supplicant data @@ -1259,6 +1303,7 @@ wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s, wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results"); return NULL; } + filter_scan_res(wpa_s, scan_res); #ifdef CONFIG_WPS if (wpas_wps_in_progress(wpa_s)) { diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h index b79410555..8c83a4230 100644 --- a/wpa_supplicant/scan.h +++ b/wpa_supplicant/scan.h @@ -32,5 +32,7 @@ struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res, u32 vendor_type); struct wpabuf * wpa_scan_get_vendor_ie_multi_beacon( const struct wpa_scan_res *res, u32 vendor_type); +int wpa_supplicant_filter_bssid_match(struct wpa_supplicant *wpa_s, + const u8 *bssid); #endif /* SCAN_H */ diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index eff04597f..b58e2fdd8 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -445,6 +445,9 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) wpa_s->gas = NULL; free_hw_features(wpa_s); + + os_free(wpa_s->bssid_filter); + wpa_s->bssid_filter = NULL; } diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 8c9f4a8ab..671bca266 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -280,6 +280,9 @@ struct wpa_supplicant { void *drv_priv; /* private data used by driver_ops */ void *global_drv_priv; + u8 *bssid_filter; + size_t bssid_filter_count; + /* previous scan was wildcard when interleaving between * wildcard scans and specific SSID scan when max_ssids=1 */ int prev_scan_wildcard;