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