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