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