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