scan.c revision 20df807cb700c516ff346732f1bc8f914d0d26d8
18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * WPA Supplicant - Scanning
38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
58d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This program is free software; you can redistribute it and/or modify
68d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * it under the terms of the GNU General Public License version 2 as
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * published by the Free Software Foundation.
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Alternatively, this software may be distributed under the terms of BSD
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * license.
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * See README and COPYING for more details.
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/includes.h"
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/common.h"
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/eloop.h"
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common/ieee802_11_defs.h"
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "config.h"
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wpa_supplicant_i.h"
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "driver_i.h"
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "mlme.h"
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wps_supplicant.h"
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "p2p_supplicant.h"
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "p2p/p2p.h"
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "notify.h"
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "bss.h"
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "scan.h"
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s)
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_ssid *ssid;
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data data;
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ssid = wpa_supplicant_get_ssid(wpa_s);
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ssid == NULL)
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->current_ssid == NULL) {
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_s->current_ssid = ssid;
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wpa_s->current_ssid != NULL)
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpas_notify_network_changed(wpa_s);
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_initiate_eapol(wpa_s);
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_dbg(wpa_s, MSG_DEBUG, "Already associated with a configured "
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		"network - generating associated event");
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&data, 0, sizeof(data));
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(wpa_s, EVENT_ASSOC, &data);
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpas_wps_in_use(struct wpa_config *conf,
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   enum wps_request_type *req_type)
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_ssid *ssid;
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int wps = 0;
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (ssid = conf->ssid; ssid; ssid = ssid->next) {
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS))
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps = 1;
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*req_type = wpas_wps_get_req_type(ssid);
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!ssid->eap.phase1)
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(ssid->eap.phase1, "pbc=1"))
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return 2;
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return wps;
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS */
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wpa_supplicant_enabled_networks(struct wpa_config *conf)
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_ssid *ssid = conf->ssid;
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int count = 0;
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (ssid) {
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!ssid->disabled)
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			count++;
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ssid = ssid->next;
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return count;
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_supplicant_assoc_try(struct wpa_supplicant *wpa_s,
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     struct wpa_ssid *ssid)
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (ssid) {
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!ssid->disabled)
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ssid = ssid->next;
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* ap_scan=2 mode - try to associate with each SSID. */
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ssid == NULL) {
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_dbg(wpa_s, MSG_DEBUG, "wpa_supplicant_assoc_try: Reached "
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			"end of scan list - go back to beginning");
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_supplicant_req_scan(wpa_s, 0, 0);
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ssid->next) {
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Continue from the next SSID on the next attempt. */
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_s->prev_scan_ssid = ssid;
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Start from the beginning of the SSID list. */
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_associate(wpa_s, NULL, ssid);
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int int_array_len(const int *a)
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; a && a[i]; i++)
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		;
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return i;
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void int_array_concat(int **res, const int *a)
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int reslen, alen, i;
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int *n;
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reslen = int_array_len(*res);
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	alen = int_array_len(a);
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	n = os_realloc(*res, (reslen + alen + 1) * sizeof(int));
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (n == NULL) {
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(*res);
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*res = NULL;
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i <= alen; i++)
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		n[reslen + i] = a[i];
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*res = n;
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int freq_cmp(const void *a, const void *b)
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int _a = *(int *) a;
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int _b = *(int *) b;
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (_a == 0)
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 1;
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (_b == 0)
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return _a - _b;
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void int_array_sort_unique(int *a)
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int alen;
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i, j;
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (a == NULL)
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	alen = int_array_len(a);
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	qsort(a, alen, sizeof(int), freq_cmp);
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	i = 0;
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	j = 1;
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (a[i] && a[j]) {
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (a[i] == a[j]) {
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			j++;
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		a[++i] = a[j++];
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (a[i])
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		i++;
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	a[i] = 0;
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				struct wpa_driver_scan_params *params)
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_notify_scanning(wpa_s, 1);
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = ieee80211_sta_req_scan(wpa_s, params);
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = wpa_drv_scan(wpa_s, params);
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_supplicant_notify_scanning(wpa_s, 0);
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpas_notify_scan_done(wpa_s, 0);
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_s->scan_runs++;
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpa_driver_scan_filter *
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtwpa_supplicant_build_filter_ssids(struct wpa_config *conf, size_t *num_ssids)
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_scan_filter *ssids;
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_ssid *ssid;
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t count;
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*num_ssids = 0;
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!conf->filter_ssids)
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (count = 0, ssid = conf->ssid; ssid; ssid = ssid->next) {
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ssid->ssid && ssid->ssid_len)
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			count++;
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (count == 0)
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ssids = os_zalloc(count * sizeof(struct wpa_driver_scan_filter));
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ssids == NULL)
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (ssid = conf->ssid; ssid; ssid = ssid->next) {
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!ssid->ssid || !ssid->ssid_len)
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(ssids[*num_ssids].ssid, ssid->ssid, ssid->ssid_len);
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ssids[*num_ssids].ssid_len = ssid->ssid_len;
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		(*num_ssids)++;
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ssids;
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_supplicant *wpa_s = eloop_ctx;
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_ssid *ssid;
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int scan_req = 0, ret;
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *wps_ie = NULL;
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int wps = 0;
2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO;
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS */
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_scan_params params;
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t max_ssids;
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enum wpa_states prev_state;
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - interface disabled");
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->disconnected && !wpa_s->scan_req) {
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!wpa_supplicant_enabled_networks(wpa_s->conf) &&
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    !wpa_s->scan_req) {
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks - do not scan");
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->conf->ap_scan != 0 &&
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED)) {
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_dbg(wpa_s, MSG_DEBUG, "Using wired authentication - "
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			"overriding ap_scan configuration");
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_s->conf->ap_scan = 0;
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpas_notify_ap_scan_changed(wpa_s);
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->conf->ap_scan == 0) {
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_supplicant_gen_assoc_event(wpa_s);
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) ||
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wpa_s->conf->ap_scan == 2)
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		max_ssids = 1;
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else {
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		max_ssids = wpa_s->max_scan_ssids;
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (max_ssids > WPAS_MAX_SCAN_SSIDS)
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			max_ssids = WPAS_MAX_SCAN_SSIDS;
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps = wpas_wps_in_use(wpa_s->conf, &req_type);
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS */
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	scan_req = wpa_s->scan_req;
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_s->scan_req = 0;
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&params, 0, sizeof(params));
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	prev_state = wpa_s->wpa_state;
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->wpa_state == WPA_DISCONNECTED ||
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wpa_s->wpa_state == WPA_INACTIVE)
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_supplicant_set_state(wpa_s, WPA_SCANNING);
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Find the starting point from which to continue scanning */
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ssid = wpa_s->conf->ssid;
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->prev_scan_ssid != WILDCARD_SSID_SCAN) {
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		while (ssid) {
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (ssid == wpa_s->prev_scan_ssid) {
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				ssid = ssid->next;
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				break;
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ssid = ssid->next;
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (scan_req != 2 && (wpa_s->conf->ap_scan == 2 ||
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      wpa_s->connect_without_scan)) {
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_s->connect_without_scan = 0;
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_supplicant_assoc_try(wpa_s, ssid);
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (wpa_s->conf->ap_scan == 2) {
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * User-initiated scan request in ap_scan == 2; scan with
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * wildcard SSID.
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ssid = NULL;
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct wpa_ssid *start = ssid, *tssid;
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int freqs_set = 0;
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ssid == NULL && max_ssids > 1)
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ssid = wpa_s->conf->ssid;
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		while (ssid) {
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (!ssid->disabled && ssid->scan_ssid) {
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID",
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						  ssid->ssid, ssid->ssid_len);
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				params.ssids[params.num_ssids].ssid =
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					ssid->ssid;
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				params.ssids[params.num_ssids].ssid_len =
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					ssid->ssid_len;
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				params.num_ssids++;
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				if (params.num_ssids + 1 >= max_ssids)
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					break;
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ssid = ssid->next;
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (ssid == start)
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				break;
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (ssid == NULL && max_ssids > 1 &&
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    start != wpa_s->conf->ssid)
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				ssid = wpa_s->conf->ssid;
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		for (tssid = wpa_s->conf->ssid; tssid; tssid = tssid->next) {
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (tssid->disabled)
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				continue;
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if ((params.freqs || !freqs_set) && tssid->scan_freq) {
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				int_array_concat(&params.freqs,
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 tssid->scan_freq);
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			} else {
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				os_free(params.freqs);
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				params.freqs = NULL;
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			freqs_set = 1;
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int_array_sort_unique(params.freqs);
3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ssid) {
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_s->prev_scan_ssid = ssid;
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (max_ssids > 1) {
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_dbg(wpa_s, MSG_DEBUG, "Include wildcard SSID in "
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				"the scan request");
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			params.num_ssids++;
3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for specific "
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			"SSID(s)");
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		params.num_ssids++;
3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for wildcard "
3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			"SSID");
3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_P2P
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_s->wps->dev.p2p = 1;
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!wps) {
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps = 1;
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		req_type = WPS_REQ_ENROLLEE_INFO;
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params.freqs == NULL && wpa_s->p2p_in_provisioning &&
3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wpa_s->go_params) {
3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Optimize provisioning state scan based on GO information */
3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wpa_s->p2p_in_provisioning < 5 &&
4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    wpa_s->go_params->freq > 0) {
4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only GO "
4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				"preferred frequency %d MHz",
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_s->go_params->freq);
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			params.freqs = os_zalloc(2 * sizeof(int));
4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (params.freqs)
4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				params.freqs[0] = wpa_s->go_params->freq;
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else if (wpa_s->p2p_in_provisioning < 8 &&
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   wpa_s->go_params->freq_list[0]) {
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only common "
4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				"channels");
4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			int_array_concat(&params.freqs,
4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 wpa_s->go_params->freq_list);
4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (params.freqs)
4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				int_array_sort_unique(params.freqs);
4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_s->p2p_in_provisioning++;
4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_P2P */
4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS
4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params.freqs == NULL && wpa_s->after_wps && wpa_s->wps_freq) {
4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Optimize post-provisioning scan based on channel used
4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * during provisioning.
4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Scan only frequency %u MHz "
4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			"that was used during provisioning", wpa_s->wps_freq);
4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		params.freqs = os_zalloc(2 * sizeof(int));
4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (params.freqs)
4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			params.freqs[0] = wpa_s->wps_freq;
4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_s->after_wps--;
4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps) {
4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_ie = wps_build_probe_req_ie(wps == 2, &wpa_s->wps->dev,
4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						wpa_s->wps->uuid, req_type,
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						0, NULL);
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wps_ie) {
4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			params.extra_ies = wpabuf_head(wps_ie);
4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			params.extra_ies_len = wpabuf_len(wps_ie);
4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS */
4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_P2P
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_ie) {
4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wpabuf_resize(&wps_ie, 100) == 0) {
4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpas_p2p_scan_ie(wpa_s, wps_ie);
4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			params.extra_ies = wpabuf_head(wps_ie);
4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			params.extra_ies_len = wpabuf_len(wps_ie);
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_P2P */
4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params.freqs == NULL && wpa_s->next_scan_freqs) {
4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on previously "
4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			"generated frequency list");
4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		params.freqs = wpa_s->next_scan_freqs;
4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else
4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(wpa_s->next_scan_freqs);
4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_s->next_scan_freqs = NULL;
4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	params.filter_ssids = wpa_supplicant_build_filter_ssids(
4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_s->conf, &params.num_filter_ssids);
4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = wpa_supplicant_trigger_scan(wpa_s, &params);
4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(wps_ie);
4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(params.freqs);
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(params.filter_ssids);
4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate AP scan");
4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (prev_state != wpa_s->wpa_state)
4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_supplicant_set_state(wpa_s, prev_state);
4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_supplicant_req_scan(wpa_s, 1, 0);
4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_supplicant_req_scan - Schedule a scan for neighboring access points
4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @wpa_s: Pointer to wpa_supplicant data
4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sec: Number of seconds after which to scan
4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @usec: Number of microseconds after which to scan
4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This function is used to schedule a scan for neighboring access points after
4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * the specified time.
4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* If there's at least one network that should be specifically scanned
4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * then don't cancel the scan and reschedule.  Some drivers do
4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * background scanning which generates frequent scan results, and that
4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * causes the specific SSID scan to get continually pushed back and
4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * never happen, which causes hidden APs to never get probe-scanned.
4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL) &&
4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wpa_s->conf->ap_scan == 1) {
5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct wpa_ssid *ssid = wpa_s->conf->ssid;
5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		while (ssid) {
5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (!ssid->disabled && ssid->scan_ssid)
5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				break;
5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ssid = ssid->next;
5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ssid) {
5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_dbg(wpa_s, MSG_DEBUG, "Not rescheduling scan to "
5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			        "ensure that specific SSID scans occur");
5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return;
5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_dbg(wpa_s, MSG_DEBUG, "Setting scan request: %d sec %d usec",
5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sec, usec);
5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL);
5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_supplicant_cancel_scan - Cancel a scheduled scan request
5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @wpa_s: Pointer to wpa_supplicant data
5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This function is used to cancel a scan request scheduled with
5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_supplicant_req_scan().
5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s)
5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling scan request");
5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
53220df807cb700c516ff346732f1bc8f914d0d26d8Dmitry Shmidt	wpa_supplicant_notify_scanning(wpa_s, 0);
5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s,
5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    int scanning)
5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->scanning != scanning) {
5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_s->scanning = scanning;
5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpas_notify_scanning(wpa_s);
5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_scan_get_max_rate(const struct wpa_scan_res *res)
5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int rate = 0;
5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *ie;
5508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ie = wpa_scan_get_ie(res, WLAN_EID_SUPP_RATES);
5538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; ie && i < ie[1]; i++) {
5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if ((ie[i + 2] & 0x7f) > rate)
5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			rate = ie[i + 2] & 0x7f;
5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ie = wpa_scan_get_ie(res, WLAN_EID_EXT_SUPP_RATES);
5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; ie && i < ie[1]; i++) {
5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if ((ie[i + 2] & 0x7f) > rate)
5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			rate = ie[i + 2] & 0x7f;
5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return rate;
5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie)
5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *end, *pos;
5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = (const u8 *) (res + 1);
5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = pos + res->ie_len;
5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (pos + 1 < end) {
5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (pos + 2 + pos[1] > end)
5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (pos[0] == ie)
5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return pos;
5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += 2 + pos[1];
5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res,
5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  u32 vendor_type)
5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *end, *pos;
5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = (const u8 *) (res + 1);
5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = pos + res->ie_len;
5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (pos + 1 < end) {
5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (pos + 2 + pos[1] > end)
5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    vendor_type == WPA_GET_BE32(&pos[2]))
6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return pos;
6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += 2 + pos[1];
6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					     u32 vendor_type)
6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *buf;
6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *end, *pos;
6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf = wpabuf_alloc(res->ie_len);
6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (buf == NULL)
6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = (const u8 *) (res + 1);
6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = pos + res->ie_len;
6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (pos + 1 < end) {
6228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (pos + 2 + pos[1] > end)
6238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
6248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    vendor_type == WPA_GET_BE32(&pos[2]))
6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += 2 + pos[1];
6288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpabuf_len(buf) == 0) {
6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(buf);
6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		buf = NULL;
6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return buf;
6368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * wpa_scan_get_vendor_ie_multi_beacon(
6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct wpa_scan_res *res, u32 vendor_type)
6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *buf;
6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *end, *pos;
6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res->beacon_ie_len == 0)
6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf = wpabuf_alloc(res->beacon_ie_len);
6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (buf == NULL)
6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = (const u8 *) (res + 1);
6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += res->ie_len;
6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = pos + res->beacon_ie_len;
6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (pos + 1 < end) {
6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (pos + 2 + pos[1] > end)
6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    vendor_type == WPA_GET_BE32(&pos[2]))
6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += 2 + pos[1];
6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpabuf_len(buf) == 0) {
6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(buf);
6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		buf = NULL;
6678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return buf;
6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* Compare function for sorting scan results. Return >0 if @b is considered
6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * better. */
6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_scan_result_compar(const void *a, const void *b)
6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_scan_res **_wa = (void *) a;
6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_scan_res **_wb = (void *) b;
6798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_scan_res *wa = *_wa;
6808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_scan_res *wb = *_wb;
6818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int wpa_a, wpa_b, maxrate_a, maxrate_b;
6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* WPA/WPA2 support preferred */
6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_a = wpa_scan_get_vendor_ie(wa, WPA_IE_VENDOR_TYPE) != NULL ||
6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_scan_get_ie(wa, WLAN_EID_RSN) != NULL;
6868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_b = wpa_scan_get_vendor_ie(wb, WPA_IE_VENDOR_TYPE) != NULL ||
6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_scan_get_ie(wb, WLAN_EID_RSN) != NULL;
6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_b && !wpa_a)
6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 1;
6918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!wpa_b && wpa_a)
6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* privacy support preferred */
6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if ((wa->caps & IEEE80211_CAP_PRIVACY) == 0 &&
6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    (wb->caps & IEEE80211_CAP_PRIVACY))
6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 1;
6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if ((wa->caps & IEEE80211_CAP_PRIVACY) &&
6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    (wb->caps & IEEE80211_CAP_PRIVACY) == 0)
7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* best/max rate preferred if signal level close enough XXX */
7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if ((wa->level && wb->level && abs(wb->level - wa->level) < 5) ||
7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    (wa->qual && wb->qual && abs(wb->qual - wa->qual) < 10)) {
7058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		maxrate_a = wpa_scan_get_max_rate(wa);
7068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		maxrate_b = wpa_scan_get_max_rate(wb);
7078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (maxrate_a != maxrate_b)
7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return maxrate_b - maxrate_a;
7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* use freq for channel preference */
7128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* all things being equal, use signal level; if signal levels are
7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * identical, use quality values since some drivers may only report
7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * that value and leave the signal level zero */
7168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wb->level == wa->level)
7178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return wb->qual - wa->qual;
7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return wb->level - wa->level;
7198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS
7238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* Compare function for sorting scan results when searching a WPS AP for
7248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * provisioning. Return >0 if @b is considered better. */
7258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_scan_result_wps_compar(const void *a, const void *b)
7268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_scan_res **_wa = (void *) a;
7288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_scan_res **_wb = (void *) b;
7298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_scan_res *wa = *_wa;
7308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_scan_res *wb = *_wb;
7318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int uses_wps_a, uses_wps_b;
7328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *wps_a, *wps_b;
7338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int res;
7348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Optimization - check WPS IE existence before allocated memory and
7368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * doing full reassembly. */
7378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	uses_wps_a = wpa_scan_get_vendor_ie(wa, WPS_IE_VENDOR_TYPE) != NULL;
7388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	uses_wps_b = wpa_scan_get_vendor_ie(wb, WPS_IE_VENDOR_TYPE) != NULL;
7398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (uses_wps_a && !uses_wps_b)
7408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
7418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!uses_wps_a && uses_wps_b)
7428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 1;
7438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (uses_wps_a && uses_wps_b) {
7458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_a = wpa_scan_get_vendor_ie_multi(wa, WPS_IE_VENDOR_TYPE);
7468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_b = wpa_scan_get_vendor_ie_multi(wb, WPS_IE_VENDOR_TYPE);
7478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		res = wps_ap_priority_compar(wps_a, wps_b);
7488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(wps_a);
7498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(wps_b);
7508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (res)
7518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return res;
7528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
7558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Do not use current AP security policy as a sorting criteria during
7568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * WPS provisioning step since the AP may get reconfigured at the
7578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * completion of provisioning.
7588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
7598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* all things being equal, use signal level; if signal levels are
7618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * identical, use quality values since some drivers may only report
7628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * that value and leave the signal level zero */
7638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wb->level == wa->level)
7648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return wb->qual - wa->qual;
7658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return wb->level - wa->level;
7668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS */
7688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
7718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_supplicant_get_scan_results - Get scan results
7728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @wpa_s: Pointer to wpa_supplicant data
7738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @info: Information about what was scanned or %NULL if not available
7748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @new_scan: Whether a new scan was performed
7758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Scan results, %NULL on failure
7768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
7778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This function request the current scan results from the driver and updates
7788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * the local BSS list wpa_s->bss. The caller is responsible for freeing the
7798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * results with wpa_scan_results_free().
7808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
7818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpa_scan_results *
7828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtwpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,
7838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				struct scan_info *info, int new_scan)
7848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_scan_results *scan_res;
7868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t i;
7878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int (*compar)(const void *, const void *) = wpa_scan_result_compar;
7888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
7908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		scan_res = ieee80211_sta_get_scan_results(wpa_s);
7918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
7928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		scan_res = wpa_drv_get_scan_results2(wpa_s);
7938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (scan_res == NULL) {
7948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results");
7958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
7968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS
7998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpas_wps_in_progress(wpa_s)) {
8008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Order scan results with WPS "
8018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			"provisioning rules");
8028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		compar = wpa_scan_result_wps_compar;
8038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS */
8058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	qsort(scan_res->res, scan_res->num, sizeof(struct wpa_scan_res *),
8078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	      compar);
8088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_bss_update_start(wpa_s);
8108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < scan_res->num; i++)
8118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_bss_update_scan_res(wpa_s, scan_res->res[i]);
8128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_bss_update_end(wpa_s, info, new_scan);
8138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return scan_res;
8158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wpa_supplicant_update_scan_results(struct wpa_supplicant *wpa_s)
8198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_scan_results *scan_res;
8218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0);
8228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (scan_res == NULL)
8238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
8248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_scan_results_free(scan_res);
8258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
8278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wpa_scan_results_free(struct wpa_scan_results *res)
8318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t i;
8338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res == NULL)
8358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
8368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < res->num; i++)
8388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(res->res[i]);
8398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(res->res);
8408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(res);
8418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
842