diff options
Diffstat (limited to 'wpa_supplicant/bssid_ignore.c')
-rw-r--r-- | wpa_supplicant/bssid_ignore.c | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/wpa_supplicant/bssid_ignore.c b/wpa_supplicant/bssid_ignore.c new file mode 100644 index 000000000000..e37857798a02 --- /dev/null +++ b/wpa_supplicant/bssid_ignore.c @@ -0,0 +1,221 @@ +/* + * wpa_supplicant - List of temporarily ignored BSSIDs + * Copyright (c) 2003-2021, Jouni Malinen <j@w1.fi> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "wpa_supplicant_i.h" +#include "bssid_ignore.h" + +/** + * wpa_bssid_ignore_get - Get the ignore list entry for a BSSID + * @wpa_s: Pointer to wpa_supplicant data + * @bssid: BSSID + * Returns: Matching entry for the BSSID or %NULL if not found + */ +struct wpa_bssid_ignore * wpa_bssid_ignore_get(struct wpa_supplicant *wpa_s, + const u8 *bssid) +{ + struct wpa_bssid_ignore *e; + + if (wpa_s == NULL || bssid == NULL) + return NULL; + + if (wpa_s->current_ssid && + wpa_s->current_ssid->was_recently_reconfigured) { + wpa_bssid_ignore_clear(wpa_s); + wpa_s->current_ssid->was_recently_reconfigured = false; + return NULL; + } + + wpa_bssid_ignore_update(wpa_s); + + e = wpa_s->bssid_ignore; + while (e) { + if (os_memcmp(e->bssid, bssid, ETH_ALEN) == 0) + return e; + e = e->next; + } + + return NULL; +} + + +/** + * wpa_bssid_ignore_add - Add an BSSID to the ignore list + * @wpa_s: Pointer to wpa_supplicant data + * @bssid: BSSID to be added to the ignore list + * Returns: Current ignore list count on success, -1 on failure + * + * This function adds the specified BSSID to the ignore list or increases the + * ignore count if the BSSID was already listed. It should be called when + * an association attempt fails either due to the selected BSS rejecting + * association or due to timeout. + * + * This ignore list is used to force %wpa_supplicant to go through all available + * BSSes before retrying to associate with an BSS that rejected or timed out + * association. It does not prevent the listed BSS from being used; it only + * changes the order in which they are tried. + */ +int wpa_bssid_ignore_add(struct wpa_supplicant *wpa_s, const u8 *bssid) +{ + struct wpa_bssid_ignore *e; + struct os_reltime now; + + if (wpa_s == NULL || bssid == NULL) + return -1; + + e = wpa_bssid_ignore_get(wpa_s, bssid); + os_get_reltime(&now); + if (e) { + e->start = now; + e->count++; + if (e->count > 5) + e->timeout_secs = 1800; + else if (e->count == 5) + e->timeout_secs = 600; + else if (e->count == 4) + e->timeout_secs = 120; + else if (e->count == 3) + e->timeout_secs = 60; + else + e->timeout_secs = 10; + wpa_printf(MSG_INFO, "BSSID " MACSTR + " ignore list count incremented to %d, ignoring for %d seconds", + MAC2STR(bssid), e->count, e->timeout_secs); + return e->count; + } + + e = os_zalloc(sizeof(*e)); + if (e == NULL) + return -1; + os_memcpy(e->bssid, bssid, ETH_ALEN); + e->count = 1; + e->timeout_secs = 10; + e->start = now; + e->next = wpa_s->bssid_ignore; + wpa_s->bssid_ignore = e; + wpa_printf(MSG_DEBUG, "Added BSSID " MACSTR + " into ignore list, ignoring for %d seconds", + MAC2STR(bssid), e->timeout_secs); + + return e->count; +} + + +/** + * wpa_bssid_ignore_del - Remove an BSSID from the ignore list + * @wpa_s: Pointer to wpa_supplicant data + * @bssid: BSSID to be removed from the ignore list + * Returns: 0 on success, -1 on failure + */ +int wpa_bssid_ignore_del(struct wpa_supplicant *wpa_s, const u8 *bssid) +{ + struct wpa_bssid_ignore *e, *prev = NULL; + + if (wpa_s == NULL || bssid == NULL) + return -1; + + e = wpa_s->bssid_ignore; + while (e) { + if (os_memcmp(e->bssid, bssid, ETH_ALEN) == 0) { + if (prev == NULL) { + wpa_s->bssid_ignore = e->next; + } else { + prev->next = e->next; + } + wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR + " from ignore list", MAC2STR(bssid)); + os_free(e); + return 0; + } + prev = e; + e = e->next; + } + return -1; +} + + +/** + * wpa_bssid_ignore_is_listed - Check whether a BSSID is ignored temporarily + * @wpa_s: Pointer to wpa_supplicant data + * @bssid: BSSID to be checked + * Returns: count if BSS is currently considered to be ignored, 0 otherwise + */ +int wpa_bssid_ignore_is_listed(struct wpa_supplicant *wpa_s, const u8 *bssid) +{ + struct wpa_bssid_ignore *e; + struct os_reltime now; + + e = wpa_bssid_ignore_get(wpa_s, bssid); + if (!e) + return 0; + os_get_reltime(&now); + if (os_reltime_expired(&now, &e->start, e->timeout_secs)) + return 0; + return e->count; +} + + +/** + * wpa_bssid_ignore_clear - Clear the ignore list of all entries + * @wpa_s: Pointer to wpa_supplicant data + */ +void wpa_bssid_ignore_clear(struct wpa_supplicant *wpa_s) +{ + struct wpa_bssid_ignore *e, *prev; + + e = wpa_s->bssid_ignore; + wpa_s->bssid_ignore = NULL; + while (e) { + prev = e; + e = e->next; + wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR + " from ignore list (clear)", MAC2STR(prev->bssid)); + os_free(prev); + } +} + + +/** + * wpa_bssid_ignore_update - Update the entries in the ignore list, + * deleting entries that have been expired for over an hour. + * @wpa_s: Pointer to wpa_supplicant data + */ +void wpa_bssid_ignore_update(struct wpa_supplicant *wpa_s) +{ + struct wpa_bssid_ignore *e, *prev = NULL; + struct os_reltime now; + + if (!wpa_s) + return; + + e = wpa_s->bssid_ignore; + os_get_reltime(&now); + while (e) { + if (os_reltime_expired(&now, &e->start, + e->timeout_secs + 3600)) { + struct wpa_bssid_ignore *to_delete = e; + + if (prev) { + prev->next = e->next; + e = prev->next; + } else { + wpa_s->bssid_ignore = e->next; + e = wpa_s->bssid_ignore; + } + wpa_printf(MSG_INFO, "Removed BSSID " MACSTR + " from ignore list (expired)", + MAC2STR(to_delete->bssid)); + os_free(to_delete); + } else { + prev = e; + e = e->next; + } + } +} |