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