blob: 914bd5d9bc58fbb36cfa0d07ca50a6afb83aa74f [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * BSS table
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003 * Copyright (c) 2009-2015, Jouni Malinen <j@w1.fi>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 */
8
9#include "utils/includes.h"
10
11#include "utils/common.h"
12#include "utils/eloop.h"
13#include "common/ieee802_11_defs.h"
14#include "drivers/driver.h"
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -070015#include "eap_peer/eap.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070016#include "wpa_supplicant_i.h"
17#include "config.h"
18#include "notify.h"
19#include "scan.h"
20#include "bss.h"
21
22
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070023#define WPA_BSS_FREQ_CHANGED_FLAG BIT(0)
24#define WPA_BSS_SIGNAL_CHANGED_FLAG BIT(1)
25#define WPA_BSS_PRIVACY_CHANGED_FLAG BIT(2)
26#define WPA_BSS_MODE_CHANGED_FLAG BIT(3)
27#define WPA_BSS_WPAIE_CHANGED_FLAG BIT(4)
28#define WPA_BSS_RSNIE_CHANGED_FLAG BIT(5)
29#define WPA_BSS_WPS_CHANGED_FLAG BIT(6)
30#define WPA_BSS_RATES_CHANGED_FLAG BIT(7)
31#define WPA_BSS_IES_CHANGED_FLAG BIT(8)
32
33
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -070034static void wpa_bss_set_hessid(struct wpa_bss *bss)
35{
36#ifdef CONFIG_INTERWORKING
37 const u8 *ie = wpa_bss_get_ie(bss, WLAN_EID_INTERWORKING);
38 if (ie == NULL || (ie[1] != 7 && ie[1] != 9)) {
39 os_memset(bss->hessid, 0, ETH_ALEN);
40 return;
41 }
42 if (ie[1] == 7)
43 os_memcpy(bss->hessid, ie + 3, ETH_ALEN);
44 else
45 os_memcpy(bss->hessid, ie + 5, ETH_ALEN);
46#endif /* CONFIG_INTERWORKING */
47}
48
49
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080050/**
51 * wpa_bss_anqp_alloc - Allocate ANQP data structure for a BSS entry
52 * Returns: Allocated ANQP data structure or %NULL on failure
53 *
54 * The allocated ANQP data structure has its users count set to 1. It may be
55 * shared by multiple BSS entries and each shared entry is freed with
56 * wpa_bss_anqp_free().
57 */
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -070058struct wpa_bss_anqp * wpa_bss_anqp_alloc(void)
59{
60 struct wpa_bss_anqp *anqp;
61 anqp = os_zalloc(sizeof(*anqp));
62 if (anqp == NULL)
63 return NULL;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080064#ifdef CONFIG_INTERWORKING
65 dl_list_init(&anqp->anqp_elems);
66#endif /* CONFIG_INTERWORKING */
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -070067 anqp->users = 1;
68 return anqp;
69}
70
71
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080072/**
73 * wpa_bss_anqp_clone - Clone an ANQP data structure
74 * @anqp: ANQP data structure from wpa_bss_anqp_alloc()
75 * Returns: Cloned ANQP data structure or %NULL on failure
76 */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -080077static struct wpa_bss_anqp * wpa_bss_anqp_clone(struct wpa_bss_anqp *anqp)
78{
79 struct wpa_bss_anqp *n;
80
81 n = os_zalloc(sizeof(*n));
82 if (n == NULL)
83 return NULL;
84
85#define ANQP_DUP(f) if (anqp->f) n->f = wpabuf_dup(anqp->f)
86#ifdef CONFIG_INTERWORKING
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080087 dl_list_init(&n->anqp_elems);
Dmitry Shmidt7f656022015-02-25 14:36:37 -080088 ANQP_DUP(capability_list);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -080089 ANQP_DUP(venue_name);
90 ANQP_DUP(network_auth_type);
91 ANQP_DUP(roaming_consortium);
92 ANQP_DUP(ip_addr_type_availability);
93 ANQP_DUP(nai_realm);
94 ANQP_DUP(anqp_3gpp);
95 ANQP_DUP(domain_name);
Dmitry Shmidt29333592017-01-09 12:27:11 -080096 ANQP_DUP(fils_realm_info);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -080097#endif /* CONFIG_INTERWORKING */
98#ifdef CONFIG_HS20
Dmitry Shmidt7f656022015-02-25 14:36:37 -080099 ANQP_DUP(hs20_capability_list);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800100 ANQP_DUP(hs20_operator_friendly_name);
101 ANQP_DUP(hs20_wan_metrics);
102 ANQP_DUP(hs20_connection_capability);
103 ANQP_DUP(hs20_operating_class);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800104 ANQP_DUP(hs20_osu_providers_list);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800105#endif /* CONFIG_HS20 */
106#undef ANQP_DUP
107
108 return n;
109}
110
111
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800112/**
113 * wpa_bss_anqp_unshare_alloc - Unshare ANQP data (if shared) in a BSS entry
114 * @bss: BSS entry
115 * Returns: 0 on success, -1 on failure
116 *
117 * This function ensures the specific BSS entry has an ANQP data structure that
118 * is not shared with any other BSS entry.
119 */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800120int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss)
121{
122 struct wpa_bss_anqp *anqp;
123
124 if (bss->anqp && bss->anqp->users > 1) {
125 /* allocated, but shared - clone an unshared copy */
126 anqp = wpa_bss_anqp_clone(bss->anqp);
127 if (anqp == NULL)
128 return -1;
129 anqp->users = 1;
130 bss->anqp->users--;
131 bss->anqp = anqp;
132 return 0;
133 }
134
135 if (bss->anqp)
136 return 0; /* already allocated and not shared */
137
138 /* not allocated - allocate a new storage area */
139 bss->anqp = wpa_bss_anqp_alloc();
140 return bss->anqp ? 0 : -1;
141}
142
143
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800144/**
145 * wpa_bss_anqp_free - Free an ANQP data structure
146 * @anqp: ANQP data structure from wpa_bss_anqp_alloc() or wpa_bss_anqp_clone()
147 */
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -0700148static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
149{
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800150#ifdef CONFIG_INTERWORKING
151 struct wpa_bss_anqp_elem *elem;
152#endif /* CONFIG_INTERWORKING */
153
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -0700154 if (anqp == NULL)
155 return;
156
157 anqp->users--;
158 if (anqp->users > 0) {
159 /* Another BSS entry holds a pointer to this ANQP info */
160 return;
161 }
162
163#ifdef CONFIG_INTERWORKING
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800164 wpabuf_free(anqp->capability_list);
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -0700165 wpabuf_free(anqp->venue_name);
166 wpabuf_free(anqp->network_auth_type);
167 wpabuf_free(anqp->roaming_consortium);
168 wpabuf_free(anqp->ip_addr_type_availability);
169 wpabuf_free(anqp->nai_realm);
170 wpabuf_free(anqp->anqp_3gpp);
171 wpabuf_free(anqp->domain_name);
Dmitry Shmidt29333592017-01-09 12:27:11 -0800172 wpabuf_free(anqp->fils_realm_info);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800173
174 while ((elem = dl_list_first(&anqp->anqp_elems,
175 struct wpa_bss_anqp_elem, list))) {
176 dl_list_del(&elem->list);
177 wpabuf_free(elem->payload);
178 os_free(elem);
179 }
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -0700180#endif /* CONFIG_INTERWORKING */
181#ifdef CONFIG_HS20
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800182 wpabuf_free(anqp->hs20_capability_list);
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -0700183 wpabuf_free(anqp->hs20_operator_friendly_name);
184 wpabuf_free(anqp->hs20_wan_metrics);
185 wpabuf_free(anqp->hs20_connection_capability);
186 wpabuf_free(anqp->hs20_operating_class);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800187 wpabuf_free(anqp->hs20_osu_providers_list);
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -0700188#endif /* CONFIG_HS20 */
189
190 os_free(anqp);
191}
192
193
Dmitry Shmidt2e425d62014-11-10 11:18:27 -0800194static void wpa_bss_update_pending_connect(struct wpa_supplicant *wpa_s,
195 struct wpa_bss *old_bss,
196 struct wpa_bss *new_bss)
197{
198 struct wpa_radio_work *work;
199 struct wpa_connect_work *cwork;
200
201 work = radio_work_pending(wpa_s, "sme-connect");
202 if (!work)
203 work = radio_work_pending(wpa_s, "connect");
204 if (!work)
205 return;
206
207 cwork = work->ctx;
208 if (cwork->bss != old_bss)
209 return;
210
211 wpa_printf(MSG_DEBUG,
212 "Update BSS pointer for the pending connect radio work");
213 cwork->bss = new_bss;
214 if (!new_bss)
215 cwork->bss_removed = 1;
216}
217
218
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800219void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
220 const char *reason)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700221{
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -0700222 if (wpa_s->last_scan_res) {
223 unsigned int i;
224 for (i = 0; i < wpa_s->last_scan_res_used; i++) {
225 if (wpa_s->last_scan_res[i] == bss) {
226 os_memmove(&wpa_s->last_scan_res[i],
227 &wpa_s->last_scan_res[i + 1],
228 (wpa_s->last_scan_res_used - i - 1)
229 * sizeof(struct wpa_bss *));
230 wpa_s->last_scan_res_used--;
231 break;
232 }
233 }
234 }
Dmitry Shmidt2e425d62014-11-10 11:18:27 -0800235 wpa_bss_update_pending_connect(wpa_s, bss, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700236 dl_list_del(&bss->list);
237 dl_list_del(&bss->list_id);
238 wpa_s->num_bss--;
239 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Remove id %u BSSID " MACSTR
Dmitry Shmidt04949592012-07-19 12:16:46 -0700240 " SSID '%s' due to %s", bss->id, MAC2STR(bss->bssid),
241 wpa_ssid_txt(bss->ssid, bss->ssid_len), reason);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700242 wpas_notify_bss_removed(wpa_s, bss->bssid, bss->id);
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -0700243 wpa_bss_anqp_free(bss->anqp);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700244 os_free(bss);
245}
246
247
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800248/**
249 * wpa_bss_get - Fetch a BSS table entry based on BSSID and SSID
250 * @wpa_s: Pointer to wpa_supplicant data
251 * @bssid: BSSID
252 * @ssid: SSID
253 * @ssid_len: Length of @ssid
254 * Returns: Pointer to the BSS entry or %NULL if not found
255 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700256struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
257 const u8 *ssid, size_t ssid_len)
258{
259 struct wpa_bss *bss;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700260 if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
261 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700262 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
263 if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
264 bss->ssid_len == ssid_len &&
265 os_memcmp(bss->ssid, ssid, ssid_len) == 0)
266 return bss;
267 }
268 return NULL;
269}
270
271
Dmitry Shmidt29333592017-01-09 12:27:11 -0800272void calculate_update_time(const struct os_reltime *fetch_time,
273 unsigned int age_ms,
274 struct os_reltime *update_time)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700275{
276 os_time_t usec;
277
Dmitry Shmidt444d5672013-04-01 13:08:44 -0700278 update_time->sec = fetch_time->sec;
279 update_time->usec = fetch_time->usec;
280 update_time->sec -= age_ms / 1000;
281 usec = (age_ms % 1000) * 1000;
282 if (update_time->usec < usec) {
283 update_time->sec--;
284 update_time->usec += 1000000;
285 }
286 update_time->usec -= usec;
287}
288
289
290static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src,
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800291 struct os_reltime *fetch_time)
Dmitry Shmidt444d5672013-04-01 13:08:44 -0700292{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700293 dst->flags = src->flags;
294 os_memcpy(dst->bssid, src->bssid, ETH_ALEN);
295 dst->freq = src->freq;
296 dst->beacon_int = src->beacon_int;
297 dst->caps = src->caps;
298 dst->qual = src->qual;
299 dst->noise = src->noise;
300 dst->level = src->level;
301 dst->tsf = src->tsf;
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800302 dst->est_throughput = src->est_throughput;
303 dst->snr = src->snr;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700304
Dmitry Shmidt444d5672013-04-01 13:08:44 -0700305 calculate_update_time(fetch_time, src->age, &dst->last_update);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700306}
307
308
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -0700309static int wpa_bss_is_wps_candidate(struct wpa_supplicant *wpa_s,
310 struct wpa_bss *bss)
311{
312#ifdef CONFIG_WPS
313 struct wpa_ssid *ssid;
314 struct wpabuf *wps_ie;
315 int pbc = 0, ret;
316
317 wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
318 if (!wps_ie)
319 return 0;
320
321 if (wps_is_selected_pbc_registrar(wps_ie)) {
322 pbc = 1;
323 } else if (!wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1)) {
324 wpabuf_free(wps_ie);
325 return 0;
326 }
327
328 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
329 if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS))
330 continue;
331 if (ssid->ssid_len &&
332 (ssid->ssid_len != bss->ssid_len ||
333 os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) != 0))
334 continue;
335
336 if (pbc)
337 ret = eap_is_wps_pbc_enrollee(&ssid->eap);
338 else
339 ret = eap_is_wps_pin_enrollee(&ssid->eap);
340 wpabuf_free(wps_ie);
341 return ret;
342 }
343 wpabuf_free(wps_ie);
344#endif /* CONFIG_WPS */
345
346 return 0;
347}
348
349
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800350static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
351{
352 struct wpa_ssid *ssid;
353
354 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
355 if (ssid->ssid == NULL || ssid->ssid_len == 0)
356 continue;
357 if (ssid->ssid_len == bss->ssid_len &&
358 os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) == 0)
359 return 1;
360 }
361
362 return 0;
363}
364
365
Dmitry Shmidt04949592012-07-19 12:16:46 -0700366static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
367{
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800368 if (bss == wpa_s->current_bss)
369 return 1;
370
371 if (wpa_s->current_bss &&
372 (bss->ssid_len != wpa_s->current_bss->ssid_len ||
373 os_memcmp(bss->ssid, wpa_s->current_bss->ssid,
374 bss->ssid_len) != 0))
375 return 0; /* SSID has changed */
376
377 return !is_zero_ether_addr(bss->bssid) &&
378 (os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 ||
379 os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0);
Dmitry Shmidt04949592012-07-19 12:16:46 -0700380}
381
382
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800383static int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s)
384{
385 struct wpa_bss *bss;
386
387 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -0700388 if (!wpa_bss_known(wpa_s, bss) &&
389 !wpa_bss_is_wps_candidate(wpa_s, bss)) {
Dmitry Shmidt04949592012-07-19 12:16:46 -0700390 wpa_bss_remove(wpa_s, bss, __func__);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800391 return 0;
392 }
393 }
394
395 return -1;
396}
397
398
Dmitry Shmidt04949592012-07-19 12:16:46 -0700399static int wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800400{
Dmitry Shmidt04949592012-07-19 12:16:46 -0700401 struct wpa_bss *bss;
402
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800403 /*
404 * Remove the oldest entry that does not match with any configured
405 * network.
406 */
407 if (wpa_bss_remove_oldest_unknown(wpa_s) == 0)
Dmitry Shmidt04949592012-07-19 12:16:46 -0700408 return 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800409
410 /*
Dmitry Shmidt04949592012-07-19 12:16:46 -0700411 * Remove the oldest entry that isn't currently in use.
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800412 */
Dmitry Shmidt04949592012-07-19 12:16:46 -0700413 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
414 if (!wpa_bss_in_use(wpa_s, bss)) {
415 wpa_bss_remove(wpa_s, bss, __func__);
416 return 0;
417 }
418 }
419
420 return -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800421}
422
423
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -0700424static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s,
425 const u8 *ssid, size_t ssid_len,
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800426 struct wpa_scan_res *res,
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800427 struct os_reltime *fetch_time)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700428{
429 struct wpa_bss *bss;
430
431 bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len);
432 if (bss == NULL)
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -0700433 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700434 bss->id = wpa_s->bss_next_id++;
435 bss->last_update_idx = wpa_s->bss_update_idx;
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800436 wpa_bss_copy_res(bss, res, fetch_time);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700437 os_memcpy(bss->ssid, ssid, ssid_len);
438 bss->ssid_len = ssid_len;
439 bss->ie_len = res->ie_len;
440 bss->beacon_ie_len = res->beacon_ie_len;
441 os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -0700442 wpa_bss_set_hessid(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700443
Jouni Malinen7a6c8302013-09-27 15:47:09 +0300444 if (wpa_s->num_bss + 1 > wpa_s->conf->bss_max_count &&
445 wpa_bss_remove_oldest(wpa_s) != 0) {
446 wpa_printf(MSG_ERROR, "Increasing the MAX BSS count to %d "
447 "because all BSSes are in use. We should normally "
448 "not get here!", (int) wpa_s->num_bss + 1);
449 wpa_s->conf->bss_max_count = wpa_s->num_bss + 1;
450 }
451
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700452 dl_list_add_tail(&wpa_s->bss, &bss->list);
453 dl_list_add_tail(&wpa_s->bss_id, &bss->list_id);
454 wpa_s->num_bss++;
455 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Add new id %u BSSID " MACSTR
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800456 " SSID '%s' freq %d",
457 bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len),
458 bss->freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700459 wpas_notify_bss_added(wpa_s, bss->bssid, bss->id);
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -0700460 return bss;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700461}
462
463
464static int are_ies_equal(const struct wpa_bss *old,
Dmitry Shmidt1d755d02015-04-28 10:34:29 -0700465 const struct wpa_scan_res *new_res, u32 ie)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700466{
467 const u8 *old_ie, *new_ie;
468 struct wpabuf *old_ie_buff = NULL;
469 struct wpabuf *new_ie_buff = NULL;
470 int new_ie_len, old_ie_len, ret, is_multi;
471
472 switch (ie) {
473 case WPA_IE_VENDOR_TYPE:
474 old_ie = wpa_bss_get_vendor_ie(old, ie);
Dmitry Shmidt1d755d02015-04-28 10:34:29 -0700475 new_ie = wpa_scan_get_vendor_ie(new_res, ie);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700476 is_multi = 0;
477 break;
478 case WPS_IE_VENDOR_TYPE:
479 old_ie_buff = wpa_bss_get_vendor_ie_multi(old, ie);
Dmitry Shmidt1d755d02015-04-28 10:34:29 -0700480 new_ie_buff = wpa_scan_get_vendor_ie_multi(new_res, ie);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700481 is_multi = 1;
482 break;
483 case WLAN_EID_RSN:
484 case WLAN_EID_SUPP_RATES:
485 case WLAN_EID_EXT_SUPP_RATES:
486 old_ie = wpa_bss_get_ie(old, ie);
Dmitry Shmidt1d755d02015-04-28 10:34:29 -0700487 new_ie = wpa_scan_get_ie(new_res, ie);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700488 is_multi = 0;
489 break;
490 default:
491 wpa_printf(MSG_DEBUG, "bss: %s: cannot compare IEs", __func__);
492 return 0;
493 }
494
495 if (is_multi) {
496 /* in case of multiple IEs stored in buffer */
497 old_ie = old_ie_buff ? wpabuf_head_u8(old_ie_buff) : NULL;
498 new_ie = new_ie_buff ? wpabuf_head_u8(new_ie_buff) : NULL;
499 old_ie_len = old_ie_buff ? wpabuf_len(old_ie_buff) : 0;
500 new_ie_len = new_ie_buff ? wpabuf_len(new_ie_buff) : 0;
501 } else {
502 /* in case of single IE */
503 old_ie_len = old_ie ? old_ie[1] + 2 : 0;
504 new_ie_len = new_ie ? new_ie[1] + 2 : 0;
505 }
506
507 if (!old_ie || !new_ie)
508 ret = !old_ie && !new_ie;
509 else
510 ret = (old_ie_len == new_ie_len &&
511 os_memcmp(old_ie, new_ie, old_ie_len) == 0);
512
513 wpabuf_free(old_ie_buff);
514 wpabuf_free(new_ie_buff);
515
516 return ret;
517}
518
519
520static u32 wpa_bss_compare_res(const struct wpa_bss *old,
Dmitry Shmidt1d755d02015-04-28 10:34:29 -0700521 const struct wpa_scan_res *new_res)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700522{
523 u32 changes = 0;
Dmitry Shmidt1d755d02015-04-28 10:34:29 -0700524 int caps_diff = old->caps ^ new_res->caps;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700525
Dmitry Shmidt1d755d02015-04-28 10:34:29 -0700526 if (old->freq != new_res->freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700527 changes |= WPA_BSS_FREQ_CHANGED_FLAG;
528
Dmitry Shmidt1d755d02015-04-28 10:34:29 -0700529 if (old->level != new_res->level)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700530 changes |= WPA_BSS_SIGNAL_CHANGED_FLAG;
531
532 if (caps_diff & IEEE80211_CAP_PRIVACY)
533 changes |= WPA_BSS_PRIVACY_CHANGED_FLAG;
534
535 if (caps_diff & IEEE80211_CAP_IBSS)
536 changes |= WPA_BSS_MODE_CHANGED_FLAG;
537
Dmitry Shmidt1d755d02015-04-28 10:34:29 -0700538 if (old->ie_len == new_res->ie_len &&
539 os_memcmp(old + 1, new_res + 1, old->ie_len) == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700540 return changes;
541 changes |= WPA_BSS_IES_CHANGED_FLAG;
542
Dmitry Shmidt1d755d02015-04-28 10:34:29 -0700543 if (!are_ies_equal(old, new_res, WPA_IE_VENDOR_TYPE))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700544 changes |= WPA_BSS_WPAIE_CHANGED_FLAG;
545
Dmitry Shmidt1d755d02015-04-28 10:34:29 -0700546 if (!are_ies_equal(old, new_res, WLAN_EID_RSN))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700547 changes |= WPA_BSS_RSNIE_CHANGED_FLAG;
548
Dmitry Shmidt1d755d02015-04-28 10:34:29 -0700549 if (!are_ies_equal(old, new_res, WPS_IE_VENDOR_TYPE))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700550 changes |= WPA_BSS_WPS_CHANGED_FLAG;
551
Dmitry Shmidt1d755d02015-04-28 10:34:29 -0700552 if (!are_ies_equal(old, new_res, WLAN_EID_SUPP_RATES) ||
553 !are_ies_equal(old, new_res, WLAN_EID_EXT_SUPP_RATES))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700554 changes |= WPA_BSS_RATES_CHANGED_FLAG;
555
556 return changes;
557}
558
559
560static void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
561 const struct wpa_bss *bss)
562{
563 if (changes & WPA_BSS_FREQ_CHANGED_FLAG)
564 wpas_notify_bss_freq_changed(wpa_s, bss->id);
565
566 if (changes & WPA_BSS_SIGNAL_CHANGED_FLAG)
567 wpas_notify_bss_signal_changed(wpa_s, bss->id);
568
569 if (changes & WPA_BSS_PRIVACY_CHANGED_FLAG)
570 wpas_notify_bss_privacy_changed(wpa_s, bss->id);
571
572 if (changes & WPA_BSS_MODE_CHANGED_FLAG)
573 wpas_notify_bss_mode_changed(wpa_s, bss->id);
574
575 if (changes & WPA_BSS_WPAIE_CHANGED_FLAG)
576 wpas_notify_bss_wpaie_changed(wpa_s, bss->id);
577
578 if (changes & WPA_BSS_RSNIE_CHANGED_FLAG)
579 wpas_notify_bss_rsnie_changed(wpa_s, bss->id);
580
581 if (changes & WPA_BSS_WPS_CHANGED_FLAG)
582 wpas_notify_bss_wps_changed(wpa_s, bss->id);
583
584 if (changes & WPA_BSS_IES_CHANGED_FLAG)
585 wpas_notify_bss_ies_changed(wpa_s, bss->id);
586
587 if (changes & WPA_BSS_RATES_CHANGED_FLAG)
588 wpas_notify_bss_rates_changed(wpa_s, bss->id);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -0700589
590 wpas_notify_bss_seen(wpa_s, bss->id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700591}
592
593
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -0700594static struct wpa_bss *
595wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800596 struct wpa_scan_res *res, struct os_reltime *fetch_time)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700597{
598 u32 changes;
599
Dmitry Shmidtabb90a32016-12-05 15:34:39 -0800600 if (bss->last_update_idx == wpa_s->bss_update_idx) {
601 struct os_reltime update_time;
602
603 /*
604 * Some drivers (e.g., cfg80211) include multiple BSS entries
605 * for the same BSS if that BSS's channel changes. The BSS list
606 * implementation in wpa_supplicant does not do that and we need
607 * to filter out the obsolete results here to make sure only the
608 * most current BSS information remains in the table.
609 */
610 wpa_printf(MSG_DEBUG, "BSS: " MACSTR
611 " has multiple entries in the scan results - select the most current one",
612 MAC2STR(bss->bssid));
613 calculate_update_time(fetch_time, res->age, &update_time);
614 wpa_printf(MSG_DEBUG,
615 "Previous last_update: %u.%06u (freq %d%s)",
616 (unsigned int) bss->last_update.sec,
617 (unsigned int) bss->last_update.usec,
618 bss->freq,
619 (bss->flags & WPA_BSS_ASSOCIATED) ? " assoc" : "");
620 wpa_printf(MSG_DEBUG, "New last_update: %u.%06u (freq %d%s)",
621 (unsigned int) update_time.sec,
622 (unsigned int) update_time.usec,
623 res->freq,
624 (res->flags & WPA_SCAN_ASSOCIATED) ? " assoc" : "");
625 if ((bss->flags & WPA_BSS_ASSOCIATED) ||
626 (!(res->flags & WPA_SCAN_ASSOCIATED) &&
627 !os_reltime_before(&bss->last_update, &update_time))) {
628 wpa_printf(MSG_DEBUG,
629 "Ignore this BSS entry since the previous update looks more current");
630 return bss;
631 }
632 wpa_printf(MSG_DEBUG,
633 "Accept this BSS entry since it looks more current than the previous update");
634 }
635
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700636 changes = wpa_bss_compare_res(bss, res);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800637 if (changes & WPA_BSS_FREQ_CHANGED_FLAG)
638 wpa_printf(MSG_DEBUG, "BSS: " MACSTR " changed freq %d --> %d",
639 MAC2STR(bss->bssid), bss->freq, res->freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700640 bss->scan_miss_count = 0;
641 bss->last_update_idx = wpa_s->bss_update_idx;
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800642 wpa_bss_copy_res(bss, res, fetch_time);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700643 /* Move the entry to the end of the list */
644 dl_list_del(&bss->list);
Dmitry Shmidt96571392013-10-14 12:54:46 -0700645#ifdef CONFIG_P2P
646 if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
647 !wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE)) {
648 /*
649 * This can happen when non-P2P station interface runs a scan
650 * without P2P IE in the Probe Request frame. P2P GO would reply
651 * to that with a Probe Response that does not include P2P IE.
652 * Do not update the IEs in this BSS entry to avoid such loss of
653 * information that may be needed for P2P operations to
654 * determine group information.
655 */
656 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Do not update scan IEs for "
657 MACSTR " since that would remove P2P IE information",
658 MAC2STR(bss->bssid));
659 } else
660#endif /* CONFIG_P2P */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700661 if (bss->ie_len + bss->beacon_ie_len >=
662 res->ie_len + res->beacon_ie_len) {
663 os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
664 bss->ie_len = res->ie_len;
665 bss->beacon_ie_len = res->beacon_ie_len;
666 } else {
667 struct wpa_bss *nbss;
668 struct dl_list *prev = bss->list_id.prev;
669 dl_list_del(&bss->list_id);
670 nbss = os_realloc(bss, sizeof(*bss) + res->ie_len +
671 res->beacon_ie_len);
672 if (nbss) {
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -0700673 unsigned int i;
674 for (i = 0; i < wpa_s->last_scan_res_used; i++) {
675 if (wpa_s->last_scan_res[i] == bss) {
676 wpa_s->last_scan_res[i] = nbss;
677 break;
678 }
679 }
Dmitry Shmidt04949592012-07-19 12:16:46 -0700680 if (wpa_s->current_bss == bss)
681 wpa_s->current_bss = nbss;
Dmitry Shmidt2e425d62014-11-10 11:18:27 -0800682 wpa_bss_update_pending_connect(wpa_s, bss, nbss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700683 bss = nbss;
684 os_memcpy(bss + 1, res + 1,
685 res->ie_len + res->beacon_ie_len);
686 bss->ie_len = res->ie_len;
687 bss->beacon_ie_len = res->beacon_ie_len;
688 }
689 dl_list_add(prev, &bss->list_id);
690 }
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -0700691 if (changes & WPA_BSS_IES_CHANGED_FLAG)
692 wpa_bss_set_hessid(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700693 dl_list_add_tail(&wpa_s->bss, &bss->list);
694
695 notify_bss_changes(wpa_s, changes, bss);
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -0700696
697 return bss;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700698}
699
700
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800701/**
702 * wpa_bss_update_start - Start a BSS table update from scan results
703 * @wpa_s: Pointer to wpa_supplicant data
704 *
705 * This function is called at the start of each BSS table update round for new
706 * scan results. The actual scan result entries are indicated with calls to
707 * wpa_bss_update_scan_res() and the update round is finished with a call to
708 * wpa_bss_update_end().
709 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700710void wpa_bss_update_start(struct wpa_supplicant *wpa_s)
711{
712 wpa_s->bss_update_idx++;
713 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Start scan result update %u",
714 wpa_s->bss_update_idx);
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -0700715 wpa_s->last_scan_res_used = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700716}
717
718
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800719/**
720 * wpa_bss_update_scan_res - Update a BSS table entry based on a scan result
721 * @wpa_s: Pointer to wpa_supplicant data
722 * @res: Scan result
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800723 * @fetch_time: Time when the result was fetched from the driver
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800724 *
725 * This function updates a BSS table entry (or adds one) based on a scan result.
726 * This is called separately for each scan result between the calls to
727 * wpa_bss_update_start() and wpa_bss_update_end().
728 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700729void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800730 struct wpa_scan_res *res,
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800731 struct os_reltime *fetch_time)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700732{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800733 const u8 *ssid, *p2p, *mesh;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700734 struct wpa_bss *bss;
735
Dmitry Shmidt444d5672013-04-01 13:08:44 -0700736 if (wpa_s->conf->ignore_old_scan_res) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800737 struct os_reltime update;
Dmitry Shmidt444d5672013-04-01 13:08:44 -0700738 calculate_update_time(fetch_time, res->age, &update);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800739 if (os_reltime_before(&update, &wpa_s->scan_trigger_time)) {
740 struct os_reltime age;
741 os_reltime_sub(&wpa_s->scan_trigger_time, &update,
742 &age);
Dmitry Shmidt444d5672013-04-01 13:08:44 -0700743 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Ignore driver BSS "
744 "table entry that is %u.%06u seconds older "
745 "than our scan trigger",
746 (unsigned int) age.sec,
747 (unsigned int) age.usec);
748 return;
749 }
750 }
751
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700752 ssid = wpa_scan_get_ie(res, WLAN_EID_SSID);
753 if (ssid == NULL) {
754 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: No SSID IE included for "
755 MACSTR, MAC2STR(res->bssid));
756 return;
757 }
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -0700758 if (ssid[1] > SSID_MAX_LEN) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700759 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Too long SSID IE included for "
760 MACSTR, MAC2STR(res->bssid));
761 return;
762 }
763
764 p2p = wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE);
Dmitry Shmidt04949592012-07-19 12:16:46 -0700765#ifdef CONFIG_P2P
766 if (p2p == NULL &&
767 wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
768 /*
769 * If it's a P2P specific interface, then don't update
770 * the scan result without a P2P IE.
771 */
772 wpa_printf(MSG_DEBUG, "BSS: No P2P IE - skipping BSS " MACSTR
773 " update for P2P interface", MAC2STR(res->bssid));
774 return;
775 }
776#endif /* CONFIG_P2P */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700777 if (p2p && ssid[1] == P2P_WILDCARD_SSID_LEN &&
778 os_memcmp(ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 0)
779 return; /* Skip P2P listen discovery results here */
780
781 /* TODO: add option for ignoring BSSes we are not interested in
782 * (to save memory) */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800783
784 mesh = wpa_scan_get_ie(res, WLAN_EID_MESH_ID);
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -0700785 if (mesh && mesh[1] <= SSID_MAX_LEN)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800786 ssid = mesh;
787
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700788 bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
789 if (bss == NULL)
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800790 bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res, fetch_time);
Dmitry Shmidt56052862013-10-04 10:23:25 -0700791 else {
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800792 bss = wpa_bss_update(wpa_s, bss, res, fetch_time);
Dmitry Shmidt56052862013-10-04 10:23:25 -0700793 if (wpa_s->last_scan_res) {
794 unsigned int i;
795 for (i = 0; i < wpa_s->last_scan_res_used; i++) {
796 if (bss == wpa_s->last_scan_res[i]) {
797 /* Already in the list */
798 return;
799 }
800 }
801 }
802 }
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -0700803
804 if (bss == NULL)
805 return;
806 if (wpa_s->last_scan_res_used >= wpa_s->last_scan_res_size) {
807 struct wpa_bss **n;
808 unsigned int siz;
809 if (wpa_s->last_scan_res_size == 0)
810 siz = 32;
811 else
812 siz = wpa_s->last_scan_res_size * 2;
813 n = os_realloc_array(wpa_s->last_scan_res, siz,
814 sizeof(struct wpa_bss *));
815 if (n == NULL)
816 return;
817 wpa_s->last_scan_res = n;
818 wpa_s->last_scan_res_size = siz;
819 }
820
Dmitry Shmidt7832adb2014-04-29 10:53:02 -0700821 if (wpa_s->last_scan_res)
822 wpa_s->last_scan_res[wpa_s->last_scan_res_used++] = bss;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700823}
824
825
826static int wpa_bss_included_in_scan(const struct wpa_bss *bss,
827 const struct scan_info *info)
828{
829 int found;
830 size_t i;
831
832 if (info == NULL)
833 return 1;
834
835 if (info->num_freqs) {
836 found = 0;
837 for (i = 0; i < info->num_freqs; i++) {
838 if (bss->freq == info->freqs[i]) {
839 found = 1;
840 break;
841 }
842 }
843 if (!found)
844 return 0;
845 }
846
847 if (info->num_ssids) {
848 found = 0;
849 for (i = 0; i < info->num_ssids; i++) {
850 const struct wpa_driver_scan_ssid *s = &info->ssids[i];
851 if ((s->ssid == NULL || s->ssid_len == 0) ||
852 (s->ssid_len == bss->ssid_len &&
853 os_memcmp(s->ssid, bss->ssid, bss->ssid_len) ==
854 0)) {
855 found = 1;
856 break;
857 }
858 }
859 if (!found)
860 return 0;
861 }
862
863 return 1;
864}
865
866
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800867/**
868 * wpa_bss_update_end - End a BSS table update from scan results
869 * @wpa_s: Pointer to wpa_supplicant data
870 * @info: Information about scan parameters
871 * @new_scan: Whether this update round was based on a new scan
872 *
873 * This function is called at the end of each BSS table update round for new
874 * scan results. The start of the update was indicated with a call to
875 * wpa_bss_update_start().
876 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700877void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
878 int new_scan)
879{
880 struct wpa_bss *bss, *n;
881
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800882 os_get_reltime(&wpa_s->last_scan);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800883 if ((info && info->aborted) || !new_scan)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700884 return; /* do not expire entries without new scan */
885
886 dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
887 if (wpa_bss_in_use(wpa_s, bss))
888 continue;
889 if (!wpa_bss_included_in_scan(bss, info))
890 continue; /* expire only BSSes that were scanned */
891 if (bss->last_update_idx < wpa_s->bss_update_idx)
892 bss->scan_miss_count++;
893 if (bss->scan_miss_count >=
894 wpa_s->conf->bss_expiration_scan_count) {
Dmitry Shmidt04949592012-07-19 12:16:46 -0700895 wpa_bss_remove(wpa_s, bss, "no match in scan");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700896 }
897 }
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -0700898
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800899 wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%u/%u",
900 wpa_s->last_scan_res_used, wpa_s->last_scan_res_size);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700901}
902
903
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800904/**
905 * wpa_bss_flush_by_age - Flush old BSS entries
906 * @wpa_s: Pointer to wpa_supplicant data
907 * @age: Maximum entry age in seconds
908 *
909 * Remove BSS entries that have not been updated during the last @age seconds.
910 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700911void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age)
912{
913 struct wpa_bss *bss, *n;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800914 struct os_reltime t;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700915
916 if (dl_list_empty(&wpa_s->bss))
917 return;
918
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800919 os_get_reltime(&t);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700920 t.sec -= age;
921
922 dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
923 if (wpa_bss_in_use(wpa_s, bss))
924 continue;
925
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800926 if (os_reltime_before(&bss->last_update, &t)) {
Dmitry Shmidt04949592012-07-19 12:16:46 -0700927 wpa_bss_remove(wpa_s, bss, __func__);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700928 } else
929 break;
930 }
931}
932
933
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800934/**
935 * wpa_bss_init - Initialize BSS table
936 * @wpa_s: Pointer to wpa_supplicant data
937 * Returns: 0 on success, -1 on failure
938 *
939 * This prepares BSS table lists and timer for periodic updates. The BSS table
940 * is deinitialized with wpa_bss_deinit() once not needed anymore.
941 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700942int wpa_bss_init(struct wpa_supplicant *wpa_s)
943{
944 dl_list_init(&wpa_s->bss);
945 dl_list_init(&wpa_s->bss_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700946 return 0;
947}
948
949
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800950/**
951 * wpa_bss_flush - Flush all unused BSS entries
952 * @wpa_s: Pointer to wpa_supplicant data
953 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700954void wpa_bss_flush(struct wpa_supplicant *wpa_s)
955{
956 struct wpa_bss *bss, *n;
957
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800958 wpa_s->clear_driver_scan_cache = 1;
959
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700960 if (wpa_s->bss.next == NULL)
961 return; /* BSS table not yet initialized */
962
963 dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
964 if (wpa_bss_in_use(wpa_s, bss))
965 continue;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700966 wpa_bss_remove(wpa_s, bss, __func__);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700967 }
968}
969
970
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800971/**
972 * wpa_bss_deinit - Deinitialize BSS table
973 * @wpa_s: Pointer to wpa_supplicant data
974 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700975void wpa_bss_deinit(struct wpa_supplicant *wpa_s)
976{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700977 wpa_bss_flush(wpa_s);
978}
979
980
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800981/**
982 * wpa_bss_get_bssid - Fetch a BSS table entry based on BSSID
983 * @wpa_s: Pointer to wpa_supplicant data
984 * @bssid: BSSID
985 * Returns: Pointer to the BSS entry or %NULL if not found
986 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700987struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
988 const u8 *bssid)
989{
990 struct wpa_bss *bss;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700991 if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
992 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700993 dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
994 if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
995 return bss;
996 }
997 return NULL;
998}
999
1000
Dmitry Shmidt444d5672013-04-01 13:08:44 -07001001/**
1002 * wpa_bss_get_bssid_latest - Fetch the latest BSS table entry based on BSSID
1003 * @wpa_s: Pointer to wpa_supplicant data
1004 * @bssid: BSSID
1005 * Returns: Pointer to the BSS entry or %NULL if not found
1006 *
1007 * This function is like wpa_bss_get_bssid(), but full BSS table is iterated to
1008 * find the entry that has the most recent update. This can help in finding the
1009 * correct entry in cases where the SSID of the AP may have changed recently
1010 * (e.g., in WPS reconfiguration cases).
1011 */
1012struct wpa_bss * wpa_bss_get_bssid_latest(struct wpa_supplicant *wpa_s,
1013 const u8 *bssid)
1014{
1015 struct wpa_bss *bss, *found = NULL;
1016 if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
1017 return NULL;
1018 dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
1019 if (os_memcmp(bss->bssid, bssid, ETH_ALEN) != 0)
1020 continue;
1021 if (found == NULL ||
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001022 os_reltime_before(&found->last_update, &bss->last_update))
Dmitry Shmidt444d5672013-04-01 13:08:44 -07001023 found = bss;
1024 }
1025 return found;
1026}
1027
1028
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001029#ifdef CONFIG_P2P
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001030/**
1031 * wpa_bss_get_p2p_dev_addr - Fetch a BSS table entry based on P2P Device Addr
1032 * @wpa_s: Pointer to wpa_supplicant data
1033 * @dev_addr: P2P Device Address of the GO
1034 * Returns: Pointer to the BSS entry or %NULL if not found
1035 */
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001036struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s,
1037 const u8 *dev_addr)
1038{
1039 struct wpa_bss *bss;
1040 dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
1041 u8 addr[ETH_ALEN];
1042 if (p2p_parse_dev_addr((const u8 *) (bss + 1), bss->ie_len,
1043 addr) == 0 &&
1044 os_memcmp(addr, dev_addr, ETH_ALEN) == 0)
1045 return bss;
1046 }
1047 return NULL;
1048}
1049#endif /* CONFIG_P2P */
1050
1051
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001052/**
1053 * wpa_bss_get_id - Fetch a BSS table entry based on identifier
1054 * @wpa_s: Pointer to wpa_supplicant data
1055 * @id: Unique identifier (struct wpa_bss::id) assigned for the entry
1056 * Returns: Pointer to the BSS entry or %NULL if not found
1057 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001058struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id)
1059{
1060 struct wpa_bss *bss;
1061 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
1062 if (bss->id == id)
1063 return bss;
1064 }
1065 return NULL;
1066}
1067
1068
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001069/**
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001070 * wpa_bss_get_id_range - Fetch a BSS table entry based on identifier range
1071 * @wpa_s: Pointer to wpa_supplicant data
1072 * @idf: Smallest allowed identifier assigned for the entry
1073 * @idf: Largest allowed identifier assigned for the entry
1074 * Returns: Pointer to the BSS entry or %NULL if not found
1075 *
1076 * This function is similar to wpa_bss_get_id() but allows a BSS entry with the
1077 * smallest id value to be fetched within the specified range without the
1078 * caller having to know the exact id.
1079 */
1080struct wpa_bss * wpa_bss_get_id_range(struct wpa_supplicant *wpa_s,
1081 unsigned int idf, unsigned int idl)
1082{
1083 struct wpa_bss *bss;
1084 dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
1085 if (bss->id >= idf && bss->id <= idl)
1086 return bss;
1087 }
1088 return NULL;
1089}
1090
1091
1092/**
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001093 * wpa_bss_get_ie - Fetch a specified information element from a BSS entry
1094 * @bss: BSS table entry
1095 * @ie: Information element identitifier (WLAN_EID_*)
1096 * Returns: Pointer to the information element (id field) or %NULL if not found
1097 *
1098 * This function returns the first matching information element in the BSS
1099 * entry.
1100 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001101const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
1102{
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001103 return get_ie((const u8 *) (bss + 1), bss->ie_len, ie);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001104}
1105
1106
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001107/**
1108 * wpa_bss_get_vendor_ie - Fetch a vendor information element from a BSS entry
1109 * @bss: BSS table entry
1110 * @vendor_type: Vendor type (four octets starting the IE payload)
1111 * Returns: Pointer to the information element (id field) or %NULL if not found
1112 *
1113 * This function returns the first matching information element in the BSS
1114 * entry.
1115 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001116const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
1117{
1118 const u8 *end, *pos;
1119
1120 pos = (const u8 *) (bss + 1);
1121 end = pos + bss->ie_len;
1122
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001123 while (end - pos > 1) {
1124 if (2 + pos[1] > end - pos)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001125 break;
1126 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1127 vendor_type == WPA_GET_BE32(&pos[2]))
1128 return pos;
1129 pos += 2 + pos[1];
1130 }
1131
1132 return NULL;
1133}
1134
1135
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001136/**
Dmitry Shmidt96571392013-10-14 12:54:46 -07001137 * wpa_bss_get_vendor_ie_beacon - Fetch a vendor information from a BSS entry
1138 * @bss: BSS table entry
1139 * @vendor_type: Vendor type (four octets starting the IE payload)
1140 * Returns: Pointer to the information element (id field) or %NULL if not found
1141 *
1142 * This function returns the first matching information element in the BSS
1143 * entry.
1144 *
1145 * This function is like wpa_bss_get_vendor_ie(), but uses IE buffer only
1146 * from Beacon frames instead of either Beacon or Probe Response frames.
1147 */
1148const u8 * wpa_bss_get_vendor_ie_beacon(const struct wpa_bss *bss,
1149 u32 vendor_type)
1150{
1151 const u8 *end, *pos;
1152
1153 if (bss->beacon_ie_len == 0)
1154 return NULL;
1155
1156 pos = (const u8 *) (bss + 1);
1157 pos += bss->ie_len;
1158 end = pos + bss->beacon_ie_len;
1159
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001160 while (end - pos > 1) {
1161 if (2 + pos[1] > end - pos)
Dmitry Shmidt96571392013-10-14 12:54:46 -07001162 break;
1163 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1164 vendor_type == WPA_GET_BE32(&pos[2]))
1165 return pos;
1166 pos += 2 + pos[1];
1167 }
1168
1169 return NULL;
1170}
1171
1172
1173/**
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001174 * wpa_bss_get_vendor_ie_multi - Fetch vendor IE data from a BSS entry
1175 * @bss: BSS table entry
1176 * @vendor_type: Vendor type (four octets starting the IE payload)
1177 * Returns: Pointer to the information element payload or %NULL if not found
1178 *
1179 * This function returns concatenated payload of possibly fragmented vendor
1180 * specific information elements in the BSS entry. The caller is responsible for
1181 * freeing the returned buffer.
1182 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001183struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
1184 u32 vendor_type)
1185{
1186 struct wpabuf *buf;
1187 const u8 *end, *pos;
1188
1189 buf = wpabuf_alloc(bss->ie_len);
1190 if (buf == NULL)
1191 return NULL;
1192
1193 pos = (const u8 *) (bss + 1);
1194 end = pos + bss->ie_len;
1195
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001196 while (end - pos > 1) {
1197 if (2 + pos[1] > end - pos)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001198 break;
1199 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1200 vendor_type == WPA_GET_BE32(&pos[2]))
1201 wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
1202 pos += 2 + pos[1];
1203 }
1204
1205 if (wpabuf_len(buf) == 0) {
1206 wpabuf_free(buf);
1207 buf = NULL;
1208 }
1209
1210 return buf;
1211}
1212
1213
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001214/**
1215 * wpa_bss_get_vendor_ie_multi_beacon - Fetch vendor IE data from a BSS entry
1216 * @bss: BSS table entry
1217 * @vendor_type: Vendor type (four octets starting the IE payload)
1218 * Returns: Pointer to the information element payload or %NULL if not found
1219 *
1220 * This function returns concatenated payload of possibly fragmented vendor
1221 * specific information elements in the BSS entry. The caller is responsible for
1222 * freeing the returned buffer.
1223 *
1224 * This function is like wpa_bss_get_vendor_ie_multi(), but uses IE buffer only
1225 * from Beacon frames instead of either Beacon or Probe Response frames.
1226 */
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -07001227struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss,
1228 u32 vendor_type)
1229{
1230 struct wpabuf *buf;
1231 const u8 *end, *pos;
1232
1233 buf = wpabuf_alloc(bss->beacon_ie_len);
1234 if (buf == NULL)
1235 return NULL;
1236
1237 pos = (const u8 *) (bss + 1);
1238 pos += bss->ie_len;
1239 end = pos + bss->beacon_ie_len;
1240
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001241 while (end - pos > 1) {
1242 if (2 + pos[1] > end - pos)
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -07001243 break;
1244 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1245 vendor_type == WPA_GET_BE32(&pos[2]))
1246 wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
1247 pos += 2 + pos[1];
1248 }
1249
1250 if (wpabuf_len(buf) == 0) {
1251 wpabuf_free(buf);
1252 buf = NULL;
1253 }
1254
1255 return buf;
1256}
1257
1258
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001259/**
1260 * wpa_bss_get_max_rate - Get maximum legacy TX rate supported in a BSS
1261 * @bss: BSS table entry
1262 * Returns: Maximum legacy rate in units of 500 kbps
1263 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001264int wpa_bss_get_max_rate(const struct wpa_bss *bss)
1265{
1266 int rate = 0;
1267 const u8 *ie;
1268 int i;
1269
1270 ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
1271 for (i = 0; ie && i < ie[1]; i++) {
1272 if ((ie[i + 2] & 0x7f) > rate)
1273 rate = ie[i + 2] & 0x7f;
1274 }
1275
1276 ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
1277 for (i = 0; ie && i < ie[1]; i++) {
1278 if ((ie[i + 2] & 0x7f) > rate)
1279 rate = ie[i + 2] & 0x7f;
1280 }
1281
1282 return rate;
1283}
1284
1285
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001286/**
1287 * wpa_bss_get_bit_rates - Get legacy TX rates supported in a BSS
1288 * @bss: BSS table entry
1289 * @rates: Buffer for returning a pointer to the rates list (units of 500 kbps)
1290 * Returns: number of legacy TX rates or -1 on failure
1291 *
1292 * The caller is responsible for freeing the returned buffer with os_free() in
1293 * case of success.
1294 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001295int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates)
1296{
1297 const u8 *ie, *ie2;
1298 int i, j;
1299 unsigned int len;
1300 u8 *r;
1301
1302 ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
1303 ie2 = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
1304
1305 len = (ie ? ie[1] : 0) + (ie2 ? ie2[1] : 0);
1306
1307 r = os_malloc(len);
1308 if (!r)
1309 return -1;
1310
1311 for (i = 0; ie && i < ie[1]; i++)
1312 r[i] = ie[i + 2] & 0x7f;
1313
1314 for (j = 0; ie2 && j < ie2[1]; j++)
1315 r[i + j] = ie2[j + 2] & 0x7f;
1316
1317 *rates = r;
1318 return len;
1319}