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 os_free(bss); 54 } 55 56 57 struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid, 58 const u8 *ssid, size_t ssid_len) 59 { 60 struct wpa_bss *bss; 61 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { 62 if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 && 63 bss->ssid_len == ssid_len && 64 os_memcmp(bss->ssid, ssid, ssid_len) == 0) 65 return bss; 66 } 67 return NULL; 68 } 69 70 71 static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src) 72 { 73 os_time_t usec; 74 75 dst->flags = src->flags; 76 os_memcpy(dst->bssid, src->bssid, ETH_ALEN); 77 dst->freq = src->freq; 78 dst->beacon_int = src->beacon_int; 79 dst->caps = src->caps; 80 dst->qual = src->qual; 81 dst->noise = src->noise; 82 dst->level = src->level; 83 dst->tsf = src->tsf; 84 85 os_get_time(&dst->last_update); 86 dst->last_update.sec -= src->age / 1000; 87 usec = (src->age % 1000) * 1000; 88 if (dst->last_update.usec < usec) { 89 dst->last_update.sec--; 90 dst->last_update.usec += 1000000; 91 } 92 dst->last_update.usec -= usec; 93 } 94 95 96 static void wpa_bss_add(struct wpa_supplicant *wpa_s, 97 const u8 *ssid, size_t ssid_len, 98 struct wpa_scan_res *res) 99 { 100 struct wpa_bss *bss; 101 102 bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len); 103 if (bss == NULL) 104 return; 105 bss->id = wpa_s->bss_next_id++; 106 bss->last_update_idx = wpa_s->bss_update_idx; 107 wpa_bss_copy_res(bss, res); 108 os_memcpy(bss->ssid, ssid, ssid_len); 109 bss->ssid_len = ssid_len; 110 bss->ie_len = res->ie_len; 111 bss->beacon_ie_len = res->beacon_ie_len; 112 os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len); 113 114 dl_list_add_tail(&wpa_s->bss, &bss->list); 115 dl_list_add_tail(&wpa_s->bss_id, &bss->list_id); 116 wpa_s->num_bss++; 117 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Add new id %u BSSID " MACSTR 118 " SSID '%s'", 119 bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len)); 120 wpas_notify_bss_added(wpa_s, bss->bssid, bss->id); 121 if (wpa_s->num_bss > wpa_s->conf->bss_max_count) { 122 /* Remove the oldest entry */ 123 wpa_bss_remove(wpa_s, dl_list_first(&wpa_s->bss, 124 struct wpa_bss, list)); 125 } 126 } 127 128 129 static int are_ies_equal(const struct wpa_bss *old, 130 const struct wpa_scan_res *new, u32 ie) 131 { 132 const u8 *old_ie, *new_ie; 133 struct wpabuf *old_ie_buff = NULL; 134 struct wpabuf *new_ie_buff = NULL; 135 int new_ie_len, old_ie_len, ret, is_multi; 136 137 switch (ie) { 138 case WPA_IE_VENDOR_TYPE: 139 old_ie = wpa_bss_get_vendor_ie(old, ie); 140 new_ie = wpa_scan_get_vendor_ie(new, ie); 141 is_multi = 0; 142 break; 143 case WPS_IE_VENDOR_TYPE: 144 old_ie_buff = wpa_bss_get_vendor_ie_multi(old, ie); 145 new_ie_buff = wpa_scan_get_vendor_ie_multi(new, ie); 146 is_multi = 1; 147 break; 148 case WLAN_EID_RSN: 149 case WLAN_EID_SUPP_RATES: 150 case WLAN_EID_EXT_SUPP_RATES: 151 old_ie = wpa_bss_get_ie(old, ie); 152 new_ie = wpa_scan_get_ie(new, ie); 153 is_multi = 0; 154 break; 155 default: 156 wpa_printf(MSG_DEBUG, "bss: %s: cannot compare IEs", __func__); 157 return 0; 158 } 159 160 if (is_multi) { 161 /* in case of multiple IEs stored in buffer */ 162 old_ie = old_ie_buff ? wpabuf_head_u8(old_ie_buff) : NULL; 163 new_ie = new_ie_buff ? wpabuf_head_u8(new_ie_buff) : NULL; 164 old_ie_len = old_ie_buff ? wpabuf_len(old_ie_buff) : 0; 165 new_ie_len = new_ie_buff ? wpabuf_len(new_ie_buff) : 0; 166 } else { 167 /* in case of single IE */ 168 old_ie_len = old_ie ? old_ie[1] + 2 : 0; 169 new_ie_len = new_ie ? new_ie[1] + 2 : 0; 170 } 171 172 if (!old_ie || !new_ie) 173 ret = !old_ie && !new_ie; 174 else 175 ret = (old_ie_len == new_ie_len && 176 os_memcmp(old_ie, new_ie, old_ie_len) == 0); 177 178 wpabuf_free(old_ie_buff); 179 wpabuf_free(new_ie_buff); 180 181 return ret; 182 } 183 184 185 static u32 wpa_bss_compare_res(const struct wpa_bss *old, 186 const struct wpa_scan_res *new) 187 { 188 u32 changes = 0; 189 int caps_diff = old->caps ^ new->caps; 190 191 if (old->freq != new->freq) 192 changes |= WPA_BSS_FREQ_CHANGED_FLAG; 193 194 if (old->level != new->level) 195 changes |= WPA_BSS_SIGNAL_CHANGED_FLAG; 196 197 if (caps_diff & IEEE80211_CAP_PRIVACY) 198 changes |= WPA_BSS_PRIVACY_CHANGED_FLAG; 199 200 if (caps_diff & IEEE80211_CAP_IBSS) 201 changes |= WPA_BSS_MODE_CHANGED_FLAG; 202 203 if (old->ie_len == new->ie_len && 204 os_memcmp(old + 1, new + 1, old->ie_len) == 0) 205 return changes; 206 changes |= WPA_BSS_IES_CHANGED_FLAG; 207 208 if (!are_ies_equal(old, new, WPA_IE_VENDOR_TYPE)) 209 changes |= WPA_BSS_WPAIE_CHANGED_FLAG; 210 211 if (!are_ies_equal(old, new, WLAN_EID_RSN)) 212 changes |= WPA_BSS_RSNIE_CHANGED_FLAG; 213 214 if (!are_ies_equal(old, new, WPS_IE_VENDOR_TYPE)) 215 changes |= WPA_BSS_WPS_CHANGED_FLAG; 216 217 if (!are_ies_equal(old, new, WLAN_EID_SUPP_RATES) || 218 !are_ies_equal(old, new, WLAN_EID_EXT_SUPP_RATES)) 219 changes |= WPA_BSS_RATES_CHANGED_FLAG; 220 221 return changes; 222 } 223 224 225 static void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes, 226 const struct wpa_bss *bss) 227 { 228 if (changes & WPA_BSS_FREQ_CHANGED_FLAG) 229 wpas_notify_bss_freq_changed(wpa_s, bss->id); 230 231 if (changes & WPA_BSS_SIGNAL_CHANGED_FLAG) 232 wpas_notify_bss_signal_changed(wpa_s, bss->id); 233 234 if (changes & WPA_BSS_PRIVACY_CHANGED_FLAG) 235 wpas_notify_bss_privacy_changed(wpa_s, bss->id); 236 237 if (changes & WPA_BSS_MODE_CHANGED_FLAG) 238 wpas_notify_bss_mode_changed(wpa_s, bss->id); 239 240 if (changes & WPA_BSS_WPAIE_CHANGED_FLAG) 241 wpas_notify_bss_wpaie_changed(wpa_s, bss->id); 242 243 if (changes & WPA_BSS_RSNIE_CHANGED_FLAG) 244 wpas_notify_bss_rsnie_changed(wpa_s, bss->id); 245 246 if (changes & WPA_BSS_WPS_CHANGED_FLAG) 247 wpas_notify_bss_wps_changed(wpa_s, bss->id); 248 249 if (changes & WPA_BSS_IES_CHANGED_FLAG) 250 wpas_notify_bss_ies_changed(wpa_s, bss->id); 251 252 if (changes & WPA_BSS_RATES_CHANGED_FLAG) 253 wpas_notify_bss_rates_changed(wpa_s, bss->id); 254 } 255 256 257 static void wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, 258 struct wpa_scan_res *res) 259 { 260 u32 changes; 261 262 changes = wpa_bss_compare_res(bss, res); 263 bss->scan_miss_count = 0; 264 bss->last_update_idx = wpa_s->bss_update_idx; 265 wpa_bss_copy_res(bss, res); 266 /* Move the entry to the end of the list */ 267 dl_list_del(&bss->list); 268 if (bss->ie_len + bss->beacon_ie_len >= 269 res->ie_len + res->beacon_ie_len) { 270 os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len); 271 bss->ie_len = res->ie_len; 272 bss->beacon_ie_len = res->beacon_ie_len; 273 } else { 274 struct wpa_bss *nbss; 275 struct dl_list *prev = bss->list_id.prev; 276 dl_list_del(&bss->list_id); 277 nbss = os_realloc(bss, sizeof(*bss) + res->ie_len + 278 res->beacon_ie_len); 279 if (nbss) { 280 bss = nbss; 281 os_memcpy(bss + 1, res + 1, 282 res->ie_len + res->beacon_ie_len); 283 bss->ie_len = res->ie_len; 284 bss->beacon_ie_len = res->beacon_ie_len; 285 } 286 dl_list_add(prev, &bss->list_id); 287 } 288 dl_list_add_tail(&wpa_s->bss, &bss->list); 289 290 notify_bss_changes(wpa_s, changes, bss); 291 } 292 293 294 static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) 295 { 296 return bss == wpa_s->current_bss || 297 os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 || 298 os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0; 299 } 300 301 302 void wpa_bss_update_start(struct wpa_supplicant *wpa_s) 303 { 304 wpa_s->bss_update_idx++; 305 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Start scan result update %u", 306 wpa_s->bss_update_idx); 307 } 308 309 310 void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s, 311 struct wpa_scan_res *res) 312 { 313 const u8 *ssid, *p2p; 314 struct wpa_bss *bss; 315 316 ssid = wpa_scan_get_ie(res, WLAN_EID_SSID); 317 if (ssid == NULL) { 318 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: No SSID IE included for " 319 MACSTR, MAC2STR(res->bssid)); 320 return; 321 } 322 if (ssid[1] > 32) { 323 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Too long SSID IE included for " 324 MACSTR, MAC2STR(res->bssid)); 325 return; 326 } 327 328 p2p = wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE); 329 if (p2p && ssid[1] == P2P_WILDCARD_SSID_LEN && 330 os_memcmp(ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 0) 331 return; /* Skip P2P listen discovery results here */ 332 333 /* TODO: add option for ignoring BSSes we are not interested in 334 * (to save memory) */ 335 bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]); 336 if (bss == NULL) 337 wpa_bss_add(wpa_s, ssid + 2, ssid[1], res); 338 else 339 wpa_bss_update(wpa_s, bss, res); 340 } 341 342 343 static int wpa_bss_included_in_scan(const struct wpa_bss *bss, 344 const struct scan_info *info) 345 { 346 int found; 347 size_t i; 348 349 if (info == NULL) 350 return 1; 351 352 if (info->num_freqs) { 353 found = 0; 354 for (i = 0; i < info->num_freqs; i++) { 355 if (bss->freq == info->freqs[i]) { 356 found = 1; 357 break; 358 } 359 } 360 if (!found) 361 return 0; 362 } 363 364 if (info->num_ssids) { 365 found = 0; 366 for (i = 0; i < info->num_ssids; i++) { 367 const struct wpa_driver_scan_ssid *s = &info->ssids[i]; 368 if ((s->ssid == NULL || s->ssid_len == 0) || 369 (s->ssid_len == bss->ssid_len && 370 os_memcmp(s->ssid, bss->ssid, bss->ssid_len) == 371 0)) { 372 found = 1; 373 break; 374 } 375 } 376 if (!found) 377 return 0; 378 } 379 380 return 1; 381 } 382 383 384 void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info, 385 int new_scan) 386 { 387 struct wpa_bss *bss, *n; 388 389 if (!new_scan) 390 return; /* do not expire entries without new scan */ 391 392 dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) { 393 if (wpa_bss_in_use(wpa_s, bss)) 394 continue; 395 if (!wpa_bss_included_in_scan(bss, info)) 396 continue; /* expire only BSSes that were scanned */ 397 if (bss->last_update_idx < wpa_s->bss_update_idx) 398 bss->scan_miss_count++; 399 if (bss->scan_miss_count >= 400 wpa_s->conf->bss_expiration_scan_count) { 401 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Expire BSS %u due to " 402 "no match in scan", bss->id); 403 wpa_bss_remove(wpa_s, bss); 404 } 405 } 406 } 407 408 409 void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age) 410 { 411 struct wpa_bss *bss, *n; 412 struct os_time t; 413 414 if (dl_list_empty(&wpa_s->bss)) 415 return; 416 417 os_get_time(&t); 418 t.sec -= age; 419 420 dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) { 421 if (wpa_bss_in_use(wpa_s, bss)) 422 continue; 423 424 if (os_time_before(&bss->last_update, &t)) { 425 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Expire BSS %u due to " 426 "age", bss->id); 427 wpa_bss_remove(wpa_s, bss); 428 } else 429 break; 430 } 431 } 432 433 434 static void wpa_bss_timeout(void *eloop_ctx, void *timeout_ctx) 435 { 436 struct wpa_supplicant *wpa_s = eloop_ctx; 437 438 wpa_bss_flush_by_age(wpa_s, wpa_s->conf->bss_expiration_age); 439 eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0, 440 wpa_bss_timeout, wpa_s, NULL); 441 } 442 443 444 int wpa_bss_init(struct wpa_supplicant *wpa_s) 445 { 446 dl_list_init(&wpa_s->bss); 447 dl_list_init(&wpa_s->bss_id); 448 eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0, 449 wpa_bss_timeout, wpa_s, NULL); 450 return 0; 451 } 452 453 454 void wpa_bss_flush(struct wpa_supplicant *wpa_s) 455 { 456 struct wpa_bss *bss, *n; 457 458 if (wpa_s->bss.next == NULL) 459 return; /* BSS table not yet initialized */ 460 461 dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) { 462 if (wpa_bss_in_use(wpa_s, bss)) 463 continue; 464 wpa_bss_remove(wpa_s, bss); 465 } 466 } 467 468 469 void wpa_bss_deinit(struct wpa_supplicant *wpa_s) 470 { 471 eloop_cancel_timeout(wpa_bss_timeout, wpa_s, NULL); 472 wpa_bss_flush(wpa_s); 473 } 474 475 476 struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s, 477 const u8 *bssid) 478 { 479 struct wpa_bss *bss; 480 dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) { 481 if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0) 482 return bss; 483 } 484 return NULL; 485 } 486 487 488 struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id) 489 { 490 struct wpa_bss *bss; 491 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { 492 if (bss->id == id) 493 return bss; 494 } 495 return NULL; 496 } 497 498 499 const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie) 500 { 501 const u8 *end, *pos; 502 503 pos = (const u8 *) (bss + 1); 504 end = pos + bss->ie_len; 505 506 while (pos + 1 < end) { 507 if (pos + 2 + pos[1] > end) 508 break; 509 if (pos[0] == ie) 510 return pos; 511 pos += 2 + pos[1]; 512 } 513 514 return NULL; 515 } 516 517 518 const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type) 519 { 520 const u8 *end, *pos; 521 522 pos = (const u8 *) (bss + 1); 523 end = pos + bss->ie_len; 524 525 while (pos + 1 < end) { 526 if (pos + 2 + pos[1] > end) 527 break; 528 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && 529 vendor_type == WPA_GET_BE32(&pos[2])) 530 return pos; 531 pos += 2 + pos[1]; 532 } 533 534 return NULL; 535 } 536 537 538 struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss, 539 u32 vendor_type) 540 { 541 struct wpabuf *buf; 542 const u8 *end, *pos; 543 544 buf = wpabuf_alloc(bss->ie_len); 545 if (buf == NULL) 546 return NULL; 547 548 pos = (const u8 *) (bss + 1); 549 end = pos + bss->ie_len; 550 551 while (pos + 1 < end) { 552 if (pos + 2 + pos[1] > end) 553 break; 554 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && 555 vendor_type == WPA_GET_BE32(&pos[2])) 556 wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4); 557 pos += 2 + pos[1]; 558 } 559 560 if (wpabuf_len(buf) == 0) { 561 wpabuf_free(buf); 562 buf = NULL; 563 } 564 565 return buf; 566 } 567 568 569 int wpa_bss_get_max_rate(const struct wpa_bss *bss) 570 { 571 int rate = 0; 572 const u8 *ie; 573 int i; 574 575 ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES); 576 for (i = 0; ie && i < ie[1]; i++) { 577 if ((ie[i + 2] & 0x7f) > rate) 578 rate = ie[i + 2] & 0x7f; 579 } 580 581 ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES); 582 for (i = 0; ie && i < ie[1]; i++) { 583 if ((ie[i + 2] & 0x7f) > rate) 584 rate = ie[i + 2] & 0x7f; 585 } 586 587 return rate; 588 } 589 590 591 int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates) 592 { 593 const u8 *ie, *ie2; 594 int i, j; 595 unsigned int len; 596 u8 *r; 597 598 ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES); 599 ie2 = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES); 600 601 len = (ie ? ie[1] : 0) + (ie2 ? ie2[1] : 0); 602 603 r = os_malloc(len); 604 if (!r) 605 return -1; 606 607 for (i = 0; ie && i < ie[1]; i++) 608 r[i] = ie[i + 2] & 0x7f; 609 610 for (j = 0; ie2 && j < ie2[1]; j++) 611 r[i + j] = ie2[j + 2] & 0x7f; 612 613 *rates = r; 614 return len; 615 } 616