scan.c revision 8d520ff1dc2da35cdca849e982051b86468016d8
1/* 2 * WPA Supplicant - Scanning 3 * Copyright (c) 2003-2010, Jouni Malinen <j@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 "config.h" 21#include "wpa_supplicant_i.h" 22#include "driver_i.h" 23#include "mlme.h" 24#include "wps_supplicant.h" 25#include "p2p_supplicant.h" 26#include "p2p/p2p.h" 27#include "notify.h" 28#include "bss.h" 29#include "scan.h" 30 31 32static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s) 33{ 34 struct wpa_ssid *ssid; 35 union wpa_event_data data; 36 37 ssid = wpa_supplicant_get_ssid(wpa_s); 38 if (ssid == NULL) 39 return; 40 41 if (wpa_s->current_ssid == NULL) { 42 wpa_s->current_ssid = ssid; 43 if (wpa_s->current_ssid != NULL) 44 wpas_notify_network_changed(wpa_s); 45 } 46 wpa_supplicant_initiate_eapol(wpa_s); 47 wpa_dbg(wpa_s, MSG_DEBUG, "Already associated with a configured " 48 "network - generating associated event"); 49 os_memset(&data, 0, sizeof(data)); 50 wpa_supplicant_event(wpa_s, EVENT_ASSOC, &data); 51} 52 53 54#ifdef CONFIG_WPS 55static int wpas_wps_in_use(struct wpa_config *conf, 56 enum wps_request_type *req_type) 57{ 58 struct wpa_ssid *ssid; 59 int wps = 0; 60 61 for (ssid = conf->ssid; ssid; ssid = ssid->next) { 62 if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS)) 63 continue; 64 65 wps = 1; 66 *req_type = wpas_wps_get_req_type(ssid); 67 if (!ssid->eap.phase1) 68 continue; 69 70 if (os_strstr(ssid->eap.phase1, "pbc=1")) 71 return 2; 72 } 73 74 return wps; 75} 76#endif /* CONFIG_WPS */ 77 78 79int wpa_supplicant_enabled_networks(struct wpa_config *conf) 80{ 81 struct wpa_ssid *ssid = conf->ssid; 82 int count = 0; 83 while (ssid) { 84 if (!ssid->disabled) 85 count++; 86 ssid = ssid->next; 87 } 88 return count; 89} 90 91 92static void wpa_supplicant_assoc_try(struct wpa_supplicant *wpa_s, 93 struct wpa_ssid *ssid) 94{ 95 while (ssid) { 96 if (!ssid->disabled) 97 break; 98 ssid = ssid->next; 99 } 100 101 /* ap_scan=2 mode - try to associate with each SSID. */ 102 if (ssid == NULL) { 103 wpa_dbg(wpa_s, MSG_DEBUG, "wpa_supplicant_assoc_try: Reached " 104 "end of scan list - go back to beginning"); 105 wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN; 106 wpa_supplicant_req_scan(wpa_s, 0, 0); 107 return; 108 } 109 if (ssid->next) { 110 /* Continue from the next SSID on the next attempt. */ 111 wpa_s->prev_scan_ssid = ssid; 112 } else { 113 /* Start from the beginning of the SSID list. */ 114 wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN; 115 } 116 wpa_supplicant_associate(wpa_s, NULL, ssid); 117} 118 119 120static int int_array_len(const int *a) 121{ 122 int i; 123 for (i = 0; a && a[i]; i++) 124 ; 125 return i; 126} 127 128 129static void int_array_concat(int **res, const int *a) 130{ 131 int reslen, alen, i; 132 int *n; 133 134 reslen = int_array_len(*res); 135 alen = int_array_len(a); 136 137 n = os_realloc(*res, (reslen + alen + 1) * sizeof(int)); 138 if (n == NULL) { 139 os_free(*res); 140 *res = NULL; 141 return; 142 } 143 for (i = 0; i <= alen; i++) 144 n[reslen + i] = a[i]; 145 *res = n; 146} 147 148 149static int freq_cmp(const void *a, const void *b) 150{ 151 int _a = *(int *) a; 152 int _b = *(int *) b; 153 154 if (_a == 0) 155 return 1; 156 if (_b == 0) 157 return -1; 158 return _a - _b; 159} 160 161 162static void int_array_sort_unique(int *a) 163{ 164 int alen; 165 int i, j; 166 167 if (a == NULL) 168 return; 169 170 alen = int_array_len(a); 171 qsort(a, alen, sizeof(int), freq_cmp); 172 173 i = 0; 174 j = 1; 175 while (a[i] && a[j]) { 176 if (a[i] == a[j]) { 177 j++; 178 continue; 179 } 180 a[++i] = a[j++]; 181 } 182 if (a[i]) 183 i++; 184 a[i] = 0; 185} 186 187 188int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s, 189 struct wpa_driver_scan_params *params) 190{ 191 int ret; 192 193 wpa_supplicant_notify_scanning(wpa_s, 1); 194 195 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) 196 ret = ieee80211_sta_req_scan(wpa_s, params); 197 else 198 ret = wpa_drv_scan(wpa_s, params); 199 200 if (ret) { 201 wpa_supplicant_notify_scanning(wpa_s, 0); 202 wpas_notify_scan_done(wpa_s, 0); 203 } else 204 wpa_s->scan_runs++; 205 206 return ret; 207} 208 209 210static struct wpa_driver_scan_filter * 211wpa_supplicant_build_filter_ssids(struct wpa_config *conf, size_t *num_ssids) 212{ 213 struct wpa_driver_scan_filter *ssids; 214 struct wpa_ssid *ssid; 215 size_t count; 216 217 *num_ssids = 0; 218 if (!conf->filter_ssids) 219 return NULL; 220 221 for (count = 0, ssid = conf->ssid; ssid; ssid = ssid->next) { 222 if (ssid->ssid && ssid->ssid_len) 223 count++; 224 } 225 if (count == 0) 226 return NULL; 227 ssids = os_zalloc(count * sizeof(struct wpa_driver_scan_filter)); 228 if (ssids == NULL) 229 return NULL; 230 231 for (ssid = conf->ssid; ssid; ssid = ssid->next) { 232 if (!ssid->ssid || !ssid->ssid_len) 233 continue; 234 os_memcpy(ssids[*num_ssids].ssid, ssid->ssid, ssid->ssid_len); 235 ssids[*num_ssids].ssid_len = ssid->ssid_len; 236 (*num_ssids)++; 237 } 238 239 return ssids; 240} 241 242 243static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) 244{ 245 struct wpa_supplicant *wpa_s = eloop_ctx; 246 struct wpa_ssid *ssid; 247 int scan_req = 0, ret; 248 struct wpabuf *wps_ie = NULL; 249#ifdef CONFIG_WPS 250 int wps = 0; 251 enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO; 252#endif /* CONFIG_WPS */ 253 struct wpa_driver_scan_params params; 254 size_t max_ssids; 255 enum wpa_states prev_state; 256 257 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { 258 wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - interface disabled"); 259 return; 260 } 261 262 if (wpa_s->disconnected && !wpa_s->scan_req) { 263 wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); 264 return; 265 } 266 267 if (!wpa_supplicant_enabled_networks(wpa_s->conf) && 268 !wpa_s->scan_req) { 269 wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks - do not scan"); 270 wpa_supplicant_set_state(wpa_s, WPA_INACTIVE); 271 return; 272 } 273 274 if (wpa_s->conf->ap_scan != 0 && 275 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED)) { 276 wpa_dbg(wpa_s, MSG_DEBUG, "Using wired authentication - " 277 "overriding ap_scan configuration"); 278 wpa_s->conf->ap_scan = 0; 279 wpas_notify_ap_scan_changed(wpa_s); 280 } 281 282 if (wpa_s->conf->ap_scan == 0) { 283 wpa_supplicant_gen_assoc_event(wpa_s); 284 return; 285 } 286 287 if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) || 288 wpa_s->conf->ap_scan == 2) 289 max_ssids = 1; 290 else { 291 max_ssids = wpa_s->max_scan_ssids; 292 if (max_ssids > WPAS_MAX_SCAN_SSIDS) 293 max_ssids = WPAS_MAX_SCAN_SSIDS; 294 } 295 296#ifdef CONFIG_WPS 297 wps = wpas_wps_in_use(wpa_s->conf, &req_type); 298#endif /* CONFIG_WPS */ 299 300 scan_req = wpa_s->scan_req; 301 wpa_s->scan_req = 0; 302 303 os_memset(¶ms, 0, sizeof(params)); 304 305 prev_state = wpa_s->wpa_state; 306 if (wpa_s->wpa_state == WPA_DISCONNECTED || 307 wpa_s->wpa_state == WPA_INACTIVE) 308 wpa_supplicant_set_state(wpa_s, WPA_SCANNING); 309 310 /* Find the starting point from which to continue scanning */ 311 ssid = wpa_s->conf->ssid; 312 if (wpa_s->prev_scan_ssid != WILDCARD_SSID_SCAN) { 313 while (ssid) { 314 if (ssid == wpa_s->prev_scan_ssid) { 315 ssid = ssid->next; 316 break; 317 } 318 ssid = ssid->next; 319 } 320 } 321 322 if (scan_req != 2 && (wpa_s->conf->ap_scan == 2 || 323 wpa_s->connect_without_scan)) { 324 wpa_s->connect_without_scan = 0; 325 wpa_supplicant_assoc_try(wpa_s, ssid); 326 return; 327 } else if (wpa_s->conf->ap_scan == 2) { 328 /* 329 * User-initiated scan request in ap_scan == 2; scan with 330 * wildcard SSID. 331 */ 332 ssid = NULL; 333 } else { 334 struct wpa_ssid *start = ssid, *tssid; 335 int freqs_set = 0; 336 if (ssid == NULL && max_ssids > 1) 337 ssid = wpa_s->conf->ssid; 338 while (ssid) { 339 if (!ssid->disabled && ssid->scan_ssid) { 340 wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID", 341 ssid->ssid, ssid->ssid_len); 342 params.ssids[params.num_ssids].ssid = 343 ssid->ssid; 344 params.ssids[params.num_ssids].ssid_len = 345 ssid->ssid_len; 346 params.num_ssids++; 347 if (params.num_ssids + 1 >= max_ssids) 348 break; 349 } 350 ssid = ssid->next; 351 if (ssid == start) 352 break; 353 if (ssid == NULL && max_ssids > 1 && 354 start != wpa_s->conf->ssid) 355 ssid = wpa_s->conf->ssid; 356 } 357 358 for (tssid = wpa_s->conf->ssid; tssid; tssid = tssid->next) { 359 if (tssid->disabled) 360 continue; 361 if ((params.freqs || !freqs_set) && tssid->scan_freq) { 362 int_array_concat(¶ms.freqs, 363 tssid->scan_freq); 364 } else { 365 os_free(params.freqs); 366 params.freqs = NULL; 367 } 368 freqs_set = 1; 369 } 370 int_array_sort_unique(params.freqs); 371 } 372 373 if (ssid) { 374 wpa_s->prev_scan_ssid = ssid; 375 if (max_ssids > 1) { 376 wpa_dbg(wpa_s, MSG_DEBUG, "Include wildcard SSID in " 377 "the scan request"); 378 params.num_ssids++; 379 } 380 wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for specific " 381 "SSID(s)"); 382 } else { 383 wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN; 384 params.num_ssids++; 385 wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for wildcard " 386 "SSID"); 387 } 388 389#ifdef CONFIG_P2P 390 wpa_s->wps->dev.p2p = 1; 391 if (!wps) { 392 wps = 1; 393 req_type = WPS_REQ_ENROLLEE_INFO; 394 } 395 396 if (params.freqs == NULL && wpa_s->p2p_in_provisioning && 397 wpa_s->go_params) { 398 /* Optimize provisioning state scan based on GO information */ 399 if (wpa_s->p2p_in_provisioning < 5 && 400 wpa_s->go_params->freq > 0) { 401 wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only GO " 402 "preferred frequency %d MHz", 403 wpa_s->go_params->freq); 404 params.freqs = os_zalloc(2 * sizeof(int)); 405 if (params.freqs) 406 params.freqs[0] = wpa_s->go_params->freq; 407 } else if (wpa_s->p2p_in_provisioning < 8 && 408 wpa_s->go_params->freq_list[0]) { 409 wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only common " 410 "channels"); 411 int_array_concat(¶ms.freqs, 412 wpa_s->go_params->freq_list); 413 if (params.freqs) 414 int_array_sort_unique(params.freqs); 415 } 416 wpa_s->p2p_in_provisioning++; 417 } 418#endif /* CONFIG_P2P */ 419 420#ifdef CONFIG_WPS 421 if (params.freqs == NULL && wpa_s->after_wps && wpa_s->wps_freq) { 422 /* 423 * Optimize post-provisioning scan based on channel used 424 * during provisioning. 425 */ 426 wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Scan only frequency %u MHz " 427 "that was used during provisioning", wpa_s->wps_freq); 428 params.freqs = os_zalloc(2 * sizeof(int)); 429 if (params.freqs) 430 params.freqs[0] = wpa_s->wps_freq; 431 wpa_s->after_wps--; 432 } 433 434 if (wps) { 435 wps_ie = wps_build_probe_req_ie(wps == 2, &wpa_s->wps->dev, 436 wpa_s->wps->uuid, req_type, 437 0, NULL); 438 if (wps_ie) { 439 params.extra_ies = wpabuf_head(wps_ie); 440 params.extra_ies_len = wpabuf_len(wps_ie); 441 } 442 } 443#endif /* CONFIG_WPS */ 444 445#ifdef CONFIG_P2P 446 if (wps_ie) { 447 if (wpabuf_resize(&wps_ie, 100) == 0) { 448 wpas_p2p_scan_ie(wpa_s, wps_ie); 449 params.extra_ies = wpabuf_head(wps_ie); 450 params.extra_ies_len = wpabuf_len(wps_ie); 451 } 452 } 453#endif /* CONFIG_P2P */ 454 455 if (params.freqs == NULL && wpa_s->next_scan_freqs) { 456 wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on previously " 457 "generated frequency list"); 458 params.freqs = wpa_s->next_scan_freqs; 459 } else 460 os_free(wpa_s->next_scan_freqs); 461 wpa_s->next_scan_freqs = NULL; 462 463 params.filter_ssids = wpa_supplicant_build_filter_ssids( 464 wpa_s->conf, ¶ms.num_filter_ssids); 465 466 ret = wpa_supplicant_trigger_scan(wpa_s, ¶ms); 467 468 wpabuf_free(wps_ie); 469 os_free(params.freqs); 470 os_free(params.filter_ssids); 471 472 if (ret) { 473 wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate AP scan"); 474 if (prev_state != wpa_s->wpa_state) 475 wpa_supplicant_set_state(wpa_s, prev_state); 476 wpa_supplicant_req_scan(wpa_s, 1, 0); 477 } 478} 479 480 481/** 482 * wpa_supplicant_req_scan - Schedule a scan for neighboring access points 483 * @wpa_s: Pointer to wpa_supplicant data 484 * @sec: Number of seconds after which to scan 485 * @usec: Number of microseconds after which to scan 486 * 487 * This function is used to schedule a scan for neighboring access points after 488 * the specified time. 489 */ 490void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec) 491{ 492 /* If there's at least one network that should be specifically scanned 493 * then don't cancel the scan and reschedule. Some drivers do 494 * background scanning which generates frequent scan results, and that 495 * causes the specific SSID scan to get continually pushed back and 496 * never happen, which causes hidden APs to never get probe-scanned. 497 */ 498 if (eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL) && 499 wpa_s->conf->ap_scan == 1) { 500 struct wpa_ssid *ssid = wpa_s->conf->ssid; 501 502 while (ssid) { 503 if (!ssid->disabled && ssid->scan_ssid) 504 break; 505 ssid = ssid->next; 506 } 507 if (ssid) { 508 wpa_dbg(wpa_s, MSG_DEBUG, "Not rescheduling scan to " 509 "ensure that specific SSID scans occur"); 510 return; 511 } 512 } 513 514 wpa_dbg(wpa_s, MSG_DEBUG, "Setting scan request: %d sec %d usec", 515 sec, usec); 516 eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL); 517 eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL); 518} 519 520 521/** 522 * wpa_supplicant_cancel_scan - Cancel a scheduled scan request 523 * @wpa_s: Pointer to wpa_supplicant data 524 * 525 * This function is used to cancel a scan request scheduled with 526 * wpa_supplicant_req_scan(). 527 */ 528void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s) 529{ 530 wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling scan request"); 531 eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL); 532} 533 534 535void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s, 536 int scanning) 537{ 538 if (wpa_s->scanning != scanning) { 539 wpa_s->scanning = scanning; 540 wpas_notify_scanning(wpa_s); 541 } 542} 543 544 545static int wpa_scan_get_max_rate(const struct wpa_scan_res *res) 546{ 547 int rate = 0; 548 const u8 *ie; 549 int i; 550 551 ie = wpa_scan_get_ie(res, WLAN_EID_SUPP_RATES); 552 for (i = 0; ie && i < ie[1]; i++) { 553 if ((ie[i + 2] & 0x7f) > rate) 554 rate = ie[i + 2] & 0x7f; 555 } 556 557 ie = wpa_scan_get_ie(res, WLAN_EID_EXT_SUPP_RATES); 558 for (i = 0; ie && i < ie[1]; i++) { 559 if ((ie[i + 2] & 0x7f) > rate) 560 rate = ie[i + 2] & 0x7f; 561 } 562 563 return rate; 564} 565 566 567const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie) 568{ 569 const u8 *end, *pos; 570 571 pos = (const u8 *) (res + 1); 572 end = pos + res->ie_len; 573 574 while (pos + 1 < end) { 575 if (pos + 2 + pos[1] > end) 576 break; 577 if (pos[0] == ie) 578 return pos; 579 pos += 2 + pos[1]; 580 } 581 582 return NULL; 583} 584 585 586const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res, 587 u32 vendor_type) 588{ 589 const u8 *end, *pos; 590 591 pos = (const u8 *) (res + 1); 592 end = pos + res->ie_len; 593 594 while (pos + 1 < end) { 595 if (pos + 2 + pos[1] > end) 596 break; 597 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && 598 vendor_type == WPA_GET_BE32(&pos[2])) 599 return pos; 600 pos += 2 + pos[1]; 601 } 602 603 return NULL; 604} 605 606 607struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res, 608 u32 vendor_type) 609{ 610 struct wpabuf *buf; 611 const u8 *end, *pos; 612 613 buf = wpabuf_alloc(res->ie_len); 614 if (buf == NULL) 615 return NULL; 616 617 pos = (const u8 *) (res + 1); 618 end = pos + res->ie_len; 619 620 while (pos + 1 < end) { 621 if (pos + 2 + pos[1] > end) 622 break; 623 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && 624 vendor_type == WPA_GET_BE32(&pos[2])) 625 wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4); 626 pos += 2 + pos[1]; 627 } 628 629 if (wpabuf_len(buf) == 0) { 630 wpabuf_free(buf); 631 buf = NULL; 632 } 633 634 return buf; 635} 636 637 638struct wpabuf * wpa_scan_get_vendor_ie_multi_beacon( 639 const struct wpa_scan_res *res, u32 vendor_type) 640{ 641 struct wpabuf *buf; 642 const u8 *end, *pos; 643 644 if (res->beacon_ie_len == 0) 645 return NULL; 646 buf = wpabuf_alloc(res->beacon_ie_len); 647 if (buf == NULL) 648 return NULL; 649 650 pos = (const u8 *) (res + 1); 651 pos += res->ie_len; 652 end = pos + res->beacon_ie_len; 653 654 while (pos + 1 < end) { 655 if (pos + 2 + pos[1] > end) 656 break; 657 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && 658 vendor_type == WPA_GET_BE32(&pos[2])) 659 wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4); 660 pos += 2 + pos[1]; 661 } 662 663 if (wpabuf_len(buf) == 0) { 664 wpabuf_free(buf); 665 buf = NULL; 666 } 667 668 return buf; 669} 670 671 672/* Compare function for sorting scan results. Return >0 if @b is considered 673 * better. */ 674static int wpa_scan_result_compar(const void *a, const void *b) 675{ 676 struct wpa_scan_res **_wa = (void *) a; 677 struct wpa_scan_res **_wb = (void *) b; 678 struct wpa_scan_res *wa = *_wa; 679 struct wpa_scan_res *wb = *_wb; 680 int wpa_a, wpa_b, maxrate_a, maxrate_b; 681 682 /* WPA/WPA2 support preferred */ 683 wpa_a = wpa_scan_get_vendor_ie(wa, WPA_IE_VENDOR_TYPE) != NULL || 684 wpa_scan_get_ie(wa, WLAN_EID_RSN) != NULL; 685 wpa_b = wpa_scan_get_vendor_ie(wb, WPA_IE_VENDOR_TYPE) != NULL || 686 wpa_scan_get_ie(wb, WLAN_EID_RSN) != NULL; 687 688 if (wpa_b && !wpa_a) 689 return 1; 690 if (!wpa_b && wpa_a) 691 return -1; 692 693 /* privacy support preferred */ 694 if ((wa->caps & IEEE80211_CAP_PRIVACY) == 0 && 695 (wb->caps & IEEE80211_CAP_PRIVACY)) 696 return 1; 697 if ((wa->caps & IEEE80211_CAP_PRIVACY) && 698 (wb->caps & IEEE80211_CAP_PRIVACY) == 0) 699 return -1; 700 701 /* best/max rate preferred if signal level close enough XXX */ 702 if ((wa->level && wb->level && abs(wb->level - wa->level) < 5) || 703 (wa->qual && wb->qual && abs(wb->qual - wa->qual) < 10)) { 704 maxrate_a = wpa_scan_get_max_rate(wa); 705 maxrate_b = wpa_scan_get_max_rate(wb); 706 if (maxrate_a != maxrate_b) 707 return maxrate_b - maxrate_a; 708 } 709 710 /* use freq for channel preference */ 711 712 /* all things being equal, use signal level; if signal levels are 713 * identical, use quality values since some drivers may only report 714 * that value and leave the signal level zero */ 715 if (wb->level == wa->level) 716 return wb->qual - wa->qual; 717 return wb->level - wa->level; 718} 719 720 721#ifdef CONFIG_WPS 722/* Compare function for sorting scan results when searching a WPS AP for 723 * provisioning. Return >0 if @b is considered better. */ 724static int wpa_scan_result_wps_compar(const void *a, const void *b) 725{ 726 struct wpa_scan_res **_wa = (void *) a; 727 struct wpa_scan_res **_wb = (void *) b; 728 struct wpa_scan_res *wa = *_wa; 729 struct wpa_scan_res *wb = *_wb; 730 int uses_wps_a, uses_wps_b; 731 struct wpabuf *wps_a, *wps_b; 732 int res; 733 734 /* Optimization - check WPS IE existence before allocated memory and 735 * doing full reassembly. */ 736 uses_wps_a = wpa_scan_get_vendor_ie(wa, WPS_IE_VENDOR_TYPE) != NULL; 737 uses_wps_b = wpa_scan_get_vendor_ie(wb, WPS_IE_VENDOR_TYPE) != NULL; 738 if (uses_wps_a && !uses_wps_b) 739 return -1; 740 if (!uses_wps_a && uses_wps_b) 741 return 1; 742 743 if (uses_wps_a && uses_wps_b) { 744 wps_a = wpa_scan_get_vendor_ie_multi(wa, WPS_IE_VENDOR_TYPE); 745 wps_b = wpa_scan_get_vendor_ie_multi(wb, WPS_IE_VENDOR_TYPE); 746 res = wps_ap_priority_compar(wps_a, wps_b); 747 wpabuf_free(wps_a); 748 wpabuf_free(wps_b); 749 if (res) 750 return res; 751 } 752 753 /* 754 * Do not use current AP security policy as a sorting criteria during 755 * WPS provisioning step since the AP may get reconfigured at the 756 * completion of provisioning. 757 */ 758 759 /* all things being equal, use signal level; if signal levels are 760 * identical, use quality values since some drivers may only report 761 * that value and leave the signal level zero */ 762 if (wb->level == wa->level) 763 return wb->qual - wa->qual; 764 return wb->level - wa->level; 765} 766#endif /* CONFIG_WPS */ 767 768 769/** 770 * wpa_supplicant_get_scan_results - Get scan results 771 * @wpa_s: Pointer to wpa_supplicant data 772 * @info: Information about what was scanned or %NULL if not available 773 * @new_scan: Whether a new scan was performed 774 * Returns: Scan results, %NULL on failure 775 * 776 * This function request the current scan results from the driver and updates 777 * the local BSS list wpa_s->bss. The caller is responsible for freeing the 778 * results with wpa_scan_results_free(). 779 */ 780struct wpa_scan_results * 781wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s, 782 struct scan_info *info, int new_scan) 783{ 784 struct wpa_scan_results *scan_res; 785 size_t i; 786 int (*compar)(const void *, const void *) = wpa_scan_result_compar; 787 788 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) 789 scan_res = ieee80211_sta_get_scan_results(wpa_s); 790 else 791 scan_res = wpa_drv_get_scan_results2(wpa_s); 792 if (scan_res == NULL) { 793 wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results"); 794 return NULL; 795 } 796 797#ifdef CONFIG_WPS 798 if (wpas_wps_in_progress(wpa_s)) { 799 wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Order scan results with WPS " 800 "provisioning rules"); 801 compar = wpa_scan_result_wps_compar; 802 } 803#endif /* CONFIG_WPS */ 804 805 qsort(scan_res->res, scan_res->num, sizeof(struct wpa_scan_res *), 806 compar); 807 808 wpa_bss_update_start(wpa_s); 809 for (i = 0; i < scan_res->num; i++) 810 wpa_bss_update_scan_res(wpa_s, scan_res->res[i]); 811 wpa_bss_update_end(wpa_s, info, new_scan); 812 813 return scan_res; 814} 815 816 817int wpa_supplicant_update_scan_results(struct wpa_supplicant *wpa_s) 818{ 819 struct wpa_scan_results *scan_res; 820 scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0); 821 if (scan_res == NULL) 822 return -1; 823 wpa_scan_results_free(scan_res); 824 825 return 0; 826} 827 828 829void wpa_scan_results_free(struct wpa_scan_results *res) 830{ 831 size_t i; 832 833 if (res == NULL) 834 return; 835 836 for (i = 0; i < res->num; i++) 837 os_free(res->res[i]); 838 os_free(res->res); 839 os_free(res); 840} 841