Home | History | Annotate | Line # | Download | only in wpa_supplicant
bss.c revision 1.1.1.9
      1      1.1  christos /*
      2      1.1  christos  * BSS table
      3  1.1.1.8  christos  * 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.1.9  christos #include "rsn_supp/wpa.h"
     17      1.1  christos #include "wpa_supplicant_i.h"
     18      1.1  christos #include "config.h"
     19      1.1  christos #include "notify.h"
     20      1.1  christos #include "scan.h"
     21  1.1.1.9  christos #include "bssid_ignore.h"
     22      1.1  christos #include "bss.h"
     23      1.1  christos 
     24  1.1.1.3  christos static void wpa_bss_set_hessid(struct wpa_bss *bss)
     25  1.1.1.3  christos {
     26  1.1.1.3  christos #ifdef CONFIG_INTERWORKING
     27  1.1.1.3  christos 	const u8 *ie = wpa_bss_get_ie(bss, WLAN_EID_INTERWORKING);
     28  1.1.1.3  christos 	if (ie == NULL || (ie[1] != 7 && ie[1] != 9)) {
     29  1.1.1.3  christos 		os_memset(bss->hessid, 0, ETH_ALEN);
     30  1.1.1.3  christos 		return;
     31  1.1.1.3  christos 	}
     32  1.1.1.3  christos 	if (ie[1] == 7)
     33  1.1.1.3  christos 		os_memcpy(bss->hessid, ie + 3, ETH_ALEN);
     34  1.1.1.3  christos 	else
     35  1.1.1.3  christos 		os_memcpy(bss->hessid, ie + 5, ETH_ALEN);
     36  1.1.1.3  christos #endif /* CONFIG_INTERWORKING */
     37  1.1.1.3  christos }
     38  1.1.1.3  christos 
     39  1.1.1.3  christos 
     40  1.1.1.3  christos /**
     41  1.1.1.3  christos  * wpa_bss_anqp_alloc - Allocate ANQP data structure for a BSS entry
     42  1.1.1.3  christos  * Returns: Allocated ANQP data structure or %NULL on failure
     43  1.1.1.3  christos  *
     44  1.1.1.3  christos  * The allocated ANQP data structure has its users count set to 1. It may be
     45  1.1.1.3  christos  * shared by multiple BSS entries and each shared entry is freed with
     46  1.1.1.3  christos  * wpa_bss_anqp_free().
     47  1.1.1.3  christos  */
     48  1.1.1.3  christos struct wpa_bss_anqp * wpa_bss_anqp_alloc(void)
     49  1.1.1.3  christos {
     50  1.1.1.3  christos 	struct wpa_bss_anqp *anqp;
     51  1.1.1.3  christos 	anqp = os_zalloc(sizeof(*anqp));
     52  1.1.1.3  christos 	if (anqp == NULL)
     53  1.1.1.3  christos 		return NULL;
     54  1.1.1.6  christos #ifdef CONFIG_INTERWORKING
     55  1.1.1.6  christos 	dl_list_init(&anqp->anqp_elems);
     56  1.1.1.6  christos #endif /* CONFIG_INTERWORKING */
     57  1.1.1.3  christos 	anqp->users = 1;
     58  1.1.1.3  christos 	return anqp;
     59  1.1.1.3  christos }
     60  1.1.1.3  christos 
     61  1.1.1.3  christos 
     62  1.1.1.3  christos /**
     63  1.1.1.3  christos  * wpa_bss_anqp_clone - Clone an ANQP data structure
     64  1.1.1.3  christos  * @anqp: ANQP data structure from wpa_bss_anqp_alloc()
     65  1.1.1.3  christos  * Returns: Cloned ANQP data structure or %NULL on failure
     66  1.1.1.3  christos  */
     67  1.1.1.3  christos static struct wpa_bss_anqp * wpa_bss_anqp_clone(struct wpa_bss_anqp *anqp)
     68  1.1.1.3  christos {
     69  1.1.1.3  christos 	struct wpa_bss_anqp *n;
     70  1.1.1.3  christos 
     71  1.1.1.3  christos 	n = os_zalloc(sizeof(*n));
     72  1.1.1.3  christos 	if (n == NULL)
     73  1.1.1.3  christos 		return NULL;
     74  1.1.1.3  christos 
     75  1.1.1.3  christos #define ANQP_DUP(f) if (anqp->f) n->f = wpabuf_dup(anqp->f)
     76  1.1.1.3  christos #ifdef CONFIG_INTERWORKING
     77  1.1.1.6  christos 	dl_list_init(&n->anqp_elems);
     78  1.1.1.5  christos 	ANQP_DUP(capability_list);
     79  1.1.1.3  christos 	ANQP_DUP(venue_name);
     80  1.1.1.3  christos 	ANQP_DUP(network_auth_type);
     81  1.1.1.3  christos 	ANQP_DUP(roaming_consortium);
     82  1.1.1.3  christos 	ANQP_DUP(ip_addr_type_availability);
     83  1.1.1.3  christos 	ANQP_DUP(nai_realm);
     84  1.1.1.3  christos 	ANQP_DUP(anqp_3gpp);
     85  1.1.1.3  christos 	ANQP_DUP(domain_name);
     86  1.1.1.7  christos 	ANQP_DUP(fils_realm_info);
     87  1.1.1.3  christos #endif /* CONFIG_INTERWORKING */
     88  1.1.1.3  christos #ifdef CONFIG_HS20
     89  1.1.1.5  christos 	ANQP_DUP(hs20_capability_list);
     90  1.1.1.3  christos 	ANQP_DUP(hs20_operator_friendly_name);
     91  1.1.1.3  christos 	ANQP_DUP(hs20_wan_metrics);
     92  1.1.1.3  christos 	ANQP_DUP(hs20_connection_capability);
     93  1.1.1.3  christos 	ANQP_DUP(hs20_operating_class);
     94  1.1.1.4  christos 	ANQP_DUP(hs20_osu_providers_list);
     95  1.1.1.7  christos 	ANQP_DUP(hs20_operator_icon_metadata);
     96  1.1.1.7  christos 	ANQP_DUP(hs20_osu_providers_nai_list);
     97  1.1.1.3  christos #endif /* CONFIG_HS20 */
     98  1.1.1.3  christos #undef ANQP_DUP
     99  1.1.1.3  christos 
    100  1.1.1.3  christos 	return n;
    101  1.1.1.3  christos }
    102  1.1.1.3  christos 
    103  1.1.1.3  christos 
    104  1.1.1.3  christos /**
    105  1.1.1.3  christos  * wpa_bss_anqp_unshare_alloc - Unshare ANQP data (if shared) in a BSS entry
    106  1.1.1.3  christos  * @bss: BSS entry
    107  1.1.1.3  christos  * Returns: 0 on success, -1 on failure
    108  1.1.1.3  christos  *
    109  1.1.1.3  christos  * This function ensures the specific BSS entry has an ANQP data structure that
    110  1.1.1.3  christos  * is not shared with any other BSS entry.
    111  1.1.1.3  christos  */
    112  1.1.1.3  christos int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss)
    113  1.1.1.3  christos {
    114  1.1.1.3  christos 	struct wpa_bss_anqp *anqp;
    115  1.1.1.3  christos 
    116  1.1.1.3  christos 	if (bss->anqp && bss->anqp->users > 1) {
    117  1.1.1.3  christos 		/* allocated, but shared - clone an unshared copy */
    118  1.1.1.3  christos 		anqp = wpa_bss_anqp_clone(bss->anqp);
    119  1.1.1.3  christos 		if (anqp == NULL)
    120  1.1.1.3  christos 			return -1;
    121  1.1.1.3  christos 		anqp->users = 1;
    122  1.1.1.3  christos 		bss->anqp->users--;
    123  1.1.1.3  christos 		bss->anqp = anqp;
    124  1.1.1.3  christos 		return 0;
    125  1.1.1.3  christos 	}
    126  1.1.1.3  christos 
    127  1.1.1.3  christos 	if (bss->anqp)
    128  1.1.1.3  christos 		return 0; /* already allocated and not shared */
    129  1.1.1.3  christos 
    130  1.1.1.3  christos 	/* not allocated - allocate a new storage area */
    131  1.1.1.3  christos 	bss->anqp = wpa_bss_anqp_alloc();
    132  1.1.1.3  christos 	return bss->anqp ? 0 : -1;
    133  1.1.1.3  christos }
    134  1.1.1.3  christos 
    135  1.1.1.3  christos 
    136  1.1.1.3  christos /**
    137  1.1.1.3  christos  * wpa_bss_anqp_free - Free an ANQP data structure
    138  1.1.1.3  christos  * @anqp: ANQP data structure from wpa_bss_anqp_alloc() or wpa_bss_anqp_clone()
    139  1.1.1.3  christos  */
    140  1.1.1.3  christos static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
    141      1.1  christos {
    142  1.1.1.6  christos #ifdef CONFIG_INTERWORKING
    143  1.1.1.6  christos 	struct wpa_bss_anqp_elem *elem;
    144  1.1.1.6  christos #endif /* CONFIG_INTERWORKING */
    145  1.1.1.6  christos 
    146  1.1.1.3  christos 	if (anqp == NULL)
    147  1.1.1.3  christos 		return;
    148  1.1.1.3  christos 
    149  1.1.1.3  christos 	anqp->users--;
    150  1.1.1.3  christos 	if (anqp->users > 0) {
    151  1.1.1.3  christos 		/* Another BSS entry holds a pointer to this ANQP info */
    152  1.1.1.3  christos 		return;
    153  1.1.1.3  christos 	}
    154  1.1.1.3  christos 
    155  1.1.1.3  christos #ifdef CONFIG_INTERWORKING
    156  1.1.1.5  christos 	wpabuf_free(anqp->capability_list);
    157  1.1.1.3  christos 	wpabuf_free(anqp->venue_name);
    158  1.1.1.3  christos 	wpabuf_free(anqp->network_auth_type);
    159  1.1.1.3  christos 	wpabuf_free(anqp->roaming_consortium);
    160  1.1.1.3  christos 	wpabuf_free(anqp->ip_addr_type_availability);
    161  1.1.1.3  christos 	wpabuf_free(anqp->nai_realm);
    162  1.1.1.3  christos 	wpabuf_free(anqp->anqp_3gpp);
    163  1.1.1.3  christos 	wpabuf_free(anqp->domain_name);
    164  1.1.1.7  christos 	wpabuf_free(anqp->fils_realm_info);
    165  1.1.1.6  christos 
    166  1.1.1.6  christos 	while ((elem = dl_list_first(&anqp->anqp_elems,
    167  1.1.1.6  christos 				     struct wpa_bss_anqp_elem, list))) {
    168  1.1.1.6  christos 		dl_list_del(&elem->list);
    169  1.1.1.6  christos 		wpabuf_free(elem->payload);
    170  1.1.1.6  christos 		os_free(elem);
    171  1.1.1.6  christos 	}
    172  1.1.1.3  christos #endif /* CONFIG_INTERWORKING */
    173  1.1.1.3  christos #ifdef CONFIG_HS20
    174  1.1.1.5  christos 	wpabuf_free(anqp->hs20_capability_list);
    175  1.1.1.3  christos 	wpabuf_free(anqp->hs20_operator_friendly_name);
    176  1.1.1.3  christos 	wpabuf_free(anqp->hs20_wan_metrics);
    177  1.1.1.3  christos 	wpabuf_free(anqp->hs20_connection_capability);
    178  1.1.1.3  christos 	wpabuf_free(anqp->hs20_operating_class);
    179  1.1.1.4  christos 	wpabuf_free(anqp->hs20_osu_providers_list);
    180  1.1.1.7  christos 	wpabuf_free(anqp->hs20_operator_icon_metadata);
    181  1.1.1.7  christos 	wpabuf_free(anqp->hs20_osu_providers_nai_list);
    182  1.1.1.3  christos #endif /* CONFIG_HS20 */
    183  1.1.1.3  christos 
    184  1.1.1.3  christos 	os_free(anqp);
    185  1.1.1.3  christos }
    186  1.1.1.3  christos 
    187  1.1.1.3  christos 
    188  1.1.1.9  christos static struct wpa_connect_work *
    189  1.1.1.9  christos wpa_bss_check_pending_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
    190  1.1.1.5  christos {
    191  1.1.1.5  christos 	struct wpa_radio_work *work;
    192  1.1.1.5  christos 	struct wpa_connect_work *cwork;
    193  1.1.1.5  christos 
    194  1.1.1.5  christos 	work = radio_work_pending(wpa_s, "sme-connect");
    195  1.1.1.5  christos 	if (!work)
    196  1.1.1.5  christos 		work = radio_work_pending(wpa_s, "connect");
    197  1.1.1.5  christos 	if (!work)
    198  1.1.1.9  christos 		return NULL;
    199  1.1.1.5  christos 
    200  1.1.1.5  christos 	cwork = work->ctx;
    201  1.1.1.9  christos 	if (cwork->bss != bss)
    202  1.1.1.9  christos 		return NULL;
    203  1.1.1.9  christos 
    204  1.1.1.9  christos 	return cwork;
    205  1.1.1.9  christos }
    206  1.1.1.9  christos 
    207  1.1.1.5  christos 
    208  1.1.1.9  christos static void wpa_bss_update_pending_connect(struct wpa_connect_work *cwork,
    209  1.1.1.9  christos 					   struct wpa_bss *new_bss)
    210  1.1.1.9  christos {
    211  1.1.1.5  christos 	wpa_printf(MSG_DEBUG,
    212  1.1.1.5  christos 		   "Update BSS pointer for the pending connect radio work");
    213  1.1.1.5  christos 	cwork->bss = new_bss;
    214  1.1.1.5  christos 	if (!new_bss)
    215  1.1.1.5  christos 		cwork->bss_removed = 1;
    216  1.1.1.5  christos }
    217  1.1.1.5  christos 
    218  1.1.1.5  christos 
    219  1.1.1.6  christos void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
    220  1.1.1.6  christos 		    const char *reason)
    221  1.1.1.3  christos {
    222  1.1.1.9  christos 	struct wpa_connect_work *cwork;
    223  1.1.1.9  christos 
    224  1.1.1.3  christos 	if (wpa_s->last_scan_res) {
    225  1.1.1.3  christos 		unsigned int i;
    226  1.1.1.3  christos 		for (i = 0; i < wpa_s->last_scan_res_used; i++) {
    227  1.1.1.3  christos 			if (wpa_s->last_scan_res[i] == bss) {
    228  1.1.1.3  christos 				os_memmove(&wpa_s->last_scan_res[i],
    229  1.1.1.3  christos 					   &wpa_s->last_scan_res[i + 1],
    230  1.1.1.3  christos 					   (wpa_s->last_scan_res_used - i - 1)
    231  1.1.1.3  christos 					   * sizeof(struct wpa_bss *));
    232  1.1.1.3  christos 				wpa_s->last_scan_res_used--;
    233  1.1.1.3  christos 				break;
    234  1.1.1.3  christos 			}
    235  1.1.1.3  christos 		}
    236  1.1.1.3  christos 	}
    237  1.1.1.9  christos 	cwork = wpa_bss_check_pending_connect(wpa_s, bss);
    238  1.1.1.9  christos 	if (cwork)
    239  1.1.1.9  christos 		wpa_bss_update_pending_connect(cwork, 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.9  christos  * @bssid: BSSID, or %NULL to match any 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.9  christos 
    265  1.1.1.9  christos 	if (bssid && !wpa_supplicant_filter_bssid_match(wpa_s, bssid))
    266  1.1.1.3  christos 		return NULL;
    267      1.1  christos 	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
    268  1.1.1.9  christos 		if ((!bssid || ether_addr_equal(bss->bssid, bssid)) &&
    269      1.1  christos 		    bss->ssid_len == ssid_len &&
    270      1.1  christos 		    os_memcmp(bss->ssid, ssid, ssid_len) == 0)
    271      1.1  christos 			return bss;
    272      1.1  christos 	}
    273      1.1  christos 	return NULL;
    274      1.1  christos }
    275      1.1  christos 
    276      1.1  christos 
    277  1.1.1.7  christos void calculate_update_time(const struct os_reltime *fetch_time,
    278  1.1.1.7  christos 			   unsigned int age_ms,
    279  1.1.1.7  christos 			   struct os_reltime *update_time)
    280      1.1  christos {
    281      1.1  christos 	os_time_t usec;
    282      1.1  christos 
    283  1.1.1.4  christos 	update_time->sec = fetch_time->sec;
    284  1.1.1.4  christos 	update_time->usec = fetch_time->usec;
    285  1.1.1.4  christos 	update_time->sec -= age_ms / 1000;
    286  1.1.1.4  christos 	usec = (age_ms % 1000) * 1000;
    287  1.1.1.4  christos 	if (update_time->usec < usec) {
    288  1.1.1.4  christos 		update_time->sec--;
    289  1.1.1.4  christos 		update_time->usec += 1000000;
    290  1.1.1.4  christos 	}
    291  1.1.1.4  christos 	update_time->usec -= usec;
    292  1.1.1.4  christos }
    293  1.1.1.4  christos 
    294  1.1.1.4  christos 
    295  1.1.1.4  christos static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src,
    296  1.1.1.4  christos 			     struct os_reltime *fetch_time)
    297  1.1.1.4  christos {
    298      1.1  christos 	dst->flags = src->flags;
    299      1.1  christos 	os_memcpy(dst->bssid, src->bssid, ETH_ALEN);
    300      1.1  christos 	dst->freq = src->freq;
    301  1.1.1.9  christos 	dst->max_cw = src->max_cw;
    302      1.1  christos 	dst->beacon_int = src->beacon_int;
    303      1.1  christos 	dst->caps = src->caps;
    304      1.1  christos 	dst->qual = src->qual;
    305      1.1  christos 	dst->noise = src->noise;
    306      1.1  christos 	dst->level = src->level;
    307      1.1  christos 	dst->tsf = src->tsf;
    308  1.1.1.9  christos 	dst->beacon_newer = src->beacon_newer;
    309  1.1.1.5  christos 	dst->est_throughput = src->est_throughput;
    310  1.1.1.5  christos 	dst->snr = src->snr;
    311      1.1  christos 
    312  1.1.1.4  christos 	calculate_update_time(fetch_time, src->age, &dst->last_update);
    313      1.1  christos }
    314      1.1  christos 
    315      1.1  christos 
    316  1.1.1.6  christos static int wpa_bss_is_wps_candidate(struct wpa_supplicant *wpa_s,
    317  1.1.1.6  christos 				    struct wpa_bss *bss)
    318  1.1.1.6  christos {
    319  1.1.1.6  christos #ifdef CONFIG_WPS
    320  1.1.1.6  christos 	struct wpa_ssid *ssid;
    321  1.1.1.6  christos 	struct wpabuf *wps_ie;
    322  1.1.1.6  christos 	int pbc = 0, ret;
    323  1.1.1.6  christos 
    324  1.1.1.6  christos 	wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
    325  1.1.1.6  christos 	if (!wps_ie)
    326  1.1.1.6  christos 		return 0;
    327  1.1.1.6  christos 
    328  1.1.1.6  christos 	if (wps_is_selected_pbc_registrar(wps_ie)) {
    329  1.1.1.6  christos 		pbc = 1;
    330  1.1.1.6  christos 	} else if (!wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1)) {
    331  1.1.1.6  christos 		wpabuf_free(wps_ie);
    332  1.1.1.6  christos 		return 0;
    333  1.1.1.6  christos 	}
    334  1.1.1.6  christos 
    335  1.1.1.6  christos 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
    336  1.1.1.6  christos 		if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS))
    337  1.1.1.6  christos 			continue;
    338  1.1.1.6  christos 		if (ssid->ssid_len &&
    339  1.1.1.6  christos 		    (ssid->ssid_len != bss->ssid_len ||
    340  1.1.1.6  christos 		     os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) != 0))
    341  1.1.1.6  christos 			continue;
    342  1.1.1.6  christos 
    343  1.1.1.6  christos 		if (pbc)
    344  1.1.1.6  christos 			ret = eap_is_wps_pbc_enrollee(&ssid->eap);
    345  1.1.1.6  christos 		else
    346  1.1.1.6  christos 			ret = eap_is_wps_pin_enrollee(&ssid->eap);
    347  1.1.1.6  christos 		wpabuf_free(wps_ie);
    348  1.1.1.6  christos 		return ret;
    349  1.1.1.6  christos 	}
    350  1.1.1.6  christos 	wpabuf_free(wps_ie);
    351  1.1.1.6  christos #endif /* CONFIG_WPS */
    352  1.1.1.6  christos 
    353  1.1.1.6  christos 	return 0;
    354  1.1.1.6  christos }
    355  1.1.1.6  christos 
    356  1.1.1.6  christos 
    357  1.1.1.9  christos static bool is_p2p_pending_bss(struct wpa_supplicant *wpa_s,
    358  1.1.1.9  christos 			       struct wpa_bss *bss)
    359  1.1.1.9  christos {
    360  1.1.1.9  christos #ifdef CONFIG_P2P
    361  1.1.1.9  christos 	u8 addr[ETH_ALEN];
    362  1.1.1.9  christos 
    363  1.1.1.9  christos 	if (ether_addr_equal(bss->bssid, wpa_s->pending_join_iface_addr))
    364  1.1.1.9  christos 		return true;
    365  1.1.1.9  christos 	if (!is_zero_ether_addr(wpa_s->pending_join_dev_addr) &&
    366  1.1.1.9  christos 	    p2p_parse_dev_addr(wpa_bss_ie_ptr(bss), bss->ie_len, addr) == 0 &&
    367  1.1.1.9  christos 	    ether_addr_equal(addr, wpa_s->pending_join_dev_addr))
    368  1.1.1.9  christos 		return true;
    369  1.1.1.9  christos #endif /* CONFIG_P2P */
    370  1.1.1.9  christos 	return false;
    371  1.1.1.9  christos }
    372  1.1.1.9  christos 
    373  1.1.1.9  christos 
    374  1.1.1.2  christos static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
    375  1.1.1.2  christos {
    376  1.1.1.2  christos 	struct wpa_ssid *ssid;
    377  1.1.1.2  christos 
    378  1.1.1.9  christos 	if (is_p2p_pending_bss(wpa_s, bss))
    379  1.1.1.9  christos 		return 1;
    380  1.1.1.9  christos 
    381  1.1.1.2  christos 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
    382  1.1.1.2  christos 		if (ssid->ssid == NULL || ssid->ssid_len == 0)
    383  1.1.1.2  christos 			continue;
    384  1.1.1.2  christos 		if (ssid->ssid_len == bss->ssid_len &&
    385  1.1.1.2  christos 		    os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) == 0)
    386  1.1.1.2  christos 			return 1;
    387  1.1.1.2  christos 	}
    388  1.1.1.2  christos 
    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.3  christos static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
    394  1.1.1.3  christos {
    395  1.1.1.9  christos 	int i;
    396  1.1.1.9  christos 
    397  1.1.1.6  christos 	if (bss == wpa_s->current_bss)
    398  1.1.1.6  christos 		return 1;
    399  1.1.1.6  christos 
    400  1.1.1.9  christos 	if (bss == wpa_s->ml_connect_probe_bss)
    401  1.1.1.9  christos 		return 1;
    402  1.1.1.9  christos 
    403  1.1.1.9  christos #ifdef CONFIG_WNM
    404  1.1.1.9  christos 	if (bss == wpa_s->wnm_target_bss)
    405  1.1.1.9  christos 		return 1;
    406  1.1.1.9  christos #endif /* CONFIG_WNM */
    407  1.1.1.9  christos 
    408  1.1.1.6  christos 	if (wpa_s->current_bss &&
    409  1.1.1.6  christos 	    (bss->ssid_len != wpa_s->current_bss->ssid_len ||
    410  1.1.1.6  christos 	     os_memcmp(bss->ssid, wpa_s->current_bss->ssid,
    411  1.1.1.6  christos 		       bss->ssid_len) != 0))
    412  1.1.1.6  christos 		return 0; /* SSID has changed */
    413  1.1.1.6  christos 
    414  1.1.1.9  christos 	if (!is_zero_ether_addr(bss->bssid) &&
    415  1.1.1.9  christos 	    (ether_addr_equal(bss->bssid, wpa_s->bssid) ||
    416  1.1.1.9  christos 	     ether_addr_equal(bss->bssid, wpa_s->pending_bssid)))
    417  1.1.1.9  christos 		return 1;
    418  1.1.1.9  christos 
    419  1.1.1.9  christos 	if (!wpa_s->valid_links)
    420  1.1.1.9  christos 		return 0;
    421  1.1.1.9  christos 
    422  1.1.1.9  christos 	for_each_link(wpa_s->valid_links, i) {
    423  1.1.1.9  christos 		if (ether_addr_equal(bss->bssid, wpa_s->links[i].bssid))
    424  1.1.1.9  christos 			return 1;
    425  1.1.1.9  christos 	}
    426  1.1.1.9  christos 
    427  1.1.1.9  christos 	return 0;
    428  1.1.1.3  christos }
    429  1.1.1.3  christos 
    430  1.1.1.3  christos 
    431  1.1.1.2  christos static int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s)
    432  1.1.1.2  christos {
    433  1.1.1.2  christos 	struct wpa_bss *bss;
    434  1.1.1.2  christos 
    435  1.1.1.2  christos 	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
    436  1.1.1.6  christos 		if (!wpa_bss_known(wpa_s, bss) &&
    437  1.1.1.6  christos 		    !wpa_bss_is_wps_candidate(wpa_s, bss)) {
    438  1.1.1.3  christos 			wpa_bss_remove(wpa_s, bss, __func__);
    439  1.1.1.2  christos 			return 0;
    440  1.1.1.2  christos 		}
    441  1.1.1.2  christos 	}
    442  1.1.1.2  christos 
    443  1.1.1.2  christos 	return -1;
    444  1.1.1.2  christos }
    445  1.1.1.2  christos 
    446  1.1.1.2  christos 
    447  1.1.1.3  christos static int wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s)
    448  1.1.1.2  christos {
    449  1.1.1.3  christos 	struct wpa_bss *bss;
    450  1.1.1.3  christos 
    451  1.1.1.2  christos 	/*
    452  1.1.1.2  christos 	 * Remove the oldest entry that does not match with any configured
    453  1.1.1.2  christos 	 * network.
    454  1.1.1.2  christos 	 */
    455  1.1.1.2  christos 	if (wpa_bss_remove_oldest_unknown(wpa_s) == 0)
    456  1.1.1.3  christos 		return 0;
    457  1.1.1.2  christos 
    458  1.1.1.2  christos 	/*
    459  1.1.1.3  christos 	 * Remove the oldest entry that isn't currently in use.
    460  1.1.1.2  christos 	 */
    461  1.1.1.3  christos 	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
    462  1.1.1.3  christos 		if (!wpa_bss_in_use(wpa_s, bss)) {
    463  1.1.1.3  christos 			wpa_bss_remove(wpa_s, bss, __func__);
    464  1.1.1.3  christos 			return 0;
    465  1.1.1.3  christos 		}
    466  1.1.1.3  christos 	}
    467  1.1.1.3  christos 
    468  1.1.1.3  christos 	return -1;
    469  1.1.1.2  christos }
    470  1.1.1.2  christos 
    471  1.1.1.2  christos 
    472  1.1.1.3  christos static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s,
    473  1.1.1.3  christos 				    const u8 *ssid, size_t ssid_len,
    474  1.1.1.4  christos 				    struct wpa_scan_res *res,
    475  1.1.1.4  christos 				    struct os_reltime *fetch_time)
    476      1.1  christos {
    477      1.1  christos 	struct wpa_bss *bss;
    478  1.1.1.9  christos 	char extra[100];
    479  1.1.1.9  christos 	const u8 *ml_ie;
    480  1.1.1.9  christos 	char *pos, *end;
    481  1.1.1.9  christos 	int ret = 0;
    482  1.1.1.9  christos 	const u8 *mld_addr;
    483      1.1  christos 
    484      1.1  christos 	bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len);
    485      1.1  christos 	if (bss == NULL)
    486  1.1.1.3  christos 		return NULL;
    487      1.1  christos 	bss->id = wpa_s->bss_next_id++;
    488      1.1  christos 	bss->last_update_idx = wpa_s->bss_update_idx;
    489  1.1.1.4  christos 	wpa_bss_copy_res(bss, res, fetch_time);
    490      1.1  christos 	os_memcpy(bss->ssid, ssid, ssid_len);
    491      1.1  christos 	bss->ssid_len = ssid_len;
    492      1.1  christos 	bss->ie_len = res->ie_len;
    493      1.1  christos 	bss->beacon_ie_len = res->beacon_ie_len;
    494  1.1.1.9  christos 	os_memcpy(bss->ies, res + 1, res->ie_len + res->beacon_ie_len);
    495  1.1.1.3  christos 	wpa_bss_set_hessid(bss);
    496      1.1  christos 
    497  1.1.1.9  christos 	os_memset(bss->mld_addr, 0, ETH_ALEN);
    498  1.1.1.9  christos 	ml_ie = wpa_scan_get_ml_ie(res, MULTI_LINK_CONTROL_TYPE_BASIC);
    499  1.1.1.9  christos 	if (ml_ie) {
    500  1.1.1.9  christos 		mld_addr = get_basic_mle_mld_addr(&ml_ie[3], ml_ie[1] - 1);
    501  1.1.1.9  christos 		if (mld_addr)
    502  1.1.1.9  christos 			os_memcpy(bss->mld_addr, mld_addr, ETH_ALEN);
    503  1.1.1.9  christos 	}
    504  1.1.1.9  christos 
    505  1.1.1.4  christos 	if (wpa_s->num_bss + 1 > wpa_s->conf->bss_max_count &&
    506  1.1.1.4  christos 	    wpa_bss_remove_oldest(wpa_s) != 0) {
    507  1.1.1.4  christos 		wpa_printf(MSG_ERROR, "Increasing the MAX BSS count to %d "
    508  1.1.1.4  christos 			   "because all BSSes are in use. We should normally "
    509  1.1.1.4  christos 			   "not get here!", (int) wpa_s->num_bss + 1);
    510  1.1.1.4  christos 		wpa_s->conf->bss_max_count = wpa_s->num_bss + 1;
    511  1.1.1.4  christos 	}
    512  1.1.1.4  christos 
    513      1.1  christos 	dl_list_add_tail(&wpa_s->bss, &bss->list);
    514      1.1  christos 	dl_list_add_tail(&wpa_s->bss_id, &bss->list_id);
    515      1.1  christos 	wpa_s->num_bss++;
    516  1.1.1.9  christos 
    517  1.1.1.9  christos 	extra[0] = '\0';
    518  1.1.1.9  christos 	pos = extra;
    519  1.1.1.9  christos 	end = pos + sizeof(extra);
    520  1.1.1.8  christos 	if (!is_zero_ether_addr(bss->hessid))
    521  1.1.1.9  christos 		ret = os_snprintf(pos, end - pos, " HESSID " MACSTR,
    522  1.1.1.9  christos 				  MAC2STR(bss->hessid));
    523  1.1.1.9  christos 
    524  1.1.1.9  christos 	if (!is_zero_ether_addr(bss->mld_addr) &&
    525  1.1.1.9  christos 	    !os_snprintf_error(end - pos, ret)) {
    526  1.1.1.9  christos 		pos += ret;
    527  1.1.1.9  christos 		ret = os_snprintf(pos, end - pos, " MLD ADDR " MACSTR,
    528  1.1.1.9  christos 				  MAC2STR(bss->mld_addr));
    529  1.1.1.9  christos 	}
    530  1.1.1.9  christos 
    531  1.1.1.2  christos 	wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Add new id %u BSSID " MACSTR
    532  1.1.1.8  christos 		" SSID '%s' freq %d%s",
    533  1.1.1.6  christos 		bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len),
    534  1.1.1.8  christos 		bss->freq, extra);
    535      1.1  christos 	wpas_notify_bss_added(wpa_s, bss->bssid, bss->id);
    536  1.1.1.3  christos 	return bss;
    537      1.1  christos }
    538      1.1  christos 
    539      1.1  christos 
    540      1.1  christos static int are_ies_equal(const struct wpa_bss *old,
    541  1.1.1.6  christos 			 const struct wpa_scan_res *new_res, u32 ie)
    542      1.1  christos {
    543      1.1  christos 	const u8 *old_ie, *new_ie;
    544      1.1  christos 	struct wpabuf *old_ie_buff = NULL;
    545      1.1  christos 	struct wpabuf *new_ie_buff = NULL;
    546      1.1  christos 	int new_ie_len, old_ie_len, ret, is_multi;
    547      1.1  christos 
    548      1.1  christos 	switch (ie) {
    549      1.1  christos 	case WPA_IE_VENDOR_TYPE:
    550      1.1  christos 		old_ie = wpa_bss_get_vendor_ie(old, ie);
    551  1.1.1.6  christos 		new_ie = wpa_scan_get_vendor_ie(new_res, ie);
    552      1.1  christos 		is_multi = 0;
    553      1.1  christos 		break;
    554      1.1  christos 	case WPS_IE_VENDOR_TYPE:
    555      1.1  christos 		old_ie_buff = wpa_bss_get_vendor_ie_multi(old, ie);
    556  1.1.1.6  christos 		new_ie_buff = wpa_scan_get_vendor_ie_multi(new_res, ie);
    557      1.1  christos 		is_multi = 1;
    558      1.1  christos 		break;
    559      1.1  christos 	case WLAN_EID_RSN:
    560      1.1  christos 	case WLAN_EID_SUPP_RATES:
    561      1.1  christos 	case WLAN_EID_EXT_SUPP_RATES:
    562      1.1  christos 		old_ie = wpa_bss_get_ie(old, ie);
    563  1.1.1.6  christos 		new_ie = wpa_scan_get_ie(new_res, ie);
    564      1.1  christos 		is_multi = 0;
    565      1.1  christos 		break;
    566      1.1  christos 	default:
    567      1.1  christos 		wpa_printf(MSG_DEBUG, "bss: %s: cannot compare IEs", __func__);
    568      1.1  christos 		return 0;
    569      1.1  christos 	}
    570      1.1  christos 
    571      1.1  christos 	if (is_multi) {
    572      1.1  christos 		/* in case of multiple IEs stored in buffer */
    573      1.1  christos 		old_ie = old_ie_buff ? wpabuf_head_u8(old_ie_buff) : NULL;
    574      1.1  christos 		new_ie = new_ie_buff ? wpabuf_head_u8(new_ie_buff) : NULL;
    575      1.1  christos 		old_ie_len = old_ie_buff ? wpabuf_len(old_ie_buff) : 0;
    576      1.1  christos 		new_ie_len = new_ie_buff ? wpabuf_len(new_ie_buff) : 0;
    577      1.1  christos 	} else {
    578      1.1  christos 		/* in case of single IE */
    579      1.1  christos 		old_ie_len = old_ie ? old_ie[1] + 2 : 0;
    580      1.1  christos 		new_ie_len = new_ie ? new_ie[1] + 2 : 0;
    581      1.1  christos 	}
    582      1.1  christos 
    583  1.1.1.2  christos 	if (!old_ie || !new_ie)
    584  1.1.1.2  christos 		ret = !old_ie && !new_ie;
    585  1.1.1.2  christos 	else
    586  1.1.1.2  christos 		ret = (old_ie_len == new_ie_len &&
    587  1.1.1.2  christos 		       os_memcmp(old_ie, new_ie, old_ie_len) == 0);
    588      1.1  christos 
    589      1.1  christos 	wpabuf_free(old_ie_buff);
    590      1.1  christos 	wpabuf_free(new_ie_buff);
    591      1.1  christos 
    592      1.1  christos 	return ret;
    593      1.1  christos }
    594      1.1  christos 
    595      1.1  christos 
    596      1.1  christos static u32 wpa_bss_compare_res(const struct wpa_bss *old,
    597  1.1.1.6  christos 			       const struct wpa_scan_res *new_res)
    598      1.1  christos {
    599      1.1  christos 	u32 changes = 0;
    600  1.1.1.6  christos 	int caps_diff = old->caps ^ new_res->caps;
    601      1.1  christos 
    602  1.1.1.6  christos 	if (old->freq != new_res->freq)
    603      1.1  christos 		changes |= WPA_BSS_FREQ_CHANGED_FLAG;
    604      1.1  christos 
    605  1.1.1.6  christos 	if (old->level != new_res->level)
    606      1.1  christos 		changes |= WPA_BSS_SIGNAL_CHANGED_FLAG;
    607      1.1  christos 
    608      1.1  christos 	if (caps_diff & IEEE80211_CAP_PRIVACY)
    609      1.1  christos 		changes |= WPA_BSS_PRIVACY_CHANGED_FLAG;
    610      1.1  christos 
    611      1.1  christos 	if (caps_diff & IEEE80211_CAP_IBSS)
    612      1.1  christos 		changes |= WPA_BSS_MODE_CHANGED_FLAG;
    613      1.1  christos 
    614  1.1.1.6  christos 	if (old->ie_len == new_res->ie_len &&
    615  1.1.1.9  christos 	    os_memcmp(wpa_bss_ie_ptr(old), new_res + 1, old->ie_len) == 0)
    616      1.1  christos 		return changes;
    617      1.1  christos 	changes |= WPA_BSS_IES_CHANGED_FLAG;
    618      1.1  christos 
    619  1.1.1.6  christos 	if (!are_ies_equal(old, new_res, WPA_IE_VENDOR_TYPE))
    620      1.1  christos 		changes |= WPA_BSS_WPAIE_CHANGED_FLAG;
    621      1.1  christos 
    622  1.1.1.6  christos 	if (!are_ies_equal(old, new_res, WLAN_EID_RSN))
    623      1.1  christos 		changes |= WPA_BSS_RSNIE_CHANGED_FLAG;
    624      1.1  christos 
    625  1.1.1.6  christos 	if (!are_ies_equal(old, new_res, WPS_IE_VENDOR_TYPE))
    626      1.1  christos 		changes |= WPA_BSS_WPS_CHANGED_FLAG;
    627      1.1  christos 
    628  1.1.1.6  christos 	if (!are_ies_equal(old, new_res, WLAN_EID_SUPP_RATES) ||
    629  1.1.1.6  christos 	    !are_ies_equal(old, new_res, WLAN_EID_EXT_SUPP_RATES))
    630      1.1  christos 		changes |= WPA_BSS_RATES_CHANGED_FLAG;
    631      1.1  christos 
    632      1.1  christos 	return changes;
    633      1.1  christos }
    634      1.1  christos 
    635      1.1  christos 
    636  1.1.1.9  christos void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
    637  1.1.1.9  christos 			const struct wpa_bss *bss)
    638      1.1  christos {
    639      1.1  christos 	if (changes & WPA_BSS_FREQ_CHANGED_FLAG)
    640      1.1  christos 		wpas_notify_bss_freq_changed(wpa_s, bss->id);
    641      1.1  christos 
    642      1.1  christos 	if (changes & WPA_BSS_SIGNAL_CHANGED_FLAG)
    643      1.1  christos 		wpas_notify_bss_signal_changed(wpa_s, bss->id);
    644      1.1  christos 
    645      1.1  christos 	if (changes & WPA_BSS_PRIVACY_CHANGED_FLAG)
    646      1.1  christos 		wpas_notify_bss_privacy_changed(wpa_s, bss->id);
    647      1.1  christos 
    648      1.1  christos 	if (changes & WPA_BSS_MODE_CHANGED_FLAG)
    649      1.1  christos 		wpas_notify_bss_mode_changed(wpa_s, bss->id);
    650      1.1  christos 
    651      1.1  christos 	if (changes & WPA_BSS_WPAIE_CHANGED_FLAG)
    652      1.1  christos 		wpas_notify_bss_wpaie_changed(wpa_s, bss->id);
    653      1.1  christos 
    654      1.1  christos 	if (changes & WPA_BSS_RSNIE_CHANGED_FLAG)
    655      1.1  christos 		wpas_notify_bss_rsnie_changed(wpa_s, bss->id);
    656      1.1  christos 
    657      1.1  christos 	if (changes & WPA_BSS_WPS_CHANGED_FLAG)
    658      1.1  christos 		wpas_notify_bss_wps_changed(wpa_s, bss->id);
    659      1.1  christos 
    660      1.1  christos 	if (changes & WPA_BSS_IES_CHANGED_FLAG)
    661      1.1  christos 		wpas_notify_bss_ies_changed(wpa_s, bss->id);
    662      1.1  christos 
    663      1.1  christos 	if (changes & WPA_BSS_RATES_CHANGED_FLAG)
    664      1.1  christos 		wpas_notify_bss_rates_changed(wpa_s, bss->id);
    665  1.1.1.4  christos 
    666  1.1.1.4  christos 	wpas_notify_bss_seen(wpa_s, bss->id);
    667      1.1  christos }
    668      1.1  christos 
    669      1.1  christos 
    670  1.1.1.3  christos static struct wpa_bss *
    671  1.1.1.3  christos wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
    672  1.1.1.4  christos 	       struct wpa_scan_res *res, struct os_reltime *fetch_time)
    673      1.1  christos {
    674      1.1  christos 	u32 changes;
    675      1.1  christos 
    676  1.1.1.7  christos 	if (bss->last_update_idx == wpa_s->bss_update_idx) {
    677  1.1.1.7  christos 		struct os_reltime update_time;
    678  1.1.1.7  christos 
    679  1.1.1.7  christos 		/*
    680  1.1.1.7  christos 		 * Some drivers (e.g., cfg80211) include multiple BSS entries
    681  1.1.1.7  christos 		 * for the same BSS if that BSS's channel changes. The BSS list
    682  1.1.1.7  christos 		 * implementation in wpa_supplicant does not do that and we need
    683  1.1.1.7  christos 		 * to filter out the obsolete results here to make sure only the
    684  1.1.1.7  christos 		 * most current BSS information remains in the table.
    685  1.1.1.7  christos 		 */
    686  1.1.1.7  christos 		wpa_printf(MSG_DEBUG, "BSS: " MACSTR
    687  1.1.1.7  christos 			   " has multiple entries in the scan results - select the most current one",
    688  1.1.1.7  christos 			   MAC2STR(bss->bssid));
    689  1.1.1.7  christos 		calculate_update_time(fetch_time, res->age, &update_time);
    690  1.1.1.7  christos 		wpa_printf(MSG_DEBUG,
    691  1.1.1.7  christos 			   "Previous last_update: %u.%06u (freq %d%s)",
    692  1.1.1.7  christos 			   (unsigned int) bss->last_update.sec,
    693  1.1.1.7  christos 			   (unsigned int) bss->last_update.usec,
    694  1.1.1.7  christos 			   bss->freq,
    695  1.1.1.7  christos 			   (bss->flags & WPA_BSS_ASSOCIATED) ? " assoc" : "");
    696  1.1.1.7  christos 		wpa_printf(MSG_DEBUG, "New last_update: %u.%06u (freq %d%s)",
    697  1.1.1.7  christos 			   (unsigned int) update_time.sec,
    698  1.1.1.7  christos 			   (unsigned int) update_time.usec,
    699  1.1.1.7  christos 			   res->freq,
    700  1.1.1.7  christos 			   (res->flags & WPA_SCAN_ASSOCIATED) ? " assoc" : "");
    701  1.1.1.7  christos 		if ((bss->flags & WPA_BSS_ASSOCIATED) ||
    702  1.1.1.7  christos 		    (!(res->flags & WPA_SCAN_ASSOCIATED) &&
    703  1.1.1.7  christos 		     !os_reltime_before(&bss->last_update, &update_time))) {
    704  1.1.1.7  christos 			wpa_printf(MSG_DEBUG,
    705  1.1.1.7  christos 				   "Ignore this BSS entry since the previous update looks more current");
    706  1.1.1.7  christos 			return bss;
    707  1.1.1.7  christos 		}
    708  1.1.1.7  christos 		wpa_printf(MSG_DEBUG,
    709  1.1.1.7  christos 			   "Accept this BSS entry since it looks more current than the previous update");
    710  1.1.1.7  christos 	}
    711  1.1.1.7  christos 
    712      1.1  christos 	changes = wpa_bss_compare_res(bss, res);
    713  1.1.1.6  christos 	if (changes & WPA_BSS_FREQ_CHANGED_FLAG)
    714  1.1.1.6  christos 		wpa_printf(MSG_DEBUG, "BSS: " MACSTR " changed freq %d --> %d",
    715  1.1.1.6  christos 			   MAC2STR(bss->bssid), bss->freq, res->freq);
    716      1.1  christos 	bss->scan_miss_count = 0;
    717      1.1  christos 	bss->last_update_idx = wpa_s->bss_update_idx;
    718  1.1.1.4  christos 	wpa_bss_copy_res(bss, res, fetch_time);
    719      1.1  christos 	/* Move the entry to the end of the list */
    720      1.1  christos 	dl_list_del(&bss->list);
    721  1.1.1.4  christos #ifdef CONFIG_P2P
    722  1.1.1.4  christos 	if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
    723  1.1.1.9  christos 	    !wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE) &&
    724  1.1.1.9  christos 	    !(changes & WPA_BSS_FREQ_CHANGED_FLAG)) {
    725  1.1.1.4  christos 		/*
    726  1.1.1.4  christos 		 * This can happen when non-P2P station interface runs a scan
    727  1.1.1.4  christos 		 * without P2P IE in the Probe Request frame. P2P GO would reply
    728  1.1.1.4  christos 		 * to that with a Probe Response that does not include P2P IE.
    729  1.1.1.4  christos 		 * Do not update the IEs in this BSS entry to avoid such loss of
    730  1.1.1.4  christos 		 * information that may be needed for P2P operations to
    731  1.1.1.4  christos 		 * determine group information.
    732  1.1.1.4  christos 		 */
    733  1.1.1.4  christos 		wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Do not update scan IEs for "
    734  1.1.1.4  christos 			MACSTR " since that would remove P2P IE information",
    735  1.1.1.4  christos 			MAC2STR(bss->bssid));
    736  1.1.1.4  christos 	} else
    737  1.1.1.4  christos #endif /* CONFIG_P2P */
    738      1.1  christos 	if (bss->ie_len + bss->beacon_ie_len >=
    739      1.1  christos 	    res->ie_len + res->beacon_ie_len) {
    740  1.1.1.9  christos 		os_memcpy(bss->ies, res + 1, res->ie_len + res->beacon_ie_len);
    741      1.1  christos 		bss->ie_len = res->ie_len;
    742      1.1  christos 		bss->beacon_ie_len = res->beacon_ie_len;
    743      1.1  christos 	} else {
    744      1.1  christos 		struct wpa_bss *nbss;
    745      1.1  christos 		struct dl_list *prev = bss->list_id.prev;
    746  1.1.1.9  christos 		struct wpa_connect_work *cwork;
    747  1.1.1.9  christos 		unsigned int i;
    748  1.1.1.9  christos 		bool update_current_bss = wpa_s->current_bss == bss;
    749  1.1.1.9  christos 		bool update_ml_probe_bss = wpa_s->ml_connect_probe_bss == bss;
    750  1.1.1.9  christos 
    751  1.1.1.9  christos 		cwork = wpa_bss_check_pending_connect(wpa_s, bss);
    752  1.1.1.9  christos 
    753  1.1.1.9  christos 		for (i = 0; i < wpa_s->last_scan_res_used; i++) {
    754  1.1.1.9  christos 			if (wpa_s->last_scan_res[i] == bss)
    755  1.1.1.9  christos 				break;
    756  1.1.1.9  christos 		}
    757  1.1.1.9  christos 
    758      1.1  christos 		dl_list_del(&bss->list_id);
    759      1.1  christos 		nbss = os_realloc(bss, sizeof(*bss) + res->ie_len +
    760      1.1  christos 				  res->beacon_ie_len);
    761      1.1  christos 		if (nbss) {
    762  1.1.1.9  christos 			if (i != wpa_s->last_scan_res_used)
    763  1.1.1.9  christos 				wpa_s->last_scan_res[i] = nbss;
    764  1.1.1.9  christos 
    765  1.1.1.9  christos 			if (update_current_bss)
    766  1.1.1.2  christos 				wpa_s->current_bss = nbss;
    767  1.1.1.9  christos 
    768  1.1.1.9  christos 			if (update_ml_probe_bss)
    769  1.1.1.9  christos 				wpa_s->ml_connect_probe_bss = nbss;
    770  1.1.1.9  christos 
    771  1.1.1.9  christos 			if (cwork)
    772  1.1.1.9  christos 				wpa_bss_update_pending_connect(cwork, nbss);
    773  1.1.1.9  christos 
    774      1.1  christos 			bss = nbss;
    775  1.1.1.9  christos 			os_memcpy(bss->ies, res + 1,
    776      1.1  christos 				  res->ie_len + res->beacon_ie_len);
    777      1.1  christos 			bss->ie_len = res->ie_len;
    778      1.1  christos 			bss->beacon_ie_len = res->beacon_ie_len;
    779      1.1  christos 		}
    780      1.1  christos 		dl_list_add(prev, &bss->list_id);
    781      1.1  christos 	}
    782  1.1.1.9  christos 	if (changes & WPA_BSS_IES_CHANGED_FLAG) {
    783  1.1.1.9  christos 		const u8 *ml_ie, *mld_addr;
    784  1.1.1.9  christos 
    785  1.1.1.3  christos 		wpa_bss_set_hessid(bss);
    786  1.1.1.9  christos 		os_memset(bss->mld_addr, 0, ETH_ALEN);
    787  1.1.1.9  christos 		ml_ie = wpa_scan_get_ml_ie(res, MULTI_LINK_CONTROL_TYPE_BASIC);
    788  1.1.1.9  christos 		if (ml_ie) {
    789  1.1.1.9  christos 			mld_addr = get_basic_mle_mld_addr(&ml_ie[3],
    790  1.1.1.9  christos 							  ml_ie[1] - 1);
    791  1.1.1.9  christos 			if (mld_addr)
    792  1.1.1.9  christos 				os_memcpy(bss->mld_addr, mld_addr, ETH_ALEN);
    793  1.1.1.9  christos 		}
    794  1.1.1.9  christos 	}
    795      1.1  christos 	dl_list_add_tail(&wpa_s->bss, &bss->list);
    796      1.1  christos 
    797      1.1  christos 	notify_bss_changes(wpa_s, changes, bss);
    798      1.1  christos 
    799  1.1.1.3  christos 	return bss;
    800      1.1  christos }
    801      1.1  christos 
    802      1.1  christos 
    803  1.1.1.3  christos /**
    804  1.1.1.3  christos  * wpa_bss_update_start - Start a BSS table update from scan results
    805  1.1.1.3  christos  * @wpa_s: Pointer to wpa_supplicant data
    806  1.1.1.3  christos  *
    807  1.1.1.3  christos  * This function is called at the start of each BSS table update round for new
    808  1.1.1.3  christos  * scan results. The actual scan result entries are indicated with calls to
    809  1.1.1.3  christos  * wpa_bss_update_scan_res() and the update round is finished with a call to
    810  1.1.1.3  christos  * wpa_bss_update_end().
    811  1.1.1.3  christos  */
    812      1.1  christos void wpa_bss_update_start(struct wpa_supplicant *wpa_s)
    813      1.1  christos {
    814      1.1  christos 	wpa_s->bss_update_idx++;
    815  1.1.1.2  christos 	wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Start scan result update %u",
    816  1.1.1.2  christos 		wpa_s->bss_update_idx);
    817  1.1.1.3  christos 	wpa_s->last_scan_res_used = 0;
    818      1.1  christos }
    819      1.1  christos 
    820      1.1  christos 
    821  1.1.1.3  christos /**
    822  1.1.1.3  christos  * wpa_bss_update_scan_res - Update a BSS table entry based on a scan result
    823  1.1.1.3  christos  * @wpa_s: Pointer to wpa_supplicant data
    824  1.1.1.3  christos  * @res: Scan result
    825  1.1.1.4  christos  * @fetch_time: Time when the result was fetched from the driver
    826  1.1.1.3  christos  *
    827  1.1.1.3  christos  * This function updates a BSS table entry (or adds one) based on a scan result.
    828  1.1.1.3  christos  * This is called separately for each scan result between the calls to
    829  1.1.1.3  christos  * wpa_bss_update_start() and wpa_bss_update_end().
    830  1.1.1.3  christos  */
    831      1.1  christos void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
    832  1.1.1.4  christos 			     struct wpa_scan_res *res,
    833  1.1.1.4  christos 			     struct os_reltime *fetch_time)
    834      1.1  christos {
    835  1.1.1.5  christos 	const u8 *ssid, *p2p, *mesh;
    836      1.1  christos 	struct wpa_bss *bss;
    837      1.1  christos 
    838  1.1.1.4  christos 	if (wpa_s->conf->ignore_old_scan_res) {
    839  1.1.1.4  christos 		struct os_reltime update;
    840  1.1.1.4  christos 		calculate_update_time(fetch_time, res->age, &update);
    841  1.1.1.4  christos 		if (os_reltime_before(&update, &wpa_s->scan_trigger_time)) {
    842  1.1.1.4  christos 			struct os_reltime age;
    843  1.1.1.4  christos 			os_reltime_sub(&wpa_s->scan_trigger_time, &update,
    844  1.1.1.4  christos 				       &age);
    845  1.1.1.4  christos 			wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Ignore driver BSS "
    846  1.1.1.4  christos 				"table entry that is %u.%06u seconds older "
    847  1.1.1.4  christos 				"than our scan trigger",
    848  1.1.1.4  christos 				(unsigned int) age.sec,
    849  1.1.1.4  christos 				(unsigned int) age.usec);
    850  1.1.1.4  christos 			return;
    851  1.1.1.4  christos 		}
    852  1.1.1.4  christos 	}
    853  1.1.1.4  christos 
    854      1.1  christos 	ssid = wpa_scan_get_ie(res, WLAN_EID_SSID);
    855      1.1  christos 	if (ssid == NULL) {
    856  1.1.1.2  christos 		wpa_dbg(wpa_s, MSG_DEBUG, "BSS: No SSID IE included for "
    857  1.1.1.2  christos 			MACSTR, MAC2STR(res->bssid));
    858      1.1  christos 		return;
    859      1.1  christos 	}
    860  1.1.1.6  christos 	if (ssid[1] > SSID_MAX_LEN) {
    861  1.1.1.2  christos 		wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Too long SSID IE included for "
    862  1.1.1.2  christos 			MACSTR, MAC2STR(res->bssid));
    863      1.1  christos 		return;
    864      1.1  christos 	}
    865      1.1  christos 
    866  1.1.1.2  christos 	p2p = wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE);
    867  1.1.1.3  christos #ifdef CONFIG_P2P
    868  1.1.1.3  christos 	if (p2p == NULL &&
    869  1.1.1.3  christos 	    wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
    870  1.1.1.3  christos 		/*
    871  1.1.1.3  christos 		 * If it's a P2P specific interface, then don't update
    872  1.1.1.3  christos 		 * the scan result without a P2P IE.
    873  1.1.1.3  christos 		 */
    874  1.1.1.3  christos 		wpa_printf(MSG_DEBUG, "BSS: No P2P IE - skipping BSS " MACSTR
    875  1.1.1.3  christos 			   " update for P2P interface", MAC2STR(res->bssid));
    876  1.1.1.3  christos 		return;
    877  1.1.1.3  christos 	}
    878  1.1.1.3  christos #endif /* CONFIG_P2P */
    879  1.1.1.2  christos 	if (p2p && ssid[1] == P2P_WILDCARD_SSID_LEN &&
    880  1.1.1.2  christos 	    os_memcmp(ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 0)
    881  1.1.1.2  christos 		return; /* Skip P2P listen discovery results here */
    882  1.1.1.2  christos 
    883      1.1  christos 	/* TODO: add option for ignoring BSSes we are not interested in
    884      1.1  christos 	 * (to save memory) */
    885  1.1.1.5  christos 
    886  1.1.1.5  christos 	mesh = wpa_scan_get_ie(res, WLAN_EID_MESH_ID);
    887  1.1.1.6  christos 	if (mesh && mesh[1] <= SSID_MAX_LEN)
    888  1.1.1.5  christos 		ssid = mesh;
    889  1.1.1.5  christos 
    890      1.1  christos 	bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
    891      1.1  christos 	if (bss == NULL)
    892  1.1.1.4  christos 		bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res, fetch_time);
    893  1.1.1.4  christos 	else {
    894  1.1.1.4  christos 		bss = wpa_bss_update(wpa_s, bss, res, fetch_time);
    895  1.1.1.4  christos 		if (wpa_s->last_scan_res) {
    896  1.1.1.4  christos 			unsigned int i;
    897  1.1.1.4  christos 			for (i = 0; i < wpa_s->last_scan_res_used; i++) {
    898  1.1.1.4  christos 				if (bss == wpa_s->last_scan_res[i]) {
    899  1.1.1.4  christos 					/* Already in the list */
    900  1.1.1.4  christos 					return;
    901  1.1.1.4  christos 				}
    902  1.1.1.4  christos 			}
    903  1.1.1.4  christos 		}
    904  1.1.1.4  christos 	}
    905  1.1.1.3  christos 
    906  1.1.1.3  christos 	if (bss == NULL)
    907  1.1.1.3  christos 		return;
    908  1.1.1.3  christos 	if (wpa_s->last_scan_res_used >= wpa_s->last_scan_res_size) {
    909  1.1.1.3  christos 		struct wpa_bss **n;
    910  1.1.1.3  christos 		unsigned int siz;
    911  1.1.1.3  christos 		if (wpa_s->last_scan_res_size == 0)
    912  1.1.1.3  christos 			siz = 32;
    913  1.1.1.3  christos 		else
    914  1.1.1.3  christos 			siz = wpa_s->last_scan_res_size * 2;
    915  1.1.1.3  christos 		n = os_realloc_array(wpa_s->last_scan_res, siz,
    916  1.1.1.3  christos 				     sizeof(struct wpa_bss *));
    917  1.1.1.3  christos 		if (n == NULL)
    918  1.1.1.3  christos 			return;
    919  1.1.1.3  christos 		wpa_s->last_scan_res = n;
    920  1.1.1.3  christos 		wpa_s->last_scan_res_size = siz;
    921  1.1.1.3  christos 	}
    922  1.1.1.3  christos 
    923  1.1.1.4  christos 	if (wpa_s->last_scan_res)
    924  1.1.1.4  christos 		wpa_s->last_scan_res[wpa_s->last_scan_res_used++] = bss;
    925      1.1  christos }
    926      1.1  christos 
    927      1.1  christos 
    928      1.1  christos static int wpa_bss_included_in_scan(const struct wpa_bss *bss,
    929      1.1  christos 				    const struct scan_info *info)
    930      1.1  christos {
    931      1.1  christos 	int found;
    932      1.1  christos 	size_t i;
    933      1.1  christos 
    934      1.1  christos 	if (info == NULL)
    935      1.1  christos 		return 1;
    936      1.1  christos 
    937      1.1  christos 	if (info->num_freqs) {
    938      1.1  christos 		found = 0;
    939      1.1  christos 		for (i = 0; i < info->num_freqs; i++) {
    940      1.1  christos 			if (bss->freq == info->freqs[i]) {
    941      1.1  christos 				found = 1;
    942      1.1  christos 				break;
    943      1.1  christos 			}
    944      1.1  christos 		}
    945      1.1  christos 		if (!found)
    946      1.1  christos 			return 0;
    947      1.1  christos 	}
    948      1.1  christos 
    949      1.1  christos 	if (info->num_ssids) {
    950      1.1  christos 		found = 0;
    951      1.1  christos 		for (i = 0; i < info->num_ssids; i++) {
    952      1.1  christos 			const struct wpa_driver_scan_ssid *s = &info->ssids[i];
    953      1.1  christos 			if ((s->ssid == NULL || s->ssid_len == 0) ||
    954      1.1  christos 			    (s->ssid_len == bss->ssid_len &&
    955      1.1  christos 			     os_memcmp(s->ssid, bss->ssid, bss->ssid_len) ==
    956      1.1  christos 			     0)) {
    957      1.1  christos 				found = 1;
    958      1.1  christos 				break;
    959      1.1  christos 			}
    960      1.1  christos 		}
    961      1.1  christos 		if (!found)
    962      1.1  christos 			return 0;
    963      1.1  christos 	}
    964      1.1  christos 
    965      1.1  christos 	return 1;
    966      1.1  christos }
    967      1.1  christos 
    968      1.1  christos 
    969  1.1.1.3  christos /**
    970  1.1.1.3  christos  * wpa_bss_update_end - End a BSS table update from scan results
    971  1.1.1.3  christos  * @wpa_s: Pointer to wpa_supplicant data
    972  1.1.1.3  christos  * @info: Information about scan parameters
    973  1.1.1.3  christos  * @new_scan: Whether this update round was based on a new scan
    974  1.1.1.3  christos  *
    975  1.1.1.3  christos  * This function is called at the end of each BSS table update round for new
    976  1.1.1.3  christos  * scan results. The start of the update was indicated with a call to
    977  1.1.1.3  christos  * wpa_bss_update_start().
    978  1.1.1.3  christos  */
    979      1.1  christos void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
    980      1.1  christos 			int new_scan)
    981      1.1  christos {
    982      1.1  christos 	struct wpa_bss *bss, *n;
    983      1.1  christos 
    984  1.1.1.4  christos 	os_get_reltime(&wpa_s->last_scan);
    985  1.1.1.6  christos 	if ((info && info->aborted) || !new_scan)
    986      1.1  christos 		return; /* do not expire entries without new scan */
    987      1.1  christos 
    988      1.1  christos 	dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
    989      1.1  christos 		if (wpa_bss_in_use(wpa_s, bss))
    990      1.1  christos 			continue;
    991      1.1  christos 		if (!wpa_bss_included_in_scan(bss, info))
    992      1.1  christos 			continue; /* expire only BSSes that were scanned */
    993      1.1  christos 		if (bss->last_update_idx < wpa_s->bss_update_idx)
    994      1.1  christos 			bss->scan_miss_count++;
    995  1.1.1.2  christos 		if (bss->scan_miss_count >=
    996  1.1.1.2  christos 		    wpa_s->conf->bss_expiration_scan_count) {
    997  1.1.1.3  christos 			wpa_bss_remove(wpa_s, bss, "no match in scan");
    998      1.1  christos 		}
    999      1.1  christos 	}
   1000  1.1.1.3  christos 
   1001  1.1.1.9  christos 	wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%zu/%zu",
   1002  1.1.1.4  christos 		   wpa_s->last_scan_res_used, wpa_s->last_scan_res_size);
   1003      1.1  christos }
   1004      1.1  christos 
   1005      1.1  christos 
   1006  1.1.1.3  christos /**
   1007  1.1.1.3  christos  * wpa_bss_flush_by_age - Flush old BSS entries
   1008  1.1.1.3  christos  * @wpa_s: Pointer to wpa_supplicant data
   1009  1.1.1.3  christos  * @age: Maximum entry age in seconds
   1010  1.1.1.3  christos  *
   1011  1.1.1.3  christos  * Remove BSS entries that have not been updated during the last @age seconds.
   1012  1.1.1.3  christos  */
   1013  1.1.1.2  christos void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age)
   1014      1.1  christos {
   1015      1.1  christos 	struct wpa_bss *bss, *n;
   1016  1.1.1.4  christos 	struct os_reltime t;
   1017      1.1  christos 
   1018      1.1  christos 	if (dl_list_empty(&wpa_s->bss))
   1019      1.1  christos 		return;
   1020      1.1  christos 
   1021  1.1.1.4  christos 	os_get_reltime(&t);
   1022  1.1.1.9  christos 
   1023  1.1.1.9  christos 	if (t.sec < age)
   1024  1.1.1.9  christos 		return; /* avoid underflow; there can be no older entries */
   1025  1.1.1.9  christos 
   1026  1.1.1.2  christos 	t.sec -= age;
   1027      1.1  christos 
   1028      1.1  christos 	dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
   1029      1.1  christos 		if (wpa_bss_in_use(wpa_s, bss))
   1030      1.1  christos 			continue;
   1031      1.1  christos 
   1032  1.1.1.9  christos 		if (wpa_s->reassoc_same_ess &&
   1033  1.1.1.9  christos 		    wpa_s->wpa_state != WPA_COMPLETED &&
   1034  1.1.1.9  christos 		    wpa_s->last_ssid &&
   1035  1.1.1.9  christos 		    bss->ssid_len == wpa_s->last_ssid->ssid_len &&
   1036  1.1.1.9  christos 		    os_memcmp(bss->ssid, wpa_s->last_ssid->ssid,
   1037  1.1.1.9  christos 			      bss->ssid_len) == 0)
   1038  1.1.1.9  christos 			continue;
   1039  1.1.1.9  christos 
   1040  1.1.1.4  christos 		if (os_reltime_before(&bss->last_update, &t)) {
   1041  1.1.1.3  christos 			wpa_bss_remove(wpa_s, bss, __func__);
   1042      1.1  christos 		} else
   1043      1.1  christos 			break;
   1044      1.1  christos 	}
   1045  1.1.1.2  christos }
   1046  1.1.1.2  christos 
   1047  1.1.1.2  christos 
   1048  1.1.1.3  christos /**
   1049  1.1.1.3  christos  * wpa_bss_init - Initialize BSS table
   1050  1.1.1.3  christos  * @wpa_s: Pointer to wpa_supplicant data
   1051  1.1.1.3  christos  * Returns: 0 on success, -1 on failure
   1052  1.1.1.3  christos  *
   1053  1.1.1.3  christos  * This prepares BSS table lists and timer for periodic updates. The BSS table
   1054  1.1.1.3  christos  * is deinitialized with wpa_bss_deinit() once not needed anymore.
   1055  1.1.1.3  christos  */
   1056      1.1  christos int wpa_bss_init(struct wpa_supplicant *wpa_s)
   1057      1.1  christos {
   1058      1.1  christos 	dl_list_init(&wpa_s->bss);
   1059      1.1  christos 	dl_list_init(&wpa_s->bss_id);
   1060      1.1  christos 	return 0;
   1061      1.1  christos }
   1062      1.1  christos 
   1063      1.1  christos 
   1064  1.1.1.3  christos /**
   1065  1.1.1.3  christos  * wpa_bss_flush - Flush all unused BSS entries
   1066  1.1.1.3  christos  * @wpa_s: Pointer to wpa_supplicant data
   1067  1.1.1.3  christos  */
   1068  1.1.1.2  christos void wpa_bss_flush(struct wpa_supplicant *wpa_s)
   1069      1.1  christos {
   1070      1.1  christos 	struct wpa_bss *bss, *n;
   1071  1.1.1.2  christos 
   1072  1.1.1.4  christos 	wpa_s->clear_driver_scan_cache = 1;
   1073  1.1.1.4  christos 
   1074      1.1  christos 	if (wpa_s->bss.next == NULL)
   1075      1.1  christos 		return; /* BSS table not yet initialized */
   1076  1.1.1.2  christos 
   1077  1.1.1.2  christos 	dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
   1078  1.1.1.2  christos 		if (wpa_bss_in_use(wpa_s, bss))
   1079  1.1.1.2  christos 			continue;
   1080  1.1.1.3  christos 		wpa_bss_remove(wpa_s, bss, __func__);
   1081  1.1.1.2  christos 	}
   1082  1.1.1.2  christos }
   1083  1.1.1.2  christos 
   1084  1.1.1.2  christos 
   1085  1.1.1.3  christos /**
   1086  1.1.1.3  christos  * wpa_bss_deinit - Deinitialize BSS table
   1087  1.1.1.3  christos  * @wpa_s: Pointer to wpa_supplicant data
   1088  1.1.1.3  christos  */
   1089  1.1.1.2  christos void wpa_bss_deinit(struct wpa_supplicant *wpa_s)
   1090  1.1.1.2  christos {
   1091  1.1.1.2  christos 	wpa_bss_flush(wpa_s);
   1092      1.1  christos }
   1093      1.1  christos 
   1094      1.1  christos 
   1095  1.1.1.3  christos /**
   1096  1.1.1.3  christos  * wpa_bss_get_bssid - Fetch a BSS table entry based on BSSID
   1097  1.1.1.3  christos  * @wpa_s: Pointer to wpa_supplicant data
   1098  1.1.1.3  christos  * @bssid: BSSID
   1099  1.1.1.3  christos  * Returns: Pointer to the BSS entry or %NULL if not found
   1100  1.1.1.3  christos  */
   1101      1.1  christos struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
   1102      1.1  christos 				   const u8 *bssid)
   1103      1.1  christos {
   1104      1.1  christos 	struct wpa_bss *bss;
   1105  1.1.1.3  christos 	if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
   1106  1.1.1.3  christos 		return NULL;
   1107  1.1.1.2  christos 	dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
   1108  1.1.1.9  christos 		if (ether_addr_equal(bss->bssid, bssid))
   1109      1.1  christos 			return bss;
   1110      1.1  christos 	}
   1111      1.1  christos 	return NULL;
   1112      1.1  christos }
   1113      1.1  christos 
   1114      1.1  christos 
   1115  1.1.1.4  christos /**
   1116  1.1.1.4  christos  * wpa_bss_get_bssid_latest - Fetch the latest BSS table entry based on BSSID
   1117  1.1.1.4  christos  * @wpa_s: Pointer to wpa_supplicant data
   1118  1.1.1.4  christos  * @bssid: BSSID
   1119  1.1.1.4  christos  * Returns: Pointer to the BSS entry or %NULL if not found
   1120  1.1.1.4  christos  *
   1121  1.1.1.4  christos  * This function is like wpa_bss_get_bssid(), but full BSS table is iterated to
   1122  1.1.1.4  christos  * find the entry that has the most recent update. This can help in finding the
   1123  1.1.1.4  christos  * correct entry in cases where the SSID of the AP may have changed recently
   1124  1.1.1.4  christos  * (e.g., in WPS reconfiguration cases).
   1125  1.1.1.4  christos  */
   1126  1.1.1.4  christos struct wpa_bss * wpa_bss_get_bssid_latest(struct wpa_supplicant *wpa_s,
   1127  1.1.1.4  christos 					  const u8 *bssid)
   1128  1.1.1.4  christos {
   1129  1.1.1.4  christos 	struct wpa_bss *bss, *found = NULL;
   1130  1.1.1.4  christos 	if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
   1131  1.1.1.4  christos 		return NULL;
   1132  1.1.1.4  christos 	dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
   1133  1.1.1.9  christos 		if (!ether_addr_equal(bss->bssid, bssid))
   1134  1.1.1.4  christos 			continue;
   1135  1.1.1.4  christos 		if (found == NULL ||
   1136  1.1.1.4  christos 		    os_reltime_before(&found->last_update, &bss->last_update))
   1137  1.1.1.4  christos 			found = bss;
   1138  1.1.1.4  christos 	}
   1139  1.1.1.4  christos 	return found;
   1140  1.1.1.4  christos }
   1141  1.1.1.4  christos 
   1142  1.1.1.4  christos 
   1143  1.1.1.2  christos #ifdef CONFIG_P2P
   1144  1.1.1.3  christos /**
   1145  1.1.1.9  christos  * wpa_bss_get_p2p_dev_addr - Fetch the latest BSS table entry based on P2P Device Addr
   1146  1.1.1.3  christos  * @wpa_s: Pointer to wpa_supplicant data
   1147  1.1.1.3  christos  * @dev_addr: P2P Device Address of the GO
   1148  1.1.1.3  christos  * Returns: Pointer to the BSS entry or %NULL if not found
   1149  1.1.1.9  christos  *
   1150  1.1.1.9  christos  * This function tries to find the entry that has the most recent update. This
   1151  1.1.1.9  christos  * can help in finding the correct entry in cases where the SSID of the P2P
   1152  1.1.1.9  christos  * Device may have changed recently.
   1153  1.1.1.3  christos  */
   1154  1.1.1.2  christos struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s,
   1155  1.1.1.2  christos 					  const u8 *dev_addr)
   1156  1.1.1.2  christos {
   1157  1.1.1.9  christos 	struct wpa_bss *bss, *found = NULL;
   1158  1.1.1.2  christos 	dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
   1159  1.1.1.2  christos 		u8 addr[ETH_ALEN];
   1160  1.1.1.9  christos 		if (p2p_parse_dev_addr(wpa_bss_ie_ptr(bss), bss->ie_len,
   1161  1.1.1.9  christos 				       addr) != 0 ||
   1162  1.1.1.9  christos 		    !ether_addr_equal(addr, dev_addr))
   1163  1.1.1.9  christos 			continue;
   1164  1.1.1.9  christos 		if (!found ||
   1165  1.1.1.9  christos 		    os_reltime_before(&found->last_update, &bss->last_update))
   1166  1.1.1.9  christos 			found = bss;
   1167  1.1.1.2  christos 	}
   1168  1.1.1.9  christos 	return found;
   1169  1.1.1.2  christos }
   1170  1.1.1.2  christos #endif /* CONFIG_P2P */
   1171  1.1.1.2  christos 
   1172  1.1.1.2  christos 
   1173  1.1.1.3  christos /**
   1174  1.1.1.3  christos  * wpa_bss_get_id - Fetch a BSS table entry based on identifier
   1175  1.1.1.3  christos  * @wpa_s: Pointer to wpa_supplicant data
   1176  1.1.1.3  christos  * @id: Unique identifier (struct wpa_bss::id) assigned for the entry
   1177  1.1.1.3  christos  * Returns: Pointer to the BSS entry or %NULL if not found
   1178  1.1.1.3  christos  */
   1179      1.1  christos struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id)
   1180      1.1  christos {
   1181      1.1  christos 	struct wpa_bss *bss;
   1182      1.1  christos 	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
   1183      1.1  christos 		if (bss->id == id)
   1184      1.1  christos 			return bss;
   1185      1.1  christos 	}
   1186      1.1  christos 	return NULL;
   1187      1.1  christos }
   1188      1.1  christos 
   1189      1.1  christos 
   1190  1.1.1.3  christos /**
   1191  1.1.1.4  christos  * wpa_bss_get_id_range - Fetch a BSS table entry based on identifier range
   1192  1.1.1.4  christos  * @wpa_s: Pointer to wpa_supplicant data
   1193  1.1.1.4  christos  * @idf: Smallest allowed identifier assigned for the entry
   1194  1.1.1.4  christos  * @idf: Largest allowed identifier assigned for the entry
   1195  1.1.1.4  christos  * Returns: Pointer to the BSS entry or %NULL if not found
   1196  1.1.1.4  christos  *
   1197  1.1.1.4  christos  * This function is similar to wpa_bss_get_id() but allows a BSS entry with the
   1198  1.1.1.4  christos  * smallest id value to be fetched within the specified range without the
   1199  1.1.1.4  christos  * caller having to know the exact id.
   1200  1.1.1.4  christos  */
   1201  1.1.1.4  christos struct wpa_bss * wpa_bss_get_id_range(struct wpa_supplicant *wpa_s,
   1202  1.1.1.4  christos 				      unsigned int idf, unsigned int idl)
   1203  1.1.1.4  christos {
   1204  1.1.1.4  christos 	struct wpa_bss *bss;
   1205  1.1.1.4  christos 	dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
   1206  1.1.1.4  christos 		if (bss->id >= idf && bss->id <= idl)
   1207  1.1.1.4  christos 			return bss;
   1208  1.1.1.4  christos 	}
   1209  1.1.1.4  christos 	return NULL;
   1210  1.1.1.4  christos }
   1211  1.1.1.4  christos 
   1212  1.1.1.4  christos 
   1213  1.1.1.4  christos /**
   1214  1.1.1.3  christos  * wpa_bss_get_ie - Fetch a specified information element from a BSS entry
   1215  1.1.1.3  christos  * @bss: BSS table entry
   1216  1.1.1.3  christos  * @ie: Information element identitifier (WLAN_EID_*)
   1217  1.1.1.3  christos  * Returns: Pointer to the information element (id field) or %NULL if not found
   1218  1.1.1.3  christos  *
   1219  1.1.1.3  christos  * This function returns the first matching information element in the BSS
   1220  1.1.1.3  christos  * entry.
   1221  1.1.1.3  christos  */
   1222      1.1  christos const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
   1223      1.1  christos {
   1224  1.1.1.9  christos 	return get_ie(wpa_bss_ie_ptr(bss), bss->ie_len, ie);
   1225  1.1.1.9  christos }
   1226  1.1.1.9  christos 
   1227  1.1.1.9  christos 
   1228  1.1.1.9  christos /**
   1229  1.1.1.9  christos  * wpa_bss_get_ie_beacon - Fetch a specified information element from a BSS entry
   1230  1.1.1.9  christos  * @bss: BSS table entry
   1231  1.1.1.9  christos  * @ie: Information element identitifier (WLAN_EID_*)
   1232  1.1.1.9  christos  * Returns: Pointer to the information element (id field) or %NULL if not found
   1233  1.1.1.9  christos  *
   1234  1.1.1.9  christos  * This function returns the first matching information element in the BSS
   1235  1.1.1.9  christos  * entry.
   1236  1.1.1.9  christos  *
   1237  1.1.1.9  christos  * This function is like wpa_bss_get_ie(), but uses IE buffer only from Beacon
   1238  1.1.1.9  christos  * frames instead of either Beacon or Probe Response frames.
   1239  1.1.1.9  christos  */
   1240  1.1.1.9  christos const u8 * wpa_bss_get_ie_beacon(const struct wpa_bss *bss, u8 ie)
   1241  1.1.1.9  christos {
   1242  1.1.1.9  christos 	const u8 *ies;
   1243  1.1.1.9  christos 
   1244  1.1.1.9  christos 	if (bss->beacon_ie_len == 0)
   1245  1.1.1.9  christos 		return NULL;
   1246  1.1.1.9  christos 
   1247  1.1.1.9  christos 	ies = wpa_bss_ie_ptr(bss);
   1248  1.1.1.9  christos 	ies += bss->ie_len;
   1249  1.1.1.9  christos 	return get_ie(ies, bss->beacon_ie_len, ie);
   1250  1.1.1.9  christos }
   1251  1.1.1.9  christos 
   1252  1.1.1.9  christos 
   1253  1.1.1.9  christos /**
   1254  1.1.1.9  christos  * wpa_bss_get_ie_ext - Fetch a specified extended IE from a BSS entry
   1255  1.1.1.9  christos  * @bss: BSS table entry
   1256  1.1.1.9  christos  * @ext: Information element extension identifier (WLAN_EID_EXT_*)
   1257  1.1.1.9  christos  * Returns: Pointer to the information element (id field) or %NULL if not found
   1258  1.1.1.9  christos  *
   1259  1.1.1.9  christos  * This function returns the first matching information element in the BSS
   1260  1.1.1.9  christos  * entry.
   1261  1.1.1.9  christos  */
   1262  1.1.1.9  christos const u8 * wpa_bss_get_ie_ext(const struct wpa_bss *bss, u8 ext)
   1263  1.1.1.9  christos {
   1264  1.1.1.9  christos 	return get_ie_ext(wpa_bss_ie_ptr(bss), bss->ie_len, ext);
   1265      1.1  christos }
   1266      1.1  christos 
   1267      1.1  christos 
   1268  1.1.1.3  christos /**
   1269  1.1.1.3  christos  * wpa_bss_get_vendor_ie - Fetch a vendor information element from a BSS entry
   1270  1.1.1.3  christos  * @bss: BSS table entry
   1271  1.1.1.3  christos  * @vendor_type: Vendor type (four octets starting the IE payload)
   1272  1.1.1.3  christos  * Returns: Pointer to the information element (id field) or %NULL if not found
   1273  1.1.1.3  christos  *
   1274  1.1.1.3  christos  * This function returns the first matching information element in the BSS
   1275  1.1.1.3  christos  * entry.
   1276  1.1.1.3  christos  */
   1277      1.1  christos const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
   1278      1.1  christos {
   1279  1.1.1.9  christos 	const u8 *ies;
   1280  1.1.1.9  christos 	const struct element *elem;
   1281      1.1  christos 
   1282  1.1.1.9  christos 	ies = wpa_bss_ie_ptr(bss);
   1283      1.1  christos 
   1284  1.1.1.9  christos 	for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, bss->ie_len) {
   1285  1.1.1.9  christos 		if (elem->datalen >= 4 &&
   1286  1.1.1.9  christos 		    vendor_type == WPA_GET_BE32(elem->data))
   1287  1.1.1.9  christos 			return &elem->id;
   1288      1.1  christos 	}
   1289      1.1  christos 
   1290      1.1  christos 	return NULL;
   1291      1.1  christos }
   1292      1.1  christos 
   1293      1.1  christos 
   1294  1.1.1.3  christos /**
   1295  1.1.1.4  christos  * wpa_bss_get_vendor_ie_beacon - Fetch a vendor information from a BSS entry
   1296  1.1.1.4  christos  * @bss: BSS table entry
   1297  1.1.1.4  christos  * @vendor_type: Vendor type (four octets starting the IE payload)
   1298  1.1.1.4  christos  * Returns: Pointer to the information element (id field) or %NULL if not found
   1299  1.1.1.4  christos  *
   1300  1.1.1.4  christos  * This function returns the first matching information element in the BSS
   1301  1.1.1.4  christos  * entry.
   1302  1.1.1.4  christos  *
   1303  1.1.1.4  christos  * This function is like wpa_bss_get_vendor_ie(), but uses IE buffer only
   1304  1.1.1.4  christos  * from Beacon frames instead of either Beacon or Probe Response frames.
   1305  1.1.1.4  christos  */
   1306  1.1.1.4  christos const u8 * wpa_bss_get_vendor_ie_beacon(const struct wpa_bss *bss,
   1307  1.1.1.4  christos 					u32 vendor_type)
   1308  1.1.1.4  christos {
   1309  1.1.1.9  christos 	const u8 *ies;
   1310  1.1.1.9  christos 	const struct element *elem;
   1311  1.1.1.4  christos 
   1312  1.1.1.4  christos 	if (bss->beacon_ie_len == 0)
   1313  1.1.1.4  christos 		return NULL;
   1314  1.1.1.4  christos 
   1315  1.1.1.9  christos 	ies = wpa_bss_ie_ptr(bss);
   1316  1.1.1.9  christos 	ies += bss->ie_len;
   1317  1.1.1.4  christos 
   1318  1.1.1.9  christos 	for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies,
   1319  1.1.1.9  christos 			    bss->beacon_ie_len) {
   1320  1.1.1.9  christos 		if (elem->datalen >= 4 &&
   1321  1.1.1.9  christos 		    vendor_type == WPA_GET_BE32(elem->data))
   1322  1.1.1.9  christos 			return &elem->id;
   1323  1.1.1.4  christos 	}
   1324  1.1.1.4  christos 
   1325  1.1.1.4  christos 	return NULL;
   1326  1.1.1.4  christos }
   1327  1.1.1.4  christos 
   1328  1.1.1.4  christos 
   1329  1.1.1.4  christos /**
   1330  1.1.1.3  christos  * wpa_bss_get_vendor_ie_multi - Fetch vendor IE data from a BSS entry
   1331  1.1.1.3  christos  * @bss: BSS table entry
   1332  1.1.1.3  christos  * @vendor_type: Vendor type (four octets starting the IE payload)
   1333  1.1.1.3  christos  * Returns: Pointer to the information element payload or %NULL if not found
   1334  1.1.1.3  christos  *
   1335  1.1.1.3  christos  * This function returns concatenated payload of possibly fragmented vendor
   1336  1.1.1.3  christos  * specific information elements in the BSS entry. The caller is responsible for
   1337  1.1.1.3  christos  * freeing the returned buffer.
   1338  1.1.1.3  christos  */
   1339      1.1  christos struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
   1340      1.1  christos 					    u32 vendor_type)
   1341      1.1  christos {
   1342      1.1  christos 	struct wpabuf *buf;
   1343      1.1  christos 	const u8 *end, *pos;
   1344      1.1  christos 
   1345      1.1  christos 	buf = wpabuf_alloc(bss->ie_len);
   1346      1.1  christos 	if (buf == NULL)
   1347      1.1  christos 		return NULL;
   1348      1.1  christos 
   1349  1.1.1.9  christos 	pos = wpa_bss_ie_ptr(bss);
   1350      1.1  christos 	end = pos + bss->ie_len;
   1351      1.1  christos 
   1352  1.1.1.6  christos 	while (end - pos > 1) {
   1353  1.1.1.9  christos 		u8 ie, len;
   1354  1.1.1.9  christos 
   1355  1.1.1.9  christos 		ie = pos[0];
   1356  1.1.1.9  christos 		len = pos[1];
   1357  1.1.1.9  christos 		if (len > end - pos - 2)
   1358      1.1  christos 			break;
   1359  1.1.1.9  christos 		pos += 2;
   1360  1.1.1.9  christos 		if (ie == WLAN_EID_VENDOR_SPECIFIC && len >= 4 &&
   1361  1.1.1.9  christos 		    vendor_type == WPA_GET_BE32(pos))
   1362  1.1.1.9  christos 			wpabuf_put_data(buf, pos + 4, len - 4);
   1363  1.1.1.9  christos 		pos += len;
   1364      1.1  christos 	}
   1365      1.1  christos 
   1366      1.1  christos 	if (wpabuf_len(buf) == 0) {
   1367      1.1  christos 		wpabuf_free(buf);
   1368      1.1  christos 		buf = NULL;
   1369      1.1  christos 	}
   1370      1.1  christos 
   1371      1.1  christos 	return buf;
   1372      1.1  christos }
   1373      1.1  christos 
   1374      1.1  christos 
   1375  1.1.1.3  christos /**
   1376  1.1.1.3  christos  * wpa_bss_get_vendor_ie_multi_beacon - Fetch vendor IE data from a BSS entry
   1377  1.1.1.3  christos  * @bss: BSS table entry
   1378  1.1.1.3  christos  * @vendor_type: Vendor type (four octets starting the IE payload)
   1379  1.1.1.3  christos  * Returns: Pointer to the information element payload or %NULL if not found
   1380  1.1.1.3  christos  *
   1381  1.1.1.3  christos  * This function returns concatenated payload of possibly fragmented vendor
   1382  1.1.1.3  christos  * specific information elements in the BSS entry. The caller is responsible for
   1383  1.1.1.3  christos  * freeing the returned buffer.
   1384  1.1.1.3  christos  *
   1385  1.1.1.3  christos  * This function is like wpa_bss_get_vendor_ie_multi(), but uses IE buffer only
   1386  1.1.1.3  christos  * from Beacon frames instead of either Beacon or Probe Response frames.
   1387  1.1.1.3  christos  */
   1388  1.1.1.3  christos struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss,
   1389  1.1.1.3  christos 						   u32 vendor_type)
   1390  1.1.1.3  christos {
   1391  1.1.1.3  christos 	struct wpabuf *buf;
   1392  1.1.1.3  christos 	const u8 *end, *pos;
   1393  1.1.1.3  christos 
   1394  1.1.1.3  christos 	buf = wpabuf_alloc(bss->beacon_ie_len);
   1395  1.1.1.3  christos 	if (buf == NULL)
   1396  1.1.1.3  christos 		return NULL;
   1397  1.1.1.3  christos 
   1398  1.1.1.9  christos 	pos = wpa_bss_ie_ptr(bss);
   1399  1.1.1.3  christos 	pos += bss->ie_len;
   1400  1.1.1.3  christos 	end = pos + bss->beacon_ie_len;
   1401  1.1.1.3  christos 
   1402  1.1.1.6  christos 	while (end - pos > 1) {
   1403  1.1.1.9  christos 		u8 id, len;
   1404  1.1.1.9  christos 
   1405  1.1.1.9  christos 		id = *pos++;
   1406  1.1.1.9  christos 		len = *pos++;
   1407  1.1.1.9  christos 		if (len > end - pos)
   1408  1.1.1.3  christos 			break;
   1409  1.1.1.9  christos 		if (id == WLAN_EID_VENDOR_SPECIFIC && len >= 4 &&
   1410  1.1.1.9  christos 		    vendor_type == WPA_GET_BE32(pos))
   1411  1.1.1.9  christos 			wpabuf_put_data(buf, pos + 4, len - 4);
   1412  1.1.1.9  christos 		pos += len;
   1413  1.1.1.3  christos 	}
   1414  1.1.1.3  christos 
   1415  1.1.1.3  christos 	if (wpabuf_len(buf) == 0) {
   1416  1.1.1.3  christos 		wpabuf_free(buf);
   1417  1.1.1.3  christos 		buf = NULL;
   1418  1.1.1.3  christos 	}
   1419  1.1.1.3  christos 
   1420  1.1.1.3  christos 	return buf;
   1421  1.1.1.3  christos }
   1422  1.1.1.3  christos 
   1423  1.1.1.3  christos 
   1424  1.1.1.3  christos /**
   1425  1.1.1.3  christos  * wpa_bss_get_max_rate - Get maximum legacy TX rate supported in a BSS
   1426  1.1.1.3  christos  * @bss: BSS table entry
   1427  1.1.1.3  christos  * Returns: Maximum legacy rate in units of 500 kbps
   1428  1.1.1.3  christos  */
   1429      1.1  christos int wpa_bss_get_max_rate(const struct wpa_bss *bss)
   1430      1.1  christos {
   1431      1.1  christos 	int rate = 0;
   1432      1.1  christos 	const u8 *ie;
   1433      1.1  christos 	int i;
   1434      1.1  christos 
   1435      1.1  christos 	ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
   1436      1.1  christos 	for (i = 0; ie && i < ie[1]; i++) {
   1437      1.1  christos 		if ((ie[i + 2] & 0x7f) > rate)
   1438      1.1  christos 			rate = ie[i + 2] & 0x7f;
   1439      1.1  christos 	}
   1440      1.1  christos 
   1441      1.1  christos 	ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
   1442      1.1  christos 	for (i = 0; ie && i < ie[1]; i++) {
   1443      1.1  christos 		if ((ie[i + 2] & 0x7f) > rate)
   1444      1.1  christos 			rate = ie[i + 2] & 0x7f;
   1445      1.1  christos 	}
   1446      1.1  christos 
   1447      1.1  christos 	return rate;
   1448      1.1  christos }
   1449      1.1  christos 
   1450      1.1  christos 
   1451  1.1.1.3  christos /**
   1452  1.1.1.3  christos  * wpa_bss_get_bit_rates - Get legacy TX rates supported in a BSS
   1453  1.1.1.3  christos  * @bss: BSS table entry
   1454  1.1.1.3  christos  * @rates: Buffer for returning a pointer to the rates list (units of 500 kbps)
   1455  1.1.1.3  christos  * Returns: number of legacy TX rates or -1 on failure
   1456  1.1.1.3  christos  *
   1457  1.1.1.3  christos  * The caller is responsible for freeing the returned buffer with os_free() in
   1458  1.1.1.3  christos  * case of success.
   1459  1.1.1.3  christos  */
   1460      1.1  christos int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates)
   1461      1.1  christos {
   1462      1.1  christos 	const u8 *ie, *ie2;
   1463      1.1  christos 	int i, j;
   1464      1.1  christos 	unsigned int len;
   1465      1.1  christos 	u8 *r;
   1466      1.1  christos 
   1467      1.1  christos 	ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
   1468      1.1  christos 	ie2 = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
   1469      1.1  christos 
   1470      1.1  christos 	len = (ie ? ie[1] : 0) + (ie2 ? ie2[1] : 0);
   1471      1.1  christos 
   1472      1.1  christos 	r = os_malloc(len);
   1473      1.1  christos 	if (!r)
   1474      1.1  christos 		return -1;
   1475      1.1  christos 
   1476      1.1  christos 	for (i = 0; ie && i < ie[1]; i++)
   1477      1.1  christos 		r[i] = ie[i + 2] & 0x7f;
   1478      1.1  christos 
   1479      1.1  christos 	for (j = 0; ie2 && j < ie2[1]; j++)
   1480      1.1  christos 		r[i + j] = ie2[j + 2] & 0x7f;
   1481      1.1  christos 
   1482      1.1  christos 	*rates = r;
   1483      1.1  christos 	return len;
   1484      1.1  christos }
   1485  1.1.1.7  christos 
   1486  1.1.1.7  christos 
   1487  1.1.1.7  christos #ifdef CONFIG_FILS
   1488  1.1.1.9  christos const u8 * wpa_bss_get_fils_cache_id(const struct wpa_bss *bss)
   1489  1.1.1.7  christos {
   1490  1.1.1.7  christos 	const u8 *ie;
   1491  1.1.1.7  christos 
   1492  1.1.1.7  christos 	if (bss) {
   1493  1.1.1.7  christos 		ie = wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION);
   1494  1.1.1.7  christos 		if (ie && ie[1] >= 4 && WPA_GET_LE16(ie + 2) & BIT(7))
   1495  1.1.1.7  christos 			return ie + 4;
   1496  1.1.1.7  christos 	}
   1497  1.1.1.7  christos 
   1498  1.1.1.7  christos 	return NULL;
   1499  1.1.1.7  christos }
   1500  1.1.1.7  christos #endif /* CONFIG_FILS */
   1501  1.1.1.8  christos 
   1502  1.1.1.8  christos 
   1503  1.1.1.8  christos int wpa_bss_ext_capab(const struct wpa_bss *bss, unsigned int capab)
   1504  1.1.1.8  christos {
   1505  1.1.1.9  christos 	if (!bss)
   1506  1.1.1.9  christos 		return 0;
   1507  1.1.1.8  christos 	return ieee802_11_ext_capab(wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB),
   1508  1.1.1.8  christos 				    capab);
   1509  1.1.1.8  christos }
   1510  1.1.1.9  christos 
   1511  1.1.1.9  christos 
   1512  1.1.1.9  christos static void
   1513  1.1.1.9  christos wpa_bss_parse_ml_rnr_ap_info(struct wpa_supplicant *wpa_s,
   1514  1.1.1.9  christos 			     struct wpa_bss *bss, u8 mbssid_idx,
   1515  1.1.1.9  christos 			     const struct ieee80211_neighbor_ap_info *ap_info,
   1516  1.1.1.9  christos 			     size_t len, u16 *seen, u16 *missing,
   1517  1.1.1.9  christos 			     struct wpa_ssid *ssid)
   1518  1.1.1.9  christos {
   1519  1.1.1.9  christos 	const u8 *pos, *end;
   1520  1.1.1.9  christos 	const u8 *mld_params;
   1521  1.1.1.9  christos 	u8 count, mld_params_offset;
   1522  1.1.1.9  christos 	u8 i, type, link_id;
   1523  1.1.1.9  christos 
   1524  1.1.1.9  christos 	count = RNR_TBTT_INFO_COUNT_VAL(ap_info->tbtt_info_hdr) + 1;
   1525  1.1.1.9  christos 	type = ap_info->tbtt_info_hdr & RNR_TBTT_INFO_HDR_TYPE_MSK;
   1526  1.1.1.9  christos 
   1527  1.1.1.9  christos 	/* MLD information is at offset 13 or at start */
   1528  1.1.1.9  christos 	if (type == 0 && ap_info->tbtt_info_len >= RNR_TBTT_INFO_MLD_LEN) {
   1529  1.1.1.9  christos 		/* MLD info is appended */
   1530  1.1.1.9  christos 		mld_params_offset = RNR_TBTT_INFO_LEN;
   1531  1.1.1.9  christos 	} else {
   1532  1.1.1.9  christos 		/* TODO: Support NSTR AP */
   1533  1.1.1.9  christos 		return;
   1534  1.1.1.9  christos 	}
   1535  1.1.1.9  christos 
   1536  1.1.1.9  christos 	pos = (const u8 *) ap_info;
   1537  1.1.1.9  christos 	end = pos + len;
   1538  1.1.1.9  christos 	pos += sizeof(*ap_info);
   1539  1.1.1.9  christos 
   1540  1.1.1.9  christos 	for (i = 0; i < count; i++) {
   1541  1.1.1.9  christos 		u8 bss_params;
   1542  1.1.1.9  christos 
   1543  1.1.1.9  christos 		if (end - pos < ap_info->tbtt_info_len)
   1544  1.1.1.9  christos 			break;
   1545  1.1.1.9  christos 
   1546  1.1.1.9  christos 		bss_params = pos[1 + ETH_ALEN + 4];
   1547  1.1.1.9  christos 		mld_params = pos + mld_params_offset;
   1548  1.1.1.9  christos 
   1549  1.1.1.9  christos 		link_id = *(mld_params + 1) & EHT_ML_LINK_ID_MSK;
   1550  1.1.1.9  christos 		if (link_id >= MAX_NUM_MLD_LINKS)
   1551  1.1.1.9  christos 			return;
   1552  1.1.1.9  christos 
   1553  1.1.1.9  christos 		if (*mld_params != mbssid_idx) {
   1554  1.1.1.9  christos 			wpa_printf(MSG_DEBUG,
   1555  1.1.1.9  christos 				   "MLD: Reported link not part of MLD");
   1556  1.1.1.9  christos 		} else if (!(BIT(link_id) & *seen)) {
   1557  1.1.1.9  christos 			struct wpa_bss *neigh_bss;
   1558  1.1.1.9  christos 
   1559  1.1.1.9  christos 			if (ssid && ssid->ssid_len)
   1560  1.1.1.9  christos 				neigh_bss = wpa_bss_get(wpa_s, pos + 1,
   1561  1.1.1.9  christos 							ssid->ssid,
   1562  1.1.1.9  christos 							ssid->ssid_len);
   1563  1.1.1.9  christos 			else
   1564  1.1.1.9  christos 				neigh_bss = wpa_bss_get_bssid(wpa_s, pos + 1);
   1565  1.1.1.9  christos 
   1566  1.1.1.9  christos 			*seen |= BIT(link_id);
   1567  1.1.1.9  christos 			wpa_printf(MSG_DEBUG, "MLD: mld ID=%u, link ID=%u",
   1568  1.1.1.9  christos 				   *mld_params, link_id);
   1569  1.1.1.9  christos 
   1570  1.1.1.9  christos 			if (!neigh_bss) {
   1571  1.1.1.9  christos 				*missing |= BIT(link_id);
   1572  1.1.1.9  christos 			} else if ((!ssid ||
   1573  1.1.1.9  christos 				    (bss_params & (RNR_BSS_PARAM_SAME_SSID |
   1574  1.1.1.9  christos 						   RNR_BSS_PARAM_CO_LOCATED)) ||
   1575  1.1.1.9  christos 				    wpa_scan_res_match(wpa_s, 0, neigh_bss,
   1576  1.1.1.9  christos 						       ssid, 1, 0)) &&
   1577  1.1.1.9  christos 				   !wpa_bssid_ignore_is_listed(
   1578  1.1.1.9  christos 					   wpa_s, neigh_bss->bssid)) {
   1579  1.1.1.9  christos 				struct mld_link *l;
   1580  1.1.1.9  christos 
   1581  1.1.1.9  christos 				bss->valid_links |= BIT(link_id);
   1582  1.1.1.9  christos 				l = &bss->mld_links[link_id];
   1583  1.1.1.9  christos 				os_memcpy(l->bssid, pos + 1, ETH_ALEN);
   1584  1.1.1.9  christos 				l->freq = neigh_bss->freq;
   1585  1.1.1.9  christos 				l->disabled = mld_params[2] &
   1586  1.1.1.9  christos 					RNR_TBTT_INFO_MLD_PARAM2_LINK_DISABLED;
   1587  1.1.1.9  christos 			}
   1588  1.1.1.9  christos 		}
   1589  1.1.1.9  christos 
   1590  1.1.1.9  christos 		pos += ap_info->tbtt_info_len;
   1591  1.1.1.9  christos 	}
   1592  1.1.1.9  christos }
   1593  1.1.1.9  christos 
   1594  1.1.1.9  christos 
   1595  1.1.1.9  christos /**
   1596  1.1.1.9  christos  * wpa_bss_parse_basic_ml_element - Parse the Basic Multi-Link element
   1597  1.1.1.9  christos  * @wpa_s: Pointer to wpa_supplicant data
   1598  1.1.1.9  christos  * @bss: BSS table entry
   1599  1.1.1.9  christos  * @mld_addr: AP MLD address (or %NULL)
   1600  1.1.1.9  christos  * @link_info: Array to store link information (or %NULL),
   1601  1.1.1.9  christos  *   should be initialized and #MAX_NUM_MLD_LINKS elements long
   1602  1.1.1.9  christos  * @missing_links: Result bitmask of links that were not discovered (or %NULL)
   1603  1.1.1.9  christos  * @ssid: Target SSID (or %NULL)
   1604  1.1.1.9  christos  * @ap_mld_id: On return would hold the corresponding AP MLD ID (or %NULL)
   1605  1.1.1.9  christos  * Returns: 0 on success or -1 for non-MLD or parsing failures
   1606  1.1.1.9  christos  *
   1607  1.1.1.9  christos  * Parses the Basic Multi-Link element of the BSS into @link_info using the scan
   1608  1.1.1.9  christos  * information stored in the wpa_supplicant data to fill in information for
   1609  1.1.1.9  christos  * links where possible. The @missing_links out parameter will contain any links
   1610  1.1.1.9  christos  * for which no corresponding BSS was found.
   1611  1.1.1.9  christos  */
   1612  1.1.1.9  christos int wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s,
   1613  1.1.1.9  christos 				   struct wpa_bss *bss,
   1614  1.1.1.9  christos 				   u8 *ap_mld_addr,
   1615  1.1.1.9  christos 				   u16 *missing_links,
   1616  1.1.1.9  christos 				   struct wpa_ssid *ssid,
   1617  1.1.1.9  christos 				   u8 *ap_mld_id)
   1618  1.1.1.9  christos {
   1619  1.1.1.9  christos 	struct ieee802_11_elems elems;
   1620  1.1.1.9  christos 	struct wpabuf *mlbuf;
   1621  1.1.1.9  christos 	const struct element *elem;
   1622  1.1.1.9  christos 	u8 mbssid_idx = 0;
   1623  1.1.1.9  christos 	size_t ml_ie_len;
   1624  1.1.1.9  christos 	const struct ieee80211_eht_ml *eht_ml;
   1625  1.1.1.9  christos 	const struct eht_ml_basic_common_info *ml_basic_common_info;
   1626  1.1.1.9  christos 	u8 i, link_id;
   1627  1.1.1.9  christos 	const u16 control_mask =
   1628  1.1.1.9  christos 		MULTI_LINK_CONTROL_TYPE_MASK |
   1629  1.1.1.9  christos 		BASIC_MULTI_LINK_CTRL_PRES_LINK_ID |
   1630  1.1.1.9  christos 		BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT |
   1631  1.1.1.9  christos 		BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA;
   1632  1.1.1.9  christos 	const u16 control =
   1633  1.1.1.9  christos 		MULTI_LINK_CONTROL_TYPE_BASIC |
   1634  1.1.1.9  christos 		BASIC_MULTI_LINK_CTRL_PRES_LINK_ID |
   1635  1.1.1.9  christos 		BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT |
   1636  1.1.1.9  christos 		BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA;
   1637  1.1.1.9  christos 	u16 missing = 0;
   1638  1.1.1.9  christos 	u16 seen;
   1639  1.1.1.9  christos 	const u8 *ies_pos = wpa_bss_ie_ptr(bss);
   1640  1.1.1.9  christos 	size_t ies_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
   1641  1.1.1.9  christos 	int ret = -1;
   1642  1.1.1.9  christos 	struct mld_link *l;
   1643  1.1.1.9  christos 
   1644  1.1.1.9  christos 	if (ieee802_11_parse_elems(ies_pos, ies_len, &elems, 1) ==
   1645  1.1.1.9  christos 	    ParseFailed) {
   1646  1.1.1.9  christos 		wpa_dbg(wpa_s, MSG_DEBUG, "MLD: Failed to parse elements");
   1647  1.1.1.9  christos 		return ret;
   1648  1.1.1.9  christos 	}
   1649  1.1.1.9  christos 
   1650  1.1.1.9  christos 	mlbuf = ieee802_11_defrag(elems.basic_mle, elems.basic_mle_len, true);
   1651  1.1.1.9  christos 	if (!mlbuf) {
   1652  1.1.1.9  christos 		wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No Multi-Link element");
   1653  1.1.1.9  christos 		return ret;
   1654  1.1.1.9  christos 	}
   1655  1.1.1.9  christos 
   1656  1.1.1.9  christos 	ml_ie_len = wpabuf_len(mlbuf);
   1657  1.1.1.9  christos 
   1658  1.1.1.9  christos 	if (ssid) {
   1659  1.1.1.9  christos 		struct wpa_ie_data ie;
   1660  1.1.1.9  christos 
   1661  1.1.1.9  christos 		if (!elems.rsn_ie ||
   1662  1.1.1.9  christos 		    wpa_parse_wpa_ie(elems.rsn_ie - 2, 2 + elems.rsn_ie_len,
   1663  1.1.1.9  christos 				     &ie)) {
   1664  1.1.1.9  christos 			wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No RSN element");
   1665  1.1.1.9  christos 			goto out;
   1666  1.1.1.9  christos 		}
   1667  1.1.1.9  christos 
   1668  1.1.1.9  christos 		if (!(ie.capabilities & WPA_CAPABILITY_MFPC) ||
   1669  1.1.1.9  christos 		    wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION) {
   1670  1.1.1.9  christos 			wpa_dbg(wpa_s, MSG_DEBUG,
   1671  1.1.1.9  christos 				"MLD: No management frame protection");
   1672  1.1.1.9  christos 			goto out;
   1673  1.1.1.9  christos 		}
   1674  1.1.1.9  christos 
   1675  1.1.1.9  christos 		ie.key_mgmt &= ~(WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK |
   1676  1.1.1.9  christos 				 WPA_KEY_MGMT_PSK_SHA256);
   1677  1.1.1.9  christos 		if (!(ie.key_mgmt & ssid->key_mgmt)) {
   1678  1.1.1.9  christos 			wpa_dbg(wpa_s, MSG_DEBUG,
   1679  1.1.1.9  christos 				"MLD: No valid key management");
   1680  1.1.1.9  christos 			goto out;
   1681  1.1.1.9  christos 		}
   1682  1.1.1.9  christos 	}
   1683  1.1.1.9  christos 
   1684  1.1.1.9  christos 	/*
   1685  1.1.1.9  christos 	 * for ext ID + 2 control + common info len + MLD address +
   1686  1.1.1.9  christos 	 * link info
   1687  1.1.1.9  christos 	 */
   1688  1.1.1.9  christos 	if (ml_ie_len < 2UL + 1UL + ETH_ALEN + 1UL)
   1689  1.1.1.9  christos 		goto out;
   1690  1.1.1.9  christos 
   1691  1.1.1.9  christos 	eht_ml = (const struct ieee80211_eht_ml *) wpabuf_head(mlbuf);
   1692  1.1.1.9  christos 	if ((le_to_host16(eht_ml->ml_control) & control_mask) != control) {
   1693  1.1.1.9  christos 		wpa_printf(MSG_DEBUG,
   1694  1.1.1.9  christos 			   "MLD: Unexpected Multi-Link element control=0x%x (mask 0x%x expected 0x%x)",
   1695  1.1.1.9  christos 			   le_to_host16(eht_ml->ml_control), control_mask,
   1696  1.1.1.9  christos 			   control);
   1697  1.1.1.9  christos 		goto out;
   1698  1.1.1.9  christos 	}
   1699  1.1.1.9  christos 
   1700  1.1.1.9  christos 	ml_basic_common_info =
   1701  1.1.1.9  christos 		(const struct eht_ml_basic_common_info *) eht_ml->variable;
   1702  1.1.1.9  christos 
   1703  1.1.1.9  christos 	/* Common info length should be valid */
   1704  1.1.1.9  christos 	if (ml_basic_common_info->len < ETH_ALEN + 1UL)
   1705  1.1.1.9  christos 		goto out;
   1706  1.1.1.9  christos 
   1707  1.1.1.9  christos 	/* Get the MLD address and MLD link ID */
   1708  1.1.1.9  christos 	if (ap_mld_addr)
   1709  1.1.1.9  christos 		os_memcpy(ap_mld_addr, ml_basic_common_info->mld_addr,
   1710  1.1.1.9  christos 			  ETH_ALEN);
   1711  1.1.1.9  christos 
   1712  1.1.1.9  christos 	link_id = ml_basic_common_info->variable[0] & EHT_ML_LINK_ID_MSK;
   1713  1.1.1.9  christos 
   1714  1.1.1.9  christos 	bss->mld_link_id = link_id;
   1715  1.1.1.9  christos 	seen = bss->valid_links = BIT(link_id);
   1716  1.1.1.9  christos 
   1717  1.1.1.9  christos 	l = &bss->mld_links[link_id];
   1718  1.1.1.9  christos 	os_memcpy(l->bssid, bss->bssid, ETH_ALEN);
   1719  1.1.1.9  christos 	l->freq = bss->freq;
   1720  1.1.1.9  christos 
   1721  1.1.1.9  christos 
   1722  1.1.1.9  christos 	/*
   1723  1.1.1.9  christos 	 * The AP MLD ID in the RNR corresponds to the MBSSID index, see
   1724  1.1.1.9  christos 	 * IEEE P802.11be/D4.0, 9.4.2.169.2 (Neighbor AP Information field).
   1725  1.1.1.9  christos 	 *
   1726  1.1.1.9  christos 	 * For the transmitting BSSID it is clear that both the MBSSID index
   1727  1.1.1.9  christos 	 * and the AP MLD ID in the RNR are zero.
   1728  1.1.1.9  christos 	 *
   1729  1.1.1.9  christos 	 * For nontransmitted BSSIDs we will have a BSS generated from the
   1730  1.1.1.9  christos 	 * MBSSID element(s) using inheritance rules. Included in the elements
   1731  1.1.1.9  christos 	 * is the MBSSID Index Element. The RNR is copied from the Beacon/Probe
   1732  1.1.1.9  christos 	 * Response frame that was send by the transmitting BSSID. As such, the
   1733  1.1.1.9  christos 	 * reported AP MLD ID in the RNR will match the value in the MBSSID
   1734  1.1.1.9  christos 	 * Index Element.
   1735  1.1.1.9  christos 	 */
   1736  1.1.1.9  christos 	elem = (const struct element *)
   1737  1.1.1.9  christos 		wpa_bss_get_ie(bss, WLAN_EID_MULTIPLE_BSSID_INDEX);
   1738  1.1.1.9  christos 	if (elem && elem->datalen >= 1)
   1739  1.1.1.9  christos 		mbssid_idx = elem->data[0];
   1740  1.1.1.9  christos 
   1741  1.1.1.9  christos 	for_each_element_id(elem, WLAN_EID_REDUCED_NEIGHBOR_REPORT,
   1742  1.1.1.9  christos 			    wpa_bss_ie_ptr(bss),
   1743  1.1.1.9  christos 			    bss->ie_len ? bss->ie_len : bss->beacon_ie_len) {
   1744  1.1.1.9  christos 		const struct ieee80211_neighbor_ap_info *ap_info;
   1745  1.1.1.9  christos 		const u8 *pos = elem->data;
   1746  1.1.1.9  christos 		size_t len = elem->datalen;
   1747  1.1.1.9  christos 
   1748  1.1.1.9  christos 		/* RNR IE may contain more than one Neighbor AP Info */
   1749  1.1.1.9  christos 		while (sizeof(*ap_info) <= len) {
   1750  1.1.1.9  christos 			size_t ap_info_len = sizeof(*ap_info);
   1751  1.1.1.9  christos 			u8 count;
   1752  1.1.1.9  christos 
   1753  1.1.1.9  christos 			ap_info = (const struct ieee80211_neighbor_ap_info *)
   1754  1.1.1.9  christos 				pos;
   1755  1.1.1.9  christos 			count = RNR_TBTT_INFO_COUNT_VAL(ap_info->tbtt_info_hdr) + 1;
   1756  1.1.1.9  christos 			ap_info_len += count * ap_info->tbtt_info_len;
   1757  1.1.1.9  christos 
   1758  1.1.1.9  christos 			if (ap_info_len > len)
   1759  1.1.1.9  christos 				goto out;
   1760  1.1.1.9  christos 
   1761  1.1.1.9  christos 			wpa_bss_parse_ml_rnr_ap_info(wpa_s, bss, mbssid_idx,
   1762  1.1.1.9  christos 						     ap_info, len, &seen,
   1763  1.1.1.9  christos 						     &missing, ssid);
   1764  1.1.1.9  christos 
   1765  1.1.1.9  christos 			pos += ap_info_len;
   1766  1.1.1.9  christos 			len -= ap_info_len;
   1767  1.1.1.9  christos 		}
   1768  1.1.1.9  christos 	}
   1769  1.1.1.9  christos 
   1770  1.1.1.9  christos 	wpa_printf(MSG_DEBUG, "MLD: valid_links=%04hx (unresolved: 0x%04hx)",
   1771  1.1.1.9  christos 		   bss->valid_links, missing);
   1772  1.1.1.9  christos 
   1773  1.1.1.9  christos 	for_each_link(bss->valid_links, i) {
   1774  1.1.1.9  christos 		wpa_printf(MSG_DEBUG, "MLD: link=%u, bssid=" MACSTR,
   1775  1.1.1.9  christos 			   i, MAC2STR(bss->mld_links[i].bssid));
   1776  1.1.1.9  christos 	}
   1777  1.1.1.9  christos 
   1778  1.1.1.9  christos 	if (missing_links)
   1779  1.1.1.9  christos 		*missing_links = missing;
   1780  1.1.1.9  christos 
   1781  1.1.1.9  christos 	if (ap_mld_id)
   1782  1.1.1.9  christos 		*ap_mld_id = mbssid_idx;
   1783  1.1.1.9  christos 
   1784  1.1.1.9  christos 	ret = 0;
   1785  1.1.1.9  christos out:
   1786  1.1.1.9  christos 	wpabuf_free(mlbuf);
   1787  1.1.1.9  christos 	return ret;
   1788  1.1.1.9  christos }
   1789  1.1.1.9  christos 
   1790  1.1.1.9  christos 
   1791  1.1.1.9  christos /*
   1792  1.1.1.9  christos  * wpa_bss_parse_reconf_ml_element - Parse the Reconfiguration ML element
   1793  1.1.1.9  christos  * @wpa_s: Pointer to wpa_supplicant data
   1794  1.1.1.9  christos  * @bss: BSS table entry
   1795  1.1.1.9  christos  * Returns: The bitmap of links that are going to be removed
   1796  1.1.1.9  christos  */
   1797  1.1.1.9  christos u16 wpa_bss_parse_reconf_ml_element(struct wpa_supplicant *wpa_s,
   1798  1.1.1.9  christos 				    struct wpa_bss *bss)
   1799  1.1.1.9  christos {
   1800  1.1.1.9  christos 	struct ieee802_11_elems elems;
   1801  1.1.1.9  christos 	struct wpabuf *mlbuf;
   1802  1.1.1.9  christos 	const u8 *pos = wpa_bss_ie_ptr(bss);
   1803  1.1.1.9  christos 	size_t len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
   1804  1.1.1.9  christos 	const struct ieee80211_eht_ml *ml;
   1805  1.1.1.9  christos 	u16 removed_links = 0;
   1806  1.1.1.9  christos 	u8 ml_common_len;
   1807  1.1.1.9  christos 
   1808  1.1.1.9  christos 	if (ieee802_11_parse_elems(pos, len, &elems, 1) == ParseFailed)
   1809  1.1.1.9  christos 		return 0;
   1810  1.1.1.9  christos 
   1811  1.1.1.9  christos 	if (!elems.reconf_mle || !elems.reconf_mle_len)
   1812  1.1.1.9  christos 		return 0;
   1813  1.1.1.9  christos 
   1814  1.1.1.9  christos 	mlbuf = ieee802_11_defrag(elems.reconf_mle, elems.reconf_mle_len, true);
   1815  1.1.1.9  christos 	if (!mlbuf)
   1816  1.1.1.9  christos 		return 0;
   1817  1.1.1.9  christos 
   1818  1.1.1.9  christos 	ml = (const struct ieee80211_eht_ml *) wpabuf_head(mlbuf);
   1819  1.1.1.9  christos 	len = wpabuf_len(mlbuf);
   1820  1.1.1.9  christos 
   1821  1.1.1.9  christos 	if (len < sizeof(*ml))
   1822  1.1.1.9  christos 		goto out;
   1823  1.1.1.9  christos 
   1824  1.1.1.9  christos 	ml_common_len = 1;
   1825  1.1.1.9  christos 	if (ml->ml_control & RECONF_MULTI_LINK_CTRL_PRES_MLD_MAC_ADDR)
   1826  1.1.1.9  christos 		ml_common_len += ETH_ALEN;
   1827  1.1.1.9  christos 
   1828  1.1.1.9  christos 	if (len < sizeof(*ml) + ml_common_len) {
   1829  1.1.1.9  christos 		wpa_printf(MSG_DEBUG,
   1830  1.1.1.9  christos 			   "MLD: Unexpected Reconfiguration ML element length: (%zu < %zu)",
   1831  1.1.1.9  christos 			   len, sizeof(*ml) + ml_common_len);
   1832  1.1.1.9  christos 		goto out;
   1833  1.1.1.9  christos 	}
   1834  1.1.1.9  christos 
   1835  1.1.1.9  christos 	pos = ml->variable + ml_common_len;
   1836  1.1.1.9  christos 	len -= sizeof(*ml) + ml_common_len;
   1837  1.1.1.9  christos 
   1838  1.1.1.9  christos 	while (len >= 2 + sizeof(struct ieee80211_eht_per_sta_profile)) {
   1839  1.1.1.9  christos 		size_t sub_elem_len = *(pos + 1);
   1840  1.1.1.9  christos 
   1841  1.1.1.9  christos 		if (2 + sub_elem_len > len) {
   1842  1.1.1.9  christos 			wpa_printf(MSG_DEBUG,
   1843  1.1.1.9  christos 				   "MLD: Invalid link info len: %zu %zu",
   1844  1.1.1.9  christos 				   2 + sub_elem_len, len);
   1845  1.1.1.9  christos 			goto out;
   1846  1.1.1.9  christos 		}
   1847  1.1.1.9  christos 
   1848  1.1.1.9  christos 		if  (*pos == EHT_ML_SUB_ELEM_PER_STA_PROFILE) {
   1849  1.1.1.9  christos 			const struct ieee80211_eht_per_sta_profile *sta_prof =
   1850  1.1.1.9  christos 				(const struct ieee80211_eht_per_sta_profile *)
   1851  1.1.1.9  christos 				(pos + 2);
   1852  1.1.1.9  christos 			u16 control = le_to_host16(sta_prof->sta_control);
   1853  1.1.1.9  christos 			u8 link_id;
   1854  1.1.1.9  christos 
   1855  1.1.1.9  christos 			link_id = control & EHT_PER_STA_RECONF_CTRL_LINK_ID_MSK;
   1856  1.1.1.9  christos 			removed_links |= BIT(link_id);
   1857  1.1.1.9  christos 		}
   1858  1.1.1.9  christos 
   1859  1.1.1.9  christos 		pos += 2 + sub_elem_len;
   1860  1.1.1.9  christos 		len -= 2 + sub_elem_len;
   1861  1.1.1.9  christos 	}
   1862  1.1.1.9  christos 
   1863  1.1.1.9  christos 	wpa_printf(MSG_DEBUG, "MLD: Reconfiguration: removed_links=0x%x",
   1864  1.1.1.9  christos 		   removed_links);
   1865  1.1.1.9  christos out:
   1866  1.1.1.9  christos 	wpabuf_free(mlbuf);
   1867  1.1.1.9  christos 	return removed_links;
   1868  1.1.1.9  christos }
   1869