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 : 926 : static void wpa_bss_set_hessid(struct wpa_bss *bss)
39 : : {
40 : : #ifdef CONFIG_INTERWORKING
41 : 926 : const u8 *ie = wpa_bss_get_ie(bss, WLAN_EID_INTERWORKING);
42 [ + + ][ + + ]: 926 : if (ie == NULL || (ie[1] != 7 && ie[1] != 9)) {
[ + + ]
43 : 879 : os_memset(bss->hessid, 0, ETH_ALEN);
44 : 926 : return;
45 : : }
46 [ + + ]: 47 : if (ie[1] == 7)
47 : 7 : os_memcpy(bss->hessid, ie + 3, ETH_ALEN);
48 : : else
49 : 40 : 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 : 30 : struct wpa_bss_anqp * wpa_bss_anqp_alloc(void)
63 : : {
64 : : struct wpa_bss_anqp *anqp;
65 : 30 : anqp = os_zalloc(sizeof(*anqp));
66 [ - + ]: 30 : if (anqp == NULL)
67 : 0 : return NULL;
68 : 30 : anqp->users = 1;
69 : 30 : 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 : 901 : static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
145 : : {
146 [ + + ]: 901 : if (anqp == NULL)
147 : 870 : return;
148 : :
149 : 31 : anqp->users--;
150 [ - + ]: 31 : 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 : 31 : wpabuf_free(anqp->venue_name);
157 : 31 : wpabuf_free(anqp->network_auth_type);
158 : 31 : wpabuf_free(anqp->roaming_consortium);
159 : 31 : wpabuf_free(anqp->ip_addr_type_availability);
160 : 31 : wpabuf_free(anqp->nai_realm);
161 : 31 : wpabuf_free(anqp->anqp_3gpp);
162 : 31 : wpabuf_free(anqp->domain_name);
163 : : #endif /* CONFIG_INTERWORKING */
164 : : #ifdef CONFIG_HS20
165 : 31 : wpabuf_free(anqp->hs20_operator_friendly_name);
166 : 31 : wpabuf_free(anqp->hs20_wan_metrics);
167 : 31 : wpabuf_free(anqp->hs20_connection_capability);
168 : 31 : wpabuf_free(anqp->hs20_operating_class);
169 : : #endif /* CONFIG_HS20 */
170 : :
171 : 901 : os_free(anqp);
172 : : }
173 : :
174 : :
175 : 901 : static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
176 : : const char *reason)
177 : : {
178 [ + - ]: 901 : if (wpa_s->last_scan_res) {
179 : : unsigned int i;
180 [ + + ]: 967 : for (i = 0; i < wpa_s->last_scan_res_used; i++) {
181 [ + + ]: 943 : if (wpa_s->last_scan_res[i] == bss) {
182 : 877 : 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 : 877 : wpa_s->last_scan_res_used--;
187 : 877 : break;
188 : : }
189 : : }
190 : : }
191 : 901 : dl_list_del(&bss->list);
192 : 901 : dl_list_del(&bss->list_id);
193 : 901 : wpa_s->num_bss--;
194 : 901 : 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 : 901 : wpas_notify_bss_removed(wpa_s, bss->bssid, bss->id);
198 : 901 : wpa_bss_anqp_free(bss->anqp);
199 : 901 : os_free(bss);
200 : 901 : }
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 : 2563 : 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 [ - + ]: 2563 : if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
216 : 0 : return NULL;
217 [ + + ]: 5118 : dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
218 [ + + ][ + + ]: 4150 : if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
219 [ + + ]: 2223 : bss->ssid_len == ssid_len &&
220 : 2223 : os_memcmp(bss->ssid, ssid, ssid_len) == 0)
221 : 1595 : return bss;
222 : : }
223 : 2563 : return NULL;
224 : : }
225 : :
226 : :
227 : 2726 : 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 : 2726 : update_time->sec = fetch_time->sec;
234 : 2726 : update_time->usec = fetch_time->usec;
235 : 2726 : update_time->sec -= age_ms / 1000;
236 : 2726 : usec = (age_ms % 1000) * 1000;
237 [ + + ]: 2726 : if (update_time->usec < usec) {
238 : 1092 : update_time->sec--;
239 : 1092 : update_time->usec += 1000000;
240 : : }
241 : 2726 : update_time->usec -= usec;
242 : 2726 : }
243 : :
244 : :
245 : 2003 : static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src,
246 : : struct os_reltime *fetch_time)
247 : : {
248 : 2003 : dst->flags = src->flags;
249 : 2003 : os_memcpy(dst->bssid, src->bssid, ETH_ALEN);
250 : 2003 : dst->freq = src->freq;
251 : 2003 : dst->beacon_int = src->beacon_int;
252 : 2003 : dst->caps = src->caps;
253 : 2003 : dst->qual = src->qual;
254 : 2003 : dst->noise = src->noise;
255 : 2003 : dst->level = src->level;
256 : 2003 : dst->tsf = src->tsf;
257 : :
258 : 2003 : calculate_update_time(fetch_time, src->age, &dst->last_update);
259 : 2003 : }
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 : 3080 : static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
279 : : {
280 [ + + ][ + + ]: 6053 : return bss == wpa_s->current_bss ||
281 [ + + ]: 2973 : os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 ||
282 : 2973 : 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 : 901 : 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 : 901 : bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len);
334 [ - + ]: 901 : if (bss == NULL)
335 : 0 : return NULL;
336 : 901 : bss->id = wpa_s->bss_next_id++;
337 : 901 : bss->last_update_idx = wpa_s->bss_update_idx;
338 : 901 : wpa_bss_copy_res(bss, res, fetch_time);
339 : 901 : os_memcpy(bss->ssid, ssid, ssid_len);
340 : 901 : bss->ssid_len = ssid_len;
341 : 901 : bss->ie_len = res->ie_len;
342 : 901 : bss->beacon_ie_len = res->beacon_ie_len;
343 : 901 : os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
344 : 901 : wpa_bss_set_hessid(bss);
345 : :
346 [ - + # # ]: 901 : 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 : 901 : dl_list_add_tail(&wpa_s->bss, &bss->list);
355 : 901 : dl_list_add_tail(&wpa_s->bss_id, &bss->list_id);
356 : 901 : wpa_s->num_bss++;
357 : 901 : 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 : 901 : wpas_notify_bss_added(wpa_s, bss->bssid, bss->id);
361 : 901 : return bss;
362 : : }
363 : :
364 : :
365 : 125 : 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 : 125 : struct wpabuf *old_ie_buff = NULL;
370 : 125 : struct wpabuf *new_ie_buff = NULL;
371 : : int new_ie_len, old_ie_len, ret, is_multi;
372 : :
373 [ + + + - ]: 125 : switch (ie) {
374 : : case WPA_IE_VENDOR_TYPE:
375 : 25 : old_ie = wpa_bss_get_vendor_ie(old, ie);
376 : 25 : new_ie = wpa_scan_get_vendor_ie(new, ie);
377 : 25 : is_multi = 0;
378 : 25 : break;
379 : : case WPS_IE_VENDOR_TYPE:
380 : 25 : old_ie_buff = wpa_bss_get_vendor_ie_multi(old, ie);
381 : 25 : new_ie_buff = wpa_scan_get_vendor_ie_multi(new, ie);
382 : 25 : is_multi = 1;
383 : 25 : break;
384 : : case WLAN_EID_RSN:
385 : : case WLAN_EID_SUPP_RATES:
386 : : case WLAN_EID_EXT_SUPP_RATES:
387 : 75 : old_ie = wpa_bss_get_ie(old, ie);
388 : 75 : new_ie = wpa_scan_get_ie(new, ie);
389 : 75 : is_multi = 0;
390 : 75 : break;
391 : : default:
392 : 0 : wpa_printf(MSG_DEBUG, "bss: %s: cannot compare IEs", __func__);
393 : 0 : return 0;
394 : : }
395 : :
396 [ + + ]: 125 : if (is_multi) {
397 : : /* in case of multiple IEs stored in buffer */
398 [ + + ]: 25 : old_ie = old_ie_buff ? wpabuf_head_u8(old_ie_buff) : NULL;
399 [ + + ]: 25 : new_ie = new_ie_buff ? wpabuf_head_u8(new_ie_buff) : NULL;
400 [ + + ]: 25 : old_ie_len = old_ie_buff ? wpabuf_len(old_ie_buff) : 0;
401 [ + + ]: 25 : new_ie_len = new_ie_buff ? wpabuf_len(new_ie_buff) : 0;
402 : : } else {
403 : : /* in case of single IE */
404 [ + + ]: 100 : old_ie_len = old_ie ? old_ie[1] + 2 : 0;
405 [ + + ]: 100 : new_ie_len = new_ie ? new_ie[1] + 2 : 0;
406 : : }
407 : :
408 [ + + ][ - + ]: 125 : if (!old_ie || !new_ie)
409 [ + - ][ + + ]: 62 : ret = !old_ie && !new_ie;
410 : : else
411 [ + + ][ + + ]: 63 : ret = (old_ie_len == new_ie_len &&
412 : 56 : os_memcmp(old_ie, new_ie, old_ie_len) == 0);
413 : :
414 : 125 : wpabuf_free(old_ie_buff);
415 : 125 : wpabuf_free(new_ie_buff);
416 : :
417 : 125 : return ret;
418 : : }
419 : :
420 : :
421 : 1102 : static u32 wpa_bss_compare_res(const struct wpa_bss *old,
422 : : const struct wpa_scan_res *new)
423 : : {
424 : 1102 : u32 changes = 0;
425 : 1102 : int caps_diff = old->caps ^ new->caps;
426 : :
427 [ + + ]: 1102 : if (old->freq != new->freq)
428 : 3 : changes |= WPA_BSS_FREQ_CHANGED_FLAG;
429 : :
430 [ - + ]: 1102 : if (old->level != new->level)
431 : 0 : changes |= WPA_BSS_SIGNAL_CHANGED_FLAG;
432 : :
433 [ + + ]: 1102 : if (caps_diff & IEEE80211_CAP_PRIVACY)
434 : 3 : changes |= WPA_BSS_PRIVACY_CHANGED_FLAG;
435 : :
436 [ - + ]: 1102 : if (caps_diff & IEEE80211_CAP_IBSS)
437 : 0 : changes |= WPA_BSS_MODE_CHANGED_FLAG;
438 : :
439 [ + + ][ + + ]: 1102 : if (old->ie_len == new->ie_len &&
440 : 1093 : os_memcmp(old + 1, new + 1, old->ie_len) == 0)
441 : 1077 : return changes;
442 : 25 : changes |= WPA_BSS_IES_CHANGED_FLAG;
443 : :
444 [ + + ]: 25 : if (!are_ies_equal(old, new, WPA_IE_VENDOR_TYPE))
445 : 3 : changes |= WPA_BSS_WPAIE_CHANGED_FLAG;
446 : :
447 [ + + ]: 25 : if (!are_ies_equal(old, new, WLAN_EID_RSN))
448 : 4 : changes |= WPA_BSS_RSNIE_CHANGED_FLAG;
449 : :
450 [ + + ]: 25 : if (!are_ies_equal(old, new, WPS_IE_VENDOR_TYPE))
451 : 10 : changes |= WPA_BSS_WPS_CHANGED_FLAG;
452 : :
453 [ + - - + ]: 50 : if (!are_ies_equal(old, new, WLAN_EID_SUPP_RATES) ||
454 : 25 : !are_ies_equal(old, new, WLAN_EID_EXT_SUPP_RATES))
455 : 0 : changes |= WPA_BSS_RATES_CHANGED_FLAG;
456 : :
457 : 1102 : return changes;
458 : : }
459 : :
460 : :
461 : 1102 : static void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
462 : : const struct wpa_bss *bss)
463 : : {
464 [ + + ]: 1102 : if (changes & WPA_BSS_FREQ_CHANGED_FLAG)
465 : 3 : wpas_notify_bss_freq_changed(wpa_s, bss->id);
466 : :
467 [ - + ]: 1102 : if (changes & WPA_BSS_SIGNAL_CHANGED_FLAG)
468 : 0 : wpas_notify_bss_signal_changed(wpa_s, bss->id);
469 : :
470 [ + + ]: 1102 : if (changes & WPA_BSS_PRIVACY_CHANGED_FLAG)
471 : 3 : wpas_notify_bss_privacy_changed(wpa_s, bss->id);
472 : :
473 [ - + ]: 1102 : if (changes & WPA_BSS_MODE_CHANGED_FLAG)
474 : 0 : wpas_notify_bss_mode_changed(wpa_s, bss->id);
475 : :
476 [ + + ]: 1102 : if (changes & WPA_BSS_WPAIE_CHANGED_FLAG)
477 : 3 : wpas_notify_bss_wpaie_changed(wpa_s, bss->id);
478 : :
479 [ + + ]: 1102 : if (changes & WPA_BSS_RSNIE_CHANGED_FLAG)
480 : 4 : wpas_notify_bss_rsnie_changed(wpa_s, bss->id);
481 : :
482 [ + + ]: 1102 : if (changes & WPA_BSS_WPS_CHANGED_FLAG)
483 : 10 : wpas_notify_bss_wps_changed(wpa_s, bss->id);
484 : :
485 [ + + ]: 1102 : if (changes & WPA_BSS_IES_CHANGED_FLAG)
486 : 25 : wpas_notify_bss_ies_changed(wpa_s, bss->id);
487 : :
488 [ - + ]: 1102 : if (changes & WPA_BSS_RATES_CHANGED_FLAG)
489 : 0 : wpas_notify_bss_rates_changed(wpa_s, bss->id);
490 : 1102 : }
491 : :
492 : :
493 : : static struct wpa_bss *
494 : 1102 : 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 : 1102 : changes = wpa_bss_compare_res(bss, res);
500 : 1102 : bss->scan_miss_count = 0;
501 : 1102 : bss->last_update_idx = wpa_s->bss_update_idx;
502 : 1102 : wpa_bss_copy_res(bss, res, fetch_time);
503 : : /* Move the entry to the end of the list */
504 : 1102 : dl_list_del(&bss->list);
505 : : #ifdef CONFIG_P2P
506 [ + + - + ]: 1796 : if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
507 : 694 : !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 [ + + ]: 1102 : if (bss->ie_len + bss->beacon_ie_len >=
522 : 1102 : res->ie_len + res->beacon_ie_len) {
523 : 1082 : os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
524 : 1082 : bss->ie_len = res->ie_len;
525 : 1082 : bss->beacon_ie_len = res->beacon_ie_len;
526 : : } else {
527 : : struct wpa_bss *nbss;
528 : 20 : struct dl_list *prev = bss->list_id.prev;
529 : 20 : dl_list_del(&bss->list_id);
530 : 20 : nbss = os_realloc(bss, sizeof(*bss) + res->ie_len +
531 : 20 : res->beacon_ie_len);
532 [ + - ]: 20 : if (nbss) {
533 : : unsigned int i;
534 [ + + ]: 41 : for (i = 0; i < wpa_s->last_scan_res_used; i++) {
535 [ - + ]: 21 : if (wpa_s->last_scan_res[i] == bss) {
536 : 0 : wpa_s->last_scan_res[i] = nbss;
537 : 0 : break;
538 : : }
539 : : }
540 [ + + ]: 20 : if (wpa_s->current_bss == bss)
541 : 2 : wpa_s->current_bss = nbss;
542 : 20 : bss = nbss;
543 : 20 : os_memcpy(bss + 1, res + 1,
544 : : res->ie_len + res->beacon_ie_len);
545 : 20 : bss->ie_len = res->ie_len;
546 : 20 : bss->beacon_ie_len = res->beacon_ie_len;
547 : : }
548 : 20 : dl_list_add(prev, &bss->list_id);
549 : : }
550 [ + + ]: 1102 : if (changes & WPA_BSS_IES_CHANGED_FLAG)
551 : 25 : wpa_bss_set_hessid(bss);
552 : 1102 : dl_list_add_tail(&wpa_s->bss, &bss->list);
553 : :
554 : 1102 : notify_bss_changes(wpa_s, changes, bss);
555 : :
556 : 1102 : 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 : 767 : void wpa_bss_update_start(struct wpa_supplicant *wpa_s)
570 : : {
571 : 767 : wpa_s->bss_update_idx++;
572 : 767 : wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Start scan result update %u",
573 : : wpa_s->bss_update_idx);
574 : 767 : wpa_s->last_scan_res_used = 0;
575 : 767 : }
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 : 2996 : 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 [ + + ]: 2996 : if (wpa_s->conf->ignore_old_scan_res) {
596 : : struct os_reltime update;
597 : 723 : calculate_update_time(fetch_time, res->age, &update);
598 [ + + ]: 723 : if (os_reltime_before(&update, &wpa_s->scan_trigger_time)) {
599 : : struct os_reltime age;
600 : 510 : os_reltime_sub(&wpa_s->scan_trigger_time, &update,
601 : : &age);
602 : 510 : 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 : 510 : return;
608 : : }
609 : : }
610 : :
611 : 2486 : ssid = wpa_scan_get_ie(res, WLAN_EID_SSID);
612 [ - + ]: 2486 : 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 [ - + ]: 2486 : 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 : 2486 : p2p = wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE);
624 : : #ifdef CONFIG_P2P
625 [ + + ][ + + ]: 2486 : if (p2p == NULL &&
626 : 1054 : 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 : 16 : wpa_printf(MSG_DEBUG, "BSS: No P2P IE - skipping BSS " MACSTR
632 : 96 : " update for P2P interface", MAC2STR(res->bssid));
633 : 16 : return;
634 : : }
635 : : #endif /* CONFIG_P2P */
636 [ + + ][ + + ]: 2470 : if (p2p && ssid[1] == P2P_WILDCARD_SSID_LEN &&
[ + - ]
637 : 467 : os_memcmp(ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 0)
638 : 467 : 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 : 2003 : bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
643 [ + + ]: 2003 : if (bss == NULL)
644 : 901 : bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res, fetch_time);
645 : : else {
646 : 1102 : bss = wpa_bss_update(wpa_s, bss, res, fetch_time);
647 [ + - ]: 1102 : if (wpa_s->last_scan_res) {
648 : : unsigned int i;
649 [ + + ]: 2730 : for (i = 0; i < wpa_s->last_scan_res_used; i++) {
650 [ - + ]: 1628 : if (bss == wpa_s->last_scan_res[i]) {
651 : : /* Already in the list */
652 : 0 : return;
653 : : }
654 : : }
655 : : }
656 : : }
657 : :
658 [ - + ]: 2003 : if (bss == NULL)
659 : 0 : return;
660 [ + + ]: 2003 : if (wpa_s->last_scan_res_used >= wpa_s->last_scan_res_size) {
661 : : struct wpa_bss **n;
662 : : unsigned int siz;
663 [ + - ]: 13 : if (wpa_s->last_scan_res_size == 0)
664 : 13 : siz = 32;
665 : : else
666 : 0 : siz = wpa_s->last_scan_res_size * 2;
667 : 13 : n = os_realloc_array(wpa_s->last_scan_res, siz,
668 : : sizeof(struct wpa_bss *));
669 [ - + ]: 13 : if (n == NULL)
670 : 0 : return;
671 : 13 : wpa_s->last_scan_res = n;
672 : 13 : wpa_s->last_scan_res_size = siz;
673 : : }
674 : :
675 : 2996 : wpa_s->last_scan_res[wpa_s->last_scan_res_used++] = bss;
676 : : }
677 : :
678 : :
679 : 2024 : 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 [ - + ]: 2024 : if (info == NULL)
686 : 0 : return 1;
687 : :
688 [ + - ]: 2024 : if (info->num_freqs) {
689 : 2024 : found = 0;
690 [ + + ]: 3188 : for (i = 0; i < info->num_freqs; i++) {
691 [ + + ]: 2990 : if (bss->freq == info->freqs[i]) {
692 : 1826 : found = 1;
693 : 1826 : break;
694 : : }
695 : : }
696 [ + + ]: 2024 : if (!found)
697 : 198 : return 0;
698 : : }
699 : :
700 [ + - ]: 1826 : if (info->num_ssids) {
701 : 1826 : found = 0;
702 [ + + ]: 2935 : for (i = 0; i < info->num_ssids; i++) {
703 : 1826 : const struct wpa_driver_scan_ssid *s = &info->ssids[i];
704 [ + - ][ + + ]: 1826 : if ((s->ssid == NULL || s->ssid_len == 0) ||
[ + + ]
705 [ + + ]: 142 : (s->ssid_len == bss->ssid_len &&
706 : 142 : os_memcmp(s->ssid, bss->ssid, bss->ssid_len) ==
707 : : 0)) {
708 : 717 : found = 1;
709 : 717 : break;
710 : : }
711 : : }
712 [ + + ]: 1826 : if (!found)
713 : 1109 : return 0;
714 : : }
715 : :
716 : 2024 : 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 : 767 : 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 : 767 : os_get_reltime(&wpa_s->last_scan);
736 [ + + ]: 767 : if (!new_scan)
737 : 767 : return; /* do not expire entries without new scan */
738 : :
739 [ + + ]: 2817 : dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
740 [ + + ]: 2051 : if (wpa_bss_in_use(wpa_s, bss))
741 : 27 : continue;
742 [ + + ]: 2024 : if (!wpa_bss_included_in_scan(bss, info))
743 : 1307 : continue; /* expire only BSSes that were scanned */
744 [ + + ]: 717 : if (bss->last_update_idx < wpa_s->bss_update_idx)
745 : 17 : bss->scan_miss_count++;
746 [ + + ]: 717 : if (bss->scan_miss_count >=
747 : 717 : wpa_s->conf->bss_expiration_scan_count) {
748 : 4 : wpa_bss_remove(wpa_s, bss, "no match in scan");
749 : : }
750 : : }
751 : :
752 : 766 : 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 : 276 : 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 [ + + ]: 276 : if (dl_list_empty(&wpa_s->bss))
770 : 276 : return;
771 : :
772 : 85 : os_get_reltime(&t);
773 : 85 : t.sec -= age;
774 : :
775 [ + + ]: 166 : dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
776 [ + + ]: 132 : if (wpa_bss_in_use(wpa_s, bss))
777 : 81 : continue;
778 : :
779 [ - + ]: 51 : if (os_reltime_before(&bss->last_update, &t)) {
780 : 0 : wpa_bss_remove(wpa_s, bss, __func__);
781 : : } else
782 : 51 : break;
783 : : }
784 : : }
785 : :
786 : :
787 : 276 : static void wpa_bss_timeout(void *eloop_ctx, void *timeout_ctx)
788 : : {
789 : 276 : struct wpa_supplicant *wpa_s = eloop_ctx;
790 : :
791 : 276 : wpa_bss_flush_by_age(wpa_s, wpa_s->conf->bss_expiration_age);
792 : 276 : eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0,
793 : : wpa_bss_timeout, wpa_s, NULL);
794 : 276 : }
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 : 22 : int wpa_bss_init(struct wpa_supplicant *wpa_s)
806 : : {
807 : 22 : dl_list_init(&wpa_s->bss);
808 : 22 : dl_list_init(&wpa_s->bss_id);
809 : 22 : eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0,
810 : : wpa_bss_timeout, wpa_s, NULL);
811 : 22 : 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 : 677 : void wpa_bss_flush(struct wpa_supplicant *wpa_s)
820 : : {
821 : : struct wpa_bss *bss, *n;
822 : :
823 [ - + ]: 677 : if (wpa_s->bss.next == NULL)
824 : 677 : return; /* BSS table not yet initialized */
825 : :
826 [ + + ]: 1574 : dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
827 [ - + ]: 897 : if (wpa_bss_in_use(wpa_s, bss))
828 : 0 : continue;
829 : 897 : wpa_bss_remove(wpa_s, bss, __func__);
830 : : }
831 : : }
832 : :
833 : :
834 : : /**
835 : : * wpa_bss_deinit - Deinitialize BSS table
836 : : * @wpa_s: Pointer to wpa_supplicant data
837 : : */
838 : 22 : void wpa_bss_deinit(struct wpa_supplicant *wpa_s)
839 : : {
840 : 22 : eloop_cancel_timeout(wpa_bss_timeout, wpa_s, NULL);
841 : 22 : wpa_bss_flush(wpa_s);
842 : 22 : }
843 : :
844 : :
845 : : /**
846 : : * wpa_bss_get_bssid - Fetch a BSS table entry based on BSSID
847 : : * @wpa_s: Pointer to wpa_supplicant data
848 : : * @bssid: BSSID
849 : : * Returns: Pointer to the BSS entry or %NULL if not found
850 : : */
851 : 117 : struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
852 : : const u8 *bssid)
853 : : {
854 : : struct wpa_bss *bss;
855 [ - + ]: 117 : if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
856 : 0 : return NULL;
857 [ + + ]: 128 : dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
858 [ + + ]: 127 : if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
859 : 116 : return bss;
860 : : }
861 : 117 : return NULL;
862 : : }
863 : :
864 : :
865 : : /**
866 : : * wpa_bss_get_bssid_latest - Fetch the latest BSS table entry based on BSSID
867 : : * @wpa_s: Pointer to wpa_supplicant data
868 : : * @bssid: BSSID
869 : : * Returns: Pointer to the BSS entry or %NULL if not found
870 : : *
871 : : * This function is like wpa_bss_get_bssid(), but full BSS table is iterated to
872 : : * find the entry that has the most recent update. This can help in finding the
873 : : * correct entry in cases where the SSID of the AP may have changed recently
874 : : * (e.g., in WPS reconfiguration cases).
875 : : */
876 : 91 : struct wpa_bss * wpa_bss_get_bssid_latest(struct wpa_supplicant *wpa_s,
877 : : const u8 *bssid)
878 : : {
879 : 91 : struct wpa_bss *bss, *found = NULL;
880 [ - + ]: 91 : if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
881 : 0 : return NULL;
882 [ + + ]: 318 : dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
883 [ + + ]: 227 : if (os_memcmp(bss->bssid, bssid, ETH_ALEN) != 0)
884 : 64 : continue;
885 [ + + - + ]: 255 : if (found == NULL ||
886 : 92 : os_reltime_before(&found->last_update, &bss->last_update))
887 : 71 : found = bss;
888 : : }
889 : 91 : return found;
890 : : }
891 : :
892 : :
893 : : #ifdef CONFIG_P2P
894 : : /**
895 : : * wpa_bss_get_p2p_dev_addr - Fetch a BSS table entry based on P2P Device Addr
896 : : * @wpa_s: Pointer to wpa_supplicant data
897 : : * @dev_addr: P2P Device Address of the GO
898 : : * Returns: Pointer to the BSS entry or %NULL if not found
899 : : */
900 : 3 : struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s,
901 : : const u8 *dev_addr)
902 : : {
903 : : struct wpa_bss *bss;
904 [ + - ]: 8 : dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
905 : : u8 addr[ETH_ALEN];
906 [ + + ]: 8 : if (p2p_parse_dev_addr((const u8 *) (bss + 1), bss->ie_len,
907 [ + - ]: 3 : addr) == 0 &&
908 : 3 : os_memcmp(addr, dev_addr, ETH_ALEN) == 0)
909 : 3 : return bss;
910 : : }
911 : 3 : return NULL;
912 : : }
913 : : #endif /* CONFIG_P2P */
914 : :
915 : :
916 : : /**
917 : : * wpa_bss_get_id - Fetch a BSS table entry based on identifier
918 : : * @wpa_s: Pointer to wpa_supplicant data
919 : : * @id: Unique identifier (struct wpa_bss::id) assigned for the entry
920 : : * Returns: Pointer to the BSS entry or %NULL if not found
921 : : */
922 : 1 : struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id)
923 : : {
924 : : struct wpa_bss *bss;
925 [ + - ]: 1 : dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
926 [ + - ]: 1 : if (bss->id == id)
927 : 1 : return bss;
928 : : }
929 : 1 : return NULL;
930 : : }
931 : :
932 : :
933 : : /**
934 : : * wpa_bss_get_id_range - Fetch a BSS table entry based on identifier range
935 : : * @wpa_s: Pointer to wpa_supplicant data
936 : : * @idf: Smallest allowed identifier assigned for the entry
937 : : * @idf: Largest allowed identifier assigned for the entry
938 : : * Returns: Pointer to the BSS entry or %NULL if not found
939 : : *
940 : : * This function is similar to wpa_bss_get_id() but allows a BSS entry with the
941 : : * smallest id value to be fetched within the specified range without the
942 : : * caller having to know the exact id.
943 : : */
944 : 1 : struct wpa_bss * wpa_bss_get_id_range(struct wpa_supplicant *wpa_s,
945 : : unsigned int idf, unsigned int idl)
946 : : {
947 : : struct wpa_bss *bss;
948 [ + - ]: 1 : dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
949 [ + - ][ + - ]: 1 : if (bss->id >= idf && bss->id <= idl)
950 : 1 : return bss;
951 : : }
952 : 1 : return NULL;
953 : : }
954 : :
955 : :
956 : : /**
957 : : * wpa_bss_get_ie - Fetch a specified information element from a BSS entry
958 : : * @bss: BSS table entry
959 : : * @ie: Information element identitifier (WLAN_EID_*)
960 : : * Returns: Pointer to the information element (id field) or %NULL if not found
961 : : *
962 : : * This function returns the first matching information element in the BSS
963 : : * entry.
964 : : */
965 : 6342 : const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
966 : : {
967 : : const u8 *end, *pos;
968 : :
969 : 6342 : pos = (const u8 *) (bss + 1);
970 : 6342 : end = pos + bss->ie_len;
971 : :
972 [ + + ]: 42484 : while (pos + 1 < end) {
973 [ - + ]: 40289 : if (pos + 2 + pos[1] > end)
974 : 0 : break;
975 [ + + ]: 40289 : if (pos[0] == ie)
976 : 4147 : return pos;
977 : 36142 : pos += 2 + pos[1];
978 : : }
979 : :
980 : 6342 : return NULL;
981 : : }
982 : :
983 : :
984 : : /**
985 : : * wpa_bss_get_vendor_ie - Fetch a vendor information element from a BSS entry
986 : : * @bss: BSS table entry
987 : : * @vendor_type: Vendor type (four octets starting the IE payload)
988 : : * Returns: Pointer to the information element (id field) or %NULL if not found
989 : : *
990 : : * This function returns the first matching information element in the BSS
991 : : * entry.
992 : : */
993 : 6503 : const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
994 : : {
995 : : const u8 *end, *pos;
996 : :
997 : 6503 : pos = (const u8 *) (bss + 1);
998 : 6503 : end = pos + bss->ie_len;
999 : :
1000 [ + + ]: 70541 : while (pos + 1 < end) {
1001 [ - + ]: 66395 : if (pos + 2 + pos[1] > end)
1002 : 0 : break;
1003 [ + + ]: 81261 : if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
[ + - + + ]
1004 : 14866 : vendor_type == WPA_GET_BE32(&pos[2]))
1005 : 2357 : return pos;
1006 : 64038 : pos += 2 + pos[1];
1007 : : }
1008 : :
1009 : 6503 : return NULL;
1010 : : }
1011 : :
1012 : :
1013 : : /**
1014 : : * wpa_bss_get_vendor_ie_beacon - Fetch a vendor information from a BSS entry
1015 : : * @bss: BSS table entry
1016 : : * @vendor_type: Vendor type (four octets starting the IE payload)
1017 : : * Returns: Pointer to the information element (id field) or %NULL if not found
1018 : : *
1019 : : * This function returns the first matching information element in the BSS
1020 : : * entry.
1021 : : *
1022 : : * This function is like wpa_bss_get_vendor_ie(), but uses IE buffer only
1023 : : * from Beacon frames instead of either Beacon or Probe Response frames.
1024 : : */
1025 : 785 : const u8 * wpa_bss_get_vendor_ie_beacon(const struct wpa_bss *bss,
1026 : : u32 vendor_type)
1027 : : {
1028 : : const u8 *end, *pos;
1029 : :
1030 [ + + ]: 785 : if (bss->beacon_ie_len == 0)
1031 : 141 : return NULL;
1032 : :
1033 : 644 : pos = (const u8 *) (bss + 1);
1034 : 644 : pos += bss->ie_len;
1035 : 644 : end = pos + bss->beacon_ie_len;
1036 : :
1037 [ + + ]: 7088 : while (pos + 1 < end) {
1038 [ - + ]: 6454 : if (pos + 2 + pos[1] > end)
1039 : 0 : break;
1040 [ + + ]: 7270 : if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
[ + - + + ]
1041 : 816 : vendor_type == WPA_GET_BE32(&pos[2]))
1042 : 10 : return pos;
1043 : 6444 : pos += 2 + pos[1];
1044 : : }
1045 : :
1046 : 785 : return NULL;
1047 : : }
1048 : :
1049 : :
1050 : : /**
1051 : : * wpa_bss_get_vendor_ie_multi - Fetch vendor IE data from a BSS entry
1052 : : * @bss: BSS table entry
1053 : : * @vendor_type: Vendor type (four octets starting the IE payload)
1054 : : * Returns: Pointer to the information element payload or %NULL if not found
1055 : : *
1056 : : * This function returns concatenated payload of possibly fragmented vendor
1057 : : * specific information elements in the BSS entry. The caller is responsible for
1058 : : * freeing the returned buffer.
1059 : : */
1060 : 1550 : struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
1061 : : u32 vendor_type)
1062 : : {
1063 : : struct wpabuf *buf;
1064 : : const u8 *end, *pos;
1065 : :
1066 : 1550 : buf = wpabuf_alloc(bss->ie_len);
1067 [ - + ]: 1550 : if (buf == NULL)
1068 : 0 : return NULL;
1069 : :
1070 : 1550 : pos = (const u8 *) (bss + 1);
1071 : 1550 : end = pos + bss->ie_len;
1072 : :
1073 [ + + ]: 17344 : while (pos + 1 < end) {
1074 [ - + ]: 15794 : if (pos + 2 + pos[1] > end)
1075 : 0 : break;
1076 [ + + ]: 19409 : if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
[ + - + + ]
1077 : 3615 : vendor_type == WPA_GET_BE32(&pos[2]))
1078 : 752 : wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
1079 : 15794 : pos += 2 + pos[1];
1080 : : }
1081 : :
1082 [ + + ]: 1550 : if (wpabuf_len(buf) == 0) {
1083 : 798 : wpabuf_free(buf);
1084 : 798 : buf = NULL;
1085 : : }
1086 : :
1087 : 1550 : return buf;
1088 : : }
1089 : :
1090 : :
1091 : : /**
1092 : : * wpa_bss_get_vendor_ie_multi_beacon - Fetch vendor IE data from a BSS entry
1093 : : * @bss: BSS table entry
1094 : : * @vendor_type: Vendor type (four octets starting the IE payload)
1095 : : * Returns: Pointer to the information element payload or %NULL if not found
1096 : : *
1097 : : * This function returns concatenated payload of possibly fragmented vendor
1098 : : * specific information elements in the BSS entry. The caller is responsible for
1099 : : * freeing the returned buffer.
1100 : : *
1101 : : * This function is like wpa_bss_get_vendor_ie_multi(), but uses IE buffer only
1102 : : * from Beacon frames instead of either Beacon or Probe Response frames.
1103 : : */
1104 : 10 : struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss,
1105 : : u32 vendor_type)
1106 : : {
1107 : : struct wpabuf *buf;
1108 : : const u8 *end, *pos;
1109 : :
1110 : 10 : buf = wpabuf_alloc(bss->beacon_ie_len);
1111 [ - + ]: 10 : if (buf == NULL)
1112 : 0 : return NULL;
1113 : :
1114 : 10 : pos = (const u8 *) (bss + 1);
1115 : 10 : pos += bss->ie_len;
1116 : 10 : end = pos + bss->beacon_ie_len;
1117 : :
1118 [ + + ]: 110 : while (pos + 1 < end) {
1119 [ - + ]: 100 : if (pos + 2 + pos[1] > end)
1120 : 0 : break;
1121 [ + + ]: 122 : if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
[ + - + + ]
1122 : 22 : vendor_type == WPA_GET_BE32(&pos[2]))
1123 : 9 : wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
1124 : 100 : pos += 2 + pos[1];
1125 : : }
1126 : :
1127 [ + + ]: 10 : if (wpabuf_len(buf) == 0) {
1128 : 1 : wpabuf_free(buf);
1129 : 1 : buf = NULL;
1130 : : }
1131 : :
1132 : 10 : return buf;
1133 : : }
1134 : :
1135 : :
1136 : : /**
1137 : : * wpa_bss_get_max_rate - Get maximum legacy TX rate supported in a BSS
1138 : : * @bss: BSS table entry
1139 : : * Returns: Maximum legacy rate in units of 500 kbps
1140 : : */
1141 : 0 : int wpa_bss_get_max_rate(const struct wpa_bss *bss)
1142 : : {
1143 : 0 : int rate = 0;
1144 : : const u8 *ie;
1145 : : int i;
1146 : :
1147 : 0 : ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
1148 [ # # ][ # # ]: 0 : for (i = 0; ie && i < ie[1]; i++) {
1149 [ # # ]: 0 : if ((ie[i + 2] & 0x7f) > rate)
1150 : 0 : rate = ie[i + 2] & 0x7f;
1151 : : }
1152 : :
1153 : 0 : ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
1154 [ # # ][ # # ]: 0 : for (i = 0; ie && i < ie[1]; i++) {
1155 [ # # ]: 0 : if ((ie[i + 2] & 0x7f) > rate)
1156 : 0 : rate = ie[i + 2] & 0x7f;
1157 : : }
1158 : :
1159 : 0 : return rate;
1160 : : }
1161 : :
1162 : :
1163 : : /**
1164 : : * wpa_bss_get_bit_rates - Get legacy TX rates supported in a BSS
1165 : : * @bss: BSS table entry
1166 : : * @rates: Buffer for returning a pointer to the rates list (units of 500 kbps)
1167 : : * Returns: number of legacy TX rates or -1 on failure
1168 : : *
1169 : : * The caller is responsible for freeing the returned buffer with os_free() in
1170 : : * case of success.
1171 : : */
1172 : 0 : int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates)
1173 : : {
1174 : : const u8 *ie, *ie2;
1175 : : int i, j;
1176 : : unsigned int len;
1177 : : u8 *r;
1178 : :
1179 : 0 : ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
1180 : 0 : ie2 = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
1181 : :
1182 [ # # ][ # # ]: 0 : len = (ie ? ie[1] : 0) + (ie2 ? ie2[1] : 0);
1183 : :
1184 : 0 : r = os_malloc(len);
1185 [ # # ]: 0 : if (!r)
1186 : 0 : return -1;
1187 : :
1188 [ # # ][ # # ]: 0 : for (i = 0; ie && i < ie[1]; i++)
1189 : 0 : r[i] = ie[i + 2] & 0x7f;
1190 : :
1191 [ # # ][ # # ]: 0 : for (j = 0; ie2 && j < ie2[1]; j++)
1192 : 0 : r[i + j] = ie2[j + 2] & 0x7f;
1193 : :
1194 : 0 : *rates = r;
1195 : 0 : return len;
1196 : : }
|