blob: 5aa07eac445874445e3f355dc28549c173a02f2c [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);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700105 ANQP_DUP(hs20_operator_icon_metadata);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800106#endif /* CONFIG_HS20 */
107#undef ANQP_DUP
108
109 return n;
110}
111
112
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800113/**
114 * wpa_bss_anqp_unshare_alloc - Unshare ANQP data (if shared) in a BSS entry
115 * @bss: BSS entry
116 * Returns: 0 on success, -1 on failure
117 *
118 * This function ensures the specific BSS entry has an ANQP data structure that
119 * is not shared with any other BSS entry.
120 */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800121int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss)
122{
123 struct wpa_bss_anqp *anqp;
124
125 if (bss->anqp && bss->anqp->users > 1) {
126 /* allocated, but shared - clone an unshared copy */
127 anqp = wpa_bss_anqp_clone(bss->anqp);
128 if (anqp == NULL)
129 return -1;
130 anqp->users = 1;
131 bss->anqp->users--;
132 bss->anqp = anqp;
133 return 0;
134 }
135
136 if (bss->anqp)
137 return 0; /* already allocated and not shared */
138
139 /* not allocated - allocate a new storage area */
140 bss->anqp = wpa_bss_anqp_alloc();
141 return bss->anqp ? 0 : -1;
142}
143
144
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800145/**
146 * wpa_bss_anqp_free - Free an ANQP data structure
147 * @anqp: ANQP data structure from wpa_bss_anqp_alloc() or wpa_bss_anqp_clone()
148 */
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -0700149static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
150{
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800151#ifdef CONFIG_INTERWORKING
152 struct wpa_bss_anqp_elem *elem;
153#endif /* CONFIG_INTERWORKING */
154
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -0700155 if (anqp == NULL)
156 return;
157
158 anqp->users--;
159 if (anqp->users > 0) {
160 /* Another BSS entry holds a pointer to this ANQP info */
161 return;
162 }
163
164#ifdef CONFIG_INTERWORKING
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800165 wpabuf_free(anqp->capability_list);
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -0700166 wpabuf_free(anqp->venue_name);
167 wpabuf_free(anqp->network_auth_type);
168 wpabuf_free(anqp->roaming_consortium);
169 wpabuf_free(anqp->ip_addr_type_availability);
170 wpabuf_free(anqp->nai_realm);
171 wpabuf_free(anqp->anqp_3gpp);
172 wpabuf_free(anqp->domain_name);
Dmitry Shmidt29333592017-01-09 12:27:11 -0800173 wpabuf_free(anqp->fils_realm_info);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800174
175 while ((elem = dl_list_first(&anqp->anqp_elems,
176 struct wpa_bss_anqp_elem, list))) {
177 dl_list_del(&elem->list);
178 wpabuf_free(elem->payload);
179 os_free(elem);
180 }
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -0700181#endif /* CONFIG_INTERWORKING */
182#ifdef CONFIG_HS20
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800183 wpabuf_free(anqp->hs20_capability_list);
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -0700184 wpabuf_free(anqp->hs20_operator_friendly_name);
185 wpabuf_free(anqp->hs20_wan_metrics);
186 wpabuf_free(anqp->hs20_connection_capability);
187 wpabuf_free(anqp->hs20_operating_class);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800188 wpabuf_free(anqp->hs20_osu_providers_list);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700189 wpabuf_free(anqp->hs20_operator_icon_metadata);
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -0700190#endif /* CONFIG_HS20 */
191
192 os_free(anqp);
193}
194
195
Dmitry Shmidt2e425d62014-11-10 11:18:27 -0800196static void wpa_bss_update_pending_connect(struct wpa_supplicant *wpa_s,
197 struct wpa_bss *old_bss,
198 struct wpa_bss *new_bss)
199{
200 struct wpa_radio_work *work;
201 struct wpa_connect_work *cwork;
202
203 work = radio_work_pending(wpa_s, "sme-connect");
204 if (!work)
205 work = radio_work_pending(wpa_s, "connect");
206 if (!work)
207 return;
208
209 cwork = work->ctx;
210 if (cwork->bss != old_bss)
211 return;
212
213 wpa_printf(MSG_DEBUG,
214 "Update BSS pointer for the pending connect radio work");
215 cwork->bss = new_bss;
216 if (!new_bss)
217 cwork->bss_removed = 1;
218}
219
220
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800221void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
222 const char *reason)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700223{
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -0700224 if (wpa_s->last_scan_res) {
225 unsigned int i;
226 for (i = 0; i < wpa_s->last_scan_res_used; i++) {
227 if (wpa_s->last_scan_res[i] == bss) {
228 os_memmove(&wpa_s->last_scan_res[i],
229 &wpa_s->last_scan_res[i + 1],
230 (wpa_s->last_scan_res_used - i - 1)
231 * sizeof(struct wpa_bss *));
232 wpa_s->last_scan_res_used--;
233 break;
234 }
235 }
236 }
Dmitry Shmidt2e425d62014-11-10 11:18:27 -0800237 wpa_bss_update_pending_connect(wpa_s, bss, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700238 dl_list_del(&bss->list);
239 dl_list_del(&bss->list_id);
240 wpa_s->num_bss--;
241 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Remove id %u BSSID " MACSTR
Dmitry Shmidt04949592012-07-19 12:16:46 -0700242 " SSID '%s' due to %s", bss->id, MAC2STR(bss->bssid),
243 wpa_ssid_txt(bss->ssid, bss->ssid_len), reason);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700244 wpas_notify_bss_removed(wpa_s, bss->bssid, bss->id);
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -0700245 wpa_bss_anqp_free(bss->anqp);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700246 os_free(bss);
247}
248
249
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800250/**
251 * wpa_bss_get - Fetch a BSS table entry based on BSSID and SSID
252 * @wpa_s: Pointer to wpa_supplicant data
253 * @bssid: BSSID
254 * @ssid: SSID
255 * @ssid_len: Length of @ssid
256 * Returns: Pointer to the BSS entry or %NULL if not found
257 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700258struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
259 const u8 *ssid, size_t ssid_len)
260{
261 struct wpa_bss *bss;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700262 if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
263 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700264 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
265 if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
266 bss->ssid_len == ssid_len &&
267 os_memcmp(bss->ssid, ssid, ssid_len) == 0)
268 return bss;
269 }
270 return NULL;
271}
272
273
Dmitry Shmidt29333592017-01-09 12:27:11 -0800274void calculate_update_time(const struct os_reltime *fetch_time,
275 unsigned int age_ms,
276 struct os_reltime *update_time)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700277{
278 os_time_t usec;
279
Dmitry Shmidt444d5672013-04-01 13:08:44 -0700280 update_time->sec = fetch_time->sec;
281 update_time->usec = fetch_time->usec;
282 update_time->sec -= age_ms / 1000;
283 usec = (age_ms % 1000) * 1000;
284 if (update_time->usec < usec) {
285 update_time->sec--;
286 update_time->usec += 1000000;
287 }
288 update_time->usec -= usec;
289}
290
291
292static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src,
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800293 struct os_reltime *fetch_time)
Dmitry Shmidt444d5672013-04-01 13:08:44 -0700294{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700295 dst->flags = src->flags;
296 os_memcpy(dst->bssid, src->bssid, ETH_ALEN);
297 dst->freq = src->freq;
298 dst->beacon_int = src->beacon_int;
299 dst->caps = src->caps;
300 dst->qual = src->qual;
301 dst->noise = src->noise;
302 dst->level = src->level;
303 dst->tsf = src->tsf;
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800304 dst->est_throughput = src->est_throughput;
305 dst->snr = src->snr;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700306
Dmitry Shmidt444d5672013-04-01 13:08:44 -0700307 calculate_update_time(fetch_time, src->age, &dst->last_update);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700308}
309
310
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -0700311static int wpa_bss_is_wps_candidate(struct wpa_supplicant *wpa_s,
312 struct wpa_bss *bss)
313{
314#ifdef CONFIG_WPS
315 struct wpa_ssid *ssid;
316 struct wpabuf *wps_ie;
317 int pbc = 0, ret;
318
319 wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
320 if (!wps_ie)
321 return 0;
322
323 if (wps_is_selected_pbc_registrar(wps_ie)) {
324 pbc = 1;
325 } else if (!wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1)) {
326 wpabuf_free(wps_ie);
327 return 0;
328 }
329
330 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
331 if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS))
332 continue;
333 if (ssid->ssid_len &&
334 (ssid->ssid_len != bss->ssid_len ||
335 os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) != 0))
336 continue;
337
338 if (pbc)
339 ret = eap_is_wps_pbc_enrollee(&ssid->eap);
340 else
341 ret = eap_is_wps_pin_enrollee(&ssid->eap);
342 wpabuf_free(wps_ie);
343 return ret;
344 }
345 wpabuf_free(wps_ie);
346#endif /* CONFIG_WPS */
347
348 return 0;
349}
350
351
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800352static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
353{
354 struct wpa_ssid *ssid;
355
356 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
357 if (ssid->ssid == NULL || ssid->ssid_len == 0)
358 continue;
359 if (ssid->ssid_len == bss->ssid_len &&
360 os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) == 0)
361 return 1;
362 }
363
364 return 0;
365}
366
367
Dmitry Shmidt04949592012-07-19 12:16:46 -0700368static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
369{
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800370 if (bss == wpa_s->current_bss)
371 return 1;
372
373 if (wpa_s->current_bss &&
374 (bss->ssid_len != wpa_s->current_bss->ssid_len ||
375 os_memcmp(bss->ssid, wpa_s->current_bss->ssid,
376 bss->ssid_len) != 0))
377 return 0; /* SSID has changed */
378
379 return !is_zero_ether_addr(bss->bssid) &&
380 (os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 ||
381 os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0);
Dmitry Shmidt04949592012-07-19 12:16:46 -0700382}
383
384
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800385static int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s)
386{
387 struct wpa_bss *bss;
388
389 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -0700390 if (!wpa_bss_known(wpa_s, bss) &&
391 !wpa_bss_is_wps_candidate(wpa_s, bss)) {
Dmitry Shmidt04949592012-07-19 12:16:46 -0700392 wpa_bss_remove(wpa_s, bss, __func__);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800393 return 0;
394 }
395 }
396
397 return -1;
398}
399
400
Dmitry Shmidt04949592012-07-19 12:16:46 -0700401static int wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800402{
Dmitry Shmidt04949592012-07-19 12:16:46 -0700403 struct wpa_bss *bss;
404
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800405 /*
406 * Remove the oldest entry that does not match with any configured
407 * network.
408 */
409 if (wpa_bss_remove_oldest_unknown(wpa_s) == 0)
Dmitry Shmidt04949592012-07-19 12:16:46 -0700410 return 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800411
412 /*
Dmitry Shmidt04949592012-07-19 12:16:46 -0700413 * Remove the oldest entry that isn't currently in use.
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800414 */
Dmitry Shmidt04949592012-07-19 12:16:46 -0700415 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
416 if (!wpa_bss_in_use(wpa_s, bss)) {
417 wpa_bss_remove(wpa_s, bss, __func__);
418 return 0;
419 }
420 }
421
422 return -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800423}
424
425
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -0700426static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s,
427 const u8 *ssid, size_t ssid_len,
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800428 struct wpa_scan_res *res,
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800429 struct os_reltime *fetch_time)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700430{
431 struct wpa_bss *bss;
432
433 bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len);
434 if (bss == NULL)
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -0700435 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700436 bss->id = wpa_s->bss_next_id++;
437 bss->last_update_idx = wpa_s->bss_update_idx;
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800438 wpa_bss_copy_res(bss, res, fetch_time);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700439 os_memcpy(bss->ssid, ssid, ssid_len);
440 bss->ssid_len = ssid_len;
441 bss->ie_len = res->ie_len;
442 bss->beacon_ie_len = res->beacon_ie_len;
443 os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -0700444 wpa_bss_set_hessid(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700445
Jouni Malinen7a6c8302013-09-27 15:47:09 +0300446 if (wpa_s->num_bss + 1 > wpa_s->conf->bss_max_count &&
447 wpa_bss_remove_oldest(wpa_s) != 0) {
448 wpa_printf(MSG_ERROR, "Increasing the MAX BSS count to %d "
449 "because all BSSes are in use. We should normally "
450 "not get here!", (int) wpa_s->num_bss + 1);
451 wpa_s->conf->bss_max_count = wpa_s->num_bss + 1;
452 }
453
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700454 dl_list_add_tail(&wpa_s->bss, &bss->list);
455 dl_list_add_tail(&wpa_s->bss_id, &bss->list_id);
456 wpa_s->num_bss++;
457 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Add new id %u BSSID " MACSTR
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800458 " SSID '%s' freq %d",
459 bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len),
460 bss->freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700461 wpas_notify_bss_added(wpa_s, bss->bssid, bss->id);
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -0700462 return bss;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700463}
464
465
466static int are_ies_equal(const struct wpa_bss *old,
Dmitry Shmidt1d755d02015-04-28 10:34:29 -0700467 const struct wpa_scan_res *new_res, u32 ie)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700468{
469 const u8 *old_ie, *new_ie;
470 struct wpabuf *old_ie_buff = NULL;
471 struct wpabuf *new_ie_buff = NULL;
472 int new_ie_len, old_ie_len, ret, is_multi;
473
474 switch (ie) {
475 case WPA_IE_VENDOR_TYPE:
476 old_ie = wpa_bss_get_vendor_ie(old, ie);
Dmitry Shmidt1d755d02015-04-28 10:34:29 -0700477 new_ie = wpa_scan_get_vendor_ie(new_res, ie);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700478 is_multi = 0;
479 break;
480 case WPS_IE_VENDOR_TYPE:
481 old_ie_buff = wpa_bss_get_vendor_ie_multi(old, ie);
Dmitry Shmidt1d755d02015-04-28 10:34:29 -0700482 new_ie_buff = wpa_scan_get_vendor_ie_multi(new_res, ie);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700483 is_multi = 1;
484 break;
485 case WLAN_EID_RSN:
486 case WLAN_EID_SUPP_RATES:
487 case WLAN_EID_EXT_SUPP_RATES:
488 old_ie = wpa_bss_get_ie(old, ie);
Dmitry Shmidt1d755d02015-04-28 10:34:29 -0700489 new_ie = wpa_scan_get_ie(new_res, ie);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700490 is_multi = 0;
491 break;
492 default:
493 wpa_printf(MSG_DEBUG, "bss: %s: cannot compare IEs", __func__);
494 return 0;
495 }
496
497 if (is_multi) {
498 /* in case of multiple IEs stored in buffer */
499 old_ie = old_ie_buff ? wpabuf_head_u8(old_ie_buff) : NULL;
500 new_ie = new_ie_buff ? wpabuf_head_u8(new_ie_buff) : NULL;
501 old_ie_len = old_ie_buff ? wpabuf_len(old_ie_buff) : 0;
502 new_ie_len = new_ie_buff ? wpabuf_len(new_ie_buff) : 0;
503 } else {
504 /* in case of single IE */
505 old_ie_len = old_ie ? old_ie[1] + 2 : 0;
506 new_ie_len = new_ie ? new_ie[1] + 2 : 0;
507 }
508
509 if (!old_ie || !new_ie)
510 ret = !old_ie && !new_ie;
511 else
512 ret = (old_ie_len == new_ie_len &&
513 os_memcmp(old_ie, new_ie, old_ie_len) == 0);
514
515 wpabuf_free(old_ie_buff);
516 wpabuf_free(new_ie_buff);
517
518 return ret;
519}
520
521
522static u32 wpa_bss_compare_res(const struct wpa_bss *old,
Dmitry Shmidt1d755d02015-04-28 10:34:29 -0700523 const struct wpa_scan_res *new_res)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700524{
525 u32 changes = 0;
Dmitry Shmidt1d755d02015-04-28 10:34:29 -0700526 int caps_diff = old->caps ^ new_res->caps;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700527
Dmitry Shmidt1d755d02015-04-28 10:34:29 -0700528 if (old->freq != new_res->freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700529 changes |= WPA_BSS_FREQ_CHANGED_FLAG;
530
Dmitry Shmidt1d755d02015-04-28 10:34:29 -0700531 if (old->level != new_res->level)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700532 changes |= WPA_BSS_SIGNAL_CHANGED_FLAG;
533
534 if (caps_diff & IEEE80211_CAP_PRIVACY)
535 changes |= WPA_BSS_PRIVACY_CHANGED_FLAG;
536
537 if (caps_diff & IEEE80211_CAP_IBSS)
538 changes |= WPA_BSS_MODE_CHANGED_FLAG;
539
Dmitry Shmidt1d755d02015-04-28 10:34:29 -0700540 if (old->ie_len == new_res->ie_len &&
541 os_memcmp(old + 1, new_res + 1, old->ie_len) == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700542 return changes;
543 changes |= WPA_BSS_IES_CHANGED_FLAG;
544
Dmitry Shmidt1d755d02015-04-28 10:34:29 -0700545 if (!are_ies_equal(old, new_res, WPA_IE_VENDOR_TYPE))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700546 changes |= WPA_BSS_WPAIE_CHANGED_FLAG;
547
Dmitry Shmidt1d755d02015-04-28 10:34:29 -0700548 if (!are_ies_equal(old, new_res, WLAN_EID_RSN))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700549 changes |= WPA_BSS_RSNIE_CHANGED_FLAG;
550
Dmitry Shmidt1d755d02015-04-28 10:34:29 -0700551 if (!are_ies_equal(old, new_res, WPS_IE_VENDOR_TYPE))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700552 changes |= WPA_BSS_WPS_CHANGED_FLAG;
553
Dmitry Shmidt1d755d02015-04-28 10:34:29 -0700554 if (!are_ies_equal(old, new_res, WLAN_EID_SUPP_RATES) ||
555 !are_ies_equal(old, new_res, WLAN_EID_EXT_SUPP_RATES))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700556 changes |= WPA_BSS_RATES_CHANGED_FLAG;
557
558 return changes;
559}
560
561
562static void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
563 const struct wpa_bss *bss)
564{
565 if (changes & WPA_BSS_FREQ_CHANGED_FLAG)
566 wpas_notify_bss_freq_changed(wpa_s, bss->id);
567
568 if (changes & WPA_BSS_SIGNAL_CHANGED_FLAG)
569 wpas_notify_bss_signal_changed(wpa_s, bss->id);
570
571 if (changes & WPA_BSS_PRIVACY_CHANGED_FLAG)
572 wpas_notify_bss_privacy_changed(wpa_s, bss->id);
573
574 if (changes & WPA_BSS_MODE_CHANGED_FLAG)
575 wpas_notify_bss_mode_changed(wpa_s, bss->id);
576
577 if (changes & WPA_BSS_WPAIE_CHANGED_FLAG)
578 wpas_notify_bss_wpaie_changed(wpa_s, bss->id);
579
580 if (changes & WPA_BSS_RSNIE_CHANGED_FLAG)
581 wpas_notify_bss_rsnie_changed(wpa_s, bss->id);
582
583 if (changes & WPA_BSS_WPS_CHANGED_FLAG)
584 wpas_notify_bss_wps_changed(wpa_s, bss->id);
585
586 if (changes & WPA_BSS_IES_CHANGED_FLAG)
587 wpas_notify_bss_ies_changed(wpa_s, bss->id);
588
589 if (changes & WPA_BSS_RATES_CHANGED_FLAG)
590 wpas_notify_bss_rates_changed(wpa_s, bss->id);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -0700591
592 wpas_notify_bss_seen(wpa_s, bss->id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700593}
594
595
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -0700596static struct wpa_bss *
597wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800598 struct wpa_scan_res *res, struct os_reltime *fetch_time)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700599{
600 u32 changes;
601
Dmitry Shmidtabb90a32016-12-05 15:34:39 -0800602 if (bss->last_update_idx == wpa_s->bss_update_idx) {
603 struct os_reltime update_time;
604
605 /*
606 * Some drivers (e.g., cfg80211) include multiple BSS entries
607 * for the same BSS if that BSS's channel changes. The BSS list
608 * implementation in wpa_supplicant does not do that and we need
609 * to filter out the obsolete results here to make sure only the
610 * most current BSS information remains in the table.
611 */
612 wpa_printf(MSG_DEBUG, "BSS: " MACSTR
613 " has multiple entries in the scan results - select the most current one",
614 MAC2STR(bss->bssid));
615 calculate_update_time(fetch_time, res->age, &update_time);
616 wpa_printf(MSG_DEBUG,
617 "Previous last_update: %u.%06u (freq %d%s)",
618 (unsigned int) bss->last_update.sec,
619 (unsigned int) bss->last_update.usec,
620 bss->freq,
621 (bss->flags & WPA_BSS_ASSOCIATED) ? " assoc" : "");
622 wpa_printf(MSG_DEBUG, "New last_update: %u.%06u (freq %d%s)",
623 (unsigned int) update_time.sec,
624 (unsigned int) update_time.usec,
625 res->freq,
626 (res->flags & WPA_SCAN_ASSOCIATED) ? " assoc" : "");
627 if ((bss->flags & WPA_BSS_ASSOCIATED) ||
628 (!(res->flags & WPA_SCAN_ASSOCIATED) &&
629 !os_reltime_before(&bss->last_update, &update_time))) {
630 wpa_printf(MSG_DEBUG,
631 "Ignore this BSS entry since the previous update looks more current");
632 return bss;
633 }
634 wpa_printf(MSG_DEBUG,
635 "Accept this BSS entry since it looks more current than the previous update");
636 }
637
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700638 changes = wpa_bss_compare_res(bss, res);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800639 if (changes & WPA_BSS_FREQ_CHANGED_FLAG)
640 wpa_printf(MSG_DEBUG, "BSS: " MACSTR " changed freq %d --> %d",
641 MAC2STR(bss->bssid), bss->freq, res->freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700642 bss->scan_miss_count = 0;
643 bss->last_update_idx = wpa_s->bss_update_idx;
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800644 wpa_bss_copy_res(bss, res, fetch_time);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700645 /* Move the entry to the end of the list */
646 dl_list_del(&bss->list);
Dmitry Shmidt96571392013-10-14 12:54:46 -0700647#ifdef CONFIG_P2P
648 if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
649 !wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE)) {
650 /*
651 * This can happen when non-P2P station interface runs a scan
652 * without P2P IE in the Probe Request frame. P2P GO would reply
653 * to that with a Probe Response that does not include P2P IE.
654 * Do not update the IEs in this BSS entry to avoid such loss of
655 * information that may be needed for P2P operations to
656 * determine group information.
657 */
658 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Do not update scan IEs for "
659 MACSTR " since that would remove P2P IE information",
660 MAC2STR(bss->bssid));
661 } else
662#endif /* CONFIG_P2P */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700663 if (bss->ie_len + bss->beacon_ie_len >=
664 res->ie_len + res->beacon_ie_len) {
665 os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
666 bss->ie_len = res->ie_len;
667 bss->beacon_ie_len = res->beacon_ie_len;
668 } else {
669 struct wpa_bss *nbss;
670 struct dl_list *prev = bss->list_id.prev;
671 dl_list_del(&bss->list_id);
672 nbss = os_realloc(bss, sizeof(*bss) + res->ie_len +
673 res->beacon_ie_len);
674 if (nbss) {
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -0700675 unsigned int i;
676 for (i = 0; i < wpa_s->last_scan_res_used; i++) {
677 if (wpa_s->last_scan_res[i] == bss) {
678 wpa_s->last_scan_res[i] = nbss;
679 break;
680 }
681 }
Dmitry Shmidt04949592012-07-19 12:16:46 -0700682 if (wpa_s->current_bss == bss)
683 wpa_s->current_bss = nbss;
Dmitry Shmidt2e425d62014-11-10 11:18:27 -0800684 wpa_bss_update_pending_connect(wpa_s, bss, nbss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700685 bss = nbss;
686 os_memcpy(bss + 1, res + 1,
687 res->ie_len + res->beacon_ie_len);
688 bss->ie_len = res->ie_len;
689 bss->beacon_ie_len = res->beacon_ie_len;
690 }
691 dl_list_add(prev, &bss->list_id);
692 }
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -0700693 if (changes & WPA_BSS_IES_CHANGED_FLAG)
694 wpa_bss_set_hessid(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700695 dl_list_add_tail(&wpa_s->bss, &bss->list);
696
697 notify_bss_changes(wpa_s, changes, bss);
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -0700698
699 return bss;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700700}
701
702
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800703/**
704 * wpa_bss_update_start - Start a BSS table update from scan results
705 * @wpa_s: Pointer to wpa_supplicant data
706 *
707 * This function is called at the start of each BSS table update round for new
708 * scan results. The actual scan result entries are indicated with calls to
709 * wpa_bss_update_scan_res() and the update round is finished with a call to
710 * wpa_bss_update_end().
711 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700712void wpa_bss_update_start(struct wpa_supplicant *wpa_s)
713{
714 wpa_s->bss_update_idx++;
715 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Start scan result update %u",
716 wpa_s->bss_update_idx);
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -0700717 wpa_s->last_scan_res_used = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700718}
719
720
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800721/**
722 * wpa_bss_update_scan_res - Update a BSS table entry based on a scan result
723 * @wpa_s: Pointer to wpa_supplicant data
724 * @res: Scan result
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800725 * @fetch_time: Time when the result was fetched from the driver
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800726 *
727 * This function updates a BSS table entry (or adds one) based on a scan result.
728 * This is called separately for each scan result between the calls to
729 * wpa_bss_update_start() and wpa_bss_update_end().
730 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700731void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800732 struct wpa_scan_res *res,
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800733 struct os_reltime *fetch_time)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700734{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800735 const u8 *ssid, *p2p, *mesh;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700736 struct wpa_bss *bss;
737
Dmitry Shmidt444d5672013-04-01 13:08:44 -0700738 if (wpa_s->conf->ignore_old_scan_res) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800739 struct os_reltime update;
Dmitry Shmidt444d5672013-04-01 13:08:44 -0700740 calculate_update_time(fetch_time, res->age, &update);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800741 if (os_reltime_before(&update, &wpa_s->scan_trigger_time)) {
742 struct os_reltime age;
743 os_reltime_sub(&wpa_s->scan_trigger_time, &update,
744 &age);
Dmitry Shmidt444d5672013-04-01 13:08:44 -0700745 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Ignore driver BSS "
746 "table entry that is %u.%06u seconds older "
747 "than our scan trigger",
748 (unsigned int) age.sec,
749 (unsigned int) age.usec);
750 return;
751 }
752 }
753
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700754 ssid = wpa_scan_get_ie(res, WLAN_EID_SSID);
755 if (ssid == NULL) {
756 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: No SSID IE included for "
757 MACSTR, MAC2STR(res->bssid));
758 return;
759 }
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -0700760 if (ssid[1] > SSID_MAX_LEN) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700761 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Too long SSID IE included for "
762 MACSTR, MAC2STR(res->bssid));
763 return;
764 }
765
766 p2p = wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE);
Dmitry Shmidt04949592012-07-19 12:16:46 -0700767#ifdef CONFIG_P2P
768 if (p2p == NULL &&
769 wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
770 /*
771 * If it's a P2P specific interface, then don't update
772 * the scan result without a P2P IE.
773 */
774 wpa_printf(MSG_DEBUG, "BSS: No P2P IE - skipping BSS " MACSTR
775 " update for P2P interface", MAC2STR(res->bssid));
776 return;
777 }
778#endif /* CONFIG_P2P */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700779 if (p2p && ssid[1] == P2P_WILDCARD_SSID_LEN &&
780 os_memcmp(ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 0)
781 return; /* Skip P2P listen discovery results here */
782
783 /* TODO: add option for ignoring BSSes we are not interested in
784 * (to save memory) */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800785
786 mesh = wpa_scan_get_ie(res, WLAN_EID_MESH_ID);
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -0700787 if (mesh && mesh[1] <= SSID_MAX_LEN)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800788 ssid = mesh;
789
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700790 bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
791 if (bss == NULL)
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800792 bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res, fetch_time);
Dmitry Shmidt56052862013-10-04 10:23:25 -0700793 else {
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800794 bss = wpa_bss_update(wpa_s, bss, res, fetch_time);
Dmitry Shmidt56052862013-10-04 10:23:25 -0700795 if (wpa_s->last_scan_res) {
796 unsigned int i;
797 for (i = 0; i < wpa_s->last_scan_res_used; i++) {
798 if (bss == wpa_s->last_scan_res[i]) {
799 /* Already in the list */
800 return;
801 }
802 }
803 }
804 }
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -0700805
806 if (bss == NULL)
807 return;
808 if (wpa_s->last_scan_res_used >= wpa_s->last_scan_res_size) {
809 struct wpa_bss **n;
810 unsigned int siz;
811 if (wpa_s->last_scan_res_size == 0)
812 siz = 32;
813 else
814 siz = wpa_s->last_scan_res_size * 2;
815 n = os_realloc_array(wpa_s->last_scan_res, siz,
816 sizeof(struct wpa_bss *));
817 if (n == NULL)
818 return;
819 wpa_s->last_scan_res = n;
820 wpa_s->last_scan_res_size = siz;
821 }
822
Dmitry Shmidt7832adb2014-04-29 10:53:02 -0700823 if (wpa_s->last_scan_res)
824 wpa_s->last_scan_res[wpa_s->last_scan_res_used++] = bss;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700825}
826
827
828static int wpa_bss_included_in_scan(const struct wpa_bss *bss,
829 const struct scan_info *info)
830{
831 int found;
832 size_t i;
833
834 if (info == NULL)
835 return 1;
836
837 if (info->num_freqs) {
838 found = 0;
839 for (i = 0; i < info->num_freqs; i++) {
840 if (bss->freq == info->freqs[i]) {
841 found = 1;
842 break;
843 }
844 }
845 if (!found)
846 return 0;
847 }
848
849 if (info->num_ssids) {
850 found = 0;
851 for (i = 0; i < info->num_ssids; i++) {
852 const struct wpa_driver_scan_ssid *s = &info->ssids[i];
853 if ((s->ssid == NULL || s->ssid_len == 0) ||
854 (s->ssid_len == bss->ssid_len &&
855 os_memcmp(s->ssid, bss->ssid, bss->ssid_len) ==
856 0)) {
857 found = 1;
858 break;
859 }
860 }
861 if (!found)
862 return 0;
863 }
864
865 return 1;
866}
867
868
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800869/**
870 * wpa_bss_update_end - End a BSS table update from scan results
871 * @wpa_s: Pointer to wpa_supplicant data
872 * @info: Information about scan parameters
873 * @new_scan: Whether this update round was based on a new scan
874 *
875 * This function is called at the end of each BSS table update round for new
876 * scan results. The start of the update was indicated with a call to
877 * wpa_bss_update_start().
878 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700879void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
880 int new_scan)
881{
882 struct wpa_bss *bss, *n;
883
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800884 os_get_reltime(&wpa_s->last_scan);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800885 if ((info && info->aborted) || !new_scan)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700886 return; /* do not expire entries without new scan */
887
888 dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
889 if (wpa_bss_in_use(wpa_s, bss))
890 continue;
891 if (!wpa_bss_included_in_scan(bss, info))
892 continue; /* expire only BSSes that were scanned */
893 if (bss->last_update_idx < wpa_s->bss_update_idx)
894 bss->scan_miss_count++;
895 if (bss->scan_miss_count >=
896 wpa_s->conf->bss_expiration_scan_count) {
Dmitry Shmidt04949592012-07-19 12:16:46 -0700897 wpa_bss_remove(wpa_s, bss, "no match in scan");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700898 }
899 }
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -0700900
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800901 wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%u/%u",
902 wpa_s->last_scan_res_used, wpa_s->last_scan_res_size);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700903}
904
905
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800906/**
907 * wpa_bss_flush_by_age - Flush old BSS entries
908 * @wpa_s: Pointer to wpa_supplicant data
909 * @age: Maximum entry age in seconds
910 *
911 * Remove BSS entries that have not been updated during the last @age seconds.
912 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700913void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age)
914{
915 struct wpa_bss *bss, *n;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800916 struct os_reltime t;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700917
918 if (dl_list_empty(&wpa_s->bss))
919 return;
920
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800921 os_get_reltime(&t);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700922 t.sec -= age;
923
924 dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
925 if (wpa_bss_in_use(wpa_s, bss))
926 continue;
927
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800928 if (os_reltime_before(&bss->last_update, &t)) {
Dmitry Shmidt04949592012-07-19 12:16:46 -0700929 wpa_bss_remove(wpa_s, bss, __func__);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700930 } else
931 break;
932 }
933}
934
935
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800936/**
937 * wpa_bss_init - Initialize BSS table
938 * @wpa_s: Pointer to wpa_supplicant data
939 * Returns: 0 on success, -1 on failure
940 *
941 * This prepares BSS table lists and timer for periodic updates. The BSS table
942 * is deinitialized with wpa_bss_deinit() once not needed anymore.
943 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700944int wpa_bss_init(struct wpa_supplicant *wpa_s)
945{
946 dl_list_init(&wpa_s->bss);
947 dl_list_init(&wpa_s->bss_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700948 return 0;
949}
950
951
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800952/**
953 * wpa_bss_flush - Flush all unused BSS entries
954 * @wpa_s: Pointer to wpa_supplicant data
955 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700956void wpa_bss_flush(struct wpa_supplicant *wpa_s)
957{
958 struct wpa_bss *bss, *n;
959
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800960 wpa_s->clear_driver_scan_cache = 1;
961
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700962 if (wpa_s->bss.next == NULL)
963 return; /* BSS table not yet initialized */
964
965 dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
966 if (wpa_bss_in_use(wpa_s, bss))
967 continue;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700968 wpa_bss_remove(wpa_s, bss, __func__);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700969 }
970}
971
972
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800973/**
974 * wpa_bss_deinit - Deinitialize BSS table
975 * @wpa_s: Pointer to wpa_supplicant data
976 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700977void wpa_bss_deinit(struct wpa_supplicant *wpa_s)
978{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700979 wpa_bss_flush(wpa_s);
980}
981
982
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800983/**
984 * wpa_bss_get_bssid - Fetch a BSS table entry based on BSSID
985 * @wpa_s: Pointer to wpa_supplicant data
986 * @bssid: BSSID
987 * Returns: Pointer to the BSS entry or %NULL if not found
988 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700989struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
990 const u8 *bssid)
991{
992 struct wpa_bss *bss;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700993 if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
994 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700995 dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
996 if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
997 return bss;
998 }
999 return NULL;
1000}
1001
1002
Dmitry Shmidt444d5672013-04-01 13:08:44 -07001003/**
1004 * wpa_bss_get_bssid_latest - Fetch the latest BSS table entry based on BSSID
1005 * @wpa_s: Pointer to wpa_supplicant data
1006 * @bssid: BSSID
1007 * Returns: Pointer to the BSS entry or %NULL if not found
1008 *
1009 * This function is like wpa_bss_get_bssid(), but full BSS table is iterated to
1010 * find the entry that has the most recent update. This can help in finding the
1011 * correct entry in cases where the SSID of the AP may have changed recently
1012 * (e.g., in WPS reconfiguration cases).
1013 */
1014struct wpa_bss * wpa_bss_get_bssid_latest(struct wpa_supplicant *wpa_s,
1015 const u8 *bssid)
1016{
1017 struct wpa_bss *bss, *found = NULL;
1018 if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
1019 return NULL;
1020 dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
1021 if (os_memcmp(bss->bssid, bssid, ETH_ALEN) != 0)
1022 continue;
1023 if (found == NULL ||
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001024 os_reltime_before(&found->last_update, &bss->last_update))
Dmitry Shmidt444d5672013-04-01 13:08:44 -07001025 found = bss;
1026 }
1027 return found;
1028}
1029
1030
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001031#ifdef CONFIG_P2P
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001032/**
1033 * wpa_bss_get_p2p_dev_addr - Fetch a BSS table entry based on P2P Device Addr
1034 * @wpa_s: Pointer to wpa_supplicant data
1035 * @dev_addr: P2P Device Address of the GO
1036 * Returns: Pointer to the BSS entry or %NULL if not found
1037 */
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001038struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s,
1039 const u8 *dev_addr)
1040{
1041 struct wpa_bss *bss;
1042 dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
1043 u8 addr[ETH_ALEN];
1044 if (p2p_parse_dev_addr((const u8 *) (bss + 1), bss->ie_len,
1045 addr) == 0 &&
1046 os_memcmp(addr, dev_addr, ETH_ALEN) == 0)
1047 return bss;
1048 }
1049 return NULL;
1050}
1051#endif /* CONFIG_P2P */
1052
1053
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001054/**
1055 * wpa_bss_get_id - Fetch a BSS table entry based on identifier
1056 * @wpa_s: Pointer to wpa_supplicant data
1057 * @id: Unique identifier (struct wpa_bss::id) assigned for the entry
1058 * Returns: Pointer to the BSS entry or %NULL if not found
1059 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001060struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id)
1061{
1062 struct wpa_bss *bss;
1063 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
1064 if (bss->id == id)
1065 return bss;
1066 }
1067 return NULL;
1068}
1069
1070
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001071/**
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001072 * wpa_bss_get_id_range - Fetch a BSS table entry based on identifier range
1073 * @wpa_s: Pointer to wpa_supplicant data
1074 * @idf: Smallest allowed identifier assigned for the entry
1075 * @idf: Largest allowed identifier assigned for the entry
1076 * Returns: Pointer to the BSS entry or %NULL if not found
1077 *
1078 * This function is similar to wpa_bss_get_id() but allows a BSS entry with the
1079 * smallest id value to be fetched within the specified range without the
1080 * caller having to know the exact id.
1081 */
1082struct wpa_bss * wpa_bss_get_id_range(struct wpa_supplicant *wpa_s,
1083 unsigned int idf, unsigned int idl)
1084{
1085 struct wpa_bss *bss;
1086 dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
1087 if (bss->id >= idf && bss->id <= idl)
1088 return bss;
1089 }
1090 return NULL;
1091}
1092
1093
1094/**
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001095 * wpa_bss_get_ie - Fetch a specified information element from a BSS entry
1096 * @bss: BSS table entry
1097 * @ie: Information element identitifier (WLAN_EID_*)
1098 * Returns: Pointer to the information element (id field) or %NULL if not found
1099 *
1100 * This function returns the first matching information element in the BSS
1101 * entry.
1102 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001103const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
1104{
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001105 return get_ie((const u8 *) (bss + 1), bss->ie_len, ie);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001106}
1107
1108
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001109/**
1110 * wpa_bss_get_vendor_ie - Fetch a vendor information element from a BSS entry
1111 * @bss: BSS table entry
1112 * @vendor_type: Vendor type (four octets starting the IE payload)
1113 * Returns: Pointer to the information element (id field) or %NULL if not found
1114 *
1115 * This function returns the first matching information element in the BSS
1116 * entry.
1117 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001118const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
1119{
1120 const u8 *end, *pos;
1121
1122 pos = (const u8 *) (bss + 1);
1123 end = pos + bss->ie_len;
1124
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001125 while (end - pos > 1) {
1126 if (2 + pos[1] > end - pos)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001127 break;
1128 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1129 vendor_type == WPA_GET_BE32(&pos[2]))
1130 return pos;
1131 pos += 2 + pos[1];
1132 }
1133
1134 return NULL;
1135}
1136
1137
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001138/**
Dmitry Shmidt96571392013-10-14 12:54:46 -07001139 * wpa_bss_get_vendor_ie_beacon - Fetch a vendor information from a BSS entry
1140 * @bss: BSS table entry
1141 * @vendor_type: Vendor type (four octets starting the IE payload)
1142 * Returns: Pointer to the information element (id field) or %NULL if not found
1143 *
1144 * This function returns the first matching information element in the BSS
1145 * entry.
1146 *
1147 * This function is like wpa_bss_get_vendor_ie(), but uses IE buffer only
1148 * from Beacon frames instead of either Beacon or Probe Response frames.
1149 */
1150const u8 * wpa_bss_get_vendor_ie_beacon(const struct wpa_bss *bss,
1151 u32 vendor_type)
1152{
1153 const u8 *end, *pos;
1154
1155 if (bss->beacon_ie_len == 0)
1156 return NULL;
1157
1158 pos = (const u8 *) (bss + 1);
1159 pos += bss->ie_len;
1160 end = pos + bss->beacon_ie_len;
1161
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001162 while (end - pos > 1) {
1163 if (2 + pos[1] > end - pos)
Dmitry Shmidt96571392013-10-14 12:54:46 -07001164 break;
1165 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1166 vendor_type == WPA_GET_BE32(&pos[2]))
1167 return pos;
1168 pos += 2 + pos[1];
1169 }
1170
1171 return NULL;
1172}
1173
1174
1175/**
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001176 * wpa_bss_get_vendor_ie_multi - Fetch vendor IE data from a BSS entry
1177 * @bss: BSS table entry
1178 * @vendor_type: Vendor type (four octets starting the IE payload)
1179 * Returns: Pointer to the information element payload or %NULL if not found
1180 *
1181 * This function returns concatenated payload of possibly fragmented vendor
1182 * specific information elements in the BSS entry. The caller is responsible for
1183 * freeing the returned buffer.
1184 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001185struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
1186 u32 vendor_type)
1187{
1188 struct wpabuf *buf;
1189 const u8 *end, *pos;
1190
1191 buf = wpabuf_alloc(bss->ie_len);
1192 if (buf == NULL)
1193 return NULL;
1194
1195 pos = (const u8 *) (bss + 1);
1196 end = pos + bss->ie_len;
1197
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001198 while (end - pos > 1) {
1199 if (2 + pos[1] > end - pos)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001200 break;
1201 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1202 vendor_type == WPA_GET_BE32(&pos[2]))
1203 wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
1204 pos += 2 + pos[1];
1205 }
1206
1207 if (wpabuf_len(buf) == 0) {
1208 wpabuf_free(buf);
1209 buf = NULL;
1210 }
1211
1212 return buf;
1213}
1214
1215
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001216/**
1217 * wpa_bss_get_vendor_ie_multi_beacon - Fetch vendor IE data from a BSS entry
1218 * @bss: BSS table entry
1219 * @vendor_type: Vendor type (four octets starting the IE payload)
1220 * Returns: Pointer to the information element payload or %NULL if not found
1221 *
1222 * This function returns concatenated payload of possibly fragmented vendor
1223 * specific information elements in the BSS entry. The caller is responsible for
1224 * freeing the returned buffer.
1225 *
1226 * This function is like wpa_bss_get_vendor_ie_multi(), but uses IE buffer only
1227 * from Beacon frames instead of either Beacon or Probe Response frames.
1228 */
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -07001229struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss,
1230 u32 vendor_type)
1231{
1232 struct wpabuf *buf;
1233 const u8 *end, *pos;
1234
1235 buf = wpabuf_alloc(bss->beacon_ie_len);
1236 if (buf == NULL)
1237 return NULL;
1238
1239 pos = (const u8 *) (bss + 1);
1240 pos += bss->ie_len;
1241 end = pos + bss->beacon_ie_len;
1242
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001243 while (end - pos > 1) {
1244 if (2 + pos[1] > end - pos)
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -07001245 break;
1246 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1247 vendor_type == WPA_GET_BE32(&pos[2]))
1248 wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
1249 pos += 2 + pos[1];
1250 }
1251
1252 if (wpabuf_len(buf) == 0) {
1253 wpabuf_free(buf);
1254 buf = NULL;
1255 }
1256
1257 return buf;
1258}
1259
1260
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001261/**
1262 * wpa_bss_get_max_rate - Get maximum legacy TX rate supported in a BSS
1263 * @bss: BSS table entry
1264 * Returns: Maximum legacy rate in units of 500 kbps
1265 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001266int wpa_bss_get_max_rate(const struct wpa_bss *bss)
1267{
1268 int rate = 0;
1269 const u8 *ie;
1270 int i;
1271
1272 ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
1273 for (i = 0; ie && i < ie[1]; i++) {
1274 if ((ie[i + 2] & 0x7f) > rate)
1275 rate = ie[i + 2] & 0x7f;
1276 }
1277
1278 ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
1279 for (i = 0; ie && i < ie[1]; i++) {
1280 if ((ie[i + 2] & 0x7f) > rate)
1281 rate = ie[i + 2] & 0x7f;
1282 }
1283
1284 return rate;
1285}
1286
1287
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001288/**
1289 * wpa_bss_get_bit_rates - Get legacy TX rates supported in a BSS
1290 * @bss: BSS table entry
1291 * @rates: Buffer for returning a pointer to the rates list (units of 500 kbps)
1292 * Returns: number of legacy TX rates or -1 on failure
1293 *
1294 * The caller is responsible for freeing the returned buffer with os_free() in
1295 * case of success.
1296 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001297int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates)
1298{
1299 const u8 *ie, *ie2;
1300 int i, j;
1301 unsigned int len;
1302 u8 *r;
1303
1304 ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
1305 ie2 = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
1306
1307 len = (ie ? ie[1] : 0) + (ie2 ? ie2[1] : 0);
1308
1309 r = os_malloc(len);
1310 if (!r)
1311 return -1;
1312
1313 for (i = 0; ie && i < ie[1]; i++)
1314 r[i] = ie[i + 2] & 0x7f;
1315
1316 for (j = 0; ie2 && j < ie2[1]; j++)
1317 r[i + j] = ie2[j + 2] & 0x7f;
1318
1319 *rates = r;
1320 return len;
1321}
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001322
1323
1324#ifdef CONFIG_FILS
1325const u8 * wpa_bss_get_fils_cache_id(struct wpa_bss *bss)
1326{
1327 const u8 *ie;
1328
1329 if (bss) {
1330 ie = wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION);
1331 if (ie && ie[1] >= 4 && WPA_GET_LE16(ie + 2) & BIT(7))
1332 return ie + 4;
1333 }
1334
1335 return NULL;
1336}
1337#endif /* CONFIG_FILS */