18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * BSS table
37f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt * Copyright (c) 2009-2015, Jouni Malinen <j@w1.fi>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details.
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/includes.h"
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/common.h"
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/eloop.h"
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common/ieee802_11_defs.h"
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "drivers/driver.h"
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wpa_supplicant_i.h"
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "config.h"
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "notify.h"
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "scan.h"
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "bss.h"
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * WPA_BSS_EXPIRATION_PERIOD - Period of expiration run in seconds
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define WPA_BSS_EXPIRATION_PERIOD 10
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define WPA_BSS_FREQ_CHANGED_FLAG	BIT(0)
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define WPA_BSS_SIGNAL_CHANGED_FLAG	BIT(1)
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define WPA_BSS_PRIVACY_CHANGED_FLAG	BIT(2)
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define WPA_BSS_MODE_CHANGED_FLAG	BIT(3)
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define WPA_BSS_WPAIE_CHANGED_FLAG	BIT(4)
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define WPA_BSS_RSNIE_CHANGED_FLAG	BIT(5)
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define WPA_BSS_WPS_CHANGED_FLAG	BIT(6)
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define WPA_BSS_RATES_CHANGED_FLAG	BIT(7)
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define WPA_BSS_IES_CHANGED_FLAG	BIT(8)
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
384530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidtstatic void wpa_bss_set_hessid(struct wpa_bss *bss)
394530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt{
404530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt#ifdef CONFIG_INTERWORKING
414530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	const u8 *ie = wpa_bss_get_ie(bss, WLAN_EID_INTERWORKING);
424530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (ie == NULL || (ie[1] != 7 && ie[1] != 9)) {
434530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		os_memset(bss->hessid, 0, ETH_ALEN);
444530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		return;
454530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	}
464530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (ie[1] == 7)
474530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		os_memcpy(bss->hessid, ie + 3, ETH_ALEN);
484530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	else
494530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		os_memcpy(bss->hessid, ie + 5, ETH_ALEN);
504530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt#endif /* CONFIG_INTERWORKING */
514530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt}
524530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
534530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
54a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt/**
55a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * wpa_bss_anqp_alloc - Allocate ANQP data structure for a BSS entry
56a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * Returns: Allocated ANQP data structure or %NULL on failure
57a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt *
58a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * The allocated ANQP data structure has its users count set to 1. It may be
59a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * shared by multiple BSS entries and each shared entry is freed with
60a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * wpa_bss_anqp_free().
61a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt */
624530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidtstruct wpa_bss_anqp * wpa_bss_anqp_alloc(void)
634530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt{
644530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	struct wpa_bss_anqp *anqp;
654530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	anqp = os_zalloc(sizeof(*anqp));
664530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (anqp == NULL)
674530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		return NULL;
684530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	anqp->users = 1;
694530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	return anqp;
704530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt}
714530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
724530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
73a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt/**
74a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * wpa_bss_anqp_clone - Clone an ANQP data structure
75a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @anqp: ANQP data structure from wpa_bss_anqp_alloc()
76a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * Returns: Cloned ANQP data structure or %NULL on failure
77a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt */
78d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidtstatic struct wpa_bss_anqp * wpa_bss_anqp_clone(struct wpa_bss_anqp *anqp)
79d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt{
80d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	struct wpa_bss_anqp *n;
81d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
82d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	n = os_zalloc(sizeof(*n));
83d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	if (n == NULL)
84d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		return NULL;
85d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
86d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt#define ANQP_DUP(f) if (anqp->f) n->f = wpabuf_dup(anqp->f)
87d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt#ifdef CONFIG_INTERWORKING
887f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	ANQP_DUP(capability_list);
89d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	ANQP_DUP(venue_name);
90d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	ANQP_DUP(network_auth_type);
91d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	ANQP_DUP(roaming_consortium);
92d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	ANQP_DUP(ip_addr_type_availability);
93d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	ANQP_DUP(nai_realm);
94d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	ANQP_DUP(anqp_3gpp);
95d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	ANQP_DUP(domain_name);
96d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt#endif /* CONFIG_INTERWORKING */
97d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt#ifdef CONFIG_HS20
987f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	ANQP_DUP(hs20_capability_list);
99d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	ANQP_DUP(hs20_operator_friendly_name);
100d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	ANQP_DUP(hs20_wan_metrics);
101d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	ANQP_DUP(hs20_connection_capability);
102d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	ANQP_DUP(hs20_operating_class);
103f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	ANQP_DUP(hs20_osu_providers_list);
104d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt#endif /* CONFIG_HS20 */
105d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt#undef ANQP_DUP
106d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
107d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	return n;
108d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt}
109d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
110d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
111a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt/**
112a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * wpa_bss_anqp_unshare_alloc - Unshare ANQP data (if shared) in a BSS entry
113a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @bss: BSS entry
114a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * Returns: 0 on success, -1 on failure
115a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt *
116a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * This function ensures the specific BSS entry has an ANQP data structure that
117a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * is not shared with any other BSS entry.
118a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt */
119d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidtint wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss)
120d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt{
121d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	struct wpa_bss_anqp *anqp;
122d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
123d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	if (bss->anqp && bss->anqp->users > 1) {
124d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		/* allocated, but shared - clone an unshared copy */
125d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		anqp = wpa_bss_anqp_clone(bss->anqp);
126d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		if (anqp == NULL)
127d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			return -1;
128d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		anqp->users = 1;
129d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		bss->anqp->users--;
130d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		bss->anqp = anqp;
131d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		return 0;
132d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	}
133d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
134d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	if (bss->anqp)
135d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		return 0; /* already allocated and not shared */
136d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
137d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	/* not allocated - allocate a new storage area */
138d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	bss->anqp = wpa_bss_anqp_alloc();
139d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	return bss->anqp ? 0 : -1;
140d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt}
141d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
142d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
143a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt/**
144a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * wpa_bss_anqp_free - Free an ANQP data structure
145a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @anqp: ANQP data structure from wpa_bss_anqp_alloc() or wpa_bss_anqp_clone()
146a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt */
1474530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidtstatic void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
1484530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt{
1494530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (anqp == NULL)
1504530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		return;
1514530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
1524530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	anqp->users--;
1534530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (anqp->users > 0) {
1544530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		/* Another BSS entry holds a pointer to this ANQP info */
1554530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		return;
1564530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	}
1574530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
1584530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt#ifdef CONFIG_INTERWORKING
1597f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	wpabuf_free(anqp->capability_list);
1604530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	wpabuf_free(anqp->venue_name);
1614530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	wpabuf_free(anqp->network_auth_type);
1624530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	wpabuf_free(anqp->roaming_consortium);
1634530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	wpabuf_free(anqp->ip_addr_type_availability);
1644530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	wpabuf_free(anqp->nai_realm);
1654530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	wpabuf_free(anqp->anqp_3gpp);
1664530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	wpabuf_free(anqp->domain_name);
1674530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt#endif /* CONFIG_INTERWORKING */
1684530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt#ifdef CONFIG_HS20
1697f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	wpabuf_free(anqp->hs20_capability_list);
1704530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	wpabuf_free(anqp->hs20_operator_friendly_name);
1714530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	wpabuf_free(anqp->hs20_wan_metrics);
1724530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	wpabuf_free(anqp->hs20_connection_capability);
1734530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	wpabuf_free(anqp->hs20_operating_class);
174f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	wpabuf_free(anqp->hs20_osu_providers_list);
1754530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt#endif /* CONFIG_HS20 */
1764530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
1774530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	os_free(anqp);
1784530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt}
1794530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
1804530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
1812e425d69801667e42b4874548f2a49dc16e95617Dmitry Shmidtstatic void wpa_bss_update_pending_connect(struct wpa_supplicant *wpa_s,
1822e425d69801667e42b4874548f2a49dc16e95617Dmitry Shmidt					   struct wpa_bss *old_bss,
1832e425d69801667e42b4874548f2a49dc16e95617Dmitry Shmidt					   struct wpa_bss *new_bss)
1842e425d69801667e42b4874548f2a49dc16e95617Dmitry Shmidt{
1852e425d69801667e42b4874548f2a49dc16e95617Dmitry Shmidt	struct wpa_radio_work *work;
1862e425d69801667e42b4874548f2a49dc16e95617Dmitry Shmidt	struct wpa_connect_work *cwork;
1872e425d69801667e42b4874548f2a49dc16e95617Dmitry Shmidt
1882e425d69801667e42b4874548f2a49dc16e95617Dmitry Shmidt	work = radio_work_pending(wpa_s, "sme-connect");
1892e425d69801667e42b4874548f2a49dc16e95617Dmitry Shmidt	if (!work)
1902e425d69801667e42b4874548f2a49dc16e95617Dmitry Shmidt		work = radio_work_pending(wpa_s, "connect");
1912e425d69801667e42b4874548f2a49dc16e95617Dmitry Shmidt	if (!work)
1922e425d69801667e42b4874548f2a49dc16e95617Dmitry Shmidt		return;
1932e425d69801667e42b4874548f2a49dc16e95617Dmitry Shmidt
1942e425d69801667e42b4874548f2a49dc16e95617Dmitry Shmidt	cwork = work->ctx;
1952e425d69801667e42b4874548f2a49dc16e95617Dmitry Shmidt	if (cwork->bss != old_bss)
1962e425d69801667e42b4874548f2a49dc16e95617Dmitry Shmidt		return;
1972e425d69801667e42b4874548f2a49dc16e95617Dmitry Shmidt
1982e425d69801667e42b4874548f2a49dc16e95617Dmitry Shmidt	wpa_printf(MSG_DEBUG,
1992e425d69801667e42b4874548f2a49dc16e95617Dmitry Shmidt		   "Update BSS pointer for the pending connect radio work");
2002e425d69801667e42b4874548f2a49dc16e95617Dmitry Shmidt	cwork->bss = new_bss;
2012e425d69801667e42b4874548f2a49dc16e95617Dmitry Shmidt	if (!new_bss)
2022e425d69801667e42b4874548f2a49dc16e95617Dmitry Shmidt		cwork->bss_removed = 1;
2032e425d69801667e42b4874548f2a49dc16e95617Dmitry Shmidt}
2042e425d69801667e42b4874548f2a49dc16e95617Dmitry Shmidt
2052e425d69801667e42b4874548f2a49dc16e95617Dmitry Shmidt
20604949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
20704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			   const char *reason)
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2099bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt	if (wpa_s->last_scan_res) {
2109bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt		unsigned int i;
2119bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt		for (i = 0; i < wpa_s->last_scan_res_used; i++) {
2129bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt			if (wpa_s->last_scan_res[i] == bss) {
2139bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt				os_memmove(&wpa_s->last_scan_res[i],
2149bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt					   &wpa_s->last_scan_res[i + 1],
2159bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt					   (wpa_s->last_scan_res_used - i - 1)
2169bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt					   * sizeof(struct wpa_bss *));
2179bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt				wpa_s->last_scan_res_used--;
2189bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt				break;
2199bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt			}
2209bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt		}
2219bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt	}
2222e425d69801667e42b4874548f2a49dc16e95617Dmitry Shmidt	wpa_bss_update_pending_connect(wpa_s, bss, NULL);
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_del(&bss->list);
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_del(&bss->list_id);
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_s->num_bss--;
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Remove id %u BSSID " MACSTR
22704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		" SSID '%s' due to %s", bss->id, MAC2STR(bss->bssid),
22804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpa_ssid_txt(bss->ssid, bss->ssid_len), reason);
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpas_notify_bss_removed(wpa_s, bss->bssid, bss->id);
2304530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	wpa_bss_anqp_free(bss->anqp);
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(bss);
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
235a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt/**
236a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * wpa_bss_get - Fetch a BSS table entry based on BSSID and SSID
237a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @wpa_s: Pointer to wpa_supplicant data
238a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @bssid: BSSID
239a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @ssid: SSID
240a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @ssid_len: Length of @ssid
241a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * Returns: Pointer to the BSS entry or %NULL if not found
242a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt */
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     const u8 *ssid, size_t ssid_len)
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_bss *bss;
24704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
24804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return NULL;
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    bss->ssid_len == ssid_len &&
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    os_memcmp(bss->ssid, ssid, ssid_len) == 0)
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return bss;
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
259fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidtstatic void calculate_update_time(const struct os_reltime *fetch_time,
260444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt				  unsigned int age_ms,
261fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt				  struct os_reltime *update_time)
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_time_t usec;
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
265444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	update_time->sec = fetch_time->sec;
266444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	update_time->usec = fetch_time->usec;
267444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	update_time->sec -= age_ms / 1000;
268444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	usec = (age_ms % 1000) * 1000;
269444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	if (update_time->usec < usec) {
270444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt		update_time->sec--;
271444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt		update_time->usec += 1000000;
272444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	}
273444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	update_time->usec -= usec;
274444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt}
275444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt
276444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt
277444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidtstatic void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src,
278fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			     struct os_reltime *fetch_time)
279444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt{
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dst->flags = src->flags;
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(dst->bssid, src->bssid, ETH_ALEN);
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dst->freq = src->freq;
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dst->beacon_int = src->beacon_int;
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dst->caps = src->caps;
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dst->qual = src->qual;
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dst->noise = src->noise;
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dst->level = src->level;
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dst->tsf = src->tsf;
2897f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	dst->est_throughput = src->est_throughput;
2907f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	dst->snr = src->snr;
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
292444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	calculate_update_time(fetch_time, src->age, &dst->last_update);
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
2971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
2981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_ssid *ssid;
2991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
3011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (ssid->ssid == NULL || ssid->ssid_len == 0)
3021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			continue;
3031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (ssid->ssid_len == bss->ssid_len &&
3041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		    os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) == 0)
3051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			return 1;
3061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
3071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return 0;
3091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
3101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
31204949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
31304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
31404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	return bss == wpa_s->current_bss ||
3156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		(!is_zero_ether_addr(bss->bssid) &&
3166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 (os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 ||
3176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		  os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0));
31804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
31904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
32004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
3211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s)
3221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
3231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_bss *bss;
3241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
3261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (!wpa_bss_known(wpa_s, bss)) {
32704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			wpa_bss_remove(wpa_s, bss, __func__);
3281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			return 0;
3291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
3301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
3311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return -1;
3331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
3341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
33604949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic int wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s)
3371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
33804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct wpa_bss *bss;
33904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
3401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/*
3411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * Remove the oldest entry that does not match with any configured
3421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * network.
3431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 */
3441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (wpa_bss_remove_oldest_unknown(wpa_s) == 0)
34504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return 0;
3461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/*
34804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	 * Remove the oldest entry that isn't currently in use.
3491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 */
35004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
35104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		if (!wpa_bss_in_use(wpa_s, bss)) {
35204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			wpa_bss_remove(wpa_s, bss, __func__);
35304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			return 0;
35404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		}
35504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
35604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
35704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	return -1;
3581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
3591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3619bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidtstatic struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s,
3629bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt				    const u8 *ssid, size_t ssid_len,
363f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt				    struct wpa_scan_res *res,
364fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt				    struct os_reltime *fetch_time)
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_bss *bss;
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len);
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss == NULL)
3709bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt		return NULL;
3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bss->id = wpa_s->bss_next_id++;
3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bss->last_update_idx = wpa_s->bss_update_idx;
373f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	wpa_bss_copy_res(bss, res, fetch_time);
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(bss->ssid, ssid, ssid_len);
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bss->ssid_len = ssid_len;
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bss->ie_len = res->ie_len;
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bss->beacon_ie_len = res->beacon_ie_len;
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
3794530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	wpa_bss_set_hessid(bss);
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3817a6c830dbfaa00fa8918ab9065374c3d8b87f874Jouni Malinen	if (wpa_s->num_bss + 1 > wpa_s->conf->bss_max_count &&
3827a6c830dbfaa00fa8918ab9065374c3d8b87f874Jouni Malinen	    wpa_bss_remove_oldest(wpa_s) != 0) {
3837a6c830dbfaa00fa8918ab9065374c3d8b87f874Jouni Malinen		wpa_printf(MSG_ERROR, "Increasing the MAX BSS count to %d "
3847a6c830dbfaa00fa8918ab9065374c3d8b87f874Jouni Malinen			   "because all BSSes are in use. We should normally "
3857a6c830dbfaa00fa8918ab9065374c3d8b87f874Jouni Malinen			   "not get here!", (int) wpa_s->num_bss + 1);
3867a6c830dbfaa00fa8918ab9065374c3d8b87f874Jouni Malinen		wpa_s->conf->bss_max_count = wpa_s->num_bss + 1;
3877a6c830dbfaa00fa8918ab9065374c3d8b87f874Jouni Malinen	}
3887a6c830dbfaa00fa8918ab9065374c3d8b87f874Jouni Malinen
3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_add_tail(&wpa_s->bss, &bss->list);
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_add_tail(&wpa_s->bss_id, &bss->list_id);
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_s->num_bss++;
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Add new id %u BSSID " MACSTR
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		" SSID '%s'",
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len));
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpas_notify_bss_added(wpa_s, bss->bssid, bss->id);
3969bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt	return bss;
3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int are_ies_equal(const struct wpa_bss *old,
4011d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt			 const struct wpa_scan_res *new_res, u32 ie)
4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *old_ie, *new_ie;
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *old_ie_buff = NULL;
4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *new_ie_buff = NULL;
4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int new_ie_len, old_ie_len, ret, is_multi;
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (ie) {
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_IE_VENDOR_TYPE:
4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		old_ie = wpa_bss_get_vendor_ie(old, ie);
4111d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt		new_ie = wpa_scan_get_vendor_ie(new_res, ie);
4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		is_multi = 0;
4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPS_IE_VENDOR_TYPE:
4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		old_ie_buff = wpa_bss_get_vendor_ie_multi(old, ie);
4161d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt		new_ie_buff = wpa_scan_get_vendor_ie_multi(new_res, ie);
4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		is_multi = 1;
4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WLAN_EID_RSN:
4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WLAN_EID_SUPP_RATES:
4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WLAN_EID_EXT_SUPP_RATES:
4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		old_ie = wpa_bss_get_ie(old, ie);
4231d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt		new_ie = wpa_scan_get_ie(new_res, ie);
4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		is_multi = 0;
4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "bss: %s: cannot compare IEs", __func__);
4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (is_multi) {
4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* in case of multiple IEs stored in buffer */
4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		old_ie = old_ie_buff ? wpabuf_head_u8(old_ie_buff) : NULL;
4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		new_ie = new_ie_buff ? wpabuf_head_u8(new_ie_buff) : NULL;
4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		old_ie_len = old_ie_buff ? wpabuf_len(old_ie_buff) : 0;
4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		new_ie_len = new_ie_buff ? wpabuf_len(new_ie_buff) : 0;
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* in case of single IE */
4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		old_ie_len = old_ie ? old_ie[1] + 2 : 0;
4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		new_ie_len = new_ie ? new_ie[1] + 2 : 0;
4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!old_ie || !new_ie)
4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = !old_ie && !new_ie;
4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = (old_ie_len == new_ie_len &&
4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       os_memcmp(old_ie, new_ie, old_ie_len) == 0);
4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(old_ie_buff);
4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(new_ie_buff);
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic u32 wpa_bss_compare_res(const struct wpa_bss *old,
4571d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt			       const struct wpa_scan_res *new_res)
4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u32 changes = 0;
4601d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt	int caps_diff = old->caps ^ new_res->caps;
4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4621d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt	if (old->freq != new_res->freq)
4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		changes |= WPA_BSS_FREQ_CHANGED_FLAG;
4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4651d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt	if (old->level != new_res->level)
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		changes |= WPA_BSS_SIGNAL_CHANGED_FLAG;
4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (caps_diff & IEEE80211_CAP_PRIVACY)
4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		changes |= WPA_BSS_PRIVACY_CHANGED_FLAG;
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (caps_diff & IEEE80211_CAP_IBSS)
4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		changes |= WPA_BSS_MODE_CHANGED_FLAG;
4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4741d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt	if (old->ie_len == new_res->ie_len &&
4751d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt	    os_memcmp(old + 1, new_res + 1, old->ie_len) == 0)
4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return changes;
4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	changes |= WPA_BSS_IES_CHANGED_FLAG;
4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4791d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt	if (!are_ies_equal(old, new_res, WPA_IE_VENDOR_TYPE))
4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		changes |= WPA_BSS_WPAIE_CHANGED_FLAG;
4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4821d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt	if (!are_ies_equal(old, new_res, WLAN_EID_RSN))
4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		changes |= WPA_BSS_RSNIE_CHANGED_FLAG;
4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4851d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt	if (!are_ies_equal(old, new_res, WPS_IE_VENDOR_TYPE))
4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		changes |= WPA_BSS_WPS_CHANGED_FLAG;
4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4881d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt	if (!are_ies_equal(old, new_res, WLAN_EID_SUPP_RATES) ||
4891d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt	    !are_ies_equal(old, new_res, WLAN_EID_EXT_SUPP_RATES))
4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		changes |= WPA_BSS_RATES_CHANGED_FLAG;
4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return changes;
4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       const struct wpa_bss *bss)
4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (changes & WPA_BSS_FREQ_CHANGED_FLAG)
5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpas_notify_bss_freq_changed(wpa_s, bss->id);
5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (changes & WPA_BSS_SIGNAL_CHANGED_FLAG)
5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpas_notify_bss_signal_changed(wpa_s, bss->id);
5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (changes & WPA_BSS_PRIVACY_CHANGED_FLAG)
5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpas_notify_bss_privacy_changed(wpa_s, bss->id);
5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (changes & WPA_BSS_MODE_CHANGED_FLAG)
5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpas_notify_bss_mode_changed(wpa_s, bss->id);
5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (changes & WPA_BSS_WPAIE_CHANGED_FLAG)
5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpas_notify_bss_wpaie_changed(wpa_s, bss->id);
5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (changes & WPA_BSS_RSNIE_CHANGED_FLAG)
5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpas_notify_bss_rsnie_changed(wpa_s, bss->id);
5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (changes & WPA_BSS_WPS_CHANGED_FLAG)
5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpas_notify_bss_wps_changed(wpa_s, bss->id);
5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (changes & WPA_BSS_IES_CHANGED_FLAG)
5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpas_notify_bss_ies_changed(wpa_s, bss->id);
5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (changes & WPA_BSS_RATES_CHANGED_FLAG)
5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpas_notify_bss_rates_changed(wpa_s, bss->id);
525661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
526661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	wpas_notify_bss_seen(wpa_s, bss->id);
5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5309bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidtstatic struct wpa_bss *
5319bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidtwpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
532fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	       struct wpa_scan_res *res, struct os_reltime *fetch_time)
5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u32 changes;
5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	changes = wpa_bss_compare_res(bss, res);
5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bss->scan_miss_count = 0;
5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bss->last_update_idx = wpa_s->bss_update_idx;
539f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	wpa_bss_copy_res(bss, res, fetch_time);
5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Move the entry to the end of the list */
5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_del(&bss->list);
5429657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt#ifdef CONFIG_P2P
5439657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt	if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
5449657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt	    !wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE)) {
5459657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt		/*
5469657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt		 * This can happen when non-P2P station interface runs a scan
5479657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt		 * without P2P IE in the Probe Request frame. P2P GO would reply
5489657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt		 * to that with a Probe Response that does not include P2P IE.
5499657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt		 * Do not update the IEs in this BSS entry to avoid such loss of
5509657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt		 * information that may be needed for P2P operations to
5519657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt		 * determine group information.
5529657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt		 */
5539657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt		wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Do not update scan IEs for "
5549657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt			MACSTR " since that would remove P2P IE information",
5559657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt			MAC2STR(bss->bssid));
5569657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt	} else
5579657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt#endif /* CONFIG_P2P */
5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss->ie_len + bss->beacon_ie_len >=
5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    res->ie_len + res->beacon_ie_len) {
5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bss->ie_len = res->ie_len;
5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bss->beacon_ie_len = res->beacon_ie_len;
5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct wpa_bss *nbss;
5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct dl_list *prev = bss->list_id.prev;
5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dl_list_del(&bss->list_id);
5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nbss = os_realloc(bss, sizeof(*bss) + res->ie_len +
5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  res->beacon_ie_len);
5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (nbss) {
5709bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt			unsigned int i;
5719bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt			for (i = 0; i < wpa_s->last_scan_res_used; i++) {
5729bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt				if (wpa_s->last_scan_res[i] == bss) {
5739bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt					wpa_s->last_scan_res[i] = nbss;
5749bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt					break;
5759bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt				}
5769bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt			}
57704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			if (wpa_s->current_bss == bss)
57804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				wpa_s->current_bss = nbss;
5792e425d69801667e42b4874548f2a49dc16e95617Dmitry Shmidt			wpa_bss_update_pending_connect(wpa_s, bss, nbss);
5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			bss = nbss;
5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_memcpy(bss + 1, res + 1,
5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  res->ie_len + res->beacon_ie_len);
5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			bss->ie_len = res->ie_len;
5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			bss->beacon_ie_len = res->beacon_ie_len;
5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dl_list_add(prev, &bss->list_id);
5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5884530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (changes & WPA_BSS_IES_CHANGED_FLAG)
5894530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		wpa_bss_set_hessid(bss);
5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_add_tail(&wpa_s->bss, &bss->list);
5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	notify_bss_changes(wpa_s, changes, bss);
5939bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt
5949bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt	return bss;
5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
598a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt/**
599a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * wpa_bss_update_start - Start a BSS table update from scan results
600a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @wpa_s: Pointer to wpa_supplicant data
601a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt *
602a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * This function is called at the start of each BSS table update round for new
603a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * scan results. The actual scan result entries are indicated with calls to
604a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * wpa_bss_update_scan_res() and the update round is finished with a call to
605a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * wpa_bss_update_end().
606a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt */
6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wpa_bss_update_start(struct wpa_supplicant *wpa_s)
6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_s->bss_update_idx++;
6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Start scan result update %u",
6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_s->bss_update_idx);
6129bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt	wpa_s->last_scan_res_used = 0;
6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
616a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt/**
617a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * wpa_bss_update_scan_res - Update a BSS table entry based on a scan result
618a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @wpa_s: Pointer to wpa_supplicant data
619a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @res: Scan result
620f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt * @fetch_time: Time when the result was fetched from the driver
621a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt *
622a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * This function updates a BSS table entry (or adds one) based on a scan result.
623a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * This is called separately for each scan result between the calls to
624a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * wpa_bss_update_start() and wpa_bss_update_end().
625a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt */
6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
627f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt			     struct wpa_scan_res *res,
628fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			     struct os_reltime *fetch_time)
6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	const u8 *ssid, *p2p, *mesh;
6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_bss *bss;
6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
633444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	if (wpa_s->conf->ignore_old_scan_res) {
634fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		struct os_reltime update;
635444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt		calculate_update_time(fetch_time, res->age, &update);
636fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		if (os_reltime_before(&update, &wpa_s->scan_trigger_time)) {
637fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			struct os_reltime age;
638fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			os_reltime_sub(&wpa_s->scan_trigger_time, &update,
639fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt				       &age);
640444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt			wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Ignore driver BSS "
641444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt				"table entry that is %u.%06u seconds older "
642444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt				"than our scan trigger",
643444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt				(unsigned int) age.sec,
644444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt				(unsigned int) age.usec);
645444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt			return;
646444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt		}
647444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	}
648444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt
6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ssid = wpa_scan_get_ie(res, WLAN_EID_SSID);
6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ssid == NULL) {
6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_dbg(wpa_s, MSG_DEBUG, "BSS: No SSID IE included for "
6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			MACSTR, MAC2STR(res->bssid));
6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6559d9e60286e05ae45025b672636490bd12586138dDmitry Shmidt	if (ssid[1] > SSID_MAX_LEN) {
6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Too long SSID IE included for "
6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			MACSTR, MAC2STR(res->bssid));
6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	p2p = wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE);
66204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#ifdef CONFIG_P2P
66304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (p2p == NULL &&
66404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	    wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
66504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		/*
66604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		 * If it's a P2P specific interface, then don't update
66704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		 * the scan result without a P2P IE.
66804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		 */
66904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpa_printf(MSG_DEBUG, "BSS: No P2P IE - skipping BSS " MACSTR
67004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			   " update for P2P interface", MAC2STR(res->bssid));
67104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return;
67204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
67304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#endif /* CONFIG_P2P */
6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (p2p && ssid[1] == P2P_WILDCARD_SSID_LEN &&
6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    os_memcmp(ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 0)
6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return; /* Skip P2P listen discovery results here */
6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO: add option for ignoring BSSes we are not interested in
6798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * (to save memory) */
6806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
6816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	mesh = wpa_scan_get_ie(res, WLAN_EID_MESH_ID);
6829d9e60286e05ae45025b672636490bd12586138dDmitry Shmidt	if (mesh && mesh[1] <= SSID_MAX_LEN)
6836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ssid = mesh;
6846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
6868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss == NULL)
687f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res, fetch_time);
6885605286c30e1701491bd3af974ae423727750eddDmitry Shmidt	else {
689f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		bss = wpa_bss_update(wpa_s, bss, res, fetch_time);
6905605286c30e1701491bd3af974ae423727750eddDmitry Shmidt		if (wpa_s->last_scan_res) {
6915605286c30e1701491bd3af974ae423727750eddDmitry Shmidt			unsigned int i;
6925605286c30e1701491bd3af974ae423727750eddDmitry Shmidt			for (i = 0; i < wpa_s->last_scan_res_used; i++) {
6935605286c30e1701491bd3af974ae423727750eddDmitry Shmidt				if (bss == wpa_s->last_scan_res[i]) {
6945605286c30e1701491bd3af974ae423727750eddDmitry Shmidt					/* Already in the list */
6955605286c30e1701491bd3af974ae423727750eddDmitry Shmidt					return;
6965605286c30e1701491bd3af974ae423727750eddDmitry Shmidt				}
6975605286c30e1701491bd3af974ae423727750eddDmitry Shmidt			}
6985605286c30e1701491bd3af974ae423727750eddDmitry Shmidt		}
6995605286c30e1701491bd3af974ae423727750eddDmitry Shmidt	}
7009bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt
7019bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt	if (bss == NULL)
7029bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt		return;
7039bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt	if (wpa_s->last_scan_res_used >= wpa_s->last_scan_res_size) {
7049bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt		struct wpa_bss **n;
7059bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt		unsigned int siz;
7069bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt		if (wpa_s->last_scan_res_size == 0)
7079bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt			siz = 32;
7089bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt		else
7099bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt			siz = wpa_s->last_scan_res_size * 2;
7109bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt		n = os_realloc_array(wpa_s->last_scan_res, siz,
7119bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt				     sizeof(struct wpa_bss *));
7129bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt		if (n == NULL)
7139bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt			return;
7149bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt		wpa_s->last_scan_res = n;
7159bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt		wpa_s->last_scan_res_size = siz;
7169bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt	}
7179bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt
7187832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt	if (wpa_s->last_scan_res)
7197832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt		wpa_s->last_scan_res[wpa_s->last_scan_res_used++] = bss;
7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_bss_included_in_scan(const struct wpa_bss *bss,
7248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    const struct scan_info *info)
7258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int found;
7278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t i;
7288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (info == NULL)
7308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 1;
7318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (info->num_freqs) {
7338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		found = 0;
7348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		for (i = 0; i < info->num_freqs; i++) {
7358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (bss->freq == info->freqs[i]) {
7368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				found = 1;
7378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				break;
7388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
7398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
7408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!found)
7418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return 0;
7428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (info->num_ssids) {
7458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		found = 0;
7468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		for (i = 0; i < info->num_ssids; i++) {
7478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			const struct wpa_driver_scan_ssid *s = &info->ssids[i];
7488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if ((s->ssid == NULL || s->ssid_len == 0) ||
7498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    (s->ssid_len == bss->ssid_len &&
7508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     os_memcmp(s->ssid, bss->ssid, bss->ssid_len) ==
7518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     0)) {
7528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				found = 1;
7538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				break;
7548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
7558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
7568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!found)
7578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return 0;
7588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 1;
7618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
764a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt/**
765a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * wpa_bss_update_end - End a BSS table update from scan results
766a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @wpa_s: Pointer to wpa_supplicant data
767a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @info: Information about scan parameters
768a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @new_scan: Whether this update round was based on a new scan
769a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt *
770a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * This function is called at the end of each BSS table update round for new
771a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * scan results. The start of the update was indicated with a call to
772a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * wpa_bss_update_start().
773a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt */
7748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
7758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			int new_scan)
7768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_bss *bss, *n;
7788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
779fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	os_get_reltime(&wpa_s->last_scan);
7808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!new_scan)
7818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return; /* do not expire entries without new scan */
7828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
7848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wpa_bss_in_use(wpa_s, bss))
7858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
7868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!wpa_bss_included_in_scan(bss, info))
7878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue; /* expire only BSSes that were scanned */
7888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (bss->last_update_idx < wpa_s->bss_update_idx)
7898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			bss->scan_miss_count++;
7908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (bss->scan_miss_count >=
7918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    wpa_s->conf->bss_expiration_scan_count) {
79204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			wpa_bss_remove(wpa_s, bss, "no match in scan");
7938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
7948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7959bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt
796fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%u/%u",
797fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		   wpa_s->last_scan_res_used, wpa_s->last_scan_res_size);
7988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
801a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt/**
802a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * wpa_bss_flush_by_age - Flush old BSS entries
803a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @wpa_s: Pointer to wpa_supplicant data
804a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @age: Maximum entry age in seconds
805a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt *
806a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * Remove BSS entries that have not been updated during the last @age seconds.
807a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt */
8088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age)
8098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_bss *bss, *n;
811fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	struct os_reltime t;
8128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (dl_list_empty(&wpa_s->bss))
8148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
8158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
816fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	os_get_reltime(&t);
8178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	t.sec -= age;
8188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
8208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wpa_bss_in_use(wpa_s, bss))
8218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
8228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
823fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		if (os_reltime_before(&bss->last_update, &t)) {
82404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			wpa_bss_remove(wpa_s, bss, __func__);
8258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else
8268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
8278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_bss_timeout(void *eloop_ctx, void *timeout_ctx)
8328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_supplicant *wpa_s = eloop_ctx;
8348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_bss_flush_by_age(wpa_s, wpa_s->conf->bss_expiration_age);
8368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0,
8378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       wpa_bss_timeout, wpa_s, NULL);
8388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
841a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt/**
842a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * wpa_bss_init - Initialize BSS table
843a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @wpa_s: Pointer to wpa_supplicant data
844a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * Returns: 0 on success, -1 on failure
845a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt *
846a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * This prepares BSS table lists and timer for periodic updates. The BSS table
847a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * is deinitialized with wpa_bss_deinit() once not needed anymore.
848a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt */
8498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wpa_bss_init(struct wpa_supplicant *wpa_s)
8508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_init(&wpa_s->bss);
8528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_init(&wpa_s->bss_id);
8538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0,
8548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       wpa_bss_timeout, wpa_s, NULL);
8558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
8568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
859a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt/**
860a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * wpa_bss_flush - Flush all unused BSS entries
861a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @wpa_s: Pointer to wpa_supplicant data
862a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt */
8638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wpa_bss_flush(struct wpa_supplicant *wpa_s)
8648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_bss *bss, *n;
8668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
867fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	wpa_s->clear_driver_scan_cache = 1;
868fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
8698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->bss.next == NULL)
8708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return; /* BSS table not yet initialized */
8718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
8738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wpa_bss_in_use(wpa_s, bss))
8748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
87504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpa_bss_remove(wpa_s, bss, __func__);
8768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
880a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt/**
881a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * wpa_bss_deinit - Deinitialize BSS table
882a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @wpa_s: Pointer to wpa_supplicant data
883a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt */
8848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wpa_bss_deinit(struct wpa_supplicant *wpa_s)
8858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(wpa_bss_timeout, wpa_s, NULL);
8878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_bss_flush(wpa_s);
8888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
891a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt/**
892a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * wpa_bss_get_bssid - Fetch a BSS table entry based on BSSID
893a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @wpa_s: Pointer to wpa_supplicant data
894a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @bssid: BSSID
895a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * Returns: Pointer to the BSS entry or %NULL if not found
896a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt */
8978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
8988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   const u8 *bssid)
8998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_bss *bss;
90104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
90204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return NULL;
9038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
9048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
9058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return bss;
9068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
9078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
9088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
911444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt/**
912444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt * wpa_bss_get_bssid_latest - Fetch the latest BSS table entry based on BSSID
913444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt * @wpa_s: Pointer to wpa_supplicant data
914444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt * @bssid: BSSID
915444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt * Returns: Pointer to the BSS entry or %NULL if not found
916444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt *
917444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt * This function is like wpa_bss_get_bssid(), but full BSS table is iterated to
918444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt * find the entry that has the most recent update. This can help in finding the
919444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt * correct entry in cases where the SSID of the AP may have changed recently
920444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt * (e.g., in WPS reconfiguration cases).
921444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt */
922444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidtstruct wpa_bss * wpa_bss_get_bssid_latest(struct wpa_supplicant *wpa_s,
923444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt					  const u8 *bssid)
924444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt{
925444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	struct wpa_bss *bss, *found = NULL;
926444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
927444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt		return NULL;
928444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
929444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt		if (os_memcmp(bss->bssid, bssid, ETH_ALEN) != 0)
930444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt			continue;
931444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt		if (found == NULL ||
932fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		    os_reltime_before(&found->last_update, &bss->last_update))
933444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt			found = bss;
934444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	}
935444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	return found;
936444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt}
937444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt
938444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt
939c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt#ifdef CONFIG_P2P
940a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt/**
941a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * wpa_bss_get_p2p_dev_addr - Fetch a BSS table entry based on P2P Device Addr
942a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @wpa_s: Pointer to wpa_supplicant data
943a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @dev_addr: P2P Device Address of the GO
944a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * Returns: Pointer to the BSS entry or %NULL if not found
945a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt */
946c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidtstruct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s,
947c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt					  const u8 *dev_addr)
948c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt{
949c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	struct wpa_bss *bss;
950c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
951c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		u8 addr[ETH_ALEN];
952c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		if (p2p_parse_dev_addr((const u8 *) (bss + 1), bss->ie_len,
953c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				       addr) == 0 &&
954c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		    os_memcmp(addr, dev_addr, ETH_ALEN) == 0)
955c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			return bss;
956c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	}
957c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	return NULL;
958c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt}
959c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt#endif /* CONFIG_P2P */
960c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
961c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
962a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt/**
963a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * wpa_bss_get_id - Fetch a BSS table entry based on identifier
964a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @wpa_s: Pointer to wpa_supplicant data
965a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @id: Unique identifier (struct wpa_bss::id) assigned for the entry
966a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * Returns: Pointer to the BSS entry or %NULL if not found
967a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt */
9688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id)
9698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_bss *bss;
9718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
9728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (bss->id == id)
9738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return bss;
9748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
9758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
9768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
979a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt/**
980f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt * wpa_bss_get_id_range - Fetch a BSS table entry based on identifier range
981f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt * @wpa_s: Pointer to wpa_supplicant data
982f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt * @idf: Smallest allowed identifier assigned for the entry
983f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt * @idf: Largest allowed identifier assigned for the entry
984f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt * Returns: Pointer to the BSS entry or %NULL if not found
985f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt *
986f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt * This function is similar to wpa_bss_get_id() but allows a BSS entry with the
987f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt * smallest id value to be fetched within the specified range without the
988f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt * caller having to know the exact id.
989f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt */
990f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtstruct wpa_bss * wpa_bss_get_id_range(struct wpa_supplicant *wpa_s,
991f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt				      unsigned int idf, unsigned int idl)
992f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt{
993f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	struct wpa_bss *bss;
994f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
995f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		if (bss->id >= idf && bss->id <= idl)
996f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt			return bss;
997f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	}
998f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	return NULL;
999f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt}
1000f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
1001f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
1002f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt/**
1003a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * wpa_bss_get_ie - Fetch a specified information element from a BSS entry
1004a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @bss: BSS table entry
1005a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @ie: Information element identitifier (WLAN_EID_*)
1006a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * Returns: Pointer to the information element (id field) or %NULL if not found
1007a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt *
1008a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * This function returns the first matching information element in the BSS
1009a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * entry.
1010a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt */
10118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
10128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *end, *pos;
10148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = (const u8 *) (bss + 1);
10168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = pos + bss->ie_len;
10178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (pos + 1 < end) {
10198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (pos + 2 + pos[1] > end)
10208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
10218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (pos[0] == ie)
10228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return pos;
10238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += 2 + pos[1];
10248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
10278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1030a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt/**
1031a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * wpa_bss_get_vendor_ie - Fetch a vendor information element from a BSS entry
1032a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @bss: BSS table entry
1033a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @vendor_type: Vendor type (four octets starting the IE payload)
1034a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * Returns: Pointer to the information element (id field) or %NULL if not found
1035a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt *
1036a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * This function returns the first matching information element in the BSS
1037a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * entry.
1038a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt */
10398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
10408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *end, *pos;
10428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = (const u8 *) (bss + 1);
10448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = pos + bss->ie_len;
10458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (pos + 1 < end) {
10478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (pos + 2 + pos[1] > end)
10488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
10498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
10508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    vendor_type == WPA_GET_BE32(&pos[2]))
10518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return pos;
10528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += 2 + pos[1];
10538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
10568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1059a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt/**
10609657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt * wpa_bss_get_vendor_ie_beacon - Fetch a vendor information from a BSS entry
10619657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt * @bss: BSS table entry
10629657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt * @vendor_type: Vendor type (four octets starting the IE payload)
10639657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt * Returns: Pointer to the information element (id field) or %NULL if not found
10649657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt *
10659657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt * This function returns the first matching information element in the BSS
10669657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt * entry.
10679657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt *
10689657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt * This function is like wpa_bss_get_vendor_ie(), but uses IE buffer only
10699657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt * from Beacon frames instead of either Beacon or Probe Response frames.
10709657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt */
10719657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidtconst u8 * wpa_bss_get_vendor_ie_beacon(const struct wpa_bss *bss,
10729657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt					u32 vendor_type)
10739657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt{
10749657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt	const u8 *end, *pos;
10759657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt
10769657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt	if (bss->beacon_ie_len == 0)
10779657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt		return NULL;
10789657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt
10799657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt	pos = (const u8 *) (bss + 1);
10809657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt	pos += bss->ie_len;
10819657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt	end = pos + bss->beacon_ie_len;
10829657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt
10839657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt	while (pos + 1 < end) {
10849657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt		if (pos + 2 + pos[1] > end)
10859657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt			break;
10869657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
10879657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt		    vendor_type == WPA_GET_BE32(&pos[2]))
10889657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt			return pos;
10899657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt		pos += 2 + pos[1];
10909657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt	}
10919657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt
10929657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt	return NULL;
10939657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt}
10949657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt
10959657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt
10969657139ca0bbea9a84e0a3c7e9438d1f53c9ed24Dmitry Shmidt/**
1097a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * wpa_bss_get_vendor_ie_multi - Fetch vendor IE data from a BSS entry
1098a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @bss: BSS table entry
1099a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @vendor_type: Vendor type (four octets starting the IE payload)
1100a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * Returns: Pointer to the information element payload or %NULL if not found
1101a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt *
1102a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * This function returns concatenated payload of possibly fragmented vendor
1103a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * specific information elements in the BSS entry. The caller is responsible for
1104a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * freeing the returned buffer.
1105a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt */
11068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
11078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    u32 vendor_type)
11088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *buf;
11108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *end, *pos;
11118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf = wpabuf_alloc(bss->ie_len);
11138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (buf == NULL)
11148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
11158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = (const u8 *) (bss + 1);
11178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = pos + bss->ie_len;
11188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (pos + 1 < end) {
11208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (pos + 2 + pos[1] > end)
11218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
11228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
11238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    vendor_type == WPA_GET_BE32(&pos[2]))
11248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
11259bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt		pos += 2 + pos[1];
11269bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt	}
11279bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt
11289bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt	if (wpabuf_len(buf) == 0) {
11299bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt		wpabuf_free(buf);
11309bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt		buf = NULL;
11319bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt	}
11329bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt
11339bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt	return buf;
11349bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt}
11359bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt
11369bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt
1137a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt/**
1138a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * wpa_bss_get_vendor_ie_multi_beacon - Fetch vendor IE data from a BSS entry
1139a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @bss: BSS table entry
1140a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @vendor_type: Vendor type (four octets starting the IE payload)
1141a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * Returns: Pointer to the information element payload or %NULL if not found
1142a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt *
1143a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * This function returns concatenated payload of possibly fragmented vendor
1144a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * specific information elements in the BSS entry. The caller is responsible for
1145a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * freeing the returned buffer.
1146a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt *
1147a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * This function is like wpa_bss_get_vendor_ie_multi(), but uses IE buffer only
1148a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * from Beacon frames instead of either Beacon or Probe Response frames.
1149a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt */
11509bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidtstruct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss,
11519bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt						   u32 vendor_type)
11529bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt{
11539bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt	struct wpabuf *buf;
11549bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt	const u8 *end, *pos;
11559bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt
11569bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt	buf = wpabuf_alloc(bss->beacon_ie_len);
11579bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt	if (buf == NULL)
11589bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt		return NULL;
11599bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt
11609bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt	pos = (const u8 *) (bss + 1);
11619bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt	pos += bss->ie_len;
11629bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt	end = pos + bss->beacon_ie_len;
11639bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt
11649bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt	while (pos + 1 < end) {
11659bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt		if (pos + 2 + pos[1] > end)
11669bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt			break;
11679bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
11689bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt		    vendor_type == WPA_GET_BE32(&pos[2]))
11699bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt			wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
11708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += 2 + pos[1];
11718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpabuf_len(buf) == 0) {
11748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(buf);
11758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		buf = NULL;
11768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return buf;
11798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
11808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1182a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt/**
1183a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * wpa_bss_get_max_rate - Get maximum legacy TX rate supported in a BSS
1184a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @bss: BSS table entry
1185a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * Returns: Maximum legacy rate in units of 500 kbps
1186a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt */
11878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wpa_bss_get_max_rate(const struct wpa_bss *bss)
11888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int rate = 0;
11908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *ie;
11918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
11928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
11948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; ie && i < ie[1]; i++) {
11958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if ((ie[i + 2] & 0x7f) > rate)
11968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			rate = ie[i + 2] & 0x7f;
11978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
12008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; ie && i < ie[1]; i++) {
12018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if ((ie[i + 2] & 0x7f) > rate)
12028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			rate = ie[i + 2] & 0x7f;
12038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
12048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return rate;
12068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
12078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1209a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt/**
1210a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * wpa_bss_get_bit_rates - Get legacy TX rates supported in a BSS
1211a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @bss: BSS table entry
1212a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * @rates: Buffer for returning a pointer to the rates list (units of 500 kbps)
1213a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * Returns: number of legacy TX rates or -1 on failure
1214a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt *
1215a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * The caller is responsible for freeing the returned buffer with os_free() in
1216a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * case of success.
1217a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt */
12188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates)
12198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
12208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *ie, *ie2;
12218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i, j;
12228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int len;
12238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *r;
12248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
12268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ie2 = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
12278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len = (ie ? ie[1] : 0) + (ie2 ? ie2[1] : 0);
12298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	r = os_malloc(len);
12318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!r)
12328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
12338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; ie && i < ie[1]; i++)
12358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		r[i] = ie[i + 2] & 0x7f;
12368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (j = 0; ie2 && j < ie2[1]; j++)
12388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		r[i + j] = ie2[j + 2] & 0x7f;
12398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*rates = r;
12418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return len;
12428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1243