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