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