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