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