| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * WPA Supplicant - Scanning | 
| Dmitry Shmidt | a54fa5f | 2013-01-15 13:53:35 -0800 | [diff] [blame] | 3 |  * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi> | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 4 |  * | 
| Dmitry Shmidt | c5ec7f5 | 2012-03-06 16:33:24 -0800 | [diff] [blame] | 5 |  * This software may be distributed under the terms of the BSD license. | 
 | 6 |  * See README for more details. | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 7 |  */ | 
 | 8 |  | 
 | 9 | #include "utils/includes.h" | 
 | 10 |  | 
 | 11 | #include "utils/common.h" | 
 | 12 | #include "utils/eloop.h" | 
 | 13 | #include "common/ieee802_11_defs.h" | 
| Dmitry Shmidt | 3a787e6 | 2013-01-17 10:32:35 -0800 | [diff] [blame] | 14 | #include "common/wpa_ctrl.h" | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 15 | #include "config.h" | 
 | 16 | #include "wpa_supplicant_i.h" | 
 | 17 | #include "driver_i.h" | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 18 | #include "wps_supplicant.h" | 
 | 19 | #include "p2p_supplicant.h" | 
 | 20 | #include "p2p/p2p.h" | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 21 | #include "hs20_supplicant.h" | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 22 | #include "notify.h" | 
 | 23 | #include "bss.h" | 
| Dmitry Shmidt | 051af73 | 2013-10-22 13:52:46 -0700 | [diff] [blame] | 24 | #include "gas_query.h" | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 25 | #include "scan.h" | 
 | 26 |  | 
 | 27 |  | 
 | 28 | static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s) | 
 | 29 | { | 
 | 30 | 	struct wpa_ssid *ssid; | 
 | 31 | 	union wpa_event_data data; | 
 | 32 |  | 
 | 33 | 	ssid = wpa_supplicant_get_ssid(wpa_s); | 
 | 34 | 	if (ssid == NULL) | 
 | 35 | 		return; | 
 | 36 |  | 
 | 37 | 	if (wpa_s->current_ssid == NULL) { | 
 | 38 | 		wpa_s->current_ssid = ssid; | 
 | 39 | 		if (wpa_s->current_ssid != NULL) | 
 | 40 | 			wpas_notify_network_changed(wpa_s); | 
 | 41 | 	} | 
 | 42 | 	wpa_supplicant_initiate_eapol(wpa_s); | 
 | 43 | 	wpa_dbg(wpa_s, MSG_DEBUG, "Already associated with a configured " | 
 | 44 | 		"network - generating associated event"); | 
 | 45 | 	os_memset(&data, 0, sizeof(data)); | 
 | 46 | 	wpa_supplicant_event(wpa_s, EVENT_ASSOC, &data); | 
 | 47 | } | 
 | 48 |  | 
 | 49 |  | 
 | 50 | #ifdef CONFIG_WPS | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 51 | static int wpas_wps_in_use(struct wpa_supplicant *wpa_s, | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 52 | 			   enum wps_request_type *req_type) | 
 | 53 | { | 
 | 54 | 	struct wpa_ssid *ssid; | 
 | 55 | 	int wps = 0; | 
 | 56 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 57 | 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 58 | 		if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS)) | 
 | 59 | 			continue; | 
 | 60 |  | 
 | 61 | 		wps = 1; | 
 | 62 | 		*req_type = wpas_wps_get_req_type(ssid); | 
 | 63 | 		if (!ssid->eap.phase1) | 
 | 64 | 			continue; | 
 | 65 |  | 
 | 66 | 		if (os_strstr(ssid->eap.phase1, "pbc=1")) | 
 | 67 | 			return 2; | 
 | 68 | 	} | 
 | 69 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 70 | #ifdef CONFIG_P2P | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 71 | 	if (!wpa_s->global->p2p_disabled && wpa_s->global->p2p && | 
 | 72 | 	    !wpa_s->conf->p2p_disabled) { | 
| Dmitry Shmidt | c5ec7f5 | 2012-03-06 16:33:24 -0800 | [diff] [blame] | 73 | 		wpa_s->wps->dev.p2p = 1; | 
 | 74 | 		if (!wps) { | 
 | 75 | 			wps = 1; | 
 | 76 | 			*req_type = WPS_REQ_ENROLLEE_INFO; | 
 | 77 | 		} | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 78 | 	} | 
 | 79 | #endif /* CONFIG_P2P */ | 
 | 80 |  | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 81 | 	return wps; | 
 | 82 | } | 
 | 83 | #endif /* CONFIG_WPS */ | 
 | 84 |  | 
 | 85 |  | 
| Dmitry Shmidt | a54fa5f | 2013-01-15 13:53:35 -0800 | [diff] [blame] | 86 | /** | 
 | 87 |  * wpa_supplicant_enabled_networks - Check whether there are enabled networks | 
 | 88 |  * @wpa_s: Pointer to wpa_supplicant data | 
 | 89 |  * Returns: 0 if no networks are enabled, >0 if networks are enabled | 
 | 90 |  * | 
 | 91 |  * This function is used to figure out whether any networks (or Interworking | 
 | 92 |  * with enabled credentials and auto_interworking) are present in the current | 
 | 93 |  * configuration. | 
 | 94 |  */ | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 95 | int wpa_supplicant_enabled_networks(struct wpa_supplicant *wpa_s) | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 96 | { | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 97 | 	struct wpa_ssid *ssid = wpa_s->conf->ssid; | 
| Dmitry Shmidt | aa53251 | 2012-09-24 10:35:31 -0700 | [diff] [blame] | 98 | 	int count = 0, disabled = 0; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 99 | 	while (ssid) { | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 100 | 		if (!wpas_network_disabled(wpa_s, ssid)) | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 101 | 			count++; | 
| Dmitry Shmidt | aa53251 | 2012-09-24 10:35:31 -0700 | [diff] [blame] | 102 | 		else | 
 | 103 | 			disabled++; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 104 | 		ssid = ssid->next; | 
 | 105 | 	} | 
| Dmitry Shmidt | 61d9df3 | 2012-08-29 16:22:06 -0700 | [diff] [blame] | 106 | 	if (wpa_s->conf->cred && wpa_s->conf->interworking && | 
 | 107 | 	    wpa_s->conf->auto_interworking) | 
 | 108 | 		count++; | 
| Dmitry Shmidt | aa53251 | 2012-09-24 10:35:31 -0700 | [diff] [blame] | 109 | 	if (count == 0 && disabled > 0) { | 
 | 110 | 		wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks (%d disabled " | 
 | 111 | 			"networks)", disabled); | 
 | 112 | 	} | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 113 | 	return count; | 
 | 114 | } | 
 | 115 |  | 
 | 116 |  | 
 | 117 | static void wpa_supplicant_assoc_try(struct wpa_supplicant *wpa_s, | 
 | 118 | 				     struct wpa_ssid *ssid) | 
 | 119 | { | 
 | 120 | 	while (ssid) { | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 121 | 		if (!wpas_network_disabled(wpa_s, ssid)) | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 122 | 			break; | 
 | 123 | 		ssid = ssid->next; | 
 | 124 | 	} | 
 | 125 |  | 
 | 126 | 	/* ap_scan=2 mode - try to associate with each SSID. */ | 
 | 127 | 	if (ssid == NULL) { | 
 | 128 | 		wpa_dbg(wpa_s, MSG_DEBUG, "wpa_supplicant_assoc_try: Reached " | 
 | 129 | 			"end of scan list - go back to beginning"); | 
 | 130 | 		wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN; | 
 | 131 | 		wpa_supplicant_req_scan(wpa_s, 0, 0); | 
 | 132 | 		return; | 
 | 133 | 	} | 
 | 134 | 	if (ssid->next) { | 
 | 135 | 		/* Continue from the next SSID on the next attempt. */ | 
 | 136 | 		wpa_s->prev_scan_ssid = ssid; | 
 | 137 | 	} else { | 
 | 138 | 		/* Start from the beginning of the SSID list. */ | 
 | 139 | 		wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN; | 
 | 140 | 	} | 
 | 141 | 	wpa_supplicant_associate(wpa_s, NULL, ssid); | 
 | 142 | } | 
 | 143 |  | 
 | 144 |  | 
 | 145 | static int int_array_len(const int *a) | 
 | 146 | { | 
 | 147 | 	int i; | 
 | 148 | 	for (i = 0; a && a[i]; i++) | 
 | 149 | 		; | 
 | 150 | 	return i; | 
 | 151 | } | 
 | 152 |  | 
 | 153 |  | 
 | 154 | static void int_array_concat(int **res, const int *a) | 
 | 155 | { | 
 | 156 | 	int reslen, alen, i; | 
 | 157 | 	int *n; | 
 | 158 |  | 
 | 159 | 	reslen = int_array_len(*res); | 
 | 160 | 	alen = int_array_len(a); | 
 | 161 |  | 
| Dmitry Shmidt | 61d9df3 | 2012-08-29 16:22:06 -0700 | [diff] [blame] | 162 | 	n = os_realloc_array(*res, reslen + alen + 1, sizeof(int)); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 163 | 	if (n == NULL) { | 
 | 164 | 		os_free(*res); | 
 | 165 | 		*res = NULL; | 
 | 166 | 		return; | 
 | 167 | 	} | 
 | 168 | 	for (i = 0; i <= alen; i++) | 
 | 169 | 		n[reslen + i] = a[i]; | 
 | 170 | 	*res = n; | 
 | 171 | } | 
 | 172 |  | 
 | 173 |  | 
 | 174 | static int freq_cmp(const void *a, const void *b) | 
 | 175 | { | 
 | 176 | 	int _a = *(int *) a; | 
 | 177 | 	int _b = *(int *) b; | 
 | 178 |  | 
 | 179 | 	if (_a == 0) | 
 | 180 | 		return 1; | 
 | 181 | 	if (_b == 0) | 
 | 182 | 		return -1; | 
 | 183 | 	return _a - _b; | 
 | 184 | } | 
 | 185 |  | 
 | 186 |  | 
 | 187 | static void int_array_sort_unique(int *a) | 
 | 188 | { | 
 | 189 | 	int alen; | 
 | 190 | 	int i, j; | 
 | 191 |  | 
 | 192 | 	if (a == NULL) | 
 | 193 | 		return; | 
 | 194 |  | 
 | 195 | 	alen = int_array_len(a); | 
 | 196 | 	qsort(a, alen, sizeof(int), freq_cmp); | 
 | 197 |  | 
 | 198 | 	i = 0; | 
 | 199 | 	j = 1; | 
 | 200 | 	while (a[i] && a[j]) { | 
 | 201 | 		if (a[i] == a[j]) { | 
 | 202 | 			j++; | 
 | 203 | 			continue; | 
 | 204 | 		} | 
 | 205 | 		a[++i] = a[j++]; | 
 | 206 | 	} | 
 | 207 | 	if (a[i]) | 
 | 208 | 		i++; | 
 | 209 | 	a[i] = 0; | 
 | 210 | } | 
 | 211 |  | 
 | 212 |  | 
| Dmitry Shmidt | a54fa5f | 2013-01-15 13:53:35 -0800 | [diff] [blame] | 213 | /** | 
 | 214 |  * wpa_supplicant_trigger_scan - Request driver to start a scan | 
 | 215 |  * @wpa_s: Pointer to wpa_supplicant data | 
 | 216 |  * @params: Scan parameters | 
 | 217 |  * Returns: 0 on success, -1 on failure | 
 | 218 |  */ | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 219 | int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s, | 
 | 220 | 				struct wpa_driver_scan_params *params) | 
 | 221 | { | 
 | 222 | 	int ret; | 
 | 223 |  | 
 | 224 | 	wpa_supplicant_notify_scanning(wpa_s, 1); | 
 | 225 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 226 | 	ret = wpa_drv_scan(wpa_s, params); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 227 | 	if (ret) { | 
 | 228 | 		wpa_supplicant_notify_scanning(wpa_s, 0); | 
 | 229 | 		wpas_notify_scan_done(wpa_s, 0); | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 230 | 	} else { | 
| Dmitry Shmidt | 444d567 | 2013-04-01 13:08:44 -0700 | [diff] [blame] | 231 | 		os_get_time(&wpa_s->scan_trigger_time); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 232 | 		wpa_s->scan_runs++; | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 233 | 		wpa_s->normal_scans++; | 
 | 234 | 	} | 
 | 235 |  | 
 | 236 | 	return ret; | 
 | 237 | } | 
 | 238 |  | 
 | 239 |  | 
 | 240 | static void | 
 | 241 | wpa_supplicant_delayed_sched_scan_timeout(void *eloop_ctx, void *timeout_ctx) | 
 | 242 | { | 
 | 243 | 	struct wpa_supplicant *wpa_s = eloop_ctx; | 
 | 244 |  | 
 | 245 | 	wpa_dbg(wpa_s, MSG_DEBUG, "Starting delayed sched scan"); | 
 | 246 |  | 
 | 247 | 	if (wpa_supplicant_req_sched_scan(wpa_s)) | 
 | 248 | 		wpa_supplicant_req_scan(wpa_s, 0, 0); | 
 | 249 | } | 
 | 250 |  | 
 | 251 |  | 
 | 252 | static void | 
 | 253 | wpa_supplicant_sched_scan_timeout(void *eloop_ctx, void *timeout_ctx) | 
 | 254 | { | 
 | 255 | 	struct wpa_supplicant *wpa_s = eloop_ctx; | 
 | 256 |  | 
 | 257 | 	wpa_dbg(wpa_s, MSG_DEBUG, "Sched scan timeout - stopping it"); | 
 | 258 |  | 
 | 259 | 	wpa_s->sched_scan_timed_out = 1; | 
 | 260 | 	wpa_supplicant_cancel_sched_scan(wpa_s); | 
 | 261 | } | 
 | 262 |  | 
 | 263 |  | 
