aboutsummaryrefslogtreecommitdiff
path: root/contrib/wpa/wpa_supplicant/bssid_ignore.c
blob: e37857798a0282daaac074d521e27d1f33d4f63b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
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;
		}
	}
}