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