| Dmitry Shmidt | e0e48dc | 2013-11-18 12:00:06 -0800 | [diff] [blame] | 264 | int wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s, | 
 | 265 | 				    struct wpa_driver_scan_params *params, | 
 | 266 | 				    int interval) | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 267 | { | 
 | 268 | 	int ret; | 
| Dmitry Shmidt | b7b4d0e | 2013-08-26 12:09:05 -0700 | [diff] [blame] | 269 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 270 | 	wpa_supplicant_notify_scanning(wpa_s, 1); | 
 | 271 | 	ret = wpa_drv_sched_scan(wpa_s, params, interval * 1000); | 
 | 272 | 	if (ret) | 
 | 273 | 		wpa_supplicant_notify_scanning(wpa_s, 0); | 
| Dmitry Shmidt | b96dad4 | 2013-11-05 10:07:29 -0800 | [diff] [blame] | 274 | 	else | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 275 | 		wpa_s->sched_scanning = 1; | 
 | 276 |  | 
 | 277 | 	return ret; | 
 | 278 | } | 
 | 279 |  | 
 | 280 |  | 
| Dmitry Shmidt | e0e48dc | 2013-11-18 12:00:06 -0800 | [diff] [blame] | 281 | int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s) | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 282 | { | 
 | 283 | 	int ret; | 
 | 284 |  | 
 | 285 | 	ret = wpa_drv_stop_sched_scan(wpa_s); | 
 | 286 | 	if (ret) { | 
 | 287 | 		wpa_dbg(wpa_s, MSG_DEBUG, "stopping sched_scan failed!"); | 
 | 288 | 		/* TODO: what to do if stopping fails? */ | 
 | 289 | 		return -1; | 
 | 290 | 	} | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 291 |  | 
 | 292 | 	return ret; | 
 | 293 | } | 
 | 294 |  | 
 | 295 |  | 
 | 296 | static struct wpa_driver_scan_filter * | 
 | 297 | wpa_supplicant_build_filter_ssids(struct wpa_config *conf, size_t *num_ssids) | 
 | 298 | { | 
 | 299 | 	struct wpa_driver_scan_filter *ssids; | 
 | 300 | 	struct wpa_ssid *ssid; | 
 | 301 | 	size_t count; | 
 | 302 |  | 
 | 303 | 	*num_ssids = 0; | 
 | 304 | 	if (!conf->filter_ssids) | 
 | 305 | 		return NULL; | 
 | 306 |  | 
 | 307 | 	for (count = 0, ssid = conf->ssid; ssid; ssid = ssid->next) { | 
 | 308 | 		if (ssid->ssid && ssid->ssid_len) | 
 | 309 | 			count++; | 
 | 310 | 	} | 
 | 311 | 	if (count == 0) | 
 | 312 | 		return NULL; | 
 | 313 | 	ssids = os_zalloc(count * sizeof(struct wpa_driver_scan_filter)); | 
 | 314 | 	if (ssids == NULL) | 
 | 315 | 		return NULL; | 
 | 316 |  | 
 | 317 | 	for (ssid = conf->ssid; ssid; ssid = ssid->next) { | 
 | 318 | 		if (!ssid->ssid || !ssid->ssid_len) | 
 | 319 | 			continue; | 
 | 320 | 		os_memcpy(ssids[*num_ssids].ssid, ssid->ssid, ssid->ssid_len); | 
 | 321 | 		ssids[*num_ssids].ssid_len = ssid->ssid_len; | 
 | 322 | 		(*num_ssids)++; | 
 | 323 | 	} | 
 | 324 |  | 
 | 325 | 	return ssids; | 
 | 326 | } | 
 | 327 |  | 
 | 328 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 329 | static void wpa_supplicant_optimize_freqs( | 
 | 330 | 	struct wpa_supplicant *wpa_s, struct wpa_driver_scan_params *params) | 
 | 331 | { | 
 | 332 | #ifdef CONFIG_P2P | 
 | 333 | 	if (params->freqs == NULL && wpa_s->p2p_in_provisioning && | 
 | 334 | 	    wpa_s->go_params) { | 
 | 335 | 		/* Optimize provisioning state scan based on GO information */ | 
 | 336 | 		if (wpa_s->p2p_in_provisioning < 5 && | 
 | 337 | 		    wpa_s->go_params->freq > 0) { | 
 | 338 | 			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only GO " | 
 | 339 | 				"preferred frequency %d MHz", | 
 | 340 | 				wpa_s->go_params->freq); | 
 | 341 | 			params->freqs = os_zalloc(2 * sizeof(int)); | 
 | 342 | 			if (params->freqs) | 
 | 343 | 				params->freqs[0] = wpa_s->go_params->freq; | 
 | 344 | 		} else if (wpa_s->p2p_in_provisioning < 8 && | 
 | 345 | 			   wpa_s->go_params->freq_list[0]) { | 
 | 346 | 			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only common " | 
 | 347 | 				"channels"); | 
 | 348 | 			int_array_concat(¶ms->freqs, | 
 | 349 | 					 wpa_s->go_params->freq_list); | 
 | 350 | 			if (params->freqs) | 
 | 351 | 				int_array_sort_unique(params->freqs); | 
 | 352 | 		} | 
 | 353 | 		wpa_s->p2p_in_provisioning++; | 
 | 354 | 	} | 
 | 355 | #endif /* CONFIG_P2P */ | 
 | 356 |  | 
 | 357 | #ifdef CONFIG_WPS | 
 | 358 | 	if (params->freqs == NULL && wpa_s->after_wps && wpa_s->wps_freq) { | 
 | 359 | 		/* | 
 | 360 | 		 * Optimize post-provisioning scan based on channel used | 
 | 361 | 		 * during provisioning. | 
 | 362 | 		 */ | 
 | 363 | 		wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Scan only frequency %u MHz " | 
 | 364 | 			"that was used during provisioning", wpa_s->wps_freq); | 
 | 365 | 		params->freqs = os_zalloc(2 * sizeof(int)); | 
 | 366 | 		if (params->freqs) | 
 | 367 | 			params->freqs[0] = wpa_s->wps_freq; | 
 | 368 | 		wpa_s->after_wps--; | 
 | 369 | 	} | 
 | 370 |  | 
| Dmitry Shmidt | c5ec7f5 | 2012-03-06 16:33:24 -0800 | [diff] [blame] | 371 | 	if (params->freqs == NULL && wpa_s->known_wps_freq && wpa_s->wps_freq) | 
 | 372 | 	{ | 
 | 373 | 		/* Optimize provisioning scan based on already known channel */ | 
 | 374 | 		wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Scan only frequency %u MHz", | 
 | 375 | 			wpa_s->wps_freq); | 
 | 376 | 		params->freqs = os_zalloc(2 * sizeof(int)); | 
 | 377 | 		if (params->freqs) | 
 | 378 | 			params->freqs[0] = wpa_s->wps_freq; | 
 | 379 | 		wpa_s->known_wps_freq = 0; /* only do this once */ | 
 | 380 | 	} | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 381 | #endif /* CONFIG_WPS */ | 
 | 382 | } | 
 | 383 |  | 
 | 384 |  | 
 | 385 | #ifdef CONFIG_INTERWORKING | 
 | 386 | static void wpas_add_interworking_elements(struct wpa_supplicant *wpa_s, | 
 | 387 | 					   struct wpabuf *buf) | 
 | 388 | { | 
 | 389 | 	if (wpa_s->conf->interworking == 0) | 
 | 390 | 		return; | 
 | 391 |  | 
 | 392 | 	wpabuf_put_u8(buf, WLAN_EID_EXT_CAPAB); | 
 | 393 | 	wpabuf_put_u8(buf, 4); | 
 | 394 | 	wpabuf_put_u8(buf, 0x00); | 
 | 395 | 	wpabuf_put_u8(buf, 0x00); | 
 | 396 | 	wpabuf_put_u8(buf, 0x00); | 
 | 397 | 	wpabuf_put_u8(buf, 0x80); /* Bit 31 - Interworking */ | 
 | 398 |  | 
 | 399 | 	wpabuf_put_u8(buf, WLAN_EID_INTERWORKING); | 
 | 400 | 	wpabuf_put_u8(buf, is_zero_ether_addr(wpa_s->conf->hessid) ? 1 : | 
 | 401 | 		      1 + ETH_ALEN); | 
 | 402 | 	wpabuf_put_u8(buf, wpa_s->conf->access_network_type); | 
 | 403 | 	/* No Venue Info */ | 
 | 404 | 	if (!is_zero_ether_addr(wpa_s->conf->hessid)) | 
 | 405 | 		wpabuf_put_data(buf, wpa_s->conf->hessid, ETH_ALEN); | 
 | 406 | } | 
 | 407 | #endif /* CONFIG_INTERWORKING */ | 
 | 408 |  | 
 | 409 |  | 
| Dmitry Shmidt | 61d9df3 | 2012-08-29 16:22:06 -0700 | [diff] [blame] | 410 | static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s) | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 411 | { | 
 | 412 | 	struct wpabuf *extra_ie = NULL; | 
 | 413 | #ifdef CONFIG_WPS | 
 | 414 | 	int wps = 0; | 
 | 415 | 	enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO; | 
 | 416 | #endif /* CONFIG_WPS */ | 
 | 417 |  | 
 | 418 | #ifdef CONFIG_INTERWORKING | 
 | 419 | 	if (wpa_s->conf->interworking && | 
 | 420 | 	    wpabuf_resize(&extra_ie, 100) == 0) | 
 | 421 | 		wpas_add_interworking_elements(wpa_s, extra_ie); | 
 | 422 | #endif /* CONFIG_INTERWORKING */ | 
 | 423 |  | 
 | 424 | #ifdef CONFIG_WPS | 
 | 425 | 	wps = wpas_wps_in_use(wpa_s, &req_type); | 
 | 426 |  | 
 | 427 | 	if (wps) { | 
 | 428 | 		struct wpabuf *wps_ie; | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 429 | 		wps_ie = wps_build_probe_req_ie(wps == 2 ? DEV_PW_PUSHBUTTON : | 
 | 430 | 						DEV_PW_DEFAULT, | 
 | 431 | 						&wpa_s->wps->dev, | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 432 | 						wpa_s->wps->uuid, req_type, | 
 | 433 | 						0, NULL); | 
 | 434 | 		if (wps_ie) { | 
 | 435 | 			if (wpabuf_resize(&extra_ie, wpabuf_len(wps_ie)) == 0) | 
 | 436 | 				wpabuf_put_buf(extra_ie, wps_ie); | 
 | 437 | 			wpabuf_free(wps_ie); | 
 | 438 | 		} | 
 | 439 | 	} | 
 | 440 |  | 
 | 441 | #ifdef CONFIG_P2P | 
 | 442 | 	if (wps) { | 
 | 443 | 		size_t ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p); | 
 | 444 | 		if (wpabuf_resize(&extra_ie, ielen) == 0) | 
 | 445 | 			wpas_p2p_scan_ie(wpa_s, extra_ie); | 
 | 446 | 	} | 
 | 447 | #endif /* CONFIG_P2P */ | 
 | 448 |  | 
 | 449 | #endif /* CONFIG_WPS */ | 
 | 450 |  | 
| Dmitry Shmidt | 51b6ea8 | 2013-05-08 10:42:09 -0700 | [diff] [blame] | 451 | #ifdef CONFIG_HS20 | 
 | 452 | 	if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 7) == 0) | 
 | 453 | 		wpas_hs20_add_indication(extra_ie); | 
 | 454 | #endif /* CONFIG_HS20 */ | 
 | 455 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 456 | 	return extra_ie; | 
 | 457 | } | 
 | 458 |  | 
 | 459 |  | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 460 | #ifdef CONFIG_P2P | 
 | 461 |  | 
 | 462 | /* | 
 | 463 |  * Check whether there are any enabled networks or credentials that could be | 
 | 464 |  * used for a non-P2P connection. | 
 | 465 |  */ | 
 | 466 | static int non_p2p_network_enabled(struct wpa_supplicant *wpa_s) | 
 | 467 | { | 
 | 468 | 	struct wpa_ssid *ssid; | 
 | 469 |  | 
 | 470 | 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { | 
 | 471 | 		if (wpas_network_disabled(wpa_s, ssid)) | 
 | 472 | 			continue; | 
 | 473 | 		if (!ssid->p2p_group) | 
 | 474 | 			return 1; | 
 | 475 | 	} | 
 | 476 |  | 
 | 477 | 	if (wpa_s->conf->cred && wpa_s->conf->interworking && | 
 | 478 | 	    wpa_s->conf->auto_interworking) | 
 | 479 | 		return 1; | 
 | 480 |  | 
 | 481 | 	return 0; | 
 | 482 | } | 
 | 483 |  | 
