scan.c revision 02304a41d4807a728b67d2efc7db0f85722640c8
1/* 2 * WPA Supplicant - Scanning 3 * Copyright (c) 2003-2008, 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 "includes.h" 16 17#include "common.h" 18#include "eloop.h" 19#include "config.h" 20#include "wpa_supplicant_i.h" 21#include "mlme.h" 22#include "wps_supplicant.h" 23#include "ctrl_iface_dbus.h" 24 25 26static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s) 27{ 28 struct wpa_ssid *ssid; 29 union wpa_event_data data; 30 31 ssid = wpa_supplicant_get_ssid(wpa_s); 32 if (ssid == NULL) 33 return; 34 35 if (wpa_s->current_ssid == NULL) 36 wpa_s->current_ssid = ssid; 37 wpa_supplicant_initiate_eapol(wpa_s); 38 wpa_printf(MSG_DEBUG, "Already associated with a configured network - " 39 "generating associated event"); 40 os_memset(&data, 0, sizeof(data)); 41 wpa_supplicant_event(wpa_s, EVENT_ASSOC, &data); 42} 43 44 45#ifdef CONFIG_WPS 46static int wpas_wps_in_use(struct wpa_config *conf, 47 enum wps_request_type *req_type) 48{ 49 struct wpa_ssid *ssid; 50 int wps = 0; 51 52 for (ssid = conf->ssid; ssid; ssid = ssid->next) { 53 if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS)) 54 continue; 55 56 wps = 1; 57 *req_type = wpas_wps_get_req_type(ssid); 58 if (!ssid->eap.phase1) 59 continue; 60 61 if (os_strstr(ssid->eap.phase1, "pbc=1")) 62 return 2; 63 } 64 65 return wps; 66} 67#endif /* CONFIG_WPS */ 68 69 70int wpa_supplicant_enabled_networks(struct wpa_config *conf) 71{ 72 struct wpa_ssid *ssid = conf->ssid; 73 while (ssid) { 74 if (!ssid->disabled) 75 return 1; 76 ssid = ssid->next; 77 } 78 return 0; 79} 80 81 82static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) 83{ 84 struct wpa_supplicant *wpa_s = eloop_ctx; 85 struct wpa_ssid *ssid; 86 int scan_req = 0, ret; 87 struct wpabuf *wps_ie = NULL; 88 const u8 *extra_ie = NULL; 89 size_t extra_ie_len = 0; 90 int wps = 0; 91#ifdef CONFIG_WPS 92 enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO; 93#endif /* CONFIG_WPS */ 94 95 if (wpa_s->disconnected && !wpa_s->scan_req) { 96 wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); 97 return; 98 } 99 100 if (!wpa_supplicant_enabled_networks(wpa_s->conf) && 101 !wpa_s->scan_req) { 102 wpa_printf(MSG_DEBUG, "No enabled networks - do not scan"); 103 wpa_supplicant_set_state(wpa_s, WPA_INACTIVE); 104 return; 105 } 106 scan_req = wpa_s->scan_req; 107 wpa_s->scan_req = 0; 108 109 if (wpa_s->conf->ap_scan != 0 && 110 wpa_s->driver && IS_WIRED(wpa_s->driver)) { 111 wpa_printf(MSG_DEBUG, "Using wired authentication - " 112 "overriding ap_scan configuration"); 113 wpa_s->conf->ap_scan = 0; 114 } 115 116 if (wpa_s->conf->ap_scan == 0) { 117 wpa_supplicant_gen_assoc_event(wpa_s); 118 return; 119 } 120 121 if (wpa_s->wpa_state == WPA_DISCONNECTED || 122 wpa_s->wpa_state == WPA_INACTIVE) 123 wpa_supplicant_set_state(wpa_s, WPA_SCANNING); 124 125 ssid = wpa_s->conf->ssid; 126 if (wpa_s->prev_scan_ssid != BROADCAST_SSID_SCAN) { 127 while (ssid) { 128 if (ssid == wpa_s->prev_scan_ssid) { 129 ssid = ssid->next; 130 break; 131 } 132 ssid = ssid->next; 133 } 134 } 135 while (ssid) { 136 if (!ssid->disabled && 137 (ssid->scan_ssid || wpa_s->conf->ap_scan == 2)) 138 break; 139 ssid = ssid->next; 140 } 141 142 if (scan_req != 2 && wpa_s->conf->ap_scan == 2) { 143 /* 144 * ap_scan=2 mode - try to associate with each SSID instead of 145 * scanning for each scan_ssid=1 network. 146 */ 147 if (ssid == NULL) { 148 wpa_printf(MSG_DEBUG, "wpa_supplicant_scan: Reached " 149 "end of scan list - go back to beginning"); 150 wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN; 151 wpa_supplicant_req_scan(wpa_s, 0, 0); 152 return; 153 } 154 if (ssid->next) { 155 /* Continue from the next SSID on the next attempt. */ 156 wpa_s->prev_scan_ssid = ssid; 157 } else { 158 /* Start from the beginning of the SSID list. */ 159 wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN; 160 } 161 wpa_supplicant_associate(wpa_s, NULL, ssid); 162 return; 163 } 164 165 wpa_printf(MSG_DEBUG, "Starting AP scan (%s SSID)", 166 ssid ? "specific": "broadcast"); 167 if (ssid) { 168 wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID", 169 ssid->ssid, ssid->ssid_len); 170 wpa_s->prev_scan_ssid = ssid; 171 } else 172 wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN; 173 174#ifdef CONFIG_WPS 175 wps = wpas_wps_in_use(wpa_s->conf, &req_type); 176#endif /* CONFIG_WPS */ 177 178 if (wpa_s->scan_res_tried == 0 && wpa_s->conf->ap_scan == 1 && 179 !wpa_s->use_client_mlme && wps != 2) { 180 wpa_s->scan_res_tried++; 181 wpa_s->scan_req = scan_req; 182 wpa_printf(MSG_DEBUG, "Trying to get current scan results " 183 "first without requesting a new scan to speed up " 184 "initial association"); 185 wpa_supplicant_event(wpa_s, EVENT_SCAN_RESULTS, NULL); 186 return; 187 } 188 189#ifdef CONFIG_WPS 190 if (wps) { 191 wps_ie = wps_build_probe_req_ie(wps == 2, &wpa_s->wps->dev, 192 wpa_s->wps->uuid, req_type); 193 if (wps_ie) { 194 extra_ie = wpabuf_head(wps_ie); 195 extra_ie_len = wpabuf_len(wps_ie); 196 } 197 } 198#endif /* CONFIG_WPS */ 199 200 wpa_supplicant_notify_scanning(wpa_s, 1); 201 202 if (wpa_s->use_client_mlme) { 203 ieee80211_sta_set_probe_req_ie(wpa_s, extra_ie, extra_ie_len); 204 ret = ieee80211_sta_req_scan(wpa_s, ssid ? ssid->ssid : NULL, 205 ssid ? ssid->ssid_len : 0); 206 } else { 207 wpa_drv_set_probe_req_ie(wpa_s, extra_ie, extra_ie_len); 208 ret = wpa_drv_scan(wpa_s, ssid ? ssid->ssid : NULL, 209 ssid ? ssid->ssid_len : 0); 210 } 211 212 wpabuf_free(wps_ie); 213 214 if (ret) { 215 wpa_printf(MSG_WARNING, "Failed to initiate AP scan."); 216 wpa_supplicant_notify_scanning(wpa_s, 0); 217 wpa_supplicant_req_scan(wpa_s, 10, 0); 218 } else { 219 wpa_s->scan_runs++; 220 } 221} 222 223 224/** 225 * wpa_supplicant_req_scan - Schedule a scan for neighboring access points 226 * @wpa_s: Pointer to wpa_supplicant data 227 * @sec: Number of seconds after which to scan 228 * @usec: Number of microseconds after which to scan 229 * 230 * This function is used to schedule a scan for neighboring access points after 231 * the specified time. 232 */ 233void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec) 234{ 235#ifndef ANDROID 236 /* If there's at least one network that should be specifically scanned 237 * then don't cancel the scan and reschedule. Some drivers do 238 * background scanning which generates frequent scan results, and that 239 * causes the specific SSID scan to get continually pushed back and 240 * never happen, which causes hidden APs to never get probe-scanned. 241 */ 242 if (eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL) && 243 wpa_s->conf->ap_scan == 1) { 244 struct wpa_ssid *ssid = wpa_s->conf->ssid; 245 246 while (ssid) { 247 if (!ssid->disabled && ssid->scan_ssid) 248 break; 249 ssid = ssid->next; 250 } 251 if (ssid) { 252 wpa_msg(wpa_s, MSG_DEBUG, "Not rescheduling scan to " 253 "ensure that specific SSID scans occur"); 254 return; 255 } 256 } 257#endif 258 259 wpa_msg(wpa_s, MSG_DEBUG, "Setting scan request: %d sec %d usec", 260 sec, usec); 261 eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL); 262 eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL); 263} 264 265 266/** 267 * wpa_supplicant_cancel_scan - Cancel a scheduled scan request 268 * @wpa_s: Pointer to wpa_supplicant data 269 * 270 * This function is used to cancel a scan request scheduled with 271 * wpa_supplicant_req_scan(). 272 */ 273void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s) 274{ 275 wpa_msg(wpa_s, MSG_DEBUG, "Cancelling scan request"); 276 eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL); 277 wpa_supplicant_notify_scanning(wpa_s, 0); 278} 279 280 281void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s, 282 int scanning) 283{ 284 if (wpa_s->scanning != scanning) { 285 wpa_s->scanning = scanning; 286 wpa_supplicant_dbus_notify_scanning(wpa_s); 287 } 288} 289 290