scan.c revision c1ce337f7a9d8f8f1c1a1dbf2f68c1afa95bc2ab
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 wpa_printf(MSG_DEBUG, "%s: scan_req = %d, ap_scan = %d", __func__, 96 wpa_s->scan_req, wpa_s->conf->ap_scan); 97 98 if (wpa_s->disconnected && !wpa_s->scan_req) { 99 wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); 100 return; 101 } 102 103 if (!wpa_supplicant_enabled_networks(wpa_s->conf) && 104 !wpa_s->scan_req) { 105 wpa_printf(MSG_DEBUG, "No enabled networks - do not scan"); 106 wpa_supplicant_set_state(wpa_s, WPA_INACTIVE); 107 return; 108 } 109 scan_req = wpa_s->scan_req; 110 wpa_s->scan_req = 0; 111 112 if (wpa_s->conf->ap_scan != 0 && 113 wpa_s->driver && IS_WIRED(wpa_s->driver)) { 114 wpa_printf(MSG_DEBUG, "Using wired authentication - " 115 "overriding ap_scan configuration"); 116 wpa_s->conf->ap_scan = 0; 117 } 118 119 if (wpa_s->conf->ap_scan == 0) { 120 wpa_supplicant_gen_assoc_event(wpa_s); 121 return; 122 } 123 124 if (wpa_s->wpa_state == WPA_DISCONNECTED || 125 wpa_s->wpa_state == WPA_INACTIVE) 126 wpa_supplicant_set_state(wpa_s, WPA_SCANNING); 127 128 ssid = wpa_s->conf->ssid; 129 if (wpa_s->prev_scan_ssid != BROADCAST_SSID_SCAN) { 130 while (ssid) { 131 if (ssid == wpa_s->prev_scan_ssid) { 132 ssid = ssid->next; 133 break; 134 } 135 ssid = ssid->next; 136 } 137 } 138 while (ssid) { 139 if (!ssid->disabled && 140 (ssid->scan_ssid || wpa_s->conf->ap_scan == 2)) 141 break; 142 ssid = ssid->next; 143 } 144 145 if (scan_req != 2 && wpa_s->conf->ap_scan == 2) { 146 /* 147 * ap_scan=2 mode - try to associate with each SSID instead of 148 * scanning for each scan_ssid=1 network. 149 */ 150 if (ssid == NULL) { 151 wpa_printf(MSG_DEBUG, "wpa_supplicant_scan: Reached " 152 "end of scan list - go back to beginning"); 153 wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN; 154 wpa_supplicant_req_scan(wpa_s, 0, 0); 155 return; 156 } 157 if (ssid->next) { 158 /* Continue from the next SSID on the next attempt. */ 159 wpa_s->prev_scan_ssid = ssid; 160 } else { 161 /* Start from the beginning of the SSID list. */ 162 wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN; 163 } 164 wpa_supplicant_associate(wpa_s, NULL, ssid); 165 return; 166 } 167 168#ifdef CONFIG_WPS 169 wps = wpas_wps_in_use(wpa_s->conf, &req_type); 170#endif /* CONFIG_WPS */ 171 172 if (wpa_s->scan_res_tried == 0 && wpa_s->conf->ap_scan == 1 && 173 !wpa_s->use_client_mlme && wps != 2) { 174 wpa_s->scan_res_tried++; 175 wpa_s->scan_req = scan_req; 176 wpa_printf(MSG_DEBUG, "Trying to get current scan results " 177 "first without requesting a new scan to speed up " 178 "initial association"); 179 wpa_supplicant_event(wpa_s, EVENT_SCAN_RESULTS, NULL); 180 return; 181 } 182 183#ifdef CONFIG_WPS 184 if (wps) { 185 wps_ie = wps_build_probe_req_ie(wps == 2, &wpa_s->wps->dev, 186 wpa_s->wps->uuid, req_type); 187 if (wps_ie) { 188 extra_ie = wpabuf_head(wps_ie); 189 extra_ie_len = wpabuf_len(wps_ie); 190 } 191 } 192#endif /* CONFIG_WPS */ 193 194 wpa_supplicant_notify_scanning(wpa_s, 1); 195 196 wpa_printf(MSG_DEBUG, "Starting AP scan (%s SSID)", 197 ssid ? "specific": "broadcast"); 198 if (ssid) { 199 wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID", 200 ssid->ssid, ssid->ssid_len); 201 wpa_s->prev_scan_ssid = ssid; 202 } else 203 wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN; 204 205 if (wpa_s->use_client_mlme) { 206 ieee80211_sta_set_probe_req_ie(wpa_s, extra_ie, extra_ie_len); 207 ret = ieee80211_sta_req_scan(wpa_s, ssid ? ssid->ssid : NULL, 208 ssid ? ssid->ssid_len : 0); 209 } else { 210 wpa_drv_set_probe_req_ie(wpa_s, extra_ie, extra_ie_len); 211 ret = wpa_drv_scan(wpa_s, &ssid); 212 } 213 214 wpabuf_free(wps_ie); 215 216 if (ret) { 217 wpa_printf(MSG_WARNING, "Failed to initiate AP scan."); 218 wpa_supplicant_notify_scanning(wpa_s, 0); 219 wpa_supplicant_req_scan(wpa_s, 10, 0); 220 } else { 221 wpa_s->scan_runs++; 222 } 223} 224 225 226/** 227 * wpa_supplicant_req_scan - Schedule a scan for neighboring access points 228 * @wpa_s: Pointer to wpa_supplicant data 229 * @sec: Number of seconds after which to scan 230 * @usec: Number of microseconds after which to scan 231 * 232 * This function is used to schedule a scan for neighboring access points after 233 * the specified time. 234 */ 235void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec) 236{ 237#ifndef ANDROID 238 /* If there's at least one network that should be specifically scanned 239 * then don't cancel the scan and reschedule. Some drivers do 240 * background scanning which generates frequent scan results, and that 241 * causes the specific SSID scan to get continually pushed back and 242 * never happen, which causes hidden APs to never get probe-scanned. 243 */ 244 if (eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL) && 245 wpa_s->conf->ap_scan == 1) { 246 struct wpa_ssid *ssid = wpa_s->conf->ssid; 247 248 while (ssid) { 249 if (!ssid->disabled && ssid->scan_ssid) 250 break; 251 ssid = ssid->next; 252 } 253 if (ssid) { 254 wpa_msg(wpa_s, MSG_DEBUG, "Not rescheduling scan to " 255 "ensure that specific SSID scans occur"); 256 return; 257 } 258 } 259#endif 260 261 wpa_msg(wpa_s, MSG_DEBUG, "Setting scan request: %d sec %d usec", 262 sec, usec); 263 eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL); 264 eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL); 265} 266 267 268/** 269 * wpa_supplicant_cancel_scan - Cancel a scheduled scan request 270 * @wpa_s: Pointer to wpa_supplicant data 271 * 272 * This function is used to cancel a scan request scheduled with 273 * wpa_supplicant_req_scan(). 274 */ 275void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s) 276{ 277 wpa_msg(wpa_s, MSG_DEBUG, "Cancelling scan request"); 278 eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL); 279 wpa_supplicant_notify_scanning(wpa_s, 0); 280} 281 282 283void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s, 284 int scanning) 285{ 286 if (wpa_s->scanning != scanning) { 287 wpa_s->scanning = scanning; 288 wpa_supplicant_dbus_notify_scanning(wpa_s); 289 } 290} 291 292