| Dmitry Shmidt | ea69e84 | 2013-05-13 14:52:28 -0700 | [diff] [blame] | 484 | #endif /* CONFIG_P2P */ | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 485 |  | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 486 |  | 
| Dmitry Shmidt | b6e9aaf | 2013-05-20 14:49:44 -0700 | [diff] [blame] | 487 | static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes, | 
 | 488 | 					  u16 num_modes, | 
 | 489 | 					  enum hostapd_hw_mode mode) | 
 | 490 | { | 
 | 491 | 	u16 i; | 
 | 492 |  | 
 | 493 | 	for (i = 0; i < num_modes; i++) { | 
 | 494 | 		if (modes[i].mode == mode) | 
 | 495 | 			return &modes[i]; | 
 | 496 | 	} | 
 | 497 |  | 
 | 498 | 	return NULL; | 
 | 499 | } | 
 | 500 |  | 
 | 501 |  | 
 | 502 | static void wpa_setband_scan_freqs_list(struct wpa_supplicant *wpa_s, | 
 | 503 | 					enum hostapd_hw_mode band, | 
 | 504 | 					struct wpa_driver_scan_params *params) | 
 | 505 | { | 
 | 506 | 	/* Include only supported channels for the specified band */ | 
 | 507 | 	struct hostapd_hw_modes *mode; | 
 | 508 | 	int count, i; | 
 | 509 |  | 
 | 510 | 	mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band); | 
 | 511 | 	if (mode == NULL) { | 
 | 512 | 		/* No channels supported in this band - use empty list */ | 
 | 513 | 		params->freqs = os_zalloc(sizeof(int)); | 
 | 514 | 		return; | 
 | 515 | 	} | 
 | 516 |  | 
 | 517 | 	params->freqs = os_zalloc((mode->num_channels + 1) * sizeof(int)); | 
 | 518 | 	if (params->freqs == NULL) | 
 | 519 | 		return; | 
 | 520 | 	for (count = 0, i = 0; i < mode->num_channels; i++) { | 
 | 521 | 		if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED) | 
 | 522 | 			continue; | 
 | 523 | 		params->freqs[count++] = mode->channels[i].freq; | 
 | 524 | 	} | 
 | 525 | } | 
 | 526 |  | 
 | 527 |  | 
 | 528 | static void wpa_setband_scan_freqs(struct wpa_supplicant *wpa_s, | 
 | 529 | 				   struct wpa_driver_scan_params *params) | 
 | 530 | { | 
 | 531 | 	if (wpa_s->hw.modes == NULL) | 
 | 532 | 		return; /* unknown what channels the driver supports */ | 
 | 533 | 	if (params->freqs) | 
 | 534 | 		return; /* already using a limited channel set */ | 
 | 535 | 	if (wpa_s->setband == WPA_SETBAND_5G) | 
 | 536 | 		wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, | 
 | 537 | 					    params); | 
 | 538 | 	else if (wpa_s->setband == WPA_SETBAND_2G) | 
 | 539 | 		wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, | 
 | 540 | 					    params); | 
 | 541 | } | 
 | 542 |  | 
 | 543 |  | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 544 | static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) | 
 | 545 | { | 
 | 546 | 	struct wpa_supplicant *wpa_s = eloop_ctx; | 
 | 547 | 	struct wpa_ssid *ssid; | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 548 | 	enum scan_req_type scan_req = NORMAL_SCAN_REQ; | 
 | 549 | 	int ret; | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 550 | 	struct wpabuf *extra_ie = NULL; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 551 | 	struct wpa_driver_scan_params params; | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 552 | 	struct wpa_driver_scan_params *scan_params; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 553 | 	size_t max_ssids; | 
 | 554 | 	enum wpa_states prev_state; | 
 | 555 |  | 
 | 556 | 	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { | 
 | 557 | 		wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - interface disabled"); | 
| Dmitry Shmidt | 37d4d6a | 2013-03-18 13:09:42 -0700 | [diff] [blame] | 558 | 		wpas_p2p_continue_after_scan(wpa_s); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 559 | 		return; | 
 | 560 | 	} | 
 | 561 |  | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 562 | 	if (wpa_s->disconnected && wpa_s->scan_req == NORMAL_SCAN_REQ) { | 
| Dmitry Shmidt | aa53251 | 2012-09-24 10:35:31 -0700 | [diff] [blame] | 563 | 		wpa_dbg(wpa_s, MSG_DEBUG, "Disconnected - do not scan"); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 564 | 		wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); | 
| Dmitry Shmidt | 37d4d6a | 2013-03-18 13:09:42 -0700 | [diff] [blame] | 565 | 		wpas_p2p_continue_after_scan(wpa_s); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 566 | 		return; | 
 | 567 | 	} | 
| Dmitry Shmidt | e0e48dc | 2013-11-18 12:00:06 -0800 | [diff] [blame] | 568 |  | 
| Dmitry Shmidt | 5887a9d | 2012-09-14 10:47:43 -0700 | [diff] [blame] | 569 | 	if (wpa_s->scanning) { | 
| Dmitry Shmidt | e0e48dc | 2013-11-18 12:00:06 -0800 | [diff] [blame] | 570 | 		/* | 
 | 571 | 		 * If we are already in scanning state, we shall reschedule the | 
 | 572 | 		 * the incoming scan request. | 
 | 573 | 		 */ | 
 | 574 | 		wpa_dbg(wpa_s, MSG_DEBUG, "Already scanning - Reschedule the incoming scan req"); | 
 | 575 | 		wpa_supplicant_req_scan(wpa_s, 1, 0); | 
| Dmitry Shmidt | 5887a9d | 2012-09-14 10:47:43 -0700 | [diff] [blame] | 576 | 		return; | 
 | 577 | 	} | 
| Dmitry Shmidt | e0e48dc | 2013-11-18 12:00:06 -0800 | [diff] [blame] | 578 |  | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 579 | 	if (!wpa_supplicant_enabled_networks(wpa_s) && | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 580 | 	    wpa_s->scan_req == NORMAL_SCAN_REQ) { | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 581 | 		wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks - do not scan"); | 
 | 582 | 		wpa_supplicant_set_state(wpa_s, WPA_INACTIVE); | 
| Dmitry Shmidt | 37d4d6a | 2013-03-18 13:09:42 -0700 | [diff] [blame] | 583 | 		wpas_p2p_continue_after_scan(wpa_s); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 584 | 		return; | 
 | 585 | 	} | 
 | 586 |  | 
 | 587 | 	if (wpa_s->conf->ap_scan != 0 && | 
 | 588 | 	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED)) { | 
 | 589 | 		wpa_dbg(wpa_s, MSG_DEBUG, "Using wired authentication - " | 
 | 590 | 			"overriding ap_scan configuration"); | 
 | 591 | 		wpa_s->conf->ap_scan = 0; | 
 | 592 | 		wpas_notify_ap_scan_changed(wpa_s); | 
 | 593 | 	} | 
 | 594 |  | 
 | 595 | 	if (wpa_s->conf->ap_scan == 0) { | 
 | 596 | 		wpa_supplicant_gen_assoc_event(wpa_s); | 
 | 597 | 		return; | 
 | 598 | 	} | 
 | 599 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 600 | #ifdef CONFIG_P2P | 
| Dmitry Shmidt | 051af73 | 2013-10-22 13:52:46 -0700 | [diff] [blame] | 601 | 	if (wpas_p2p_in_progress(wpa_s) || wpas_wpa_is_in_progress(wpa_s, 0)) { | 
| Dmitry Shmidt | 61d9df3 | 2012-08-29 16:22:06 -0700 | [diff] [blame] | 602 | 		if (wpa_s->sta_scan_pending && | 
 | 603 | 		    wpas_p2p_in_progress(wpa_s) == 2 && | 
| Jouni Malinen | dc7b713 | 2012-09-14 12:53:47 -0700 | [diff] [blame] | 604 | 		    wpa_s->global->p2p_cb_on_scan_complete) { | 
| Dmitry Shmidt | 61d9df3 | 2012-08-29 16:22:06 -0700 | [diff] [blame] | 605 | 			wpa_dbg(wpa_s, MSG_DEBUG, "Process pending station " | 
 | 606 | 				"mode scan during P2P search"); | 
 | 607 | 		} else { | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 608 | 			wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan " | 
 | 609 | 				"while P2P operation is in progress"); | 
| Dmitry Shmidt | 61d9df3 | 2012-08-29 16:22:06 -0700 | [diff] [blame] | 610 | 			wpa_s->sta_scan_pending = 1; | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 611 | 			wpa_supplicant_req_scan(wpa_s, 5, 0); | 
| Dmitry Shmidt | 61d9df3 | 2012-08-29 16:22:06 -0700 | [diff] [blame] | 612 | 			return; | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 613 | 		} | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 614 | 	} | 
 | 615 | #endif /* CONFIG_P2P */ | 
 | 616 |  | 
| Dmitry Shmidt | 051af73 | 2013-10-22 13:52:46 -0700 | [diff] [blame] | 617 | #ifdef CONFIG_GAS | 
 | 618 | 	if (gas_query_in_progress(wpa_s->gas)) { | 
 | 619 | 		wpa_dbg(wpa_s, MSG_DEBUG, "Delay scan while GAS query is in progress"); | 
 | 620 | 		wpa_supplicant_req_scan(wpa_s, 1, 0); | 
 | 621 | 		return; | 
 | 622 | 	} | 
 | 623 | #endif /* CONFIG_GAS */ | 
 | 624 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 625 | 	if (wpa_s->conf->ap_scan == 2) | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 626 | 		max_ssids = 1; | 
 | 627 | 	else { | 
 | 628 | 		max_ssids = wpa_s->max_scan_ssids; | 
 | 629 | 		if (max_ssids > WPAS_MAX_SCAN_SSIDS) | 
 | 630 | 			max_ssids = WPAS_MAX_SCAN_SSIDS; | 
 | 631 | 	} | 
 | 632 |  | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 633 | 	scan_req = wpa_s->scan_req; | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 634 | 	wpa_s->scan_req = NORMAL_SCAN_REQ; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 635 |  | 
 | 636 | 	os_memset(¶ms, 0, sizeof(params)); | 
 | 637 |  | 
 | 638 | 	prev_state = wpa_s->wpa_state; | 
 | 639 | 	if (wpa_s->wpa_state == WPA_DISCONNECTED || | 
 | 640 | 	    wpa_s->wpa_state == WPA_INACTIVE) | 
 | 641 | 		wpa_supplicant_set_state(wpa_s, WPA_SCANNING); | 
 | 642 |  | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 643 | 	/* | 
 | 644 | 	 * If autoscan has set its own scanning parameters | 
 | 645 | 	 */ | 
 | 646 | 	if (wpa_s->autoscan_params != NULL) { | 
 | 647 | 		scan_params = wpa_s->autoscan_params; | 
 | 648 | 		goto scan; | 
 | 649 | 	} | 
 | 650 |  | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 651 | 	if (scan_req != MANUAL_SCAN_REQ && wpa_s->connect_without_scan) { | 
| Jouni Malinen | 75ecf52 | 2011-06-27 15:19:46 -0700 | [diff] [blame] | 652 | 		for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { | 
 | 653 | 			if (ssid == wpa_s->connect_without_scan) | 
 | 654 | 				break; | 
 | 655 | 		} | 
 | 656 | 		wpa_s->connect_without_scan = NULL; | 
 | 657 | 		if (ssid) { | 
 | 658 | 			wpa_printf(MSG_DEBUG, "Start a pre-selected network " | 
 | 659 | 				   "without scan step"); | 
 | 660 | 			wpa_supplicant_associate(wpa_s, NULL, ssid); | 
 | 661 | 			return; | 
 | 662 | 		} | 
 | 663 | 	} | 
 | 664 |  | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 665 | #ifdef CONFIG_P2P | 
 | 666 | 	if ((wpa_s->p2p_in_provisioning || wpa_s->show_group_started) && | 
 | 667 | 	    wpa_s->go_params) { | 
| Dmitry Shmidt | cce0666 | 2013-11-04 18:44:24 -0800 | [diff] [blame] | 668 | 		wpa_printf(MSG_DEBUG, "P2P: Use specific SSID for scan during P2P group formation (p2p_in_provisioning=%d show_group_started=%d)", | 
 | 669 | 			   wpa_s->p2p_in_provisioning, | 
 | 670 | 			   wpa_s->show_group_started); | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 671 | 		params.ssids[0].ssid = wpa_s->go_params->ssid; | 
 | 672 | 		params.ssids[0].ssid_len = wpa_s->go_params->ssid_len; | 
 | 673 | 		params.num_ssids = 1; | 
 | 674 | 		goto ssid_list_set; | 
 | 675 | 	} | 
 | 676 | #endif /* CONFIG_P2P */ | 
 | 677 |  | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 678 | 	/* Find the starting point from which to continue scanning */ | 
 | 679 | 	ssid = wpa_s->conf->ssid; | 
 | 680 | 	if (wpa_s->prev_scan_ssid != WILDCARD_SSID_SCAN) { | 
 | 681 | 		while (ssid) { | 
 | 682 | 			if (ssid == wpa_s->prev_scan_ssid) { | 
 | 683 | 				ssid = ssid->next; | 
 | 684 | 				break; | 
 | 685 | 			} | 
 | 686 | 			ssid = ssid->next; | 
 | 687 | 		} | 
 | 688 | 	} | 
 | 689 |  | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 690 | 	if (scan_req != MANUAL_SCAN_REQ && wpa_s->conf->ap_scan == 2) { | 
| Jouni Malinen | 75ecf52 | 2011-06-27 15:19:46 -0700 | [diff] [blame] | 691 | 		wpa_s->connect_without_scan = NULL; | 
| Dmitry Shmidt | c5ec7f5 | 2012-03-06 16:33:24 -0800 | [diff] [blame] | 692 | 		wpa_s->prev_scan_wildcard = 0; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 693 | 		wpa_supplicant_assoc_try(wpa_s, ssid); | 
 | 694 | 		return; | 
 | 695 | 	} else if (wpa_s->conf->ap_scan == 2) { | 
 | 696 | 		/* | 
 | 697 | 		 * User-initiated scan request in ap_scan == 2; scan with | 
 | 698 | 		 * wildcard SSID. | 
 | 699 | 		 */ | 
 | 700 | 		ssid = NULL; | 
 | 701 | 	} else { | 
 | 702 | 		struct wpa_ssid *start = ssid, *tssid; | 
 | 703 | 		int freqs_set = 0; | 
 | 704 | 		if (ssid == NULL && max_ssids > 1) | 
 | 705 | 			ssid = wpa_s->conf->ssid; | 
 | 706 | 		while (ssid) { | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 707 | 			if (!wpas_network_disabled(wpa_s, ssid) && | 
 | 708 | 			    ssid->scan_ssid) { | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 709 | 				wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID", | 
 | 710 | 						  ssid->ssid, ssid->ssid_len); | 
 | 711 | 				params.ssids[params.num_ssids].ssid = | 
 | 712 | 					ssid->ssid; | 
 | 713 | 				params.ssids[params.num_ssids].ssid_len = | 
 | 714 | 					ssid->ssid_len; | 
 | 715 | 				params.num_ssids++; | 
 | 716 | 				if (params.num_ssids + 1 >= max_ssids) | 
 | 717 | 					break; | 
 | 718 | 			} | 
 | 719 | 			ssid = ssid->next; | 
 | 720 | 			if (ssid == start) | 
 | 721 | 				break; | 
 | 722 | 			if (ssid == NULL && max_ssids > 1 && | 
 | 723 | 			    start != wpa_s->conf->ssid) | 
 | 724 | 				ssid = wpa_s->conf->ssid; | 
 | 725 | 		} | 
 | 726 |  | 
 | 727 | 		for (tssid = wpa_s->conf->ssid; tssid; tssid = tssid->next) { | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 728 | 			if (wpas_network_disabled(wpa_s, tssid)) | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 729 | 				continue; | 
 | 730 | 			if ((params.freqs || !freqs_set) && tssid->scan_freq) { | 
 | 731 | 				int_array_concat(¶ms.freqs, | 
 | 732 | 						 tssid->scan_freq); | 
 | 733 | 			} else { | 
 | 734 | 				os_free(params.freqs); | 
 | 735 | 				params.freqs = NULL; | 
 | 736 | 			} | 
 | 737 | 			freqs_set = 1; | 
 | 738 | 		} | 
 | 739 | 		int_array_sort_unique(params.freqs); | 
 | 740 | 	} | 
 | 741 |  | 
