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 1060 : static void wpa_bss_set_hessid(struct wpa_bss *bss)
39 : {
40 : #ifdef CONFIG_INTERWORKING
41 1060 : const u8 *ie = wpa_bss_get_ie(bss, WLAN_EID_INTERWORKING);
42 1060 : if (ie == NULL || (ie[1] != 7 && ie[1] != 9)) {
43 1009 : os_memset(bss->hessid, 0, ETH_ALEN);
44 2069 : return;
45 : }
46 51 : if (ie[1] == 7)
47 2 : os_memcpy(bss->hessid, ie + 3, ETH_ALEN);
48 : else
49 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 : */
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 1011 : static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
146 : {
147 1011 : if (anqp == NULL)
148 913 : 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 1011 : static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
178 : const char *reason)
179 : {
180 1011 : if (wpa_s->last_scan_res) {
181 : unsigned int i;
182 1053 : for (i = 0; i < wpa_s->last_scan_res_used; i++) {
183 1010 : if (wpa_s->last_scan_res[i] == bss) {
184 968 : 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 968 : wpa_s->last_scan_res_used--;
189 968 : break;
190 : }
191 : }
192 : }
193 1011 : dl_list_del(&bss->list);
194 1011 : dl_list_del(&bss->list_id);
195 1011 : wpa_s->num_bss--;
196 1011 : 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 1011 : wpas_notify_bss_removed(wpa_s, bss->bssid, bss->id);
200 1011 : wpa_bss_anqp_free(bss->anqp);
201 1011 : os_free(bss);
202 1011 : }
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 2369 : 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 2369 : if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
218 0 : return NULL;
219 3039 : dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
220 3201 : if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
221 2666 : bss->ssid_len == ssid_len &&
222 1315 : os_memcmp(bss->ssid, ssid, ssid_len) == 0)
223 1180 : return bss;
224 : }
225 1189 : return NULL;
226 : }
227 :
228 :
229 3922 : 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 3922 : update_time->sec = fetch_time->sec;
236 3922 : update_time->usec = fetch_time->usec;
237 3922 : update_time->sec -= age_ms / 1000;
238 3922 : usec = (age_ms % 1000) * 1000;
239 3922 : if (update_time->usec < usec) {
240 391 : update_time->sec--;
241 391 : update_time->usec += 1000000;
242 : }
243 3922 : update_time->usec -= usec;
244 3922 : }
245 :
246 :
247 1684 : static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src,
248 : struct os_reltime *fetch_time)
249 : {
250 1684 : dst->flags = src->flags;
251 1684 : os_memcpy(dst->bssid, src->bssid, ETH_ALEN);
252 1684 : dst->freq = src->freq;
253 1684 : dst->beacon_int = src->beacon_int;
254 1684 : dst->caps = src->caps;
255 1684 : dst->qual = src->qual;
256 1684 : dst->noise = src->noise;
257 1684 : dst->level = src->level;
258 1684 : dst->tsf = src->tsf;
259 :
260 1684 : calculate_update_time(fetch_time, src->age, &dst->last_update);
261 1684 : }
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 2979 : static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
281 : {
282 8756 : return bss == wpa_s->current_bss ||
283 5766 : os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 ||
284 2787 : 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 1011 : 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 1011 : bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len);
336 1011 : if (bss == NULL)
337 0 : return NULL;
338 1011 : bss->id = wpa_s->bss_next_id++;
339 1011 : bss->last_update_idx = wpa_s->bss_update_idx;
340 1011 : wpa_bss_copy_res(bss, res, fetch_time);
341 1011 : os_memcpy(bss->ssid, ssid, ssid_len);
342 1011 : bss->ssid_len = ssid_len;
343 1011 : bss->ie_len = res->ie_len;
344 1011 : bss->beacon_ie_len = res->beacon_ie_len;
345 1011 : os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
346 1011 : wpa_bss_set_hessid(bss);
347 :
348 1011 : 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 1011 : dl_list_add_tail(&wpa_s->bss, &bss->list);
357 1011 : dl_list_add_tail(&wpa_s->bss_id, &bss->list_id);
358 1011 : wpa_s->num_bss++;
359 1011 : 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 1011 : wpas_notify_bss_added(wpa_s, bss->bssid, bss->id);
363 1011 : return bss;
364 : }
365 :
366 :
367 245 : 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 245 : struct wpabuf *old_ie_buff = NULL;
372 245 : struct wpabuf *new_ie_buff = NULL;
373 : int new_ie_len, old_ie_len, ret, is_multi;
374 :
375 245 : switch (ie) {
376 : case WPA_IE_VENDOR_TYPE:
377 49 : old_ie = wpa_bss_get_vendor_ie(old, ie);
378 49 : new_ie = wpa_scan_get_vendor_ie(new, ie);
379 49 : is_multi = 0;
380 49 : break;
381 : case WPS_IE_VENDOR_TYPE:
382 49 : old_ie_buff = wpa_bss_get_vendor_ie_multi(old, ie);
383 49 : new_ie_buff = wpa_scan_get_vendor_ie_multi(new, ie);
384 49 : is_multi = 1;
385 49 : break;
386 : case WLAN_EID_RSN:
387 : case WLAN_EID_SUPP_RATES:
388 : case WLAN_EID_EXT_SUPP_RATES:
389 147 : old_ie = wpa_bss_get_ie(old, ie);
390 147 : new_ie = wpa_scan_get_ie(new, ie);
391 147 : is_multi = 0;
392 147 : break;
393 : default:
394 0 : wpa_printf(MSG_DEBUG, "bss: %s: cannot compare IEs", __func__);
395 0 : return 0;
396 : }
397 :
398 245 : if (is_multi) {
399 : /* in case of multiple IEs stored in buffer */
400 49 : old_ie = old_ie_buff ? wpabuf_head_u8(old_ie_buff) : NULL;
401 49 : new_ie = new_ie_buff ? wpabuf_head_u8(new_ie_buff) : NULL;
402 49 : old_ie_len = old_ie_buff ? wpabuf_len(old_ie_buff) : 0;
403 49 : new_ie_len = new_ie_buff ? wpabuf_len(new_ie_buff) : 0;
404 : } else {
405 : /* in case of single IE */
406 196 : old_ie_len = old_ie ? old_ie[1] + 2 : 0;
407 196 : new_ie_len = new_ie ? new_ie[1] + 2 : 0;
408 : }
409 :
410 245 : if (!old_ie || !new_ie)
411 92 : ret = !old_ie && !new_ie;
412 : else
413 277 : ret = (old_ie_len == new_ie_len &&
414 124 : os_memcmp(old_ie, new_ie, old_ie_len) == 0);
415 :
416 245 : wpabuf_free(old_ie_buff);
417 245 : wpabuf_free(new_ie_buff);
418 :
419 245 : return ret;
420 : }
421 :
422 :
423 673 : static u32 wpa_bss_compare_res(const struct wpa_bss *old,
424 : const struct wpa_scan_res *new)
425 : {
426 673 : u32 changes = 0;
427 673 : int caps_diff = old->caps ^ new->caps;
428 :
429 673 : if (old->freq != new->freq)
430 5 : changes |= WPA_BSS_FREQ_CHANGED_FLAG;
431 :
432 673 : if (old->level != new->level)
433 0 : changes |= WPA_BSS_SIGNAL_CHANGED_FLAG;
434 :
435 673 : if (caps_diff & IEEE80211_CAP_PRIVACY)
436 9 : changes |= WPA_BSS_PRIVACY_CHANGED_FLAG;
437 :
438 673 : if (caps_diff & IEEE80211_CAP_IBSS)
439 0 : changes |= WPA_BSS_MODE_CHANGED_FLAG;
440 :
441 1311 : if (old->ie_len == new->ie_len &&
442 638 : os_memcmp(old + 1, new + 1, old->ie_len) == 0)
443 624 : return changes;
444 49 : changes |= WPA_BSS_IES_CHANGED_FLAG;
445 :
446 49 : if (!are_ies_equal(old, new, WPA_IE_VENDOR_TYPE))
447 8 : changes |= WPA_BSS_WPAIE_CHANGED_FLAG;
448 :
449 49 : if (!are_ies_equal(old, new, WLAN_EID_RSN))
450 9 : changes |= WPA_BSS_RSNIE_CHANGED_FLAG;
451 :
452 49 : if (!are_ies_equal(old, new, WPS_IE_VENDOR_TYPE))
453 34 : changes |= WPA_BSS_WPS_CHANGED_FLAG;
454 :
455 98 : if (!are_ies_equal(old, new, WLAN_EID_SUPP_RATES) ||
456 49 : !are_ies_equal(old, new, WLAN_EID_EXT_SUPP_RATES))
457 0 : changes |= WPA_BSS_RATES_CHANGED_FLAG;
458 :
459 49 : return changes;
460 : }
461 :
462 :
463 673 : static void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
464 : const struct wpa_bss *bss)
465 : {
466 673 : if (changes & WPA_BSS_FREQ_CHANGED_FLAG)
467 5 : wpas_notify_bss_freq_changed(wpa_s, bss->id);
468 :
469 673 : if (changes & WPA_BSS_SIGNAL_CHANGED_FLAG)
470 0 : wpas_notify_bss_signal_changed(wpa_s, bss->id);
471 :
472 673 : if (changes & WPA_BSS_PRIVACY_CHANGED_FLAG)
473 9 : wpas_notify_bss_privacy_changed(wpa_s, bss->id);
474 :
475 673 : if (changes & WPA_BSS_MODE_CHANGED_FLAG)
476 0 : wpas_notify_bss_mode_changed(wpa_s, bss->id);
477 :
478 673 : if (changes & WPA_BSS_WPAIE_CHANGED_FLAG)
479 8 : wpas_notify_bss_wpaie_changed(wpa_s, bss->id);
480 :
481 673 : if (changes & WPA_BSS_RSNIE_CHANGED_FLAG)
482 9 : wpas_notify_bss_rsnie_changed(wpa_s, bss->id);
483 :
484 673 : if (changes & WPA_BSS_WPS_CHANGED_FLAG)
485 34 : wpas_notify_bss_wps_changed(wpa_s, bss->id);
486 :
487 673 : if (changes & WPA_BSS_IES_CHANGED_FLAG)
488 49 : wpas_notify_bss_ies_changed(wpa_s, bss->id);
489 :
490 673 : if (changes & WPA_BSS_RATES_CHANGED_FLAG)
491 0 : wpas_notify_bss_rates_changed(wpa_s, bss->id);
492 673 : }
493 :
494 :
495 : static struct wpa_bss *
496 673 : 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 673 : changes = wpa_bss_compare_res(bss, res);
502 673 : bss->scan_miss_count = 0;
503 673 : bss->last_update_idx = wpa_s->bss_update_idx;
504 673 : wpa_bss_copy_res(bss, res, fetch_time);
505 : /* Move the entry to the end of the list */
506 673 : dl_list_del(&bss->list);
507 : #ifdef CONFIG_P2P
508 868 : if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
509 195 : !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 1346 : if (bss->ie_len + bss->beacon_ie_len >=
524 673 : res->ie_len + res->beacon_ie_len) {
525 579 : os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
526 579 : bss->ie_len = res->ie_len;
527 579 : bss->beacon_ie_len = res->beacon_ie_len;
528 : } else {
529 : struct wpa_bss *nbss;
530 94 : struct dl_list *prev = bss->list_id.prev;
531 94 : dl_list_del(&bss->list_id);
532 188 : nbss = os_realloc(bss, sizeof(*bss) + res->ie_len +
533 94 : res->beacon_ie_len);
534 94 : if (nbss) {
535 : unsigned int i;
536 112 : for (i = 0; i < wpa_s->last_scan_res_used; i++) {
537 18 : if (wpa_s->last_scan_res[i] == bss) {
538 0 : wpa_s->last_scan_res[i] = nbss;
539 0 : break;
540 : }
541 : }
542 94 : if (wpa_s->current_bss == bss)
543 10 : wpa_s->current_bss = nbss;
544 94 : bss = nbss;
545 94 : os_memcpy(bss + 1, res + 1,
546 : res->ie_len + res->beacon_ie_len);
547 94 : bss->ie_len = res->ie_len;
548 94 : bss->beacon_ie_len = res->beacon_ie_len;
549 : }
550 94 : dl_list_add(prev, &bss->list_id);
551 : }
552 673 : if (changes & WPA_BSS_IES_CHANGED_FLAG)
553 49 : wpa_bss_set_hessid(bss);
554 673 : dl_list_add_tail(&wpa_s->bss, &bss->list);
555 :
556 673 : notify_bss_changes(wpa_s, changes, bss);
557 :
558 673 : 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 1935 : void wpa_bss_update_start(struct wpa_supplicant *wpa_s)
572 : {
573 1935 : wpa_s->bss_update_idx++;
574 1935 : wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Start scan result update %u",
575 : wpa_s->bss_update_idx);
576 1935 : wpa_s->last_scan_res_used = 0;
577 1935 : }
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 2889 : 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 2889 : if (wpa_s->conf->ignore_old_scan_res) {
598 : struct os_reltime update;
599 2238 : calculate_update_time(fetch_time, res->age, &update);
600 2238 : if (os_reltime_before(&update, &wpa_s->scan_trigger_time)) {
601 : struct os_reltime age;
602 654 : os_reltime_sub(&wpa_s->scan_trigger_time, &update,
603 : &age);
604 654 : 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 654 : return;
610 : }
611 : }
612 :
613 2235 : ssid = wpa_scan_get_ie(res, WLAN_EID_SSID);
614 2235 : 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 2235 : 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 2235 : p2p = wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE);
626 : #ifdef CONFIG_P2P
627 3557 : if (p2p == NULL &&
628 1322 : 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 30 : wpa_printf(MSG_DEBUG, "BSS: No P2P IE - skipping BSS " MACSTR
634 30 : " update for P2P interface", MAC2STR(res->bssid));
635 5 : return;
636 : }
637 : #endif /* CONFIG_P2P */
638 2776 : if (p2p && ssid[1] == P2P_WILDCARD_SSID_LEN &&
639 546 : os_memcmp(ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 0)
640 546 : 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 1684 : bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
645 1684 : if (bss == NULL)
646 1011 : bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res, fetch_time);
647 : else {
648 673 : bss = wpa_bss_update(wpa_s, bss, res, fetch_time);
649 673 : if (wpa_s->last_scan_res) {
650 : unsigned int i;
651 755 : for (i = 0; i < wpa_s->last_scan_res_used; i++) {
652 82 : if (bss == wpa_s->last_scan_res[i]) {
653 : /* Already in the list */
654 0 : return;
655 : }
656 : }
657 : }
658 : }
659 :
660 1684 : if (bss == NULL)
661 0 : return;
662 1684 : if (wpa_s->last_scan_res_used >= wpa_s->last_scan_res_size) {
663 : struct wpa_bss **n;
664 : unsigned int siz;
665 40 : if (wpa_s->last_scan_res_size == 0)
666 40 : siz = 32;
667 : else
668 0 : siz = wpa_s->last_scan_res_size * 2;
669 40 : n = os_realloc_array(wpa_s->last_scan_res, siz,
670 : sizeof(struct wpa_bss *));
671 40 : if (n == NULL)
672 0 : return;
673 40 : wpa_s->last_scan_res = n;
674 40 : wpa_s->last_scan_res_size = siz;
675 : }
676 :
677 1684 : if (wpa_s->last_scan_res)
678 1684 : wpa_s->last_scan_res[wpa_s->last_scan_res_used++] = bss;
679 : }
680 :
681 :
682 1699 : 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 1699 : if (info == NULL)
689 0 : return 1;
690 :
691 1699 : if (info->num_freqs) {
692 1699 : found = 0;
693 2344 : for (i = 0; i < info->num_freqs; i++) {
694 2288 : if (bss->freq == info->freqs[i]) {
695 1643 : found = 1;
696 1643 : break;
697 : }
698 : }
699 1699 : if (!found)
700 56 : return 0;
701 : }
702 :
703 1643 : if (info->num_ssids) {
704 1631 : found = 0;
705 1936 : for (i = 0; i < info->num_ssids; i++) {
706 1631 : const struct wpa_driver_scan_ssid *s = &info->ssids[i];
707 2086 : if ((s->ssid == NULL || s->ssid_len == 0) ||
708 636 : (s->ssid_len == bss->ssid_len &&
709 181 : os_memcmp(s->ssid, bss->ssid, bss->ssid_len) ==
710 : 0)) {
711 1326 : found = 1;
712 1326 : break;
713 : }
714 : }
715 1631 : if (!found)
716 305 : return 0;
717 : }
718 :
719 1338 : 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 1935 : 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 1935 : os_get_reltime(&wpa_s->last_scan);
739 1935 : if (!new_scan)
740 1941 : return; /* do not expire entries without new scan */
741 :
742 3714 : dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
743 1785 : if (wpa_bss_in_use(wpa_s, bss))
744 86 : continue;
745 1699 : if (!wpa_bss_included_in_scan(bss, info))
746 361 : continue; /* expire only BSSes that were scanned */
747 1338 : if (bss->last_update_idx < wpa_s->bss_update_idx)
748 33 : bss->scan_miss_count++;
749 2676 : if (bss->scan_miss_count >=
750 1338 : wpa_s->conf->bss_expiration_scan_count) {
751 5 : wpa_bss_remove(wpa_s, bss, "no match in scan");
752 : }
753 : }
754 :
755 1929 : 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 756 : 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 756 : if (dl_list_empty(&wpa_s->bss))
773 1351 : return;
774 :
775 161 : os_get_reltime(&t);
776 161 : t.sec -= age;
777 :
778 258 : dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
779 174 : if (wpa_bss_in_use(wpa_s, bss))
780 96 : continue;
781 :
782 78 : if (os_reltime_before(&bss->last_update, &t)) {
783 1 : wpa_bss_remove(wpa_s, bss, __func__);
784 : } else
785 77 : break;
786 : }
787 : }
788 :
789 :
790 756 : static void wpa_bss_timeout(void *eloop_ctx, void *timeout_ctx)
791 : {
792 756 : struct wpa_supplicant *wpa_s = eloop_ctx;
793 :
794 756 : wpa_bss_flush_by_age(wpa_s, wpa_s->conf->bss_expiration_age);
795 756 : eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0,
796 : wpa_bss_timeout, wpa_s, NULL);
797 756 : }
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 72 : int wpa_bss_init(struct wpa_supplicant *wpa_s)
809 : {
810 72 : dl_list_init(&wpa_s->bss);
811 72 : dl_list_init(&wpa_s->bss_id);
812 72 : eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0,
813 : wpa_bss_timeout, wpa_s, NULL);
814 72 : 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 2166 : void wpa_bss_flush(struct wpa_supplicant *wpa_s)
823 : {
824 : struct wpa_bss *bss, *n;
825 :
826 2166 : wpa_s->clear_driver_scan_cache = 1;
827 :
828 2166 : if (wpa_s->bss.next == NULL)
829 2175 : return; /* BSS table not yet initialized */
830 :
831 3177 : dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
832 1020 : if (wpa_bss_in_use(wpa_s, bss))
833 15 : continue;
834 1005 : 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 81 : void wpa_bss_deinit(struct wpa_supplicant *wpa_s)
844 : {
845 81 : eloop_cancel_timeout(wpa_bss_timeout, wpa_s, NULL);
846 81 : wpa_bss_flush(wpa_s);
847 81 : }
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 952 : struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
857 : const u8 *bssid)
858 : {
859 : struct wpa_bss *bss;
860 952 : if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
861 1 : return NULL;
862 1258 : dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
863 1204 : if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
864 897 : return bss;
865 : }
866 54 : 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 227 : struct wpa_bss * wpa_bss_get_bssid_latest(struct wpa_supplicant *wpa_s,
882 : const u8 *bssid)
883 : {
884 227 : struct wpa_bss *bss, *found = NULL;
885 227 : if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
886 0 : return NULL;
887 407 : dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
888 180 : if (os_memcmp(bss->bssid, bssid, ETH_ALEN) != 0)
889 14 : continue;
890 188 : if (found == NULL ||
891 22 : os_reltime_before(&found->last_update, &bss->last_update))
892 144 : found = bss;
893 : }
894 227 : 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 12898 : const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
971 : {
972 : const u8 *end, *pos;
973 :
974 12898 : pos = (const u8 *) (bss + 1);
975 12898 : end = pos + bss->ie_len;
976 :
977 105026 : while (pos + 1 < end) {
978 88505 : if (pos + 2 + pos[1] > end)
979 0 : break;
980 88505 : if (pos[0] == ie)
981 9275 : return pos;
982 79230 : pos += 2 + pos[1];
983 : }
984 :
985 3623 : 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 13631 : const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
999 : {
1000 : const u8 *end, *pos;
1001 :
1002 13631 : pos = (const u8 *) (bss + 1);
1003 13631 : end = pos + bss->ie_len;
1004 :
1005 169081 : while (pos + 1 < end) {
1006 144311 : if (pos + 2 + pos[1] > end)
1007 0 : break;
1008 167899 : if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1009 23588 : vendor_type == WPA_GET_BE32(&pos[2]))
1010 2492 : return pos;
1011 141819 : pos += 2 + pos[1];
1012 : }
1013 :
1014 11139 : 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 1607 : 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 1607 : if (bss->beacon_ie_len == 0)
1036 419 : return NULL;
1037 :
1038 1188 : pos = (const u8 *) (bss + 1);
1039 1188 : pos += bss->ie_len;
1040 1188 : end = pos + bss->beacon_ie_len;
1041 :
1042 16194 : while (pos + 1 < end) {
1043 13826 : if (pos + 2 + pos[1] > end)
1044 0 : break;
1045 15570 : if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1046 1744 : vendor_type == WPA_GET_BE32(&pos[2]))
1047 8 : return pos;
1048 13818 : pos += 2 + pos[1];
1049 : }
1050 :
1051 1180 : 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 3843 : 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 3843 : buf = wpabuf_alloc(bss->ie_len);
1072 3843 : if (buf == NULL)
1073 0 : return NULL;
1074 :
1075 3843 : pos = (const u8 *) (bss + 1);
1076 3843 : end = pos + bss->ie_len;
1077 :
1078 48764 : while (pos + 1 < end) {
1079 41078 : if (pos + 2 + pos[1] > end)
1080 0 : break;
1081 48852 : if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1082 7774 : vendor_type == WPA_GET_BE32(&pos[2]))
1083 1919 : wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
1084 41078 : pos += 2 + pos[1];
1085 : }
1086 :
1087 3843 : if (wpabuf_len(buf) == 0) {
1088 1930 : wpabuf_free(buf);
1089 1930 : buf = NULL;
1090 : }
1091 :
1092 3843 : 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 : }
|