1214501Srpaulo/* 2214501Srpaulo * BSS table 3214501Srpaulo * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi> 4214501Srpaulo * 5214501Srpaulo * This program is free software; you can redistribute it and/or modify 6214501Srpaulo * it under the terms of the GNU General Public License version 2 as 7214501Srpaulo * published by the Free Software Foundation. 8214501Srpaulo * 9214501Srpaulo * Alternatively, this software may be distributed under the terms of BSD 10214501Srpaulo * license. 11214501Srpaulo * 12214501Srpaulo * See README and COPYING for more details. 13214501Srpaulo */ 14214501Srpaulo 15214501Srpaulo#include "utils/includes.h" 16214501Srpaulo 17214501Srpaulo#include "utils/common.h" 18214501Srpaulo#include "utils/eloop.h" 19214501Srpaulo#include "common/ieee802_11_defs.h" 20214501Srpaulo#include "drivers/driver.h" 21214501Srpaulo#include "wpa_supplicant_i.h" 22214501Srpaulo#include "config.h" 23214501Srpaulo#include "notify.h" 24214501Srpaulo#include "scan.h" 25214501Srpaulo#include "bss.h" 26214501Srpaulo 27214501Srpaulo 28214501Srpaulo/** 29214501Srpaulo * WPA_BSS_EXPIRATION_PERIOD - Period of expiration run in seconds 30214501Srpaulo */ 31214501Srpaulo#define WPA_BSS_EXPIRATION_PERIOD 10 32214501Srpaulo 33214501Srpaulo/** 34214501Srpaulo * WPA_BSS_EXPIRATION_AGE - BSS entry age after which it can be expired 35214501Srpaulo * 36214501Srpaulo * This value control the time in seconds after which a BSS entry gets removed 37214501Srpaulo * if it has not been updated or is not in use. 38214501Srpaulo */ 39214501Srpaulo#define WPA_BSS_EXPIRATION_AGE 180 40214501Srpaulo 41214501Srpaulo/** 42214501Srpaulo * WPA_BSS_EXPIRATION_SCAN_COUNT - Expire BSS after number of scans 43214501Srpaulo * 44214501Srpaulo * If the BSS entry has not been seen in this many scans, it will be removed. 45214501Srpaulo * Value 1 means that the entry is removed after the first scan without the 46214501Srpaulo * BSSID being seen. Larger values can be used to avoid BSS entries 47214501Srpaulo * disappearing if they are not visible in every scan (e.g., low signal quality 48214501Srpaulo * or interference). 49214501Srpaulo */ 50214501Srpaulo#define WPA_BSS_EXPIRATION_SCAN_COUNT 2 51214501Srpaulo 52214501Srpaulo#define WPA_BSS_FREQ_CHANGED_FLAG BIT(0) 53214501Srpaulo#define WPA_BSS_SIGNAL_CHANGED_FLAG BIT(1) 54214501Srpaulo#define WPA_BSS_PRIVACY_CHANGED_FLAG BIT(2) 55214501Srpaulo#define WPA_BSS_MODE_CHANGED_FLAG BIT(3) 56214501Srpaulo#define WPA_BSS_WPAIE_CHANGED_FLAG BIT(4) 57214501Srpaulo#define WPA_BSS_RSNIE_CHANGED_FLAG BIT(5) 58214501Srpaulo#define WPA_BSS_WPS_CHANGED_FLAG BIT(6) 59214501Srpaulo#define WPA_BSS_RATES_CHANGED_FLAG BIT(7) 60214501Srpaulo#define WPA_BSS_IES_CHANGED_FLAG BIT(8) 61214501Srpaulo 62214501Srpaulo 63214501Srpaulostatic void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) 64214501Srpaulo{ 65214501Srpaulo dl_list_del(&bss->list); 66214501Srpaulo dl_list_del(&bss->list_id); 67214501Srpaulo wpa_s->num_bss--; 68214501Srpaulo wpa_printf(MSG_DEBUG, "BSS: Remove id %u BSSID " MACSTR " SSID '%s'", 69214501Srpaulo bss->id, MAC2STR(bss->bssid), 70214501Srpaulo wpa_ssid_txt(bss->ssid, bss->ssid_len)); 71214501Srpaulo wpas_notify_bss_removed(wpa_s, bss->bssid, bss->id); 72214501Srpaulo os_free(bss); 73214501Srpaulo} 74214501Srpaulo 75214501Srpaulo 76214501Srpaulostruct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid, 77214501Srpaulo const u8 *ssid, size_t ssid_len) 78214501Srpaulo{ 79214501Srpaulo struct wpa_bss *bss; 80214501Srpaulo dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { 81214501Srpaulo if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 && 82214501Srpaulo bss->ssid_len == ssid_len && 83214501Srpaulo os_memcmp(bss->ssid, ssid, ssid_len) == 0) 84214501Srpaulo return bss; 85214501Srpaulo } 86214501Srpaulo return NULL; 87214501Srpaulo} 88214501Srpaulo 89214501Srpaulo 90214501Srpaulostatic void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src) 91214501Srpaulo{ 92214501Srpaulo os_time_t usec; 93214501Srpaulo 94214501Srpaulo dst->flags = src->flags; 95214501Srpaulo os_memcpy(dst->bssid, src->bssid, ETH_ALEN); 96214501Srpaulo dst->freq = src->freq; 97214501Srpaulo dst->beacon_int = src->beacon_int; 98214501Srpaulo dst->caps = src->caps; 99214501Srpaulo dst->qual = src->qual; 100214501Srpaulo dst->noise = src->noise; 101214501Srpaulo dst->level = src->level; 102214501Srpaulo dst->tsf = src->tsf; 103214501Srpaulo 104214501Srpaulo os_get_time(&dst->last_update); 105214501Srpaulo dst->last_update.sec -= src->age / 1000; 106214501Srpaulo usec = (src->age % 1000) * 1000; 107214501Srpaulo if (dst->last_update.usec < usec) { 108214501Srpaulo dst->last_update.sec--; 109214501Srpaulo dst->last_update.usec += 1000000; 110214501Srpaulo } 111214501Srpaulo dst->last_update.usec -= usec; 112214501Srpaulo} 113214501Srpaulo 114214501Srpaulo 115214501Srpaulostatic void wpa_bss_add(struct wpa_supplicant *wpa_s, 116214501Srpaulo const u8 *ssid, size_t ssid_len, 117214501Srpaulo struct wpa_scan_res *res) 118214501Srpaulo{ 119214501Srpaulo struct wpa_bss *bss; 120214501Srpaulo 121214501Srpaulo bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len); 122214501Srpaulo if (bss == NULL) 123214501Srpaulo return; 124214501Srpaulo bss->id = wpa_s->bss_next_id++; 125214501Srpaulo bss->last_update_idx = wpa_s->bss_update_idx; 126214501Srpaulo wpa_bss_copy_res(bss, res); 127214501Srpaulo os_memcpy(bss->ssid, ssid, ssid_len); 128214501Srpaulo bss->ssid_len = ssid_len; 129214501Srpaulo bss->ie_len = res->ie_len; 130214501Srpaulo bss->beacon_ie_len = res->beacon_ie_len; 131214501Srpaulo os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len); 132214501Srpaulo 133214501Srpaulo dl_list_add_tail(&wpa_s->bss, &bss->list); 134214501Srpaulo dl_list_add_tail(&wpa_s->bss_id, &bss->list_id); 135214501Srpaulo wpa_s->num_bss++; 136214501Srpaulo wpa_printf(MSG_DEBUG, "BSS: Add new id %u BSSID " MACSTR " SSID '%s'", 137214501Srpaulo bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len)); 138214501Srpaulo wpas_notify_bss_added(wpa_s, bss->bssid, bss->id); 139214501Srpaulo if (wpa_s->num_bss > wpa_s->conf->bss_max_count) { 140214501Srpaulo /* Remove the oldest entry */ 141214501Srpaulo wpa_bss_remove(wpa_s, dl_list_first(&wpa_s->bss, 142214501Srpaulo struct wpa_bss, list)); 143214501Srpaulo } 144214501Srpaulo} 145214501Srpaulo 146214501Srpaulo 147214501Srpaulostatic int are_ies_equal(const struct wpa_bss *old, 148214501Srpaulo const struct wpa_scan_res *new, u32 ie) 149214501Srpaulo{ 150214501Srpaulo const u8 *old_ie, *new_ie; 151214501Srpaulo struct wpabuf *old_ie_buff = NULL; 152214501Srpaulo struct wpabuf *new_ie_buff = NULL; 153214501Srpaulo int new_ie_len, old_ie_len, ret, is_multi; 154214501Srpaulo 155214501Srpaulo switch (ie) { 156214501Srpaulo case WPA_IE_VENDOR_TYPE: 157214501Srpaulo old_ie = wpa_bss_get_vendor_ie(old, ie); 158214501Srpaulo new_ie = wpa_scan_get_vendor_ie(new, ie); 159214501Srpaulo is_multi = 0; 160214501Srpaulo break; 161214501Srpaulo case WPS_IE_VENDOR_TYPE: 162214501Srpaulo old_ie_buff = wpa_bss_get_vendor_ie_multi(old, ie); 163214501Srpaulo new_ie_buff = wpa_scan_get_vendor_ie_multi(new, ie); 164214501Srpaulo is_multi = 1; 165214501Srpaulo break; 166214501Srpaulo case WLAN_EID_RSN: 167214501Srpaulo case WLAN_EID_SUPP_RATES: 168214501Srpaulo case WLAN_EID_EXT_SUPP_RATES: 169214501Srpaulo old_ie = wpa_bss_get_ie(old, ie); 170214501Srpaulo new_ie = wpa_scan_get_ie(new, ie); 171214501Srpaulo is_multi = 0; 172214501Srpaulo break; 173214501Srpaulo default: 174214501Srpaulo wpa_printf(MSG_DEBUG, "bss: %s: cannot compare IEs", __func__); 175214501Srpaulo return 0; 176214501Srpaulo } 177214501Srpaulo 178214501Srpaulo if (is_multi) { 179214501Srpaulo /* in case of multiple IEs stored in buffer */ 180214501Srpaulo old_ie = old_ie_buff ? wpabuf_head_u8(old_ie_buff) : NULL; 181214501Srpaulo new_ie = new_ie_buff ? wpabuf_head_u8(new_ie_buff) : NULL; 182214501Srpaulo old_ie_len = old_ie_buff ? wpabuf_len(old_ie_buff) : 0; 183214501Srpaulo new_ie_len = new_ie_buff ? wpabuf_len(new_ie_buff) : 0; 184214501Srpaulo } else { 185214501Srpaulo /* in case of single IE */ 186214501Srpaulo old_ie_len = old_ie ? old_ie[1] + 2 : 0; 187214501Srpaulo new_ie_len = new_ie ? new_ie[1] + 2 : 0; 188214501Srpaulo } 189214501Srpaulo 190214501Srpaulo ret = (old_ie_len == new_ie_len && 191214501Srpaulo os_memcmp(old_ie, new_ie, old_ie_len) == 0); 192214501Srpaulo 193214501Srpaulo wpabuf_free(old_ie_buff); 194214501Srpaulo wpabuf_free(new_ie_buff); 195214501Srpaulo 196214501Srpaulo return ret; 197214501Srpaulo} 198214501Srpaulo 199214501Srpaulo 200214501Srpaulostatic u32 wpa_bss_compare_res(const struct wpa_bss *old, 201214501Srpaulo const struct wpa_scan_res *new) 202214501Srpaulo{ 203214501Srpaulo u32 changes = 0; 204214501Srpaulo int caps_diff = old->caps ^ new->caps; 205214501Srpaulo 206214501Srpaulo if (old->freq != new->freq) 207214501Srpaulo changes |= WPA_BSS_FREQ_CHANGED_FLAG; 208214501Srpaulo 209214501Srpaulo if (old->level != new->level) 210214501Srpaulo changes |= WPA_BSS_SIGNAL_CHANGED_FLAG; 211214501Srpaulo 212214501Srpaulo if (caps_diff & IEEE80211_CAP_PRIVACY) 213214501Srpaulo changes |= WPA_BSS_PRIVACY_CHANGED_FLAG; 214214501Srpaulo 215214501Srpaulo if (caps_diff & IEEE80211_CAP_IBSS) 216214501Srpaulo changes |= WPA_BSS_MODE_CHANGED_FLAG; 217214501Srpaulo 218214501Srpaulo if (old->ie_len == new->ie_len && 219214501Srpaulo os_memcmp(old + 1, new + 1, old->ie_len) == 0) 220214501Srpaulo return changes; 221214501Srpaulo changes |= WPA_BSS_IES_CHANGED_FLAG; 222214501Srpaulo 223214501Srpaulo if (!are_ies_equal(old, new, WPA_IE_VENDOR_TYPE)) 224214501Srpaulo changes |= WPA_BSS_WPAIE_CHANGED_FLAG; 225214501Srpaulo 226214501Srpaulo if (!are_ies_equal(old, new, WLAN_EID_RSN)) 227214501Srpaulo changes |= WPA_BSS_RSNIE_CHANGED_FLAG; 228214501Srpaulo 229214501Srpaulo if (!are_ies_equal(old, new, WPS_IE_VENDOR_TYPE)) 230214501Srpaulo changes |= WPA_BSS_WPS_CHANGED_FLAG; 231214501Srpaulo 232214501Srpaulo if (!are_ies_equal(old, new, WLAN_EID_SUPP_RATES) || 233214501Srpaulo !are_ies_equal(old, new, WLAN_EID_EXT_SUPP_RATES)) 234214501Srpaulo changes |= WPA_BSS_RATES_CHANGED_FLAG; 235214501Srpaulo 236214501Srpaulo return changes; 237214501Srpaulo} 238214501Srpaulo 239214501Srpaulo 240214501Srpaulostatic void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes, 241214501Srpaulo const struct wpa_bss *bss) 242214501Srpaulo{ 243214501Srpaulo if (changes & WPA_BSS_FREQ_CHANGED_FLAG) 244214501Srpaulo wpas_notify_bss_freq_changed(wpa_s, bss->id); 245214501Srpaulo 246214501Srpaulo if (changes & WPA_BSS_SIGNAL_CHANGED_FLAG) 247214501Srpaulo wpas_notify_bss_signal_changed(wpa_s, bss->id); 248214501Srpaulo 249214501Srpaulo if (changes & WPA_BSS_PRIVACY_CHANGED_FLAG) 250214501Srpaulo wpas_notify_bss_privacy_changed(wpa_s, bss->id); 251214501Srpaulo 252214501Srpaulo if (changes & WPA_BSS_MODE_CHANGED_FLAG) 253214501Srpaulo wpas_notify_bss_mode_changed(wpa_s, bss->id); 254214501Srpaulo 255214501Srpaulo if (changes & WPA_BSS_WPAIE_CHANGED_FLAG) 256214501Srpaulo wpas_notify_bss_wpaie_changed(wpa_s, bss->id); 257214501Srpaulo 258214501Srpaulo if (changes & WPA_BSS_RSNIE_CHANGED_FLAG) 259214501Srpaulo wpas_notify_bss_rsnie_changed(wpa_s, bss->id); 260214501Srpaulo 261214501Srpaulo if (changes & WPA_BSS_WPS_CHANGED_FLAG) 262214501Srpaulo wpas_notify_bss_wps_changed(wpa_s, bss->id); 263214501Srpaulo 264214501Srpaulo if (changes & WPA_BSS_IES_CHANGED_FLAG) 265214501Srpaulo wpas_notify_bss_ies_changed(wpa_s, bss->id); 266214501Srpaulo 267214501Srpaulo if (changes & WPA_BSS_RATES_CHANGED_FLAG) 268214501Srpaulo wpas_notify_bss_rates_changed(wpa_s, bss->id); 269214501Srpaulo} 270214501Srpaulo 271214501Srpaulo 272214501Srpaulostatic void wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, 273214501Srpaulo struct wpa_scan_res *res) 274214501Srpaulo{ 275214501Srpaulo u32 changes; 276214501Srpaulo 277214501Srpaulo changes = wpa_bss_compare_res(bss, res); 278214501Srpaulo bss->scan_miss_count = 0; 279214501Srpaulo bss->last_update_idx = wpa_s->bss_update_idx; 280214501Srpaulo wpa_bss_copy_res(bss, res); 281214501Srpaulo /* Move the entry to the end of the list */ 282214501Srpaulo dl_list_del(&bss->list); 283214501Srpaulo if (bss->ie_len + bss->beacon_ie_len >= 284214501Srpaulo res->ie_len + res->beacon_ie_len) { 285214501Srpaulo os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len); 286214501Srpaulo bss->ie_len = res->ie_len; 287214501Srpaulo bss->beacon_ie_len = res->beacon_ie_len; 288214501Srpaulo } else { 289214501Srpaulo struct wpa_bss *nbss; 290214501Srpaulo struct dl_list *prev = bss->list_id.prev; 291214501Srpaulo dl_list_del(&bss->list_id); 292214501Srpaulo nbss = os_realloc(bss, sizeof(*bss) + res->ie_len + 293214501Srpaulo res->beacon_ie_len); 294214501Srpaulo if (nbss) { 295214501Srpaulo bss = nbss; 296214501Srpaulo os_memcpy(bss + 1, res + 1, 297214501Srpaulo res->ie_len + res->beacon_ie_len); 298214501Srpaulo bss->ie_len = res->ie_len; 299214501Srpaulo bss->beacon_ie_len = res->beacon_ie_len; 300214501Srpaulo } 301214501Srpaulo dl_list_add(prev, &bss->list_id); 302214501Srpaulo } 303214501Srpaulo dl_list_add_tail(&wpa_s->bss, &bss->list); 304214501Srpaulo 305214501Srpaulo notify_bss_changes(wpa_s, changes, bss); 306214501Srpaulo} 307214501Srpaulo 308214501Srpaulo 309214501Srpaulostatic int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) 310214501Srpaulo{ 311214501Srpaulo return bss == wpa_s->current_bss || 312214501Srpaulo os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 || 313214501Srpaulo os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0; 314214501Srpaulo} 315214501Srpaulo 316214501Srpaulo 317214501Srpaulovoid wpa_bss_update_start(struct wpa_supplicant *wpa_s) 318214501Srpaulo{ 319214501Srpaulo wpa_s->bss_update_idx++; 320214501Srpaulo wpa_printf(MSG_DEBUG, "BSS: Start scan result update %u", 321214501Srpaulo wpa_s->bss_update_idx); 322214501Srpaulo} 323214501Srpaulo 324214501Srpaulo 325214501Srpaulovoid wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s, 326214501Srpaulo struct wpa_scan_res *res) 327214501Srpaulo{ 328214501Srpaulo const u8 *ssid; 329214501Srpaulo struct wpa_bss *bss; 330214501Srpaulo 331214501Srpaulo ssid = wpa_scan_get_ie(res, WLAN_EID_SSID); 332214501Srpaulo if (ssid == NULL) { 333214501Srpaulo wpa_printf(MSG_DEBUG, "BSS: No SSID IE included for " MACSTR, 334214501Srpaulo MAC2STR(res->bssid)); 335214501Srpaulo return; 336214501Srpaulo } 337214501Srpaulo if (ssid[1] > 32) { 338214501Srpaulo wpa_printf(MSG_DEBUG, "BSS: Too long SSID IE included for " 339214501Srpaulo MACSTR, MAC2STR(res->bssid)); 340214501Srpaulo return; 341214501Srpaulo } 342214501Srpaulo 343214501Srpaulo /* TODO: add option for ignoring BSSes we are not interested in 344214501Srpaulo * (to save memory) */ 345214501Srpaulo bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]); 346214501Srpaulo if (bss == NULL) 347214501Srpaulo wpa_bss_add(wpa_s, ssid + 2, ssid[1], res); 348214501Srpaulo else 349214501Srpaulo wpa_bss_update(wpa_s, bss, res); 350214501Srpaulo} 351214501Srpaulo 352214501Srpaulo 353214501Srpaulostatic int wpa_bss_included_in_scan(const struct wpa_bss *bss, 354214501Srpaulo const struct scan_info *info) 355214501Srpaulo{ 356214501Srpaulo int found; 357214501Srpaulo size_t i; 358214501Srpaulo 359214501Srpaulo if (info == NULL) 360214501Srpaulo return 1; 361214501Srpaulo 362214501Srpaulo if (info->num_freqs) { 363214501Srpaulo found = 0; 364214501Srpaulo for (i = 0; i < info->num_freqs; i++) { 365214501Srpaulo if (bss->freq == info->freqs[i]) { 366214501Srpaulo found = 1; 367214501Srpaulo break; 368214501Srpaulo } 369214501Srpaulo } 370214501Srpaulo if (!found) 371214501Srpaulo return 0; 372214501Srpaulo } 373214501Srpaulo 374214501Srpaulo if (info->num_ssids) { 375214501Srpaulo found = 0; 376214501Srpaulo for (i = 0; i < info->num_ssids; i++) { 377214501Srpaulo const struct wpa_driver_scan_ssid *s = &info->ssids[i]; 378214501Srpaulo if ((s->ssid == NULL || s->ssid_len == 0) || 379214501Srpaulo (s->ssid_len == bss->ssid_len && 380214501Srpaulo os_memcmp(s->ssid, bss->ssid, bss->ssid_len) == 381214501Srpaulo 0)) { 382214501Srpaulo found = 1; 383214501Srpaulo break; 384214501Srpaulo } 385214501Srpaulo } 386214501Srpaulo if (!found) 387214501Srpaulo return 0; 388214501Srpaulo } 389214501Srpaulo 390214501Srpaulo return 1; 391214501Srpaulo} 392214501Srpaulo 393214501Srpaulo 394214501Srpaulovoid wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info, 395214501Srpaulo int new_scan) 396214501Srpaulo{ 397214501Srpaulo struct wpa_bss *bss, *n; 398214501Srpaulo 399214501Srpaulo if (!new_scan) 400214501Srpaulo return; /* do not expire entries without new scan */ 401214501Srpaulo 402214501Srpaulo dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) { 403214501Srpaulo if (wpa_bss_in_use(wpa_s, bss)) 404214501Srpaulo continue; 405214501Srpaulo if (!wpa_bss_included_in_scan(bss, info)) 406214501Srpaulo continue; /* expire only BSSes that were scanned */ 407214501Srpaulo if (bss->last_update_idx < wpa_s->bss_update_idx) 408214501Srpaulo bss->scan_miss_count++; 409214501Srpaulo if (bss->scan_miss_count >= WPA_BSS_EXPIRATION_SCAN_COUNT) { 410214501Srpaulo wpa_printf(MSG_DEBUG, "BSS: Expire BSS %u due to no " 411214501Srpaulo "match in scan", bss->id); 412214501Srpaulo wpa_bss_remove(wpa_s, bss); 413214501Srpaulo } 414214501Srpaulo } 415214501Srpaulo} 416214501Srpaulo 417214501Srpaulo 418214501Srpaulostatic void wpa_bss_timeout(void *eloop_ctx, void *timeout_ctx) 419214501Srpaulo{ 420214501Srpaulo struct wpa_supplicant *wpa_s = eloop_ctx; 421214501Srpaulo struct wpa_bss *bss, *n; 422214501Srpaulo struct os_time t; 423214501Srpaulo 424214501Srpaulo if (dl_list_empty(&wpa_s->bss)) 425214501Srpaulo return; 426214501Srpaulo 427214501Srpaulo os_get_time(&t); 428214501Srpaulo t.sec -= WPA_BSS_EXPIRATION_AGE; 429214501Srpaulo 430214501Srpaulo dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) { 431214501Srpaulo if (wpa_bss_in_use(wpa_s, bss)) 432214501Srpaulo continue; 433214501Srpaulo 434214501Srpaulo if (os_time_before(&bss->last_update, &t)) { 435214501Srpaulo wpa_printf(MSG_DEBUG, "BSS: Expire BSS %u due to age", 436214501Srpaulo bss->id); 437214501Srpaulo wpa_bss_remove(wpa_s, bss); 438214501Srpaulo } else 439214501Srpaulo break; 440214501Srpaulo } 441214501Srpaulo eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0, 442214501Srpaulo wpa_bss_timeout, wpa_s, NULL); 443214501Srpaulo} 444214501Srpaulo 445214501Srpaulo 446214501Srpauloint wpa_bss_init(struct wpa_supplicant *wpa_s) 447214501Srpaulo{ 448214501Srpaulo dl_list_init(&wpa_s->bss); 449214501Srpaulo dl_list_init(&wpa_s->bss_id); 450214501Srpaulo eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0, 451214501Srpaulo wpa_bss_timeout, wpa_s, NULL); 452214501Srpaulo return 0; 453214501Srpaulo} 454214501Srpaulo 455214501Srpaulo 456214501Srpaulovoid wpa_bss_deinit(struct wpa_supplicant *wpa_s) 457214501Srpaulo{ 458214501Srpaulo struct wpa_bss *bss, *n; 459214501Srpaulo eloop_cancel_timeout(wpa_bss_timeout, wpa_s, NULL); 460214501Srpaulo if (wpa_s->bss.next == NULL) 461214501Srpaulo return; /* BSS table not yet initialized */ 462214501Srpaulo dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) 463214501Srpaulo wpa_bss_remove(wpa_s, bss); 464214501Srpaulo} 465214501Srpaulo 466214501Srpaulo 467214501Srpaulostruct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s, 468214501Srpaulo const u8 *bssid) 469214501Srpaulo{ 470214501Srpaulo struct wpa_bss *bss; 471214501Srpaulo dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { 472214501Srpaulo if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0) 473214501Srpaulo return bss; 474214501Srpaulo } 475214501Srpaulo return NULL; 476214501Srpaulo} 477214501Srpaulo 478214501Srpaulo 479214501Srpaulostruct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id) 480214501Srpaulo{ 481214501Srpaulo struct wpa_bss *bss; 482214501Srpaulo dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { 483214501Srpaulo if (bss->id == id) 484214501Srpaulo return bss; 485214501Srpaulo } 486214501Srpaulo return NULL; 487214501Srpaulo} 488214501Srpaulo 489214501Srpaulo 490214501Srpauloconst u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie) 491214501Srpaulo{ 492214501Srpaulo const u8 *end, *pos; 493214501Srpaulo 494214501Srpaulo pos = (const u8 *) (bss + 1); 495214501Srpaulo end = pos + bss->ie_len; 496214501Srpaulo 497214501Srpaulo while (pos + 1 < end) { 498214501Srpaulo if (pos + 2 + pos[1] > end) 499214501Srpaulo break; 500214501Srpaulo if (pos[0] == ie) 501214501Srpaulo return pos; 502214501Srpaulo pos += 2 + pos[1]; 503214501Srpaulo } 504214501Srpaulo 505214501Srpaulo return NULL; 506214501Srpaulo} 507214501Srpaulo 508214501Srpaulo 509214501Srpauloconst u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type) 510214501Srpaulo{ 511214501Srpaulo const u8 *end, *pos; 512214501Srpaulo 513214501Srpaulo pos = (const u8 *) (bss + 1); 514214501Srpaulo end = pos + bss->ie_len; 515214501Srpaulo 516214501Srpaulo while (pos + 1 < end) { 517214501Srpaulo if (pos + 2 + pos[1] > end) 518214501Srpaulo break; 519214501Srpaulo if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && 520214501Srpaulo vendor_type == WPA_GET_BE32(&pos[2])) 521214501Srpaulo return pos; 522214501Srpaulo pos += 2 + pos[1]; 523214501Srpaulo } 524214501Srpaulo 525214501Srpaulo return NULL; 526214501Srpaulo} 527214501Srpaulo 528214501Srpaulo 529214501Srpaulostruct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss, 530214501Srpaulo u32 vendor_type) 531214501Srpaulo{ 532214501Srpaulo struct wpabuf *buf; 533214501Srpaulo const u8 *end, *pos; 534214501Srpaulo 535214501Srpaulo buf = wpabuf_alloc(bss->ie_len); 536214501Srpaulo if (buf == NULL) 537214501Srpaulo return NULL; 538214501Srpaulo 539214501Srpaulo pos = (const u8 *) (bss + 1); 540214501Srpaulo end = pos + bss->ie_len; 541214501Srpaulo 542214501Srpaulo while (pos + 1 < end) { 543214501Srpaulo if (pos + 2 + pos[1] > end) 544214501Srpaulo break; 545214501Srpaulo if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && 546214501Srpaulo vendor_type == WPA_GET_BE32(&pos[2])) 547214501Srpaulo wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4); 548214501Srpaulo pos += 2 + pos[1]; 549214501Srpaulo } 550214501Srpaulo 551214501Srpaulo if (wpabuf_len(buf) == 0) { 552214501Srpaulo wpabuf_free(buf); 553214501Srpaulo buf = NULL; 554214501Srpaulo } 555214501Srpaulo 556214501Srpaulo return buf; 557214501Srpaulo} 558214501Srpaulo 559214501Srpaulo 560214501Srpauloint wpa_bss_get_max_rate(const struct wpa_bss *bss) 561214501Srpaulo{ 562214501Srpaulo int rate = 0; 563214501Srpaulo const u8 *ie; 564214501Srpaulo int i; 565214501Srpaulo 566214501Srpaulo ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES); 567214501Srpaulo for (i = 0; ie && i < ie[1]; i++) { 568214501Srpaulo if ((ie[i + 2] & 0x7f) > rate) 569214501Srpaulo rate = ie[i + 2] & 0x7f; 570214501Srpaulo } 571214501Srpaulo 572214501Srpaulo ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES); 573214501Srpaulo for (i = 0; ie && i < ie[1]; i++) { 574214501Srpaulo if ((ie[i + 2] & 0x7f) > rate) 575214501Srpaulo rate = ie[i + 2] & 0x7f; 576214501Srpaulo } 577214501Srpaulo 578214501Srpaulo return rate; 579214501Srpaulo} 580214501Srpaulo 581214501Srpaulo 582214501Srpauloint wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates) 583214501Srpaulo{ 584214501Srpaulo const u8 *ie, *ie2; 585214501Srpaulo int i, j; 586214501Srpaulo unsigned int len; 587214501Srpaulo u8 *r; 588214501Srpaulo 589214501Srpaulo ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES); 590214501Srpaulo ie2 = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES); 591214501Srpaulo 592214501Srpaulo len = (ie ? ie[1] : 0) + (ie2 ? ie2[1] : 0); 593214501Srpaulo 594214501Srpaulo r = os_malloc(len); 595214501Srpaulo if (!r) 596214501Srpaulo return -1; 597214501Srpaulo 598214501Srpaulo for (i = 0; ie && i < ie[1]; i++) 599214501Srpaulo r[i] = ie[i + 2] & 0x7f; 600214501Srpaulo 601214501Srpaulo for (j = 0; ie2 && j < ie2[1]; j++) 602214501Srpaulo r[i + j] = ie2[j + 2] & 0x7f; 603214501Srpaulo 604214501Srpaulo *rates = r; 605214501Srpaulo return len; 606214501Srpaulo} 607