| Dmitry Shmidt | c5ec7f5 | 2012-03-06 16:33:24 -0800 | [diff] [blame] | 742 | 	if (ssid && max_ssids == 1) { | 
 | 743 | 		/* | 
 | 744 | 		 * If the driver is limited to 1 SSID at a time interleave | 
 | 745 | 		 * wildcard SSID scans with specific SSID scans to avoid | 
 | 746 | 		 * waiting a long time for a wildcard scan. | 
 | 747 | 		 */ | 
 | 748 | 		if (!wpa_s->prev_scan_wildcard) { | 
 | 749 | 			params.ssids[0].ssid = NULL; | 
 | 750 | 			params.ssids[0].ssid_len = 0; | 
 | 751 | 			wpa_s->prev_scan_wildcard = 1; | 
 | 752 | 			wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for " | 
 | 753 | 				"wildcard SSID (Interleave with specific)"); | 
 | 754 | 		} else { | 
 | 755 | 			wpa_s->prev_scan_ssid = ssid; | 
 | 756 | 			wpa_s->prev_scan_wildcard = 0; | 
 | 757 | 			wpa_dbg(wpa_s, MSG_DEBUG, | 
 | 758 | 				"Starting AP scan for specific SSID: %s", | 
 | 759 | 				wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 760 | 		} | 
| Dmitry Shmidt | c5ec7f5 | 2012-03-06 16:33:24 -0800 | [diff] [blame] | 761 | 	} else if (ssid) { | 
 | 762 | 		/* max_ssids > 1 */ | 
 | 763 |  | 
 | 764 | 		wpa_s->prev_scan_ssid = ssid; | 
 | 765 | 		wpa_dbg(wpa_s, MSG_DEBUG, "Include wildcard SSID in " | 
 | 766 | 			"the scan request"); | 
 | 767 | 		params.num_ssids++; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 768 | 	} else { | 
 | 769 | 		wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN; | 
 | 770 | 		params.num_ssids++; | 
 | 771 | 		wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for wildcard " | 
 | 772 | 			"SSID"); | 
 | 773 | 	} | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 774 | #ifdef CONFIG_P2P | 
 | 775 | ssid_list_set: | 
 | 776 | #endif /* CONFIG_P2P */ | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 777 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 778 | 	wpa_supplicant_optimize_freqs(wpa_s, ¶ms); | 
| Dmitry Shmidt | 61d9df3 | 2012-08-29 16:22:06 -0700 | [diff] [blame] | 779 | 	extra_ie = wpa_supplicant_extra_ies(wpa_s); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 780 |  | 
 | 781 | 	if (params.freqs == NULL && wpa_s->next_scan_freqs) { | 
 | 782 | 		wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on previously " | 
 | 783 | 			"generated frequency list"); | 
 | 784 | 		params.freqs = wpa_s->next_scan_freqs; | 
 | 785 | 	} else | 
 | 786 | 		os_free(wpa_s->next_scan_freqs); | 
 | 787 | 	wpa_s->next_scan_freqs = NULL; | 
| Dmitry Shmidt | b6e9aaf | 2013-05-20 14:49:44 -0700 | [diff] [blame] | 788 | 	wpa_setband_scan_freqs(wpa_s, ¶ms); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 789 |  | 
| Dmitry Shmidt | 51b6ea8 | 2013-05-08 10:42:09 -0700 | [diff] [blame] | 790 | 	/* See if user specified frequencies. If so, scan only those. */ | 
 | 791 | 	if (wpa_s->conf->freq_list && !params.freqs) { | 
 | 792 | 		wpa_dbg(wpa_s, MSG_DEBUG, | 
 | 793 | 			"Optimize scan based on conf->freq_list"); | 
 | 794 | 		int_array_concat(¶ms.freqs, wpa_s->conf->freq_list); | 
 | 795 | 	} | 
 | 796 |  | 
| Dmitry Shmidt | ea69e84 | 2013-05-13 14:52:28 -0700 | [diff] [blame] | 797 | 	/* Use current associated channel? */ | 
 | 798 | 	if (wpa_s->conf->scan_cur_freq && !params.freqs) { | 
| Dmitry Shmidt | c2ebb4b | 2013-07-24 12:57:51 -0700 | [diff] [blame] | 799 | 		unsigned int num = wpa_s->num_multichan_concurrent; | 
 | 800 |  | 
 | 801 | 		params.freqs = os_calloc(num + 1, sizeof(int)); | 
 | 802 | 		if (params.freqs) { | 
 | 803 | 			num = get_shared_radio_freqs(wpa_s, params.freqs, num); | 
 | 804 | 			if (num > 0) { | 
 | 805 | 				wpa_dbg(wpa_s, MSG_DEBUG, "Scan only the " | 
 | 806 | 					"current operating channels since " | 
 | 807 | 					"scan_cur_freq is enabled"); | 
 | 808 | 			} else { | 
 | 809 | 				os_free(params.freqs); | 
 | 810 | 				params.freqs = NULL; | 
 | 811 | 			} | 
| Dmitry Shmidt | ea69e84 | 2013-05-13 14:52:28 -0700 | [diff] [blame] | 812 | 		} | 
 | 813 | 	} | 
 | 814 |  | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 815 | 	params.filter_ssids = wpa_supplicant_build_filter_ssids( | 
 | 816 | 		wpa_s->conf, ¶ms.num_filter_ssids); | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 817 | 	if (extra_ie) { | 
 | 818 | 		params.extra_ies = wpabuf_head(extra_ie); | 
 | 819 | 		params.extra_ies_len = wpabuf_len(extra_ie); | 
 | 820 | 	} | 
 | 821 |  | 
 | 822 | #ifdef CONFIG_P2P | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 823 | 	if (wpa_s->p2p_in_provisioning || | 
 | 824 | 	    (wpa_s->show_group_started && wpa_s->go_params)) { | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 825 | 		/* | 
 | 826 | 		 * The interface may not yet be in P2P mode, so we have to | 
 | 827 | 		 * explicitly request P2P probe to disable CCK rates. | 
 | 828 | 		 */ | 
 | 829 | 		params.p2p_probe = 1; | 
 | 830 | 	} | 
 | 831 | #endif /* CONFIG_P2P */ | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 832 |  | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 833 | 	scan_params = ¶ms; | 
 | 834 |  | 
 | 835 | scan: | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 836 | #ifdef CONFIG_P2P | 
 | 837 | 	/* | 
 | 838 | 	 * If the driver does not support multi-channel concurrency and a | 
 | 839 | 	 * virtual interface that shares the same radio with the wpa_s interface | 
 | 840 | 	 * is operating there may not be need to scan other channels apart from | 
 | 841 | 	 * the current operating channel on the other virtual interface. Filter | 
 | 842 | 	 * out other channels in case we are trying to find a connection for a | 
 | 843 | 	 * station interface when we are not configured to prefer station | 
 | 844 | 	 * connection and a concurrent operation is already in process. | 
 | 845 | 	 */ | 
 | 846 | 	if (wpa_s->scan_for_connection && scan_req == NORMAL_SCAN_REQ && | 
 | 847 | 	    !scan_params->freqs && !params.freqs && | 
 | 848 | 	    wpas_is_p2p_prioritized(wpa_s) && | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 849 | 	    wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE && | 
 | 850 | 	    non_p2p_network_enabled(wpa_s)) { | 
| Dmitry Shmidt | c2ebb4b | 2013-07-24 12:57:51 -0700 | [diff] [blame] | 851 | 		unsigned int num = wpa_s->num_multichan_concurrent; | 
 | 852 |  | 
 | 853 | 		params.freqs = os_calloc(num + 1, sizeof(int)); | 
 | 854 | 		if (params.freqs) { | 
 | 855 | 			num = get_shared_radio_freqs(wpa_s, params.freqs, num); | 
 | 856 | 			if (num > 0 && num == wpa_s->num_multichan_concurrent) { | 
 | 857 | 				wpa_dbg(wpa_s, MSG_DEBUG, "Scan only the current operating channels since all channels are already used"); | 
 | 858 | 			} else { | 
 | 859 | 				os_free(params.freqs); | 
 | 860 | 				params.freqs = NULL; | 
 | 861 | 			} | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 862 | 		} | 
 | 863 | 	} | 
 | 864 | #endif /* CONFIG_P2P */ | 
 | 865 |  | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 866 | 	ret = wpa_supplicant_trigger_scan(wpa_s, scan_params); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 867 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 868 | 	wpabuf_free(extra_ie); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 869 | 	os_free(params.freqs); | 
 | 870 | 	os_free(params.filter_ssids); | 
 | 871 |  | 
 | 872 | 	if (ret) { | 
 | 873 | 		wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate AP scan"); | 
 | 874 | 		if (prev_state != wpa_s->wpa_state) | 
 | 875 | 			wpa_supplicant_set_state(wpa_s, prev_state); | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 876 | 		/* Restore scan_req since we will try to scan again */ | 
 | 877 | 		wpa_s->scan_req = scan_req; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 878 | 		wpa_supplicant_req_scan(wpa_s, 1, 0); | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 879 | 	} else { | 
 | 880 | 		wpa_s->scan_for_connection = 0; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 881 | 	} | 
 | 882 | } | 
 | 883 |  | 
 | 884 |  | 
