3 * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
9 #include "utils/includes.h"
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"
23 * WPA_BSS_EXPIRATION_PERIOD - Period of expiration run in seconds
25 #define WPA_BSS_EXPIRATION_PERIOD 10
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)
38 static void wpa_bss_set_hessid(struct wpa_bss *bss)
40 #ifdef CONFIG_INTERWORKING
41 const u8 *ie = wpa_bss_get_ie(bss, WLAN_EID_INTERWORKING);
42 if (ie == NULL || (ie[1] != 7 && ie[1] != 9)) {
43 os_memset(bss->hessid, 0, ETH_ALEN);
47 os_memcpy(bss->hessid, ie + 3, ETH_ALEN);
49 os_memcpy(bss->hessid, ie + 5, ETH_ALEN);
50 #endif /* CONFIG_INTERWORKING */
54 struct wpa_bss_anqp * wpa_bss_anqp_alloc(void)
56 struct wpa_bss_anqp *anqp;
57 anqp = os_zalloc(sizeof(*anqp));
65 static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
71 if (anqp->users > 0) {
72 /* Another BSS entry holds a pointer to this ANQP info */
76 #ifdef CONFIG_INTERWORKING
77 wpabuf_free(anqp->venue_name);
78 wpabuf_free(anqp->network_auth_type);
79 wpabuf_free(anqp->roaming_consortium);
80 wpabuf_free(anqp->ip_addr_type_availability);
81 wpabuf_free(anqp->nai_realm);
82 wpabuf_free(anqp->anqp_3gpp);
83 wpabuf_free(anqp->domain_name);
84 #endif /* CONFIG_INTERWORKING */
86 wpabuf_free(anqp->hs20_operator_friendly_name);
87 wpabuf_free(anqp->hs20_wan_metrics);
88 wpabuf_free(anqp->hs20_connection_capability);
89 wpabuf_free(anqp->hs20_operating_class);
90 #endif /* CONFIG_HS20 */
96 static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
99 dl_list_del(&bss->list);
100 dl_list_del(&bss->list_id);
102 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Remove id %u BSSID " MACSTR
103 " SSID '%s' due to %s", bss->id, MAC2STR(bss->bssid),
104 wpa_ssid_txt(bss->ssid, bss->ssid_len), reason);
105 wpas_notify_bss_removed(wpa_s, bss->bssid, bss->id);
106 wpa_bss_anqp_free(bss->anqp);
111 struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
112 const u8 *ssid, size_t ssid_len)
115 if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
117 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
118 if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
119 bss->ssid_len == ssid_len &&
120 os_memcmp(bss->ssid, ssid, ssid_len) == 0)
127 static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src)
131 dst->flags = src->flags;
132 os_memcpy(dst->bssid, src->bssid, ETH_ALEN);
133 dst->freq = src->freq;
134 dst->beacon_int = src->beacon_int;
135 dst->caps = src->caps;
136 dst->qual = src->qual;
137 dst->noise = src->noise;
138 dst->level = src->level;
141 os_get_time(&dst->last_update);
142 dst->last_update.sec -= src->age / 1000;
143 usec = (src->age % 1000) * 1000;
144 if (dst->last_update.usec < usec) {
145 dst->last_update.sec--;
146 dst->last_update.usec += 1000000;
148 dst->last_update.usec -= usec;
152 static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
154 struct wpa_ssid *ssid;
156 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
157 if (ssid->ssid == NULL || ssid->ssid_len == 0)
159 if (ssid->ssid_len == bss->ssid_len &&
160 os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) == 0)
168 static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
170 return bss == wpa_s->current_bss ||
171 os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 ||
172 os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0;
176 static int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s)
180 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
181 if (!wpa_bss_known(wpa_s, bss)) {
182 wpa_bss_remove(wpa_s, bss, __func__);
191 static int wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s)
196 * Remove the oldest entry that does not match with any configured
199 if (wpa_bss_remove_oldest_unknown(wpa_s) == 0)
203 * Remove the oldest entry that isn't currently in use.
205 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
206 if (!wpa_bss_in_use(wpa_s, bss)) {
207 wpa_bss_remove(wpa_s, bss, __func__);
216 static void wpa_bss_add(struct wpa_supplicant *wpa_s,
217 const u8 *ssid, size_t ssid_len,
218 struct wpa_scan_res *res)
222 bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len);
225 bss->id = wpa_s->bss_next_id++;
226 bss->last_update_idx = wpa_s->bss_update_idx;
227 wpa_bss_copy_res(bss, res);
228 os_memcpy(bss->ssid, ssid, ssid_len);
229 bss->ssid_len = ssid_len;
230 bss->ie_len = res->ie_len;
231 bss->beacon_ie_len = res->beacon_ie_len;
232 os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
233 wpa_bss_set_hessid(bss);
235 dl_list_add_tail(&wpa_s->bss, &bss->list);
236 dl_list_add_tail(&wpa_s->bss_id, &bss->list_id);
238 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Add new id %u BSSID " MACSTR
240 bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len));
241 wpas_notify_bss_added(wpa_s, bss->bssid, bss->id);
242 if (wpa_s->num_bss > wpa_s->conf->bss_max_count &&
243 wpa_bss_remove_oldest(wpa_s) != 0) {
244 wpa_printf(MSG_ERROR, "Increasing the MAX BSS count to %d "
245 "because all BSSes are in use. We should normally "
246 "not get here!", (int) wpa_s->num_bss);
247 wpa_s->conf->bss_max_count = wpa_s->num_bss;
252 static int are_ies_equal(const struct wpa_bss *old,
253 const struct wpa_scan_res *new, u32 ie)
255 const u8 *old_ie, *new_ie;
256 struct wpabuf *old_ie_buff = NULL;
257 struct wpabuf *new_ie_buff = NULL;
258 int new_ie_len, old_ie_len, ret, is_multi;
261 case WPA_IE_VENDOR_TYPE:
262 old_ie = wpa_bss_get_vendor_ie(old, ie);
263 new_ie = wpa_scan_get_vendor_ie(new, ie);
266 case WPS_IE_VENDOR_TYPE:
267 old_ie_buff = wpa_bss_get_vendor_ie_multi(old, ie);
268 new_ie_buff = wpa_scan_get_vendor_ie_multi(new, ie);
272 case WLAN_EID_SUPP_RATES:
273 case WLAN_EID_EXT_SUPP_RATES:
274 old_ie = wpa_bss_get_ie(old, ie);
275 new_ie = wpa_scan_get_ie(new, ie);
279 wpa_printf(MSG_DEBUG, "bss: %s: cannot compare IEs", __func__);
284 /* in case of multiple IEs stored in buffer */
285 old_ie = old_ie_buff ? wpabuf_head_u8(old_ie_buff) : NULL;
286 new_ie = new_ie_buff ? wpabuf_head_u8(new_ie_buff) : NULL;
287 old_ie_len = old_ie_buff ? wpabuf_len(old_ie_buff) : 0;
288 new_ie_len = new_ie_buff ? wpabuf_len(new_ie_buff) : 0;
290 /* in case of single IE */
291 old_ie_len = old_ie ? old_ie[1] + 2 : 0;
292 new_ie_len = new_ie ? new_ie[1] + 2 : 0;
295 if (!old_ie || !new_ie)
296 ret = !old_ie && !new_ie;
298 ret = (old_ie_len == new_ie_len &&
299 os_memcmp(old_ie, new_ie, old_ie_len) == 0);
301 wpabuf_free(old_ie_buff);
302 wpabuf_free(new_ie_buff);
308 static u32 wpa_bss_compare_res(const struct wpa_bss *old,
309 const struct wpa_scan_res *new)
312 int caps_diff = old->caps ^ new->caps;
314 if (old->freq != new->freq)
315 changes |= WPA_BSS_FREQ_CHANGED_FLAG;
317 if (old->level != new->level)
318 changes |= WPA_BSS_SIGNAL_CHANGED_FLAG;
320 if (caps_diff & IEEE80211_CAP_PRIVACY)
321 changes |= WPA_BSS_PRIVACY_CHANGED_FLAG;
323 if (caps_diff & IEEE80211_CAP_IBSS)
324 changes |= WPA_BSS_MODE_CHANGED_FLAG;
326 if (old->ie_len == new->ie_len &&
327 os_memcmp(old + 1, new + 1, old->ie_len) == 0)
329 changes |= WPA_BSS_IES_CHANGED_FLAG;
331 if (!are_ies_equal(old, new, WPA_IE_VENDOR_TYPE))
332 changes |= WPA_BSS_WPAIE_CHANGED_FLAG;
334 if (!are_ies_equal(old, new, WLAN_EID_RSN))
335 changes |= WPA_BSS_RSNIE_CHANGED_FLAG;
337 if (!are_ies_equal(old, new, WPS_IE_VENDOR_TYPE))
338 changes |= WPA_BSS_WPS_CHANGED_FLAG;
340 if (!are_ies_equal(old, new, WLAN_EID_SUPP_RATES) ||
341 !are_ies_equal(old, new, WLAN_EID_EXT_SUPP_RATES))
342 changes |= WPA_BSS_RATES_CHANGED_FLAG;
348 static void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
349 const struct wpa_bss *bss)
351 if (changes & WPA_BSS_FREQ_CHANGED_FLAG)
352 wpas_notify_bss_freq_changed(wpa_s, bss->id);
354 if (changes & WPA_BSS_SIGNAL_CHANGED_FLAG)
355 wpas_notify_bss_signal_changed(wpa_s, bss->id);
357 if (changes & WPA_BSS_PRIVACY_CHANGED_FLAG)
358 wpas_notify_bss_privacy_changed(wpa_s, bss->id);
360 if (changes & WPA_BSS_MODE_CHANGED_FLAG)
361 wpas_notify_bss_mode_changed(wpa_s, bss->id);
363 if (changes & WPA_BSS_WPAIE_CHANGED_FLAG)
364 wpas_notify_bss_wpaie_changed(wpa_s, bss->id);
366 if (changes & WPA_BSS_RSNIE_CHANGED_FLAG)
367 wpas_notify_bss_rsnie_changed(wpa_s, bss->id);
369 if (changes & WPA_BSS_WPS_CHANGED_FLAG)
370 wpas_notify_bss_wps_changed(wpa_s, bss->id);
372 if (changes & WPA_BSS_IES_CHANGED_FLAG)
373 wpas_notify_bss_ies_changed(wpa_s, bss->id);
375 if (changes & WPA_BSS_RATES_CHANGED_FLAG)
376 wpas_notify_bss_rates_changed(wpa_s, bss->id);
380 static void wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
381 struct wpa_scan_res *res)
385 changes = wpa_bss_compare_res(bss, res);
386 bss->scan_miss_count = 0;
387 bss->last_update_idx = wpa_s->bss_update_idx;
388 wpa_bss_copy_res(bss, res);
389 /* Move the entry to the end of the list */
390 dl_list_del(&bss->list);
391 if (bss->ie_len + bss->beacon_ie_len >=
392 res->ie_len + res->beacon_ie_len) {
393 os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
394 bss->ie_len = res->ie_len;
395 bss->beacon_ie_len = res->beacon_ie_len;
397 struct wpa_bss *nbss;
398 struct dl_list *prev = bss->list_id.prev;
399 dl_list_del(&bss->list_id);
400 nbss = os_realloc(bss, sizeof(*bss) + res->ie_len +
403 if (wpa_s->current_bss == bss)
404 wpa_s->current_bss = nbss;
406 os_memcpy(bss + 1, res + 1,
407 res->ie_len + res->beacon_ie_len);
408 bss->ie_len = res->ie_len;
409 bss->beacon_ie_len = res->beacon_ie_len;
411 dl_list_add(prev, &bss->list_id);
413 if (changes & WPA_BSS_IES_CHANGED_FLAG)
414 wpa_bss_set_hessid(bss);
415 dl_list_add_tail(&wpa_s->bss, &bss->list);
417 notify_bss_changes(wpa_s, changes, bss);
421 void wpa_bss_update_start(struct wpa_supplicant *wpa_s)
423 wpa_s->bss_update_idx++;
424 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Start scan result update %u",
425 wpa_s->bss_update_idx);
429 void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
430 struct wpa_scan_res *res)
432 const u8 *ssid, *p2p;
435 ssid = wpa_scan_get_ie(res, WLAN_EID_SSID);
437 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: No SSID IE included for "
438 MACSTR, MAC2STR(res->bssid));
442 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Too long SSID IE included for "
443 MACSTR, MAC2STR(res->bssid));
447 p2p = wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE);
450 wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
452 * If it's a P2P specific interface, then don't update
453 * the scan result without a P2P IE.
455 wpa_printf(MSG_DEBUG, "BSS: No P2P IE - skipping BSS " MACSTR
456 " update for P2P interface", MAC2STR(res->bssid));
459 #endif /* CONFIG_P2P */
460 if (p2p && ssid[1] == P2P_WILDCARD_SSID_LEN &&
461 os_memcmp(ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 0)
462 return; /* Skip P2P listen discovery results here */
464 /* TODO: add option for ignoring BSSes we are not interested in
465 * (to save memory) */
466 bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
468 wpa_bss_add(wpa_s, ssid + 2, ssid[1], res);
470 wpa_bss_update(wpa_s, bss, res);
474 static int wpa_bss_included_in_scan(const struct wpa_bss *bss,
475 const struct scan_info *info)
483 if (info->num_freqs) {
485 for (i = 0; i < info->num_freqs; i++) {
486 if (bss->freq == info->freqs[i]) {
495 if (info->num_ssids) {
497 for (i = 0; i < info->num_ssids; i++) {
498 const struct wpa_driver_scan_ssid *s = &info->ssids[i];
499 if ((s->ssid == NULL || s->ssid_len == 0) ||
500 (s->ssid_len == bss->ssid_len &&
501 os_memcmp(s->ssid, bss->ssid, bss->ssid_len) ==
515 void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
518 struct wpa_bss *bss, *n;
521 return; /* do not expire entries without new scan */
523 dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
524 if (wpa_bss_in_use(wpa_s, bss))
526 if (!wpa_bss_included_in_scan(bss, info))
527 continue; /* expire only BSSes that were scanned */
528 if (bss->last_update_idx < wpa_s->bss_update_idx)
529 bss->scan_miss_count++;
530 if (bss->scan_miss_count >=
531 wpa_s->conf->bss_expiration_scan_count) {
532 wpa_bss_remove(wpa_s, bss, "no match in scan");
538 void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age)
540 struct wpa_bss *bss, *n;
543 if (dl_list_empty(&wpa_s->bss))
549 dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
550 if (wpa_bss_in_use(wpa_s, bss))
553 if (os_time_before(&bss->last_update, &t)) {
554 wpa_bss_remove(wpa_s, bss, __func__);
561 static void wpa_bss_timeout(void *eloop_ctx, void *timeout_ctx)
563 struct wpa_supplicant *wpa_s = eloop_ctx;
565 wpa_bss_flush_by_age(wpa_s, wpa_s->conf->bss_expiration_age);
566 eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0,
567 wpa_bss_timeout, wpa_s, NULL);
571 int wpa_bss_init(struct wpa_supplicant *wpa_s)
573 dl_list_init(&wpa_s->bss);
574 dl_list_init(&wpa_s->bss_id);
575 eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0,
576 wpa_bss_timeout, wpa_s, NULL);
581 void wpa_bss_flush(struct wpa_supplicant *wpa_s)
583 struct wpa_bss *bss, *n;
585 if (wpa_s->bss.next == NULL)
586 return; /* BSS table not yet initialized */
588 dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
589 if (wpa_bss_in_use(wpa_s, bss))
591 wpa_bss_remove(wpa_s, bss, __func__);
596 void wpa_bss_deinit(struct wpa_supplicant *wpa_s)
598 eloop_cancel_timeout(wpa_bss_timeout, wpa_s, NULL);
599 wpa_bss_flush(wpa_s);
603 struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
607 if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
609 dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
610 if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
618 struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s,
622 dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
624 if (p2p_parse_dev_addr((const u8 *) (bss + 1), bss->ie_len,
626 os_memcmp(addr, dev_addr, ETH_ALEN) == 0)
631 #endif /* CONFIG_P2P */
634 struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id)
637 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
645 const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
649 pos = (const u8 *) (bss + 1);
650 end = pos + bss->ie_len;
652 while (pos + 1 < end) {
653 if (pos + 2 + pos[1] > end)
664 const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
668 pos = (const u8 *) (bss + 1);
669 end = pos + bss->ie_len;
671 while (pos + 1 < end) {
672 if (pos + 2 + pos[1] > end)
674 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
675 vendor_type == WPA_GET_BE32(&pos[2]))
684 struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
690 buf = wpabuf_alloc(bss->ie_len);
694 pos = (const u8 *) (bss + 1);
695 end = pos + bss->ie_len;
697 while (pos + 1 < end) {
698 if (pos + 2 + pos[1] > end)
700 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
701 vendor_type == WPA_GET_BE32(&pos[2]))
702 wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
706 if (wpabuf_len(buf) == 0) {
715 int wpa_bss_get_max_rate(const struct wpa_bss *bss)
721 ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
722 for (i = 0; ie && i < ie[1]; i++) {
723 if ((ie[i + 2] & 0x7f) > rate)
724 rate = ie[i + 2] & 0x7f;
727 ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
728 for (i = 0; ie && i < ie[1]; i++) {
729 if ((ie[i + 2] & 0x7f) > rate)
730 rate = ie[i + 2] & 0x7f;
737 int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates)
744 ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
745 ie2 = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
747 len = (ie ? ie[1] : 0) + (ie2 ? ie2[1] : 0);
753 for (i = 0; ie && i < ie[1]; i++)
754 r[i] = ie[i + 2] & 0x7f;
756 for (j = 0; ie2 && j < ie2[1]; j++)
757 r[i + j] = ie2[j + 2] & 0x7f;