Home | History | Annotate | Line # | Download | only in wpa_supplicant
bss.c revision 1.1.1.7.2.1
      1          1.1  christos /*
      2          1.1  christos  * BSS table
      3  1.1.1.7.2.1    martin  * Copyright (c) 2009-2019, 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.7  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.7  christos 	ANQP_DUP(hs20_operator_icon_metadata);
    106      1.1.1.7  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.7  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.7  christos 	wpabuf_free(anqp->hs20_operator_icon_metadata);
    191      1.1.1.7  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.7  christos void calculate_update_time(const struct os_reltime *fetch_time,
    277      1.1.1.7  christos 			   unsigned int age_ms,
    278      1.1.1.7  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.1.7.2.1    martin 	char extra[50];
    435          1.1  christos 
    436          1.1  christos 	bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len);
    437          1.1  christos 	if (bss == NULL)
    438      1.1.1.3  christos 		return NULL;
    439          1.1  christos 	bss->id = wpa_s->bss_next_id++;
    440          1.1  christos 	bss->last_update_idx = wpa_s->bss_update_idx;
    441      1.1.1.4  christos 	wpa_bss_copy_res(bss, res, fetch_time);
    442          1.1  christos 	os_memcpy(bss->ssid, ssid, ssid_len);
    443          1.1  christos 	bss->ssid_len = ssid_len;
    444          1.1  christos 	bss->ie_len = res->ie_len;
    445          1.1  christos 	bss->beacon_ie_len = res->beacon_ie_len;
    446          1.1  christos 	os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
    447      1.1.1.3  christos 	wpa_bss_set_hessid(bss);
    448          1.1  christos 
    449      1.1.1.4  christos 	if (wpa_s->num_bss + 1 > wpa_s->conf->bss_max_count &&
    450      1.1.1.4  christos 	    wpa_bss_remove_oldest(wpa_s) != 0) {
    451      1.1.1.4  christos 		wpa_printf(MSG_ERROR, "Increasing the MAX BSS count to %d "
    452      1.1.1.4  christos 			   "because all BSSes are in use. We should normally "
    453      1.1.1.4  christos 			   "not get here!", (int) wpa_s->num_bss + 1);
    454      1.1.1.4  christos 		wpa_s->conf->bss_max_count = wpa_s->num_bss + 1;
    455      1.1.1.4  christos 	}
    456      1.1.1.4  christos 
    457          1.1  christos 	dl_list_add_tail(&wpa_s->bss, &bss->list);
    458          1.1  christos 	dl_list_add_tail(&wpa_s->bss_id, &bss->list_id);
    459          1.1  christos 	wpa_s->num_bss++;
    460  1.1.1.7.2.1    martin 	if (!is_zero_ether_addr(bss->hessid))
    461  1.1.1.7.2.1    martin 		os_snprintf(extra, sizeof(extra), " HESSID " MACSTR,
    462  1.1.1.7.2.1    martin 			    MAC2STR(bss->hessid));
    463  1.1.1.7.2.1    martin 	else
    464  1.1.1.7.2.1    martin 		extra[0] = '\0';
    465      1.1.1.2  christos 	wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Add new id %u BSSID " MACSTR
    466  1.1.1.7.2.1    martin 		" SSID '%s' freq %d%s",
    467      1.1.1.6  christos 		bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len),
    468  1.1.1.7.2.1    martin 		bss->freq, extra);
    469          1.1  christos 	wpas_notify_bss_added(wpa_s, bss->bssid, bss->id);
    470      1.1.1.3  christos 	return bss;
    471          1.1  christos }
    472          1.1  christos 
    473          1.1  christos 
    474          1.1  christos static int are_ies_equal(const struct wpa_bss *old,
    475      1.1.1.6  christos 			 const struct wpa_scan_res *new_res, u32 ie)
    476          1.1  christos {
    477          1.1  christos 	const u8 *old_ie, *new_ie;
    478          1.1  christos 	struct wpabuf *old_ie_buff = NULL;
    479          1.1  christos 	struct wpabuf *new_ie_buff = NULL;
    480          1.1  christos 	int new_ie_len, old_ie_len, ret, is_multi;
    481          1.1  christos 
    482          1.1  christos 	switch (ie) {
    483          1.1  christos 	case WPA_IE_VENDOR_TYPE:
    484          1.1  christos 		old_ie = wpa_bss_get_vendor_ie(old, ie);
    485      1.1.1.6  christos 		new_ie = wpa_scan_get_vendor_ie(new_res, ie);
    486          1.1  christos 		is_multi = 0;
    487          1.1  christos 		break;
    488          1.1  christos 	case WPS_IE_VENDOR_TYPE:
    489          1.1  christos 		old_ie_buff = wpa_bss_get_vendor_ie_multi(old, ie);
    490      1.1.1.6  christos 		new_ie_buff = wpa_scan_get_vendor_ie_multi(new_res, ie);
    491          1.1  christos 		is_multi = 1;
    492          1.1  christos 		break;
    493          1.1  christos 	case WLAN_EID_RSN:
    494          1.1  christos 	case WLAN_EID_SUPP_RATES:
    495          1.1  christos 	case WLAN_EID_EXT_SUPP_RATES:
    496          1.1  christos 		old_ie = wpa_bss_get_ie(old, ie);
    497      1.1.1.6  christos 		new_ie = wpa_scan_get_ie(new_res, ie);
    498          1.1  christos 		is_multi = 0;
    499          1.1  christos 		break;
    500          1.1  christos 	default:
    501          1.1  christos 		wpa_printf(MSG_DEBUG, "bss: %s: cannot compare IEs", __func__);
    502          1.1  christos 		return 0;
    503          1.1  christos 	}
    504          1.1  christos 
    505          1.1  christos 	if (is_multi) {
    506          1.1  christos 		/* in case of multiple IEs stored in buffer */
    507          1.1  christos 		old_ie = old_ie_buff ? wpabuf_head_u8(old_ie_buff) : NULL;
    508          1.1  christos 		new_ie = new_ie_buff ? wpabuf_head_u8(new_ie_buff) : NULL;
    509          1.1  christos 		old_ie_len = old_ie_buff ? wpabuf_len(old_ie_buff) : 0;
    510          1.1  christos 		new_ie_len = new_ie_buff ? wpabuf_len(new_ie_buff) : 0;
    511          1.1  christos 	} else {
    512          1.1  christos 		/* in case of single IE */
    513          1.1  christos 		old_ie_len = old_ie ? old_ie[1] + 2 : 0;
    514          1.1  christos 		new_ie_len = new_ie ? new_ie[1] + 2 : 0;
    515          1.1  christos 	}
    516          1.1  christos 
    517      1.1.1.2  christos 	if (!old_ie || !new_ie)
    518      1.1.1.2  christos 		ret = !old_ie && !new_ie;
    519      1.1.1.2  christos 	else
    520      1.1.1.2  christos 		ret = (old_ie_len == new_ie_len &&
    521      1.1.1.2  christos 		       os_memcmp(old_ie, new_ie, old_ie_len) == 0);
    522          1.1  christos 
    523          1.1  christos 	wpabuf_free(old_ie_buff);
    524          1.1  christos 	wpabuf_free(new_ie_buff);
    525          1.1  christos 
    526          1.1  christos 	return ret;
    527          1.1  christos }
    528          1.1  christos 
    529          1.1  christos 
    530          1.1  christos static u32 wpa_bss_compare_res(const struct wpa_bss *old,
    531      1.1.1.6  christos 			       const struct wpa_scan_res *new_res)
    532          1.1  christos {
    533          1.1  christos 	u32 changes = 0;
    534      1.1.1.6  christos 	int caps_diff = old->caps ^ new_res->caps;
    535          1.1  christos 
    536      1.1.1.6  christos 	if (old->freq != new_res->freq)
    537          1.1  christos 		changes |= WPA_BSS_FREQ_CHANGED_FLAG;
    538          1.1  christos 
    539      1.1.1.6  christos 	if (old->level != new_res->level)
    540          1.1  christos 		changes |= WPA_BSS_SIGNAL_CHANGED_FLAG;
    541          1.1  christos 
    542          1.1  christos 	if (caps_diff & IEEE80211_CAP_PRIVACY)
    543          1.1  christos 		changes |= WPA_BSS_PRIVACY_CHANGED_FLAG;
    544          1.1  christos 
    545          1.1  christos 	if (caps_diff & IEEE80211_CAP_IBSS)
    546          1.1  christos 		changes |= WPA_BSS_MODE_CHANGED_FLAG;
    547          1.1  christos 
    548      1.1.1.6  christos 	if (old->ie_len == new_res->ie_len &&
    549      1.1.1.6  christos 	    os_memcmp(old + 1, new_res + 1, old->ie_len) == 0)
    550          1.1  christos 		return changes;
    551          1.1  christos 	changes |= WPA_BSS_IES_CHANGED_FLAG;
    552          1.1  christos 
    553      1.1.1.6  christos 	if (!are_ies_equal(old, new_res, WPA_IE_VENDOR_TYPE))
    554          1.1  christos 		changes |= WPA_BSS_WPAIE_CHANGED_FLAG;
    555          1.1  christos 
    556      1.1.1.6  christos 	if (!are_ies_equal(old, new_res, WLAN_EID_RSN))
    557          1.1  christos 		changes |= WPA_BSS_RSNIE_CHANGED_FLAG;
    558          1.1  christos 
    559      1.1.1.6  christos 	if (!are_ies_equal(old, new_res, WPS_IE_VENDOR_TYPE))
    560          1.1  christos 		changes |= WPA_BSS_WPS_CHANGED_FLAG;
    561          1.1  christos 
    562      1.1.1.6  christos 	if (!are_ies_equal(old, new_res, WLAN_EID_SUPP_RATES) ||
    563      1.1.1.6  christos 	    !are_ies_equal(old, new_res, WLAN_EID_EXT_SUPP_RATES))
    564          1.1  christos 		changes |= WPA_BSS_RATES_CHANGED_FLAG;
    565          1.1  christos 
    566          1.1  christos 	return changes;
    567          1.1  christos }
    568          1.1  christos 
    569          1.1  christos 
    570          1.1  christos static void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
    571          1.1  christos 			       const struct wpa_bss *bss)
    572          1.1  christos {
    573          1.1  christos 	if (changes & WPA_BSS_FREQ_CHANGED_FLAG)
    574          1.1  christos 		wpas_notify_bss_freq_changed(wpa_s, bss->id);
    575          1.1  christos 
    576          1.1  christos 	if (changes & WPA_BSS_SIGNAL_CHANGED_FLAG)
    577          1.1  christos 		wpas_notify_bss_signal_changed(wpa_s, bss->id);
    578          1.1  christos 
    579          1.1  christos 	if (changes & WPA_BSS_PRIVACY_CHANGED_FLAG)
    580          1.1  christos 		wpas_notify_bss_privacy_changed(wpa_s, bss->id);
    581          1.1  christos 
    582          1.1  christos 	if (changes & WPA_BSS_MODE_CHANGED_FLAG)
    583          1.1  christos 		wpas_notify_bss_mode_changed(wpa_s, bss->id);
    584          1.1  christos 
    585          1.1  christos 	if (changes & WPA_BSS_WPAIE_CHANGED_FLAG)
    586          1.1  christos 		wpas_notify_bss_wpaie_changed(wpa_s, bss->id);
    587          1.1  christos 
    588          1.1  christos 	if (changes & WPA_BSS_RSNIE_CHANGED_FLAG)
    589          1.1  christos 		wpas_notify_bss_rsnie_changed(wpa_s, bss->id);
    590          1.1  christos 
    591          1.1  christos 	if (changes & WPA_BSS_WPS_CHANGED_FLAG)
    592          1.1  christos 		wpas_notify_bss_wps_changed(wpa_s, bss->id);
    593          1.1  christos 
    594          1.1  christos 	if (changes & WPA_BSS_IES_CHANGED_FLAG)
    595          1.1  christos 		wpas_notify_bss_ies_changed(wpa_s, bss->id);
    596          1.1  christos 
    597          1.1  christos 	if (changes & WPA_BSS_RATES_CHANGED_FLAG)
    598          1.1  christos 		wpas_notify_bss_rates_changed(wpa_s, bss->id);
    599      1.1.1.4  christos 
    600      1.1.1.4  christos 	wpas_notify_bss_seen(wpa_s, bss->id);
    601          1.1  christos }
    602          1.1  christos 
    603          1.1  christos 
    604      1.1.1.3  christos static struct wpa_bss *
    605      1.1.1.3  christos wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
    606      1.1.1.4  christos 	       struct wpa_scan_res *res, struct os_reltime *fetch_time)
    607          1.1  christos {
    608          1.1  christos 	u32 changes;
    609          1.1  christos 
    610      1.1.1.7  christos 	if (bss->last_update_idx == wpa_s->bss_update_idx) {
    611      1.1.1.7  christos 		struct os_reltime update_time;
    612      1.1.1.7  christos 
    613      1.1.1.7  christos 		/*
    614      1.1.1.7  christos 		 * Some drivers (e.g., cfg80211) include multiple BSS entries
    615      1.1.1.7  christos 		 * for the same BSS if that BSS's channel changes. The BSS list
    616      1.1.1.7  christos 		 * implementation in wpa_supplicant does not do that and we need
    617      1.1.1.7  christos 		 * to filter out the obsolete results here to make sure only the
    618      1.1.1.7  christos 		 * most current BSS information remains in the table.
    619      1.1.1.7  christos 		 */
    620      1.1.1.7  christos 		wpa_printf(MSG_DEBUG, "BSS: " MACSTR
    621      1.1.1.7  christos 			   " has multiple entries in the scan results - select the most current one",
    622      1.1.1.7  christos 			   MAC2STR(bss->bssid));
    623      1.1.1.7  christos 		calculate_update_time(fetch_time, res->age, &update_time);
    624      1.1.1.7  christos 		wpa_printf(MSG_DEBUG,
    625      1.1.1.7  christos 			   "Previous last_update: %u.%06u (freq %d%s)",
    626      1.1.1.7  christos 			   (unsigned int) bss->last_update.sec,
    627      1.1.1.7  christos 			   (unsigned int) bss->last_update.usec,
    628      1.1.1.7  christos 			   bss->freq,
    629      1.1.1.7  christos 			   (bss->flags & WPA_BSS_ASSOCIATED) ? " assoc" : "");
    630      1.1.1.7  christos 		wpa_printf(MSG_DEBUG, "New last_update: %u.%06u (freq %d%s)",
    631      1.1.1.7  christos 			   (unsigned int) update_time.sec,
    632      1.1.1.7  christos 			   (unsigned int) update_time.usec,
    633      1.1.1.7  christos 			   res->freq,
    634      1.1.1.7  christos 			   (res->flags & WPA_SCAN_ASSOCIATED) ? " assoc" : "");
    635      1.1.1.7  christos 		if ((bss->flags & WPA_BSS_ASSOCIATED) ||
    636      1.1.1.7  christos 		    (!(res->flags & WPA_SCAN_ASSOCIATED) &&
    637      1.1.1.7  christos 		     !os_reltime_before(&bss->last_update, &update_time))) {
    638      1.1.1.7  christos 			wpa_printf(MSG_DEBUG,
    639      1.1.1.7  christos 				   "Ignore this BSS entry since the previous update looks more current");
    640      1.1.1.7  christos 			return bss;
    641      1.1.1.7  christos 		}
    642      1.1.1.7  christos 		wpa_printf(MSG_DEBUG,
    643      1.1.1.7  christos 			   "Accept this BSS entry since it looks more current than the previous update");
    644      1.1.1.7  christos 	}
    645      1.1.1.7  christos 
    646          1.1  christos 	changes = wpa_bss_compare_res(bss, res);
    647      1.1.1.6  christos 	if (changes & WPA_BSS_FREQ_CHANGED_FLAG)
    648      1.1.1.6  christos 		wpa_printf(MSG_DEBUG, "BSS: " MACSTR " changed freq %d --> %d",
    649      1.1.1.6  christos 			   MAC2STR(bss->bssid), bss->freq, res->freq);
    650          1.1  christos 	bss->scan_miss_count = 0;
    651          1.1  christos 	bss->last_update_idx = wpa_s->bss_update_idx;
    652      1.1.1.4  christos 	wpa_bss_copy_res(bss, res, fetch_time);
    653          1.1  christos 	/* Move the entry to the end of the list */
    654          1.1  christos 	dl_list_del(&bss->list);
    655      1.1.1.4  christos #ifdef CONFIG_P2P
    656      1.1.1.4  christos 	if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
    657      1.1.1.4  christos 	    !wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE)) {
    658      1.1.1.4  christos 		/*
    659      1.1.1.4  christos 		 * This can happen when non-P2P station interface runs a scan
    660      1.1.1.4  christos 		 * without P2P IE in the Probe Request frame. P2P GO would reply
    661      1.1.1.4  christos 		 * to that with a Probe Response that does not include P2P IE.
    662      1.1.1.4  christos 		 * Do not update the IEs in this BSS entry to avoid such loss of
    663      1.1.1.4  christos 		 * information that may be needed for P2P operations to
    664      1.1.1.4  christos 		 * determine group information.
    665      1.1.1.4  christos 		 */
    666      1.1.1.4  christos 		wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Do not update scan IEs for "
    667      1.1.1.4  christos 			MACSTR " since that would remove P2P IE information",
    668      1.1.1.4  christos 			MAC2STR(bss->bssid));
    669      1.1.1.4  christos 	} else
    670      1.1.1.4  christos #endif /* CONFIG_P2P */
    671          1.1  christos 	if (bss->ie_len + bss->beacon_ie_len >=
    672          1.1  christos 	    res->ie_len + res->beacon_ie_len) {
    673          1.1  christos 		os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
    674          1.1  christos 		bss->ie_len = res->ie_len;
    675          1.1  christos 		bss->beacon_ie_len = res->beacon_ie_len;
    676          1.1  christos 	} else {
    677          1.1  christos 		struct wpa_bss *nbss;
    678          1.1  christos 		struct dl_list *prev = bss->list_id.prev;
    679          1.1  christos 		dl_list_del(&bss->list_id);
    680          1.1  christos 		nbss = os_realloc(bss, sizeof(*bss) + res->ie_len +
    681          1.1  christos 				  res->beacon_ie_len);
    682          1.1  christos 		if (nbss) {
    683      1.1.1.3  christos 			unsigned int i;
    684      1.1.1.3  christos 			for (i = 0; i < wpa_s->last_scan_res_used; i++) {
    685      1.1.1.3  christos 				if (wpa_s->last_scan_res[i] == bss) {
    686      1.1.1.3  christos 					wpa_s->last_scan_res[i] = nbss;
    687      1.1.1.3  christos 					break;
    688      1.1.1.3  christos 				}
    689      1.1.1.3  christos 			}
    690      1.1.1.2  christos 			if (wpa_s->current_bss == bss)
    691      1.1.1.2  christos 				wpa_s->current_bss = nbss;
    692      1.1.1.5  christos 			wpa_bss_update_pending_connect(wpa_s, bss, nbss);
    693          1.1  christos 			bss = nbss;
    694          1.1  christos 			os_memcpy(bss + 1, res + 1,
    695          1.1  christos 				  res->ie_len + res->beacon_ie_len);
    696          1.1  christos 			bss->ie_len = res->ie_len;
    697          1.1  christos 			bss->beacon_ie_len = res->beacon_ie_len;
    698          1.1  christos 		}
    699          1.1  christos 		dl_list_add(prev, &bss->list_id);
    700          1.1  christos 	}
    701      1.1.1.3  christos 	if (changes & WPA_BSS_IES_CHANGED_FLAG)
    702      1.1.1.3  christos 		wpa_bss_set_hessid(bss);
    703          1.1  christos 	dl_list_add_tail(&wpa_s->bss, &bss->list);
    704          1.1  christos 
    705          1.1  christos 	notify_bss_changes(wpa_s, changes, bss);
    706          1.1  christos 
    707      1.1.1.3  christos 	return bss;
    708          1.1  christos }
    709          1.1  christos 
    710          1.1  christos 
    711      1.1.1.3  christos /**
    712      1.1.1.3  christos  * wpa_bss_update_start - Start a BSS table update from scan results
    713      1.1.1.3  christos  * @wpa_s: Pointer to wpa_supplicant data
    714      1.1.1.3  christos  *
    715      1.1.1.3  christos  * This function is called at the start of each BSS table update round for new
    716      1.1.1.3  christos  * scan results. The actual scan result entries are indicated with calls to
    717      1.1.1.3  christos  * wpa_bss_update_scan_res() and the update round is finished with a call to
    718      1.1.1.3  christos  * wpa_bss_update_end().
    719      1.1.1.3  christos  */
    720          1.1  christos void wpa_bss_update_start(struct wpa_supplicant *wpa_s)
    721          1.1  christos {
    722          1.1  christos 	wpa_s->bss_update_idx++;
    723      1.1.1.2  christos 	wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Start scan result update %u",
    724      1.1.1.2  christos 		wpa_s->bss_update_idx);
    725      1.1.1.3  christos 	wpa_s->last_scan_res_used = 0;
    726          1.1  christos }
    727          1.1  christos 
    728          1.1  christos 
    729      1.1.1.3  christos /**
    730      1.1.1.3  christos  * wpa_bss_update_scan_res - Update a BSS table entry based on a scan result
    731      1.1.1.3  christos  * @wpa_s: Pointer to wpa_supplicant data
    732      1.1.1.3  christos  * @res: Scan result
    733      1.1.1.4  christos  * @fetch_time: Time when the result was fetched from the driver
    734      1.1.1.3  christos  *
    735      1.1.1.3  christos  * This function updates a BSS table entry (or adds one) based on a scan result.
    736      1.1.1.3  christos  * This is called separately for each scan result between the calls to
    737      1.1.1.3  christos  * wpa_bss_update_start() and wpa_bss_update_end().
    738      1.1.1.3  christos  */
    739          1.1  christos void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
    740      1.1.1.4  christos 			     struct wpa_scan_res *res,
    741      1.1.1.4  christos 			     struct os_reltime *fetch_time)
    742          1.1  christos {
    743      1.1.1.5  christos 	const u8 *ssid, *p2p, *mesh;
    744          1.1  christos 	struct wpa_bss *bss;
    745          1.1  christos 
    746      1.1.1.4  christos 	if (wpa_s->conf->ignore_old_scan_res) {
    747      1.1.1.4  christos 		struct os_reltime update;
    748      1.1.1.4  christos 		calculate_update_time(fetch_time, res->age, &update);
    749      1.1.1.4  christos 		if (os_reltime_before(&update, &wpa_s->scan_trigger_time)) {
    750      1.1.1.4  christos 			struct os_reltime age;
    751      1.1.1.4  christos 			os_reltime_sub(&wpa_s->scan_trigger_time, &update,
    752      1.1.1.4  christos 				       &age);
    753      1.1.1.4  christos 			wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Ignore driver BSS "
    754      1.1.1.4  christos 				"table entry that is %u.%06u seconds older "
    755      1.1.1.4  christos 				"than our scan trigger",
    756      1.1.1.4  christos 				(unsigned int) age.sec,
    757      1.1.1.4  christos 				(unsigned int) age.usec);
    758      1.1.1.4  christos 			return;
    759      1.1.1.4  christos 		}
    760      1.1.1.4  christos 	}
    761      1.1.1.4  christos 
    762          1.1  christos 	ssid = wpa_scan_get_ie(res, WLAN_EID_SSID);
    763          1.1  christos 	if (ssid == NULL) {
    764      1.1.1.2  christos 		wpa_dbg(wpa_s, MSG_DEBUG, "BSS: No SSID IE included for "
    765      1.1.1.2  christos 			MACSTR, MAC2STR(res->bssid));
    766          1.1  christos 		return;
    767          1.1  christos 	}
    768      1.1.1.6  christos 	if (ssid[1] > SSID_MAX_LEN) {
    769      1.1.1.2  christos 		wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Too long SSID IE included for "
    770      1.1.1.2  christos 			MACSTR, MAC2STR(res->bssid));
    771          1.1  christos 		return;
    772          1.1  christos 	}
    773          1.1  christos 
    774      1.1.1.2  christos 	p2p = wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE);
    775      1.1.1.3  christos #ifdef CONFIG_P2P
    776      1.1.1.3  christos 	if (p2p == NULL &&
    777      1.1.1.3  christos 	    wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
    778      1.1.1.3  christos 		/*
    779      1.1.1.3  christos 		 * If it's a P2P specific interface, then don't update
    780      1.1.1.3  christos 		 * the scan result without a P2P IE.
    781      1.1.1.3  christos 		 */
    782      1.1.1.3  christos 		wpa_printf(MSG_DEBUG, "BSS: No P2P IE - skipping BSS " MACSTR
    783      1.1.1.3  christos 			   " update for P2P interface", MAC2STR(res->bssid));
    784      1.1.1.3  christos 		return;
    785      1.1.1.3  christos 	}
    786      1.1.1.3  christos #endif /* CONFIG_P2P */
    787      1.1.1.2  christos 	if (p2p && ssid[1] == P2P_WILDCARD_SSID_LEN &&
    788      1.1.1.2  christos 	    os_memcmp(ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 0)
    789      1.1.1.2  christos 		return; /* Skip P2P listen discovery results here */
    790      1.1.1.2  christos 
    791          1.1  christos 	/* TODO: add option for ignoring BSSes we are not interested in
    792          1.1  christos 	 * (to save memory) */
    793      1.1.1.5  christos 
    794      1.1.1.5  christos 	mesh = wpa_scan_get_ie(res, WLAN_EID_MESH_ID);
    795      1.1.1.6  christos 	if (mesh && mesh[1] <= SSID_MAX_LEN)
    796      1.1.1.5  christos 		ssid = mesh;
    797      1.1.1.5  christos 
    798          1.1  christos 	bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
    799          1.1  christos 	if (bss == NULL)
    800      1.1.1.4  christos 		bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res, fetch_time);
    801      1.1.1.4  christos 	else {
    802      1.1.1.4  christos 		bss = wpa_bss_update(wpa_s, bss, res, fetch_time);
    803      1.1.1.4  christos 		if (wpa_s->last_scan_res) {
    804      1.1.1.4  christos 			unsigned int i;
    805      1.1.1.4  christos 			for (i = 0; i < wpa_s->last_scan_res_used; i++) {
    806      1.1.1.4  christos 				if (bss == wpa_s->last_scan_res[i]) {
    807      1.1.1.4  christos 					/* Already in the list */
    808      1.1.1.4  christos 					return;
    809      1.1.1.4  christos 				}
    810      1.1.1.4  christos 			}
    811      1.1.1.4  christos 		}
    812      1.1.1.4  christos 	}
    813      1.1.1.3  christos 
    814      1.1.1.3  christos 	if (bss == NULL)
    815      1.1.1.3  christos 		return;
    816      1.1.1.3  christos 	if (wpa_s->last_scan_res_used >= wpa_s->last_scan_res_size) {
    817      1.1.1.3  christos 		struct wpa_bss **n;
    818      1.1.1.3  christos 		unsigned int siz;
    819      1.1.1.3  christos 		if (wpa_s->last_scan_res_size == 0)
    820      1.1.1.3  christos 			siz = 32;
    821      1.1.1.3  christos 		else
    822      1.1.1.3  christos 			siz = wpa_s->last_scan_res_size * 2;
    823      1.1.1.3  christos 		n = os_realloc_array(wpa_s->last_scan_res, siz,
    824      1.1.1.3  christos 				     sizeof(struct wpa_bss *));
    825      1.1.1.3  christos 		if (n == NULL)
    826      1.1.1.3  christos 			return;
    827      1.1.1.3  christos 		wpa_s->last_scan_res = n;
    828      1.1.1.3  christos 		wpa_s->last_scan_res_size = siz;
    829      1.1.1.3  christos 	}
    830      1.1.1.3  christos 
    831      1.1.1.4  christos 	if (wpa_s->last_scan_res)
    832      1.1.1.4  christos 		wpa_s->last_scan_res[wpa_s->last_scan_res_used++] = bss;
    833          1.1  christos }
    834          1.1  christos 
    835          1.1  christos 
    836          1.1  christos static int wpa_bss_included_in_scan(const struct wpa_bss *bss,
    837          1.1  christos 				    const struct scan_info *info)
    838          1.1  christos {
    839          1.1  christos 	int found;
    840          1.1  christos 	size_t i;
    841          1.1  christos 
    842          1.1  christos 	if (info == NULL)
    843          1.1  christos 		return 1;
    844          1.1  christos 
    845          1.1  christos 	if (info->num_freqs) {
    846          1.1  christos 		found = 0;
    847          1.1  christos 		for (i = 0; i < info->num_freqs; i++) {
    848          1.1  christos 			if (bss->freq == info->freqs[i]) {
    849          1.1  christos 				found = 1;
    850          1.1  christos 				break;
    851          1.1  christos 			}
    852          1.1  christos 		}
    853          1.1  christos 		if (!found)
    854          1.1  christos 			return 0;
    855          1.1  christos 	}
    856          1.1  christos 
    857          1.1  christos 	if (info->num_ssids) {
    858          1.1  christos 		found = 0;
    859          1.1  christos 		for (i = 0; i < info->num_ssids; i++) {
    860          1.1  christos 			const struct wpa_driver_scan_ssid *s = &info->ssids[i];
    861          1.1  christos 			if ((s->ssid == NULL || s->ssid_len == 0) ||
    862          1.1  christos 			    (s->ssid_len == bss->ssid_len &&
    863          1.1  christos 			     os_memcmp(s->ssid, bss->ssid, bss->ssid_len) ==
    864          1.1  christos 			     0)) {
    865          1.1  christos 				found = 1;
    866          1.1  christos 				break;
    867          1.1  christos 			}
    868          1.1  christos 		}
    869          1.1  christos 		if (!found)
    870          1.1  christos 			return 0;
    871          1.1  christos 	}
    872          1.1  christos 
    873          1.1  christos 	return 1;
    874          1.1  christos }
    875          1.1  christos 
    876          1.1  christos 
    877      1.1.1.3  christos /**
    878      1.1.1.3  christos  * wpa_bss_update_end - End a BSS table update from scan results
    879      1.1.1.3  christos  * @wpa_s: Pointer to wpa_supplicant data
    880      1.1.1.3  christos  * @info: Information about scan parameters
    881      1.1.1.3  christos  * @new_scan: Whether this update round was based on a new scan
    882      1.1.1.3  christos  *
    883      1.1.1.3  christos  * This function is called at the end of each BSS table update round for new
    884      1.1.1.3  christos  * scan results. The start of the update was indicated with a call to
    885      1.1.1.3  christos  * wpa_bss_update_start().
    886      1.1.1.3  christos  */
    887          1.1  christos void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
    888          1.1  christos 			int new_scan)
    889          1.1  christos {
    890          1.1  christos 	struct wpa_bss *bss, *n;
    891          1.1  christos 
    892      1.1.1.4  christos 	os_get_reltime(&wpa_s->last_scan);
    893      1.1.1.6  christos 	if ((info && info->aborted) || !new_scan)
    894          1.1  christos 		return; /* do not expire entries without new scan */
    895          1.1  christos 
    896          1.1  christos 	dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
    897          1.1  christos 		if (wpa_bss_in_use(wpa_s, bss))
    898          1.1  christos 			continue;
    899          1.1  christos 		if (!wpa_bss_included_in_scan(bss, info))
    900          1.1  christos 			continue; /* expire only BSSes that were scanned */
    901          1.1  christos 		if (bss->last_update_idx < wpa_s->bss_update_idx)
    902          1.1  christos 			bss->scan_miss_count++;
    903      1.1.1.2  christos 		if (bss->scan_miss_count >=
    904      1.1.1.2  christos 		    wpa_s->conf->bss_expiration_scan_count) {
    905      1.1.1.3  christos 			wpa_bss_remove(wpa_s, bss, "no match in scan");
    906          1.1  christos 		}
    907          1.1  christos 	}
    908      1.1.1.3  christos 
    909      1.1.1.4  christos 	wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%u/%u",
    910      1.1.1.4  christos 		   wpa_s->last_scan_res_used, wpa_s->last_scan_res_size);
    911          1.1  christos }
    912          1.1  christos 
    913          1.1  christos 
    914      1.1.1.3  christos /**
    915      1.1.1.3  christos  * wpa_bss_flush_by_age - Flush old BSS entries
    916      1.1.1.3  christos  * @wpa_s: Pointer to wpa_supplicant data
    917      1.1.1.3  christos  * @age: Maximum entry age in seconds
    918      1.1.1.3  christos  *
    919      1.1.1.3  christos  * Remove BSS entries that have not been updated during the last @age seconds.
    920      1.1.1.3  christos  */
    921      1.1.1.2  christos void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age)
    922          1.1  christos {
    923          1.1  christos 	struct wpa_bss *bss, *n;
    924      1.1.1.4  christos 	struct os_reltime t;
    925          1.1  christos 
    926          1.1  christos 	if (dl_list_empty(&wpa_s->bss))
    927          1.1  christos 		return;
    928          1.1  christos 
    929      1.1.1.4  christos 	os_get_reltime(&t);
    930      1.1.1.2  christos 	t.sec -= age;
    931          1.1  christos 
    932          1.1  christos 	dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
    933          1.1  christos 		if (wpa_bss_in_use(wpa_s, bss))
    934          1.1  christos 			continue;
    935          1.1  christos 
    936      1.1.1.4  christos 		if (os_reltime_before(&bss->last_update, &t)) {
    937      1.1.1.3  christos 			wpa_bss_remove(wpa_s, bss, __func__);
    938          1.1  christos 		} else
    939          1.1  christos 			break;
    940          1.1  christos 	}
    941      1.1.1.2  christos }
    942      1.1.1.2  christos 
    943      1.1.1.2  christos 
    944      1.1.1.3  christos /**
    945      1.1.1.3  christos  * wpa_bss_init - Initialize BSS table
    946      1.1.1.3  christos  * @wpa_s: Pointer to wpa_supplicant data
    947      1.1.1.3  christos  * Returns: 0 on success, -1 on failure
    948      1.1.1.3  christos  *
    949      1.1.1.3  christos  * This prepares BSS table lists and timer for periodic updates. The BSS table
    950      1.1.1.3  christos  * is deinitialized with wpa_bss_deinit() once not needed anymore.
    951      1.1.1.3  christos  */
    952          1.1  christos int wpa_bss_init(struct wpa_supplicant *wpa_s)
    953          1.1  christos {
    954          1.1  christos 	dl_list_init(&wpa_s->bss);
    955          1.1  christos 	dl_list_init(&wpa_s->bss_id);
    956          1.1  christos 	return 0;
    957          1.1  christos }
    958          1.1  christos 
    959          1.1  christos 
    960      1.1.1.3  christos /**
    961      1.1.1.3  christos  * wpa_bss_flush - Flush all unused BSS entries
    962      1.1.1.3  christos  * @wpa_s: Pointer to wpa_supplicant data
    963      1.1.1.3  christos  */
    964      1.1.1.2  christos void wpa_bss_flush(struct wpa_supplicant *wpa_s)
    965          1.1  christos {
    966          1.1  christos 	struct wpa_bss *bss, *n;
    967      1.1.1.2  christos 
    968      1.1.1.4  christos 	wpa_s->clear_driver_scan_cache = 1;
    969      1.1.1.4  christos 
    970          1.1  christos 	if (wpa_s->bss.next == NULL)
    971          1.1  christos 		return; /* BSS table not yet initialized */
    972      1.1.1.2  christos 
    973      1.1.1.2  christos 	dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
    974      1.1.1.2  christos 		if (wpa_bss_in_use(wpa_s, bss))
    975      1.1.1.2  christos 			continue;
    976      1.1.1.3  christos 		wpa_bss_remove(wpa_s, bss, __func__);
    977      1.1.1.2  christos 	}
    978      1.1.1.2  christos }
    979      1.1.1.2  christos 
    980      1.1.1.2  christos 
    981      1.1.1.3  christos /**
    982      1.1.1.3  christos  * wpa_bss_deinit - Deinitialize BSS table
    983      1.1.1.3  christos  * @wpa_s: Pointer to wpa_supplicant data
    984      1.1.1.3  christos  */
    985      1.1.1.2  christos void wpa_bss_deinit(struct wpa_supplicant *wpa_s)
    986      1.1.1.2  christos {
    987      1.1.1.2  christos 	wpa_bss_flush(wpa_s);
    988          1.1  christos }
    989          1.1  christos 
    990          1.1  christos 
    991      1.1.1.3  christos /**
    992      1.1.1.3  christos  * wpa_bss_get_bssid - Fetch a BSS table entry based on BSSID
    993      1.1.1.3  christos  * @wpa_s: Pointer to wpa_supplicant data
    994      1.1.1.3  christos  * @bssid: BSSID
    995      1.1.1.3  christos  * Returns: Pointer to the BSS entry or %NULL if not found
    996      1.1.1.3  christos  */
    997          1.1  christos struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
    998          1.1  christos 				   const u8 *bssid)
    999          1.1  christos {
   1000          1.1  christos 	struct wpa_bss *bss;
   1001      1.1.1.3  christos 	if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
   1002      1.1.1.3  christos 		return NULL;
   1003      1.1.1.2  christos 	dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
   1004          1.1  christos 		if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
   1005          1.1  christos 			return bss;
   1006          1.1  christos 	}
   1007          1.1  christos 	return NULL;
   1008          1.1  christos }
   1009          1.1  christos 
   1010          1.1  christos 
   1011      1.1.1.4  christos /**
   1012      1.1.1.4  christos  * wpa_bss_get_bssid_latest - Fetch the latest BSS table entry based on BSSID
   1013      1.1.1.4  christos  * @wpa_s: Pointer to wpa_supplicant data
   1014      1.1.1.4  christos  * @bssid: BSSID
   1015      1.1.1.4  christos  * Returns: Pointer to the BSS entry or %NULL if not found
   1016      1.1.1.4  christos  *
   1017      1.1.1.4  christos  * This function is like wpa_bss_get_bssid(), but full BSS table is iterated to
   1018      1.1.1.4  christos  * find the entry that has the most recent update. This can help in finding the
   1019      1.1.1.4  christos  * correct entry in cases where the SSID of the AP may have changed recently
   1020      1.1.1.4  christos  * (e.g., in WPS reconfiguration cases).
   1021      1.1.1.4  christos  */
   1022      1.1.1.4  christos struct wpa_bss * wpa_bss_get_bssid_latest(struct wpa_supplicant *wpa_s,
   1023      1.1.1.4  christos 					  const u8 *bssid)
   1024      1.1.1.4  christos {
   1025      1.1.1.4  christos 	struct wpa_bss *bss, *found = NULL;
   1026      1.1.1.4  christos 	if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
   1027      1.1.1.4  christos 		return NULL;
   1028      1.1.1.4  christos 	dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
   1029      1.1.1.4  christos 		if (os_memcmp(bss->bssid, bssid, ETH_ALEN) != 0)
   1030      1.1.1.4  christos 			continue;
   1031      1.1.1.4  christos 		if (found == NULL ||
   1032      1.1.1.4  christos 		    os_reltime_before(&found->last_update, &bss->last_update))
   1033      1.1.1.4  christos 			found = bss;
   1034      1.1.1.4  christos 	}
   1035      1.1.1.4  christos 	return found;
   1036      1.1.1.4  christos }
   1037      1.1.1.4  christos 
   1038      1.1.1.4  christos 
   1039      1.1.1.2  christos #ifdef CONFIG_P2P
   1040      1.1.1.3  christos /**
   1041      1.1.1.3  christos  * wpa_bss_get_p2p_dev_addr - Fetch a BSS table entry based on P2P Device Addr
   1042      1.1.1.3  christos  * @wpa_s: Pointer to wpa_supplicant data
   1043      1.1.1.3  christos  * @dev_addr: P2P Device Address of the GO
   1044      1.1.1.3  christos  * Returns: Pointer to the BSS entry or %NULL if not found
   1045      1.1.1.3  christos  */
   1046      1.1.1.2  christos struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s,
   1047      1.1.1.2  christos 					  const u8 *dev_addr)
   1048      1.1.1.2  christos {
   1049      1.1.1.2  christos 	struct wpa_bss *bss;
   1050      1.1.1.2  christos 	dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
   1051      1.1.1.2  christos 		u8 addr[ETH_ALEN];
   1052      1.1.1.2  christos 		if (p2p_parse_dev_addr((const u8 *) (bss + 1), bss->ie_len,
   1053      1.1.1.2  christos 				       addr) == 0 &&
   1054      1.1.1.2  christos 		    os_memcmp(addr, dev_addr, ETH_ALEN) == 0)
   1055      1.1.1.2  christos 			return bss;
   1056      1.1.1.2  christos 	}
   1057      1.1.1.2  christos 	return NULL;
   1058      1.1.1.2  christos }
   1059      1.1.1.2  christos #endif /* CONFIG_P2P */
   1060      1.1.1.2  christos 
   1061      1.1.1.2  christos 
   1062      1.1.1.3  christos /**
   1063      1.1.1.3  christos  * wpa_bss_get_id - Fetch a BSS table entry based on identifier
   1064      1.1.1.3  christos  * @wpa_s: Pointer to wpa_supplicant data
   1065      1.1.1.3  christos  * @id: Unique identifier (struct wpa_bss::id) assigned for the entry
   1066      1.1.1.3  christos  * Returns: Pointer to the BSS entry or %NULL if not found
   1067      1.1.1.3  christos  */
   1068          1.1  christos struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id)
   1069          1.1  christos {
   1070          1.1  christos 	struct wpa_bss *bss;
   1071          1.1  christos 	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
   1072          1.1  christos 		if (bss->id == id)
   1073          1.1  christos 			return bss;
   1074          1.1  christos 	}
   1075          1.1  christos 	return NULL;
   1076          1.1  christos }
   1077          1.1  christos 
   1078          1.1  christos 
   1079      1.1.1.3  christos /**
   1080      1.1.1.4  christos  * wpa_bss_get_id_range - Fetch a BSS table entry based on identifier range
   1081      1.1.1.4  christos  * @wpa_s: Pointer to wpa_supplicant data
   1082      1.1.1.4  christos  * @idf: Smallest allowed identifier assigned for the entry
   1083      1.1.1.4  christos  * @idf: Largest allowed identifier assigned for the entry
   1084      1.1.1.4  christos  * Returns: Pointer to the BSS entry or %NULL if not found
   1085      1.1.1.4  christos  *
   1086      1.1.1.4  christos  * This function is similar to wpa_bss_get_id() but allows a BSS entry with the
   1087      1.1.1.4  christos  * smallest id value to be fetched within the specified range without the
   1088      1.1.1.4  christos  * caller having to know the exact id.
   1089      1.1.1.4  christos  */
   1090      1.1.1.4  christos struct wpa_bss * wpa_bss_get_id_range(struct wpa_supplicant *wpa_s,
   1091      1.1.1.4  christos 				      unsigned int idf, unsigned int idl)
   1092      1.1.1.4  christos {
   1093      1.1.1.4  christos 	struct wpa_bss *bss;
   1094      1.1.1.4  christos 	dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
   1095      1.1.1.4  christos 		if (bss->id >= idf && bss->id <= idl)
   1096      1.1.1.4  christos 			return bss;
   1097      1.1.1.4  christos 	}
   1098      1.1.1.4  christos 	return NULL;
   1099      1.1.1.4  christos }
   1100      1.1.1.4  christos 
   1101      1.1.1.4  christos 
   1102      1.1.1.4  christos /**
   1103      1.1.1.3  christos  * wpa_bss_get_ie - Fetch a specified information element from a BSS entry
   1104      1.1.1.3  christos  * @bss: BSS table entry
   1105      1.1.1.3  christos  * @ie: Information element identitifier (WLAN_EID_*)
   1106      1.1.1.3  christos  * Returns: Pointer to the information element (id field) or %NULL if not found
   1107      1.1.1.3  christos  *
   1108      1.1.1.3  christos  * This function returns the first matching information element in the BSS
   1109      1.1.1.3  christos  * entry.
   1110      1.1.1.3  christos  */
   1111          1.1  christos const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
   1112          1.1  christos {
   1113      1.1.1.6  christos 	return get_ie((const u8 *) (bss + 1), bss->ie_len, ie);
   1114          1.1  christos }
   1115          1.1  christos 
   1116          1.1  christos 
   1117      1.1.1.3  christos /**
   1118      1.1.1.3  christos  * wpa_bss_get_vendor_ie - Fetch a vendor information element from a BSS entry
   1119      1.1.1.3  christos  * @bss: BSS table entry
   1120      1.1.1.3  christos  * @vendor_type: Vendor type (four octets starting the IE payload)
   1121      1.1.1.3  christos  * Returns: Pointer to the information element (id field) or %NULL if not found
   1122      1.1.1.3  christos  *
   1123      1.1.1.3  christos  * This function returns the first matching information element in the BSS
   1124      1.1.1.3  christos  * entry.
   1125      1.1.1.3  christos  */
   1126          1.1  christos const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
   1127          1.1  christos {
   1128          1.1  christos 	const u8 *end, *pos;
   1129          1.1  christos 
   1130          1.1  christos 	pos = (const u8 *) (bss + 1);
   1131          1.1  christos 	end = pos + bss->ie_len;
   1132          1.1  christos 
   1133      1.1.1.6  christos 	while (end - pos > 1) {
   1134      1.1.1.6  christos 		if (2 + pos[1] > end - pos)
   1135          1.1  christos 			break;
   1136          1.1  christos 		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
   1137          1.1  christos 		    vendor_type == WPA_GET_BE32(&pos[2]))
   1138          1.1  christos 			return pos;
   1139          1.1  christos 		pos += 2 + pos[1];
   1140          1.1  christos 	}
   1141          1.1  christos 
   1142          1.1  christos 	return NULL;
   1143          1.1  christos }
   1144          1.1  christos 
   1145          1.1  christos 
   1146      1.1.1.3  christos /**
   1147      1.1.1.4  christos  * wpa_bss_get_vendor_ie_beacon - Fetch a vendor information from a BSS entry
   1148      1.1.1.4  christos  * @bss: BSS table entry
   1149      1.1.1.4  christos  * @vendor_type: Vendor type (four octets starting the IE payload)
   1150      1.1.1.4  christos  * Returns: Pointer to the information element (id field) or %NULL if not found
   1151      1.1.1.4  christos  *
   1152      1.1.1.4  christos  * This function returns the first matching information element in the BSS
   1153      1.1.1.4  christos  * entry.
   1154      1.1.1.4  christos  *
   1155      1.1.1.4  christos  * This function is like wpa_bss_get_vendor_ie(), but uses IE buffer only
   1156      1.1.1.4  christos  * from Beacon frames instead of either Beacon or Probe Response frames.
   1157      1.1.1.4  christos  */
   1158      1.1.1.4  christos const u8 * wpa_bss_get_vendor_ie_beacon(const struct wpa_bss *bss,
   1159      1.1.1.4  christos 					u32 vendor_type)
   1160      1.1.1.4  christos {
   1161      1.1.1.4  christos 	const u8 *end, *pos;
   1162      1.1.1.4  christos 
   1163      1.1.1.4  christos 	if (bss->beacon_ie_len == 0)
   1164      1.1.1.4  christos 		return NULL;
   1165      1.1.1.4  christos 
   1166      1.1.1.4  christos 	pos = (const u8 *) (bss + 1);
   1167      1.1.1.4  christos 	pos += bss->ie_len;
   1168      1.1.1.4  christos 	end = pos + bss->beacon_ie_len;
   1169      1.1.1.4  christos 
   1170      1.1.1.6  christos 	while (end - pos > 1) {
   1171      1.1.1.6  christos 		if (2 + pos[1] > end - pos)
   1172      1.1.1.4  christos 			break;
   1173      1.1.1.4  christos 		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
   1174      1.1.1.4  christos 		    vendor_type == WPA_GET_BE32(&pos[2]))
   1175      1.1.1.4  christos 			return pos;
   1176      1.1.1.4  christos 		pos += 2 + pos[1];
   1177      1.1.1.4  christos 	}
   1178      1.1.1.4  christos 
   1179      1.1.1.4  christos 	return NULL;
   1180      1.1.1.4  christos }
   1181      1.1.1.4  christos 
   1182      1.1.1.4  christos 
   1183      1.1.1.4  christos /**
   1184      1.1.1.3  christos  * wpa_bss_get_vendor_ie_multi - Fetch vendor IE data from a BSS entry
   1185      1.1.1.3  christos  * @bss: BSS table entry
   1186      1.1.1.3  christos  * @vendor_type: Vendor type (four octets starting the IE payload)
   1187      1.1.1.3  christos  * Returns: Pointer to the information element payload or %NULL if not found
   1188      1.1.1.3  christos  *
   1189      1.1.1.3  christos  * This function returns concatenated payload of possibly fragmented vendor
   1190      1.1.1.3  christos  * specific information elements in the BSS entry. The caller is responsible for
   1191      1.1.1.3  christos  * freeing the returned buffer.
   1192      1.1.1.3  christos  */
   1193          1.1  christos struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
   1194          1.1  christos 					    u32 vendor_type)
   1195          1.1  christos {
   1196          1.1  christos 	struct wpabuf *buf;
   1197          1.1  christos 	const u8 *end, *pos;
   1198          1.1  christos 
   1199          1.1  christos 	buf = wpabuf_alloc(bss->ie_len);
   1200          1.1  christos 	if (buf == NULL)
   1201          1.1  christos 		return NULL;
   1202          1.1  christos 
   1203          1.1  christos 	pos = (const u8 *) (bss + 1);
   1204          1.1  christos 	end = pos + bss->ie_len;
   1205          1.1  christos 
   1206      1.1.1.6  christos 	while (end - pos > 1) {
   1207      1.1.1.6  christos 		if (2 + pos[1] > end - pos)
   1208          1.1  christos 			break;
   1209          1.1  christos 		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
   1210          1.1  christos 		    vendor_type == WPA_GET_BE32(&pos[2]))
   1211          1.1  christos 			wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
   1212          1.1  christos 		pos += 2 + pos[1];
   1213          1.1  christos 	}
   1214          1.1  christos 
   1215          1.1  christos 	if (wpabuf_len(buf) == 0) {
   1216          1.1  christos 		wpabuf_free(buf);
   1217          1.1  christos 		buf = NULL;
   1218          1.1  christos 	}
   1219          1.1  christos 
   1220          1.1  christos 	return buf;
   1221          1.1  christos }
   1222          1.1  christos 
   1223          1.1  christos 
   1224      1.1.1.3  christos /**
   1225      1.1.1.3  christos  * wpa_bss_get_vendor_ie_multi_beacon - Fetch vendor IE data from a BSS entry
   1226      1.1.1.3  christos  * @bss: BSS table entry
   1227      1.1.1.3  christos  * @vendor_type: Vendor type (four octets starting the IE payload)
   1228      1.1.1.3  christos  * Returns: Pointer to the information element payload or %NULL if not found
   1229      1.1.1.3  christos  *
   1230      1.1.1.3  christos  * This function returns concatenated payload of possibly fragmented vendor
   1231      1.1.1.3  christos  * specific information elements in the BSS entry. The caller is responsible for
   1232      1.1.1.3  christos  * freeing the returned buffer.
   1233      1.1.1.3  christos  *
   1234      1.1.1.3  christos  * This function is like wpa_bss_get_vendor_ie_multi(), but uses IE buffer only
   1235      1.1.1.3  christos  * from Beacon frames instead of either Beacon or Probe Response frames.
   1236      1.1.1.3  christos  */
   1237      1.1.1.3  christos struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss,
   1238      1.1.1.3  christos 						   u32 vendor_type)
   1239      1.1.1.3  christos {
   1240      1.1.1.3  christos 	struct wpabuf *buf;
   1241      1.1.1.3  christos 	const u8 *end, *pos;
   1242      1.1.1.3  christos 
   1243      1.1.1.3  christos 	buf = wpabuf_alloc(bss->beacon_ie_len);
   1244      1.1.1.3  christos 	if (buf == NULL)
   1245      1.1.1.3  christos 		return NULL;
   1246      1.1.1.3  christos 
   1247      1.1.1.3  christos 	pos = (const u8 *) (bss + 1);
   1248      1.1.1.3  christos 	pos += bss->ie_len;
   1249      1.1.1.3  christos 	end = pos + bss->beacon_ie_len;
   1250      1.1.1.3  christos 
   1251      1.1.1.6  christos 	while (end - pos > 1) {
   1252      1.1.1.6  christos 		if (2 + pos[1] > end - pos)
   1253      1.1.1.3  christos 			break;
   1254      1.1.1.3  christos 		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
   1255      1.1.1.3  christos 		    vendor_type == WPA_GET_BE32(&pos[2]))
   1256      1.1.1.3  christos 			wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
   1257      1.1.1.3  christos 		pos += 2 + pos[1];
   1258      1.1.1.3  christos 	}
   1259      1.1.1.3  christos 
   1260      1.1.1.3  christos 	if (wpabuf_len(buf) == 0) {
   1261      1.1.1.3  christos 		wpabuf_free(buf);
   1262      1.1.1.3  christos 		buf = NULL;
   1263      1.1.1.3  christos 	}
   1264      1.1.1.3  christos 
   1265      1.1.1.3  christos 	return buf;
   1266      1.1.1.3  christos }
   1267      1.1.1.3  christos 
   1268      1.1.1.3  christos 
   1269      1.1.1.3  christos /**
   1270      1.1.1.3  christos  * wpa_bss_get_max_rate - Get maximum legacy TX rate supported in a BSS
   1271      1.1.1.3  christos  * @bss: BSS table entry
   1272      1.1.1.3  christos  * Returns: Maximum legacy rate in units of 500 kbps
   1273      1.1.1.3  christos  */
   1274          1.1  christos int wpa_bss_get_max_rate(const struct wpa_bss *bss)
   1275          1.1  christos {
   1276          1.1  christos 	int rate = 0;
   1277          1.1  christos 	const u8 *ie;
   1278          1.1  christos 	int i;
   1279          1.1  christos 
   1280          1.1  christos 	ie = wpa_bss_get_ie(bss, WLAN_EID_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 	ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
   1287          1.1  christos 	for (i = 0; ie && i < ie[1]; i++) {
   1288          1.1  christos 		if ((ie[i + 2] & 0x7f) > rate)
   1289          1.1  christos 			rate = ie[i + 2] & 0x7f;
   1290          1.1  christos 	}
   1291          1.1  christos 
   1292          1.1  christos 	return rate;
   1293          1.1  christos }
   1294          1.1  christos 
   1295          1.1  christos 
   1296      1.1.1.3  christos /**
   1297      1.1.1.3  christos  * wpa_bss_get_bit_rates - Get legacy TX rates supported in a BSS
   1298      1.1.1.3  christos  * @bss: BSS table entry
   1299      1.1.1.3  christos  * @rates: Buffer for returning a pointer to the rates list (units of 500 kbps)
   1300      1.1.1.3  christos  * Returns: number of legacy TX rates or -1 on failure
   1301      1.1.1.3  christos  *
   1302      1.1.1.3  christos  * The caller is responsible for freeing the returned buffer with os_free() in
   1303      1.1.1.3  christos  * case of success.
   1304      1.1.1.3  christos  */
   1305          1.1  christos int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates)
   1306          1.1  christos {
   1307          1.1  christos 	const u8 *ie, *ie2;
   1308          1.1  christos 	int i, j;
   1309          1.1  christos 	unsigned int len;
   1310          1.1  christos 	u8 *r;
   1311          1.1  christos 
   1312          1.1  christos 	ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
   1313          1.1  christos 	ie2 = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
   1314          1.1  christos 
   1315          1.1  christos 	len = (ie ? ie[1] : 0) + (ie2 ? ie2[1] : 0);
   1316          1.1  christos 
   1317          1.1  christos 	r = os_malloc(len);
   1318          1.1  christos 	if (!r)
   1319          1.1  christos 		return -1;
   1320          1.1  christos 
   1321          1.1  christos 	for (i = 0; ie && i < ie[1]; i++)
   1322          1.1  christos 		r[i] = ie[i + 2] & 0x7f;
   1323          1.1  christos 
   1324          1.1  christos 	for (j = 0; ie2 && j < ie2[1]; j++)
   1325          1.1  christos 		r[i + j] = ie2[j + 2] & 0x7f;
   1326          1.1  christos 
   1327          1.1  christos 	*rates = r;
   1328          1.1  christos 	return len;
   1329          1.1  christos }
   1330      1.1.1.7  christos 
   1331      1.1.1.7  christos 
   1332      1.1.1.7  christos #ifdef CONFIG_FILS
   1333      1.1.1.7  christos const u8 * wpa_bss_get_fils_cache_id(struct wpa_bss *bss)
   1334      1.1.1.7  christos {
   1335      1.1.1.7  christos 	const u8 *ie;
   1336      1.1.1.7  christos 
   1337      1.1.1.7  christos 	if (bss) {
   1338      1.1.1.7  christos 		ie = wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION);
   1339      1.1.1.7  christos 		if (ie && ie[1] >= 4 && WPA_GET_LE16(ie + 2) & BIT(7))
   1340      1.1.1.7  christos 			return ie + 4;
   1341      1.1.1.7  christos 	}
   1342      1.1.1.7  christos 
   1343      1.1.1.7  christos 	return NULL;
   1344      1.1.1.7  christos }
   1345      1.1.1.7  christos #endif /* CONFIG_FILS */
   1346  1.1.1.7.2.1    martin 
   1347  1.1.1.7.2.1    martin 
   1348  1.1.1.7.2.1    martin int wpa_bss_ext_capab(const struct wpa_bss *bss, unsigned int capab)
   1349  1.1.1.7.2.1    martin {
   1350  1.1.1.7.2.1    martin 	return ieee802_11_ext_capab(wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB),
   1351  1.1.1.7.2.1    martin 				    capab);
   1352  1.1.1.7.2.1    martin }
   1353