| Dmitry Shmidt | 4b9d52f | 2013-02-05 17:44:43 -0800 | [diff] [blame] | 885 | void wpa_supplicant_update_scan_int(struct wpa_supplicant *wpa_s, int sec) | 
 | 886 | { | 
| Dmitry Shmidt | fa3fc4a | 2013-11-21 13:34:38 -0800 | [diff] [blame] | 887 | 	struct os_reltime remaining, new_int; | 
| Dmitry Shmidt | 4b9d52f | 2013-02-05 17:44:43 -0800 | [diff] [blame] | 888 | 	int cancelled; | 
 | 889 |  | 
 | 890 | 	cancelled = eloop_cancel_timeout_one(wpa_supplicant_scan, wpa_s, NULL, | 
 | 891 | 					     &remaining); | 
 | 892 |  | 
 | 893 | 	new_int.sec = sec; | 
 | 894 | 	new_int.usec = 0; | 
| Dmitry Shmidt | fa3fc4a | 2013-11-21 13:34:38 -0800 | [diff] [blame] | 895 | 	if (cancelled && os_reltime_before(&remaining, &new_int)) { | 
| Dmitry Shmidt | 4b9d52f | 2013-02-05 17:44:43 -0800 | [diff] [blame] | 896 | 		new_int.sec = remaining.sec; | 
 | 897 | 		new_int.usec = remaining.usec; | 
 | 898 | 	} | 
 | 899 |  | 
| Dmitry Shmidt | 051af73 | 2013-10-22 13:52:46 -0700 | [diff] [blame] | 900 | 	if (cancelled) { | 
 | 901 | 		eloop_register_timeout(new_int.sec, new_int.usec, | 
 | 902 | 				       wpa_supplicant_scan, wpa_s, NULL); | 
 | 903 | 	} | 
| Dmitry Shmidt | 4b9d52f | 2013-02-05 17:44:43 -0800 | [diff] [blame] | 904 | 	wpa_s->scan_interval = sec; | 
 | 905 | } | 
 | 906 |  | 
 | 907 |  | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 908 | /** | 
 | 909 |  * wpa_supplicant_req_scan - Schedule a scan for neighboring access points | 
 | 910 |  * @wpa_s: Pointer to wpa_supplicant data | 
 | 911 |  * @sec: Number of seconds after which to scan | 
 | 912 |  * @usec: Number of microseconds after which to scan | 
 | 913 |  * | 
 | 914 |  * This function is used to schedule a scan for neighboring access points after | 
 | 915 |  * the specified time. | 
 | 916 |  */ | 
 | 917 | void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec) | 
 | 918 | { | 
| Dmitry Shmidt | e0e48dc | 2013-11-18 12:00:06 -0800 | [diff] [blame] | 919 | 	if (eloop_deplete_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL)) | 
 | 920 | 	{ | 
 | 921 | 		wpa_dbg(wpa_s, MSG_DEBUG, "Rescheduling scan request: %d sec %d usec", | 
 | 922 | 			sec, usec); | 
 | 923 | 		return; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 924 | 	} | 
| Dmitry Shmidt | 394564b | 2013-11-11 11:19:02 -0800 | [diff] [blame] | 925 |  | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 926 | 	wpa_dbg(wpa_s, MSG_DEBUG, "Setting scan request: %d sec %d usec", | 
 | 927 | 		sec, usec); | 
 | 928 | 	eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL); | 
 | 929 | 	eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL); | 
 | 930 | } | 
 | 931 |  | 
 | 932 |  | 
 | 933 | /** | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 934 |  * wpa_supplicant_delayed_sched_scan - Request a delayed scheduled scan | 
 | 935 |  * @wpa_s: Pointer to wpa_supplicant data | 
 | 936 |  * @sec: Number of seconds after which to scan | 
 | 937 |  * @usec: Number of microseconds after which to scan | 
| Dmitry Shmidt | a54fa5f | 2013-01-15 13:53:35 -0800 | [diff] [blame] | 938 |  * Returns: 0 on success or -1 otherwise | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 939 |  * | 
 | 940 |  * This function is used to schedule periodic scans for neighboring | 
 | 941 |  * access points after the specified time. | 
 | 942 |  */ | 
 | 943 | int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s, | 
 | 944 | 				      int sec, int usec) | 
 | 945 | { | 
 | 946 | 	if (!wpa_s->sched_scan_supported) | 
 | 947 | 		return -1; | 
 | 948 |  | 
 | 949 | 	eloop_register_timeout(sec, usec, | 
 | 950 | 			       wpa_supplicant_delayed_sched_scan_timeout, | 
 | 951 | 			       wpa_s, NULL); | 
 | 952 |  | 
 | 953 | 	return 0; | 
 | 954 | } | 
 | 955 |  | 
 | 956 |  | 
 | 957 | /** | 
 | 958 |  * wpa_supplicant_req_sched_scan - Start a periodic scheduled scan | 
 | 959 |  * @wpa_s: Pointer to wpa_supplicant data | 
| Dmitry Shmidt | a54fa5f | 2013-01-15 13:53:35 -0800 | [diff] [blame] | 960 |  * Returns: 0 is sched_scan was started or -1 otherwise | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 961 |  * | 
 | 962 |  * This function is used to schedule periodic scans for neighboring | 
 | 963 |  * access points repeating the scan continuously. | 
 | 964 |  */ | 
 | 965 | int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s) | 
 | 966 | { | 
 | 967 | 	struct wpa_driver_scan_params params; | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 968 | 	struct wpa_driver_scan_params *scan_params; | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 969 | 	enum wpa_states prev_state; | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 970 | 	struct wpa_ssid *ssid = NULL; | 
| Dmitry Shmidt | 61d9df3 | 2012-08-29 16:22:06 -0700 | [diff] [blame] | 971 | 	struct wpabuf *extra_ie = NULL; | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 972 | 	int ret; | 
 | 973 | 	unsigned int max_sched_scan_ssids; | 
 | 974 | 	int wildcard = 0; | 
 | 975 | 	int need_ssids; | 
 | 976 |  | 
 | 977 | 	if (!wpa_s->sched_scan_supported) | 
 | 978 | 		return -1; | 
 | 979 |  | 
 | 980 | 	if (wpa_s->max_sched_scan_ssids > WPAS_MAX_SCAN_SSIDS) | 
 | 981 | 		max_sched_scan_ssids = WPAS_MAX_SCAN_SSIDS; | 
 | 982 | 	else | 
 | 983 | 		max_sched_scan_ssids = wpa_s->max_sched_scan_ssids; | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 984 | 	if (max_sched_scan_ssids < 1 || wpa_s->conf->disable_scan_offload) | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 985 | 		return -1; | 
 | 986 |  | 
 | 987 | 	if (wpa_s->sched_scanning) { | 
 | 988 | 		wpa_dbg(wpa_s, MSG_DEBUG, "Already sched scanning"); | 
 | 989 | 		return 0; | 
 | 990 | 	} | 
 | 991 |  | 
 | 992 | 	need_ssids = 0; | 
 | 993 | 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 994 | 		if (!wpas_network_disabled(wpa_s, ssid) && !ssid->scan_ssid) { | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 995 | 			/* Use wildcard SSID to find this network */ | 
 | 996 | 			wildcard = 1; | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 997 | 		} else if (!wpas_network_disabled(wpa_s, ssid) && | 
 | 998 | 			   ssid->ssid_len) | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 999 | 			need_ssids++; | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 1000 |  | 
 | 1001 | #ifdef CONFIG_WPS | 
 | 1002 | 		if (!wpas_network_disabled(wpa_s, ssid) && | 
 | 1003 | 		    ssid->key_mgmt == WPA_KEY_MGMT_WPS) { | 
 | 1004 | 			/* | 
 | 1005 | 			 * Normal scan is more reliable and faster for WPS | 
 | 1006 | 			 * operations and since these are for short periods of | 
 | 1007 | 			 * time, the benefit of trying to use sched_scan would | 
 | 1008 | 			 * be limited. | 
 | 1009 | 			 */ | 
 | 1010 | 			wpa_dbg(wpa_s, MSG_DEBUG, "Use normal scan instead of " | 
 | 1011 | 				"sched_scan for WPS"); | 
 | 1012 | 			return -1; | 
 | 1013 | 		} | 
 | 1014 | #endif /* CONFIG_WPS */ | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1015 | 	} | 
 | 1016 | 	if (wildcard) | 
 | 1017 | 		need_ssids++; | 
 | 1018 |  | 
 | 1019 | 	if (wpa_s->normal_scans < 3 && | 
 | 1020 | 	    (need_ssids <= wpa_s->max_scan_ssids || | 
 | 1021 | 	     wpa_s->max_scan_ssids >= (int) max_sched_scan_ssids)) { | 
 | 1022 | 		/* | 
 | 1023 | 		 * When normal scan can speed up operations, use that for the | 
 | 1024 | 		 * first operations before starting the sched_scan to allow | 
 | 1025 | 		 * user space sleep more. We do this only if the normal scan | 
 | 1026 | 		 * has functionality that is suitable for this or if the | 
 | 1027 | 		 * sched_scan does not have better support for multiple SSIDs. | 
 | 1028 | 		 */ | 
 | 1029 | 		wpa_dbg(wpa_s, MSG_DEBUG, "Use normal scan instead of " | 
 | 1030 | 			"sched_scan for initial scans (normal_scans=%d)", | 
 | 1031 | 			wpa_s->normal_scans); | 
 | 1032 | 		return -1; | 
 | 1033 | 	} | 
 | 1034 |  | 
 | 1035 | 	os_memset(¶ms, 0, sizeof(params)); | 
 | 1036 |  | 
 | 1037 | 	/* If we can't allocate space for the filters, we just don't filter */ | 
 | 1038 | 	params.filter_ssids = os_zalloc(wpa_s->max_match_sets * | 
 | 1039 | 					sizeof(struct wpa_driver_scan_filter)); | 
 | 1040 |  | 
 | 1041 | 	prev_state = wpa_s->wpa_state; | 
 | 1042 | 	if (wpa_s->wpa_state == WPA_DISCONNECTED || | 
 | 1043 | 	    wpa_s->wpa_state == WPA_INACTIVE) | 
 | 1044 | 		wpa_supplicant_set_state(wpa_s, WPA_SCANNING); | 
 | 1045 |  | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 1046 | 	if (wpa_s->autoscan_params != NULL) { | 
 | 1047 | 		scan_params = wpa_s->autoscan_params; | 
 | 1048 | 		goto scan; | 
 | 1049 | 	} | 
 | 1050 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1051 | 	/* Find the starting point from which to continue scanning */ | 
 | 1052 | 	ssid = wpa_s->conf->ssid; | 
 | 1053 | 	if (wpa_s->prev_sched_ssid) { | 
 | 1054 | 		while (ssid) { | 
 | 1055 | 			if (ssid == wpa_s->prev_sched_ssid) { | 
 | 1056 | 				ssid = ssid->next; | 
 | 1057 | 				break; | 
 | 1058 | 			} | 
 | 1059 | 			ssid = ssid->next; | 
 | 1060 | 		} | 
 | 1061 | 	} | 
 | 1062 |  | 
 | 1063 | 	if (!ssid || !wpa_s->prev_sched_ssid) { | 
 | 1064 | 		wpa_dbg(wpa_s, MSG_DEBUG, "Beginning of SSID list"); | 
| Dmitry Shmidt | 51b6ea8 | 2013-05-08 10:42:09 -0700 | [diff] [blame] | 1065 | 		if (wpa_s->conf->sched_scan_interval) | 
 | 1066 | 			wpa_s->sched_scan_interval = | 
 | 1067 | 				wpa_s->conf->sched_scan_interval; | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 1068 | 		if (wpa_s->sched_scan_interval == 0) | 
 | 1069 | 			wpa_s->sched_scan_interval = 10; | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1070 | 		wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2; | 
 | 1071 | 		wpa_s->first_sched_scan = 1; | 
 | 1072 | 		ssid = wpa_s->conf->ssid; | 
 | 1073 | 		wpa_s->prev_sched_ssid = ssid; | 
 | 1074 | 	} | 
 | 1075 |  | 
 | 1076 | 	if (wildcard) { | 
 | 1077 | 		wpa_dbg(wpa_s, MSG_DEBUG, "Add wildcard SSID to sched_scan"); | 
 | 1078 | 		params.num_ssids++; | 
 | 1079 | 	} | 
 | 1080 |  | 
 | 1081 | 	while (ssid) { | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 1082 | 		if (wpas_network_disabled(wpa_s, ssid)) | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1083 | 			goto next; | 
 | 1084 |  | 
 | 1085 | 		if (params.num_filter_ssids < wpa_s->max_match_sets && | 
 | 1086 | 		    params.filter_ssids && ssid->ssid && ssid->ssid_len) { | 
 | 1087 | 			wpa_dbg(wpa_s, MSG_DEBUG, "add to filter ssid: %s", | 
 | 1088 | 				wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); | 
 | 1089 | 			os_memcpy(params.filter_ssids[params.num_filter_ssids].ssid, | 
 | 1090 | 				  ssid->ssid, ssid->ssid_len); | 
 | 1091 | 			params.filter_ssids[params.num_filter_ssids].ssid_len = | 
 | 1092 | 				ssid->ssid_len; | 
 | 1093 | 			params.num_filter_ssids++; | 
 | 1094 | 		} else if (params.filter_ssids && ssid->ssid && ssid->ssid_len) | 
 | 1095 | 		{ | 
 | 1096 | 			wpa_dbg(wpa_s, MSG_DEBUG, "Not enough room for SSID " | 
 | 1097 | 				"filter for sched_scan - drop filter"); | 
 | 1098 | 			os_free(params.filter_ssids); | 
 | 1099 | 			params.filter_ssids = NULL; | 
 | 1100 | 			params.num_filter_ssids = 0; | 
 | 1101 | 		} | 
 | 1102 |  | 
 | 1103 | 		if (ssid->scan_ssid && ssid->ssid && ssid->ssid_len) { | 
 | 1104 | 			if (params.num_ssids == max_sched_scan_ssids) | 
 | 1105 | 				break; /* only room for broadcast SSID */ | 
 | 1106 | 			wpa_dbg(wpa_s, MSG_DEBUG, | 
 | 1107 | 				"add to active scan ssid: %s", | 
 | 1108 | 				wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); | 
 | 1109 | 			params.ssids[params.num_ssids].ssid = | 
 | 1110 | 				ssid->ssid; | 
 | 1111 | 			params.ssids[params.num_ssids].ssid_len = | 
 | 1112 | 				ssid->ssid_len; | 
 | 1113 | 			params.num_ssids++; | 
 | 1114 | 			if (params.num_ssids >= max_sched_scan_ssids) { | 
 | 1115 | 				wpa_s->prev_sched_ssid = ssid; | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 1116 | 				do { | 
 | 1117 | 					ssid = ssid->next; | 
 | 1118 | 				} while (ssid && | 
 | 1119 | 					 (wpas_network_disabled(wpa_s, ssid) || | 
 | 1120 | 					  !ssid->scan_ssid)); | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1121 | 				break; | 
 | 1122 | 			} | 
 | 1123 | 		} | 
 | 1124 |  | 
 | 1125 | 	next: | 
 | 1126 | 		wpa_s->prev_sched_ssid = ssid; | 
 | 1127 | 		ssid = ssid->next; | 
 | 1128 | 	} | 
 | 1129 |  | 
 | 1130 | 	if (params.num_filter_ssids == 0) { | 
 | 1131 | 		os_free(params.filter_ssids); | 
 | 1132 | 		params.filter_ssids = NULL; | 
 | 1133 | 	} | 
 | 1134 |  | 
| Dmitry Shmidt | 61d9df3 | 2012-08-29 16:22:06 -0700 | [diff] [blame] | 1135 | 	extra_ie = wpa_supplicant_extra_ies(wpa_s); | 
 | 1136 | 	if (extra_ie) { | 
 | 1137 | 		params.extra_ies = wpabuf_head(extra_ie); | 
 | 1138 | 		params.extra_ies_len = wpabuf_len(extra_ie); | 
 | 1139 | 	} | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1140 |  | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 1141 | 	scan_params = ¶ms; | 
 | 1142 |  | 
 | 1143 | scan: | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1144 | 	if (ssid || !wpa_s->first_sched_scan) { | 
 | 1145 | 		wpa_dbg(wpa_s, MSG_DEBUG, | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1146 | 			"Starting sched scan: interval %d timeout %d", | 
 | 1147 | 			wpa_s->sched_scan_interval, wpa_s->sched_scan_timeout); | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 1148 | 	} else { | 
 | 1149 | 		wpa_dbg(wpa_s, MSG_DEBUG, | 
 | 1150 | 			"Starting sched scan: interval %d (no timeout)", | 
 | 1151 | 			wpa_s->sched_scan_interval); | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1152 | 	} | 
 | 1153 |  | 
| Dmitry Shmidt | b6e9aaf | 2013-05-20 14:49:44 -0700 | [diff] [blame] | 1154 | 	wpa_setband_scan_freqs(wpa_s, scan_params); | 
 | 1155 |  | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 1156 | 	ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params, | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1157 | 					      wpa_s->sched_scan_interval); | 
