$search
00001 /* 00002 * WPA Supplicant - Scanning 00003 * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi> 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation. 00008 * 00009 * Alternatively, this software may be distributed under the terms of BSD 00010 * license. 00011 * 00012 * See README and COPYING for more details. 00013 */ 00014 00015 #include "utils/includes.h" 00016 00017 #include "utils/common.h" 00018 #include "utils/eloop.h" 00019 #include "common/ieee802_11_defs.h" 00020 #include "config.h" 00021 #include "wpa_supplicant_i.h" 00022 #include "driver_i.h" 00023 #include "mlme.h" 00024 #include "wps_supplicant.h" 00025 #include "notify.h" 00026 #include "bss.h" 00027 #include "scan.h" 00028 #include "../../src/nodes/wpa_supplicant_node.h" 00029 00030 static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s) 00031 { 00032 struct wpa_ssid *ssid; 00033 union wpa_event_data data; 00034 00035 ssid = wpa_supplicant_get_ssid(wpa_s); 00036 if (ssid == NULL) 00037 return; 00038 00039 if (wpa_s->current_ssid == NULL) { 00040 wpa_s->current_ssid = ssid; 00041 if (wpa_s->current_ssid != NULL) 00042 wpas_notify_network_changed(wpa_s); 00043 } 00044 wpa_supplicant_initiate_eapol(wpa_s); 00045 wpa_printf(MSG_DEBUG, "Already associated with a configured network - " 00046 "generating associated event"); 00047 os_memset(&data, 0, sizeof(data)); 00048 wpa_supplicant_event(wpa_s, EVENT_ASSOC, &data); 00049 } 00050 00051 00052 #ifdef CONFIG_WPS 00053 static int wpas_wps_in_use(struct wpa_config *conf, 00054 enum wps_request_type *req_type) 00055 { 00056 struct wpa_ssid *ssid; 00057 int wps = 0; 00058 00059 for (ssid = conf->ssid; ssid; ssid = ssid->next) { 00060 if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS)) 00061 continue; 00062 00063 wps = 1; 00064 *req_type = wpas_wps_get_req_type(ssid); 00065 if (!ssid->eap.phase1) 00066 continue; 00067 00068 if (os_strstr(ssid->eap.phase1, "pbc=1")) 00069 return 2; 00070 } 00071 00072 return wps; 00073 } 00074 #endif /* CONFIG_WPS */ 00075 00076 00077 int wpa_supplicant_enabled_networks(struct wpa_config *conf) 00078 { 00079 struct wpa_ssid *ssid = conf->ssid; 00080 while (ssid) { 00081 if (!ssid->disabled) 00082 return 1; 00083 ssid = ssid->next; 00084 } 00085 return 0; 00086 } 00087 00088 00089 static void wpa_supplicant_assoc_try(struct wpa_supplicant *wpa_s, 00090 struct wpa_ssid *ssid) 00091 { 00092 while (ssid) { 00093 if (!ssid->disabled) 00094 break; 00095 ssid = ssid->next; 00096 } 00097 00098 /* ap_scan=2 mode - try to associate with each SSID. */ 00099 if (ssid == NULL) { 00100 wpa_printf(MSG_DEBUG, "wpa_supplicant_scan: Reached " 00101 "end of scan list - go back to beginning"); 00102 wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN; 00103 wpa_supplicant_req_scan(wpa_s, 0, 0); 00104 return; 00105 } 00106 if (ssid->next) { 00107 /* Continue from the next SSID on the next attempt. */ 00108 wpa_s->prev_scan_ssid = ssid; 00109 } else { 00110 /* Start from the beginning of the SSID list. */ 00111 wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN; 00112 } 00113 wpa_supplicant_associate(wpa_s, NULL, ssid); 00114 } 00115 00116 00117 static int int_array_len(const int *a) 00118 { 00119 int i; 00120 for (i = 0; a && a[i]; i++) 00121 ; 00122 return i; 00123 } 00124 00125 00126 static void int_array_concat(int **res, const int *a) 00127 { 00128 int reslen, alen, i; 00129 int *n; 00130 00131 reslen = int_array_len(*res); 00132 alen = int_array_len(a); 00133 00134 n = os_realloc(*res, (reslen + alen + 1) * sizeof(int)); 00135 if (n == NULL) { 00136 os_free(*res); 00137 *res = NULL; 00138 return; 00139 } 00140 for (i = 0; i <= alen; i++) 00141 n[reslen + i] = a[i]; 00142 *res = n; 00143 } 00144 00145 00146 static int freq_cmp(const void *a, const void *b) 00147 { 00148 int _a = *(int *) a; 00149 int _b = *(int *) b; 00150 00151 if (_a == 0) 00152 return 1; 00153 if (_b == 0) 00154 return -1; 00155 return _a - _b; 00156 } 00157 00158 00159 static void int_array_sort_unique(int *a) 00160 { 00161 int alen; 00162 int i, j; 00163 00164 if (a == NULL) 00165 return; 00166 00167 alen = int_array_len(a); 00168 qsort(a, alen, sizeof(int), freq_cmp); 00169 00170 i = 0; 00171 j = 1; 00172 while (a[i] && a[j]) { 00173 if (a[i] == a[j]) { 00174 j++; 00175 continue; 00176 } 00177 a[++i] = a[j++]; 00178 } 00179 if (a[i]) 00180 i++; 00181 a[i] = 0; 00182 } 00183 00184 00185 int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s, 00186 struct wpa_driver_scan_params *params) 00187 { 00188 int ret; 00189 00190 wpa_supplicant_notify_scanning(wpa_s, 1); 00191 00192 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) 00193 ret = ieee80211_sta_req_scan(wpa_s, params); 00194 else 00195 ret = wpa_drv_scan(wpa_s, params); 00196 00197 if (ret) { 00198 wpa_supplicant_notify_scanning(wpa_s, 0); 00199 wpas_notify_scan_done(wpa_s, 0); 00200 ros_scan_completed(wpa_s, 0); 00201 } else 00202 wpa_s->scan_runs++; 00203 00204 return ret; 00205 } 00206 00207 00208 static struct wpa_driver_scan_filter * 00209 wpa_supplicant_build_filter_ssids(struct wpa_config *conf, size_t *num_ssids) 00210 { 00211 struct wpa_driver_scan_filter *ssids; 00212 struct wpa_ssid *ssid; 00213 size_t count; 00214 00215 *num_ssids = 0; 00216 if (!conf->filter_ssids) 00217 return NULL; 00218 00219 for (count = 0, ssid = conf->ssid; ssid; ssid = ssid->next) { 00220 if (ssid->ssid && ssid->ssid_len) 00221 count++; 00222 } 00223 if (count == 0) 00224 return NULL; 00225 ssids = os_zalloc(count * sizeof(struct wpa_driver_scan_filter)); 00226 if (ssids == NULL) 00227 return NULL; 00228 00229 for (ssid = conf->ssid; ssid; ssid = ssid->next) { 00230 if (!ssid->ssid || !ssid->ssid_len) 00231 continue; 00232 os_memcpy(ssids[*num_ssids].ssid, ssid->ssid, ssid->ssid_len); 00233 ssids[*num_ssids].ssid_len = ssid->ssid_len; 00234 (*num_ssids)++; 00235 } 00236 00237 return ssids; 00238 } 00239 00240 00241 static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) 00242 { 00243 struct wpa_supplicant *wpa_s = eloop_ctx; 00244 struct wpa_ssid *ssid; 00245 int scan_req = 0, ret; 00246 struct wpabuf *wps_ie = NULL; 00247 int wps = 0; 00248 #ifdef CONFIG_WPS 00249 enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO; 00250 #endif /* CONFIG_WPS */ 00251 struct wpa_driver_scan_params params; 00252 size_t max_ssids; 00253 enum wpa_states prev_state; 00254 00255 if (wpa_s->disconnected && !wpa_s->scan_req) { 00256 wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); 00257 return; 00258 } 00259 00260 if (!wpa_supplicant_enabled_networks(wpa_s->conf) && 00261 !wpa_s->scan_req) { 00262 wpa_printf(MSG_DEBUG, "No enabled networks - do not scan"); 00263 wpa_supplicant_set_state(wpa_s, WPA_INACTIVE); 00264 return; 00265 } 00266 00267 if (wpa_s->conf->ap_scan != 0 && 00268 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED)) { 00269 wpa_printf(MSG_DEBUG, "Using wired authentication - " 00270 "overriding ap_scan configuration"); 00271 wpa_s->conf->ap_scan = 0; 00272 wpas_notify_ap_scan_changed(wpa_s); 00273 } 00274 00275 if (wpa_s->conf->ap_scan == 0) { 00276 wpa_supplicant_gen_assoc_event(wpa_s); 00277 return; 00278 } 00279 00280 if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) || 00281 wpa_s->conf->ap_scan == 2) 00282 max_ssids = 1; 00283 else { 00284 max_ssids = wpa_s->max_scan_ssids; 00285 if (max_ssids > WPAS_MAX_SCAN_SSIDS) 00286 max_ssids = WPAS_MAX_SCAN_SSIDS; 00287 } 00288 00289 #ifdef CONFIG_WPS 00290 wps = wpas_wps_in_use(wpa_s->conf, &req_type); 00291 #endif /* CONFIG_WPS */ 00292 00293 if ((wpa_s->scan_res_tried == 0 && wpa_s->conf->ap_scan == 1 && 00294 !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) && 00295 wps != 2 && !wpa_s->conf->filter_ssids && 00296 !wpa_s->connect_without_scan) || 00297 wpa_s->more_bss_to_try) { 00298 wpa_s->scan_res_tried++; 00299 wpa_printf(MSG_DEBUG, "Trying to get current scan results " 00300 "first without requesting a new scan to speed up " 00301 "initial association"); 00302 wpa_supplicant_event(wpa_s, EVENT_SCAN_RESULTS, NULL); 00303 return; 00304 } 00305 00306 scan_req = wpa_s->scan_req; 00307 wpa_s->scan_req = 0; 00308 00309 os_memset(¶ms, 0, sizeof(params)); 00310 00311 prev_state = wpa_s->wpa_state; 00312 if (wpa_s->wpa_state == WPA_DISCONNECTED || 00313 wpa_s->wpa_state == WPA_INACTIVE) 00314 wpa_supplicant_set_state(wpa_s, WPA_SCANNING); 00315 00316 /* Find the starting point from which to continue scanning */ 00317 ssid = wpa_s->conf->ssid; 00318 if (wpa_s->prev_scan_ssid != WILDCARD_SSID_SCAN) { 00319 while (ssid) { 00320 if (ssid == wpa_s->prev_scan_ssid) { 00321 ssid = ssid->next; 00322 break; 00323 } 00324 ssid = ssid->next; 00325 } 00326 } 00327 00328 if (scan_req != 2 && (wpa_s->conf->ap_scan == 2 || 00329 wpa_s->connect_without_scan)) { 00330 wpa_s->connect_without_scan = 0; 00331 wpa_supplicant_assoc_try(wpa_s, ssid); 00332 return; 00333 } else if (wpa_s->conf->ap_scan == 2) { 00334 /* 00335 * User-initiated scan request in ap_scan == 2; scan with 00336 * wildcard SSID. 00337 */ 00338 ssid = NULL; 00339 } else { 00340 struct wpa_ssid *start = ssid, *tssid; 00341 int freqs_set = 0; 00342 if (ssid == NULL && max_ssids > 1) 00343 ssid = wpa_s->conf->ssid; 00344 while (ssid) { 00345 if (!ssid->disabled && ssid->scan_ssid) { 00346 wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID", 00347 ssid->ssid, ssid->ssid_len); 00348 params.ssids[params.num_ssids].ssid = 00349 ssid->ssid; 00350 params.ssids[params.num_ssids].ssid_len = 00351 ssid->ssid_len; 00352 params.num_ssids++; 00353 if (params.num_ssids + 1 >= max_ssids) 00354 break; 00355 } 00356 ssid = ssid->next; 00357 if (ssid == start) 00358 break; 00359 if (ssid == NULL && max_ssids > 1 && 00360 start != wpa_s->conf->ssid) 00361 ssid = wpa_s->conf->ssid; 00362 } 00363 00364 for (tssid = wpa_s->conf->ssid; tssid; tssid = tssid->next) { 00365 if (tssid->disabled) 00366 continue; 00367 if ((params.freqs || !freqs_set) && tssid->scan_freq) { 00368 int_array_concat(¶ms.freqs, 00369 tssid->scan_freq); 00370 } else { 00371 os_free(params.freqs); 00372 params.freqs = NULL; 00373 } 00374 freqs_set = 1; 00375 } 00376 int_array_sort_unique(params.freqs); 00377 } 00378 00379 if (ssid) { 00380 wpa_s->prev_scan_ssid = ssid; 00381 if (max_ssids > 1) { 00382 wpa_printf(MSG_DEBUG, "Include wildcard SSID in the " 00383 "scan request"); 00384 params.num_ssids++; 00385 } 00386 wpa_printf(MSG_DEBUG, "Starting AP scan for specific SSID(s)"); 00387 } else { 00388 wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN; 00389 params.num_ssids++; 00390 wpa_printf(MSG_DEBUG, "Starting AP scan for wildcard SSID"); 00391 } 00392 00393 #ifdef CONFIG_WPS 00394 if (params.freqs == NULL && wpa_s->after_wps && wpa_s->wps_freq) { 00395 /* 00396 * Optimize post-provisioning scan based on channel used 00397 * during provisioning. 00398 */ 00399 wpa_printf(MSG_DEBUG, "WPS: Scan only frequency %u MHz that " 00400 "was used during provisioning", wpa_s->wps_freq); 00401 params.freqs = os_zalloc(2 * sizeof(int)); 00402 if (params.freqs) 00403 params.freqs[0] = wpa_s->wps_freq; 00404 wpa_s->after_wps--; 00405 } 00406 00407 if (wps) { 00408 wps_ie = wps_build_probe_req_ie(wps == 2, &wpa_s->wps->dev, 00409 wpa_s->wps->uuid, req_type); 00410 if (wps_ie) { 00411 params.extra_ies = wpabuf_head(wps_ie); 00412 params.extra_ies_len = wpabuf_len(wps_ie); 00413 } 00414 } 00415 #endif /* CONFIG_WPS */ 00416 00417 params.filter_ssids = wpa_supplicant_build_filter_ssids( 00418 wpa_s->conf, ¶ms.num_filter_ssids); 00419 00420 ret = wpa_supplicant_trigger_scan(wpa_s, ¶ms); 00421 00422 wpabuf_free(wps_ie); 00423 os_free(params.freqs); 00424 os_free(params.filter_ssids); 00425 00426 if (ret) { 00427 wpa_printf(MSG_WARNING, "Failed to initiate AP scan."); 00428 if (prev_state != wpa_s->wpa_state) 00429 wpa_supplicant_set_state(wpa_s, prev_state); 00430 wpa_supplicant_req_scan(wpa_s, 1, 0); 00431 } else 00432 wpa_s->scan_runs++; 00433 } 00434 00435 00445 void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec) 00446 { 00447 /* If there's at least one network that should be specifically scanned 00448 * then don't cancel the scan and reschedule. Some drivers do 00449 * background scanning which generates frequent scan results, and that 00450 * causes the specific SSID scan to get continually pushed back and 00451 * never happen, which causes hidden APs to never get probe-scanned. 00452 */ 00453 if (eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL) && 00454 wpa_s->conf->ap_scan == 1) { 00455 struct wpa_ssid *ssid = wpa_s->conf->ssid; 00456 00457 while (ssid) { 00458 if (!ssid->disabled && ssid->scan_ssid) 00459 break; 00460 ssid = ssid->next; 00461 } 00462 if (ssid) { 00463 wpa_msg(wpa_s, MSG_DEBUG, "Not rescheduling scan to " 00464 "ensure that specific SSID scans occur"); 00465 return; 00466 } 00467 } 00468 00469 wpa_msg(wpa_s, MSG_DEBUG, "Setting scan request: %d sec %d usec", 00470 sec, usec); 00471 eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL); 00472 eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL); 00473 } 00474 00475 00483 void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s) 00484 { 00485 wpa_msg(wpa_s, MSG_DEBUG, "Cancelling scan request"); 00486 eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL); 00487 } 00488 00489 00490 void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s, 00491 int scanning) 00492 { 00493 if (wpa_s->scanning != scanning) { 00494 wpa_s->scanning = scanning; 00495 wpas_notify_scanning(wpa_s); 00496 } 00497 } 00498 00499 00500 static int wpa_scan_get_max_rate(const struct wpa_scan_res *res) 00501 { 00502 int rate = 0; 00503 const u8 *ie; 00504 int i; 00505 00506 ie = wpa_scan_get_ie(res, WLAN_EID_SUPP_RATES); 00507 for (i = 0; ie && i < ie[1]; i++) { 00508 if ((ie[i + 2] & 0x7f) > rate) 00509 rate = ie[i + 2] & 0x7f; 00510 } 00511 00512 ie = wpa_scan_get_ie(res, WLAN_EID_EXT_SUPP_RATES); 00513 for (i = 0; ie && i < ie[1]; i++) { 00514 if ((ie[i + 2] & 0x7f) > rate) 00515 rate = ie[i + 2] & 0x7f; 00516 } 00517 00518 return rate; 00519 } 00520 00521 00522 const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie) 00523 { 00524 const u8 *end, *pos; 00525 00526 pos = (const u8 *) (res + 1); 00527 end = pos + res->ie_len; 00528 00529 while (pos + 1 < end) { 00530 if (pos + 2 + pos[1] > end) 00531 break; 00532 if (pos[0] == ie) 00533 return pos; 00534 pos += 2 + pos[1]; 00535 } 00536 00537 return NULL; 00538 } 00539 00540 00541 const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res, 00542 u32 vendor_type) 00543 { 00544 const u8 *end, *pos; 00545 00546 pos = (const u8 *) (res + 1); 00547 end = pos + res->ie_len; 00548 00549 while (pos + 1 < end) { 00550 if (pos + 2 + pos[1] > end) 00551 break; 00552 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && 00553 vendor_type == WPA_GET_BE32(&pos[2])) 00554 return pos; 00555 pos += 2 + pos[1]; 00556 } 00557 00558 return NULL; 00559 } 00560 00561 00562 struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res, 00563 u32 vendor_type) 00564 { 00565 struct wpabuf *buf; 00566 const u8 *end, *pos; 00567 00568 buf = wpabuf_alloc(res->ie_len); 00569 if (buf == NULL) 00570 return NULL; 00571 00572 pos = (const u8 *) (res + 1); 00573 end = pos + res->ie_len; 00574 00575 while (pos + 1 < end) { 00576 if (pos + 2 + pos[1] > end) 00577 break; 00578 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && 00579 vendor_type == WPA_GET_BE32(&pos[2])) 00580 wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4); 00581 pos += 2 + pos[1]; 00582 } 00583 00584 if (wpabuf_len(buf) == 0) { 00585 wpabuf_free(buf); 00586 buf = NULL; 00587 } 00588 00589 return buf; 00590 } 00591 00592 00593 /* Compare function for sorting scan results. Return >0 if @b is considered 00594 * better. */ 00595 static int wpa_scan_result_compar(const void *a, const void *b) 00596 { 00597 struct wpa_scan_res **_wa = (void *) a; 00598 struct wpa_scan_res **_wb = (void *) b; 00599 struct wpa_scan_res *wa = *_wa; 00600 struct wpa_scan_res *wb = *_wb; 00601 int wpa_a, wpa_b, maxrate_a, maxrate_b; 00602 00603 /* WPA/WPA2 support preferred */ 00604 wpa_a = wpa_scan_get_vendor_ie(wa, WPA_IE_VENDOR_TYPE) != NULL || 00605 wpa_scan_get_ie(wa, WLAN_EID_RSN) != NULL; 00606 wpa_b = wpa_scan_get_vendor_ie(wb, WPA_IE_VENDOR_TYPE) != NULL || 00607 wpa_scan_get_ie(wb, WLAN_EID_RSN) != NULL; 00608 00609 if (wpa_b && !wpa_a) 00610 return 1; 00611 if (!wpa_b && wpa_a) 00612 return -1; 00613 00614 /* privacy support preferred */ 00615 if ((wa->caps & IEEE80211_CAP_PRIVACY) == 0 && 00616 (wb->caps & IEEE80211_CAP_PRIVACY)) 00617 return 1; 00618 if ((wa->caps & IEEE80211_CAP_PRIVACY) && 00619 (wb->caps & IEEE80211_CAP_PRIVACY) == 0) 00620 return -1; 00621 00622 /* best/max rate preferred if signal level close enough XXX */ 00623 if ((wa->level && wb->level && abs(wb->level - wa->level) < 5) || 00624 (wa->qual && wb->qual && abs(wb->qual - wa->qual) < 10)) { 00625 maxrate_a = wpa_scan_get_max_rate(wa); 00626 maxrate_b = wpa_scan_get_max_rate(wb); 00627 if (maxrate_a != maxrate_b) 00628 return maxrate_b - maxrate_a; 00629 } 00630 00631 /* use freq for channel preference */ 00632 00633 /* all things being equal, use signal level; if signal levels are 00634 * identical, use quality values since some drivers may only report 00635 * that value and leave the signal level zero */ 00636 if (wb->level == wa->level) 00637 return wb->qual - wa->qual; 00638 return wb->level - wa->level; 00639 } 00640 00641 00653 struct wpa_scan_results * 00654 wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s, 00655 struct scan_info *info, int new_scan) 00656 { 00657 struct wpa_scan_results *scan_res; 00658 size_t i; 00659 00660 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) 00661 scan_res = ieee80211_sta_get_scan_results(wpa_s); 00662 else 00663 scan_res = wpa_drv_get_scan_results2(wpa_s); 00664 if (scan_res == NULL) { 00665 wpa_printf(MSG_DEBUG, "Failed to get scan results"); 00666 return NULL; 00667 } 00668 00669 qsort(scan_res->res, scan_res->num, sizeof(struct wpa_scan_res *), 00670 wpa_scan_result_compar); 00671 00672 wpa_bss_update_start(wpa_s); 00673 for (i = 0; i < scan_res->num; i++) 00674 wpa_bss_update_scan_res(wpa_s, scan_res->res[i]); 00675 wpa_bss_update_end(wpa_s, info, new_scan); 00676 00677 return scan_res; 00678 } 00679 00680 00681 int wpa_supplicant_update_scan_results(struct wpa_supplicant *wpa_s) 00682 { 00683 struct wpa_scan_results *scan_res; 00684 scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0); 00685 if (scan_res == NULL) 00686 return -1; 00687 wpa_scan_results_free(scan_res); 00688 00689 return 0; 00690 } 00691 00692 00693 void wpa_scan_results_free(struct wpa_scan_results *res) 00694 { 00695 size_t i; 00696 00697 if (res == NULL) 00698 return; 00699 00700 for (i = 0; i < res->num; i++) 00701 os_free(res->res[i]); 00702 os_free(res->res); 00703 os_free(res); 00704 }