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