| Dmitry Shmidt | 61d9df3 | 2012-08-29 16:22:06 -0700 | [diff] [blame] | 1158 | 	wpabuf_free(extra_ie); | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1159 | 	os_free(params.filter_ssids); | 
 | 1160 | 	if (ret) { | 
 | 1161 | 		wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate sched scan"); | 
 | 1162 | 		if (prev_state != wpa_s->wpa_state) | 
 | 1163 | 			wpa_supplicant_set_state(wpa_s, prev_state); | 
 | 1164 | 		return ret; | 
 | 1165 | 	} | 
 | 1166 |  | 
 | 1167 | 	/* If we have more SSIDs to scan, add a timeout so we scan them too */ | 
 | 1168 | 	if (ssid || !wpa_s->first_sched_scan) { | 
 | 1169 | 		wpa_s->sched_scan_timed_out = 0; | 
 | 1170 | 		eloop_register_timeout(wpa_s->sched_scan_timeout, 0, | 
 | 1171 | 				       wpa_supplicant_sched_scan_timeout, | 
 | 1172 | 				       wpa_s, NULL); | 
 | 1173 | 		wpa_s->first_sched_scan = 0; | 
 | 1174 | 		wpa_s->sched_scan_timeout /= 2; | 
 | 1175 | 		wpa_s->sched_scan_interval *= 2; | 
| Dmitry Shmidt | 2f02319 | 2013-03-12 12:44:17 -0700 | [diff] [blame] | 1176 | 		if (wpa_s->sched_scan_timeout < wpa_s->sched_scan_interval) { | 
 | 1177 | 			wpa_s->sched_scan_interval = 10; | 
 | 1178 | 			wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2; | 
 | 1179 | 		} | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1180 | 	} | 
 | 1181 |  | 
| Dmitry Shmidt | 2f02319 | 2013-03-12 12:44:17 -0700 | [diff] [blame] | 1182 | 	/* If there is no more ssids, start next time from the beginning */ | 
 | 1183 | 	if (!ssid) | 
 | 1184 | 		wpa_s->prev_sched_ssid = NULL; | 
 | 1185 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1186 | 	return 0; | 
 | 1187 | } | 
 | 1188 |  | 
 | 1189 |  | 
 | 1190 | /** | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1191 |  * wpa_supplicant_cancel_scan - Cancel a scheduled scan request | 
 | 1192 |  * @wpa_s: Pointer to wpa_supplicant data | 
 | 1193 |  * | 
 | 1194 |  * This function is used to cancel a scan request scheduled with | 
 | 1195 |  * wpa_supplicant_req_scan(). | 
 | 1196 |  */ | 
 | 1197 | void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s) | 
 | 1198 | { | 
 | 1199 | 	wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling scan request"); | 
 | 1200 | 	eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL); | 
| Dmitry Shmidt | 37d4d6a | 2013-03-18 13:09:42 -0700 | [diff] [blame] | 1201 | 	wpas_p2p_continue_after_scan(wpa_s); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1202 | } | 
 | 1203 |  | 
 | 1204 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1205 | /** | 
| Dmitry Shmidt | c2ebb4b | 2013-07-24 12:57:51 -0700 | [diff] [blame] | 1206 |  * wpa_supplicant_cancel_delayed_sched_scan - Stop a delayed scheduled scan | 
 | 1207 |  * @wpa_s: Pointer to wpa_supplicant data | 
 | 1208 |  * | 
 | 1209 |  * This function is used to stop a delayed scheduled scan. | 
 | 1210 |  */ | 
 | 1211 | void wpa_supplicant_cancel_delayed_sched_scan(struct wpa_supplicant *wpa_s) | 
 | 1212 | { | 
 | 1213 | 	if (!wpa_s->sched_scan_supported) | 
 | 1214 | 		return; | 
 | 1215 |  | 
 | 1216 | 	wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling delayed sched scan"); | 
 | 1217 | 	eloop_cancel_timeout(wpa_supplicant_delayed_sched_scan_timeout, | 
 | 1218 | 			     wpa_s, NULL); | 
 | 1219 | } | 
 | 1220 |  | 
 | 1221 |  | 
 | 1222 | /** | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1223 |  * wpa_supplicant_cancel_sched_scan - Stop running scheduled scans | 
 | 1224 |  * @wpa_s: Pointer to wpa_supplicant data | 
 | 1225 |  * | 
 | 1226 |  * This function is used to stop a periodic scheduled scan. | 
 | 1227 |  */ | 
 | 1228 | void wpa_supplicant_cancel_sched_scan(struct wpa_supplicant *wpa_s) | 
 | 1229 | { | 
 | 1230 | 	if (!wpa_s->sched_scanning) | 
 | 1231 | 		return; | 
 | 1232 |  | 
 | 1233 | 	wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling sched scan"); | 
 | 1234 | 	eloop_cancel_timeout(wpa_supplicant_sched_scan_timeout, wpa_s, NULL); | 
 | 1235 | 	wpa_supplicant_stop_sched_scan(wpa_s); | 
 | 1236 | } | 
 | 1237 |  | 
 | 1238 |  | 
| Dmitry Shmidt | a54fa5f | 2013-01-15 13:53:35 -0800 | [diff] [blame] | 1239 | /** | 
 | 1240 |  * wpa_supplicant_notify_scanning - Indicate possible scan state change | 
 | 1241 |  * @wpa_s: Pointer to wpa_supplicant data | 
 | 1242 |  * @scanning: Whether scanning is currently in progress | 
 | 1243 |  * | 
 | 1244 |  * This function is to generate scanning notifycations. It is called whenever | 
 | 1245 |  * there may have been a change in scanning (scan started, completed, stopped). | 
 | 1246 |  * wpas_notify_scanning() is called whenever the scanning state changed from the | 
 | 1247 |  * previously notified state. | 
 | 1248 |  */ | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1249 | void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s, | 
 | 1250 | 				    int scanning) | 
 | 1251 | { | 
 | 1252 | 	if (wpa_s->scanning != scanning) { | 
 | 1253 | 		wpa_s->scanning = scanning; | 
 | 1254 | 		wpas_notify_scanning(wpa_s); | 
 | 1255 | 	} | 
 | 1256 | } | 
 | 1257 |  | 
 | 1258 |  | 
 | 1259 | static int wpa_scan_get_max_rate(const struct wpa_scan_res *res) | 
 | 1260 | { | 
 | 1261 | 	int rate = 0; | 
 | 1262 | 	const u8 *ie; | 
 | 1263 | 	int i; | 
 | 1264 |  | 
 | 1265 | 	ie = wpa_scan_get_ie(res, WLAN_EID_SUPP_RATES); | 
 | 1266 | 	for (i = 0; ie && i < ie[1]; i++) { | 
 | 1267 | 		if ((ie[i + 2] & 0x7f) > rate) | 
 | 1268 | 			rate = ie[i + 2] & 0x7f; | 
 | 1269 | 	} | 
 | 1270 |  | 
 | 1271 | 	ie = wpa_scan_get_ie(res, WLAN_EID_EXT_SUPP_RATES); | 
 | 1272 | 	for (i = 0; ie && i < ie[1]; i++) { | 
 | 1273 | 		if ((ie[i + 2] & 0x7f) > rate) | 
 | 1274 | 			rate = ie[i + 2] & 0x7f; | 
 | 1275 | 	} | 
 | 1276 |  | 
 | 1277 | 	return rate; | 
 | 1278 | } | 
 | 1279 |  | 
 | 1280 |  | 
| Dmitry Shmidt | a54fa5f | 2013-01-15 13:53:35 -0800 | [diff] [blame] | 1281 | /** | 
 | 1282 |  * wpa_scan_get_ie - Fetch a specified information element from a scan result | 
 | 1283 |  * @res: Scan result entry | 
 | 1284 |  * @ie: Information element identitifier (WLAN_EID_*) | 
 | 1285 |  * Returns: Pointer to the information element (id field) or %NULL if not found | 
 | 1286 |  * | 
 | 1287 |  * This function returns the first matching information element in the scan | 
 | 1288 |  * result. | 
 | 1289 |  */ | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1290 | const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie) | 
 | 1291 | { | 
 | 1292 | 	const u8 *end, *pos; | 
 | 1293 |  | 
 | 1294 | 	pos = (const u8 *) (res + 1); | 
 | 1295 | 	end = pos + res->ie_len; | 
 | 1296 |  | 
 | 1297 | 	while (pos + 1 < end) { | 
 | 1298 | 		if (pos + 2 + pos[1] > end) | 
 | 1299 | 			break; | 
 | 1300 | 		if (pos[0] == ie) | 
 | 1301 | 			return pos; | 
 | 1302 | 		pos += 2 + pos[1]; | 
 | 1303 | 	} | 
 | 1304 |  | 
 | 1305 | 	return NULL; | 
 | 1306 | } | 
 | 1307 |  | 
 | 1308 |  | 
