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