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