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