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