$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 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 } else 00201 wpa_s->scan_runs++; 00202 00203 return ret; 00204 } 00205 00206 00207 static struct wpa_driver_scan_filter * 00208 wpa_supplicant_build_filter_ssids(struct wpa_config *conf, size_t *num_ssids) 00209 { 00210 struct wpa_driver_scan_filter *ssids; 00211 struct wpa_ssid *ssid; 00212 size_t count; 00213 00214 *num_ssids = 0; 00215 if (!conf->filter_ssids) 00216 return NULL; 00217 00218 for (count = 0, ssid = conf->ssid; ssid; ssid = ssid->next) { 00219 if (ssid->ssid && ssid->ssid_len) 00220 count++; 00221 } 00222 if (count == 0) 00223 return NULL; 00224 ssids = os_zalloc(count * sizeof(struct wpa_driver_scan_filter)); 00225 if (ssids == NULL) 00226 return NULL; 00227 00228 for (ssid = conf->ssid; ssid; ssid = ssid->next) { 00229 if (!ssid->ssid || !ssid->ssid_len) 00230 continue; 00231 os_memcpy(ssids[*num_ssids].ssid, ssid->ssid, ssid->ssid_len); 00232 ssids[*num_ssids].ssid_len = ssid->ssid_len; 00233 (*num_ssids)++; 00234 } 00235 00236 return ssids; 00237 } 00238 00239 00240 static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) 00241 { 00242 struct wpa_supplicant *wpa_s = eloop_ctx; 00243 struct wpa_ssid *ssid; 00244 int scan_req = 0, ret; 00245 struct wpabuf *wps_ie = NULL; 00246 int wps = 0; 00247 #ifdef CONFIG_WPS 00248 enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO; 00249 #endif /* CONFIG_WPS */ 00250 struct wpa_driver_scan_params params; 00251 size_t max_ssids; 00252 enum wpa_states prev_state; 00253 00254 if (wpa_s->disconnected && !wpa_s->scan_req) { 00255 wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); 00256 return; 00257 } 00258 00259 if (!wpa_supplicant_enabled_networks(wpa_s->conf) && 00260 !wpa_s->scan_req) { 00261 wpa_printf(MSG_DEBUG, "No enabled networks - do not scan"); 00262 wpa_supplicant_set_state(wpa_s, WPA_INACTIVE); 00263 return; 00264 } 00265 00266 if (wpa_s->conf->ap_scan != 0 && 00267 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED)) { 00268 wpa_printf(MSG_DEBUG, "Using wired authentication - " 00269 "overriding ap_scan configuration"); 00270 wpa_s->conf->ap_scan = 0; 00271 wpas_notify_ap_scan_changed(wpa_s); 00272 } 00273 00274 if (wpa_s->conf->ap_scan == 0) { 00275 wpa_supplicant_gen_assoc_event(wpa_s); 00276 return; 00277 } 00278 00279 if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) || 00280 wpa_s->conf->ap_scan == 2) 00281 max_ssids = 1; 00282 else { 00283 max_ssids = wpa_s->max_scan_ssids; 00284 if (max_ssids > WPAS_MAX_SCAN_SSIDS) 00285 max_ssids = WPAS_MAX_SCAN_SSIDS; 00286 } 00287 00288 #ifdef CONFIG_WPS 00289 wps = wpas_wps_in_use(wpa_s->conf, &req_type); 00290 #endif /* CONFIG_WPS */ 00291 00292 if ((wpa_s->scan_res_tried == 0 && wpa_s->conf->ap_scan == 1 && 00293 !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) && 00294 wps != 2 && !wpa_s->conf->filter_ssids && 00295 !wpa_s->connect_without_scan) || 00296 wpa_s->more_bss_to_try) { 00297 wpa_s->scan_res_tried++; 00298 wpa_printf(MSG_DEBUG, "Trying to get current scan results " 00299 "first without requesting a new scan to speed up " 00300 "initial association"); 00301 wpa_supplicant_event(wpa_s, EVENT_SCAN_RESULTS, NULL); 00302 return; 00303 } 00304 00305 scan_req = wpa_s->scan_req; 00306 wpa_s->scan_req = 0; 00307 00308 os_memset(¶ms, 0, sizeof(params)); 00309 00310 prev_state = wpa_s->wpa_state; 00311 if (wpa_s->wpa_state == WPA_DISCONNECTED || 00312 wpa_s->wpa_state == WPA_INACTIVE) 00313 wpa_supplicant_set_state(wpa_s, WPA_SCANNING); 00314 00315 /* Find the starting point from which to continue scanning */ 00316 ssid = wpa_s->conf->ssid; 00317 if (wpa_s->prev_scan_ssid != WILDCARD_SSID_SCAN) { 00318 while (ssid) { 00319 if (ssid == wpa_s->prev_scan_ssid) { 00320 ssid = ssid->next; 00321 break; 00322 } 00323 ssid = ssid->next; 00324 } 00325 } 00326 00327 if (scan_req != 2 && (wpa_s->conf->ap_scan == 2 || 00328 wpa_s->connect_without_scan)) { 00329 wpa_s->connect_without_scan = 0; 00330 wpa_supplicant_assoc_try(wpa_s, ssid); 00331 return; 00332 } else if (wpa_s->conf->ap_scan == 2) { 00333 /* 00334 * User-initiated scan request in ap_scan == 2; scan with 00335 * wildcard SSID. 00336 */ 00337 ssid = NULL; 00338 } else { 00339 struct wpa_ssid *start = ssid, *tssid; 00340 int freqs_set = 0; 00341 if (ssid == NULL && max_ssids > 1) 00342 ssid = wpa_s->conf->ssid; 00343 while (ssid) { 00344 if (!ssid->disabled && ssid->scan_ssid) { 00345 wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID", 00346 ssid->ssid, ssid->ssid_len); 00347 params.ssids[params.num_ssids].ssid = 00348 ssid->ssid; 00349 params.ssids[params.num_ssids].ssid_len = 00350 ssid->ssid_len; 00351 params.num_ssids++; 00352 if (params.num_ssids + 1 >= max_ssids) 00353 break; 00354 } 00355 ssid = ssid->next; 00356 if (ssid == start) 00357 break; 00358 if (ssid == NULL && max_ssids > 1 && 00359 start != wpa_s->conf->ssid) 00360 ssid = wpa_s->conf->ssid; 00361 } 00362 00363 for (tssid = wpa_s->conf->ssid; tssid; tssid = tssid->next) { 00364 if (tssid->disabled) 00365 continue; 00366 if ((params.freqs || !freqs_set) && tssid->scan_freq) { 00367 int_array_concat(¶ms.freqs, 00368 tssid->scan_freq); 00369 } else { 00370 os_free(params.freqs); 00371 params.freqs = NULL; 00372 } 00373 freqs_set = 1; 00374 } 00375 int_array_sort_unique(params.freqs); 00376 } 00377 00378 if (ssid) { 00379 wpa_s->prev_scan_ssid = ssid; 00380 if (max_ssids > 1) { 00381 wpa_printf(MSG_DEBUG, "Include wildcard SSID in the " 00382 "scan request"); 00383 params.num_ssids++; 00384 } 00385 wpa_printf(MSG_DEBUG, "Starting AP scan for specific SSID(s)"); 00386 } else { 00387 wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN; 00388 params.num_ssids++; 00389 wpa_printf(MSG_DEBUG, "Starting AP scan for wildcard SSID"); 00390 } 00391 00392 #ifdef CONFIG_WPS 00393 if (params.freqs == NULL && wpa_s->after_wps && wpa_s->wps_freq) { 00394 /* 00395 * Optimize post-provisioning scan based on channel used 00396 * during provisioning. 00397 */ 00398 wpa_printf(MSG_DEBUG, "WPS: Scan only frequency %u MHz that " 00399 "was used during provisioning", wpa_s->wps_freq); 00400 params.freqs = os_zalloc(2 * sizeof(int)); 00401 if (params.freqs) 00402 params.freqs[0] = wpa_s->wps_freq; 00403 wpa_s->after_wps--; 00404 } 00405 00406 if (wps) { 00407 wps_ie = wps_build_probe_req_ie(wps == 2, &wpa_s->wps->dev, 00408 wpa_s->wps->uuid, req_type); 00409 if (wps_ie) { 00410 params.extra_ies = wpabuf_head(wps_ie); 00411 params.extra_ies_len = wpabuf_len(wps_ie); 00412 } 00413 } 00414 #endif /* CONFIG_WPS */ 00415 00416 params.filter_ssids = wpa_supplicant_build_filter_ssids( 00417 wpa_s->conf, ¶ms.num_filter_ssids); 00418 00419 ret = wpa_supplicant_trigger_scan(wpa_s, ¶ms); 00420 00421 wpabuf_free(wps_ie); 00422 os_free(params.freqs); 00423 os_free(params.filter_ssids); 00424 00425 if (ret) { 00426 wpa_printf(MSG_WARNING, "Failed to initiate AP scan."); 00427 if (prev_state != wpa_s->wpa_state) 00428 wpa_supplicant_set_state(wpa_s, prev_state); 00429 wpa_supplicant_req_scan(wpa_s, 1, 0); 00430 } else 00431 wpa_s->scan_runs++; 00432 } 00433 00434 00444 void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec) 00445 { 00446 /* If there's at least one network that should be specifically scanned 00447 * then don't cancel the scan and reschedule. Some drivers do 00448 * background scanning which generates frequent scan results, and that 00449 * causes the specific SSID scan to get continually pushed back and 00450 * never happen, which causes hidden APs to never get probe-scanned. 00451 */ 00452 if (eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL) && 00453 wpa_s->conf->ap_scan == 1) { 00454 struct wpa_ssid *ssid = wpa_s->conf->ssid; 00455 00456 while (ssid) { 00457 if (!ssid->disabled && ssid->scan_ssid) 00458 break; 00459 ssid = ssid->next; 00460 } 00461 if (ssid) { 00462 wpa_msg(wpa_s, MSG_DEBUG, "Not rescheduling scan to " 00463 "ensure that specific SSID scans occur"); 00464 return; 00465 } 00466 } 00467 00468 wpa_msg(wpa_s, MSG_DEBUG, "Setting scan request: %d sec %d usec", 00469 sec, usec); 00470 eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL); 00471 eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL); 00472 } 00473 00474 00482 void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s) 00483 { 00484 wpa_msg(wpa_s, MSG_DEBUG, "Cancelling scan request"); 00485 eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL); 00486 } 00487 00488 00489 void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s, 00490 int scanning) 00491 { 00492 if (wpa_s->scanning != scanning) { 00493 wpa_s->scanning = scanning; 00494 wpas_notify_scanning(wpa_s); 00495 } 00496 } 00497 00498 00499 static int wpa_scan_get_max_rate(const struct wpa_scan_res *res) 00500 { 00501 int rate = 0; 00502 const u8 *ie; 00503 int i; 00504 00505 ie = wpa_scan_get_ie(res, WLAN_EID_SUPP_RATES); 00506 for (i = 0; ie && i < ie[1]; i++) { 00507 if ((ie[i + 2] & 0x7f) > rate) 00508 rate = ie[i + 2] & 0x7f; 00509 } 00510 00511 ie = wpa_scan_get_ie(res, WLAN_EID_EXT_SUPP_RATES); 00512 for (i = 0; ie && i < ie[1]; i++) { 00513 if ((ie[i + 2] & 0x7f) > rate) 00514 rate = ie[i + 2] & 0x7f; 00515 } 00516 00517 return rate; 00518 } 00519 00520 00521 const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie) 00522 { 00523 const u8 *end, *pos; 00524 00525 pos = (const u8 *) (res + 1); 00526 end = pos + res->ie_len; 00527 00528 while (pos + 1 < end) { 00529 if (pos + 2 + pos[1] > end) 00530 break; 00531 if (pos[0] == ie) 00532 return pos; 00533 pos += 2 + pos[1]; 00534 } 00535 00536 return NULL; 00537 } 00538 00539 00540 const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res, 00541 u32 vendor_type) 00542 { 00543 const u8 *end, *pos; 00544 00545 pos = (const u8 *) (res + 1); 00546 end = pos + res->ie_len; 00547 00548 while (pos + 1 < end) { 00549 if (pos + 2 + pos[1] > end) 00550 break; 00551 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && 00552 vendor_type == WPA_GET_BE32(&pos[2])) 00553 return pos; 00554 pos += 2 + pos[1]; 00555 } 00556 00557 return NULL; 00558 } 00559 00560 00561 struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res, 00562 u32 vendor_type) 00563 { 00564 struct wpabuf *buf; 00565 const u8 *end, *pos; 00566 00567 buf = wpabuf_alloc(res->ie_len); 00568 if (buf == NULL) 00569 return NULL; 00570 00571 pos = (const u8 *) (res + 1); 00572 end = pos + res->ie_len; 00573 00574 while (pos + 1 < end) { 00575 if (pos + 2 + pos[1] > end) 00576 break; 00577 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && 00578 vendor_type == WPA_GET_BE32(&pos[2])) 00579 wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4); 00580 pos += 2 + pos[1]; 00581 } 00582 00583 if (wpabuf_len(buf) == 0) { 00584 wpabuf_free(buf); 00585 buf = NULL; 00586 } 00587 00588 return buf; 00589 } 00590 00591 00592 /* Compare function for sorting scan results. Return >0 if @b is considered 00593 * better. */ 00594 static int wpa_scan_result_compar(const void *a, const void *b) 00595 { 00596 struct wpa_scan_res **_wa = (void *) a; 00597 struct wpa_scan_res **_wb = (void *) b; 00598 struct wpa_scan_res *wa = *_wa; 00599 struct wpa_scan_res *wb = *_wb; 00600 int wpa_a, wpa_b, maxrate_a, maxrate_b; 00601 00602 /* WPA/WPA2 support preferred */ 00603 wpa_a = wpa_scan_get_vendor_ie(wa, WPA_IE_VENDOR_TYPE) != NULL || 00604 wpa_scan_get_ie(wa, WLAN_EID_RSN) != NULL; 00605 wpa_b = wpa_scan_get_vendor_ie(wb, WPA_IE_VENDOR_TYPE) != NULL || 00606 wpa_scan_get_ie(wb, WLAN_EID_RSN) != NULL; 00607 00608 if (wpa_b && !wpa_a) 00609 return 1; 00610 if (!wpa_b && wpa_a) 00611 return -1; 00612 00613 /* privacy support preferred */ 00614 if ((wa->caps & IEEE80211_CAP_PRIVACY) == 0 && 00615 (wb->caps & IEEE80211_CAP_PRIVACY)) 00616 return 1; 00617 if ((wa->caps & IEEE80211_CAP_PRIVACY) && 00618 (wb->caps & IEEE80211_CAP_PRIVACY) == 0) 00619 return -1; 00620 00621 /* best/max rate preferred if signal level close enough XXX */ 00622 if ((wa->level && wb->level && abs(wb->level - wa->level) < 5) || 00623 (wa->qual && wb->qual && abs(wb->qual - wa->qual) < 10)) { 00624 maxrate_a = wpa_scan_get_max_rate(wa); 00625 maxrate_b = wpa_scan_get_max_rate(wb); 00626 if (maxrate_a != maxrate_b) 00627 return maxrate_b - maxrate_a; 00628 } 00629 00630 /* use freq for channel preference */ 00631 00632 /* all things being equal, use signal level; if signal levels are 00633 * identical, use quality values since some drivers may only report 00634 * that value and leave the signal level zero */ 00635 if (wb->level == wa->level) 00636 return wb->qual - wa->qual; 00637 return wb->level - wa->level; 00638 } 00639 00640 00652 struct wpa_scan_results * 00653 wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s, 00654 struct scan_info *info, int new_scan) 00655 { 00656 struct wpa_scan_results *scan_res; 00657 size_t i; 00658 00659 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) 00660 scan_res = ieee80211_sta_get_scan_results(wpa_s); 00661 else 00662 scan_res = wpa_drv_get_scan_results2(wpa_s); 00663 if (scan_res == NULL) { 00664 wpa_printf(MSG_DEBUG, "Failed to get scan results"); 00665 return NULL; 00666 } 00667 00668 qsort(scan_res->res, scan_res->num, sizeof(struct wpa_scan_res *), 00669 wpa_scan_result_compar); 00670 00671 wpa_bss_update_start(wpa_s); 00672 for (i = 0; i < scan_res->num; i++) 00673 wpa_bss_update_scan_res(wpa_s, scan_res->res[i]); 00674 wpa_bss_update_end(wpa_s, info, new_scan); 00675 00676 return scan_res; 00677 } 00678 00679 00680 int wpa_supplicant_update_scan_results(struct wpa_supplicant *wpa_s) 00681 { 00682 struct wpa_scan_results *scan_res; 00683 scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0); 00684 if (scan_res == NULL) 00685 return -1; 00686 wpa_scan_results_free(scan_res); 00687 00688 return 0; 00689 } 00690 00691 00692 void wpa_scan_results_free(struct wpa_scan_results *res) 00693 { 00694 size_t i; 00695 00696 if (res == NULL) 00697 return; 00698 00699 for (i = 0; i < res->num; i++) 00700 os_free(res->res[i]); 00701 os_free(res->res); 00702 os_free(res); 00703 }