Home | History | Annotate | Line # | Download | only in wpa_supplicant
bss.c revision 1.1
      1  1.1  christos /*
      2  1.1  christos  * BSS table
      3  1.1  christos  * Copyright (c) 2009-2010, Jouni Malinen <j (at) w1.fi>
      4  1.1  christos  *
      5  1.1  christos  * This program is free software; you can redistribute it and/or modify
      6  1.1  christos  * it under the terms of the GNU General Public License version 2 as
      7  1.1  christos  * published by the Free Software Foundation.
      8  1.1  christos  *
      9  1.1  christos  * Alternatively, this software may be distributed under the terms of BSD
     10  1.1  christos  * license.
     11  1.1  christos  *
     12  1.1  christos  * See README and COPYING for more details.
     13  1.1  christos  */
     14  1.1  christos 
     15  1.1  christos #include "utils/includes.h"
     16  1.1  christos 
     17  1.1  christos #include "utils/common.h"
     18  1.1  christos #include "utils/eloop.h"
     19  1.1  christos #include "common/ieee802_11_defs.h"
     20  1.1  christos #include "drivers/driver.h"
     21  1.1  christos #include "wpa_supplicant_i.h"
     22  1.1  christos #include "config.h"
     23  1.1  christos #include "notify.h"
     24  1.1  christos #include "scan.h"
     25  1.1  christos #include "bss.h"
     26  1.1  christos 
     27  1.1  christos 
     28  1.1  christos /**
     29  1.1  christos  * WPA_BSS_EXPIRATION_PERIOD - Period of expiration run in seconds
     30  1.1  christos  */
     31  1.1  christos #define WPA_BSS_EXPIRATION_PERIOD 10
     32  1.1  christos 
     33  1.1  christos /**
     34  1.1  christos  * WPA_BSS_EXPIRATION_AGE - BSS entry age after which it can be expired
     35  1.1  christos  *
     36  1.1  christos  * This value control the time in seconds after which a BSS entry gets removed
     37  1.1  christos  * if it has not been updated or is not in use.
     38  1.1  christos  */
     39  1.1  christos #define WPA_BSS_EXPIRATION_AGE 180
     40  1.1  christos 
     41  1.1  christos /**
     42  1.1  christos  * WPA_BSS_EXPIRATION_SCAN_COUNT - Expire BSS after number of scans
     43  1.1  christos  *
     44  1.1  christos  * If the BSS entry has not been seen in this many scans, it will be removed.
     45  1.1  christos  * Value 1 means that the entry is removed after the first scan without the
     46  1.1  christos  * BSSID being seen. Larger values can be used to avoid BSS entries
     47  1.1  christos  * disappearing if they are not visible in every scan (e.g., low signal quality
     48  1.1  christos  * or interference).
     49  1.1  christos  */
     50  1.1  christos #define WPA_BSS_EXPIRATION_SCAN_COUNT 2
     51  1.1  christos 
     52  1.1  christos #define WPA_BSS_FREQ_CHANGED_FLAG	BIT(0)
     53  1.1  christos #define WPA_BSS_SIGNAL_CHANGED_FLAG	BIT(1)
     54  1.1  christos #define WPA_BSS_PRIVACY_CHANGED_FLAG	BIT(2)
     55  1.1  christos #define WPA_BSS_MODE_CHANGED_FLAG	BIT(3)
     56  1.1  christos #define WPA_BSS_WPAIE_CHANGED_FLAG	BIT(4)
     57  1.1  christos #define WPA_BSS_RSNIE_CHANGED_FLAG	BIT(5)
     58  1.1  christos #define WPA_BSS_WPS_CHANGED_FLAG	BIT(6)
     59  1.1  christos #define WPA_BSS_RATES_CHANGED_FLAG	BIT(7)
     60  1.1  christos #define WPA_BSS_IES_CHANGED_FLAG	BIT(8)
     61  1.1  christos 
     62  1.1  christos 
     63  1.1  christos static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
     64  1.1  christos {
     65  1.1  christos 	dl_list_del(&bss->list);
     66  1.1  christos 	dl_list_del(&bss->list_id);
     67  1.1  christos 	wpa_s->num_bss--;
     68  1.1  christos 	wpa_printf(MSG_DEBUG, "BSS: Remove id %u BSSID " MACSTR " SSID '%s'",
     69  1.1  christos 		   bss->id, MAC2STR(bss->bssid),
     70  1.1  christos 		   wpa_ssid_txt(bss->ssid, bss->ssid_len));
     71  1.1  christos 	wpas_notify_bss_removed(wpa_s, bss->bssid, bss->id);
     72  1.1  christos 	os_free(bss);
     73  1.1  christos }
     74  1.1  christos 
     75  1.1  christos 
     76  1.1  christos struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
     77  1.1  christos 			     const u8 *ssid, size_t ssid_len)
     78  1.1  christos {
     79  1.1  christos 	struct wpa_bss *bss;
     80  1.1  christos 	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
     81  1.1  christos 		if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
     82  1.1  christos 		    bss->ssid_len == ssid_len &&
     83  1.1  christos 		    os_memcmp(bss->ssid, ssid, ssid_len) == 0)
     84  1.1  christos 			return bss;
     85  1.1  christos 	}
     86  1.1  christos 	return NULL;
     87  1.1  christos }
     88  1.1  christos 
     89  1.1  christos 
     90  1.1  christos static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src)
     91  1.1  christos {
     92  1.1  christos 	os_time_t usec;
     93  1.1  christos 
     94  1.1  christos 	dst->flags = src->flags;
     95  1.1  christos 	os_memcpy(dst->bssid, src->bssid, ETH_ALEN);
     96  1.1  christos 	dst->freq = src->freq;
     97  1.1  christos 	dst->beacon_int = src->beacon_int;
     98  1.1  christos 	dst->caps = src->caps;
     99  1.1  christos 	dst->qual = src->qual;
    100  1.1  christos 	dst->noise = src->noise;
    101  1.1  christos 	dst->level = src->level;
    102  1.1  christos 	dst->tsf = src->tsf;
    103  1.1  christos 
    104  1.1  christos 	os_get_time(&dst->last_update);
    105  1.1  christos 	dst->last_update.sec -= src->age / 1000;
    106  1.1  christos 	usec = (src->age % 1000) * 1000;
    107  1.1  christos 	if (dst->last_update.usec < usec) {
    108  1.1  christos 		dst->last_update.sec--;
    109  1.1  christos 		dst->last_update.usec += 1000000;
    110  1.1  christos 	}
    111  1.1  christos 	dst->last_update.usec -= usec;
    112  1.1  christos }
    113  1.1  christos 
    114  1.1  christos 
    115  1.1  christos static void wpa_bss_add(struct wpa_supplicant *wpa_s,
    116  1.1  christos 			const u8 *ssid, size_t ssid_len,
    117  1.1  christos 			struct wpa_scan_res *res)
    118  1.1  christos {
    119  1.1  christos 	struct wpa_bss *bss;
    120  1.1  christos 
    121  1.1  christos 	bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len);
    122  1.1  christos 	if (bss == NULL)
    123  1.1  christos 		return;
    124  1.1  christos 	bss->id = wpa_s->bss_next_id++;
    125  1.1  christos 	bss->last_update_idx = wpa_s->bss_update_idx;
    126  1.1  christos 	wpa_bss_copy_res(bss, res);
    127  1.1  christos 	os_memcpy(bss->ssid, ssid, ssid_len);
    128  1.1  christos 	bss->ssid_len = ssid_len;
    129  1.1  christos 	bss->ie_len = res->ie_len;
    130  1.1  christos 	bss->beacon_ie_len = res->beacon_ie_len;
    131  1.1  christos 	os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
    132  1.1  christos 
    133  1.1  christos 	dl_list_add_tail(&wpa_s->bss, &bss->list);
    134  1.1  christos 	dl_list_add_tail(&wpa_s->bss_id, &bss->list_id);
    135  1.1  christos 	wpa_s->num_bss++;
    136  1.1  christos 	wpa_printf(MSG_DEBUG, "BSS: Add new id %u BSSID " MACSTR " SSID '%s'",
    137  1.1  christos 		   bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len));
    138  1.1  christos 	wpas_notify_bss_added(wpa_s, bss->bssid, bss->id);
    139  1.1  christos 	if (wpa_s->num_bss > wpa_s->conf->bss_max_count) {
    140  1.1  christos 		/* Remove the oldest entry */
    141  1.1  christos 		wpa_bss_remove(wpa_s, dl_list_first(&wpa_s->bss,
    142  1.1  christos 						    struct wpa_bss, list));
    143  1.1  christos 	}
    144  1.1  christos }
    145  1.1  christos 
    146  1.1  christos 
    147  1.1  christos static int are_ies_equal(const struct wpa_bss *old,
    148  1.1  christos 			 const struct wpa_scan_res *new, u32 ie)
    149  1.1  christos {
    150  1.1  christos 	const u8 *old_ie, *new_ie;
    151  1.1  christos 	struct wpabuf *old_ie_buff = NULL;
    152  1.1  christos 	struct wpabuf *new_ie_buff = NULL;
    153  1.1  christos 	int new_ie_len, old_ie_len, ret, is_multi;
    154  1.1  christos 
    155  1.1  christos 	switch (ie) {
    156  1.1  christos 	case WPA_IE_VENDOR_TYPE:
    157  1.1  christos 		old_ie = wpa_bss_get_vendor_ie(old, ie);
    158  1.1  christos 		new_ie = wpa_scan_get_vendor_ie(new, ie);
    159  1.1  christos 		is_multi = 0;
    160  1.1  christos 		break;
    161  1.1  christos 	case WPS_IE_VENDOR_TYPE:
    162  1.1  christos 		old_ie_buff = wpa_bss_get_vendor_ie_multi(old, ie);
    163  1.1  christos 		new_ie_buff = wpa_scan_get_vendor_ie_multi(new, ie);
    164  1.1  christos 		is_multi = 1;
    165  1.1  christos 		break;
    166  1.1  christos 	case WLAN_EID_RSN:
    167  1.1  christos 	case WLAN_EID_SUPP_RATES:
    168  1.1  christos 	case WLAN_EID_EXT_SUPP_RATES:
    169  1.1  christos 		old_ie = wpa_bss_get_ie(old, ie);
    170  1.1  christos 		new_ie = wpa_scan_get_ie(new, ie);
    171  1.1  christos 		is_multi = 0;
    172  1.1  christos 		break;
    173  1.1  christos 	default:
    174  1.1  christos 		wpa_printf(MSG_DEBUG, "bss: %s: cannot compare IEs", __func__);
    175  1.1  christos 		return 0;
    176  1.1  christos 	}
    177  1.1  christos 
    178  1.1  christos 	if (is_multi) {
    179  1.1  christos 		/* in case of multiple IEs stored in buffer */
    180  1.1  christos 		old_ie = old_ie_buff ? wpabuf_head_u8(old_ie_buff) : NULL;
    181  1.1  christos 		new_ie = new_ie_buff ? wpabuf_head_u8(new_ie_buff) : NULL;
    182  1.1  christos 		old_ie_len = old_ie_buff ? wpabuf_len(old_ie_buff) : 0;
    183  1.1  christos 		new_ie_len = new_ie_buff ? wpabuf_len(new_ie_buff) : 0;
    184  1.1  christos 	} else {
    185  1.1  christos 		/* in case of single IE */
    186  1.1  christos 		old_ie_len = old_ie ? old_ie[1] + 2 : 0;
    187  1.1  christos 		new_ie_len = new_ie ? new_ie[1] + 2 : 0;
    188  1.1  christos 	}
    189  1.1  christos 
    190  1.1  christos 	ret = (old_ie_len == new_ie_len &&
    191  1.1  christos 	       os_memcmp(old_ie, new_ie, old_ie_len) == 0);
    192  1.1  christos 
    193  1.1  christos 	wpabuf_free(old_ie_buff);
    194  1.1  christos 	wpabuf_free(new_ie_buff);
    195  1.1  christos 
    196  1.1  christos 	return ret;
    197  1.1  christos }
    198  1.1  christos 
    199  1.1  christos 
    200  1.1  christos static u32 wpa_bss_compare_res(const struct wpa_bss *old,
    201  1.1  christos 			       const struct wpa_scan_res *new)
    202  1.1  christos {
    203  1.1  christos 	u32 changes = 0;
    204  1.1  christos 	int caps_diff = old->caps ^ new->caps;
    205  1.1  christos 
    206  1.1  christos 	if (old->freq != new->freq)
    207  1.1  christos 		changes |= WPA_BSS_FREQ_CHANGED_FLAG;
    208  1.1  christos 
    209  1.1  christos 	if (old->level != new->level)
    210  1.1  christos 		changes |= WPA_BSS_SIGNAL_CHANGED_FLAG;
    211  1.1  christos 
    212  1.1  christos 	if (caps_diff & IEEE80211_CAP_PRIVACY)
    213  1.1  christos 		changes |= WPA_BSS_PRIVACY_CHANGED_FLAG;
    214  1.1  christos 
    215  1.1  christos 	if (caps_diff & IEEE80211_CAP_IBSS)
    216  1.1  christos 		changes |= WPA_BSS_MODE_CHANGED_FLAG;
    217  1.1  christos 
    218  1.1  christos 	if (old->ie_len == new->ie_len &&
    219  1.1  christos 	    os_memcmp(old + 1, new + 1, old->ie_len) == 0)
    220  1.1  christos 		return changes;
    221  1.1  christos 	changes |= WPA_BSS_IES_CHANGED_FLAG;
    222  1.1  christos 
    223  1.1  christos 	if (!are_ies_equal(old, new, WPA_IE_VENDOR_TYPE))
    224  1.1  christos 		changes |= WPA_BSS_WPAIE_CHANGED_FLAG;
    225  1.1  christos 
    226  1.1  christos 	if (!are_ies_equal(old, new, WLAN_EID_RSN))
    227  1.1  christos 		changes |= WPA_BSS_RSNIE_CHANGED_FLAG;
    228  1.1  christos 
    229  1.1  christos 	if (!are_ies_equal(old, new, WPS_IE_VENDOR_TYPE))
    230  1.1  christos 		changes |= WPA_BSS_WPS_CHANGED_FLAG;
    231  1.1  christos 
    232  1.1  christos 	if (!are_ies_equal(old, new, WLAN_EID_SUPP_RATES) ||
    233  1.1  christos 	    !are_ies_equal(old, new, WLAN_EID_EXT_SUPP_RATES))
    234  1.1  christos 		changes |= WPA_BSS_RATES_CHANGED_FLAG;
    235  1.1  christos 
    236  1.1  christos 	return changes;
    237  1.1  christos }
    238  1.1  christos 
    239  1.1  christos 
    240  1.1  christos static void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
    241  1.1  christos 			       const struct wpa_bss *bss)
    242  1.1  christos {
    243  1.1  christos 	if (changes & WPA_BSS_FREQ_CHANGED_FLAG)
    244  1.1  christos 		wpas_notify_bss_freq_changed(wpa_s, bss->id);
    245  1.1  christos 
    246  1.1  christos 	if (changes & WPA_BSS_SIGNAL_CHANGED_FLAG)
    247  1.1  christos 		wpas_notify_bss_signal_changed(wpa_s, bss->id);
    248  1.1  christos 
    249  1.1  christos 	if (changes & WPA_BSS_PRIVACY_CHANGED_FLAG)
    250  1.1  christos 		wpas_notify_bss_privacy_changed(wpa_s, bss->id);
    251  1.1  christos 
    252  1.1  christos 	if (changes & WPA_BSS_MODE_CHANGED_FLAG)
    253  1.1  christos 		wpas_notify_bss_mode_changed(wpa_s, bss->id);
    254  1.1  christos 
    255  1.1  christos 	if (changes & WPA_BSS_WPAIE_CHANGED_FLAG)
    256  1.1  christos 		wpas_notify_bss_wpaie_changed(wpa_s, bss->id);
    257  1.1  christos 
    258  1.1  christos 	if (changes & WPA_BSS_RSNIE_CHANGED_FLAG)
    259  1.1  christos 		wpas_notify_bss_rsnie_changed(wpa_s, bss->id);
    260  1.1  christos 
    261  1.1  christos 	if (changes & WPA_BSS_WPS_CHANGED_FLAG)
    262  1.1  christos 		wpas_notify_bss_wps_changed(wpa_s, bss->id);
    263  1.1  christos 
    264  1.1  christos 	if (changes & WPA_BSS_IES_CHANGED_FLAG)
    265  1.1  christos 		wpas_notify_bss_ies_changed(wpa_s, bss->id);
    266  1.1  christos 
    267  1.1  christos 	if (changes & WPA_BSS_RATES_CHANGED_FLAG)
    268  1.1  christos 		wpas_notify_bss_rates_changed(wpa_s, bss->id);
    269  1.1  christos }
    270  1.1  christos 
    271  1.1  christos 
    272  1.1  christos static void wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
    273  1.1  christos 			   struct wpa_scan_res *res)
    274  1.1  christos {
    275  1.1  christos 	u32 changes;
    276  1.1  christos 
    277  1.1  christos 	changes = wpa_bss_compare_res(bss, res);
    278  1.1  christos 	bss->scan_miss_count = 0;
    279  1.1  christos 	bss->last_update_idx = wpa_s->bss_update_idx;
    280  1.1  christos 	wpa_bss_copy_res(bss, res);
    281  1.1  christos 	/* Move the entry to the end of the list */
    282  1.1  christos 	dl_list_del(&bss->list);
    283  1.1  christos 	if (bss->ie_len + bss->beacon_ie_len >=
    284  1.1  christos 	    res->ie_len + res->beacon_ie_len) {
    285  1.1  christos 		os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
    286  1.1  christos 		bss->ie_len = res->ie_len;
    287  1.1  christos 		bss->beacon_ie_len = res->beacon_ie_len;
    288  1.1  christos 	} else {
    289  1.1  christos 		struct wpa_bss *nbss;
    290  1.1  christos 		struct dl_list *prev = bss->list_id.prev;
    291  1.1  christos 		dl_list_del(&bss->list_id);
    292  1.1  christos 		nbss = os_realloc(bss, sizeof(*bss) + res->ie_len +
    293  1.1  christos 				  res->beacon_ie_len);
    294  1.1  christos 		if (nbss) {
    295  1.1  christos 			bss = nbss;
    296  1.1  christos 			os_memcpy(bss + 1, res + 1,
    297  1.1  christos 				  res->ie_len + res->beacon_ie_len);
    298  1.1  christos 			bss->ie_len = res->ie_len;
    299  1.1  christos 			bss->beacon_ie_len = res->beacon_ie_len;
    300  1.1  christos 		}
    301  1.1  christos 		dl_list_add(prev, &bss->list_id);
    302  1.1  christos 	}
    303  1.1  christos 	dl_list_add_tail(&wpa_s->bss, &bss->list);
    304  1.1  christos 
    305  1.1  christos 	notify_bss_changes(wpa_s, changes, bss);
    306  1.1  christos }
    307  1.1  christos 
    308  1.1  christos 
    309  1.1  christos static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
    310  1.1  christos {
    311  1.1  christos 	return bss == wpa_s->current_bss ||
    312  1.1  christos 		os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 ||
    313  1.1  christos 		os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0;
    314  1.1  christos }
    315  1.1  christos 
    316  1.1  christos 
    317  1.1  christos void wpa_bss_update_start(struct wpa_supplicant *wpa_s)
    318  1.1  christos {
    319  1.1  christos 	wpa_s->bss_update_idx++;
    320  1.1  christos 	wpa_printf(MSG_DEBUG, "BSS: Start scan result update %u",
    321  1.1  christos 		   wpa_s->bss_update_idx);
    322  1.1  christos }
    323  1.1  christos 
    324  1.1  christos 
    325  1.1  christos void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
    326  1.1  christos 			     struct wpa_scan_res *res)
    327  1.1  christos {
    328  1.1  christos 	const u8 *ssid;
    329  1.1  christos 	struct wpa_bss *bss;
    330  1.1  christos 
    331  1.1  christos 	ssid = wpa_scan_get_ie(res, WLAN_EID_SSID);
    332  1.1  christos 	if (ssid == NULL) {
    333  1.1  christos 		wpa_printf(MSG_DEBUG, "BSS: No SSID IE included for " MACSTR,
    334  1.1  christos 			   MAC2STR(res->bssid));
    335  1.1  christos 		return;
    336  1.1  christos 	}
    337  1.1  christos 	if (ssid[1] > 32) {
    338  1.1  christos 		wpa_printf(MSG_DEBUG, "BSS: Too long SSID IE included for "
    339  1.1  christos 			   MACSTR, MAC2STR(res->bssid));
    340  1.1  christos 		return;
    341  1.1  christos 	}
    342  1.1  christos 
    343  1.1  christos 	/* TODO: add option for ignoring BSSes we are not interested in
    344  1.1  christos 	 * (to save memory) */
    345  1.1  christos 	bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
    346  1.1  christos 	if (bss == NULL)
    347  1.1  christos 		wpa_bss_add(wpa_s, ssid + 2, ssid[1], res);
    348  1.1  christos 	else
    349  1.1  christos 		wpa_bss_update(wpa_s, bss, res);
    350  1.1  christos }
    351  1.1  christos 
    352  1.1  christos 
    353  1.1  christos static int wpa_bss_included_in_scan(const struct wpa_bss *bss,
    354  1.1  christos 				    const struct scan_info *info)
    355  1.1  christos {
    356  1.1  christos 	int found;
    357  1.1  christos 	size_t i;
    358  1.1  christos 
    359  1.1  christos 	if (info == NULL)
    360  1.1  christos 		return 1;
    361  1.1  christos 
    362  1.1  christos 	if (info->num_freqs) {
    363  1.1  christos 		found = 0;
    364  1.1  christos 		for (i = 0; i < info->num_freqs; i++) {
    365  1.1  christos 			if (bss->freq == info->freqs[i]) {
    366  1.1  christos 				found = 1;
    367  1.1  christos 				break;
    368  1.1  christos 			}
    369  1.1  christos 		}
    370  1.1  christos 		if (!found)
    371  1.1  christos 			return 0;
    372  1.1  christos 	}
    373  1.1  christos 
    374  1.1  christos 	if (info->num_ssids) {
    375  1.1  christos 		found = 0;
    376  1.1  christos 		for (i = 0; i < info->num_ssids; i++) {
    377  1.1  christos 			const struct wpa_driver_scan_ssid *s = &info->ssids[i];
    378  1.1  christos 			if ((s->ssid == NULL || s->ssid_len == 0) ||
    379  1.1  christos 			    (s->ssid_len == bss->ssid_len &&
    380  1.1  christos 			     os_memcmp(s->ssid, bss->ssid, bss->ssid_len) ==
    381  1.1  christos 			     0)) {
    382  1.1  christos 				found = 1;
    383  1.1  christos 				break;
    384  1.1  christos 			}
    385  1.1  christos 		}
    386  1.1  christos 		if (!found)
    387  1.1  christos 			return 0;
    388  1.1  christos 	}
    389  1.1  christos 
    390  1.1  christos 	return 1;
    391  1.1  christos }
    392  1.1  christos 
    393  1.1  christos 
    394  1.1  christos void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
    395  1.1  christos 			int new_scan)
    396  1.1  christos {
    397  1.1  christos 	struct wpa_bss *bss, *n;
    398  1.1  christos 
    399  1.1  christos 	if (!new_scan)
    400  1.1  christos 		return; /* do not expire entries without new scan */
    401  1.1  christos 
    402  1.1  christos 	dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
    403  1.1  christos 		if (wpa_bss_in_use(wpa_s, bss))
    404  1.1  christos 			continue;
    405  1.1  christos 		if (!wpa_bss_included_in_scan(bss, info))
    406  1.1  christos 			continue; /* expire only BSSes that were scanned */
    407  1.1  christos 		if (bss->last_update_idx < wpa_s->bss_update_idx)
    408  1.1  christos 			bss->scan_miss_count++;
    409  1.1  christos 		if (bss->scan_miss_count >= WPA_BSS_EXPIRATION_SCAN_COUNT) {
    410  1.1  christos 			wpa_printf(MSG_DEBUG, "BSS: Expire BSS %u due to no "
    411  1.1  christos 				   "match in scan", bss->id);
    412  1.1  christos 			wpa_bss_remove(wpa_s, bss);
    413  1.1  christos 		}
    414  1.1  christos 	}
    415  1.1  christos }
    416  1.1  christos 
    417  1.1  christos 
    418  1.1  christos static void wpa_bss_timeout(void *eloop_ctx, void *timeout_ctx)
    419  1.1  christos {
    420  1.1  christos 	struct wpa_supplicant *wpa_s = eloop_ctx;
    421  1.1  christos 	struct wpa_bss *bss, *n;
    422  1.1  christos 	struct os_time t;
    423  1.1  christos 
    424  1.1  christos 	if (dl_list_empty(&wpa_s->bss))
    425  1.1  christos 		return;
    426  1.1  christos 
    427  1.1  christos 	os_get_time(&t);
    428  1.1  christos 	t.sec -= WPA_BSS_EXPIRATION_AGE;
    429  1.1  christos 
    430  1.1  christos 	dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
    431  1.1  christos 		if (wpa_bss_in_use(wpa_s, bss))
    432  1.1  christos 			continue;
    433  1.1  christos 
    434  1.1  christos 		if (os_time_before(&bss->last_update, &t)) {
    435  1.1  christos 			wpa_printf(MSG_DEBUG, "BSS: Expire BSS %u due to age",
    436  1.1  christos 				   bss->id);
    437  1.1  christos 			wpa_bss_remove(wpa_s, bss);
    438  1.1  christos 		} else
    439  1.1  christos 			break;
    440  1.1  christos 	}
    441  1.1  christos 	eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0,
    442  1.1  christos 			       wpa_bss_timeout, wpa_s, NULL);
    443  1.1  christos }
    444  1.1  christos 
    445  1.1  christos 
    446  1.1  christos int wpa_bss_init(struct wpa_supplicant *wpa_s)
    447  1.1  christos {
    448  1.1  christos 	dl_list_init(&wpa_s->bss);
    449  1.1  christos 	dl_list_init(&wpa_s->bss_id);
    450  1.1  christos 	eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0,
    451  1.1  christos 			       wpa_bss_timeout, wpa_s, NULL);
    452  1.1  christos 	return 0;
    453  1.1  christos }
    454  1.1  christos 
    455  1.1  christos 
    456  1.1  christos void wpa_bss_deinit(struct wpa_supplicant *wpa_s)
    457  1.1  christos {
    458  1.1  christos 	struct wpa_bss *bss, *n;
    459  1.1  christos 	eloop_cancel_timeout(wpa_bss_timeout, wpa_s, NULL);
    460  1.1  christos 	if (wpa_s->bss.next == NULL)
    461  1.1  christos 		return; /* BSS table not yet initialized */
    462  1.1  christos 	dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list)
    463  1.1  christos 		wpa_bss_remove(wpa_s, bss);
    464  1.1  christos }
    465  1.1  christos 
    466  1.1  christos 
    467  1.1  christos struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
    468  1.1  christos 				   const u8 *bssid)
    469  1.1  christos {
    470  1.1  christos 	struct wpa_bss *bss;
    471  1.1  christos 	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
    472  1.1  christos 		if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
    473  1.1  christos 			return bss;
    474  1.1  christos 	}
    475  1.1  christos 	return NULL;
    476  1.1  christos }
    477  1.1  christos 
    478  1.1  christos 
    479  1.1  christos struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id)
    480  1.1  christos {
    481  1.1  christos 	struct wpa_bss *bss;
    482  1.1  christos 	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
    483  1.1  christos 		if (bss->id == id)
    484  1.1  christos 			return bss;
    485  1.1  christos 	}
    486  1.1  christos 	return NULL;
    487  1.1  christos }
    488  1.1  christos 
    489  1.1  christos 
    490  1.1  christos const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
    491  1.1  christos {
    492  1.1  christos 	const u8 *end, *pos;
    493  1.1  christos 
    494  1.1  christos 	pos = (const u8 *) (bss + 1);
    495  1.1  christos 	end = pos + bss->ie_len;
    496  1.1  christos 
    497  1.1  christos 	while (pos + 1 < end) {
    498  1.1  christos 		if (pos + 2 + pos[1] > end)
    499  1.1  christos 			break;
    500  1.1  christos 		if (pos[0] == ie)
    501  1.1  christos 			return pos;
    502  1.1  christos 		pos += 2 + pos[1];
    503  1.1  christos 	}
    504  1.1  christos 
    505  1.1  christos 	return NULL;
    506  1.1  christos }
    507  1.1  christos 
    508  1.1  christos 
    509  1.1  christos const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
    510  1.1  christos {
    511  1.1  christos 	const u8 *end, *pos;
    512  1.1  christos 
    513  1.1  christos 	pos = (const u8 *) (bss + 1);
    514  1.1  christos 	end = pos + bss->ie_len;
    515  1.1  christos 
    516  1.1  christos 	while (pos + 1 < end) {
    517  1.1  christos 		if (pos + 2 + pos[1] > end)
    518  1.1  christos 			break;
    519  1.1  christos 		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
    520  1.1  christos 		    vendor_type == WPA_GET_BE32(&pos[2]))
    521  1.1  christos 			return pos;
    522  1.1  christos 		pos += 2 + pos[1];
    523  1.1  christos 	}
    524  1.1  christos 
    525  1.1  christos 	return NULL;
    526  1.1  christos }
    527  1.1  christos 
    528  1.1  christos 
    529  1.1  christos struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
    530  1.1  christos 					    u32 vendor_type)
    531  1.1  christos {
    532  1.1  christos 	struct wpabuf *buf;
    533  1.1  christos 	const u8 *end, *pos;
    534  1.1  christos 
    535  1.1  christos 	buf = wpabuf_alloc(bss->ie_len);
    536  1.1  christos 	if (buf == NULL)
    537  1.1  christos 		return NULL;
    538  1.1  christos 
    539  1.1  christos 	pos = (const u8 *) (bss + 1);
    540  1.1  christos 	end = pos + bss->ie_len;
    541  1.1  christos 
    542  1.1  christos 	while (pos + 1 < end) {
    543  1.1  christos 		if (pos + 2 + pos[1] > end)
    544  1.1  christos 			break;
    545  1.1  christos 		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
    546  1.1  christos 		    vendor_type == WPA_GET_BE32(&pos[2]))
    547  1.1  christos 			wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
    548  1.1  christos 		pos += 2 + pos[1];
    549  1.1  christos 	}
    550  1.1  christos 
    551  1.1  christos 	if (wpabuf_len(buf) == 0) {
    552  1.1  christos 		wpabuf_free(buf);
    553  1.1  christos 		buf = NULL;
    554  1.1  christos 	}
    555  1.1  christos 
    556  1.1  christos 	return buf;
    557  1.1  christos }
    558  1.1  christos 
    559  1.1  christos 
    560  1.1  christos int wpa_bss_get_max_rate(const struct wpa_bss *bss)
    561  1.1  christos {
    562  1.1  christos 	int rate = 0;
    563  1.1  christos 	const u8 *ie;
    564  1.1  christos 	int i;
    565  1.1  christos 
    566  1.1  christos 	ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
    567  1.1  christos 	for (i = 0; ie && i < ie[1]; i++) {
    568  1.1  christos 		if ((ie[i + 2] & 0x7f) > rate)
    569  1.1  christos 			rate = ie[i + 2] & 0x7f;
    570  1.1  christos 	}
    571  1.1  christos 
    572  1.1  christos 	ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
    573  1.1  christos 	for (i = 0; ie && i < ie[1]; i++) {
    574  1.1  christos 		if ((ie[i + 2] & 0x7f) > rate)
    575  1.1  christos 			rate = ie[i + 2] & 0x7f;
    576  1.1  christos 	}
    577  1.1  christos 
    578  1.1  christos 	return rate;
    579  1.1  christos }
    580  1.1  christos 
    581  1.1  christos 
    582  1.1  christos int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates)
    583  1.1  christos {
    584  1.1  christos 	const u8 *ie, *ie2;
    585  1.1  christos 	int i, j;
    586  1.1  christos 	unsigned int len;
    587  1.1  christos 	u8 *r;
    588  1.1  christos 
    589  1.1  christos 	ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
    590  1.1  christos 	ie2 = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
    591  1.1  christos 
    592  1.1  christos 	len = (ie ? ie[1] : 0) + (ie2 ? ie2[1] : 0);
    593  1.1  christos 
    594  1.1  christos 	r = os_malloc(len);
    595  1.1  christos 	if (!r)
    596  1.1  christos 		return -1;
    597  1.1  christos 
    598  1.1  christos 	for (i = 0; ie && i < ie[1]; i++)
    599  1.1  christos 		r[i] = ie[i + 2] & 0x7f;
    600  1.1  christos 
    601  1.1  christos 	for (j = 0; ie2 && j < ie2[1]; j++)
    602  1.1  christos 		r[i + j] = ie2[j + 2] & 0x7f;
    603  1.1  christos 
    604  1.1  christos 	*rates = r;
    605  1.1  christos 	return len;
    606  1.1  christos }
    607