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