xref: /freebsd/contrib/wpa/wpa_supplicant/bssid_ignore.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
1c1d255d3SCy Schubert /*
2c1d255d3SCy Schubert  * wpa_supplicant - List of temporarily ignored BSSIDs
3c1d255d3SCy Schubert  * Copyright (c) 2003-2021, Jouni Malinen <j@w1.fi>
4c1d255d3SCy Schubert  *
5c1d255d3SCy Schubert  * This software may be distributed under the terms of the BSD license.
6c1d255d3SCy Schubert  * See README for more details.
7c1d255d3SCy Schubert  */
8c1d255d3SCy Schubert 
9c1d255d3SCy Schubert #include "includes.h"
10c1d255d3SCy Schubert 
11c1d255d3SCy Schubert #include "common.h"
12c1d255d3SCy Schubert #include "wpa_supplicant_i.h"
13c1d255d3SCy Schubert #include "bssid_ignore.h"
14c1d255d3SCy Schubert 
15c1d255d3SCy Schubert /**
16c1d255d3SCy Schubert  * wpa_bssid_ignore_get - Get the ignore list entry for a BSSID
17c1d255d3SCy Schubert  * @wpa_s: Pointer to wpa_supplicant data
18c1d255d3SCy Schubert  * @bssid: BSSID
19c1d255d3SCy Schubert  * Returns: Matching entry for the BSSID or %NULL if not found
20c1d255d3SCy Schubert  */
wpa_bssid_ignore_get(struct wpa_supplicant * wpa_s,const u8 * bssid)21c1d255d3SCy Schubert struct wpa_bssid_ignore * wpa_bssid_ignore_get(struct wpa_supplicant *wpa_s,
22c1d255d3SCy Schubert 					       const u8 *bssid)
23c1d255d3SCy Schubert {
24c1d255d3SCy Schubert 	struct wpa_bssid_ignore *e;
25c1d255d3SCy Schubert 
26c1d255d3SCy Schubert 	if (wpa_s == NULL || bssid == NULL)
27c1d255d3SCy Schubert 		return NULL;
28c1d255d3SCy Schubert 
29c1d255d3SCy Schubert 	if (wpa_s->current_ssid &&
30c1d255d3SCy Schubert 	    wpa_s->current_ssid->was_recently_reconfigured) {
31c1d255d3SCy Schubert 		wpa_bssid_ignore_clear(wpa_s);
32c1d255d3SCy Schubert 		wpa_s->current_ssid->was_recently_reconfigured = false;
33c1d255d3SCy Schubert 		return NULL;
34c1d255d3SCy Schubert 	}
35c1d255d3SCy Schubert 
36c1d255d3SCy Schubert 	wpa_bssid_ignore_update(wpa_s);
37c1d255d3SCy Schubert 
38c1d255d3SCy Schubert 	e = wpa_s->bssid_ignore;
39c1d255d3SCy Schubert 	while (e) {
40*a90b9d01SCy Schubert 		if (ether_addr_equal(e->bssid, bssid))
41c1d255d3SCy Schubert 			return e;
42c1d255d3SCy Schubert 		e = e->next;
43c1d255d3SCy Schubert 	}
44c1d255d3SCy Schubert 
45c1d255d3SCy Schubert 	return NULL;
46c1d255d3SCy Schubert }
47c1d255d3SCy Schubert 
48c1d255d3SCy Schubert 
49c1d255d3SCy Schubert /**
50c1d255d3SCy Schubert  * wpa_bssid_ignore_add - Add an BSSID to the ignore list
51c1d255d3SCy Schubert  * @wpa_s: Pointer to wpa_supplicant data
52c1d255d3SCy Schubert  * @bssid: BSSID to be added to the ignore list
53c1d255d3SCy Schubert  * Returns: Current ignore list count on success, -1 on failure
54c1d255d3SCy Schubert  *
55c1d255d3SCy Schubert  * This function adds the specified BSSID to the ignore list or increases the
56c1d255d3SCy Schubert  * ignore count if the BSSID was already listed. It should be called when
57c1d255d3SCy Schubert  * an association attempt fails either due to the selected BSS rejecting
58c1d255d3SCy Schubert  * association or due to timeout.
59c1d255d3SCy Schubert  *
60c1d255d3SCy Schubert  * This ignore list is used to force %wpa_supplicant to go through all available
61c1d255d3SCy Schubert  * BSSes before retrying to associate with an BSS that rejected or timed out
62c1d255d3SCy Schubert  * association. It does not prevent the listed BSS from being used; it only
63c1d255d3SCy Schubert  * changes the order in which they are tried.
64c1d255d3SCy Schubert  */
wpa_bssid_ignore_add(struct wpa_supplicant * wpa_s,const u8 * bssid)65c1d255d3SCy Schubert int wpa_bssid_ignore_add(struct wpa_supplicant *wpa_s, const u8 *bssid)
66c1d255d3SCy Schubert {
67c1d255d3SCy Schubert 	struct wpa_bssid_ignore *e;
68c1d255d3SCy Schubert 	struct os_reltime now;
69c1d255d3SCy Schubert 
70c1d255d3SCy Schubert 	if (wpa_s == NULL || bssid == NULL)
71c1d255d3SCy Schubert 		return -1;
72c1d255d3SCy Schubert 
73c1d255d3SCy Schubert 	e = wpa_bssid_ignore_get(wpa_s, bssid);
74c1d255d3SCy Schubert 	os_get_reltime(&now);
75c1d255d3SCy Schubert 	if (e) {
76c1d255d3SCy Schubert 		e->start = now;
77c1d255d3SCy Schubert 		e->count++;
78c1d255d3SCy Schubert 		if (e->count > 5)
79c1d255d3SCy Schubert 			e->timeout_secs = 1800;
80c1d255d3SCy Schubert 		else if (e->count == 5)
81c1d255d3SCy Schubert 			e->timeout_secs = 600;
82c1d255d3SCy Schubert 		else if (e->count == 4)
83c1d255d3SCy Schubert 			e->timeout_secs = 120;
84c1d255d3SCy Schubert 		else if (e->count == 3)
85c1d255d3SCy Schubert 			e->timeout_secs = 60;
86c1d255d3SCy Schubert 		else
87c1d255d3SCy Schubert 			e->timeout_secs = 10;
88*a90b9d01SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, "BSSID " MACSTR
89c1d255d3SCy Schubert 			" ignore list count incremented to %d, ignoring for %d seconds",
90c1d255d3SCy Schubert 			MAC2STR(bssid), e->count, e->timeout_secs);
91c1d255d3SCy Schubert 		return e->count;
92c1d255d3SCy Schubert 	}
93c1d255d3SCy Schubert 
94c1d255d3SCy Schubert 	e = os_zalloc(sizeof(*e));
95c1d255d3SCy Schubert 	if (e == NULL)
96c1d255d3SCy Schubert 		return -1;
97c1d255d3SCy Schubert 	os_memcpy(e->bssid, bssid, ETH_ALEN);
98c1d255d3SCy Schubert 	e->count = 1;
99c1d255d3SCy Schubert 	e->timeout_secs = 10;
100c1d255d3SCy Schubert 	e->start = now;
101c1d255d3SCy Schubert 	e->next = wpa_s->bssid_ignore;
102c1d255d3SCy Schubert 	wpa_s->bssid_ignore = e;
103*a90b9d01SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, "Added BSSID " MACSTR
104c1d255d3SCy Schubert 		" into ignore list, ignoring for %d seconds",
105c1d255d3SCy Schubert 		MAC2STR(bssid), e->timeout_secs);
106c1d255d3SCy Schubert 
107c1d255d3SCy Schubert 	return e->count;
108c1d255d3SCy Schubert }
109c1d255d3SCy Schubert 
110c1d255d3SCy Schubert 
111c1d255d3SCy Schubert /**
112c1d255d3SCy Schubert  * wpa_bssid_ignore_del - Remove an BSSID from the ignore list
113c1d255d3SCy Schubert  * @wpa_s: Pointer to wpa_supplicant data
114c1d255d3SCy Schubert  * @bssid: BSSID to be removed from the ignore list
115c1d255d3SCy Schubert  * Returns: 0 on success, -1 on failure
116c1d255d3SCy Schubert  */
wpa_bssid_ignore_del(struct wpa_supplicant * wpa_s,const u8 * bssid)117c1d255d3SCy Schubert int wpa_bssid_ignore_del(struct wpa_supplicant *wpa_s, const u8 *bssid)
118c1d255d3SCy Schubert {
119c1d255d3SCy Schubert 	struct wpa_bssid_ignore *e, *prev = NULL;
120c1d255d3SCy Schubert 
121c1d255d3SCy Schubert 	if (wpa_s == NULL || bssid == NULL)
122c1d255d3SCy Schubert 		return -1;
123c1d255d3SCy Schubert 
124c1d255d3SCy Schubert 	e = wpa_s->bssid_ignore;
125c1d255d3SCy Schubert 	while (e) {
126*a90b9d01SCy Schubert 		if (ether_addr_equal(e->bssid, bssid)) {
127c1d255d3SCy Schubert 			if (prev == NULL) {
128c1d255d3SCy Schubert 				wpa_s->bssid_ignore = e->next;
129c1d255d3SCy Schubert 			} else {
130c1d255d3SCy Schubert 				prev->next = e->next;
131c1d255d3SCy Schubert 			}
132*a90b9d01SCy Schubert 			wpa_msg(wpa_s, MSG_INFO, "Removed BSSID " MACSTR
133c1d255d3SCy Schubert 				" from ignore list", MAC2STR(bssid));
134c1d255d3SCy Schubert 			os_free(e);
135c1d255d3SCy Schubert 			return 0;
136c1d255d3SCy Schubert 		}
137c1d255d3SCy Schubert 		prev = e;
138c1d255d3SCy Schubert 		e = e->next;
139c1d255d3SCy Schubert 	}
140c1d255d3SCy Schubert 	return -1;
141c1d255d3SCy Schubert }
142c1d255d3SCy Schubert 
143c1d255d3SCy Schubert 
144c1d255d3SCy Schubert /**
145c1d255d3SCy Schubert  * wpa_bssid_ignore_is_listed - Check whether a BSSID is ignored temporarily
146c1d255d3SCy Schubert  * @wpa_s: Pointer to wpa_supplicant data
147c1d255d3SCy Schubert  * @bssid: BSSID to be checked
148c1d255d3SCy Schubert  * Returns: count if BSS is currently considered to be ignored, 0 otherwise
149c1d255d3SCy Schubert  */
wpa_bssid_ignore_is_listed(struct wpa_supplicant * wpa_s,const u8 * bssid)150c1d255d3SCy Schubert int wpa_bssid_ignore_is_listed(struct wpa_supplicant *wpa_s, const u8 *bssid)
151c1d255d3SCy Schubert {
152c1d255d3SCy Schubert 	struct wpa_bssid_ignore *e;
153c1d255d3SCy Schubert 	struct os_reltime now;
154c1d255d3SCy Schubert 
155c1d255d3SCy Schubert 	e = wpa_bssid_ignore_get(wpa_s, bssid);
156c1d255d3SCy Schubert 	if (!e)
157c1d255d3SCy Schubert 		return 0;
158c1d255d3SCy Schubert 	os_get_reltime(&now);
159c1d255d3SCy Schubert 	if (os_reltime_expired(&now, &e->start, e->timeout_secs))
160c1d255d3SCy Schubert 		return 0;
161c1d255d3SCy Schubert 	return e->count;
162c1d255d3SCy Schubert }
163c1d255d3SCy Schubert 
164c1d255d3SCy Schubert 
165c1d255d3SCy Schubert /**
166c1d255d3SCy Schubert  * wpa_bssid_ignore_clear - Clear the ignore list of all entries
167c1d255d3SCy Schubert  * @wpa_s: Pointer to wpa_supplicant data
168c1d255d3SCy Schubert  */
wpa_bssid_ignore_clear(struct wpa_supplicant * wpa_s)169c1d255d3SCy Schubert void wpa_bssid_ignore_clear(struct wpa_supplicant *wpa_s)
170c1d255d3SCy Schubert {
171c1d255d3SCy Schubert 	struct wpa_bssid_ignore *e, *prev;
172c1d255d3SCy Schubert 
173c1d255d3SCy Schubert 	e = wpa_s->bssid_ignore;
174c1d255d3SCy Schubert 	wpa_s->bssid_ignore = NULL;
175c1d255d3SCy Schubert 	while (e) {
176c1d255d3SCy Schubert 		prev = e;
177c1d255d3SCy Schubert 		e = e->next;
178*a90b9d01SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, "Removed BSSID " MACSTR
179c1d255d3SCy Schubert 			" from ignore list (clear)", MAC2STR(prev->bssid));
180c1d255d3SCy Schubert 		os_free(prev);
181c1d255d3SCy Schubert 	}
182c1d255d3SCy Schubert }
183c1d255d3SCy Schubert 
184c1d255d3SCy Schubert 
185c1d255d3SCy Schubert /**
186c1d255d3SCy Schubert  * wpa_bssid_ignore_update - Update the entries in the ignore list,
187c1d255d3SCy Schubert  * deleting entries that have been expired for over an hour.
188c1d255d3SCy Schubert  * @wpa_s: Pointer to wpa_supplicant data
189c1d255d3SCy Schubert  */
wpa_bssid_ignore_update(struct wpa_supplicant * wpa_s)190c1d255d3SCy Schubert void wpa_bssid_ignore_update(struct wpa_supplicant *wpa_s)
191c1d255d3SCy Schubert {
192c1d255d3SCy Schubert 	struct wpa_bssid_ignore *e, *prev = NULL;
193c1d255d3SCy Schubert 	struct os_reltime now;
194c1d255d3SCy Schubert 
195c1d255d3SCy Schubert 	if (!wpa_s)
196c1d255d3SCy Schubert 		return;
197c1d255d3SCy Schubert 
198c1d255d3SCy Schubert 	e = wpa_s->bssid_ignore;
199c1d255d3SCy Schubert 	os_get_reltime(&now);
200c1d255d3SCy Schubert 	while (e) {
201c1d255d3SCy Schubert 		if (os_reltime_expired(&now, &e->start,
202c1d255d3SCy Schubert 				       e->timeout_secs + 3600)) {
203c1d255d3SCy Schubert 			struct wpa_bssid_ignore *to_delete = e;
204c1d255d3SCy Schubert 
205c1d255d3SCy Schubert 			if (prev) {
206c1d255d3SCy Schubert 				prev->next = e->next;
207c1d255d3SCy Schubert 				e = prev->next;
208c1d255d3SCy Schubert 			} else {
209c1d255d3SCy Schubert 				wpa_s->bssid_ignore = e->next;
210c1d255d3SCy Schubert 				e = wpa_s->bssid_ignore;
211c1d255d3SCy Schubert 			}
212*a90b9d01SCy Schubert 			wpa_msg(wpa_s, MSG_INFO, "Removed BSSID " MACSTR
213c1d255d3SCy Schubert 				" from ignore list (expired)",
214c1d255d3SCy Schubert 				MAC2STR(to_delete->bssid));
215c1d255d3SCy Schubert 			os_free(to_delete);
216c1d255d3SCy Schubert 		} else {
217c1d255d3SCy Schubert 			prev = e;
218c1d255d3SCy Schubert 			e = e->next;
219c1d255d3SCy Schubert 		}
220c1d255d3SCy Schubert 	}
221c1d255d3SCy Schubert }
222