1/*
2 * BSS table
3 * Copyright (c) 2009-2012, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
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"
15#include "wpa_supplicant_i.h"
16#include "config.h"
17#include "notify.h"
18#include "scan.h"
19#include "bss.h"
20
21
22/**
23 * WPA_BSS_EXPIRATION_PERIOD - Period of expiration run in seconds
24 */
25#define WPA_BSS_EXPIRATION_PERIOD 10
26
27#define WPA_BSS_FREQ_CHANGED_FLAG	BIT(0)
28#define WPA_BSS_SIGNAL_CHANGED_FLAG	BIT(1)
29#define WPA_BSS_PRIVACY_CHANGED_FLAG	BIT(2)
30#define WPA_BSS_MODE_CHANGED_FLAG	BIT(3)
31#define WPA_BSS_WPAIE_CHANGED_FLAG	BIT(4)
32#define WPA_BSS_RSNIE_CHANGED_FLAG	BIT(5)
33#define WPA_BSS_WPS_CHANGED_FLAG	BIT(6)
34#define WPA_BSS_RATES_CHANGED_FLAG	BIT(7)
35#define WPA_BSS_IES_CHANGED_FLAG	BIT(8)
36
37
38static void wpa_bss_set_hessid(struct wpa_bss *bss)
39{
40#ifdef CONFIG_INTERWORKING
41	const u8 *ie = wpa_bss_get_ie(bss, WLAN_EID_INTERWORKING);
42	if (ie == NULL || (ie[1] != 7 && ie[1] != 9)) {
43		os_memset(bss->hessid, 0, ETH_ALEN);
44		return;
45	}
46	if (ie[1] == 7)
47		os_memcpy(bss->hessid, ie + 3, ETH_ALEN);
48	else
49		os_memcpy(bss->hessid, ie + 5, ETH_ALEN);
50#endif /* CONFIG_INTERWORKING */
51}
52
53
54/**
55 * wpa_bss_anqp_alloc - Allocate ANQP data structure for a BSS entry
56 * Returns: Allocated ANQP data structure or %NULL on failure
57 *
58 * The allocated ANQP data structure has its users count set to 1. It may be
59 * shared by multiple BSS entries and each shared entry is freed with
60 * wpa_bss_anqp_free().
61 */
62struct wpa_bss_anqp * wpa_bss_anqp_alloc(void)
63{
64	struct wpa_bss_anqp *anqp;
65	anqp = os_zalloc(sizeof(*anqp));
66	if (anqp == NULL)
67		return NULL;
68	anqp->users = 1;
69	return anqp;
70}
71
72
73/**
74 * wpa_bss_anqp_clone - Clone an ANQP data structure
75 * @anqp: ANQP data structure from wpa_bss_anqp_alloc()
76 * Returns: Cloned ANQP data structure or %NULL on failure
77 */
78static struct wpa_bss_anqp * wpa_bss_anqp_clone(struct wpa_bss_anqp *anqp)
79{
80	struct wpa_bss_anqp *n;
81
82	n = os_zalloc(sizeof(*n));
83	if (n == NULL)
84		return NULL;
85
86#define ANQP_DUP(f) if (anqp->f) n->f = wpabuf_dup(anqp->f)
87#ifdef CONFIG_INTERWORKING
88	ANQP_DUP(venue_name);
89	ANQP_DUP(network_auth_type);
90	ANQP_DUP(roaming_consortium);
91	ANQP_DUP(ip_addr_type_availability);
92	ANQP_DUP(nai_realm);
93	ANQP_DUP(anqp_3gpp);
94	ANQP_DUP(domain_name);
95#endif /* CONFIG_INTERWORKING */
96#ifdef CONFIG_HS20
97	ANQP_DUP(hs20_operator_friendly_name);
98	ANQP_DUP(hs20_wan_metrics);
99	ANQP_DUP(hs20_connection_capability);
100	ANQP_DUP(hs20_operating_class);
101#endif /* CONFIG_HS20 */
102#undef ANQP_DUP
103
104	return n;
105}
106
107
108/**
109 * wpa_bss_anqp_unshare_alloc - Unshare ANQP data (if shared) in a BSS entry
110 * @bss: BSS entry
111 * Returns: 0 on success, -1 on failure
112 *
113 * This function ensures the specific BSS entry has an ANQP data structure that
114 * is not shared with any other BSS entry.
115 */
116int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss)
117{
118	struct wpa_bss_anqp *anqp;
119
120	if (bss->anqp && bss->anqp->users > 1) {
121		/* allocated, but shared - clone an unshared copy */
122		anqp = wpa_bss_anqp_clone(bss->anqp);
123		if (anqp == NULL)
124			return -1;
125		anqp->users = 1;
126		bss->anqp->users--;
127		bss->anqp = anqp;
128		return 0;
129	}
130
131	if (bss->anqp)
132		return 0; /* already allocated and not shared */
133
134	/* not allocated - allocate a new storage area */
135	bss->anqp = wpa_bss_anqp_alloc();
136	return bss->anqp ? 0 : -1;
137}
138
139
140/**
141 * wpa_bss_anqp_free - Free an ANQP data structure
142 * @anqp: ANQP data structure from wpa_bss_anqp_alloc() or wpa_bss_anqp_clone()
143 */
144static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
145{
146	if (anqp == NULL)
147		return;
148
149	anqp->users--;
150	if (anqp->users > 0) {
151		/* Another BSS entry holds a pointer to this ANQP info */
152		return;
153	}
154
155#ifdef CONFIG_INTERWORKING
156	wpabuf_free(anqp->venue_name);
157	wpabuf_free(anqp->network_auth_type);
158	wpabuf_free(anqp->roaming_consortium);
159	wpabuf_free(anqp->ip_addr_type_availability);
160	wpabuf_free(anqp->nai_realm);
161	wpabuf_free(anqp->anqp_3gpp);
162	wpabuf_free(anqp->domain_name);
163#endif /* CONFIG_INTERWORKING */
164#ifdef CONFIG_HS20
165	wpabuf_free(anqp->hs20_operator_friendly_name);
166	wpabuf_free(anqp->hs20_wan_metrics);
167	wpabuf_free(anqp->hs20_connection_capability);
168	wpabuf_free(anqp->hs20_operating_class);
169#endif /* CONFIG_HS20 */
170
171	os_free(anqp);
172}
173
174
175static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
176			   const char *reason)
177{
178	if (wpa_s->last_scan_res) {
179		unsigned int i;
180		for (i = 0; i < wpa_s->last_scan_res_used; i++) {
181			if (wpa_s->last_scan_res[i] == bss) {
182				os_memmove(&wpa_s->last_scan_res[i],
183					   &wpa_s->last_scan_res[i + 1],
184					   (wpa_s->last_scan_res_used - i - 1)
185					   * sizeof(struct wpa_bss *));
186				wpa_s->last_scan_res_used--;
187				break;
188			}
189		}
190	}
191	dl_list_del(&bss->list);
192	dl_list_del(&bss->list_id);
193	wpa_s->num_bss--;
194	wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Remove id %u BSSID " MACSTR
195		" SSID '%s' due to %s", bss->id, MAC2STR(bss->bssid),
196		wpa_ssid_txt(bss->ssid, bss->ssid_len), reason);
197	wpas_notify_bss_removed(wpa_s, bss->bssid, bss->id);
198	wpa_bss_anqp_free(bss->anqp);
199	os_free(bss);
200}
201
202
203/**
204 * wpa_bss_get - Fetch a BSS table entry based on BSSID and SSID
205 * @wpa_s: Pointer to wpa_supplicant data
206 * @bssid: BSSID
207 * @ssid: SSID
208 * @ssid_len: Length of @ssid
209 * Returns: Pointer to the BSS entry or %NULL if not found
210 */
211struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
212			     const u8 *ssid, size_t ssid_len)
213{
214	struct wpa_bss *bss;
215	if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
216		return NULL;
217	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
218		if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
219		    bss->ssid_len == ssid_len &&
220		    os_memcmp(bss->ssid, ssid, ssid_len) == 0)
221			return bss;
222	}
223	return NULL;
224}
225
226
227static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src)
228{
229	os_time_t usec;
230
231	dst->flags = src->flags;
232	os_memcpy(dst->bssid, src->bssid, ETH_ALEN);
233	dst->freq = src->freq;
234	dst->beacon_int = src->beacon_int;
235	dst->caps = src->caps;
236	dst->qual = src->qual;
237	dst->noise = src->noise;
238	dst->level = src->level;
239	dst->tsf = src->tsf;
240
241	os_get_time(&dst->last_update);
242	dst->last_update.sec -= src->age / 1000;
243	usec = (src->age % 1000) * 1000;
244	if (dst->last_update.usec < usec) {
245		dst->last_update.sec--;
246		dst->last_update.usec += 1000000;
247	}
248	dst->last_update.usec -= usec;
249}
250
251
252static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
253{
254	struct wpa_ssid *ssid;
255
256	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
257		if (ssid->ssid == NULL || ssid->ssid_len == 0)
258			continue;
259		if (ssid->ssid_len == bss->ssid_len &&
260		    os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) == 0)
261			return 1;
262	}
263
264	return 0;
265}
266
267
268static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
269{
270	return bss == wpa_s->current_bss ||
271		os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 ||
272		os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0;
273}
274
275
276static int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s)
277{
278	struct wpa_bss *bss;
279
280	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
281		if (!wpa_bss_known(wpa_s, bss)) {
282			wpa_bss_remove(wpa_s, bss, __func__);
283			return 0;
284		}
285	}
286
287	return -1;
288}
289
290
291static int wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s)
292{
293	struct wpa_bss *bss;
294
295	/*
296	 * Remove the oldest entry that does not match with any configured
297	 * network.
298	 */
299	if (wpa_bss_remove_oldest_unknown(wpa_s) == 0)
300		return 0;
301
302	/*
303	 * Remove the oldest entry that isn't currently in use.
304	 */
305	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
306		if (!wpa_bss_in_use(wpa_s, bss)) {
307			wpa_bss_remove(wpa_s, bss, __func__);
308			return 0;
309		}
310	}
311
312	return -1;
313}
314
315
316static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s,
317				    const u8 *ssid, size_t ssid_len,
318				    struct wpa_scan_res *res)
319{
320	struct wpa_bss *bss;
321
322	bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len);
323	if (bss == NULL)
324		return NULL;
325	bss->id = wpa_s->bss_next_id++;
326	bss->last_update_idx = wpa_s->bss_update_idx;
327	wpa_bss_copy_res(bss, res);
328	os_memcpy(bss->ssid, ssid, ssid_len);
329	bss->ssid_len = ssid_len;
330	bss->ie_len = res->ie_len;
331	bss->beacon_ie_len = res->beacon_ie_len;
332	os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
333	wpa_bss_set_hessid(bss);
334
335	dl_list_add_tail(&wpa_s->bss, &bss->list);
336	dl_list_add_tail(&wpa_s->bss_id, &bss->list_id);
337	wpa_s->num_bss++;
338	wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Add new id %u BSSID " MACSTR
339		" SSID '%s'",
340		bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len));
341	wpas_notify_bss_added(wpa_s, bss->bssid, bss->id);
342	if (wpa_s->num_bss > wpa_s->conf->bss_max_count &&
343	    wpa_bss_remove_oldest(wpa_s) != 0) {
344		wpa_printf(MSG_ERROR, "Increasing the MAX BSS count to %d "
345			   "because all BSSes are in use. We should normally "
346			   "not get here!", (int) wpa_s->num_bss);
347		wpa_s->conf->bss_max_count = wpa_s->num_bss;
348	}
349	return bss;
350}
351
352
353static int are_ies_equal(const struct wpa_bss *old,
354			 const struct wpa_scan_res *new, u32 ie)
355{
356	const u8 *old_ie, *new_ie;
357	struct wpabuf *old_ie_buff = NULL;
358	struct wpabuf *new_ie_buff = NULL;
359	int new_ie_len, old_ie_len, ret, is_multi;
360
361	switch (ie) {
362	case WPA_IE_VENDOR_TYPE:
363		old_ie = wpa_bss_get_vendor_ie(old, ie);
364		new_ie = wpa_scan_get_vendor_ie(new, ie);
365		is_multi = 0;
366		break;
367	case WPS_IE_VENDOR_TYPE:
368		old_ie_buff = wpa_bss_get_vendor_ie_multi(old, ie);
369		new_ie_buff = wpa_scan_get_vendor_ie_multi(new, ie);
370		is_multi = 1;
371		break;
372	case WLAN_EID_RSN:
373	case WLAN_EID_SUPP_RATES:
374	case WLAN_EID_EXT_SUPP_RATES:
375		old_ie = wpa_bss_get_ie(old, ie);
376		new_ie = wpa_scan_get_ie(new, ie);
377		is_multi = 0;
378		break;
379	default:
380		wpa_printf(MSG_DEBUG, "bss: %s: cannot compare IEs", __func__);
381		return 0;
382	}
383
384	if (is_multi) {
385		/* in case of multiple IEs stored in buffer */
386		old_ie = old_ie_buff ? wpabuf_head_u8(old_ie_buff) : NULL;
387		new_ie = new_ie_buff ? wpabuf_head_u8(new_ie_buff) : NULL;
388		old_ie_len = old_ie_buff ? wpabuf_len(old_ie_buff) : 0;
389		new_ie_len = new_ie_buff ? wpabuf_len(new_ie_buff) : 0;
390	} else {
391		/* in case of single IE */
392		old_ie_len = old_ie ? old_ie[1] + 2 : 0;
393		new_ie_len = new_ie ? new_ie[1] + 2 : 0;
394	}
395
396	if (!old_ie || !new_ie)
397		ret = !old_ie && !new_ie;
398	else
399		ret = (old_ie_len == new_ie_len &&
400		       os_memcmp(old_ie, new_ie, old_ie_len) == 0);
401
402	wpabuf_free(old_ie_buff);
403	wpabuf_free(new_ie_buff);
404
405	return ret;
406}
407
408
409static u32 wpa_bss_compare_res(const struct wpa_bss *old,
410			       const struct wpa_scan_res *new)
411{
412	u32 changes = 0;
413	int caps_diff = old->caps ^ new->caps;
414
415	if (old->freq != new->freq)
416		changes |= WPA_BSS_FREQ_CHANGED_FLAG;
417
418	if (old->level != new->level)
419		changes |= WPA_BSS_SIGNAL_CHANGED_FLAG;
420
421	if (caps_diff & IEEE80211_CAP_PRIVACY)
422		changes |= WPA_BSS_PRIVACY_CHANGED_FLAG;
423
424	if (caps_diff & IEEE80211_CAP_IBSS)
425		changes |= WPA_BSS_MODE_CHANGED_FLAG;
426
427	if (old->ie_len == new->ie_len &&
428	    os_memcmp(old + 1, new + 1, old->ie_len) == 0)
429		return changes;
430	changes |= WPA_BSS_IES_CHANGED_FLAG;
431
432	if (!are_ies_equal(old, new, WPA_IE_VENDOR_TYPE))
433		changes |= WPA_BSS_WPAIE_CHANGED_FLAG;
434
435	if (!are_ies_equal(old, new, WLAN_EID_RSN))
436		changes |= WPA_BSS_RSNIE_CHANGED_FLAG;
437
438	if (!are_ies_equal(old, new, WPS_IE_VENDOR_TYPE))
439		changes |= WPA_BSS_WPS_CHANGED_FLAG;
440
441	if (!are_ies_equal(old, new, WLAN_EID_SUPP_RATES) ||
442	    !are_ies_equal(old, new, WLAN_EID_EXT_SUPP_RATES))
443		changes |= WPA_BSS_RATES_CHANGED_FLAG;
444
445	return changes;
446}
447
448
449static void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
450			       const struct wpa_bss *bss)
451{
452	if (changes & WPA_BSS_FREQ_CHANGED_FLAG)
453		wpas_notify_bss_freq_changed(wpa_s, bss->id);
454
455	if (changes & WPA_BSS_SIGNAL_CHANGED_FLAG)
456		wpas_notify_bss_signal_changed(wpa_s, bss->id);
457
458	if (changes & WPA_BSS_PRIVACY_CHANGED_FLAG)
459		wpas_notify_bss_privacy_changed(wpa_s, bss->id);
460
461	if (changes & WPA_BSS_MODE_CHANGED_FLAG)
462		wpas_notify_bss_mode_changed(wpa_s, bss->id);
463
464	if (changes & WPA_BSS_WPAIE_CHANGED_FLAG)
465		wpas_notify_bss_wpaie_changed(wpa_s, bss->id);
466
467	if (changes & WPA_BSS_RSNIE_CHANGED_FLAG)
468		wpas_notify_bss_rsnie_changed(wpa_s, bss->id);
469
470	if (changes & WPA_BSS_WPS_CHANGED_FLAG)
471		wpas_notify_bss_wps_changed(wpa_s, bss->id);
472
473	if (changes & WPA_BSS_IES_CHANGED_FLAG)
474		wpas_notify_bss_ies_changed(wpa_s, bss->id);
475
476	if (changes & WPA_BSS_RATES_CHANGED_FLAG)
477		wpas_notify_bss_rates_changed(wpa_s, bss->id);
478}
479
480
481static struct wpa_bss *
482wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
483	       struct wpa_scan_res *res)
484{
485	u32 changes;
486
487	changes = wpa_bss_compare_res(bss, res);
488	bss->scan_miss_count = 0;
489	bss->last_update_idx = wpa_s->bss_update_idx;
490	wpa_bss_copy_res(bss, res);
491	/* Move the entry to the end of the list */
492	dl_list_del(&bss->list);
493	if (bss->ie_len + bss->beacon_ie_len >=
494	    res->ie_len + res->beacon_ie_len) {
495		os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
496		bss->ie_len = res->ie_len;
497		bss->beacon_ie_len = res->beacon_ie_len;
498	} else {
499		struct wpa_bss *nbss;
500		struct dl_list *prev = bss->list_id.prev;
501		dl_list_del(&bss->list_id);
502		nbss = os_realloc(bss, sizeof(*bss) + res->ie_len +
503				  res->beacon_ie_len);
504		if (nbss) {
505			unsigned int i;
506			for (i = 0; i < wpa_s->last_scan_res_used; i++) {
507				if (wpa_s->last_scan_res[i] == bss) {
508					wpa_s->last_scan_res[i] = nbss;
509					break;
510				}
511			}
512			if (wpa_s->current_bss == bss)
513				wpa_s->current_bss = nbss;
514			bss = nbss;
515			os_memcpy(bss + 1, res + 1,
516				  res->ie_len + res->beacon_ie_len);
517			bss->ie_len = res->ie_len;
518			bss->beacon_ie_len = res->beacon_ie_len;
519		}
520		dl_list_add(prev, &bss->list_id);
521	}
522	if (changes & WPA_BSS_IES_CHANGED_FLAG)
523		wpa_bss_set_hessid(bss);
524	dl_list_add_tail(&wpa_s->bss, &bss->list);
525
526	notify_bss_changes(wpa_s, changes, bss);
527
528	return bss;
529}
530
531
532/**
533 * wpa_bss_update_start - Start a BSS table update from scan results
534 * @wpa_s: Pointer to wpa_supplicant data
535 *
536 * This function is called at the start of each BSS table update round for new
537 * scan results. The actual scan result entries are indicated with calls to
538 * wpa_bss_update_scan_res() and the update round is finished with a call to
539 * wpa_bss_update_end().
540 */
541void wpa_bss_update_start(struct wpa_supplicant *wpa_s)
542{
543	wpa_s->bss_update_idx++;
544	wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Start scan result update %u",
545		wpa_s->bss_update_idx);
546	wpa_s->last_scan_res_used = 0;
547}
548
549
550/**
551 * wpa_bss_update_scan_res - Update a BSS table entry based on a scan result
552 * @wpa_s: Pointer to wpa_supplicant data
553 * @res: Scan result
554 *
555 * This function updates a BSS table entry (or adds one) based on a scan result.
556 * This is called separately for each scan result between the calls to
557 * wpa_bss_update_start() and wpa_bss_update_end().
558 */
559void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
560			     struct wpa_scan_res *res)
561{
562	const u8 *ssid, *p2p;
563	struct wpa_bss *bss;
564
565	ssid = wpa_scan_get_ie(res, WLAN_EID_SSID);
566	if (ssid == NULL) {
567		wpa_dbg(wpa_s, MSG_DEBUG, "BSS: No SSID IE included for "
568			MACSTR, MAC2STR(res->bssid));
569		return;
570	}
571	if (ssid[1] > 32) {
572		wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Too long SSID IE included for "
573			MACSTR, MAC2STR(res->bssid));
574		return;
575	}
576
577	p2p = wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE);
578#ifdef CONFIG_P2P
579	if (p2p == NULL &&
580	    wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
581		/*
582		 * If it's a P2P specific interface, then don't update
583		 * the scan result without a P2P IE.
584		 */
585		wpa_printf(MSG_DEBUG, "BSS: No P2P IE - skipping BSS " MACSTR
586			   " update for P2P interface", MAC2STR(res->bssid));
587		return;
588	}
589#endif /* CONFIG_P2P */
590	if (p2p && ssid[1] == P2P_WILDCARD_SSID_LEN &&
591	    os_memcmp(ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 0)
592		return; /* Skip P2P listen discovery results here */
593
594	/* TODO: add option for ignoring BSSes we are not interested in
595	 * (to save memory) */
596	bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
597	if (bss == NULL)
598		bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res);
599	else
600		bss = wpa_bss_update(wpa_s, bss, res);
601
602	if (bss == NULL)
603		return;
604	if (wpa_s->last_scan_res_used >= wpa_s->last_scan_res_size) {
605		struct wpa_bss **n;
606		unsigned int siz;
607		if (wpa_s->last_scan_res_size == 0)
608			siz = 32;
609		else
610			siz = wpa_s->last_scan_res_size * 2;
611		n = os_realloc_array(wpa_s->last_scan_res, siz,
612				     sizeof(struct wpa_bss *));
613		if (n == NULL)
614			return;
615		wpa_s->last_scan_res = n;
616		wpa_s->last_scan_res_size = siz;
617	}
618
619	wpa_s->last_scan_res[wpa_s->last_scan_res_used++] = bss;
620}
621
622
623static int wpa_bss_included_in_scan(const struct wpa_bss *bss,
624				    const struct scan_info *info)
625{
626	int found;
627	size_t i;
628
629	if (info == NULL)
630		return 1;
631
632	if (info->num_freqs) {
633		found = 0;
634		for (i = 0; i < info->num_freqs; i++) {
635			if (bss->freq == info->freqs[i]) {
636				found = 1;
637				break;
638			}
639		}
640		if (!found)
641			return 0;
642	}
643
644	if (info->num_ssids) {
645		found = 0;
646		for (i = 0; i < info->num_ssids; i++) {
647			const struct wpa_driver_scan_ssid *s = &info->ssids[i];
648			if ((s->ssid == NULL || s->ssid_len == 0) ||
649			    (s->ssid_len == bss->ssid_len &&
650			     os_memcmp(s->ssid, bss->ssid, bss->ssid_len) ==
651			     0)) {
652				found = 1;
653				break;
654			}
655		}
656		if (!found)
657			return 0;
658	}
659
660	return 1;
661}
662
663
664/**
665 * wpa_bss_update_end - End a BSS table update from scan results
666 * @wpa_s: Pointer to wpa_supplicant data
667 * @info: Information about scan parameters
668 * @new_scan: Whether this update round was based on a new scan
669 *
670 * This function is called at the end of each BSS table update round for new
671 * scan results. The start of the update was indicated with a call to
672 * wpa_bss_update_start().
673 */
674void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
675			int new_scan)
676{
677	struct wpa_bss *bss, *n;
678
679	wpa_s->last_scan_full = 0;
680	os_get_time(&wpa_s->last_scan);
681	if (!new_scan)
682		return; /* do not expire entries without new scan */
683
684	if (info && !info->aborted && !info->freqs) {
685		size_t i;
686		if (info->num_ssids == 0) {
687			wpa_s->last_scan_full = 1;
688		} else {
689			for (i = 0; i < info->num_ssids; i++) {
690				if (info->ssids[i].ssid == NULL ||
691				    info->ssids[i].ssid_len == 0) {
692					wpa_s->last_scan_full = 1;
693					break;
694				}
695			}
696		}
697	}
698
699	dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
700		if (wpa_bss_in_use(wpa_s, bss))
701			continue;
702		if (!wpa_bss_included_in_scan(bss, info))
703			continue; /* expire only BSSes that were scanned */
704		if (bss->last_update_idx < wpa_s->bss_update_idx)
705			bss->scan_miss_count++;
706		if (bss->scan_miss_count >=
707		    wpa_s->conf->bss_expiration_scan_count) {
708			wpa_bss_remove(wpa_s, bss, "no match in scan");
709		}
710	}
711
712	wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%u/%u "
713		   "last_scan_full=%d",
714		   wpa_s->last_scan_res_used, wpa_s->last_scan_res_size,
715		   wpa_s->last_scan_full);
716}
717
718
719/**
720 * wpa_bss_flush_by_age - Flush old BSS entries
721 * @wpa_s: Pointer to wpa_supplicant data
722 * @age: Maximum entry age in seconds
723 *
724 * Remove BSS entries that have not been updated during the last @age seconds.
725 */
726void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age)
727{
728	struct wpa_bss *bss, *n;
729	struct os_time t;
730
731	if (dl_list_empty(&wpa_s->bss))
732		return;
733
734	os_get_time(&t);
735	t.sec -= age;
736
737	dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
738		if (wpa_bss_in_use(wpa_s, bss))
739			continue;
740
741		if (os_time_before(&bss->last_update, &t)) {
742			wpa_bss_remove(wpa_s, bss, __func__);
743		} else
744			break;
745	}
746}
747
748
749static void wpa_bss_timeout(void *eloop_ctx, void *timeout_ctx)
750{
751	struct wpa_supplicant *wpa_s = eloop_ctx;
752
753	wpa_bss_flush_by_age(wpa_s, wpa_s->conf->bss_expiration_age);
754	eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0,
755			       wpa_bss_timeout, wpa_s, NULL);
756}
757
758
759/**
760 * wpa_bss_init - Initialize BSS table
761 * @wpa_s: Pointer to wpa_supplicant data
762 * Returns: 0 on success, -1 on failure
763 *
764 * This prepares BSS table lists and timer for periodic updates. The BSS table
765 * is deinitialized with wpa_bss_deinit() once not needed anymore.
766 */
767int wpa_bss_init(struct wpa_supplicant *wpa_s)
768{
769	dl_list_init(&wpa_s->bss);
770	dl_list_init(&wpa_s->bss_id);
771	eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0,
772			       wpa_bss_timeout, wpa_s, NULL);
773	return 0;
774}
775
776
777/**
778 * wpa_bss_flush - Flush all unused BSS entries
779 * @wpa_s: Pointer to wpa_supplicant data
780 */
781void wpa_bss_flush(struct wpa_supplicant *wpa_s)
782{
783	struct wpa_bss *bss, *n;
784
785	if (wpa_s->bss.next == NULL)
786		return; /* BSS table not yet initialized */
787
788	dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
789		if (wpa_bss_in_use(wpa_s, bss))
790			continue;
791		wpa_bss_remove(wpa_s, bss, __func__);
792	}
793}
794
795
796/**
797 * wpa_bss_deinit - Deinitialize BSS table
798 * @wpa_s: Pointer to wpa_supplicant data
799 */
800void wpa_bss_deinit(struct wpa_supplicant *wpa_s)
801{
802	eloop_cancel_timeout(wpa_bss_timeout, wpa_s, NULL);
803	wpa_bss_flush(wpa_s);
804}
805
806
807/**
808 * wpa_bss_get_bssid - Fetch a BSS table entry based on BSSID
809 * @wpa_s: Pointer to wpa_supplicant data
810 * @bssid: BSSID
811 * Returns: Pointer to the BSS entry or %NULL if not found
812 */
813struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
814				   const u8 *bssid)
815{
816	struct wpa_bss *bss;
817	if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
818		return NULL;
819	dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
820		if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
821			return bss;
822	}
823	return NULL;
824}
825
826
827#ifdef CONFIG_P2P
828/**
829 * wpa_bss_get_p2p_dev_addr - Fetch a BSS table entry based on P2P Device Addr
830 * @wpa_s: Pointer to wpa_supplicant data
831 * @dev_addr: P2P Device Address of the GO
832 * Returns: Pointer to the BSS entry or %NULL if not found
833 */
834struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s,
835					  const u8 *dev_addr)
836{
837	struct wpa_bss *bss;
838	dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
839		u8 addr[ETH_ALEN];
840		if (p2p_parse_dev_addr((const u8 *) (bss + 1), bss->ie_len,
841				       addr) == 0 &&
842		    os_memcmp(addr, dev_addr, ETH_ALEN) == 0)
843			return bss;
844	}
845	return NULL;
846}
847#endif /* CONFIG_P2P */
848
849
850/**
851 * wpa_bss_get_id - Fetch a BSS table entry based on identifier
852 * @wpa_s: Pointer to wpa_supplicant data
853 * @id: Unique identifier (struct wpa_bss::id) assigned for the entry
854 * Returns: Pointer to the BSS entry or %NULL if not found
855 */
856struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id)
857{
858	struct wpa_bss *bss;
859	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
860		if (bss->id == id)
861			return bss;
862	}
863	return NULL;
864}
865
866
867/**
868 * wpa_bss_get_ie - Fetch a specified information element from a BSS entry
869 * @bss: BSS table entry
870 * @ie: Information element identitifier (WLAN_EID_*)
871 * Returns: Pointer to the information element (id field) or %NULL if not found
872 *
873 * This function returns the first matching information element in the BSS
874 * entry.
875 */
876const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
877{
878	const u8 *end, *pos;
879
880	pos = (const u8 *) (bss + 1);
881	end = pos + bss->ie_len;
882
883	while (pos + 1 < end) {
884		if (pos + 2 + pos[1] > end)
885			break;
886		if (pos[0] == ie)
887			return pos;
888		pos += 2 + pos[1];
889	}
890
891	return NULL;
892}
893
894
895/**
896 * wpa_bss_get_vendor_ie - Fetch a vendor information element from a BSS entry
897 * @bss: BSS table entry
898 * @vendor_type: Vendor type (four octets starting the IE payload)
899 * Returns: Pointer to the information element (id field) or %NULL if not found
900 *
901 * This function returns the first matching information element in the BSS
902 * entry.
903 */
904const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
905{
906	const u8 *end, *pos;
907
908	pos = (const u8 *) (bss + 1);
909	end = pos + bss->ie_len;
910
911	while (pos + 1 < end) {
912		if (pos + 2 + pos[1] > end)
913			break;
914		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
915		    vendor_type == WPA_GET_BE32(&pos[2]))
916			return pos;
917		pos += 2 + pos[1];
918	}
919
920	return NULL;
921}
922
923
924/**
925 * wpa_bss_get_vendor_ie_multi - Fetch vendor IE data from a BSS entry
926 * @bss: BSS table entry
927 * @vendor_type: Vendor type (four octets starting the IE payload)
928 * Returns: Pointer to the information element payload or %NULL if not found
929 *
930 * This function returns concatenated payload of possibly fragmented vendor
931 * specific information elements in the BSS entry. The caller is responsible for
932 * freeing the returned buffer.
933 */
934struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
935					    u32 vendor_type)
936{
937	struct wpabuf *buf;
938	const u8 *end, *pos;
939
940	buf = wpabuf_alloc(bss->ie_len);
941	if (buf == NULL)
942		return NULL;
943
944	pos = (const u8 *) (bss + 1);
945	end = pos + bss->ie_len;
946
947	while (pos + 1 < end) {
948		if (pos + 2 + pos[1] > end)
949			break;
950		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
951		    vendor_type == WPA_GET_BE32(&pos[2]))
952			wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
953		pos += 2 + pos[1];
954	}
955
956	if (wpabuf_len(buf) == 0) {
957		wpabuf_free(buf);
958		buf = NULL;
959	}
960
961	return buf;
962}
963
964
965/**
966 * wpa_bss_get_vendor_ie_multi_beacon - Fetch vendor IE data from a BSS entry
967 * @bss: BSS table entry
968 * @vendor_type: Vendor type (four octets starting the IE payload)
969 * Returns: Pointer to the information element payload or %NULL if not found
970 *
971 * This function returns concatenated payload of possibly fragmented vendor
972 * specific information elements in the BSS entry. The caller is responsible for
973 * freeing the returned buffer.
974 *
975 * This function is like wpa_bss_get_vendor_ie_multi(), but uses IE buffer only
976 * from Beacon frames instead of either Beacon or Probe Response frames.
977 */
978struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss,
979						   u32 vendor_type)
980{
981	struct wpabuf *buf;
982	const u8 *end, *pos;
983
984	buf = wpabuf_alloc(bss->beacon_ie_len);
985	if (buf == NULL)
986		return NULL;
987
988	pos = (const u8 *) (bss + 1);
989	pos += bss->ie_len;
990	end = pos + bss->beacon_ie_len;
991
992	while (pos + 1 < end) {
993		if (pos + 2 + pos[1] > end)
994			break;
995		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
996		    vendor_type == WPA_GET_BE32(&pos[2]))
997			wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
998		pos += 2 + pos[1];
999	}
1000
1001	if (wpabuf_len(buf) == 0) {
1002		wpabuf_free(buf);
1003		buf = NULL;
1004	}
1005
1006	return buf;
1007}
1008
1009
1010/**
1011 * wpa_bss_get_max_rate - Get maximum legacy TX rate supported in a BSS
1012 * @bss: BSS table entry
1013 * Returns: Maximum legacy rate in units of 500 kbps
1014 */
1015int wpa_bss_get_max_rate(const struct wpa_bss *bss)
1016{
1017	int rate = 0;
1018	const u8 *ie;
1019	int i;
1020
1021	ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
1022	for (i = 0; ie && i < ie[1]; i++) {
1023		if ((ie[i + 2] & 0x7f) > rate)
1024			rate = ie[i + 2] & 0x7f;
1025	}
1026
1027	ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
1028	for (i = 0; ie && i < ie[1]; i++) {
1029		if ((ie[i + 2] & 0x7f) > rate)
1030			rate = ie[i + 2] & 0x7f;
1031	}
1032
1033	return rate;
1034}
1035
1036
1037/**
1038 * wpa_bss_get_bit_rates - Get legacy TX rates supported in a BSS
1039 * @bss: BSS table entry
1040 * @rates: Buffer for returning a pointer to the rates list (units of 500 kbps)
1041 * Returns: number of legacy TX rates or -1 on failure
1042 *
1043 * The caller is responsible for freeing the returned buffer with os_free() in
1044 * case of success.
1045 */
1046int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates)
1047{
1048	const u8 *ie, *ie2;
1049	int i, j;
1050	unsigned int len;
1051	u8 *r;
1052
1053	ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
1054	ie2 = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
1055
1056	len = (ie ? ie[1] : 0) + (ie2 ? ie2[1] : 0);
1057
1058	r = os_malloc(len);
1059	if (!r)
1060		return -1;
1061
1062	for (i = 0; ie && i < ie[1]; i++)
1063		r[i] = ie[i + 2] & 0x7f;
1064
1065	for (j = 0; ie2 && j < ie2[1]; j++)
1066		r[i + j] = ie2[j + 2] & 0x7f;
1067
1068	*rates = r;
1069	return len;
1070}
1071