| Dmitry Shmidt | a54fa5f | 2013-01-15 13:53:35 -0800 | [diff] [blame] | 1309 | /** | 
 | 1310 |  * wpa_scan_get_vendor_ie - Fetch vendor information element from a scan result | 
 | 1311 |  * @res: Scan result entry | 
 | 1312 |  * @vendor_type: Vendor type (four octets starting the IE payload) | 
 | 1313 |  * Returns: Pointer to the information element (id field) or %NULL if not found | 
 | 1314 |  * | 
 | 1315 |  * This function returns the first matching information element in the scan | 
 | 1316 |  * result. | 
 | 1317 |  */ | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1318 | const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res, | 
 | 1319 | 				  u32 vendor_type) | 
 | 1320 | { | 
 | 1321 | 	const u8 *end, *pos; | 
 | 1322 |  | 
 | 1323 | 	pos = (const u8 *) (res + 1); | 
 | 1324 | 	end = pos + res->ie_len; | 
 | 1325 |  | 
 | 1326 | 	while (pos + 1 < end) { | 
 | 1327 | 		if (pos + 2 + pos[1] > end) | 
 | 1328 | 			break; | 
 | 1329 | 		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && | 
 | 1330 | 		    vendor_type == WPA_GET_BE32(&pos[2])) | 
 | 1331 | 			return pos; | 
 | 1332 | 		pos += 2 + pos[1]; | 
 | 1333 | 	} | 
 | 1334 |  | 
 | 1335 | 	return NULL; | 
 | 1336 | } | 
 | 1337 |  | 
 | 1338 |  | 
| Dmitry Shmidt | a54fa5f | 2013-01-15 13:53:35 -0800 | [diff] [blame] | 1339 | /** | 
| Dmitry Shmidt | 9657139 | 2013-10-14 12:54:46 -0700 | [diff] [blame] | 1340 |  * wpa_scan_get_vendor_ie_beacon - Fetch vendor information from a scan result | 
 | 1341 |  * @res: Scan result entry | 
 | 1342 |  * @vendor_type: Vendor type (four octets starting the IE payload) | 
 | 1343 |  * Returns: Pointer to the information element (id field) or %NULL if not found | 
 | 1344 |  * | 
 | 1345 |  * This function returns the first matching information element in the scan | 
 | 1346 |  * result. | 
 | 1347 |  * | 
 | 1348 |  * This function is like wpa_scan_get_vendor_ie(), but uses IE buffer only | 
 | 1349 |  * from Beacon frames instead of either Beacon or Probe Response frames. | 
 | 1350 |  */ | 
 | 1351 | const u8 * wpa_scan_get_vendor_ie_beacon(const struct wpa_scan_res *res, | 
 | 1352 | 					 u32 vendor_type) | 
 | 1353 | { | 
 | 1354 | 	const u8 *end, *pos; | 
 | 1355 |  | 
 | 1356 | 	if (res->beacon_ie_len == 0) | 
 | 1357 | 		return NULL; | 
 | 1358 |  | 
 | 1359 | 	pos = (const u8 *) (res + 1); | 
 | 1360 | 	pos += res->ie_len; | 
 | 1361 | 	end = pos + res->beacon_ie_len; | 
 | 1362 |  | 
 | 1363 | 	while (pos + 1 < end) { | 
 | 1364 | 		if (pos + 2 + pos[1] > end) | 
 | 1365 | 			break; | 
 | 1366 | 		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && | 
 | 1367 | 		    vendor_type == WPA_GET_BE32(&pos[2])) | 
 | 1368 | 			return pos; | 
 | 1369 | 		pos += 2 + pos[1]; | 
 | 1370 | 	} | 
 | 1371 |  | 
 | 1372 | 	return NULL; | 
 | 1373 | } | 
 | 1374 |  | 
 | 1375 |  | 
 | 1376 | /** | 
| Dmitry Shmidt | a54fa5f | 2013-01-15 13:53:35 -0800 | [diff] [blame] | 1377 |  * wpa_scan_get_vendor_ie_multi - Fetch vendor IE data from a scan result | 
 | 1378 |  * @res: Scan result entry | 
 | 1379 |  * @vendor_type: Vendor type (four octets starting the IE payload) | 
 | 1380 |  * Returns: Pointer to the information element payload or %NULL if not found | 
 | 1381 |  * | 
 | 1382 |  * This function returns concatenated payload of possibly fragmented vendor | 
 | 1383 |  * specific information elements in the scan result. The caller is responsible | 
 | 1384 |  * for freeing the returned buffer. | 
 | 1385 |  */ | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1386 | struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res, | 
 | 1387 | 					     u32 vendor_type) | 
 | 1388 | { | 
 | 1389 | 	struct wpabuf *buf; | 
 | 1390 | 	const u8 *end, *pos; | 
 | 1391 |  | 
 | 1392 | 	buf = wpabuf_alloc(res->ie_len); | 
 | 1393 | 	if (buf == NULL) | 
 | 1394 | 		return NULL; | 
 | 1395 |  | 
 | 1396 | 	pos = (const u8 *) (res + 1); | 
 | 1397 | 	end = pos + res->ie_len; | 
 | 1398 |  | 
 | 1399 | 	while (pos + 1 < end) { | 
 | 1400 | 		if (pos + 2 + pos[1] > end) | 
 | 1401 | 			break; | 
 | 1402 | 		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && | 
 | 1403 | 		    vendor_type == WPA_GET_BE32(&pos[2])) | 
 | 1404 | 			wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4); | 
 | 1405 | 		pos += 2 + pos[1]; | 
 | 1406 | 	} | 
 | 1407 |  | 
 | 1408 | 	if (wpabuf_len(buf) == 0) { | 
 | 1409 | 		wpabuf_free(buf); | 
 | 1410 | 		buf = NULL; | 
 | 1411 | 	} | 
 | 1412 |  | 
 | 1413 | 	return buf; | 
 | 1414 | } | 
 | 1415 |  | 
 | 1416 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1417 | /* | 
 | 1418 |  * Channels with a great SNR can operate at full rate. What is a great SNR? | 
 | 1419 |  * This doc https://supportforums.cisco.com/docs/DOC-12954 says, "the general | 
 | 1420 |  * rule of thumb is that any SNR above 20 is good." This one | 
 | 1421 |  * http://www.cisco.com/en/US/tech/tk722/tk809/technologies_q_and_a_item09186a00805e9a96.shtml#qa23 | 
 | 1422 |  * recommends 25 as a minimum SNR for 54 Mbps data rate. 30 is chosen here as a | 
 | 1423 |  * conservative value. | 
 | 1424 |  */ | 
 | 1425 | #define GREAT_SNR 30 | 
 | 1426 |  | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1427 | /* Compare function for sorting scan results. Return >0 if @b is considered | 
 | 1428 |  * better. */ | 
 | 1429 | static int wpa_scan_result_compar(const void *a, const void *b) | 
 | 1430 | { | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1431 | #define IS_5GHZ(n) (n > 4000) | 
 | 1432 | #define MIN(a,b) a < b ? a : b | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1433 | 	struct wpa_scan_res **_wa = (void *) a; | 
 | 1434 | 	struct wpa_scan_res **_wb = (void *) b; | 
 | 1435 | 	struct wpa_scan_res *wa = *_wa; | 
 | 1436 | 	struct wpa_scan_res *wb = *_wb; | 
 | 1437 | 	int wpa_a, wpa_b, maxrate_a, maxrate_b; | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1438 | 	int snr_a, snr_b; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1439 |  | 
 | 1440 | 	/* WPA/WPA2 support preferred */ | 
 | 1441 | 	wpa_a = wpa_scan_get_vendor_ie(wa, WPA_IE_VENDOR_TYPE) != NULL || | 
 | 1442 | 		wpa_scan_get_ie(wa, WLAN_EID_RSN) != NULL; | 
 | 1443 | 	wpa_b = wpa_scan_get_vendor_ie(wb, WPA_IE_VENDOR_TYPE) != NULL || | 
 | 1444 | 		wpa_scan_get_ie(wb, WLAN_EID_RSN) != NULL; | 
 | 1445 |  | 
 | 1446 | 	if (wpa_b && !wpa_a) | 
 | 1447 | 		return 1; | 
 | 1448 | 	if (!wpa_b && wpa_a) | 
 | 1449 | 		return -1; | 
 | 1450 |  | 
 | 1451 | 	/* privacy support preferred */ | 
 | 1452 | 	if ((wa->caps & IEEE80211_CAP_PRIVACY) == 0 && | 
 | 1453 | 	    (wb->caps & IEEE80211_CAP_PRIVACY)) | 
 | 1454 | 		return 1; | 
 | 1455 | 	if ((wa->caps & IEEE80211_CAP_PRIVACY) && | 
 | 1456 | 	    (wb->caps & IEEE80211_CAP_PRIVACY) == 0) | 
 | 1457 | 		return -1; | 
 | 1458 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1459 | 	if ((wa->flags & wb->flags & WPA_SCAN_LEVEL_DBM) && | 
 | 1460 | 	    !((wa->flags | wb->flags) & WPA_SCAN_NOISE_INVALID)) { | 
 | 1461 | 		snr_a = MIN(wa->level - wa->noise, GREAT_SNR); | 
 | 1462 | 		snr_b = MIN(wb->level - wb->noise, GREAT_SNR); | 
 | 1463 | 	} else { | 
 | 1464 | 		/* Not suitable information to calculate SNR, so use level */ | 
 | 1465 | 		snr_a = wa->level; | 
 | 1466 | 		snr_b = wb->level; | 
 | 1467 | 	} | 
 | 1468 |  | 
 | 1469 | 	/* best/max rate preferred if SNR close enough */ | 
 | 1470 |         if ((snr_a && snr_b && abs(snr_b - snr_a) < 5) || | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1471 | 	    (wa->qual && wb->qual && abs(wb->qual - wa->qual) < 10)) { | 
 | 1472 | 		maxrate_a = wpa_scan_get_max_rate(wa); | 
 | 1473 | 		maxrate_b = wpa_scan_get_max_rate(wb); | 
 | 1474 | 		if (maxrate_a != maxrate_b) | 
 | 1475 | 			return maxrate_b - maxrate_a; | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1476 | 		if (IS_5GHZ(wa->freq) ^ IS_5GHZ(wb->freq)) | 
 | 1477 | 			return IS_5GHZ(wa->freq) ? -1 : 1; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1478 | 	} | 
 | 1479 |  | 
 | 1480 | 	/* use freq for channel preference */ | 
 | 1481 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1482 | 	/* all things being equal, use SNR; if SNRs are | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1483 | 	 * identical, use quality values since some drivers may only report | 
 | 1484 | 	 * that value and leave the signal level zero */ | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1485 | 	if (snr_b == snr_a) | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1486 | 		return wb->qual - wa->qual; | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1487 | 	return snr_b - snr_a; | 
 | 1488 | #undef MIN | 
 | 1489 | #undef IS_5GHZ | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1490 | } | 
 | 1491 |  | 
 | 1492 |  | 
 | 1493 | #ifdef CONFIG_WPS | 
 | 1494 | /* Compare function for sorting scan results when searching a WPS AP for | 
 | 1495 |  * provisioning. Return >0 if @b is considered better. */ | 
 | 1496 | static int wpa_scan_result_wps_compar(const void *a, const void *b) | 
 | 1497 | { | 
 | 1498 | 	struct wpa_scan_res **_wa = (void *) a; | 
 | 1499 | 	struct wpa_scan_res **_wb = (void *) b; | 
 | 1500 | 	struct wpa_scan_res *wa = *_wa; | 
 | 1501 | 	struct wpa_scan_res *wb = *_wb; | 
 | 1502 | 	int uses_wps_a, uses_wps_b; | 
 | 1503 | 	struct wpabuf *wps_a, *wps_b; | 
 | 1504 | 	int res; | 
 | 1505 |  | 
 | 1506 | 	/* Optimization - check WPS IE existence before allocated memory and | 
 | 1507 | 	 * doing full reassembly. */ | 
 | 1508 | 	uses_wps_a = wpa_scan_get_vendor_ie(wa, WPS_IE_VENDOR_TYPE) != NULL; | 
 | 1509 | 	uses_wps_b = wpa_scan_get_vendor_ie(wb, WPS_IE_VENDOR_TYPE) != NULL; | 
 | 1510 | 	if (uses_wps_a && !uses_wps_b) | 
 | 1511 | 		return -1; | 
 | 1512 | 	if (!uses_wps_a && uses_wps_b) | 
 | 1513 | 		return 1; | 
 | 1514 |  | 
 | 1515 | 	if (uses_wps_a && uses_wps_b) { | 
 | 1516 | 		wps_a = wpa_scan_get_vendor_ie_multi(wa, WPS_IE_VENDOR_TYPE); | 
 | 1517 | 		wps_b = wpa_scan_get_vendor_ie_multi(wb, WPS_IE_VENDOR_TYPE); | 
 | 1518 | 		res = wps_ap_priority_compar(wps_a, wps_b); | 
 | 1519 | 		wpabuf_free(wps_a); | 
 | 1520 | 		wpabuf_free(wps_b); | 
 | 1521 | 		if (res) | 
 | 1522 | 			return res; | 
 | 1523 | 	} | 
 | 1524 |  | 
 | 1525 | 	/* | 
 | 1526 | 	 * Do not use current AP security policy as a sorting criteria during | 
 | 1527 | 	 * WPS provisioning step since the AP may get reconfigured at the | 
 | 1528 | 	 * completion of provisioning. | 
 | 1529 | 	 */ | 
 | 1530 |  | 
 | 1531 | 	/* all things being equal, use signal level; if signal levels are | 
 | 1532 | 	 * identical, use quality values since some drivers may only report | 
 | 1533 | 	 * that value and leave the signal level zero */ | 
 | 1534 | 	if (wb->level == wa->level) | 
 | 1535 | 		return wb->qual - wa->qual; | 
 | 1536 | 	return wb->level - wa->level; | 
 | 1537 | } | 
 | 1538 | #endif /* CONFIG_WPS */ | 
 | 1539 |  | 
 | 1540 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1541 | static void dump_scan_res(struct wpa_scan_results *scan_res) | 
 | 1542 | { | 
 | 1543 | #ifndef CONFIG_NO_STDOUT_DEBUG | 
 | 1544 | 	size_t i; | 
 | 1545 |  | 
 | 1546 | 	if (scan_res->res == NULL || scan_res->num == 0) | 
 | 1547 | 		return; | 
 | 1548 |  | 
 | 1549 | 	wpa_printf(MSG_EXCESSIVE, "Sorted scan results"); | 
 | 1550 |  | 
 | 1551 | 	for (i = 0; i < scan_res->num; i++) { | 
 | 1552 | 		struct wpa_scan_res *r = scan_res->res[i]; | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 1553 | 		u8 *pos; | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1554 | 		if ((r->flags & (WPA_SCAN_LEVEL_DBM | WPA_SCAN_NOISE_INVALID)) | 
 | 1555 | 		    == WPA_SCAN_LEVEL_DBM) { | 
 | 1556 | 			int snr = r->level - r->noise; | 
 | 1557 | 			wpa_printf(MSG_EXCESSIVE, MACSTR " freq=%d qual=%d " | 
| Dmitry Shmidt | f862328 | 2013-02-20 14:34:59 -0800 | [diff] [blame] | 1558 | 				   "noise=%d level=%d snr=%d%s flags=0x%x " | 
 | 1559 | 				   "age=%u", | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1560 | 				   MAC2STR(r->bssid), r->freq, r->qual, | 
 | 1561 | 				   r->noise, r->level, snr, | 
| Dmitry Shmidt | f862328 | 2013-02-20 14:34:59 -0800 | [diff] [blame] | 1562 | 				   snr >= GREAT_SNR ? "*" : "", r->flags, | 
 | 1563 | 				   r->age); | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1564 | 		} else { | 
 | 1565 | 			wpa_printf(MSG_EXCESSIVE, MACSTR " freq=%d qual=%d " | 
| Dmitry Shmidt | f862328 | 2013-02-20 14:34:59 -0800 | [diff] [blame] | 1566 | 				   "noise=%d level=%d flags=0x%x age=%u", | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1567 | 				   MAC2STR(r->bssid), r->freq, r->qual, | 
| Dmitry Shmidt | f862328 | 2013-02-20 14:34:59 -0800 | [diff] [blame] | 1568 | 				   r->noise, r->level, r->flags, r->age); | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1569 | 		} | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 1570 | 		pos = (u8 *) (r + 1); | 
 | 1571 | 		if (r->ie_len) | 
 | 1572 | 			wpa_hexdump(MSG_EXCESSIVE, "IEs", pos, r->ie_len); | 
 | 1573 | 		pos += r->ie_len; | 
 | 1574 | 		if (r->beacon_ie_len) | 
 | 1575 | 			wpa_hexdump(MSG_EXCESSIVE, "Beacon IEs", | 
 | 1576 | 				    pos, r->beacon_ie_len); | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1577 | 	} | 
 | 1578 | #endif /* CONFIG_NO_STDOUT_DEBUG */ | 
 | 1579 | } | 
 | 1580 |  | 
 | 1581 |  | 
| Dmitry Shmidt | a54fa5f | 2013-01-15 13:53:35 -0800 | [diff] [blame] | 1582 | /** | 
 | 1583 |  * wpa_supplicant_filter_bssid_match - Is the specified BSSID allowed | 
 | 1584 |  * @wpa_s: Pointer to wpa_supplicant data | 
 | 1585 |  * @bssid: BSSID to check | 
 | 1586 |  * Returns: 0 if the BSSID is filtered or 1 if not | 
 | 1587 |  * | 
 | 1588 |  * This function is used to filter out specific BSSIDs from scan reslts mainly | 
 | 1589 |  * for testing purposes (SET bssid_filter ctrl_iface command). | 
 | 1590 |  */ | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 1591 | int wpa_supplicant_filter_bssid_match(struct wpa_supplicant *wpa_s, | 
 | 1592 | 				      const u8 *bssid) | 
 | 1593 | { | 
 | 1594 | 	size_t i; | 
 | 1595 |  | 
 | 1596 | 	if (wpa_s->bssid_filter == NULL) | 
 | 1597 | 		return 1; | 
 | 1598 |  | 
 | 1599 | 	for (i = 0; i < wpa_s->bssid_filter_count; i++) { | 
 | 1600 | 		if (os_memcmp(wpa_s->bssid_filter + i * ETH_ALEN, bssid, | 
 | 1601 | 			      ETH_ALEN) == 0) | 
 | 1602 | 			return 1; | 
 | 1603 | 	} | 
 | 1604 |  | 
 | 1605 | 	return 0; | 
 | 1606 | } | 
 | 1607 |  | 
 | 1608 |  | 
 | 1609 | static void filter_scan_res(struct wpa_supplicant *wpa_s, | 
 | 1610 | 			    struct wpa_scan_results *res) | 
 | 1611 | { | 
 | 1612 | 	size_t i, j; | 
 | 1613 |  | 
 | 1614 | 	if (wpa_s->bssid_filter == NULL) | 
 | 1615 | 		return; | 
 | 1616 |  | 
 | 1617 | 	for (i = 0, j = 0; i < res->num; i++) { | 
 | 1618 | 		if (wpa_supplicant_filter_bssid_match(wpa_s, | 
 | 1619 | 						      res->res[i]->bssid)) { | 
 | 1620 | 			res->res[j++] = res->res[i]; | 
 | 1621 | 		} else { | 
 | 1622 | 			os_free(res->res[i]); | 
 | 1623 | 			res->res[i] = NULL; | 
 | 1624 | 		} | 
 | 1625 | 	} | 
 | 1626 |  | 
 | 1627 | 	if (res->num != j) { | 
 | 1628 | 		wpa_printf(MSG_DEBUG, "Filtered out %d scan results", | 
 | 1629 | 			   (int) (res->num - j)); | 
 | 1630 | 		res->num = j; | 
 | 1631 | 	} | 
 | 1632 | } | 
 | 1633 |  | 
 | 1634 |  | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1635 | /** | 
 | 1636 |  * wpa_supplicant_get_scan_results - Get scan results | 
 | 1637 |  * @wpa_s: Pointer to wpa_supplicant data | 
 | 1638 |  * @info: Information about what was scanned or %NULL if not available | 
 | 1639 |  * @new_scan: Whether a new scan was performed | 
 | 1640 |  * Returns: Scan results, %NULL on failure | 
 | 1641 |  * | 
 | 1642 |  * This function request the current scan results from the driver and updates | 
 | 1643 |  * the local BSS list wpa_s->bss. The caller is responsible for freeing the | 
 | 1644 |  * results with wpa_scan_results_free(). | 
 | 1645 |  */ | 
 | 1646 | struct wpa_scan_results * | 
 | 1647 | wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s, | 
 | 1648 | 				struct scan_info *info, int new_scan) | 
 | 1649 | { | 
 | 1650 | 	struct wpa_scan_results *scan_res; | 
 | 1651 | 	size_t i; | 
 | 1652 | 	int (*compar)(const void *, const void *) = wpa_scan_result_compar; | 
 | 1653 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1654 | 	scan_res = wpa_drv_get_scan_results2(wpa_s); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1655 | 	if (scan_res == NULL) { | 
 | 1656 | 		wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results"); | 
 | 1657 | 		return NULL; | 
 | 1658 | 	} | 
| Dmitry Shmidt | f862328 | 2013-02-20 14:34:59 -0800 | [diff] [blame] | 1659 | 	if (scan_res->fetch_time.sec == 0) { | 
 | 1660 | 		/* | 
 | 1661 | 		 * Make sure we have a valid timestamp if the driver wrapper | 
 | 1662 | 		 * does not set this. | 
 | 1663 | 		 */ | 
 | 1664 | 		os_get_time(&scan_res->fetch_time); | 
 | 1665 | 	} | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 1666 | 	filter_scan_res(wpa_s, scan_res); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1667 |  | 
 | 1668 | #ifdef CONFIG_WPS | 
 | 1669 | 	if (wpas_wps_in_progress(wpa_s)) { | 
 | 1670 | 		wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Order scan results with WPS " | 
 | 1671 | 			"provisioning rules"); | 
 | 1672 | 		compar = wpa_scan_result_wps_compar; | 
 | 1673 | 	} | 
 | 1674 | #endif /* CONFIG_WPS */ | 
 | 1675 |  | 
 | 1676 | 	qsort(scan_res->res, scan_res->num, sizeof(struct wpa_scan_res *), | 
 | 1677 | 	      compar); | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1678 | 	dump_scan_res(scan_res); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1679 |  | 
 | 1680 | 	wpa_bss_update_start(wpa_s); | 
 | 1681 | 	for (i = 0; i < scan_res->num; i++) | 
