16c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt/*
26c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * Driver interaction with Linux nl80211/cfg80211 - Scanning
3d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt * Copyright(c) 2015 Intel Deutschland GmbH
46c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
56c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
66c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * Copyright (c) 2009-2010, Atheros Communications
76c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt *
86c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * This software may be distributed under the terms of the BSD license.
96c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * See README for more details.
106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt */
116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "includes.h"
136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include <netlink/genl/genl.h>
146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "utils/common.h"
166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "utils/eloop.h"
176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "common/ieee802_11_defs.h"
1857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt#include "common/ieee802_11_common.h"
19d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt#include "common/qca-vendor.h"
206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "driver_nl80211.h"
216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int get_noise_for_scan_results(struct nl_msg *msg, void *arg)
246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	};
326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_scan_results *scan_results = arg;
336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_scan_res *scan_res;
346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	size_t i;
356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!tb[NL80211_ATTR_SURVEY_INFO]) {
406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Survey data missing");
416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			     tb[NL80211_ATTR_SURVEY_INFO],
466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			     survey_policy)) {
476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Failed to parse nested "
486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "attributes");
496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!sinfo[NL80211_SURVEY_INFO_NOISE])
536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	for (i = 0; i < scan_results->num; ++i) {
596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		scan_res = scan_results->res[i];
606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (!scan_res)
616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			continue;
626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if ((int) nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    scan_res->freq)
646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			continue;
656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (!(scan_res->flags & WPA_SCAN_NOISE_INVALID))
666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			continue;
676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		scan_res->noise = (s8)
686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		scan_res->flags &= ~WPA_SCAN_NOISE_INVALID;
706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return NL_SKIP;
736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_get_noise_for_scan_results(
776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv,
786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_scan_results *scan_res)
796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return send_and_recv_msgs(drv, msg, get_noise_for_scan_results,
846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  scan_res);
856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt/**
896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * wpa_driver_nl80211_scan_timeout - Scan timeout to report scan completion
906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * @eloop_ctx: Driver private data
916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * @timeout_ctx: ctx argument given to wpa_driver_nl80211_init()
926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt *
936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * This function can be used as registered timeout when starting a scan to
946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * generate a scan completed event if the driver does not report this.
956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt */
966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtvoid wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = eloop_ctx;
999c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt
1009c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Scan timeout - try to abort it");
1019c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	if (!wpa_driver_nl80211_abort_scan(drv->first_bss))
1029c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt		return;
1039c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt
1049c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Failed to abort scan");
1059c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt
1066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) {
1076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_driver_nl80211_set_mode(drv->first_bss,
1086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					    drv->ap_scan_as_station);
1096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
1106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
1119c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt
1129c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Try to get scan results");
1136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
1146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
1156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic struct nl_msg *
1186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtnl80211_scan_common(struct i802_bss *bss, u8 cmd,
1196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    struct wpa_driver_scan_params *params)
1206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
1216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
1226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
1236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	size_t i;
1246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	u32 scan_flags = 0;
1256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_cmd_msg(bss, 0, cmd);
1276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!msg)
1286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NULL;
1296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->num_ssids) {
1316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		struct nlattr *ssids;
1326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ssids = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS);
1346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (ssids == NULL)
1356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
1366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		for (i = 0; i < params->num_ssids; i++) {
1376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
1386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					  params->ssids[i].ssid,
1396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					  params->ssids[i].ssid_len);
1406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			if (nla_put(msg, i + 1, params->ssids[i].ssid_len,
1416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				    params->ssids[i].ssid))
1426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				goto fail;
1436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
1446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nla_nest_end(msg, ssids);
145b70d0bbd90f638aa38da542e337c312309200e87Dmitry Shmidt	} else {
146b70d0bbd90f638aa38da542e337c312309200e87Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Passive scan requested");
1476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
1486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->extra_ies) {
1506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",
1516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    params->extra_ies, params->extra_ies_len);
1526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put(msg, NL80211_ATTR_IE, params->extra_ies_len,
1536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    params->extra_ies))
1546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
1556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
1566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->freqs) {
1586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		struct nlattr *freqs;
1596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
1606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (freqs == NULL)
1616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
1626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		for (i = 0; params->freqs[i]; i++) {
1636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
1646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   "MHz", params->freqs[i]);
1656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			if (nla_put_u32(msg, i + 1, params->freqs[i]))
1666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				goto fail;
1676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
1686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nla_nest_end(msg, freqs);
1696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
1706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	os_free(drv->filter_ssids);
1726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->filter_ssids = params->filter_ssids;
1736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	params->filter_ssids = NULL;
1746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->num_filter_ssids = params->num_filter_ssids;
1756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->only_new_results) {
1776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Add NL80211_SCAN_FLAG_FLUSH");
1786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		scan_flags |= NL80211_SCAN_FLAG_FLUSH;
1796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
1806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->low_priority && drv->have_low_prio_scan) {
1826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
1836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: Add NL80211_SCAN_FLAG_LOW_PRIORITY");
1846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		scan_flags |= NL80211_SCAN_FLAG_LOW_PRIORITY;
1856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
1866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->mac_addr_rand) {
1886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
1896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: Add NL80211_SCAN_FLAG_RANDOM_ADDR");
1906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		scan_flags |= NL80211_SCAN_FLAG_RANDOM_ADDR;
1916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (params->mac_addr) {
1936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: MAC address: " MACSTR,
1946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   MAC2STR(params->mac_addr));
1956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN,
1966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				    params->mac_addr))
1976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				goto fail;
1986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
1996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (params->mac_addr_mask) {
2016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: MAC address mask: "
2026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   MACSTR, MAC2STR(params->mac_addr_mask));
2036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			if (nla_put(msg, NL80211_ATTR_MAC_MASK, ETH_ALEN,
2046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				    params->mac_addr_mask))
2056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				goto fail;
2066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
2076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
2086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (scan_flags &&
2106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, scan_flags))
2116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
2126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return msg;
2146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtfail:
2166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nlmsg_free(msg);
2176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return NULL;
2186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
2196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt/**
2226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * wpa_driver_nl80211_scan - Request the driver to initiate scan
2236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * @bss: Pointer to private driver data from wpa_driver_nl80211_init()
2246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * @params: Scan parameters
2256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * Returns: 0 on success, -1 on failure
2266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt */
2276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtint wpa_driver_nl80211_scan(struct i802_bss *bss,
2286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    struct wpa_driver_scan_params *params)
2296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
2306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
2316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret = -1, timeout;
2326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg = NULL;
2336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request");
2356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->scan_for_auth = 0;
2366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
237d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	if (TEST_FAIL())
238d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		return -1;
239d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
2406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_scan_common(bss, NL80211_CMD_TRIGGER_SCAN, params);
2416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!msg)
2426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
2436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->p2p_probe) {
2456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		struct nlattr *rates;
2466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates");
2486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		rates = nla_nest_start(msg, NL80211_ATTR_SCAN_SUPP_RATES);
2506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (rates == NULL)
2516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
2526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		/*
2546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates
2556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * by masking out everything else apart from the OFDM rates 6,
2566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz
2576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * rates are left enabled.
2586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 */
2596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put(msg, NL80211_BAND_2GHZ, 8,
2606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    "\x0c\x12\x18\x24\x30\x48\x60\x6c"))
2616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
2626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nla_nest_end(msg, rates);
2636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put_flag(msg, NL80211_ATTR_TX_NO_CCK_RATE))
2656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
2666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
2676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2689c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	if (params->bssid) {
2699c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Scan for a specific BSSID: "
2709c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt			   MACSTR, MAC2STR(params->bssid));
2719c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt		if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
2729c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt			goto fail;
2739c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	}
2749c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt
2756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
2766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = NULL;
2776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret) {
2786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
2796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "(%s)", ret, strerror(-ret));
2806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (drv->hostapd && is_ap_interface(drv->nlmode)) {
2816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			enum nl80211_iftype old_mode = drv->nlmode;
2826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			/*
2846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			 * mac80211 does not allow scan requests in AP mode, so
2856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			 * try to do this in station mode.
2866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			 */
2876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			if (wpa_driver_nl80211_set_mode(
2886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				    bss, NL80211_IFTYPE_STATION))
2896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				goto fail;
2906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			if (wpa_driver_nl80211_scan(bss, params)) {
2922f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt				wpa_driver_nl80211_set_mode(bss, old_mode);
2936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				goto fail;
2946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			}
2956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			/* Restore AP mode when processing scan results */
2976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			drv->ap_scan_as_station = old_mode;
2986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			ret = 0;
2996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		} else
3006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
3016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
3026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
3036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->scan_state = SCAN_REQUESTED;
3046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* Not all drivers generate "scan completed" wireless event, so try to
3056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 * read results after a timeout. */
3066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	timeout = 10;
3076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (drv->scan_complete_events) {
3086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		/*
3096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * The driver seems to deliver events to notify when scan is
3106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * complete, so use longer timeout to avoid race conditions
3116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * with scanning and following association request.
3126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 */
3136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		timeout = 30;
3146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
3156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
3166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   "seconds", ret, timeout);
3176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
3186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout,
3196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			       drv, drv->ctx);
320d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	drv->last_scan_cmd = NL80211_CMD_TRIGGER_SCAN;
3216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
3226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtfail:
3236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nlmsg_free(msg);
3246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return ret;
3256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
3266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
3276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
328d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidtstatic int
329d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidtnl80211_sched_scan_add_scan_plans(struct wpa_driver_nl80211_data *drv,
330d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt				  struct nl_msg *msg,
331d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt				  struct wpa_driver_scan_params *params)
332d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt{
333d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt	struct nlattr *plans;
334d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt	struct sched_scan_plan *scan_plans = params->sched_scan_plans;
335d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt	unsigned int i;
336d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt
337d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt	plans = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_PLANS);
338d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt	if (!plans)
339d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		return -1;
340d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt
341d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt	for (i = 0; i < params->sched_scan_plans_num; i++) {
342d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		struct nlattr *plan = nla_nest_start(msg, i + 1);
343d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt
344d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		if (!plan)
345d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt			return -1;
346d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt
347d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		if (!scan_plans[i].interval ||
348d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		    scan_plans[i].interval >
349d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		    drv->capa.max_sched_scan_plan_interval) {
350d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt			wpa_printf(MSG_DEBUG,
351d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt				   "nl80211: sched scan plan no. %u: Invalid interval: %u",
352d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt				   i, scan_plans[i].interval);
353d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt			return -1;
354d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		}
355d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt
356d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		if (nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_INTERVAL,
357d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt				scan_plans[i].interval))
358d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt			return -1;
359d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt
360d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		if (scan_plans[i].iterations >
361d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		    drv->capa.max_sched_scan_plan_iterations) {
362d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt			wpa_printf(MSG_DEBUG,
363d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt				   "nl80211: sched scan plan no. %u: Invalid number of iterations: %u",
364d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt				   i, scan_plans[i].iterations);
365d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt			return -1;
366d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		}
367d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt
368d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		if (scan_plans[i].iterations &&
369d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		    nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_ITERATIONS,
370d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt				scan_plans[i].iterations))
371d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt			return -1;
372d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt
373d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		nla_nest_end(msg, plan);
374d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt
375d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		/*
376d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		 * All the scan plans must specify the number of iterations
377d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		 * except the last plan, which will run infinitely. So if the
378d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		 * number of iterations is not specified, this ought to be the
379d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		 * last scan plan.
380d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		 */
381d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		if (!scan_plans[i].iterations)
382d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt			break;
383d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt	}
384d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt
385d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt	if (i != params->sched_scan_plans_num - 1) {
386d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		wpa_printf(MSG_DEBUG,
387d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt			   "nl80211: All sched scan plans but the last must specify number of iterations");
388d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		return -1;
389d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt	}
390d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt
391d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt	nla_nest_end(msg, plans);
392d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt	return 0;
393d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt}
394d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt
395d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt
3966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt/**
3976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * wpa_driver_nl80211_sched_scan - Initiate a scheduled scan
3986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
3996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * @params: Scan parameters
4006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * Returns: 0 on success, -1 on failure or if not supported
4016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt */
4026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtint wpa_driver_nl80211_sched_scan(void *priv,
403d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt				  struct wpa_driver_scan_params *params)
4046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
4056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
4066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
4076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret = -1;
4086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
4096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	size_t i;
4106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: sched_scan request");
4126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#ifdef ANDROID
4146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!drv->capa.sched_scan_supported)
4156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return android_pno_start(bss, params);
4166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#endif /* ANDROID */
4176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
418d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt	if (!params->sched_scan_plans_num ||
419d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt	    params->sched_scan_plans_num > drv->capa.max_sched_scan_plans) {
420d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		wpa_printf(MSG_ERROR,
421d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt			   "nl80211: Invalid number of sched scan plans: %u",
422d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt			   params->sched_scan_plans_num);
423d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		return -1;
424d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt	}
425d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt
4266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_scan_common(bss, NL80211_CMD_START_SCHED_SCAN, params);
427d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt	if (!msg)
4286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
4296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
430d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt	if (drv->capa.max_sched_scan_plan_iterations) {
431d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		if (nl80211_sched_scan_add_scan_plans(drv, msg, params))
432d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt			goto fail;
433d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt	} else {
434d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL,
435d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt				params->sched_scan_plans[0].interval * 1000))
436d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt			goto fail;
437d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt	}
438d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt
4396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if ((drv->num_filter_ssids &&
4406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (int) drv->num_filter_ssids <= drv->capa.max_match_sets) ||
4416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    params->filter_rssi) {
4426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		struct nlattr *match_sets;
4436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		match_sets = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH);
4446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (match_sets == NULL)
4456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
4466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		for (i = 0; i < drv->num_filter_ssids; i++) {
4486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			struct nlattr *match_set_ssid;
4496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_hexdump_ascii(MSG_MSGDUMP,
4506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					  "nl80211: Sched scan filter SSID",
4516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					  drv->filter_ssids[i].ssid,
4526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					  drv->filter_ssids[i].ssid_len);
4536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			match_set_ssid = nla_nest_start(msg, i + 1);
4556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			if (match_set_ssid == NULL ||
4566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    nla_put(msg, NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
4576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				    drv->filter_ssids[i].ssid_len,
4586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				    drv->filter_ssids[i].ssid) ||
4596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    (params->filter_rssi &&
4606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			     nla_put_u32(msg,
4616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					 NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
4626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					 params->filter_rssi)))
4636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				goto fail;
4646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			nla_nest_end(msg, match_set_ssid);
4666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
4676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		/*
4696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * Due to backward compatibility code, newer kernels treat this
4706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * matchset (with only an RSSI filter) as the default for all
4716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * other matchsets, unless it's the only one, in which case the
4726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * matchset will actually allow all SSIDs above the RSSI.
4736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 */
4746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (params->filter_rssi) {
4756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			struct nlattr *match_set_rssi;
4766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			match_set_rssi = nla_nest_start(msg, 0);
4776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			if (match_set_rssi == NULL ||
4786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    nla_put_u32(msg, NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
4796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					params->filter_rssi))
4806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				goto fail;
4816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_MSGDUMP,
4826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   "nl80211: Sched scan RSSI filter %d dBm",
4836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   params->filter_rssi);
4846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			nla_nest_end(msg, match_set_rssi);
4856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
4866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nla_nest_end(msg, match_sets);
4886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
4896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
4916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* TODO: if we get an error here, we should fall back to normal scan */
4936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = NULL;
4956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret) {
4966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Sched scan start failed: "
4976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "ret=%d (%s)", ret, strerror(-ret));
4986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
4996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
5006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
501d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Sched scan requested (ret=%d)", ret);
5026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
5036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtfail:
5046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nlmsg_free(msg);
5056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return ret;
5066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
5076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
5086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
5096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt/**
5106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * wpa_driver_nl80211_stop_sched_scan - Stop a scheduled scan
5116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
5126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * Returns: 0 on success, -1 on failure or if not supported
5136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt */
5146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtint wpa_driver_nl80211_stop_sched_scan(void *priv)
5156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
5166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
5176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
5186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret;
5196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
5206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
5216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#ifdef ANDROID
5226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!drv->capa.sched_scan_supported)
5236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return android_pno_stop(bss);
5246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#endif /* ANDROID */
5256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
5266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_STOP_SCHED_SCAN);
5276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
5286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret) {
5296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
5306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: Sched scan stop failed: ret=%d (%s)",
5316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   ret, strerror(-ret));
5326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} else {
5336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
5346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: Sched scan stop sent");
5356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
5366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
5376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return ret;
5386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
5396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
5406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
5416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_scan_filtered(struct wpa_driver_nl80211_data *drv,
5426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				 const u8 *ie, size_t ie_len)
5436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
5446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	const u8 *ssid;
5456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	size_t i;
5466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
5476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (drv->filter_ssids == NULL)
5486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return 0;
5496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
55057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt	ssid = get_ie(ie, ie_len, WLAN_EID_SSID);
5516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ssid == NULL)
5526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return 1;
5536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
5546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	for (i = 0; i < drv->num_filter_ssids; i++) {
5556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (ssid[1] == drv->filter_ssids[i].ssid_len &&
5566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    os_memcmp(ssid + 2, drv->filter_ssids[i].ssid, ssid[1]) ==
5576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    0)
5586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return 0;
5596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
5606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
5616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return 1;
5626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
5636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
5646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
5656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtint bss_info_handler(struct nl_msg *msg, void *arg)
5666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
5676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
5686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
5696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nlattr *bss[NL80211_BSS_MAX + 1];
5706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
5716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_BSS_BSSID] = { .type = NLA_UNSPEC },
5726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
5736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_BSS_TSF] = { .type = NLA_U64 },
5746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
5756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
5766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC },
5776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
5786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
5796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_BSS_STATUS] = { .type = NLA_U32 },
5806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
5816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC },
5826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	};
5836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl80211_bss_info_arg *_arg = arg;
5846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_scan_results *res = _arg->res;
5856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_scan_res **tmp;
5866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_scan_res *r;
5876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	const u8 *ie, *beacon_ie;
5886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	size_t ie_len, beacon_ie_len;
5896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	u8 *pos;
5906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	size_t i;
5916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
5926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
5936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
5946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!tb[NL80211_ATTR_BSS])
5956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
5966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
5976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			     bss_policy))
5986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
5996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (bss[NL80211_BSS_STATUS]) {
6006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		enum nl80211_bss_status status;
6016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		status = nla_get_u32(bss[NL80211_BSS_STATUS]);
6026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (status == NL80211_BSS_STATUS_ASSOCIATED &&
6036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    bss[NL80211_BSS_FREQUENCY]) {
6046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			_arg->assoc_freq =
6056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
6066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
6076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   _arg->assoc_freq);
6086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
6096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (status == NL80211_BSS_STATUS_IBSS_JOINED &&
6106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    bss[NL80211_BSS_FREQUENCY]) {
6116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			_arg->ibss_freq =
6126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
6136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: IBSS-joined on %u MHz",
6146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   _arg->ibss_freq);
6156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
6166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (status == NL80211_BSS_STATUS_ASSOCIATED &&
6176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    bss[NL80211_BSS_BSSID]) {
6186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			os_memcpy(_arg->assoc_bssid,
6196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN);
6206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Associated with "
6216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   MACSTR, MAC2STR(_arg->assoc_bssid));
6226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
6236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
6246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!res)
6256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
6266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
6276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
6286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
6296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} else {
6306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ie = NULL;
6316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ie_len = 0;
6326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
6336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (bss[NL80211_BSS_BEACON_IES]) {
6346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		beacon_ie = nla_data(bss[NL80211_BSS_BEACON_IES]);
6356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		beacon_ie_len = nla_len(bss[NL80211_BSS_BEACON_IES]);
6366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} else {
6376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		beacon_ie = NULL;
6386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		beacon_ie_len = 0;
6396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
6406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
6416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl80211_scan_filtered(_arg->drv, ie ? ie : beacon_ie,
6426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  ie ? ie_len : beacon_ie_len))
6436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
6446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
6456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	r = os_zalloc(sizeof(*r) + ie_len + beacon_ie_len);
6466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (r == NULL)
6476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
6486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (bss[NL80211_BSS_BSSID])
6496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		os_memcpy(r->bssid, nla_data(bss[NL80211_BSS_BSSID]),
6506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  ETH_ALEN);
6516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (bss[NL80211_BSS_FREQUENCY])
6526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		r->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
6536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (bss[NL80211_BSS_BEACON_INTERVAL])
6546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		r->beacon_int = nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]);
6556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (bss[NL80211_BSS_CAPABILITY])
6566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		r->caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
6576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	r->flags |= WPA_SCAN_NOISE_INVALID;
6586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (bss[NL80211_BSS_SIGNAL_MBM]) {
6596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		r->level = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
6606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		r->level /= 100; /* mBm to dBm */
6616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		r->flags |= WPA_SCAN_LEVEL_DBM | WPA_SCAN_QUAL_INVALID;
6626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} else if (bss[NL80211_BSS_SIGNAL_UNSPEC]) {
6636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		r->level = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
6646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		r->flags |= WPA_SCAN_QUAL_INVALID;
6656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} else
6666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID;
6676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (bss[NL80211_BSS_TSF])
6686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]);
669f8467ce3721b7154974a1f8a6e0dff54d4493f4dSrinivas Dasari	if (bss[NL80211_BSS_BEACON_TSF]) {
670f8467ce3721b7154974a1f8a6e0dff54d4493f4dSrinivas Dasari		u64 tsf = nla_get_u64(bss[NL80211_BSS_BEACON_TSF]);
671f8467ce3721b7154974a1f8a6e0dff54d4493f4dSrinivas Dasari		if (tsf > r->tsf)
672f8467ce3721b7154974a1f8a6e0dff54d4493f4dSrinivas Dasari			r->tsf = tsf;
673f8467ce3721b7154974a1f8a6e0dff54d4493f4dSrinivas Dasari	}
6746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (bss[NL80211_BSS_SEEN_MS_AGO])
6756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]);
6766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	r->ie_len = ie_len;
6776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	pos = (u8 *) (r + 1);
6786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ie) {
6796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		os_memcpy(pos, ie, ie_len);
6806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		pos += ie_len;
6816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
6826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	r->beacon_ie_len = beacon_ie_len;
6836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (beacon_ie)
6846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		os_memcpy(pos, beacon_ie, beacon_ie_len);
6856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
6866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (bss[NL80211_BSS_STATUS]) {
6876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		enum nl80211_bss_status status;
6886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		status = nla_get_u32(bss[NL80211_BSS_STATUS]);
6896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		switch (status) {
6906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		case NL80211_BSS_STATUS_ASSOCIATED:
6916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			r->flags |= WPA_SCAN_ASSOCIATED;
6926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			break;
6936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		default:
6946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			break;
6956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
6966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
6976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
6986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/*
6996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 * cfg80211 maintains separate BSS table entries for APs if the same
7006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 * BSSID,SSID pair is seen on multiple channels. wpa_supplicant does
7016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 * not use frequency as a separate key in the BSS table, so filter out
7026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 * duplicated entries. Prefer associated BSS entry in such a case in
7036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 * order to get the correct frequency into the BSS table. Similarly,
7046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 * prefer newer entries over older.
7056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 */
7066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	for (i = 0; i < res->num; i++) {
7076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		const u8 *s1, *s2;
7086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (os_memcmp(res->res[i]->bssid, r->bssid, ETH_ALEN) != 0)
7096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			continue;
7106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
71157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		s1 = get_ie((u8 *) (res->res[i] + 1),
71257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt			    res->res[i]->ie_len, WLAN_EID_SSID);
71357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		s2 = get_ie((u8 *) (r + 1), r->ie_len, WLAN_EID_SSID);
7146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (s1 == NULL || s2 == NULL || s1[1] != s2[1] ||
7156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    os_memcmp(s1, s2, 2 + s1[1]) != 0)
7166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			continue;
7176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
7186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		/* Same BSSID,SSID was already included in scan results */
7196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Remove duplicated scan result "
7206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "for " MACSTR, MAC2STR(r->bssid));
7216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
7226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (((r->flags & WPA_SCAN_ASSOCIATED) &&
7236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		     !(res->res[i]->flags & WPA_SCAN_ASSOCIATED)) ||
7246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    r->age < res->res[i]->age) {
7256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			os_free(res->res[i]);
7266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			res->res[i] = r;
7276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		} else
7286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			os_free(r);
7296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
7306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
7316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
7326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	tmp = os_realloc_array(res->res, res->num + 1,
7336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			       sizeof(struct wpa_scan_res *));
7346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (tmp == NULL) {
7356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		os_free(r);
7366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
7376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
7386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	tmp[res->num++] = r;
7396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	res->res = tmp;
7406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
7416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return NL_SKIP;
7426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
7436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
7446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
7456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void clear_state_mismatch(struct wpa_driver_nl80211_data *drv,
7466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				 const u8 *addr)
7476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
7486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
7496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Clear possible state "
7506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "mismatch (" MACSTR ")", MAC2STR(addr));
7516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_driver_nl80211_mlme(drv, addr,
7526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					NL80211_CMD_DEAUTHENTICATE,
7536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					WLAN_REASON_PREV_AUTH_NOT_VALID, 1);
7546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
7556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
7566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
7576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
7586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void wpa_driver_nl80211_check_bss_status(
7596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv, struct wpa_scan_results *res)
7606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
7616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	size_t i;
7626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
7636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	for (i = 0; i < res->num; i++) {
7646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		struct wpa_scan_res *r = res->res[i];
7656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
7666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (r->flags & WPA_SCAN_ASSOCIATED) {
7676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Scan results "
7686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   "indicate BSS status with " MACSTR
7696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   " as associated",
7706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   MAC2STR(r->bssid));
7716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			if (is_sta_interface(drv->nlmode) &&
7726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    !drv->associated) {
7736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				wpa_printf(MSG_DEBUG, "nl80211: Local state "
7746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					   "(not associated) does not match "
7756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					   "with BSS state");
7766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				clear_state_mismatch(drv, r->bssid);
7776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			} else if (is_sta_interface(drv->nlmode) &&
7786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   os_memcmp(drv->bssid, r->bssid, ETH_ALEN) !=
7796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   0) {
7806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				wpa_printf(MSG_DEBUG, "nl80211: Local state "
7816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					   "(associated with " MACSTR ") does "
7826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					   "not match with BSS state",
7836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					   MAC2STR(drv->bssid));
7846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				clear_state_mismatch(drv, r->bssid);
7856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				clear_state_mismatch(drv, drv->bssid);
7866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			}
7876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
7886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
7896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
7906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
7916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
7926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic struct wpa_scan_results *
7936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtnl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
7946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
7956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
7966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_scan_results *res;
7976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret;
7986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl80211_bss_info_arg arg;
7996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
8006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	res = os_zalloc(sizeof(*res));
8016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (res == NULL)
8026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NULL;
8036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_cmd_msg(drv->first_bss, NLM_F_DUMP,
8046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				    NL80211_CMD_GET_SCAN))) {
8056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_scan_results_free(res);
8066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NULL;
8076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
8086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
8096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	arg.drv = drv;
8106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	arg.res = res;
8116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
8126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret == 0) {
8136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Received scan results (%lu "
8146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "BSSes)", (unsigned long) res->num);
8156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nl80211_get_noise_for_scan_results(drv, res);
8166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return res;
8176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
8186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
8196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   "(%s)", ret, strerror(-ret));
8206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_scan_results_free(res);
8216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return NULL;
8226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
8236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
8246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
8256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt/**
8266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * wpa_driver_nl80211_get_scan_results - Fetch the latest scan results
8276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
8286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * Returns: Scan results on success, -1 on failure
8296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt */
8306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstruct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv)
8316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
8326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
8336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
8346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_scan_results *res;
8356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
8366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	res = nl80211_get_scan_results(drv);
8376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (res)
8386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_driver_nl80211_check_bss_status(drv, res);
8396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return res;
8406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
8416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
8426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
8436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtvoid nl80211_dump_scan(struct wpa_driver_nl80211_data *drv)
8446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
8456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_scan_results *res;
8466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	size_t i;
8476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
8486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	res = nl80211_get_scan_results(drv);
8496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (res == NULL) {
8506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Failed to get scan results");
8516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return;
8526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
8536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
8546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Scan result dump");
8556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	for (i = 0; i < res->num; i++) {
8566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		struct wpa_scan_res *r = res->res[i];
857ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: %d/%d " MACSTR "%s",
8586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   (int) i, (int) res->num, MAC2STR(r->bssid),
8596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   r->flags & WPA_SCAN_ASSOCIATED ? " [assoc]" : "");
8606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
8616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
8626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_scan_results_free(res);
8636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
864d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
865d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
866d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidtint wpa_driver_nl80211_abort_scan(void *priv)
867d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt{
868d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt	struct i802_bss *bss = priv;
869d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
870d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt	int ret;
871d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt	struct nl_msg *msg;
872d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt
873d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Abort scan");
874d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt	msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_ABORT_SCAN);
875d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
876d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt	if (ret) {
877d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Abort scan failed: ret=%d (%s)",
878d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt			   ret, strerror(-ret));
879d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt	}
880d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt
881d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt	return ret;
882d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt}
883d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt
884d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt
885d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt#ifdef CONFIG_DRIVER_NL80211_QCA
886d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
887d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidtstatic int scan_cookie_handler(struct nl_msg *msg, void *arg)
888d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt{
889d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
890d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
891d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	u64 *cookie = arg;
892d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
893d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
894d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
895d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
896d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	if (tb[NL80211_ATTR_VENDOR_DATA]) {
897d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		struct nlattr *nl_vendor = tb[NL80211_ATTR_VENDOR_DATA];
898d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_SCAN_MAX + 1];
899d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
900d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_SCAN_MAX,
901d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			  nla_data(nl_vendor), nla_len(nl_vendor), NULL);
902d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
903d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		if (tb_vendor[QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE])
904d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			*cookie = nla_get_u64(
905d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt				tb_vendor[QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE]);
906d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	}
907d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
908d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	return NL_SKIP;
909d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt}
910d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
911d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
912d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt/**
913d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt * wpa_driver_nl80211_vendor_scan - Request the driver to initiate a vendor scan
914d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt * @bss: Pointer to private driver data from wpa_driver_nl80211_init()
915d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt * @params: Scan parameters
916d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt * Returns: 0 on success, -1 on failure
917d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt */
918d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidtint wpa_driver_nl80211_vendor_scan(struct i802_bss *bss,
919d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt				   struct wpa_driver_scan_params *params)
920d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt{
921d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
922d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	struct nl_msg *msg = NULL;
923d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	struct nlattr *attr;
924d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	size_t i;
925d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	u32 scan_flags = 0;
926d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	int ret = -1;
927d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	u64 cookie = 0;
928d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
929d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: vendor scan request");
930d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	drv->scan_for_auth = 0;
931d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
932d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
933d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	    nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
934d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	    nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
935d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN) )
936d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		goto fail;
937d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
938d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
939d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	if (attr == NULL)
940d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		goto fail;
941d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
942d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	if (params->num_ssids) {
943d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		struct nlattr *ssids;
944d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
945d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		ssids = nla_nest_start(msg, QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS);
946d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		if (ssids == NULL)
947d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			goto fail;
948d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		for (i = 0; i < params->num_ssids; i++) {
949d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
950d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt					params->ssids[i].ssid,
951d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt					params->ssids[i].ssid_len);
952d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			if (nla_put(msg, i + 1, params->ssids[i].ssid_len,
953d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt				    params->ssids[i].ssid))
954d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt				goto fail;
955d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		}
956d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		nla_nest_end(msg, ssids);
957d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	}
958d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
959d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	if (params->extra_ies) {
960d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",
961d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			    params->extra_ies, params->extra_ies_len);
962d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_SCAN_IE,
963d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			    params->extra_ies_len, params->extra_ies))
964d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			goto fail;
965d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	}
966d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
967d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	if (params->freqs) {
968d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		struct nlattr *freqs;
969d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
970d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		freqs = nla_nest_start(msg,
971d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt				       QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES);
972d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		if (freqs == NULL)
973d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			goto fail;
974d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		for (i = 0; params->freqs[i]; i++) {
975d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			wpa_printf(MSG_MSGDUMP,
976d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt				   "nl80211: Scan frequency %u MHz",
977d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt				   params->freqs[i]);
978d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			if (nla_put_u32(msg, i + 1, params->freqs[i]))
979d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt				goto fail;
980d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		}
981d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		nla_nest_end(msg, freqs);
982d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	}
983d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
984d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	os_free(drv->filter_ssids);
985d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	drv->filter_ssids = params->filter_ssids;
986d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	params->filter_ssids = NULL;
987d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	drv->num_filter_ssids = params->num_filter_ssids;
988d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
989d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	if (params->low_priority && drv->have_low_prio_scan) {
990d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		wpa_printf(MSG_DEBUG,
991d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			   "nl80211: Add NL80211_SCAN_FLAG_LOW_PRIORITY");
992d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		scan_flags |= NL80211_SCAN_FLAG_LOW_PRIORITY;
993d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	}
994d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
995d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	if (params->mac_addr_rand) {
996d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		wpa_printf(MSG_DEBUG,
997d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			   "nl80211: Add NL80211_SCAN_FLAG_RANDOM_ADDR");
998d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		scan_flags |= NL80211_SCAN_FLAG_RANDOM_ADDR;
999d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
1000d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		if (params->mac_addr) {
1001d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: MAC address: " MACSTR,
1002d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt				   MAC2STR(params->mac_addr));
1003d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_SCAN_MAC,
1004d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt				    ETH_ALEN, params->mac_addr))
1005d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt				goto fail;
1006d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		}
1007d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
1008d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		if (params->mac_addr_mask) {
1009d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: MAC address mask: "
1010d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt				   MACSTR, MAC2STR(params->mac_addr_mask));
1011d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK,
1012d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt				    ETH_ALEN, params->mac_addr_mask))
1013d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt				goto fail;
1014d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		}
1015d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	}
1016d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
1017d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	if (scan_flags &&
1018d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	    nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, scan_flags))
1019d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		goto fail;
1020d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
1021d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	if (params->p2p_probe) {
1022d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		struct nlattr *rates;
1023d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
1024d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates");
1025d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
1026d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		rates = nla_nest_start(msg,
1027d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt				       QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES);
1028d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		if (rates == NULL)
1029d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			goto fail;
1030d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
1031d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		/*
1032d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		 * Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates
1033d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		 * by masking out everything else apart from the OFDM rates 6,
1034d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		 * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz
1035d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		 * rates are left enabled.
1036d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		 */
1037d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		if (nla_put(msg, NL80211_BAND_2GHZ, 8,
1038d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			    "\x0c\x12\x18\x24\x30\x48\x60\x6c"))
1039d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			goto fail;
1040d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		nla_nest_end(msg, rates);
1041d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
1042d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		if (nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE))
1043d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			goto fail;
1044d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	}
1045d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
1046d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	nla_nest_end(msg, attr);
1047d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
1048d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, scan_cookie_handler, &cookie);
1049d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	msg = NULL;
1050d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	if (ret) {
1051d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		wpa_printf(MSG_DEBUG,
1052d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			   "nl80211: Vendor scan trigger failed: ret=%d (%s)",
1053d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			   ret, strerror(-ret));
1054d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		goto fail;
1055d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	}
1056d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
1057d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	drv->vendor_scan_cookie = cookie;
1058d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	drv->scan_state = SCAN_REQUESTED;
1059d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
1060d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	wpa_printf(MSG_DEBUG,
1061d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		   "nl80211: Vendor scan requested (ret=%d) - scan timeout 30 seconds, scan cookie:0x%llx",
1062d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		   ret, (long long unsigned int) cookie);
1063d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
1064d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	eloop_register_timeout(30, 0, wpa_driver_nl80211_scan_timeout,
1065d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			       drv, drv->ctx);
1066d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	drv->last_scan_cmd = NL80211_CMD_VENDOR;
1067d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
1068d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidtfail:
1069d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	nlmsg_free(msg);
1070d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	return ret;
1071d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt}
1072d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
1073d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt#endif /* CONFIG_DRIVER_NL80211_QCA */
1074