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