| Dmitry Shmidt | f862328 | 2013-02-20 14:34:59 -0800 | [diff] [blame] | 1682 | 		wpa_bss_update_scan_res(wpa_s, scan_res->res[i], | 
 | 1683 | 					&scan_res->fetch_time); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1684 | 	wpa_bss_update_end(wpa_s, info, new_scan); | 
 | 1685 |  | 
 | 1686 | 	return scan_res; | 
 | 1687 | } | 
 | 1688 |  | 
 | 1689 |  | 
| Dmitry Shmidt | a54fa5f | 2013-01-15 13:53:35 -0800 | [diff] [blame] | 1690 | /** | 
 | 1691 |  * wpa_supplicant_update_scan_results - Update scan results from the driver | 
 | 1692 |  * @wpa_s: Pointer to wpa_supplicant data | 
 | 1693 |  * Returns: 0 on success, -1 on failure | 
 | 1694 |  * | 
 | 1695 |  * This function updates the BSS table within wpa_supplicant based on the | 
 | 1696 |  * currently available scan results from the driver without requesting a new | 
 | 1697 |  * scan. This is used in cases where the driver indicates an association | 
 | 1698 |  * (including roaming within ESS) and wpa_supplicant does not yet have the | 
 | 1699 |  * needed information to complete the connection (e.g., to perform validation | 
 | 1700 |  * steps in 4-way handshake). | 
 | 1701 |  */ | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1702 | int wpa_supplicant_update_scan_results(struct wpa_supplicant *wpa_s) | 
 | 1703 | { | 
 | 1704 | 	struct wpa_scan_results *scan_res; | 
 | 1705 | 	scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0); | 
 | 1706 | 	if (scan_res == NULL) | 
 | 1707 | 		return -1; | 
 | 1708 | 	wpa_scan_results_free(scan_res); | 
 | 1709 |  | 
 | 1710 | 	return 0; | 
 | 1711 | } | 
| Dmitry Shmidt | 3a787e6 | 2013-01-17 10:32:35 -0800 | [diff] [blame] | 1712 |  | 
 | 1713 |  | 
 | 1714 | /** | 
 | 1715 |  * scan_only_handler - Reports scan results | 
 | 1716 |  */ | 
 | 1717 | void scan_only_handler(struct wpa_supplicant *wpa_s, | 
 | 1718 | 		       struct wpa_scan_results *scan_res) | 
 | 1719 | { | 
| Dmitry Shmidt | 4b9d52f | 2013-02-05 17:44:43 -0800 | [diff] [blame] | 1720 | 	wpa_dbg(wpa_s, MSG_DEBUG, "Scan-only results received"); | 
| Dmitry Shmidt | 3a787e6 | 2013-01-17 10:32:35 -0800 | [diff] [blame] | 1721 | 	wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS); | 
 | 1722 | 	wpas_notify_scan_results(wpa_s); | 
| Dmitry Shmidt | 4b9d52f | 2013-02-05 17:44:43 -0800 | [diff] [blame] | 1723 | 	wpas_notify_scan_done(wpa_s, 1); | 
| Dmitry Shmidt | 3a787e6 | 2013-01-17 10:32:35 -0800 | [diff] [blame] | 1724 | } | 
| Dmitry Shmidt | 37d4d6a | 2013-03-18 13:09:42 -0700 | [diff] [blame] | 1725 |  | 
 | 1726 |  | 
 | 1727 | int wpas_scan_scheduled(struct wpa_supplicant *wpa_s) | 
 | 1728 | { | 
 | 1729 | 	return eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL); | 
 | 1730 | } |