Home | History | Annotate | Line # | Download | only in wpa_supplicant
bss.c revision 1.1.1.1.6.1
      1 /*
      2  * BSS table
      3  * Copyright (c) 2009-2010, Jouni Malinen <j (at) w1.fi>
      4  *
      5  * This program is free software; you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License version 2 as
      7  * published by the Free Software Foundation.
      8  *
      9  * Alternatively, this software may be distributed under the terms of BSD
     10  * license.
     11  *
     12  * See README and COPYING for more details.
     13  */
     14 
     15 #include "utils/includes.h"
     16 
     17 #include "utils/common.h"
     18 #include "utils/eloop.h"
     19 #include "common/ieee802_11_defs.h"
     20 #include "drivers/driver.h"
     21 #include "wpa_supplicant_i.h"
     22 #include "config.h"
     23 #include "notify.h"
     24 #include "scan.h"
     25 #include "bss.h"
     26 
     27 
     28 /**
     29  * WPA_BSS_EXPIRATION_PERIOD - Period of expiration run in seconds
     30  */
     31 #define WPA_BSS_EXPIRATION_PERIOD 10
     32 
     33 #define WPA_BSS_FREQ_CHANGED_FLAG	BIT(0)
     34 #define WPA_BSS_SIGNAL_CHANGED_FLAG	BIT(1)
     35 #define WPA_BSS_PRIVACY_CHANGED_FLAG	BIT(2)
     36 #define WPA_BSS_MODE_CHANGED_FLAG	BIT(3)
     37 #define WPA_BSS_WPAIE_CHANGED_FLAG	BIT(4)
     38 #define WPA_BSS_RSNIE_CHANGED_FLAG	BIT(5)
     39 #define WPA_BSS_WPS_CHANGED_FLAG	BIT(6)
     40 #define WPA_BSS_RATES_CHANGED_FLAG	BIT(7)
     41 #define WPA_BSS_IES_CHANGED_FLAG	BIT(8)
     42 
     43 
     44 static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
     45 {
     46 	dl_list_del(&bss->list);
     47 	dl_list_del(&bss->list_id);
     48 	wpa_s->num_bss--;
     49 	wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Remove id %u BSSID " MACSTR
     50 		" SSID '%s'", bss->id, MAC2STR(bss->bssid),
     51 		wpa_ssid_txt(bss->ssid, bss->ssid_len));
     52 	wpas_notify_bss_removed(wpa_s, bss->bssid, bss->id);
     53 #ifdef CONFIG_INTERWORKING
     54 	wpabuf_free(bss->anqp_venue_name);
     55 	wpabuf_free(bss->anqp_network_auth_type);
     56 	wpabuf_free(bss->anqp_roaming_consortium);
     57 	wpabuf_free(bss->anqp_ip_addr_type_availability);
     58 	wpabuf_free(bss->anqp_nai_realm);
     59 	wpabuf_free(bss->anqp_3gpp);
     60 	wpabuf_free(bss->anqp_domain_name);
     61 #endif /* CONFIG_INTERWORKING */
     62 	os_free(bss);
     63 }
     64 
     65 
     66 struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
     67 			     const u8 *ssid, size_t ssid_len)
     68 {
     69 	struct wpa_bss *bss;
     70 	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
     71 		if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
     72 		    bss->ssid_len == ssid_len &&
     73 		    os_memcmp(bss->ssid, ssid, ssid_len) == 0)
     74 			return bss;
     75 	}
     76 	return NULL;
     77 }
     78 
     79 
     80 static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src)
     81 {
     82 	os_time_t usec;
     83 
     84 	dst->flags = src->flags;
     85 	os_memcpy(dst->bssid, src->bssid, ETH_ALEN);
     86 	dst->freq = src->freq;
     87 	dst->beacon_int = src->beacon_int;
     88 	dst->caps = src->caps;
     89 	dst->qual = src->qual;
     90 	dst->noise = src->noise;
     91 	dst->level = src->level;
     92 	dst->tsf = src->tsf;
     93 
     94 	os_get_time(&dst->last_update);
     95 	dst->last_update.sec -= src->age / 1000;
     96 	usec = (src->age % 1000) * 1000;
     97 	if (dst->last_update.usec < usec) {
     98 		dst->last_update.sec--;
     99 		dst->last_update.usec += 1000000;
    100 	}
    101 	dst->last_update.usec -= usec;
    102 }
    103 
    104 
    105 static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
    106 {
    107 	struct wpa_ssid *ssid;
    108 
    109 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
    110 		if (ssid->ssid == NULL || ssid->ssid_len == 0)
    111 			continue;
    112 		if (ssid->ssid_len == bss->ssid_len &&
    113 		    os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) == 0)
    114 			return 1;
    115 	}
    116 
    117 	return 0;
    118 }
    119 
    120 
    121 static int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s)
    122 {
    123 	struct wpa_bss *bss;
    124 
    125 	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
    126 		if (!wpa_bss_known(wpa_s, bss)) {
    127 			wpa_bss_remove(wpa_s, bss);
    128 			return 0;
    129 		}
    130 	}
    131 
    132 	return -1;
    133 }
    134 
    135 
    136 static void wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s)
    137 {
    138 	/*
    139 	 * Remove the oldest entry that does not match with any configured
    140 	 * network.
    141 	 */
    142 	if (wpa_bss_remove_oldest_unknown(wpa_s) == 0)
    143 		return;
    144 
    145 	/*
    146 	 * Remove the oldest entry since no better candidate for removal was
    147 	 * found.
    148 	 */
    149 	wpa_bss_remove(wpa_s, dl_list_first(&wpa_s->bss,
    150 					    struct wpa_bss, list));
    151 }
    152 
    153 
    154 static void wpa_bss_add(struct wpa_supplicant *wpa_s,
    155 			const u8 *ssid, size_t ssid_len,
    156 			struct wpa_scan_res *res)
    157 {
    158 	struct wpa_bss *bss;
    159 
    160 	bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len);
    161 	if (bss == NULL)
    162 		return;
    163 	bss->id = wpa_s->bss_next_id++;
    164 	bss->last_update_idx = wpa_s->bss_update_idx;
    165 	wpa_bss_copy_res(bss, res);
    166 	os_memcpy(bss->ssid, ssid, ssid_len);
    167 	bss->ssid_len = ssid_len;
    168 	bss->ie_len = res->ie_len;
    169 	bss->beacon_ie_len = res->beacon_ie_len;
    170 	os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
    171 
    172 	dl_list_add_tail(&wpa_s->bss, &bss->list);
    173 	dl_list_add_tail(&wpa_s->bss_id, &bss->list_id);
    174 	wpa_s->num_bss++;
    175 	wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Add new id %u BSSID " MACSTR
    176 		" SSID '%s'",
    177 		bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len));
    178 	wpas_notify_bss_added(wpa_s, bss->bssid, bss->id);
    179 	if (wpa_s->num_bss > wpa_s->conf->bss_max_count)
    180 		wpa_bss_remove_oldest(wpa_s);
    181 }
    182 
    183 
    184 static int are_ies_equal(const struct wpa_bss *old,
    185 			 const struct wpa_scan_res *new, u32 ie)
    186 {
    187 	const u8 *old_ie, *new_ie;
    188 	struct wpabuf *old_ie_buff = NULL;
    189 	struct wpabuf *new_ie_buff = NULL;
    190 	int new_ie_len, old_ie_len, ret, is_multi;
    191 
    192 	switch (ie) {
    193 	case WPA_IE_VENDOR_TYPE:
    194 		old_ie = wpa_bss_get_vendor_ie(old, ie);
    195 		new_ie = wpa_scan_get_vendor_ie(new, ie);
    196 		is_multi = 0;
    197 		break;
    198 	case WPS_IE_VENDOR_TYPE:
    199 		old_ie_buff = wpa_bss_get_vendor_ie_multi(old, ie);
    200 		new_ie_buff = wpa_scan_get_vendor_ie_multi(new, ie);
    201 		is_multi = 1;
    202 		break;
    203 	case WLAN_EID_RSN:
    204 	case WLAN_EID_SUPP_RATES:
    205 	case WLAN_EID_EXT_SUPP_RATES:
    206 		old_ie = wpa_bss_get_ie(old, ie);
    207 		new_ie = wpa_scan_get_ie(new, ie);
    208 		is_multi = 0;
    209 		break;
    210 	default:
    211 		wpa_printf(MSG_DEBUG, "bss: %s: cannot compare IEs", __func__);
    212 		return 0;
    213 	}
    214 
    215 	if (is_multi) {
    216 		/* in case of multiple IEs stored in buffer */
    217 		old_ie = old_ie_buff ? wpabuf_head_u8(old_ie_buff) : NULL;
    218 		new_ie = new_ie_buff ? wpabuf_head_u8(new_ie_buff) : NULL;
    219 		old_ie_len = old_ie_buff ? wpabuf_len(old_ie_buff) : 0;
    220 		new_ie_len = new_ie_buff ? wpabuf_len(new_ie_buff) : 0;
    221 	} else {
    222 		/* in case of single IE */
    223 		old_ie_len = old_ie ? old_ie[1] + 2 : 0;
    224 		new_ie_len = new_ie ? new_ie[1] + 2 : 0;
    225 	}
    226 
    227 	if (!old_ie || !new_ie)
    228 		ret = !old_ie && !new_ie;
    229 	else
    230 		ret = (old_ie_len == new_ie_len &&
    231 		       os_memcmp(old_ie, new_ie, old_ie_len) == 0);
    232 
    233 	wpabuf_free(old_ie_buff);
    234 	wpabuf_free(new_ie_buff);
    235 
    236 	return ret;
    237 }
    238 
    239 
    240 static u32 wpa_bss_compare_res(const struct wpa_bss *old,
    241 			       const struct wpa_scan_res *new)
    242 {
    243 	u32 changes = 0;
    244 	int caps_diff = old->caps ^ new->caps;
    245 
    246 	if (old->freq != new->freq)
    247 		changes |= WPA_BSS_FREQ_CHANGED_FLAG;
    248 
    249 	if (old->level != new->level)
    250 		changes |= WPA_BSS_SIGNAL_CHANGED_FLAG;
    251 
    252 	if (caps_diff & IEEE80211_CAP_PRIVACY)
    253 		changes |= WPA_BSS_PRIVACY_CHANGED_FLAG;
    254 
    255 	if (caps_diff & IEEE80211_CAP_IBSS)
    256 		changes |= WPA_BSS_MODE_CHANGED_FLAG;
    257 
    258 	if (old->ie_len == new->ie_len &&
    259 	    os_memcmp(old + 1, new + 1, old->ie_len) == 0)
    260 		return changes;
    261 	changes |= WPA_BSS_IES_CHANGED_FLAG;
    262 
    263 	if (!are_ies_equal(old, new, WPA_IE_VENDOR_TYPE))
    264 		changes |= WPA_BSS_WPAIE_CHANGED_FLAG;
    265 
    266 	if (!are_ies_equal(old, new, WLAN_EID_RSN))
    267 		changes |= WPA_BSS_RSNIE_CHANGED_FLAG;
    268 
    269 	if (!are_ies_equal(old, new, WPS_IE_VENDOR_TYPE))
    270 		changes |= WPA_BSS_WPS_CHANGED_FLAG;
    271 
    272 	if (!are_ies_equal(old, new, WLAN_EID_SUPP_RATES) ||
    273 	    !are_ies_equal(old, new, WLAN_EID_EXT_SUPP_RATES))
    274 		changes |= WPA_BSS_RATES_CHANGED_FLAG;
    275 
    276 	return changes;
    277 }
    278 
    279 
    280 static void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
    281 			       const struct wpa_bss *bss)
    282 {
    283 	if (changes & WPA_BSS_FREQ_CHANGED_FLAG)
    284 		wpas_notify_bss_freq_changed(wpa_s, bss->id);
    285 
    286 	if (changes & WPA_BSS_SIGNAL_CHANGED_FLAG)
    287 		wpas_notify_bss_signal_changed(wpa_s, bss->id);
    288 
    289 	if (changes & WPA_BSS_PRIVACY_CHANGED_FLAG)
    290 		wpas_notify_bss_privacy_changed(wpa_s, bss->id);
    291 
    292 	if (changes & WPA_BSS_MODE_CHANGED_FLAG)
    293 		wpas_notify_bss_mode_changed(wpa_s, bss->id);
    294 
    295 	if (changes & WPA_BSS_WPAIE_CHANGED_FLAG)
    296 		wpas_notify_bss_wpaie_changed(wpa_s, bss->id);
    297 
    298 	if (changes & WPA_BSS_RSNIE_CHANGED_FLAG)
    299 		wpas_notify_bss_rsnie_changed(wpa_s, bss->id);
    300 
    301 	if (changes & WPA_BSS_WPS_CHANGED_FLAG)
    302 		wpas_notify_bss_wps_changed(wpa_s, bss->id);
    303 
    304 	if (changes & WPA_BSS_IES_CHANGED_FLAG)
    305 		wpas_notify_bss_ies_changed(wpa_s, bss->id);
    306 
    307 	if (changes & WPA_BSS_RATES_CHANGED_FLAG)
    308 		wpas_notify_bss_rates_changed(wpa_s, bss->id);
    309 }
    310 
    311 
    312 static void wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
    313 			   struct wpa_scan_res *res)
    314 {
    315 	u32 changes;
    316 
    317 	changes = wpa_bss_compare_res(bss, res);
    318 	bss->scan_miss_count = 0;
    319 	bss->last_update_idx = wpa_s->bss_update_idx;
    320 	wpa_bss_copy_res(bss, res);
    321 	/* Move the entry to the end of the list */
    322 	dl_list_del(&bss->list);
    323 	if (bss->ie_len + bss->beacon_ie_len >=
    324 	    res->ie_len + res->beacon_ie_len) {
    325 		os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
    326 		bss->ie_len = res->ie_len;
    327 		bss->beacon_ie_len = res->beacon_ie_len;
    328 	} else {
    329 		struct wpa_bss *nbss;
    330 		struct dl_list *prev = bss->list_id.prev;
    331 		dl_list_del(&bss->list_id);
    332 		nbss = os_realloc(bss, sizeof(*bss) + res->ie_len +
    333 				  res->beacon_ie_len);
    334 		if (nbss) {
    335 			if (wpa_s->current_bss == bss)
    336 				wpa_s->current_bss = nbss;
    337 			bss = nbss;
    338 			os_memcpy(bss + 1, res + 1,
    339 				  res->ie_len + res->beacon_ie_len);
    340 			bss->ie_len = res->ie_len;
    341 			bss->beacon_ie_len = res->beacon_ie_len;
    342 		}
    343 		dl_list_add(prev, &bss->list_id);
    344 	}
    345 	dl_list_add_tail(&wpa_s->bss, &bss->list);
    346 
    347 	notify_bss_changes(wpa_s, changes, bss);
    348 }
    349 
    350 
    351 static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
    352 {
    353 	return bss == wpa_s->current_bss ||
    354 		os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 ||
    355 		os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0;
    356 }
    357 
    358 
    359 void wpa_bss_update_start(struct wpa_supplicant *wpa_s)
    360 {
    361 	wpa_s->bss_update_idx++;
    362 	wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Start scan result update %u",
    363 		wpa_s->bss_update_idx);
    364 }
    365 
    366 
    367 void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
    368 			     struct wpa_scan_res *res)
    369 {
    370 	const u8 *ssid, *p2p;
    371 	struct wpa_bss *bss;
    372 
    373 	ssid = wpa_scan_get_ie(res, WLAN_EID_SSID);
    374 	if (ssid == NULL) {
    375 		wpa_dbg(wpa_s, MSG_DEBUG, "BSS: No SSID IE included for "
    376 			MACSTR, MAC2STR(res->bssid));
    377 		return;
    378 	}
    379 	if (ssid[1] > 32) {
    380 		wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Too long SSID IE included for "
    381 			MACSTR, MAC2STR(res->bssid));
    382 		return;
    383 	}
    384 
    385 	p2p = wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE);
    386 	if (p2p && ssid[1] == P2P_WILDCARD_SSID_LEN &&
    387 	    os_memcmp(ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 0)
    388 		return; /* Skip P2P listen discovery results here */
    389 
    390 	/* TODO: add option for ignoring BSSes we are not interested in
    391 	 * (to save memory) */
    392 	bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
    393 	if (bss == NULL)
    394 		wpa_bss_add(wpa_s, ssid + 2, ssid[1], res);
    395 	else
    396 		wpa_bss_update(wpa_s, bss, res);
    397 }
    398 
    399 
    400 static int wpa_bss_included_in_scan(const struct wpa_bss *bss,
    401 				    const struct scan_info *info)
    402 {
    403 	int found;
    404 	size_t i;
    405 
    406 	if (info == NULL)
    407 		return 1;
    408 
    409 	if (info->num_freqs) {
    410 		found = 0;
    411 		for (i = 0; i < info->num_freqs; i++) {
    412 			if (bss->freq == info->freqs[i]) {
    413 				found = 1;
    414 				break;
    415 			}
    416 		}
    417 		if (!found)
    418 			return 0;
    419 	}
    420 
    421 	if (info->num_ssids) {
    422 		found = 0;
    423 		for (i = 0; i < info->num_ssids; i++) {
    424 			const struct wpa_driver_scan_ssid *s = &info->ssids[i];
    425 			if ((s->ssid == NULL || s->ssid_len == 0) ||
    426 			    (s->ssid_len == bss->ssid_len &&
    427 			     os_memcmp(s->ssid, bss->ssid, bss->ssid_len) ==
    428 			     0)) {
    429 				found = 1;
    430 				break;
    431 			}
    432 		}
    433 		if (!found)
    434 			return 0;
    435 	}
    436 
    437 	return 1;
    438 }
    439 
    440 
    441 void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
    442 			int new_scan)
    443 {
    444 	struct wpa_bss *bss, *n;
    445 
    446 	if (!new_scan)
    447 		return; /* do not expire entries without new scan */
    448 
    449 	dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
    450 		if (wpa_bss_in_use(wpa_s, bss))
    451 			continue;
    452 		if (!wpa_bss_included_in_scan(bss, info))
    453 			continue; /* expire only BSSes that were scanned */
    454 		if (bss->last_update_idx < wpa_s->bss_update_idx)
    455 			bss->scan_miss_count++;
    456 		if (bss->scan_miss_count >=
    457 		    wpa_s->conf->bss_expiration_scan_count) {
    458 			wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Expire BSS %u due to "
    459 				"no match in scan", bss->id);
    460 			wpa_bss_remove(wpa_s, bss);
    461 		}
    462 	}
    463 }
    464 
    465 
    466 void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age)
    467 {
    468 	struct wpa_bss *bss, *n;
    469 	struct os_time t;
    470 
    471 	if (dl_list_empty(&wpa_s->bss))
    472 		return;
    473 
    474 	os_get_time(&t);
    475 	t.sec -= age;
    476 
    477 	dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
    478 		if (wpa_bss_in_use(wpa_s, bss))
    479 			continue;
    480 
    481 		if (os_time_before(&bss->last_update, &t)) {
    482 			wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Expire BSS %u due to "
    483 				"age", bss->id);
    484 			wpa_bss_remove(wpa_s, bss);
    485 		} else
    486 			break;
    487 	}
    488 }
    489 
    490 
    491 static void wpa_bss_timeout(void *eloop_ctx, void *timeout_ctx)
    492 {
    493 	struct wpa_supplicant *wpa_s = eloop_ctx;
    494 
    495 	wpa_bss_flush_by_age(wpa_s, wpa_s->conf->bss_expiration_age);
    496 	eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0,
    497 			       wpa_bss_timeout, wpa_s, NULL);
    498 }
    499 
    500 
    501 int wpa_bss_init(struct wpa_supplicant *wpa_s)
    502 {
    503 	dl_list_init(&wpa_s->bss);
    504 	dl_list_init(&wpa_s->bss_id);
    505 	eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0,
    506 			       wpa_bss_timeout, wpa_s, NULL);
    507 	return 0;
    508 }
    509 
    510 
    511 void wpa_bss_flush(struct wpa_supplicant *wpa_s)
    512 {
    513 	struct wpa_bss *bss, *n;
    514 
    515 	if (wpa_s->bss.next == NULL)
    516 		return; /* BSS table not yet initialized */
    517 
    518 	dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
    519 		if (wpa_bss_in_use(wpa_s, bss))
    520 			continue;
    521 		wpa_bss_remove(wpa_s, bss);
    522 	}
    523 }
    524 
    525 
    526 void wpa_bss_deinit(struct wpa_supplicant *wpa_s)
    527 {
    528 	eloop_cancel_timeout(wpa_bss_timeout, wpa_s, NULL);
    529 	wpa_bss_flush(wpa_s);
    530 }
    531 
    532 
    533 struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
    534 				   const u8 *bssid)
    535 {
    536 	struct wpa_bss *bss;
    537 	dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
    538 		if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
    539 			return bss;
    540 	}
    541 	return NULL;
    542 }
    543 
    544 
    545 #ifdef CONFIG_P2P
    546 struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s,
    547 					  const u8 *dev_addr)
    548 {
    549 	struct wpa_bss *bss;
    550 	dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
    551 		u8 addr[ETH_ALEN];
    552 		if (p2p_parse_dev_addr((const u8 *) (bss + 1), bss->ie_len,
    553 				       addr) == 0 &&
    554 		    os_memcmp(addr, dev_addr, ETH_ALEN) == 0)
    555 			return bss;
    556 	}
    557 	return NULL;
    558 }
    559 #endif /* CONFIG_P2P */
    560 
    561 
    562 struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id)
    563 {
    564 	struct wpa_bss *bss;
    565 	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
    566 		if (bss->id == id)
    567 			return bss;
    568 	}
    569 	return NULL;
    570 }
    571 
    572 
    573 const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
    574 {
    575 	const u8 *end, *pos;
    576 
    577 	pos = (const u8 *) (bss + 1);
    578 	end = pos + bss->ie_len;
    579 
    580 	while (pos + 1 < end) {
    581 		if (pos + 2 + pos[1] > end)
    582 			break;
    583 		if (pos[0] == ie)
    584 			return pos;
    585 		pos += 2 + pos[1];
    586 	}
    587 
    588 	return NULL;
    589 }
    590 
    591 
    592 const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
    593 {
    594 	const u8 *end, *pos;
    595 
    596 	pos = (const u8 *) (bss + 1);
    597 	end = pos + bss->ie_len;
    598 
    599 	while (pos + 1 < end) {
    600 		if (pos + 2 + pos[1] > end)
    601 			break;
    602 		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
    603 		    vendor_type == WPA_GET_BE32(&pos[2]))
    604 			return pos;
    605 		pos += 2 + pos[1];
    606 	}
    607 
    608 	return NULL;
    609 }
    610 
    611 
    612 struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
    613 					    u32 vendor_type)
    614 {
    615 	struct wpabuf *buf;
    616 	const u8 *end, *pos;
    617 
    618 	buf = wpabuf_alloc(bss->ie_len);
    619 	if (buf == NULL)
    620 		return NULL;
    621 
    622 	pos = (const u8 *) (bss + 1);
    623 	end = pos + bss->ie_len;
    624 
    625 	while (pos + 1 < end) {
    626 		if (pos + 2 + pos[1] > end)
    627 			break;
    628 		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
    629 		    vendor_type == WPA_GET_BE32(&pos[2]))
    630 			wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
    631 		pos += 2 + pos[1];
    632 	}
    633 
    634 	if (wpabuf_len(buf) == 0) {
    635 		wpabuf_free(buf);
    636 		buf = NULL;
    637 	}
    638 
    639 	return buf;
    640 }
    641 
    642 
    643 int wpa_bss_get_max_rate(const struct wpa_bss *bss)
    644 {
    645 	int rate = 0;
    646 	const u8 *ie;
    647 	int i;
    648 
    649 	ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
    650 	for (i = 0; ie && i < ie[1]; i++) {
    651 		if ((ie[i + 2] & 0x7f) > rate)
    652 			rate = ie[i + 2] & 0x7f;
    653 	}
    654 
    655 	ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
    656 	for (i = 0; ie && i < ie[1]; i++) {
    657 		if ((ie[i + 2] & 0x7f) > rate)
    658 			rate = ie[i + 2] & 0x7f;
    659 	}
    660 
    661 	return rate;
    662 }
    663 
    664 
    665 int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates)
    666 {
    667 	const u8 *ie, *ie2;
    668 	int i, j;
    669 	unsigned int len;
    670 	u8 *r;
    671 
    672 	ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
    673 	ie2 = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
    674 
    675 	len = (ie ? ie[1] : 0) + (ie2 ? ie2[1] : 0);
    676 
    677 	r = os_malloc(len);
    678 	if (!r)
    679 		return -1;
    680 
    681 	for (i = 0; ie && i < ie[1]; i++)
    682 		r[i] = ie[i + 2] & 0x7f;
    683 
    684 	for (j = 0; ie2 && j < ie2[1]; j++)
    685 		r[i + j] = ie2[j + 2] & 0x7f;
    686 
    687 	*rates = r;
    688 	return len;
    689 }
    690