Home | History | Annotate | Line # | Download | only in wpa_supplicant
bss.c revision 1.1.1.8.8.1
      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.8.8.1  perseant #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.8.8.1  perseant #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.8.8.1  perseant static struct wpa_connect_work *
    189  1.1.1.8.8.1  perseant 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.8.8.1  perseant 		return NULL;
    199      1.1.1.5  christos 
    200      1.1.1.5  christos 	cwork = work->ctx;
    201  1.1.1.8.8.1  perseant 	if (cwork->bss != bss)
    202  1.1.1.8.8.1  perseant 		return NULL;
    203  1.1.1.8.8.1  perseant 
    204  1.1.1.8.8.1  perseant 	return cwork;
    205  1.1.1.8.8.1  perseant }
    206  1.1.1.8.8.1  perseant 
    207      1.1.1.5  christos 
    208  1.1.1.8.8.1  perseant static void wpa_bss_update_pending_connect(struct wpa_connect_work *cwork,
    209  1.1.1.8.8.1  perseant 					   struct wpa_bss *new_bss)
    210  1.1.1.8.8.1  perseant {
    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.8.8.1  perseant 	struct wpa_connect_work *cwork;
    223  1.1.1.8.8.1  perseant 
    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.8.8.1  perseant 	cwork = wpa_bss_check_pending_connect(wpa_s, bss);
    238  1.1.1.8.8.1  perseant 	if (cwork)
    239  1.1.1.8.8.1  perseant 		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.8.8.1  perseant  * @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.8.8.1  perseant 
    265  1.1.1.8.8.1  perseant 	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.8.8.1  perseant 		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.8.8.1  perseant 	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.8.8.1  perseant 	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.8.8.1  perseant static bool is_p2p_pending_bss(struct wpa_supplicant *wpa_s,
    358  1.1.1.8.8.1  perseant 			       struct wpa_bss *bss)
    359  1.1.1.8.8.1  perseant {
    360  1.1.1.8.8.1  perseant #ifdef CONFIG_P2P
    361  1.1.1.8.8.1  perseant 	u8 addr[ETH_ALEN];
    362  1.1.1.8.8.1  perseant 
    363  1.1.1.8.8.1  perseant 	if (ether_addr_equal(bss->bssid, wpa_s->pending_join_iface_addr))
    364  1.1.1.8.8.1  perseant 		return true;
    365  1.1.1.8.8.1  perseant 	if (!is_zero_ether_addr(wpa_s->pending_join_dev_addr) &&
    366  1.1.1.8.8.1  perseant 	    p2p_parse_dev_addr(wpa_bss_ie_ptr(bss), bss->ie_len, addr) == 0 &&
    367  1.1.1.8.8.1  perseant 	    ether_addr_equal(addr, wpa_s->pending_join_dev_addr))
    368  1.1.1.8.8.1  perseant 		return true;
    369  1.1.1.8.8.1  perseant #endif /* CONFIG_P2P */
    370  1.1.1.8.8.1  perseant 	return false;
    371  1.1.1.8.8.1  perseant }
    372  1.1.1.8.8.1  perseant 
    373  1.1.1.8.8.1  perseant 
    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.8.8.1  perseant 	if (is_p2p_pending_bss(wpa_s, bss))
    379  1.1.1.8.8.1  perseant 		return 1;
    380  1.1.1.8.8.1  perseant 
    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.8.8.1  perseant 	int i;
    396  1.1.1.8.8.1  perseant 
    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.8.8.1  perseant 	if (bss == wpa_s->ml_connect_probe_bss)
    401  1.1.1.8.8.1  perseant 		return 1;
    402  1.1.1.8.8.1  perseant 
    403  1.1.1.8.8.1  perseant #ifdef CONFIG_WNM
    404  1.1.1.8.8.1  perseant 	if (bss == wpa_s->wnm_target_bss)
    405  1.1.1.8.8.1  perseant 		return 1;
    406  1.1.1.8.8.1  perseant #endif /* CONFIG_WNM */
    407  1.1.1.8.8.1  perseant 
    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.8.8.1  perseant 	if (!is_zero_ether_addr(bss->bssid) &&
    415  1.1.1.8.8.1  perseant 	    (ether_addr_equal(bss->bssid, wpa_s->bssid) ||
    416  1.1.1.8.8.1  perseant 	     ether_addr_equal(bss->bssid, wpa_s->pending_bssid)))
    417  1.1.1.8.8.1  perseant 		return 1;
    418  1.1.1.8.8.1  perseant 
    419  1.1.1.8.8.1  perseant 	if (!wpa_s->valid_links)
    420  1.1.1.8.8.1  perseant 		return 0;
    421  1.1.1.8.8.1  perseant 
    422  1.1.1.8.8.1  perseant 	for_each_link(wpa_s->valid_links, i) {
    423  1.1.1.8.8.1  perseant 		if (ether_addr_equal(bss->bssid, wpa_s->links[i].bssid))
    424  1.1.1.8.8.1  perseant 			return 1;
    425  1.1.1.8.8.1  perseant 	}
    426  1.1.1.8.8.1  perseant 
    427  1.1.1.8.8.1  perseant 	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.8.8.1  perseant 	char extra[100];
    479  1.1.1.8.8.1  perseant 	const u8 *ml_ie;
    480  1.1.1.8.8.1  perseant 	char *pos, *end;
    481  1.1.1.8.8.1  perseant 	int ret = 0;
    482  1.1.1.8.8.1  perseant 	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.8.8.1  perseant 	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.8.8.1  perseant 	os_memset(bss->mld_addr, 0, ETH_ALEN);
    498  1.1.1.8.8.1  perseant 	ml_ie = wpa_scan_get_ml_ie(res, MULTI_LINK_CONTROL_TYPE_BASIC);
    499  1.1.1.8.8.1  perseant 	if (ml_ie) {
    500  1.1.1.8.8.1  perseant 		mld_addr = get_basic_mle_mld_addr(&ml_ie[3], ml_ie[1] - 1);
    501  1.1.1.8.8.1  perseant 		if (mld_addr)
    502  1.1.1.8.8.1  perseant 			os_memcpy(bss->mld_addr, mld_addr, ETH_ALEN);
    503  1.1.1.8.8.1  perseant 	}
    504  1.1.1.8.8.1  perseant 
    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.8.8.1  perseant 
    517  1.1.1.8.8.1  perseant 	extra[0] = '\0';
    518  1.1.1.8.8.1  perseant 	pos = extra;
    519  1.1.1.8.8.1  perseant 	end = pos + sizeof(extra);
    520      1.1.1.8  christos 	if (!is_zero_ether_addr(bss->hessid))
    521  1.1.1.8.8.1  perseant 		ret = os_snprintf(pos, end - pos, " HESSID " MACSTR,
    522  1.1.1.8.8.1  perseant 				  MAC2STR(bss->hessid));
    523  1.1.1.8.8.1  perseant 
    524  1.1.1.8.8.1  perseant 	if (!is_zero_ether_addr(bss->mld_addr) &&
    525  1.1.1.8.8.1  perseant 	    !os_snprintf_error(end - pos, ret)) {
    526  1.1.1.8.8.1  perseant 		pos += ret;
    527  1.1.1.8.8.1  perseant 		ret = os_snprintf(pos, end - pos, " MLD ADDR " MACSTR,
    528  1.1.1.8.8.1  perseant 				  MAC2STR(bss->mld_addr));
    529  1.1.1.8.8.1  perseant 	}
    530  1.1.1.8.8.1  perseant 
    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.8.8.1  perseant 	    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.8.8.1  perseant void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
    637  1.1.1.8.8.1  perseant 			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.8.8.1  perseant 	    !wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE) &&
    724  1.1.1.8.8.1  perseant 	    !(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.8.8.1  perseant 		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.8.8.1  perseant 		struct wpa_connect_work *cwork;
    747  1.1.1.8.8.1  perseant 		unsigned int i;
    748  1.1.1.8.8.1  perseant 		bool update_current_bss = wpa_s->current_bss == bss;
    749  1.1.1.8.8.1  perseant 		bool update_ml_probe_bss = wpa_s->ml_connect_probe_bss == bss;
    750  1.1.1.8.8.1  perseant 
    751  1.1.1.8.8.1  perseant 		cwork = wpa_bss_check_pending_connect(wpa_s, bss);
    752  1.1.1.8.8.1  perseant 
    753  1.1.1.8.8.1  perseant 		for (i = 0; i < wpa_s->last_scan_res_used; i++) {
    754  1.1.1.8.8.1  perseant 			if (wpa_s->last_scan_res[i] == bss)
    755  1.1.1.8.8.1  perseant 				break;
    756  1.1.1.8.8.1  perseant 		}
    757  1.1.1.8.8.1  perseant 
    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.8.8.1  perseant 			if (i != wpa_s->last_scan_res_used)
    763  1.1.1.8.8.1  perseant 				wpa_s->last_scan_res[i] = nbss;
    764  1.1.1.8.8.1  perseant 
    765  1.1.1.8.8.1  perseant 			if (update_current_bss)
    766      1.1.1.2  christos 				wpa_s->current_bss = nbss;
    767  1.1.1.8.8.1  perseant 
    768  1.1.1.8.8.1  perseant 			if (update_ml_probe_bss)
    769  1.1.1.8.8.1  perseant 				wpa_s->ml_connect_probe_bss = nbss;
    770  1.1.1.8.8.1  perseant 
    771  1.1.1.8.8.1  perseant 			if (cwork)
    772  1.1.1.8.8.1  perseant 				wpa_bss_update_pending_connect(cwork, nbss);
    773  1.1.1.8.8.1  perseant 
    774          1.1  christos 			bss = nbss;
    775  1.1.1.8.8.1  perseant 			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.8.8.1  perseant 	if (changes & WPA_BSS_IES_CHANGED_FLAG) {
    783  1.1.1.8.8.1  perseant 		const u8 *ml_ie, *mld_addr;
    784  1.1.1.8.8.1  perseant 
    785      1.1.1.3  christos 		wpa_bss_set_hessid(bss);
    786  1.1.1.8.8.1  perseant 		os_memset(bss->mld_addr, 0, ETH_ALEN);
    787  1.1.1.8.8.1  perseant 		ml_ie = wpa_scan_get_ml_ie(res, MULTI_LINK_CONTROL_TYPE_BASIC);
    788  1.1.1.8.8.1  perseant 		if (ml_ie) {
    789  1.1.1.8.8.1  perseant 			mld_addr = get_basic_mle_mld_addr(&ml_ie[3],
    790  1.1.1.8.8.1  perseant 							  ml_ie[1] - 1);
    791  1.1.1.8.8.1  perseant 			if (mld_addr)
    792  1.1.1.8.8.1  perseant 				os_memcpy(bss->mld_addr, mld_addr, ETH_ALEN);
    793  1.1.1.8.8.1  perseant 		}
    794  1.1.1.8.8.1  perseant 	}
    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.8.8.1  perseant 	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.8.8.1  perseant 
   1023  1.1.1.8.8.1  perseant 	if (t.sec < age)
   1024  1.1.1.8.8.1  perseant 		return; /* avoid underflow; there can be no older entries */
   1025  1.1.1.8.8.1  perseant 
   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.8.8.1  perseant 		if (wpa_s->reassoc_same_ess &&
   1033  1.1.1.8.8.1  perseant 		    wpa_s->wpa_state != WPA_COMPLETED &&
   1034  1.1.1.8.8.1  perseant 		    wpa_s->last_ssid &&
   1035  1.1.1.8.8.1  perseant 		    bss->ssid_len == wpa_s->last_ssid->ssid_len &&
   1036  1.1.1.8.8.1  perseant 		    os_memcmp(bss->ssid, wpa_s->last_ssid->ssid,
   1037  1.1.1.8.8.1  perseant 			      bss->ssid_len) == 0)
   1038  1.1.1.8.8.1  perseant 			continue;
   1039  1.1.1.8.8.1  perseant 
   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.8.8.1  perseant 		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.8.8.1  perseant 		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.8.8.1  perseant  * 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.8.8.1  perseant  *
   1150  1.1.1.8.8.1  perseant  * This function tries to find the entry that has the most recent update. This
   1151  1.1.1.8.8.1  perseant  * can help in finding the correct entry in cases where the SSID of the P2P
   1152  1.1.1.8.8.1  perseant  * 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.8.8.1  perseant 	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.8.8.1  perseant 		if (p2p_parse_dev_addr(wpa_bss_ie_ptr(bss), bss->ie_len,
   1161  1.1.1.8.8.1  perseant 				       addr) != 0 ||
   1162  1.1.1.8.8.1  perseant 		    !ether_addr_equal(addr, dev_addr))
   1163  1.1.1.8.8.1  perseant 			continue;
   1164  1.1.1.8.8.1  perseant 		if (!found ||
   1165  1.1.1.8.8.1  perseant 		    os_reltime_before(&found->last_update, &bss->last_update))
   1166  1.1.1.8.8.1  perseant 			found = bss;
   1167      1.1.1.2  christos 	}
   1168  1.1.1.8.8.1  perseant 	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.8.8.1  perseant 	return get_ie(wpa_bss_ie_ptr(bss), bss->ie_len, ie);
   1225  1.1.1.8.8.1  perseant }
   1226  1.1.1.8.8.1  perseant 
   1227  1.1.1.8.8.1  perseant 
   1228  1.1.1.8.8.1  perseant /**
   1229  1.1.1.8.8.1  perseant  * wpa_bss_get_ie_beacon - Fetch a specified information element from a BSS entry
   1230  1.1.1.8.8.1  perseant  * @bss: BSS table entry
   1231  1.1.1.8.8.1  perseant  * @ie: Information element identitifier (WLAN_EID_*)
   1232  1.1.1.8.8.1  perseant  * Returns: Pointer to the information element (id field) or %NULL if not found
   1233  1.1.1.8.8.1  perseant  *
   1234  1.1.1.8.8.1  perseant  * This function returns the first matching information element in the BSS
   1235  1.1.1.8.8.1  perseant  * entry.
   1236  1.1.1.8.8.1  perseant  *
   1237  1.1.1.8.8.1  perseant  * This function is like wpa_bss_get_ie(), but uses IE buffer only from Beacon
   1238  1.1.1.8.8.1  perseant  * frames instead of either Beacon or Probe Response frames.
   1239  1.1.1.8.8.1  perseant  */
   1240  1.1.1.8.8.1  perseant const u8 * wpa_bss_get_ie_beacon(const struct wpa_bss *bss, u8 ie)
   1241  1.1.1.8.8.1  perseant {
   1242  1.1.1.8.8.1  perseant 	const u8 *ies;
   1243  1.1.1.8.8.1  perseant 
   1244  1.1.1.8.8.1  perseant 	if (bss->beacon_ie_len == 0)
   1245  1.1.1.8.8.1  perseant 		return NULL;
   1246  1.1.1.8.8.1  perseant 
   1247  1.1.1.8.8.1  perseant 	ies = wpa_bss_ie_ptr(bss);
   1248  1.1.1.8.8.1  perseant 	ies += bss->ie_len;
   1249  1.1.1.8.8.1  perseant 	return get_ie(ies, bss->beacon_ie_len, ie);
   1250  1.1.1.8.8.1  perseant }
   1251  1.1.1.8.8.1  perseant 
   1252  1.1.1.8.8.1  perseant 
   1253  1.1.1.8.8.1  perseant /**
   1254  1.1.1.8.8.1  perseant  * wpa_bss_get_ie_ext - Fetch a specified extended IE from a BSS entry
   1255  1.1.1.8.8.1  perseant  * @bss: BSS table entry
   1256  1.1.1.8.8.1  perseant  * @ext: Information element extension identifier (WLAN_EID_EXT_*)
   1257  1.1.1.8.8.1  perseant  * Returns: Pointer to the information element (id field) or %NULL if not found
   1258  1.1.1.8.8.1  perseant  *
   1259  1.1.1.8.8.1  perseant  * This function returns the first matching information element in the BSS
   1260  1.1.1.8.8.1  perseant  * entry.
   1261  1.1.1.8.8.1  perseant  */
   1262  1.1.1.8.8.1  perseant const u8 * wpa_bss_get_ie_ext(const struct wpa_bss *bss, u8 ext)
   1263  1.1.1.8.8.1  perseant {
   1264  1.1.1.8.8.1  perseant 	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.8.8.1  perseant 	const u8 *ies;
   1280  1.1.1.8.8.1  perseant 	const struct element *elem;
   1281          1.1  christos 
   1282  1.1.1.8.8.1  perseant 	ies = wpa_bss_ie_ptr(bss);
   1283          1.1  christos 
   1284  1.1.1.8.8.1  perseant 	for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, bss->ie_len) {
   1285  1.1.1.8.8.1  perseant 		if (elem->datalen >= 4 &&
   1286  1.1.1.8.8.1  perseant 		    vendor_type == WPA_GET_BE32(elem->data))
   1287  1.1.1.8.8.1  perseant 			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.8.8.1  perseant 	const u8 *ies;
   1310  1.1.1.8.8.1  perseant 	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.8.8.1  perseant 	ies = wpa_bss_ie_ptr(bss);
   1316  1.1.1.8.8.1  perseant 	ies += bss->ie_len;
   1317      1.1.1.4  christos 
   1318  1.1.1.8.8.1  perseant 	for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies,
   1319  1.1.1.8.8.1  perseant 			    bss->beacon_ie_len) {
   1320  1.1.1.8.8.1  perseant 		if (elem->datalen >= 4 &&
   1321  1.1.1.8.8.1  perseant 		    vendor_type == WPA_GET_BE32(elem->data))
   1322  1.1.1.8.8.1  perseant 			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.8.8.1  perseant 	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.8.8.1  perseant 		u8 ie, len;
   1354  1.1.1.8.8.1  perseant 
   1355  1.1.1.8.8.1  perseant 		ie = pos[0];
   1356  1.1.1.8.8.1  perseant 		len = pos[1];
   1357  1.1.1.8.8.1  perseant 		if (len > end - pos - 2)
   1358          1.1  christos 			break;
   1359  1.1.1.8.8.1  perseant 		pos += 2;
   1360  1.1.1.8.8.1  perseant 		if (ie == WLAN_EID_VENDOR_SPECIFIC && len >= 4 &&
   1361  1.1.1.8.8.1  perseant 		    vendor_type == WPA_GET_BE32(pos))
   1362  1.1.1.8.8.1  perseant 			wpabuf_put_data(buf, pos + 4, len - 4);
   1363  1.1.1.8.8.1  perseant 		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.8.8.1  perseant 	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.8.8.1  perseant 		u8 id, len;
   1404  1.1.1.8.8.1  perseant 
   1405  1.1.1.8.8.1  perseant 		id = *pos++;
   1406  1.1.1.8.8.1  perseant 		len = *pos++;
   1407  1.1.1.8.8.1  perseant 		if (len > end - pos)
   1408      1.1.1.3  christos 			break;
   1409  1.1.1.8.8.1  perseant 		if (id == WLAN_EID_VENDOR_SPECIFIC && len >= 4 &&
   1410  1.1.1.8.8.1  perseant 		    vendor_type == WPA_GET_BE32(pos))
   1411  1.1.1.8.8.1  perseant 			wpabuf_put_data(buf, pos + 4, len - 4);
   1412  1.1.1.8.8.1  perseant 		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.8.8.1  perseant 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.8.8.1  perseant 	if (!bss)
   1506  1.1.1.8.8.1  perseant 		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.8.8.1  perseant 
   1511  1.1.1.8.8.1  perseant 
   1512  1.1.1.8.8.1  perseant static void
   1513  1.1.1.8.8.1  perseant wpa_bss_parse_ml_rnr_ap_info(struct wpa_supplicant *wpa_s,
   1514  1.1.1.8.8.1  perseant 			     struct wpa_bss *bss, u8 mbssid_idx,
   1515  1.1.1.8.8.1  perseant 			     const struct ieee80211_neighbor_ap_info *ap_info,
   1516  1.1.1.8.8.1  perseant 			     size_t len, u16 *seen, u16 *missing,
   1517  1.1.1.8.8.1  perseant 			     struct wpa_ssid *ssid)
   1518  1.1.1.8.8.1  perseant {
   1519  1.1.1.8.8.1  perseant 	const u8 *pos, *end;
   1520  1.1.1.8.8.1  perseant 	const u8 *mld_params;
   1521  1.1.1.8.8.1  perseant 	u8 count, mld_params_offset;
   1522  1.1.1.8.8.1  perseant 	u8 i, type, link_id;
   1523  1.1.1.8.8.1  perseant 
   1524  1.1.1.8.8.1  perseant 	count = RNR_TBTT_INFO_COUNT_VAL(ap_info->tbtt_info_hdr) + 1;
   1525  1.1.1.8.8.1  perseant 	type = ap_info->tbtt_info_hdr & RNR_TBTT_INFO_HDR_TYPE_MSK;
   1526  1.1.1.8.8.1  perseant 
   1527  1.1.1.8.8.1  perseant 	/* MLD information is at offset 13 or at start */
   1528  1.1.1.8.8.1  perseant 	if (type == 0 && ap_info->tbtt_info_len >= RNR_TBTT_INFO_MLD_LEN) {
   1529  1.1.1.8.8.1  perseant 		/* MLD info is appended */
   1530  1.1.1.8.8.1  perseant 		mld_params_offset = RNR_TBTT_INFO_LEN;
   1531  1.1.1.8.8.1  perseant 	} else {
   1532  1.1.1.8.8.1  perseant 		/* TODO: Support NSTR AP */
   1533  1.1.1.8.8.1  perseant 		return;
   1534  1.1.1.8.8.1  perseant 	}
   1535  1.1.1.8.8.1  perseant 
   1536  1.1.1.8.8.1  perseant 	pos = (const u8 *) ap_info;
   1537  1.1.1.8.8.1  perseant 	end = pos + len;
   1538  1.1.1.8.8.1  perseant 	pos += sizeof(*ap_info);
   1539  1.1.1.8.8.1  perseant 
   1540  1.1.1.8.8.1  perseant 	for (i = 0; i < count; i++) {
   1541  1.1.1.8.8.1  perseant 		u8 bss_params;
   1542  1.1.1.8.8.1  perseant 
   1543  1.1.1.8.8.1  perseant 		if (end - pos < ap_info->tbtt_info_len)
   1544  1.1.1.8.8.1  perseant 			break;
   1545  1.1.1.8.8.1  perseant 
   1546  1.1.1.8.8.1  perseant 		bss_params = pos[1 + ETH_ALEN + 4];
   1547  1.1.1.8.8.1  perseant 		mld_params = pos + mld_params_offset;
   1548  1.1.1.8.8.1  perseant 
   1549  1.1.1.8.8.1  perseant 		link_id = *(mld_params + 1) & EHT_ML_LINK_ID_MSK;
   1550  1.1.1.8.8.1  perseant 		if (link_id >= MAX_NUM_MLD_LINKS)
   1551  1.1.1.8.8.1  perseant 			return;
   1552  1.1.1.8.8.1  perseant 
   1553  1.1.1.8.8.1  perseant 		if (*mld_params != mbssid_idx) {
   1554  1.1.1.8.8.1  perseant 			wpa_printf(MSG_DEBUG,
   1555  1.1.1.8.8.1  perseant 				   "MLD: Reported link not part of MLD");
   1556  1.1.1.8.8.1  perseant 		} else if (!(BIT(link_id) & *seen)) {
   1557  1.1.1.8.8.1  perseant 			struct wpa_bss *neigh_bss;
   1558  1.1.1.8.8.1  perseant 
   1559  1.1.1.8.8.1  perseant 			if (ssid && ssid->ssid_len)
   1560  1.1.1.8.8.1  perseant 				neigh_bss = wpa_bss_get(wpa_s, pos + 1,
   1561  1.1.1.8.8.1  perseant 							ssid->ssid,
   1562  1.1.1.8.8.1  perseant 							ssid->ssid_len);
   1563  1.1.1.8.8.1  perseant 			else
   1564  1.1.1.8.8.1  perseant 				neigh_bss = wpa_bss_get_bssid(wpa_s, pos + 1);
   1565  1.1.1.8.8.1  perseant 
   1566  1.1.1.8.8.1  perseant 			*seen |= BIT(link_id);
   1567  1.1.1.8.8.1  perseant 			wpa_printf(MSG_DEBUG, "MLD: mld ID=%u, link ID=%u",
   1568  1.1.1.8.8.1  perseant 				   *mld_params, link_id);
   1569  1.1.1.8.8.1  perseant 
   1570  1.1.1.8.8.1  perseant 			if (!neigh_bss) {
   1571  1.1.1.8.8.1  perseant 				*missing |= BIT(link_id);
   1572  1.1.1.8.8.1  perseant 			} else if ((!ssid ||
   1573  1.1.1.8.8.1  perseant 				    (bss_params & (RNR_BSS_PARAM_SAME_SSID |
   1574  1.1.1.8.8.1  perseant 						   RNR_BSS_PARAM_CO_LOCATED)) ||
   1575  1.1.1.8.8.1  perseant 				    wpa_scan_res_match(wpa_s, 0, neigh_bss,
   1576  1.1.1.8.8.1  perseant 						       ssid, 1, 0)) &&
   1577  1.1.1.8.8.1  perseant 				   !wpa_bssid_ignore_is_listed(
   1578  1.1.1.8.8.1  perseant 					   wpa_s, neigh_bss->bssid)) {
   1579  1.1.1.8.8.1  perseant 				struct mld_link *l;
   1580  1.1.1.8.8.1  perseant 
   1581  1.1.1.8.8.1  perseant 				bss->valid_links |= BIT(link_id);
   1582  1.1.1.8.8.1  perseant 				l = &bss->mld_links[link_id];
   1583  1.1.1.8.8.1  perseant 				os_memcpy(l->bssid, pos + 1, ETH_ALEN);
   1584  1.1.1.8.8.1  perseant 				l->freq = neigh_bss->freq;
   1585  1.1.1.8.8.1  perseant 				l->disabled = mld_params[2] &
   1586  1.1.1.8.8.1  perseant 					RNR_TBTT_INFO_MLD_PARAM2_LINK_DISABLED;
   1587  1.1.1.8.8.1  perseant 			}
   1588  1.1.1.8.8.1  perseant 		}
   1589  1.1.1.8.8.1  perseant 
   1590  1.1.1.8.8.1  perseant 		pos += ap_info->tbtt_info_len;
   1591  1.1.1.8.8.1  perseant 	}
   1592  1.1.1.8.8.1  perseant }
   1593  1.1.1.8.8.1  perseant 
   1594  1.1.1.8.8.1  perseant 
   1595  1.1.1.8.8.1  perseant /**
   1596  1.1.1.8.8.1  perseant  * wpa_bss_parse_basic_ml_element - Parse the Basic Multi-Link element
   1597  1.1.1.8.8.1  perseant  * @wpa_s: Pointer to wpa_supplicant data
   1598  1.1.1.8.8.1  perseant  * @bss: BSS table entry
   1599  1.1.1.8.8.1  perseant  * @mld_addr: AP MLD address (or %NULL)
   1600  1.1.1.8.8.1  perseant  * @link_info: Array to store link information (or %NULL),
   1601  1.1.1.8.8.1  perseant  *   should be initialized and #MAX_NUM_MLD_LINKS elements long
   1602  1.1.1.8.8.1  perseant  * @missing_links: Result bitmask of links that were not discovered (or %NULL)
   1603  1.1.1.8.8.1  perseant  * @ssid: Target SSID (or %NULL)
   1604  1.1.1.8.8.1  perseant  * @ap_mld_id: On return would hold the corresponding AP MLD ID (or %NULL)
   1605  1.1.1.8.8.1  perseant  * Returns: 0 on success or -1 for non-MLD or parsing failures
   1606  1.1.1.8.8.1  perseant  *
   1607  1.1.1.8.8.1  perseant  * Parses the Basic Multi-Link element of the BSS into @link_info using the scan
   1608  1.1.1.8.8.1  perseant  * information stored in the wpa_supplicant data to fill in information for
   1609  1.1.1.8.8.1  perseant  * links where possible. The @missing_links out parameter will contain any links
   1610  1.1.1.8.8.1  perseant  * for which no corresponding BSS was found.
   1611  1.1.1.8.8.1  perseant  */
   1612  1.1.1.8.8.1  perseant int wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s,
   1613  1.1.1.8.8.1  perseant 				   struct wpa_bss *bss,
   1614  1.1.1.8.8.1  perseant 				   u8 *ap_mld_addr,
   1615  1.1.1.8.8.1  perseant 				   u16 *missing_links,
   1616  1.1.1.8.8.1  perseant 				   struct wpa_ssid *ssid,
   1617  1.1.1.8.8.1  perseant 				   u8 *ap_mld_id)
   1618  1.1.1.8.8.1  perseant {
   1619  1.1.1.8.8.1  perseant 	struct ieee802_11_elems elems;
   1620  1.1.1.8.8.1  perseant 	struct wpabuf *mlbuf;
   1621  1.1.1.8.8.1  perseant 	const struct element *elem;
   1622  1.1.1.8.8.1  perseant 	u8 mbssid_idx = 0;
   1623  1.1.1.8.8.1  perseant 	size_t ml_ie_len;
   1624  1.1.1.8.8.1  perseant 	const struct ieee80211_eht_ml *eht_ml;
   1625  1.1.1.8.8.1  perseant 	const struct eht_ml_basic_common_info *ml_basic_common_info;
   1626  1.1.1.8.8.1  perseant 	u8 i, link_id;
   1627  1.1.1.8.8.1  perseant 	const u16 control_mask =
   1628  1.1.1.8.8.1  perseant 		MULTI_LINK_CONTROL_TYPE_MASK |
   1629  1.1.1.8.8.1  perseant 		BASIC_MULTI_LINK_CTRL_PRES_LINK_ID |
   1630  1.1.1.8.8.1  perseant 		BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT |
   1631  1.1.1.8.8.1  perseant 		BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA;
   1632  1.1.1.8.8.1  perseant 	const u16 control =
   1633  1.1.1.8.8.1  perseant 		MULTI_LINK_CONTROL_TYPE_BASIC |
   1634  1.1.1.8.8.1  perseant 		BASIC_MULTI_LINK_CTRL_PRES_LINK_ID |
   1635  1.1.1.8.8.1  perseant 		BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT |
   1636  1.1.1.8.8.1  perseant 		BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA;
   1637  1.1.1.8.8.1  perseant 	u16 missing = 0;
   1638  1.1.1.8.8.1  perseant 	u16 seen;
   1639  1.1.1.8.8.1  perseant 	const u8 *ies_pos = wpa_bss_ie_ptr(bss);
   1640  1.1.1.8.8.1  perseant 	size_t ies_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
   1641  1.1.1.8.8.1  perseant 	int ret = -1;
   1642  1.1.1.8.8.1  perseant 	struct mld_link *l;
   1643  1.1.1.8.8.1  perseant 
   1644  1.1.1.8.8.1  perseant 	if (ieee802_11_parse_elems(ies_pos, ies_len, &elems, 1) ==
   1645  1.1.1.8.8.1  perseant 	    ParseFailed) {
   1646  1.1.1.8.8.1  perseant 		wpa_dbg(wpa_s, MSG_DEBUG, "MLD: Failed to parse elements");
   1647  1.1.1.8.8.1  perseant 		return ret;
   1648  1.1.1.8.8.1  perseant 	}
   1649  1.1.1.8.8.1  perseant 
   1650  1.1.1.8.8.1  perseant 	mlbuf = ieee802_11_defrag(elems.basic_mle, elems.basic_mle_len, true);
   1651  1.1.1.8.8.1  perseant 	if (!mlbuf) {
   1652  1.1.1.8.8.1  perseant 		wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No Multi-Link element");
   1653  1.1.1.8.8.1  perseant 		return ret;
   1654  1.1.1.8.8.1  perseant 	}
   1655  1.1.1.8.8.1  perseant 
   1656  1.1.1.8.8.1  perseant 	ml_ie_len = wpabuf_len(mlbuf);
   1657  1.1.1.8.8.1  perseant 
   1658  1.1.1.8.8.1  perseant 	if (ssid) {
   1659  1.1.1.8.8.1  perseant 		struct wpa_ie_data ie;
   1660  1.1.1.8.8.1  perseant 
   1661  1.1.1.8.8.1  perseant 		if (!elems.rsn_ie ||
   1662  1.1.1.8.8.1  perseant 		    wpa_parse_wpa_ie(elems.rsn_ie - 2, 2 + elems.rsn_ie_len,
   1663  1.1.1.8.8.1  perseant 				     &ie)) {
   1664  1.1.1.8.8.1  perseant 			wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No RSN element");
   1665  1.1.1.8.8.1  perseant 			goto out;
   1666  1.1.1.8.8.1  perseant 		}
   1667  1.1.1.8.8.1  perseant 
   1668  1.1.1.8.8.1  perseant 		if (!(ie.capabilities & WPA_CAPABILITY_MFPC) ||
   1669  1.1.1.8.8.1  perseant 		    wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION) {
   1670  1.1.1.8.8.1  perseant 			wpa_dbg(wpa_s, MSG_DEBUG,
   1671  1.1.1.8.8.1  perseant 				"MLD: No management frame protection");
   1672  1.1.1.8.8.1  perseant 			goto out;
   1673  1.1.1.8.8.1  perseant 		}
   1674  1.1.1.8.8.1  perseant 
   1675  1.1.1.8.8.1  perseant 		ie.key_mgmt &= ~(WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK |
   1676  1.1.1.8.8.1  perseant 				 WPA_KEY_MGMT_PSK_SHA256);
   1677  1.1.1.8.8.1  perseant 		if (!(ie.key_mgmt & ssid->key_mgmt)) {
   1678  1.1.1.8.8.1  perseant 			wpa_dbg(wpa_s, MSG_DEBUG,
   1679  1.1.1.8.8.1  perseant 				"MLD: No valid key management");
   1680  1.1.1.8.8.1  perseant 			goto out;
   1681  1.1.1.8.8.1  perseant 		}
   1682  1.1.1.8.8.1  perseant 	}
   1683  1.1.1.8.8.1  perseant 
   1684  1.1.1.8.8.1  perseant 	/*
   1685  1.1.1.8.8.1  perseant 	 * for ext ID + 2 control + common info len + MLD address +
   1686  1.1.1.8.8.1  perseant 	 * link info
   1687  1.1.1.8.8.1  perseant 	 */
   1688  1.1.1.8.8.1  perseant 	if (ml_ie_len < 2UL + 1UL + ETH_ALEN + 1UL)
   1689  1.1.1.8.8.1  perseant 		goto out;
   1690  1.1.1.8.8.1  perseant 
   1691  1.1.1.8.8.1  perseant 	eht_ml = (const struct ieee80211_eht_ml *) wpabuf_head(mlbuf);
   1692  1.1.1.8.8.1  perseant 	if ((le_to_host16(eht_ml->ml_control) & control_mask) != control) {
   1693  1.1.1.8.8.1  perseant 		wpa_printf(MSG_DEBUG,
   1694  1.1.1.8.8.1  perseant 			   "MLD: Unexpected Multi-Link element control=0x%x (mask 0x%x expected 0x%x)",
   1695  1.1.1.8.8.1  perseant 			   le_to_host16(eht_ml->ml_control), control_mask,
   1696  1.1.1.8.8.1  perseant 			   control);
   1697  1.1.1.8.8.1  perseant 		goto out;
   1698  1.1.1.8.8.1  perseant 	}
   1699  1.1.1.8.8.1  perseant 
   1700  1.1.1.8.8.1  perseant 	ml_basic_common_info =
   1701  1.1.1.8.8.1  perseant 		(const struct eht_ml_basic_common_info *) eht_ml->variable;
   1702  1.1.1.8.8.1  perseant 
   1703  1.1.1.8.8.1  perseant 	/* Common info length should be valid */
   1704  1.1.1.8.8.1  perseant 	if (ml_basic_common_info->len < ETH_ALEN + 1UL)
   1705  1.1.1.8.8.1  perseant 		goto out;
   1706  1.1.1.8.8.1  perseant 
   1707  1.1.1.8.8.1  perseant 	/* Get the MLD address and MLD link ID */
   1708  1.1.1.8.8.1  perseant 	if (ap_mld_addr)
   1709  1.1.1.8.8.1  perseant 		os_memcpy(ap_mld_addr, ml_basic_common_info->mld_addr,
   1710  1.1.1.8.8.1  perseant 			  ETH_ALEN);
   1711  1.1.1.8.8.1  perseant 
   1712  1.1.1.8.8.1  perseant 	link_id = ml_basic_common_info->variable[0] & EHT_ML_LINK_ID_MSK;
   1713  1.1.1.8.8.1  perseant 
   1714  1.1.1.8.8.1  perseant 	bss->mld_link_id = link_id;
   1715  1.1.1.8.8.1  perseant 	seen = bss->valid_links = BIT(link_id);
   1716  1.1.1.8.8.1  perseant 
   1717  1.1.1.8.8.1  perseant 	l = &bss->mld_links[link_id];
   1718  1.1.1.8.8.1  perseant 	os_memcpy(l->bssid, bss->bssid, ETH_ALEN);
   1719  1.1.1.8.8.1  perseant 	l->freq = bss->freq;
   1720  1.1.1.8.8.1  perseant 
   1721  1.1.1.8.8.1  perseant 
   1722  1.1.1.8.8.1  perseant 	/*
   1723  1.1.1.8.8.1  perseant 	 * The AP MLD ID in the RNR corresponds to the MBSSID index, see
   1724  1.1.1.8.8.1  perseant 	 * IEEE P802.11be/D4.0, 9.4.2.169.2 (Neighbor AP Information field).
   1725  1.1.1.8.8.1  perseant 	 *
   1726  1.1.1.8.8.1  perseant 	 * For the transmitting BSSID it is clear that both the MBSSID index
   1727  1.1.1.8.8.1  perseant 	 * and the AP MLD ID in the RNR are zero.
   1728  1.1.1.8.8.1  perseant 	 *
   1729  1.1.1.8.8.1  perseant 	 * For nontransmitted BSSIDs we will have a BSS generated from the
   1730  1.1.1.8.8.1  perseant 	 * MBSSID element(s) using inheritance rules. Included in the elements
   1731  1.1.1.8.8.1  perseant 	 * is the MBSSID Index Element. The RNR is copied from the Beacon/Probe
   1732  1.1.1.8.8.1  perseant 	 * Response frame that was send by the transmitting BSSID. As such, the
   1733  1.1.1.8.8.1  perseant 	 * reported AP MLD ID in the RNR will match the value in the MBSSID
   1734  1.1.1.8.8.1  perseant 	 * Index Element.
   1735  1.1.1.8.8.1  perseant 	 */
   1736  1.1.1.8.8.1  perseant 	elem = (const struct element *)
   1737  1.1.1.8.8.1  perseant 		wpa_bss_get_ie(bss, WLAN_EID_MULTIPLE_BSSID_INDEX);
   1738  1.1.1.8.8.1  perseant 	if (elem && elem->datalen >= 1)
   1739  1.1.1.8.8.1  perseant 		mbssid_idx = elem->data[0];
   1740  1.1.1.8.8.1  perseant 
   1741  1.1.1.8.8.1  perseant 	for_each_element_id(elem, WLAN_EID_REDUCED_NEIGHBOR_REPORT,
   1742  1.1.1.8.8.1  perseant 			    wpa_bss_ie_ptr(bss),
   1743  1.1.1.8.8.1  perseant 			    bss->ie_len ? bss->ie_len : bss->beacon_ie_len) {
   1744  1.1.1.8.8.1  perseant 		const struct ieee80211_neighbor_ap_info *ap_info;
   1745  1.1.1.8.8.1  perseant 		const u8 *pos = elem->data;
   1746  1.1.1.8.8.1  perseant 		size_t len = elem->datalen;
   1747  1.1.1.8.8.1  perseant 
   1748  1.1.1.8.8.1  perseant 		/* RNR IE may contain more than one Neighbor AP Info */
   1749  1.1.1.8.8.1  perseant 		while (sizeof(*ap_info) <= len) {
   1750  1.1.1.8.8.1  perseant 			size_t ap_info_len = sizeof(*ap_info);
   1751  1.1.1.8.8.1  perseant 			u8 count;
   1752  1.1.1.8.8.1  perseant 
   1753  1.1.1.8.8.1  perseant 			ap_info = (const struct ieee80211_neighbor_ap_info *)
   1754  1.1.1.8.8.1  perseant 				pos;
   1755  1.1.1.8.8.1  perseant 			count = RNR_TBTT_INFO_COUNT_VAL(ap_info->tbtt_info_hdr) + 1;
   1756  1.1.1.8.8.1  perseant 			ap_info_len += count * ap_info->tbtt_info_len;
   1757  1.1.1.8.8.1  perseant 
   1758  1.1.1.8.8.1  perseant 			if (ap_info_len > len)
   1759  1.1.1.8.8.1  perseant 				goto out;
   1760  1.1.1.8.8.1  perseant 
   1761  1.1.1.8.8.1  perseant 			wpa_bss_parse_ml_rnr_ap_info(wpa_s, bss, mbssid_idx,
   1762  1.1.1.8.8.1  perseant 						     ap_info, len, &seen,
   1763  1.1.1.8.8.1  perseant 						     &missing, ssid);
   1764  1.1.1.8.8.1  perseant 
   1765  1.1.1.8.8.1  perseant 			pos += ap_info_len;
   1766  1.1.1.8.8.1  perseant 			len -= ap_info_len;
   1767  1.1.1.8.8.1  perseant 		}
   1768  1.1.1.8.8.1  perseant 	}
   1769  1.1.1.8.8.1  perseant 
   1770  1.1.1.8.8.1  perseant 	wpa_printf(MSG_DEBUG, "MLD: valid_links=%04hx (unresolved: 0x%04hx)",
   1771  1.1.1.8.8.1  perseant 		   bss->valid_links, missing);
   1772  1.1.1.8.8.1  perseant 
   1773  1.1.1.8.8.1  perseant 	for_each_link(bss->valid_links, i) {
   1774  1.1.1.8.8.1  perseant 		wpa_printf(MSG_DEBUG, "MLD: link=%u, bssid=" MACSTR,
   1775  1.1.1.8.8.1  perseant 			   i, MAC2STR(bss->mld_links[i].bssid));
   1776  1.1.1.8.8.1  perseant 	}
   1777  1.1.1.8.8.1  perseant 
   1778  1.1.1.8.8.1  perseant 	if (missing_links)
   1779  1.1.1.8.8.1  perseant 		*missing_links = missing;
   1780  1.1.1.8.8.1  perseant 
   1781  1.1.1.8.8.1  perseant 	if (ap_mld_id)
   1782  1.1.1.8.8.1  perseant 		*ap_mld_id = mbssid_idx;
   1783  1.1.1.8.8.1  perseant 
   1784  1.1.1.8.8.1  perseant 	ret = 0;
   1785  1.1.1.8.8.1  perseant out:
   1786  1.1.1.8.8.1  perseant 	wpabuf_free(mlbuf);
   1787  1.1.1.8.8.1  perseant 	return ret;
   1788  1.1.1.8.8.1  perseant }
   1789  1.1.1.8.8.1  perseant 
   1790  1.1.1.8.8.1  perseant 
   1791  1.1.1.8.8.1  perseant /*
   1792  1.1.1.8.8.1  perseant  * wpa_bss_parse_reconf_ml_element - Parse the Reconfiguration ML element
   1793  1.1.1.8.8.1  perseant  * @wpa_s: Pointer to wpa_supplicant data
   1794  1.1.1.8.8.1  perseant  * @bss: BSS table entry
   1795  1.1.1.8.8.1  perseant  * Returns: The bitmap of links that are going to be removed
   1796  1.1.1.8.8.1  perseant  */
   1797  1.1.1.8.8.1  perseant u16 wpa_bss_parse_reconf_ml_element(struct wpa_supplicant *wpa_s,
   1798  1.1.1.8.8.1  perseant 				    struct wpa_bss *bss)
   1799  1.1.1.8.8.1  perseant {
   1800  1.1.1.8.8.1  perseant 	struct ieee802_11_elems elems;
   1801  1.1.1.8.8.1  perseant 	struct wpabuf *mlbuf;
   1802  1.1.1.8.8.1  perseant 	const u8 *pos = wpa_bss_ie_ptr(bss);
   1803  1.1.1.8.8.1  perseant 	size_t len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
   1804  1.1.1.8.8.1  perseant 	const struct ieee80211_eht_ml *ml;
   1805  1.1.1.8.8.1  perseant 	u16 removed_links = 0;
   1806  1.1.1.8.8.1  perseant 	u8 ml_common_len;
   1807  1.1.1.8.8.1  perseant 
   1808  1.1.1.8.8.1  perseant 	if (ieee802_11_parse_elems(pos, len, &elems, 1) == ParseFailed)
   1809  1.1.1.8.8.1  perseant 		return 0;
   1810  1.1.1.8.8.1  perseant 
   1811  1.1.1.8.8.1  perseant 	if (!elems.reconf_mle || !elems.reconf_mle_len)
   1812  1.1.1.8.8.1  perseant 		return 0;
   1813  1.1.1.8.8.1  perseant 
   1814  1.1.1.8.8.1  perseant 	mlbuf = ieee802_11_defrag(elems.reconf_mle, elems.reconf_mle_len, true);
   1815  1.1.1.8.8.1  perseant 	if (!mlbuf)
   1816  1.1.1.8.8.1  perseant 		return 0;
   1817  1.1.1.8.8.1  perseant 
   1818  1.1.1.8.8.1  perseant 	ml = (const struct ieee80211_eht_ml *) wpabuf_head(mlbuf);
   1819  1.1.1.8.8.1  perseant 	len = wpabuf_len(mlbuf);
   1820  1.1.1.8.8.1  perseant 
   1821  1.1.1.8.8.1  perseant 	if (len < sizeof(*ml))
   1822  1.1.1.8.8.1  perseant 		goto out;
   1823  1.1.1.8.8.1  perseant 
   1824  1.1.1.8.8.1  perseant 	ml_common_len = 1;
   1825  1.1.1.8.8.1  perseant 	if (ml->ml_control & RECONF_MULTI_LINK_CTRL_PRES_MLD_MAC_ADDR)
   1826  1.1.1.8.8.1  perseant 		ml_common_len += ETH_ALEN;
   1827  1.1.1.8.8.1  perseant 
   1828  1.1.1.8.8.1  perseant 	if (len < sizeof(*ml) + ml_common_len) {
   1829  1.1.1.8.8.1  perseant 		wpa_printf(MSG_DEBUG,
   1830  1.1.1.8.8.1  perseant 			   "MLD: Unexpected Reconfiguration ML element length: (%zu < %zu)",
   1831  1.1.1.8.8.1  perseant 			   len, sizeof(*ml) + ml_common_len);
   1832  1.1.1.8.8.1  perseant 		goto out;
   1833  1.1.1.8.8.1  perseant 	}
   1834  1.1.1.8.8.1  perseant 
   1835  1.1.1.8.8.1  perseant 	pos = ml->variable + ml_common_len;
   1836  1.1.1.8.8.1  perseant 	len -= sizeof(*ml) + ml_common_len;
   1837  1.1.1.8.8.1  perseant 
   1838  1.1.1.8.8.1  perseant 	while (len >= 2 + sizeof(struct ieee80211_eht_per_sta_profile)) {
   1839  1.1.1.8.8.1  perseant 		size_t sub_elem_len = *(pos + 1);
   1840  1.1.1.8.8.1  perseant 
   1841  1.1.1.8.8.1  perseant 		if (2 + sub_elem_len > len) {
   1842  1.1.1.8.8.1  perseant 			wpa_printf(MSG_DEBUG,
   1843  1.1.1.8.8.1  perseant 				   "MLD: Invalid link info len: %zu %zu",
   1844  1.1.1.8.8.1  perseant 				   2 + sub_elem_len, len);
   1845  1.1.1.8.8.1  perseant 			goto out;
   1846  1.1.1.8.8.1  perseant 		}
   1847  1.1.1.8.8.1  perseant 
   1848  1.1.1.8.8.1  perseant 		if  (*pos == EHT_ML_SUB_ELEM_PER_STA_PROFILE) {
   1849  1.1.1.8.8.1  perseant 			const struct ieee80211_eht_per_sta_profile *sta_prof =
   1850  1.1.1.8.8.1  perseant 				(const struct ieee80211_eht_per_sta_profile *)
   1851  1.1.1.8.8.1  perseant 				(pos + 2);
   1852  1.1.1.8.8.1  perseant 			u16 control = le_to_host16(sta_prof->sta_control);
   1853  1.1.1.8.8.1  perseant 			u8 link_id;
   1854  1.1.1.8.8.1  perseant 
   1855  1.1.1.8.8.1  perseant 			link_id = control & EHT_PER_STA_RECONF_CTRL_LINK_ID_MSK;
   1856  1.1.1.8.8.1  perseant 			removed_links |= BIT(link_id);
   1857  1.1.1.8.8.1  perseant 		}
   1858  1.1.1.8.8.1  perseant 
   1859  1.1.1.8.8.1  perseant 		pos += 2 + sub_elem_len;
   1860  1.1.1.8.8.1  perseant 		len -= 2 + sub_elem_len;
   1861  1.1.1.8.8.1  perseant 	}
   1862  1.1.1.8.8.1  perseant 
   1863  1.1.1.8.8.1  perseant 	wpa_printf(MSG_DEBUG, "MLD: Reconfiguration: removed_links=0x%x",
   1864  1.1.1.8.8.1  perseant 		   removed_links);
   1865  1.1.1.8.8.1  perseant out:
   1866  1.1.1.8.8.1  perseant 	wpabuf_free(mlbuf);
   1867  1.1.1.8.8.1  perseant 	return removed_links;
   1868  1.1.1.8.8.1  perseant }
   1869