driver_nl80211_scan.c revision f8467ce3721b7154974a1f8a6e0dff54d4493f4d
16c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt/*
26c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * Driver interaction with Linux nl80211/cfg80211 - Scanning
36c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
46c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
56c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * Copyright (c) 2009-2010, Atheros Communications
66c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt *
76c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * This software may be distributed under the terms of the BSD license.
86c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * See README for more details.
96c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt */
106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "includes.h"
126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include <netlink/genl/genl.h>
136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "utils/common.h"
156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "utils/eloop.h"
166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "common/ieee802_11_defs.h"
176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "driver_nl80211.h"
186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int get_noise_for_scan_results(struct nl_msg *msg, void *arg)
216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	};
296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_scan_results *scan_results = arg;
306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_scan_res *scan_res;
316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	size_t i;
326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!tb[NL80211_ATTR_SURVEY_INFO]) {
376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Survey data missing");
386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			     tb[NL80211_ATTR_SURVEY_INFO],
436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			     survey_policy)) {
446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Failed to parse nested "
456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "attributes");
466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!sinfo[NL80211_SURVEY_INFO_NOISE])
506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	for (i = 0; i < scan_results->num; ++i) {
566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		scan_res = scan_results->res[i];
576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (!scan_res)
586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			continue;
596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if ((int) nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    scan_res->freq)
616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			continue;
626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (!(scan_res->flags & WPA_SCAN_NOISE_INVALID))
636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			continue;
646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		scan_res->noise = (s8)
656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		scan_res->flags &= ~WPA_SCAN_NOISE_INVALID;
676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return NL_SKIP;
706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_get_noise_for_scan_results(
746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv,
756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_scan_results *scan_res)
766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return send_and_recv_msgs(drv, msg, get_noise_for_scan_results,
816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  scan_res);
826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt/**
866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * wpa_driver_nl80211_scan_timeout - Scan timeout to report scan completion
876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * @eloop_ctx: Driver private data
886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * @timeout_ctx: ctx argument given to wpa_driver_nl80211_init()
896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt *
906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * This function can be used as registered timeout when starting a scan to
916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * generate a scan completed event if the driver does not report this.
926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt */
936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtvoid wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = eloop_ctx;
966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) {
976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_driver_nl80211_set_mode(drv->first_bss,
986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					    drv->ap_scan_as_station);
996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
1006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
1016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
1026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
1036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
1046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic struct nl_msg *
1076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtnl80211_scan_common(struct i802_bss *bss, u8 cmd,
1086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    struct wpa_driver_scan_params *params)
1096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
1106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
1116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
1126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	size_t i;
1136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	u32 scan_flags = 0;
1146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_cmd_msg(bss, 0, cmd);
1166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!msg)
1176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NULL;
1186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->num_ssids) {
1206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		struct nlattr *ssids;
1216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ssids = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS);
1236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (ssids == NULL)
1246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
1256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		for (i = 0; i < params->num_ssids; i++) {
1266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
1276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					  params->ssids[i].ssid,
1286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					  params->ssids[i].ssid_len);
1296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			if (nla_put(msg, i + 1, params->ssids[i].ssid_len,
1306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				    params->ssids[i].ssid))
1316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				goto fail;
1326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
1336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nla_nest_end(msg, ssids);
1346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
1356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->extra_ies) {
1376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",
1386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    params->extra_ies, params->extra_ies_len);
1396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put(msg, NL80211_ATTR_IE, params->extra_ies_len,
1406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    params->extra_ies))
1416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
1426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
1436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->freqs) {
1456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		struct nlattr *freqs;
1466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
1476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (freqs == NULL)
1486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
1496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		for (i = 0; params->freqs[i]; i++) {
1506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
1516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   "MHz", params->freqs[i]);
1526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			if (nla_put_u32(msg, i + 1, params->freqs[i]))
1536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				goto fail;
1546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
1556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nla_nest_end(msg, freqs);
1566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
1576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	os_free(drv->filter_ssids);
1596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->filter_ssids = params->filter_ssids;
1606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	params->filter_ssids = NULL;
1616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->num_filter_ssids = params->num_filter_ssids;
1626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->only_new_results) {
1646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Add NL80211_SCAN_FLAG_FLUSH");
1656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		scan_flags |= NL80211_SCAN_FLAG_FLUSH;
1666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
1676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->low_priority && drv->have_low_prio_scan) {
1696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
1706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: Add NL80211_SCAN_FLAG_LOW_PRIORITY");
1716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		scan_flags |= NL80211_SCAN_FLAG_LOW_PRIORITY;
1726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
1736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->mac_addr_rand) {
1756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
1766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: Add NL80211_SCAN_FLAG_RANDOM_ADDR");
1776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		scan_flags |= NL80211_SCAN_FLAG_RANDOM_ADDR;
1786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (params->mac_addr) {
1806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: MAC address: " MACSTR,
1816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   MAC2STR(params->mac_addr));
1826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN,
1836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				    params->mac_addr))
1846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				goto fail;
1856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
1866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (params->mac_addr_mask) {
1886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: MAC address mask: "
1896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   MACSTR, MAC2STR(params->mac_addr_mask));
1906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			if (nla_put(msg, NL80211_ATTR_MAC_MASK, ETH_ALEN,
1916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				    params->mac_addr_mask))
1926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				goto fail;
1936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
1946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
1956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (scan_flags &&
1976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, scan_flags))
1986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
1996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return msg;
2016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtfail:
2036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nlmsg_free(msg);
2046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return NULL;
2056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
2066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt/**
2096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * wpa_driver_nl80211_scan - Request the driver to initiate scan
2106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * @bss: Pointer to private driver data from wpa_driver_nl80211_init()
2116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * @params: Scan parameters
2126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * Returns: 0 on success, -1 on failure
2136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt */
2146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtint wpa_driver_nl80211_scan(struct i802_bss *bss,
2156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    struct wpa_driver_scan_params *params)
2166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
2176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
2186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret = -1, timeout;
2196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg = NULL;
2206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request");
2226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->scan_for_auth = 0;
2236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_scan_common(bss, NL80211_CMD_TRIGGER_SCAN, params);
2256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!msg)
2266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
2276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->p2p_probe) {
2296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		struct nlattr *rates;
2306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates");
2326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		rates = nla_nest_start(msg, NL80211_ATTR_SCAN_SUPP_RATES);
2346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (rates == NULL)
2356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
2366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		/*
2386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates
2396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * by masking out everything else apart from the OFDM rates 6,
2406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz
2416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * rates are left enabled.
2426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 */
2436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put(msg, NL80211_BAND_2GHZ, 8,
2446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    "\x0c\x12\x18\x24\x30\x48\x60\x6c"))
2456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
2466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nla_nest_end(msg, rates);
2476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put_flag(msg, NL80211_ATTR_TX_NO_CCK_RATE))
2496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
2506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
2516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
2536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = NULL;
2546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret) {
2556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
2566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "(%s)", ret, strerror(-ret));
2576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (drv->hostapd && is_ap_interface(drv->nlmode)) {
2586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			enum nl80211_iftype old_mode = drv->nlmode;
2596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			/*
2616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			 * mac80211 does not allow scan requests in AP mode, so
2626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			 * try to do this in station mode.
2636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			 */
2646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			if (wpa_driver_nl80211_set_mode(
2656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				    bss, NL80211_IFTYPE_STATION))
2666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				goto fail;
2676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			if (wpa_driver_nl80211_scan(bss, params)) {
2692f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt				wpa_driver_nl80211_set_mode(bss, old_mode);
2706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				goto fail;
2716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			}
2726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			/* Restore AP mode when processing scan results */
2746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			drv->ap_scan_as_station = old_mode;
2756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			ret = 0;
2766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		} else
2776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
2786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
2796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->scan_state = SCAN_REQUESTED;
2816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* Not all drivers generate "scan completed" wireless event, so try to
2826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 * read results after a timeout. */
2836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	timeout = 10;
2846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (drv->scan_complete_events) {
2856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		/*
2866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * The driver seems to deliver events to notify when scan is
2876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * complete, so use longer timeout to avoid race conditions
2886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * with scanning and following association request.
2896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 */
2906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		timeout = 30;
2916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
2926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
2936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   "seconds", ret, timeout);
2946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
2956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout,
2966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			       drv, drv->ctx);
2976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtfail:
2996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nlmsg_free(msg);
3006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return ret;
3016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
3026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
3036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
3046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt/**
3056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * wpa_driver_nl80211_sched_scan - Initiate a scheduled scan
3066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
3076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * @params: Scan parameters
3086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * @interval: Interval between scan cycles in milliseconds
3096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * Returns: 0 on success, -1 on failure or if not supported
3106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt */
3116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtint wpa_driver_nl80211_sched_scan(void *priv,
3126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  struct wpa_driver_scan_params *params,
3136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  u32 interval)
3146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
3156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
3166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
3176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret = -1;
3186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
3196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	size_t i;
3206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
3216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: sched_scan request");
3226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
3236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#ifdef ANDROID
3246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!drv->capa.sched_scan_supported)
3256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return android_pno_start(bss, params);
3266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#endif /* ANDROID */
3276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
3286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_scan_common(bss, NL80211_CMD_START_SCHED_SCAN, params);
3296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!msg ||
3306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, interval))
3316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
3326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
3336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if ((drv->num_filter_ssids &&
3346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (int) drv->num_filter_ssids <= drv->capa.max_match_sets) ||
3356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    params->filter_rssi) {
3366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		struct nlattr *match_sets;
3376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		match_sets = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH);
3386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (match_sets == NULL)
3396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
3406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
3416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		for (i = 0; i < drv->num_filter_ssids; i++) {
3426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			struct nlattr *match_set_ssid;
3436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_hexdump_ascii(MSG_MSGDUMP,
3446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					  "nl80211: Sched scan filter SSID",
3456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					  drv->filter_ssids[i].ssid,
3466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					  drv->filter_ssids[i].ssid_len);
3476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
3486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			match_set_ssid = nla_nest_start(msg, i + 1);
3496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			if (match_set_ssid == NULL ||
3506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    nla_put(msg, NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
3516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				    drv->filter_ssids[i].ssid_len,
3526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				    drv->filter_ssids[i].ssid) ||
3536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    (params->filter_rssi &&
3546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			     nla_put_u32(msg,
3556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					 NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
3566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					 params->filter_rssi)))
3576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				goto fail;
3586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
3596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			nla_nest_end(msg, match_set_ssid);
3606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
3616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
3626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		/*
3636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * Due to backward compatibility code, newer kernels treat this
3646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * matchset (with only an RSSI filter) as the default for all
3656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * other matchsets, unless it's the only one, in which case the
3666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * matchset will actually allow all SSIDs above the RSSI.
3676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 */
3686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (params->filter_rssi) {
3696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			struct nlattr *match_set_rssi;
3706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			match_set_rssi = nla_nest_start(msg, 0);
3716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			if (match_set_rssi == NULL ||
3726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    nla_put_u32(msg, NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
3736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					params->filter_rssi))
3746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				goto fail;
3756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_MSGDUMP,
3766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   "nl80211: Sched scan RSSI filter %d dBm",
3776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   params->filter_rssi);
3786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			nla_nest_end(msg, match_set_rssi);
3796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
3806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
3816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nla_nest_end(msg, match_sets);
3826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
3836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
3846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
3856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
3866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* TODO: if we get an error here, we should fall back to normal scan */
3876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
3886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = NULL;
3896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret) {
3906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Sched scan start failed: "
3916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "ret=%d (%s)", ret, strerror(-ret));
3926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
3936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
3946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
3956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Sched scan requested (ret=%d) - "
3966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   "scan interval %d msec", ret, interval);
3976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
3986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtfail:
3996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nlmsg_free(msg);
4006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return ret;
4016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
4026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt/**
4056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * wpa_driver_nl80211_stop_sched_scan - Stop a scheduled scan
4066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
4076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * Returns: 0 on success, -1 on failure or if not supported
4086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt */
4096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtint wpa_driver_nl80211_stop_sched_scan(void *priv)
4106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
4116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
4126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
4136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret;
4146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
4156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#ifdef ANDROID
4176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!drv->capa.sched_scan_supported)
4186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return android_pno_stop(bss);
4196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#endif /* ANDROID */
4206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_STOP_SCHED_SCAN);
4226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
4236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret) {
4246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
4256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: Sched scan stop failed: ret=%d (%s)",
4266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   ret, strerror(-ret));
4276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} else {
4286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
4296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: Sched scan stop sent");
4306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
4316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return ret;
4336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
4346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
436dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidtconst u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie)
4376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
4386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	const u8 *end, *pos;
4396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ies == NULL)
4416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NULL;
4426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	pos = ies;
4446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	end = ies + ies_len;
4456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	while (pos + 1 < end) {
4476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (pos + 2 + pos[1] > end)
4486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			break;
4496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (pos[0] == ie)
4506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return pos;
4516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		pos += 2 + pos[1];
4526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
4536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return NULL;
4556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
4566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_scan_filtered(struct wpa_driver_nl80211_data *drv,
4596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				 const u8 *ie, size_t ie_len)
4606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
4616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	const u8 *ssid;
4626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	size_t i;
4636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (drv->filter_ssids == NULL)
4656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return 0;
4666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ssid = nl80211_get_ie(ie, ie_len, WLAN_EID_SSID);
4686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ssid == NULL)
4696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return 1;
4706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	for (i = 0; i < drv->num_filter_ssids; i++) {
4726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (ssid[1] == drv->filter_ssids[i].ssid_len &&
4736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    os_memcmp(ssid + 2, drv->filter_ssids[i].ssid, ssid[1]) ==
4746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    0)
4756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return 0;
4766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
4776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return 1;
4796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
4806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtint bss_info_handler(struct nl_msg *msg, void *arg)
4836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
4846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
4856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
4866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nlattr *bss[NL80211_BSS_MAX + 1];
4876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
4886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_BSS_BSSID] = { .type = NLA_UNSPEC },
4896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
4906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_BSS_TSF] = { .type = NLA_U64 },
4916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
4926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
4936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC },
4946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
4956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
4966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_BSS_STATUS] = { .type = NLA_U32 },
4976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
4986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC },
4996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	};
5006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl80211_bss_info_arg *_arg = arg;
5016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_scan_results *res = _arg->res;
5026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_scan_res **tmp;
5036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_scan_res *r;
5046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	const u8 *ie, *beacon_ie;
5056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	size_t ie_len, beacon_ie_len;
5066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	u8 *pos;
5076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	size_t i;
5086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
5096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
5106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
5116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!tb[NL80211_ATTR_BSS])
5126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
5136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
5146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			     bss_policy))
5156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
5166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (bss[NL80211_BSS_STATUS]) {
5176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		enum nl80211_bss_status status;
5186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		status = nla_get_u32(bss[NL80211_BSS_STATUS]);
5196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (status == NL80211_BSS_STATUS_ASSOCIATED &&
5206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    bss[NL80211_BSS_FREQUENCY]) {
5216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			_arg->assoc_freq =
5226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
5236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
5246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   _arg->assoc_freq);
5256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
5266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (status == NL80211_BSS_STATUS_IBSS_JOINED &&
5276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    bss[NL80211_BSS_FREQUENCY]) {
5286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			_arg->ibss_freq =
5296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
5306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: IBSS-joined on %u MHz",
5316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   _arg->ibss_freq);
5326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
5336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (status == NL80211_BSS_STATUS_ASSOCIATED &&
5346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    bss[NL80211_BSS_BSSID]) {
5356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			os_memcpy(_arg->assoc_bssid,
5366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN);
5376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Associated with "
5386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   MACSTR, MAC2STR(_arg->assoc_bssid));
5396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
5406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
5416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!res)
5426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
5436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
5446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
5456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
5466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} else {
5476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ie = NULL;
5486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ie_len = 0;
5496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
5506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (bss[NL80211_BSS_BEACON_IES]) {
5516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		beacon_ie = nla_data(bss[NL80211_BSS_BEACON_IES]);
5526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		beacon_ie_len = nla_len(bss[NL80211_BSS_BEACON_IES]);
5536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} else {
5546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		beacon_ie = NULL;
5556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		beacon_ie_len = 0;
5566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
5576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
5586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl80211_scan_filtered(_arg->drv, ie ? ie : beacon_ie,
5596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  ie ? ie_len : beacon_ie_len))
5606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
5616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
5626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	r = os_zalloc(sizeof(*r) + ie_len + beacon_ie_len);
5636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (r == NULL)
5646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
5656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (bss[NL80211_BSS_BSSID])
5666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		os_memcpy(r->bssid, nla_data(bss[NL80211_BSS_BSSID]),
5676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  ETH_ALEN);
5686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (bss[NL80211_BSS_FREQUENCY])
5696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		r->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
5706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (bss[NL80211_BSS_BEACON_INTERVAL])
5716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		r->beacon_int = nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]);
5726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (bss[NL80211_BSS_CAPABILITY])
5736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		r->caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
5746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	r->flags |= WPA_SCAN_NOISE_INVALID;
5756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (bss[NL80211_BSS_SIGNAL_MBM]) {
5766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		r->level = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
5776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		r->level /= 100; /* mBm to dBm */
5786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		r->flags |= WPA_SCAN_LEVEL_DBM | WPA_SCAN_QUAL_INVALID;
5796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} else if (bss[NL80211_BSS_SIGNAL_UNSPEC]) {
5806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		r->level = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
5816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		r->flags |= WPA_SCAN_QUAL_INVALID;
5826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} else
5836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID;
5846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (bss[NL80211_BSS_TSF])
5856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]);
586f8467ce3721b7154974a1f8a6e0dff54d4493f4dSrinivas Dasari	if (bss[NL80211_BSS_BEACON_TSF]) {
587f8467ce3721b7154974a1f8a6e0dff54d4493f4dSrinivas Dasari		u64 tsf = nla_get_u64(bss[NL80211_BSS_BEACON_TSF]);
588f8467ce3721b7154974a1f8a6e0dff54d4493f4dSrinivas Dasari		if (tsf > r->tsf)
589f8467ce3721b7154974a1f8a6e0dff54d4493f4dSrinivas Dasari			r->tsf = tsf;
590f8467ce3721b7154974a1f8a6e0dff54d4493f4dSrinivas Dasari	}
5916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (bss[NL80211_BSS_SEEN_MS_AGO])
5926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]);
5936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	r->ie_len = ie_len;
5946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	pos = (u8 *) (r + 1);
5956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ie) {
5966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		os_memcpy(pos, ie, ie_len);
5976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		pos += ie_len;
5986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
5996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	r->beacon_ie_len = beacon_ie_len;
6006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (beacon_ie)
6016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		os_memcpy(pos, beacon_ie, beacon_ie_len);
6026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
6036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (bss[NL80211_BSS_STATUS]) {
6046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		enum nl80211_bss_status status;
6056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		status = nla_get_u32(bss[NL80211_BSS_STATUS]);
6066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		switch (status) {
6076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		case NL80211_BSS_STATUS_ASSOCIATED:
6086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			r->flags |= WPA_SCAN_ASSOCIATED;
6096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			break;
6106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		default:
6116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			break;
6126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
6136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
6146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
6156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/*
6166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 * cfg80211 maintains separate BSS table entries for APs if the same
6176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 * BSSID,SSID pair is seen on multiple channels. wpa_supplicant does
6186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 * not use frequency as a separate key in the BSS table, so filter out
6196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 * duplicated entries. Prefer associated BSS entry in such a case in
6206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 * order to get the correct frequency into the BSS table. Similarly,
6216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 * prefer newer entries over older.
6226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 */
6236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	for (i = 0; i < res->num; i++) {
6246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		const u8 *s1, *s2;
6256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (os_memcmp(res->res[i]->bssid, r->bssid, ETH_ALEN) != 0)
6266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			continue;
6276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
6286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		s1 = nl80211_get_ie((u8 *) (res->res[i] + 1),
6296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				    res->res[i]->ie_len, WLAN_EID_SSID);
6306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		s2 = nl80211_get_ie((u8 *) (r + 1), r->ie_len, WLAN_EID_SSID);
6316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (s1 == NULL || s2 == NULL || s1[1] != s2[1] ||
6326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    os_memcmp(s1, s2, 2 + s1[1]) != 0)
6336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			continue;
6346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
6356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		/* Same BSSID,SSID was already included in scan results */
6366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Remove duplicated scan result "
6376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "for " MACSTR, MAC2STR(r->bssid));
6386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
6396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (((r->flags & WPA_SCAN_ASSOCIATED) &&
6406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		     !(res->res[i]->flags & WPA_SCAN_ASSOCIATED)) ||
6416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    r->age < res->res[i]->age) {
6426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			os_free(res->res[i]);
6436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			res->res[i] = r;
6446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		} else
6456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			os_free(r);
6466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
6476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
6486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
6496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	tmp = os_realloc_array(res->res, res->num + 1,
6506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			       sizeof(struct wpa_scan_res *));
6516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (tmp == NULL) {
6526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		os_free(r);
6536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
6546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
6556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	tmp[res->num++] = r;
6566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	res->res = tmp;
6576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
6586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return NL_SKIP;
6596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
6606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
6616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
6626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void clear_state_mismatch(struct wpa_driver_nl80211_data *drv,
6636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				 const u8 *addr)
6646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
6656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
6666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Clear possible state "
6676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "mismatch (" MACSTR ")", MAC2STR(addr));
6686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_driver_nl80211_mlme(drv, addr,
6696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					NL80211_CMD_DEAUTHENTICATE,
6706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					WLAN_REASON_PREV_AUTH_NOT_VALID, 1);
6716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
6726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
6736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
6746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
6756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void wpa_driver_nl80211_check_bss_status(
6766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv, struct wpa_scan_results *res)
6776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
6786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	size_t i;
6796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
6806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	for (i = 0; i < res->num; i++) {
6816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		struct wpa_scan_res *r = res->res[i];
6826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
6836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (r->flags & WPA_SCAN_ASSOCIATED) {
6846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Scan results "
6856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   "indicate BSS status with " MACSTR
6866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   " as associated",
6876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   MAC2STR(r->bssid));
6886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			if (is_sta_interface(drv->nlmode) &&
6896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    !drv->associated) {
6906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				wpa_printf(MSG_DEBUG, "nl80211: Local state "
6916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					   "(not associated) does not match "
6926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					   "with BSS state");
6936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				clear_state_mismatch(drv, r->bssid);
6946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			} else if (is_sta_interface(drv->nlmode) &&
6956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   os_memcmp(drv->bssid, r->bssid, ETH_ALEN) !=
6966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   0) {
6976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				wpa_printf(MSG_DEBUG, "nl80211: Local state "
6986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					   "(associated with " MACSTR ") does "
6996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					   "not match with BSS state",
7006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					   MAC2STR(drv->bssid));
7016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				clear_state_mismatch(drv, r->bssid);
7026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				clear_state_mismatch(drv, drv->bssid);
7036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			}
7046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
7056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
7066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
7076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
7086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
7096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic struct wpa_scan_results *
7106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtnl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
7116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
7126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
7136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_scan_results *res;
7146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret;
7156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl80211_bss_info_arg arg;
7166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
7176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	res = os_zalloc(sizeof(*res));
7186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (res == NULL)
7196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NULL;
7206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_cmd_msg(drv->first_bss, NLM_F_DUMP,
7216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				    NL80211_CMD_GET_SCAN))) {
7226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_scan_results_free(res);
7236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NULL;
7246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
7256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
7266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	arg.drv = drv;
7276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	arg.res = res;
7286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
7296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret == 0) {
7306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Received scan results (%lu "
7316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "BSSes)", (unsigned long) res->num);
7326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nl80211_get_noise_for_scan_results(drv, res);
7336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return res;
7346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
7356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
7366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   "(%s)", ret, strerror(-ret));
7376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_scan_results_free(res);
7386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return NULL;
7396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
7406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
7416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
7426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt/**
7436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * wpa_driver_nl80211_get_scan_results - Fetch the latest scan results
7446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
7456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * Returns: Scan results on success, -1 on failure
7466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt */
7476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstruct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv)
7486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
7496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
7506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
7516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_scan_results *res;
7526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
7536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	res = nl80211_get_scan_results(drv);
7546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (res)
7556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_driver_nl80211_check_bss_status(drv, res);
7566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return res;
7576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
7586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
7596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
7606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtvoid nl80211_dump_scan(struct wpa_driver_nl80211_data *drv)
7616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
7626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_scan_results *res;
7636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	size_t i;
7646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
7656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	res = nl80211_get_scan_results(drv);
7666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (res == NULL) {
7676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Failed to get scan results");
7686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return;
7696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
7706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
7716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Scan result dump");
7726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	for (i = 0; i < res->num; i++) {
7736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		struct wpa_scan_res *r = res->res[i];
774ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: %d/%d " MACSTR "%s",
7756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   (int) i, (int) res->num, MAC2STR(r->bssid),
7766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   r->flags & WPA_SCAN_ASSOCIATED ? " [assoc]" : "");
7776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
7786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
7796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_scan_results_free(res);
7806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
781