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