15b9c547cSRui Paulo /* 25b9c547cSRui Paulo * Driver interaction with Linux nl80211/cfg80211 - Scanning 3780fb4a2SCy Schubert * Copyright(c) 2015 Intel Deutschland GmbH 45b9c547cSRui Paulo * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> 55b9c547cSRui Paulo * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net> 65b9c547cSRui Paulo * Copyright (c) 2009-2010, Atheros Communications 75b9c547cSRui Paulo * 85b9c547cSRui Paulo * This software may be distributed under the terms of the BSD license. 95b9c547cSRui Paulo * See README for more details. 105b9c547cSRui Paulo */ 115b9c547cSRui Paulo 125b9c547cSRui Paulo #include "includes.h" 1385732ac8SCy Schubert #include <time.h> 145b9c547cSRui Paulo #include <netlink/genl/genl.h> 155b9c547cSRui Paulo 165b9c547cSRui Paulo #include "utils/common.h" 175b9c547cSRui Paulo #include "utils/eloop.h" 185b9c547cSRui Paulo #include "common/ieee802_11_defs.h" 19780fb4a2SCy Schubert #include "common/ieee802_11_common.h" 20780fb4a2SCy Schubert #include "common/qca-vendor.h" 215b9c547cSRui Paulo #include "driver_nl80211.h" 225b9c547cSRui Paulo 235b9c547cSRui Paulo 2485732ac8SCy Schubert #define MAX_NL80211_NOISE_FREQS 50 2585732ac8SCy Schubert 2685732ac8SCy Schubert struct nl80211_noise_info { 2785732ac8SCy Schubert u32 freq[MAX_NL80211_NOISE_FREQS]; 2885732ac8SCy Schubert s8 noise[MAX_NL80211_NOISE_FREQS]; 2985732ac8SCy Schubert unsigned int count; 3085732ac8SCy Schubert }; 3185732ac8SCy Schubert 325b9c547cSRui Paulo static int get_noise_for_scan_results(struct nl_msg *msg, void *arg) 335b9c547cSRui Paulo { 345b9c547cSRui Paulo struct nlattr *tb[NL80211_ATTR_MAX + 1]; 355b9c547cSRui Paulo struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); 365b9c547cSRui Paulo struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1]; 375b9c547cSRui Paulo static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = { 385b9c547cSRui Paulo [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 }, 395b9c547cSRui Paulo [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 }, 405b9c547cSRui Paulo }; 4185732ac8SCy Schubert struct nl80211_noise_info *info = arg; 4285732ac8SCy Schubert 4385732ac8SCy Schubert if (info->count >= MAX_NL80211_NOISE_FREQS) 4485732ac8SCy Schubert return NL_STOP; 455b9c547cSRui Paulo 465b9c547cSRui Paulo nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), 475b9c547cSRui Paulo genlmsg_attrlen(gnlh, 0), NULL); 485b9c547cSRui Paulo 495b9c547cSRui Paulo if (!tb[NL80211_ATTR_SURVEY_INFO]) { 505b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: Survey data missing"); 515b9c547cSRui Paulo return NL_SKIP; 525b9c547cSRui Paulo } 535b9c547cSRui Paulo 545b9c547cSRui Paulo if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX, 555b9c547cSRui Paulo tb[NL80211_ATTR_SURVEY_INFO], 565b9c547cSRui Paulo survey_policy)) { 575b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: Failed to parse nested " 585b9c547cSRui Paulo "attributes"); 595b9c547cSRui Paulo return NL_SKIP; 605b9c547cSRui Paulo } 615b9c547cSRui Paulo 625b9c547cSRui Paulo if (!sinfo[NL80211_SURVEY_INFO_NOISE]) 635b9c547cSRui Paulo return NL_SKIP; 645b9c547cSRui Paulo 655b9c547cSRui Paulo if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY]) 665b9c547cSRui Paulo return NL_SKIP; 675b9c547cSRui Paulo 6885732ac8SCy Schubert info->freq[info->count] = 6985732ac8SCy Schubert nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]); 7085732ac8SCy Schubert info->noise[info->count] = 7185732ac8SCy Schubert (s8) nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]); 7285732ac8SCy Schubert info->count++; 735b9c547cSRui Paulo 745b9c547cSRui Paulo return NL_SKIP; 755b9c547cSRui Paulo } 765b9c547cSRui Paulo 775b9c547cSRui Paulo 785b9c547cSRui Paulo static int nl80211_get_noise_for_scan_results( 7985732ac8SCy Schubert struct wpa_driver_nl80211_data *drv, struct nl80211_noise_info *info) 805b9c547cSRui Paulo { 815b9c547cSRui Paulo struct nl_msg *msg; 825b9c547cSRui Paulo 8385732ac8SCy Schubert os_memset(info, 0, sizeof(*info)); 845b9c547cSRui Paulo msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY); 8585732ac8SCy Schubert return send_and_recv_msgs(drv, msg, get_noise_for_scan_results, info); 865b9c547cSRui Paulo } 875b9c547cSRui Paulo 885b9c547cSRui Paulo 8985732ac8SCy Schubert static int nl80211_abort_scan(struct i802_bss *bss) 9085732ac8SCy Schubert { 9185732ac8SCy Schubert int ret; 9285732ac8SCy Schubert struct nl_msg *msg; 9385732ac8SCy Schubert struct wpa_driver_nl80211_data *drv = bss->drv; 9485732ac8SCy Schubert 9585732ac8SCy Schubert wpa_printf(MSG_DEBUG, "nl80211: Abort scan"); 9685732ac8SCy Schubert msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_ABORT_SCAN); 9785732ac8SCy Schubert ret = send_and_recv_msgs(drv, msg, NULL, NULL); 9885732ac8SCy Schubert if (ret) { 9985732ac8SCy Schubert wpa_printf(MSG_DEBUG, "nl80211: Abort scan failed: ret=%d (%s)", 10085732ac8SCy Schubert ret, strerror(-ret)); 10185732ac8SCy Schubert } 10285732ac8SCy Schubert return ret; 10385732ac8SCy Schubert } 10485732ac8SCy Schubert 10585732ac8SCy Schubert 10685732ac8SCy Schubert #ifdef CONFIG_DRIVER_NL80211_QCA 10785732ac8SCy Schubert static int nl80211_abort_vendor_scan(struct wpa_driver_nl80211_data *drv, 10885732ac8SCy Schubert u64 scan_cookie) 10985732ac8SCy Schubert { 11085732ac8SCy Schubert struct nl_msg *msg; 11185732ac8SCy Schubert struct nlattr *params; 11285732ac8SCy Schubert int ret; 11385732ac8SCy Schubert 11485732ac8SCy Schubert wpa_printf(MSG_DEBUG, "nl80211: Abort vendor scan with cookie 0x%llx", 11585732ac8SCy Schubert (long long unsigned int) scan_cookie); 11685732ac8SCy Schubert 11785732ac8SCy Schubert msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR); 11885732ac8SCy Schubert if (!msg || 11985732ac8SCy Schubert nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) || 12085732ac8SCy Schubert nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, 12185732ac8SCy Schubert QCA_NL80211_VENDOR_SUBCMD_ABORT_SCAN) || 12285732ac8SCy Schubert !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) || 12385732ac8SCy Schubert nla_put_u64(msg, QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE, scan_cookie)) 12485732ac8SCy Schubert goto fail; 12585732ac8SCy Schubert 12685732ac8SCy Schubert nla_nest_end(msg, params); 12785732ac8SCy Schubert 12885732ac8SCy Schubert ret = send_and_recv_msgs(drv, msg, NULL, NULL); 12985732ac8SCy Schubert msg = NULL; 13085732ac8SCy Schubert if (ret) { 13185732ac8SCy Schubert wpa_printf(MSG_INFO, 13285732ac8SCy Schubert "nl80211: Aborting vendor scan with cookie 0x%llx failed: ret=%d (%s)", 13385732ac8SCy Schubert (long long unsigned int) scan_cookie, ret, 13485732ac8SCy Schubert strerror(-ret)); 13585732ac8SCy Schubert goto fail; 13685732ac8SCy Schubert } 13785732ac8SCy Schubert return 0; 13885732ac8SCy Schubert fail: 13985732ac8SCy Schubert nlmsg_free(msg); 14085732ac8SCy Schubert return -1; 14185732ac8SCy Schubert } 14285732ac8SCy Schubert #endif /* CONFIG_DRIVER_NL80211_QCA */ 14385732ac8SCy Schubert 14485732ac8SCy Schubert 1455b9c547cSRui Paulo /** 1465b9c547cSRui Paulo * wpa_driver_nl80211_scan_timeout - Scan timeout to report scan completion 1475b9c547cSRui Paulo * @eloop_ctx: Driver private data 1485b9c547cSRui Paulo * @timeout_ctx: ctx argument given to wpa_driver_nl80211_init() 1495b9c547cSRui Paulo * 1505b9c547cSRui Paulo * This function can be used as registered timeout when starting a scan to 1515b9c547cSRui Paulo * generate a scan completed event if the driver does not report this. 1525b9c547cSRui Paulo */ 1535b9c547cSRui Paulo void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx) 1545b9c547cSRui Paulo { 1555b9c547cSRui Paulo struct wpa_driver_nl80211_data *drv = eloop_ctx; 156780fb4a2SCy Schubert 157780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "nl80211: Scan timeout - try to abort it"); 15885732ac8SCy Schubert #ifdef CONFIG_DRIVER_NL80211_QCA 15985732ac8SCy Schubert if (drv->vendor_scan_cookie && 16085732ac8SCy Schubert nl80211_abort_vendor_scan(drv, drv->vendor_scan_cookie) == 0) 16185732ac8SCy Schubert return; 16285732ac8SCy Schubert #endif /* CONFIG_DRIVER_NL80211_QCA */ 16385732ac8SCy Schubert if (!drv->vendor_scan_cookie && 16485732ac8SCy Schubert nl80211_abort_scan(drv->first_bss) == 0) 165780fb4a2SCy Schubert return; 166780fb4a2SCy Schubert 167780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "nl80211: Failed to abort scan"); 168780fb4a2SCy Schubert 1695b9c547cSRui Paulo if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) { 1705b9c547cSRui Paulo wpa_driver_nl80211_set_mode(drv->first_bss, 1715b9c547cSRui Paulo drv->ap_scan_as_station); 1725b9c547cSRui Paulo drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED; 1735b9c547cSRui Paulo } 174780fb4a2SCy Schubert 175780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "nl80211: Try to get scan results"); 1765b9c547cSRui Paulo wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); 1775b9c547cSRui Paulo } 1785b9c547cSRui Paulo 1795b9c547cSRui Paulo 1805b9c547cSRui Paulo static struct nl_msg * 1815b9c547cSRui Paulo nl80211_scan_common(struct i802_bss *bss, u8 cmd, 1825b9c547cSRui Paulo struct wpa_driver_scan_params *params) 1835b9c547cSRui Paulo { 1845b9c547cSRui Paulo struct wpa_driver_nl80211_data *drv = bss->drv; 1855b9c547cSRui Paulo struct nl_msg *msg; 1865b9c547cSRui Paulo size_t i; 1875b9c547cSRui Paulo u32 scan_flags = 0; 1885b9c547cSRui Paulo 1895b9c547cSRui Paulo msg = nl80211_cmd_msg(bss, 0, cmd); 1905b9c547cSRui Paulo if (!msg) 1915b9c547cSRui Paulo return NULL; 1925b9c547cSRui Paulo 1935b9c547cSRui Paulo if (params->num_ssids) { 1945b9c547cSRui Paulo struct nlattr *ssids; 1955b9c547cSRui Paulo 1965b9c547cSRui Paulo ssids = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS); 1975b9c547cSRui Paulo if (ssids == NULL) 1985b9c547cSRui Paulo goto fail; 1995b9c547cSRui Paulo for (i = 0; i < params->num_ssids; i++) { 200*4bc52338SCy Schubert wpa_printf(MSG_MSGDUMP, "nl80211: Scan SSID %s", 201*4bc52338SCy Schubert wpa_ssid_txt(params->ssids[i].ssid, 202*4bc52338SCy Schubert params->ssids[i].ssid_len)); 2035b9c547cSRui Paulo if (nla_put(msg, i + 1, params->ssids[i].ssid_len, 2045b9c547cSRui Paulo params->ssids[i].ssid)) 2055b9c547cSRui Paulo goto fail; 2065b9c547cSRui Paulo } 2075b9c547cSRui Paulo nla_nest_end(msg, ssids); 208780fb4a2SCy Schubert } else { 209780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "nl80211: Passive scan requested"); 2105b9c547cSRui Paulo } 2115b9c547cSRui Paulo 2125b9c547cSRui Paulo if (params->extra_ies) { 2135b9c547cSRui Paulo wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs", 2145b9c547cSRui Paulo params->extra_ies, params->extra_ies_len); 2155b9c547cSRui Paulo if (nla_put(msg, NL80211_ATTR_IE, params->extra_ies_len, 2165b9c547cSRui Paulo params->extra_ies)) 2175b9c547cSRui Paulo goto fail; 2185b9c547cSRui Paulo } 2195b9c547cSRui Paulo 2205b9c547cSRui Paulo if (params->freqs) { 2215b9c547cSRui Paulo struct nlattr *freqs; 2225b9c547cSRui Paulo freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES); 2235b9c547cSRui Paulo if (freqs == NULL) 2245b9c547cSRui Paulo goto fail; 2255b9c547cSRui Paulo for (i = 0; params->freqs[i]; i++) { 2265b9c547cSRui Paulo wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u " 2275b9c547cSRui Paulo "MHz", params->freqs[i]); 2285b9c547cSRui Paulo if (nla_put_u32(msg, i + 1, params->freqs[i])) 2295b9c547cSRui Paulo goto fail; 2305b9c547cSRui Paulo } 2315b9c547cSRui Paulo nla_nest_end(msg, freqs); 2325b9c547cSRui Paulo } 2335b9c547cSRui Paulo 2345b9c547cSRui Paulo os_free(drv->filter_ssids); 2355b9c547cSRui Paulo drv->filter_ssids = params->filter_ssids; 2365b9c547cSRui Paulo params->filter_ssids = NULL; 2375b9c547cSRui Paulo drv->num_filter_ssids = params->num_filter_ssids; 2385b9c547cSRui Paulo 2395b9c547cSRui Paulo if (params->only_new_results) { 2405b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: Add NL80211_SCAN_FLAG_FLUSH"); 2415b9c547cSRui Paulo scan_flags |= NL80211_SCAN_FLAG_FLUSH; 2425b9c547cSRui Paulo } 2435b9c547cSRui Paulo 2445b9c547cSRui Paulo if (params->low_priority && drv->have_low_prio_scan) { 2455b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 2465b9c547cSRui Paulo "nl80211: Add NL80211_SCAN_FLAG_LOW_PRIORITY"); 2475b9c547cSRui Paulo scan_flags |= NL80211_SCAN_FLAG_LOW_PRIORITY; 2485b9c547cSRui Paulo } 2495b9c547cSRui Paulo 2505b9c547cSRui Paulo if (params->mac_addr_rand) { 2515b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 2525b9c547cSRui Paulo "nl80211: Add NL80211_SCAN_FLAG_RANDOM_ADDR"); 2535b9c547cSRui Paulo scan_flags |= NL80211_SCAN_FLAG_RANDOM_ADDR; 2545b9c547cSRui Paulo 2555b9c547cSRui Paulo if (params->mac_addr) { 2565b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: MAC address: " MACSTR, 2575b9c547cSRui Paulo MAC2STR(params->mac_addr)); 2585b9c547cSRui Paulo if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, 2595b9c547cSRui Paulo params->mac_addr)) 2605b9c547cSRui Paulo goto fail; 2615b9c547cSRui Paulo } 2625b9c547cSRui Paulo 2635b9c547cSRui Paulo if (params->mac_addr_mask) { 2645b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: MAC address mask: " 2655b9c547cSRui Paulo MACSTR, MAC2STR(params->mac_addr_mask)); 2665b9c547cSRui Paulo if (nla_put(msg, NL80211_ATTR_MAC_MASK, ETH_ALEN, 2675b9c547cSRui Paulo params->mac_addr_mask)) 2685b9c547cSRui Paulo goto fail; 2695b9c547cSRui Paulo } 2705b9c547cSRui Paulo } 2715b9c547cSRui Paulo 27285732ac8SCy Schubert if (params->duration) { 27385732ac8SCy Schubert if (!(drv->capa.rrm_flags & 27485732ac8SCy Schubert WPA_DRIVER_FLAGS_SUPPORT_SET_SCAN_DWELL) || 27585732ac8SCy Schubert nla_put_u16(msg, NL80211_ATTR_MEASUREMENT_DURATION, 27685732ac8SCy Schubert params->duration)) 27785732ac8SCy Schubert goto fail; 27885732ac8SCy Schubert 27985732ac8SCy Schubert if (params->duration_mandatory && 28085732ac8SCy Schubert nla_put_flag(msg, 28185732ac8SCy Schubert NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY)) 28285732ac8SCy Schubert goto fail; 28385732ac8SCy Schubert } 28485732ac8SCy Schubert 28585732ac8SCy Schubert if (params->oce_scan) { 28685732ac8SCy Schubert wpa_printf(MSG_DEBUG, 28785732ac8SCy Schubert "nl80211: Add NL80211_SCAN_FLAG_FILS_MAX_CHANNEL_TIME"); 28885732ac8SCy Schubert wpa_printf(MSG_DEBUG, 28985732ac8SCy Schubert "nl80211: Add NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP"); 29085732ac8SCy Schubert wpa_printf(MSG_DEBUG, 29185732ac8SCy Schubert "nl80211: Add NL80211_SCAN_FLAG_OCE_PROBE_REQ_MIN_TX_RATE"); 29285732ac8SCy Schubert wpa_printf(MSG_DEBUG, 29385732ac8SCy Schubert "nl80211: Add NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION"); 29485732ac8SCy Schubert scan_flags |= NL80211_SCAN_FLAG_FILS_MAX_CHANNEL_TIME | 29585732ac8SCy Schubert NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP | 29685732ac8SCy Schubert NL80211_SCAN_FLAG_OCE_PROBE_REQ_HIGH_TX_RATE | 29785732ac8SCy Schubert NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION; 29885732ac8SCy Schubert } 29985732ac8SCy Schubert 3005b9c547cSRui Paulo if (scan_flags && 3015b9c547cSRui Paulo nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, scan_flags)) 3025b9c547cSRui Paulo goto fail; 3035b9c547cSRui Paulo 3045b9c547cSRui Paulo return msg; 3055b9c547cSRui Paulo 3065b9c547cSRui Paulo fail: 3075b9c547cSRui Paulo nlmsg_free(msg); 3085b9c547cSRui Paulo return NULL; 3095b9c547cSRui Paulo } 3105b9c547cSRui Paulo 3115b9c547cSRui Paulo 3125b9c547cSRui Paulo /** 3135b9c547cSRui Paulo * wpa_driver_nl80211_scan - Request the driver to initiate scan 3145b9c547cSRui Paulo * @bss: Pointer to private driver data from wpa_driver_nl80211_init() 3155b9c547cSRui Paulo * @params: Scan parameters 3165b9c547cSRui Paulo * Returns: 0 on success, -1 on failure 3175b9c547cSRui Paulo */ 3185b9c547cSRui Paulo int wpa_driver_nl80211_scan(struct i802_bss *bss, 3195b9c547cSRui Paulo struct wpa_driver_scan_params *params) 3205b9c547cSRui Paulo { 3215b9c547cSRui Paulo struct wpa_driver_nl80211_data *drv = bss->drv; 3225b9c547cSRui Paulo int ret = -1, timeout; 3235b9c547cSRui Paulo struct nl_msg *msg = NULL; 3245b9c547cSRui Paulo 3255b9c547cSRui Paulo wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request"); 3265b9c547cSRui Paulo drv->scan_for_auth = 0; 3275b9c547cSRui Paulo 328325151a3SRui Paulo if (TEST_FAIL()) 329325151a3SRui Paulo return -1; 330325151a3SRui Paulo 3315b9c547cSRui Paulo msg = nl80211_scan_common(bss, NL80211_CMD_TRIGGER_SCAN, params); 3325b9c547cSRui Paulo if (!msg) 3335b9c547cSRui Paulo return -1; 3345b9c547cSRui Paulo 3355b9c547cSRui Paulo if (params->p2p_probe) { 3365b9c547cSRui Paulo struct nlattr *rates; 3375b9c547cSRui Paulo 3385b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates"); 3395b9c547cSRui Paulo 3405b9c547cSRui Paulo rates = nla_nest_start(msg, NL80211_ATTR_SCAN_SUPP_RATES); 3415b9c547cSRui Paulo if (rates == NULL) 3425b9c547cSRui Paulo goto fail; 3435b9c547cSRui Paulo 3445b9c547cSRui Paulo /* 3455b9c547cSRui Paulo * Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates 3465b9c547cSRui Paulo * by masking out everything else apart from the OFDM rates 6, 3475b9c547cSRui Paulo * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz 3485b9c547cSRui Paulo * rates are left enabled. 3495b9c547cSRui Paulo */ 3505b9c547cSRui Paulo if (nla_put(msg, NL80211_BAND_2GHZ, 8, 3515b9c547cSRui Paulo "\x0c\x12\x18\x24\x30\x48\x60\x6c")) 3525b9c547cSRui Paulo goto fail; 3535b9c547cSRui Paulo nla_nest_end(msg, rates); 3545b9c547cSRui Paulo 3555b9c547cSRui Paulo if (nla_put_flag(msg, NL80211_ATTR_TX_NO_CCK_RATE)) 3565b9c547cSRui Paulo goto fail; 3575b9c547cSRui Paulo } 3585b9c547cSRui Paulo 359780fb4a2SCy Schubert if (params->bssid) { 360780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "nl80211: Scan for a specific BSSID: " 361780fb4a2SCy Schubert MACSTR, MAC2STR(params->bssid)); 362780fb4a2SCy Schubert if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid)) 363780fb4a2SCy Schubert goto fail; 364780fb4a2SCy Schubert } 365780fb4a2SCy Schubert 3665b9c547cSRui Paulo ret = send_and_recv_msgs(drv, msg, NULL, NULL); 3675b9c547cSRui Paulo msg = NULL; 3685b9c547cSRui Paulo if (ret) { 3695b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d " 3705b9c547cSRui Paulo "(%s)", ret, strerror(-ret)); 3715b9c547cSRui Paulo if (drv->hostapd && is_ap_interface(drv->nlmode)) { 3725b9c547cSRui Paulo enum nl80211_iftype old_mode = drv->nlmode; 3735b9c547cSRui Paulo 3745b9c547cSRui Paulo /* 3755b9c547cSRui Paulo * mac80211 does not allow scan requests in AP mode, so 3765b9c547cSRui Paulo * try to do this in station mode. 3775b9c547cSRui Paulo */ 3785b9c547cSRui Paulo if (wpa_driver_nl80211_set_mode( 3795b9c547cSRui Paulo bss, NL80211_IFTYPE_STATION)) 3805b9c547cSRui Paulo goto fail; 3815b9c547cSRui Paulo 3825b9c547cSRui Paulo if (wpa_driver_nl80211_scan(bss, params)) { 3835b9c547cSRui Paulo wpa_driver_nl80211_set_mode(bss, old_mode); 3845b9c547cSRui Paulo goto fail; 3855b9c547cSRui Paulo } 3865b9c547cSRui Paulo 3875b9c547cSRui Paulo /* Restore AP mode when processing scan results */ 3885b9c547cSRui Paulo drv->ap_scan_as_station = old_mode; 3895b9c547cSRui Paulo ret = 0; 3905b9c547cSRui Paulo } else 3915b9c547cSRui Paulo goto fail; 3925b9c547cSRui Paulo } 3935b9c547cSRui Paulo 3945b9c547cSRui Paulo drv->scan_state = SCAN_REQUESTED; 3955b9c547cSRui Paulo /* Not all drivers generate "scan completed" wireless event, so try to 3965b9c547cSRui Paulo * read results after a timeout. */ 3975b9c547cSRui Paulo timeout = 10; 3985b9c547cSRui Paulo if (drv->scan_complete_events) { 3995b9c547cSRui Paulo /* 4005b9c547cSRui Paulo * The driver seems to deliver events to notify when scan is 4015b9c547cSRui Paulo * complete, so use longer timeout to avoid race conditions 4025b9c547cSRui Paulo * with scanning and following association request. 4035b9c547cSRui Paulo */ 4045b9c547cSRui Paulo timeout = 30; 4055b9c547cSRui Paulo } 4065b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d " 4075b9c547cSRui Paulo "seconds", ret, timeout); 4085b9c547cSRui Paulo eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx); 4095b9c547cSRui Paulo eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout, 4105b9c547cSRui Paulo drv, drv->ctx); 411780fb4a2SCy Schubert drv->last_scan_cmd = NL80211_CMD_TRIGGER_SCAN; 4125b9c547cSRui Paulo 4135b9c547cSRui Paulo fail: 4145b9c547cSRui Paulo nlmsg_free(msg); 4155b9c547cSRui Paulo return ret; 4165b9c547cSRui Paulo } 4175b9c547cSRui Paulo 4185b9c547cSRui Paulo 419780fb4a2SCy Schubert static int 420780fb4a2SCy Schubert nl80211_sched_scan_add_scan_plans(struct wpa_driver_nl80211_data *drv, 421780fb4a2SCy Schubert struct nl_msg *msg, 422780fb4a2SCy Schubert struct wpa_driver_scan_params *params) 423780fb4a2SCy Schubert { 424780fb4a2SCy Schubert struct nlattr *plans; 425780fb4a2SCy Schubert struct sched_scan_plan *scan_plans = params->sched_scan_plans; 426780fb4a2SCy Schubert unsigned int i; 427780fb4a2SCy Schubert 428780fb4a2SCy Schubert plans = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_PLANS); 429780fb4a2SCy Schubert if (!plans) 430780fb4a2SCy Schubert return -1; 431780fb4a2SCy Schubert 432780fb4a2SCy Schubert for (i = 0; i < params->sched_scan_plans_num; i++) { 433780fb4a2SCy Schubert struct nlattr *plan = nla_nest_start(msg, i + 1); 434780fb4a2SCy Schubert 435780fb4a2SCy Schubert if (!plan) 436780fb4a2SCy Schubert return -1; 437780fb4a2SCy Schubert 438780fb4a2SCy Schubert if (!scan_plans[i].interval || 439780fb4a2SCy Schubert scan_plans[i].interval > 440780fb4a2SCy Schubert drv->capa.max_sched_scan_plan_interval) { 441780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, 442780fb4a2SCy Schubert "nl80211: sched scan plan no. %u: Invalid interval: %u", 443780fb4a2SCy Schubert i, scan_plans[i].interval); 444780fb4a2SCy Schubert return -1; 445780fb4a2SCy Schubert } 446780fb4a2SCy Schubert 447780fb4a2SCy Schubert if (nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_INTERVAL, 448780fb4a2SCy Schubert scan_plans[i].interval)) 449780fb4a2SCy Schubert return -1; 450780fb4a2SCy Schubert 451780fb4a2SCy Schubert if (scan_plans[i].iterations > 452780fb4a2SCy Schubert drv->capa.max_sched_scan_plan_iterations) { 453780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, 454780fb4a2SCy Schubert "nl80211: sched scan plan no. %u: Invalid number of iterations: %u", 455780fb4a2SCy Schubert i, scan_plans[i].iterations); 456780fb4a2SCy Schubert return -1; 457780fb4a2SCy Schubert } 458780fb4a2SCy Schubert 459780fb4a2SCy Schubert if (scan_plans[i].iterations && 460780fb4a2SCy Schubert nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_ITERATIONS, 461780fb4a2SCy Schubert scan_plans[i].iterations)) 462780fb4a2SCy Schubert return -1; 463780fb4a2SCy Schubert 464780fb4a2SCy Schubert nla_nest_end(msg, plan); 465780fb4a2SCy Schubert 466780fb4a2SCy Schubert /* 467780fb4a2SCy Schubert * All the scan plans must specify the number of iterations 468780fb4a2SCy Schubert * except the last plan, which will run infinitely. So if the 469780fb4a2SCy Schubert * number of iterations is not specified, this ought to be the 470780fb4a2SCy Schubert * last scan plan. 471780fb4a2SCy Schubert */ 472780fb4a2SCy Schubert if (!scan_plans[i].iterations) 473780fb4a2SCy Schubert break; 474780fb4a2SCy Schubert } 475780fb4a2SCy Schubert 476780fb4a2SCy Schubert if (i != params->sched_scan_plans_num - 1) { 477780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, 478780fb4a2SCy Schubert "nl80211: All sched scan plans but the last must specify number of iterations"); 479780fb4a2SCy Schubert return -1; 480780fb4a2SCy Schubert } 481780fb4a2SCy Schubert 482780fb4a2SCy Schubert nla_nest_end(msg, plans); 483780fb4a2SCy Schubert return 0; 484780fb4a2SCy Schubert } 485780fb4a2SCy Schubert 486780fb4a2SCy Schubert 4875b9c547cSRui Paulo /** 4885b9c547cSRui Paulo * wpa_driver_nl80211_sched_scan - Initiate a scheduled scan 4895b9c547cSRui Paulo * @priv: Pointer to private driver data from wpa_driver_nl80211_init() 4905b9c547cSRui Paulo * @params: Scan parameters 4915b9c547cSRui Paulo * Returns: 0 on success, -1 on failure or if not supported 4925b9c547cSRui Paulo */ 4935b9c547cSRui Paulo int wpa_driver_nl80211_sched_scan(void *priv, 494780fb4a2SCy Schubert struct wpa_driver_scan_params *params) 4955b9c547cSRui Paulo { 4965b9c547cSRui Paulo struct i802_bss *bss = priv; 4975b9c547cSRui Paulo struct wpa_driver_nl80211_data *drv = bss->drv; 4985b9c547cSRui Paulo int ret = -1; 4995b9c547cSRui Paulo struct nl_msg *msg; 5005b9c547cSRui Paulo size_t i; 5015b9c547cSRui Paulo 5025b9c547cSRui Paulo wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: sched_scan request"); 5035b9c547cSRui Paulo 5045b9c547cSRui Paulo #ifdef ANDROID 5055b9c547cSRui Paulo if (!drv->capa.sched_scan_supported) 5065b9c547cSRui Paulo return android_pno_start(bss, params); 5075b9c547cSRui Paulo #endif /* ANDROID */ 5085b9c547cSRui Paulo 509780fb4a2SCy Schubert if (!params->sched_scan_plans_num || 510780fb4a2SCy Schubert params->sched_scan_plans_num > drv->capa.max_sched_scan_plans) { 511780fb4a2SCy Schubert wpa_printf(MSG_ERROR, 512780fb4a2SCy Schubert "nl80211: Invalid number of sched scan plans: %u", 513780fb4a2SCy Schubert params->sched_scan_plans_num); 514780fb4a2SCy Schubert return -1; 515780fb4a2SCy Schubert } 516780fb4a2SCy Schubert 5175b9c547cSRui Paulo msg = nl80211_scan_common(bss, NL80211_CMD_START_SCHED_SCAN, params); 518780fb4a2SCy Schubert if (!msg) 5195b9c547cSRui Paulo goto fail; 5205b9c547cSRui Paulo 521780fb4a2SCy Schubert if (drv->capa.max_sched_scan_plan_iterations) { 522780fb4a2SCy Schubert if (nl80211_sched_scan_add_scan_plans(drv, msg, params)) 523780fb4a2SCy Schubert goto fail; 524780fb4a2SCy Schubert } else { 525780fb4a2SCy Schubert if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, 526780fb4a2SCy Schubert params->sched_scan_plans[0].interval * 1000)) 527780fb4a2SCy Schubert goto fail; 528780fb4a2SCy Schubert } 529780fb4a2SCy Schubert 5305b9c547cSRui Paulo if ((drv->num_filter_ssids && 5315b9c547cSRui Paulo (int) drv->num_filter_ssids <= drv->capa.max_match_sets) || 5325b9c547cSRui Paulo params->filter_rssi) { 5335b9c547cSRui Paulo struct nlattr *match_sets; 5345b9c547cSRui Paulo match_sets = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH); 5355b9c547cSRui Paulo if (match_sets == NULL) 5365b9c547cSRui Paulo goto fail; 5375b9c547cSRui Paulo 5385b9c547cSRui Paulo for (i = 0; i < drv->num_filter_ssids; i++) { 5395b9c547cSRui Paulo struct nlattr *match_set_ssid; 540*4bc52338SCy Schubert wpa_printf(MSG_MSGDUMP, 541*4bc52338SCy Schubert "nl80211: Sched scan filter SSID %s", 542*4bc52338SCy Schubert wpa_ssid_txt(drv->filter_ssids[i].ssid, 543*4bc52338SCy Schubert drv->filter_ssids[i].ssid_len)); 5445b9c547cSRui Paulo 5455b9c547cSRui Paulo match_set_ssid = nla_nest_start(msg, i + 1); 5465b9c547cSRui Paulo if (match_set_ssid == NULL || 5475b9c547cSRui Paulo nla_put(msg, NL80211_ATTR_SCHED_SCAN_MATCH_SSID, 5485b9c547cSRui Paulo drv->filter_ssids[i].ssid_len, 5495b9c547cSRui Paulo drv->filter_ssids[i].ssid) || 5505b9c547cSRui Paulo (params->filter_rssi && 5515b9c547cSRui Paulo nla_put_u32(msg, 5525b9c547cSRui Paulo NL80211_SCHED_SCAN_MATCH_ATTR_RSSI, 5535b9c547cSRui Paulo params->filter_rssi))) 5545b9c547cSRui Paulo goto fail; 5555b9c547cSRui Paulo 5565b9c547cSRui Paulo nla_nest_end(msg, match_set_ssid); 5575b9c547cSRui Paulo } 5585b9c547cSRui Paulo 5595b9c547cSRui Paulo /* 5605b9c547cSRui Paulo * Due to backward compatibility code, newer kernels treat this 5615b9c547cSRui Paulo * matchset (with only an RSSI filter) as the default for all 5625b9c547cSRui Paulo * other matchsets, unless it's the only one, in which case the 5635b9c547cSRui Paulo * matchset will actually allow all SSIDs above the RSSI. 5645b9c547cSRui Paulo */ 5655b9c547cSRui Paulo if (params->filter_rssi) { 5665b9c547cSRui Paulo struct nlattr *match_set_rssi; 5675b9c547cSRui Paulo match_set_rssi = nla_nest_start(msg, 0); 5685b9c547cSRui Paulo if (match_set_rssi == NULL || 5695b9c547cSRui Paulo nla_put_u32(msg, NL80211_SCHED_SCAN_MATCH_ATTR_RSSI, 5705b9c547cSRui Paulo params->filter_rssi)) 5715b9c547cSRui Paulo goto fail; 5725b9c547cSRui Paulo wpa_printf(MSG_MSGDUMP, 5735b9c547cSRui Paulo "nl80211: Sched scan RSSI filter %d dBm", 5745b9c547cSRui Paulo params->filter_rssi); 5755b9c547cSRui Paulo nla_nest_end(msg, match_set_rssi); 5765b9c547cSRui Paulo } 5775b9c547cSRui Paulo 5785b9c547cSRui Paulo nla_nest_end(msg, match_sets); 5795b9c547cSRui Paulo } 5805b9c547cSRui Paulo 58185732ac8SCy Schubert if (params->relative_rssi_set) { 58285732ac8SCy Schubert struct nl80211_bss_select_rssi_adjust rssi_adjust; 58385732ac8SCy Schubert 58485732ac8SCy Schubert os_memset(&rssi_adjust, 0, sizeof(rssi_adjust)); 58585732ac8SCy Schubert wpa_printf(MSG_DEBUG, "nl80211: Relative RSSI: %d", 58685732ac8SCy Schubert params->relative_rssi); 58785732ac8SCy Schubert if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI, 58885732ac8SCy Schubert params->relative_rssi)) 58985732ac8SCy Schubert goto fail; 59085732ac8SCy Schubert 59185732ac8SCy Schubert if (params->relative_adjust_rssi) { 59285732ac8SCy Schubert int pref_band_set = 1; 59385732ac8SCy Schubert 59485732ac8SCy Schubert switch (params->relative_adjust_band) { 59585732ac8SCy Schubert case WPA_SETBAND_5G: 59685732ac8SCy Schubert rssi_adjust.band = NL80211_BAND_5GHZ; 59785732ac8SCy Schubert break; 59885732ac8SCy Schubert case WPA_SETBAND_2G: 59985732ac8SCy Schubert rssi_adjust.band = NL80211_BAND_2GHZ; 60085732ac8SCy Schubert break; 60185732ac8SCy Schubert default: 60285732ac8SCy Schubert pref_band_set = 0; 60385732ac8SCy Schubert break; 60485732ac8SCy Schubert } 60585732ac8SCy Schubert rssi_adjust.delta = params->relative_adjust_rssi; 60685732ac8SCy Schubert 60785732ac8SCy Schubert if (pref_band_set && 60885732ac8SCy Schubert nla_put(msg, NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST, 60985732ac8SCy Schubert sizeof(rssi_adjust), &rssi_adjust)) 61085732ac8SCy Schubert goto fail; 61185732ac8SCy Schubert } 61285732ac8SCy Schubert } 61385732ac8SCy Schubert 61485732ac8SCy Schubert if (params->sched_scan_start_delay && 61585732ac8SCy Schubert nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_DELAY, 61685732ac8SCy Schubert params->sched_scan_start_delay)) 61785732ac8SCy Schubert goto fail; 61885732ac8SCy Schubert 6195b9c547cSRui Paulo ret = send_and_recv_msgs(drv, msg, NULL, NULL); 6205b9c547cSRui Paulo 6215b9c547cSRui Paulo /* TODO: if we get an error here, we should fall back to normal scan */ 6225b9c547cSRui Paulo 6235b9c547cSRui Paulo msg = NULL; 6245b9c547cSRui Paulo if (ret) { 6255b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: Sched scan start failed: " 6265b9c547cSRui Paulo "ret=%d (%s)", ret, strerror(-ret)); 6275b9c547cSRui Paulo goto fail; 6285b9c547cSRui Paulo } 6295b9c547cSRui Paulo 630780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "nl80211: Sched scan requested (ret=%d)", ret); 6315b9c547cSRui Paulo 6325b9c547cSRui Paulo fail: 6335b9c547cSRui Paulo nlmsg_free(msg); 6345b9c547cSRui Paulo return ret; 6355b9c547cSRui Paulo } 6365b9c547cSRui Paulo 6375b9c547cSRui Paulo 6385b9c547cSRui Paulo /** 6395b9c547cSRui Paulo * wpa_driver_nl80211_stop_sched_scan - Stop a scheduled scan 6405b9c547cSRui Paulo * @priv: Pointer to private driver data from wpa_driver_nl80211_init() 6415b9c547cSRui Paulo * Returns: 0 on success, -1 on failure or if not supported 6425b9c547cSRui Paulo */ 6435b9c547cSRui Paulo int wpa_driver_nl80211_stop_sched_scan(void *priv) 6445b9c547cSRui Paulo { 6455b9c547cSRui Paulo struct i802_bss *bss = priv; 6465b9c547cSRui Paulo struct wpa_driver_nl80211_data *drv = bss->drv; 6475b9c547cSRui Paulo int ret; 6485b9c547cSRui Paulo struct nl_msg *msg; 6495b9c547cSRui Paulo 6505b9c547cSRui Paulo #ifdef ANDROID 6515b9c547cSRui Paulo if (!drv->capa.sched_scan_supported) 6525b9c547cSRui Paulo return android_pno_stop(bss); 6535b9c547cSRui Paulo #endif /* ANDROID */ 6545b9c547cSRui Paulo 6555b9c547cSRui Paulo msg = nl80211_drv_msg(drv, 0, NL80211_CMD_STOP_SCHED_SCAN); 6565b9c547cSRui Paulo ret = send_and_recv_msgs(drv, msg, NULL, NULL); 6575b9c547cSRui Paulo if (ret) { 6585b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 6595b9c547cSRui Paulo "nl80211: Sched scan stop failed: ret=%d (%s)", 6605b9c547cSRui Paulo ret, strerror(-ret)); 6615b9c547cSRui Paulo } else { 6625b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 6635b9c547cSRui Paulo "nl80211: Sched scan stop sent"); 6645b9c547cSRui Paulo } 6655b9c547cSRui Paulo 6665b9c547cSRui Paulo return ret; 6675b9c547cSRui Paulo } 6685b9c547cSRui Paulo 6695b9c547cSRui Paulo 6705b9c547cSRui Paulo static int nl80211_scan_filtered(struct wpa_driver_nl80211_data *drv, 6715b9c547cSRui Paulo const u8 *ie, size_t ie_len) 6725b9c547cSRui Paulo { 6735b9c547cSRui Paulo const u8 *ssid; 6745b9c547cSRui Paulo size_t i; 6755b9c547cSRui Paulo 6765b9c547cSRui Paulo if (drv->filter_ssids == NULL) 6775b9c547cSRui Paulo return 0; 6785b9c547cSRui Paulo 679780fb4a2SCy Schubert ssid = get_ie(ie, ie_len, WLAN_EID_SSID); 6805b9c547cSRui Paulo if (ssid == NULL) 6815b9c547cSRui Paulo return 1; 6825b9c547cSRui Paulo 6835b9c547cSRui Paulo for (i = 0; i < drv->num_filter_ssids; i++) { 6845b9c547cSRui Paulo if (ssid[1] == drv->filter_ssids[i].ssid_len && 6855b9c547cSRui Paulo os_memcmp(ssid + 2, drv->filter_ssids[i].ssid, ssid[1]) == 6865b9c547cSRui Paulo 0) 6875b9c547cSRui Paulo return 0; 6885b9c547cSRui Paulo } 6895b9c547cSRui Paulo 6905b9c547cSRui Paulo return 1; 6915b9c547cSRui Paulo } 6925b9c547cSRui Paulo 6935b9c547cSRui Paulo 69485732ac8SCy Schubert static struct wpa_scan_res * 69585732ac8SCy Schubert nl80211_parse_bss_info(struct wpa_driver_nl80211_data *drv, 69685732ac8SCy Schubert struct nl_msg *msg) 6975b9c547cSRui Paulo { 6985b9c547cSRui Paulo struct nlattr *tb[NL80211_ATTR_MAX + 1]; 6995b9c547cSRui Paulo struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); 7005b9c547cSRui Paulo struct nlattr *bss[NL80211_BSS_MAX + 1]; 7015b9c547cSRui Paulo static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = { 7025b9c547cSRui Paulo [NL80211_BSS_BSSID] = { .type = NLA_UNSPEC }, 7035b9c547cSRui Paulo [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 }, 7045b9c547cSRui Paulo [NL80211_BSS_TSF] = { .type = NLA_U64 }, 7055b9c547cSRui Paulo [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 }, 7065b9c547cSRui Paulo [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 }, 7075b9c547cSRui Paulo [NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC }, 7085b9c547cSRui Paulo [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 }, 7095b9c547cSRui Paulo [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 }, 7105b9c547cSRui Paulo [NL80211_BSS_STATUS] = { .type = NLA_U32 }, 7115b9c547cSRui Paulo [NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 }, 7125b9c547cSRui Paulo [NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC }, 71385732ac8SCy Schubert [NL80211_BSS_PARENT_TSF] = { .type = NLA_U64 }, 71485732ac8SCy Schubert [NL80211_BSS_PARENT_BSSID] = { .type = NLA_UNSPEC }, 71585732ac8SCy Schubert [NL80211_BSS_LAST_SEEN_BOOTTIME] = { .type = NLA_U64 }, 7165b9c547cSRui Paulo }; 7175b9c547cSRui Paulo struct wpa_scan_res *r; 7185b9c547cSRui Paulo const u8 *ie, *beacon_ie; 7195b9c547cSRui Paulo size_t ie_len, beacon_ie_len; 7205b9c547cSRui Paulo u8 *pos; 7215b9c547cSRui Paulo 7225b9c547cSRui Paulo nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), 7235b9c547cSRui Paulo genlmsg_attrlen(gnlh, 0), NULL); 7245b9c547cSRui Paulo if (!tb[NL80211_ATTR_BSS]) 72585732ac8SCy Schubert return NULL; 7265b9c547cSRui Paulo if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS], 7275b9c547cSRui Paulo bss_policy)) 72885732ac8SCy Schubert return NULL; 7295b9c547cSRui Paulo if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) { 7305b9c547cSRui Paulo ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]); 7315b9c547cSRui Paulo ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]); 7325b9c547cSRui Paulo } else { 7335b9c547cSRui Paulo ie = NULL; 7345b9c547cSRui Paulo ie_len = 0; 7355b9c547cSRui Paulo } 7365b9c547cSRui Paulo if (bss[NL80211_BSS_BEACON_IES]) { 7375b9c547cSRui Paulo beacon_ie = nla_data(bss[NL80211_BSS_BEACON_IES]); 7385b9c547cSRui Paulo beacon_ie_len = nla_len(bss[NL80211_BSS_BEACON_IES]); 7395b9c547cSRui Paulo } else { 7405b9c547cSRui Paulo beacon_ie = NULL; 7415b9c547cSRui Paulo beacon_ie_len = 0; 7425b9c547cSRui Paulo } 7435b9c547cSRui Paulo 74485732ac8SCy Schubert if (nl80211_scan_filtered(drv, ie ? ie : beacon_ie, 7455b9c547cSRui Paulo ie ? ie_len : beacon_ie_len)) 74685732ac8SCy Schubert return NULL; 7475b9c547cSRui Paulo 7485b9c547cSRui Paulo r = os_zalloc(sizeof(*r) + ie_len + beacon_ie_len); 7495b9c547cSRui Paulo if (r == NULL) 75085732ac8SCy Schubert return NULL; 7515b9c547cSRui Paulo if (bss[NL80211_BSS_BSSID]) 7525b9c547cSRui Paulo os_memcpy(r->bssid, nla_data(bss[NL80211_BSS_BSSID]), 7535b9c547cSRui Paulo ETH_ALEN); 7545b9c547cSRui Paulo if (bss[NL80211_BSS_FREQUENCY]) 7555b9c547cSRui Paulo r->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]); 7565b9c547cSRui Paulo if (bss[NL80211_BSS_BEACON_INTERVAL]) 7575b9c547cSRui Paulo r->beacon_int = nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]); 7585b9c547cSRui Paulo if (bss[NL80211_BSS_CAPABILITY]) 7595b9c547cSRui Paulo r->caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]); 7605b9c547cSRui Paulo r->flags |= WPA_SCAN_NOISE_INVALID; 7615b9c547cSRui Paulo if (bss[NL80211_BSS_SIGNAL_MBM]) { 7625b9c547cSRui Paulo r->level = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]); 7635b9c547cSRui Paulo r->level /= 100; /* mBm to dBm */ 7645b9c547cSRui Paulo r->flags |= WPA_SCAN_LEVEL_DBM | WPA_SCAN_QUAL_INVALID; 7655b9c547cSRui Paulo } else if (bss[NL80211_BSS_SIGNAL_UNSPEC]) { 7665b9c547cSRui Paulo r->level = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]); 7675b9c547cSRui Paulo r->flags |= WPA_SCAN_QUAL_INVALID; 7685b9c547cSRui Paulo } else 7695b9c547cSRui Paulo r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID; 7705b9c547cSRui Paulo if (bss[NL80211_BSS_TSF]) 7715b9c547cSRui Paulo r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]); 772325151a3SRui Paulo if (bss[NL80211_BSS_BEACON_TSF]) { 773325151a3SRui Paulo u64 tsf = nla_get_u64(bss[NL80211_BSS_BEACON_TSF]); 774325151a3SRui Paulo if (tsf > r->tsf) 775325151a3SRui Paulo r->tsf = tsf; 776325151a3SRui Paulo } 7775b9c547cSRui Paulo if (bss[NL80211_BSS_SEEN_MS_AGO]) 7785b9c547cSRui Paulo r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]); 77985732ac8SCy Schubert if (bss[NL80211_BSS_LAST_SEEN_BOOTTIME]) { 78085732ac8SCy Schubert u64 boottime; 78185732ac8SCy Schubert struct timespec ts; 78285732ac8SCy Schubert 78385732ac8SCy Schubert #ifndef CLOCK_BOOTTIME 78485732ac8SCy Schubert #define CLOCK_BOOTTIME 7 78585732ac8SCy Schubert #endif 78685732ac8SCy Schubert if (clock_gettime(CLOCK_BOOTTIME, &ts) == 0) { 78785732ac8SCy Schubert /* Use more accurate boottime information to update the 78885732ac8SCy Schubert * scan result age since the driver reports this and 78985732ac8SCy Schubert * CLOCK_BOOTTIME is available. */ 79085732ac8SCy Schubert boottime = nla_get_u64( 79185732ac8SCy Schubert bss[NL80211_BSS_LAST_SEEN_BOOTTIME]); 79285732ac8SCy Schubert r->age = ((u64) ts.tv_sec * 1000000000 + 79385732ac8SCy Schubert ts.tv_nsec - boottime) / 1000000; 79485732ac8SCy Schubert } 79585732ac8SCy Schubert } 7965b9c547cSRui Paulo r->ie_len = ie_len; 7975b9c547cSRui Paulo pos = (u8 *) (r + 1); 7985b9c547cSRui Paulo if (ie) { 7995b9c547cSRui Paulo os_memcpy(pos, ie, ie_len); 8005b9c547cSRui Paulo pos += ie_len; 8015b9c547cSRui Paulo } 8025b9c547cSRui Paulo r->beacon_ie_len = beacon_ie_len; 8035b9c547cSRui Paulo if (beacon_ie) 8045b9c547cSRui Paulo os_memcpy(pos, beacon_ie, beacon_ie_len); 8055b9c547cSRui Paulo 8065b9c547cSRui Paulo if (bss[NL80211_BSS_STATUS]) { 8075b9c547cSRui Paulo enum nl80211_bss_status status; 8085b9c547cSRui Paulo status = nla_get_u32(bss[NL80211_BSS_STATUS]); 8095b9c547cSRui Paulo switch (status) { 8105b9c547cSRui Paulo case NL80211_BSS_STATUS_ASSOCIATED: 8115b9c547cSRui Paulo r->flags |= WPA_SCAN_ASSOCIATED; 8125b9c547cSRui Paulo break; 8135b9c547cSRui Paulo default: 8145b9c547cSRui Paulo break; 8155b9c547cSRui Paulo } 8165b9c547cSRui Paulo } 8175b9c547cSRui Paulo 81885732ac8SCy Schubert if (bss[NL80211_BSS_PARENT_TSF] && bss[NL80211_BSS_PARENT_BSSID]) { 81985732ac8SCy Schubert r->parent_tsf = nla_get_u64(bss[NL80211_BSS_PARENT_TSF]); 82085732ac8SCy Schubert os_memcpy(r->tsf_bssid, nla_data(bss[NL80211_BSS_PARENT_BSSID]), 82185732ac8SCy Schubert ETH_ALEN); 82285732ac8SCy Schubert } 8235b9c547cSRui Paulo 82485732ac8SCy Schubert return r; 82585732ac8SCy Schubert } 8265b9c547cSRui Paulo 8275b9c547cSRui Paulo 82885732ac8SCy Schubert struct nl80211_bss_info_arg { 82985732ac8SCy Schubert struct wpa_driver_nl80211_data *drv; 83085732ac8SCy Schubert struct wpa_scan_results *res; 83185732ac8SCy Schubert }; 83285732ac8SCy Schubert 83385732ac8SCy Schubert static int bss_info_handler(struct nl_msg *msg, void *arg) 83485732ac8SCy Schubert { 83585732ac8SCy Schubert struct nl80211_bss_info_arg *_arg = arg; 83685732ac8SCy Schubert struct wpa_scan_results *res = _arg->res; 83785732ac8SCy Schubert struct wpa_scan_res **tmp; 83885732ac8SCy Schubert struct wpa_scan_res *r; 83985732ac8SCy Schubert 84085732ac8SCy Schubert r = nl80211_parse_bss_info(_arg->drv, msg); 84185732ac8SCy Schubert if (!r) 84285732ac8SCy Schubert return NL_SKIP; 84385732ac8SCy Schubert 84485732ac8SCy Schubert if (!res) { 8455b9c547cSRui Paulo os_free(r); 8465b9c547cSRui Paulo return NL_SKIP; 8475b9c547cSRui Paulo } 8485b9c547cSRui Paulo tmp = os_realloc_array(res->res, res->num + 1, 8495b9c547cSRui Paulo sizeof(struct wpa_scan_res *)); 8505b9c547cSRui Paulo if (tmp == NULL) { 8515b9c547cSRui Paulo os_free(r); 8525b9c547cSRui Paulo return NL_SKIP; 8535b9c547cSRui Paulo } 8545b9c547cSRui Paulo tmp[res->num++] = r; 8555b9c547cSRui Paulo res->res = tmp; 8565b9c547cSRui Paulo 8575b9c547cSRui Paulo return NL_SKIP; 8585b9c547cSRui Paulo } 8595b9c547cSRui Paulo 8605b9c547cSRui Paulo 8615b9c547cSRui Paulo static void clear_state_mismatch(struct wpa_driver_nl80211_data *drv, 8625b9c547cSRui Paulo const u8 *addr) 8635b9c547cSRui Paulo { 8645b9c547cSRui Paulo if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) { 8655b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: Clear possible state " 8665b9c547cSRui Paulo "mismatch (" MACSTR ")", MAC2STR(addr)); 8675b9c547cSRui Paulo wpa_driver_nl80211_mlme(drv, addr, 8685b9c547cSRui Paulo NL80211_CMD_DEAUTHENTICATE, 86985732ac8SCy Schubert WLAN_REASON_PREV_AUTH_NOT_VALID, 1, 87085732ac8SCy Schubert NULL); 87185732ac8SCy Schubert } 87285732ac8SCy Schubert } 87385732ac8SCy Schubert 87485732ac8SCy Schubert 87585732ac8SCy Schubert static void nl80211_check_bss_status(struct wpa_driver_nl80211_data *drv, 87685732ac8SCy Schubert struct wpa_scan_res *r) 87785732ac8SCy Schubert { 87885732ac8SCy Schubert if (!(r->flags & WPA_SCAN_ASSOCIATED)) 87985732ac8SCy Schubert return; 88085732ac8SCy Schubert 88185732ac8SCy Schubert wpa_printf(MSG_DEBUG, "nl80211: Scan results indicate BSS status with " 88285732ac8SCy Schubert MACSTR " as associated", MAC2STR(r->bssid)); 88385732ac8SCy Schubert if (is_sta_interface(drv->nlmode) && !drv->associated) { 88485732ac8SCy Schubert wpa_printf(MSG_DEBUG, 88585732ac8SCy Schubert "nl80211: Local state (not associated) does not match with BSS state"); 88685732ac8SCy Schubert clear_state_mismatch(drv, r->bssid); 88785732ac8SCy Schubert } else if (is_sta_interface(drv->nlmode) && 88885732ac8SCy Schubert os_memcmp(drv->bssid, r->bssid, ETH_ALEN) != 0) { 88985732ac8SCy Schubert wpa_printf(MSG_DEBUG, 89085732ac8SCy Schubert "nl80211: Local state (associated with " MACSTR 89185732ac8SCy Schubert ") does not match with BSS state", 89285732ac8SCy Schubert MAC2STR(drv->bssid)); 89385732ac8SCy Schubert clear_state_mismatch(drv, r->bssid); 89485732ac8SCy Schubert clear_state_mismatch(drv, drv->bssid); 8955b9c547cSRui Paulo } 8965b9c547cSRui Paulo } 8975b9c547cSRui Paulo 8985b9c547cSRui Paulo 8995b9c547cSRui Paulo static void wpa_driver_nl80211_check_bss_status( 9005b9c547cSRui Paulo struct wpa_driver_nl80211_data *drv, struct wpa_scan_results *res) 9015b9c547cSRui Paulo { 9025b9c547cSRui Paulo size_t i; 9035b9c547cSRui Paulo 90485732ac8SCy Schubert for (i = 0; i < res->num; i++) 90585732ac8SCy Schubert nl80211_check_bss_status(drv, res->res[i]); 90685732ac8SCy Schubert } 9075b9c547cSRui Paulo 90885732ac8SCy Schubert 90985732ac8SCy Schubert static void nl80211_update_scan_res_noise(struct wpa_scan_res *res, 91085732ac8SCy Schubert struct nl80211_noise_info *info) 91185732ac8SCy Schubert { 91285732ac8SCy Schubert unsigned int i; 91385732ac8SCy Schubert 91485732ac8SCy Schubert for (i = 0; res && i < info->count; i++) { 91585732ac8SCy Schubert if ((int) info->freq[i] != res->freq || 91685732ac8SCy Schubert !(res->flags & WPA_SCAN_NOISE_INVALID)) 91785732ac8SCy Schubert continue; 91885732ac8SCy Schubert res->noise = info->noise[i]; 91985732ac8SCy Schubert res->flags &= ~WPA_SCAN_NOISE_INVALID; 9205b9c547cSRui Paulo } 9215b9c547cSRui Paulo } 9225b9c547cSRui Paulo 9235b9c547cSRui Paulo 9245b9c547cSRui Paulo static struct wpa_scan_results * 9255b9c547cSRui Paulo nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv) 9265b9c547cSRui Paulo { 9275b9c547cSRui Paulo struct nl_msg *msg; 9285b9c547cSRui Paulo struct wpa_scan_results *res; 9295b9c547cSRui Paulo int ret; 9305b9c547cSRui Paulo struct nl80211_bss_info_arg arg; 9315b9c547cSRui Paulo 9325b9c547cSRui Paulo res = os_zalloc(sizeof(*res)); 9335b9c547cSRui Paulo if (res == NULL) 9345b9c547cSRui Paulo return NULL; 9355b9c547cSRui Paulo if (!(msg = nl80211_cmd_msg(drv->first_bss, NLM_F_DUMP, 9365b9c547cSRui Paulo NL80211_CMD_GET_SCAN))) { 9375b9c547cSRui Paulo wpa_scan_results_free(res); 9385b9c547cSRui Paulo return NULL; 9395b9c547cSRui Paulo } 9405b9c547cSRui Paulo 9415b9c547cSRui Paulo arg.drv = drv; 9425b9c547cSRui Paulo arg.res = res; 9435b9c547cSRui Paulo ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg); 9445b9c547cSRui Paulo if (ret == 0) { 94585732ac8SCy Schubert struct nl80211_noise_info info; 94685732ac8SCy Schubert 9475b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: Received scan results (%lu " 9485b9c547cSRui Paulo "BSSes)", (unsigned long) res->num); 94985732ac8SCy Schubert if (nl80211_get_noise_for_scan_results(drv, &info) == 0) { 95085732ac8SCy Schubert size_t i; 95185732ac8SCy Schubert 95285732ac8SCy Schubert for (i = 0; i < res->num; ++i) 95385732ac8SCy Schubert nl80211_update_scan_res_noise(res->res[i], 95485732ac8SCy Schubert &info); 95585732ac8SCy Schubert } 9565b9c547cSRui Paulo return res; 9575b9c547cSRui Paulo } 9585b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d " 9595b9c547cSRui Paulo "(%s)", ret, strerror(-ret)); 9605b9c547cSRui Paulo wpa_scan_results_free(res); 9615b9c547cSRui Paulo return NULL; 9625b9c547cSRui Paulo } 9635b9c547cSRui Paulo 9645b9c547cSRui Paulo 9655b9c547cSRui Paulo /** 9665b9c547cSRui Paulo * wpa_driver_nl80211_get_scan_results - Fetch the latest scan results 9675b9c547cSRui Paulo * @priv: Pointer to private wext data from wpa_driver_nl80211_init() 9685b9c547cSRui Paulo * Returns: Scan results on success, -1 on failure 9695b9c547cSRui Paulo */ 9705b9c547cSRui Paulo struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv) 9715b9c547cSRui Paulo { 9725b9c547cSRui Paulo struct i802_bss *bss = priv; 9735b9c547cSRui Paulo struct wpa_driver_nl80211_data *drv = bss->drv; 9745b9c547cSRui Paulo struct wpa_scan_results *res; 9755b9c547cSRui Paulo 9765b9c547cSRui Paulo res = nl80211_get_scan_results(drv); 9775b9c547cSRui Paulo if (res) 9785b9c547cSRui Paulo wpa_driver_nl80211_check_bss_status(drv, res); 9795b9c547cSRui Paulo return res; 9805b9c547cSRui Paulo } 9815b9c547cSRui Paulo 9825b9c547cSRui Paulo 98385732ac8SCy Schubert struct nl80211_dump_scan_ctx { 98485732ac8SCy Schubert struct wpa_driver_nl80211_data *drv; 98585732ac8SCy Schubert int idx; 98685732ac8SCy Schubert }; 98785732ac8SCy Schubert 98885732ac8SCy Schubert static int nl80211_dump_scan_handler(struct nl_msg *msg, void *arg) 98985732ac8SCy Schubert { 99085732ac8SCy Schubert struct nl80211_dump_scan_ctx *ctx = arg; 99185732ac8SCy Schubert struct wpa_scan_res *r; 99285732ac8SCy Schubert 99385732ac8SCy Schubert r = nl80211_parse_bss_info(ctx->drv, msg); 99485732ac8SCy Schubert if (!r) 99585732ac8SCy Schubert return NL_SKIP; 99685732ac8SCy Schubert wpa_printf(MSG_DEBUG, "nl80211: %d " MACSTR " %d%s", 99785732ac8SCy Schubert ctx->idx, MAC2STR(r->bssid), r->freq, 99885732ac8SCy Schubert r->flags & WPA_SCAN_ASSOCIATED ? " [assoc]" : ""); 99985732ac8SCy Schubert ctx->idx++; 100085732ac8SCy Schubert os_free(r); 100185732ac8SCy Schubert return NL_SKIP; 100285732ac8SCy Schubert } 100385732ac8SCy Schubert 100485732ac8SCy Schubert 10055b9c547cSRui Paulo void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv) 10065b9c547cSRui Paulo { 100785732ac8SCy Schubert struct nl_msg *msg; 100885732ac8SCy Schubert struct nl80211_dump_scan_ctx ctx; 10095b9c547cSRui Paulo 10105b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: Scan result dump"); 101185732ac8SCy Schubert ctx.drv = drv; 101285732ac8SCy Schubert ctx.idx = 0; 101385732ac8SCy Schubert msg = nl80211_cmd_msg(drv->first_bss, NLM_F_DUMP, NL80211_CMD_GET_SCAN); 101485732ac8SCy Schubert if (msg) 101585732ac8SCy Schubert send_and_recv_msgs(drv, msg, nl80211_dump_scan_handler, &ctx); 10165b9c547cSRui Paulo } 1017780fb4a2SCy Schubert 1018780fb4a2SCy Schubert 101985732ac8SCy Schubert int wpa_driver_nl80211_abort_scan(void *priv, u64 scan_cookie) 1020780fb4a2SCy Schubert { 1021780fb4a2SCy Schubert struct i802_bss *bss = priv; 102285732ac8SCy Schubert #ifdef CONFIG_DRIVER_NL80211_QCA 1023780fb4a2SCy Schubert struct wpa_driver_nl80211_data *drv = bss->drv; 1024780fb4a2SCy Schubert 102585732ac8SCy Schubert /* 102685732ac8SCy Schubert * If scan_cookie is zero, a normal scan through kernel (cfg80211) 102785732ac8SCy Schubert * was triggered, hence abort the cfg80211 scan instead of the vendor 102885732ac8SCy Schubert * scan. 102985732ac8SCy Schubert */ 103085732ac8SCy Schubert if (drv->scan_vendor_cmd_avail && scan_cookie) 103185732ac8SCy Schubert return nl80211_abort_vendor_scan(drv, scan_cookie); 103285732ac8SCy Schubert #endif /* CONFIG_DRIVER_NL80211_QCA */ 103385732ac8SCy Schubert return nl80211_abort_scan(bss); 1034780fb4a2SCy Schubert } 1035780fb4a2SCy Schubert 1036780fb4a2SCy Schubert 1037780fb4a2SCy Schubert #ifdef CONFIG_DRIVER_NL80211_QCA 1038780fb4a2SCy Schubert 1039780fb4a2SCy Schubert static int scan_cookie_handler(struct nl_msg *msg, void *arg) 1040780fb4a2SCy Schubert { 1041780fb4a2SCy Schubert struct nlattr *tb[NL80211_ATTR_MAX + 1]; 1042780fb4a2SCy Schubert struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); 1043780fb4a2SCy Schubert u64 *cookie = arg; 1044780fb4a2SCy Schubert 1045780fb4a2SCy Schubert nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), 1046780fb4a2SCy Schubert genlmsg_attrlen(gnlh, 0), NULL); 1047780fb4a2SCy Schubert 1048780fb4a2SCy Schubert if (tb[NL80211_ATTR_VENDOR_DATA]) { 1049780fb4a2SCy Schubert struct nlattr *nl_vendor = tb[NL80211_ATTR_VENDOR_DATA]; 1050780fb4a2SCy Schubert struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_SCAN_MAX + 1]; 1051780fb4a2SCy Schubert 1052780fb4a2SCy Schubert nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_SCAN_MAX, 1053780fb4a2SCy Schubert nla_data(nl_vendor), nla_len(nl_vendor), NULL); 1054780fb4a2SCy Schubert 1055780fb4a2SCy Schubert if (tb_vendor[QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE]) 1056780fb4a2SCy Schubert *cookie = nla_get_u64( 1057780fb4a2SCy Schubert tb_vendor[QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE]); 1058780fb4a2SCy Schubert } 1059780fb4a2SCy Schubert 1060780fb4a2SCy Schubert return NL_SKIP; 1061780fb4a2SCy Schubert } 1062780fb4a2SCy Schubert 1063780fb4a2SCy Schubert 1064780fb4a2SCy Schubert /** 1065780fb4a2SCy Schubert * wpa_driver_nl80211_vendor_scan - Request the driver to initiate a vendor scan 1066780fb4a2SCy Schubert * @bss: Pointer to private driver data from wpa_driver_nl80211_init() 1067780fb4a2SCy Schubert * @params: Scan parameters 1068780fb4a2SCy Schubert * Returns: 0 on success, -1 on failure 1069780fb4a2SCy Schubert */ 1070780fb4a2SCy Schubert int wpa_driver_nl80211_vendor_scan(struct i802_bss *bss, 1071780fb4a2SCy Schubert struct wpa_driver_scan_params *params) 1072780fb4a2SCy Schubert { 1073780fb4a2SCy Schubert struct wpa_driver_nl80211_data *drv = bss->drv; 1074780fb4a2SCy Schubert struct nl_msg *msg = NULL; 1075780fb4a2SCy Schubert struct nlattr *attr; 1076780fb4a2SCy Schubert size_t i; 1077780fb4a2SCy Schubert u32 scan_flags = 0; 1078780fb4a2SCy Schubert int ret = -1; 1079780fb4a2SCy Schubert u64 cookie = 0; 1080780fb4a2SCy Schubert 1081780fb4a2SCy Schubert wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: vendor scan request"); 1082780fb4a2SCy Schubert drv->scan_for_auth = 0; 1083780fb4a2SCy Schubert 1084780fb4a2SCy Schubert if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) || 1085780fb4a2SCy Schubert nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) || 1086780fb4a2SCy Schubert nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, 1087780fb4a2SCy Schubert QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN) ) 1088780fb4a2SCy Schubert goto fail; 1089780fb4a2SCy Schubert 1090780fb4a2SCy Schubert attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA); 1091780fb4a2SCy Schubert if (attr == NULL) 1092780fb4a2SCy Schubert goto fail; 1093780fb4a2SCy Schubert 1094780fb4a2SCy Schubert if (params->num_ssids) { 1095780fb4a2SCy Schubert struct nlattr *ssids; 1096780fb4a2SCy Schubert 1097780fb4a2SCy Schubert ssids = nla_nest_start(msg, QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS); 1098780fb4a2SCy Schubert if (ssids == NULL) 1099780fb4a2SCy Schubert goto fail; 1100780fb4a2SCy Schubert for (i = 0; i < params->num_ssids; i++) { 1101*4bc52338SCy Schubert wpa_printf(MSG_MSGDUMP, "nl80211: Scan SSID %s", 1102*4bc52338SCy Schubert wpa_ssid_txt(params->ssids[i].ssid, 1103*4bc52338SCy Schubert params->ssids[i].ssid_len)); 1104780fb4a2SCy Schubert if (nla_put(msg, i + 1, params->ssids[i].ssid_len, 1105780fb4a2SCy Schubert params->ssids[i].ssid)) 1106780fb4a2SCy Schubert goto fail; 1107780fb4a2SCy Schubert } 1108780fb4a2SCy Schubert nla_nest_end(msg, ssids); 1109780fb4a2SCy Schubert } 1110780fb4a2SCy Schubert 1111780fb4a2SCy Schubert if (params->extra_ies) { 1112780fb4a2SCy Schubert wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs", 1113780fb4a2SCy Schubert params->extra_ies, params->extra_ies_len); 1114780fb4a2SCy Schubert if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_SCAN_IE, 1115780fb4a2SCy Schubert params->extra_ies_len, params->extra_ies)) 1116780fb4a2SCy Schubert goto fail; 1117780fb4a2SCy Schubert } 1118780fb4a2SCy Schubert 1119780fb4a2SCy Schubert if (params->freqs) { 1120780fb4a2SCy Schubert struct nlattr *freqs; 1121780fb4a2SCy Schubert 1122780fb4a2SCy Schubert freqs = nla_nest_start(msg, 1123780fb4a2SCy Schubert QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES); 1124780fb4a2SCy Schubert if (freqs == NULL) 1125780fb4a2SCy Schubert goto fail; 1126780fb4a2SCy Schubert for (i = 0; params->freqs[i]; i++) { 1127780fb4a2SCy Schubert wpa_printf(MSG_MSGDUMP, 1128780fb4a2SCy Schubert "nl80211: Scan frequency %u MHz", 1129780fb4a2SCy Schubert params->freqs[i]); 1130780fb4a2SCy Schubert if (nla_put_u32(msg, i + 1, params->freqs[i])) 1131780fb4a2SCy Schubert goto fail; 1132780fb4a2SCy Schubert } 1133780fb4a2SCy Schubert nla_nest_end(msg, freqs); 1134780fb4a2SCy Schubert } 1135780fb4a2SCy Schubert 1136780fb4a2SCy Schubert os_free(drv->filter_ssids); 1137780fb4a2SCy Schubert drv->filter_ssids = params->filter_ssids; 1138780fb4a2SCy Schubert params->filter_ssids = NULL; 1139780fb4a2SCy Schubert drv->num_filter_ssids = params->num_filter_ssids; 1140780fb4a2SCy Schubert 1141780fb4a2SCy Schubert if (params->low_priority && drv->have_low_prio_scan) { 1142780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, 1143780fb4a2SCy Schubert "nl80211: Add NL80211_SCAN_FLAG_LOW_PRIORITY"); 1144780fb4a2SCy Schubert scan_flags |= NL80211_SCAN_FLAG_LOW_PRIORITY; 1145780fb4a2SCy Schubert } 1146780fb4a2SCy Schubert 1147780fb4a2SCy Schubert if (params->mac_addr_rand) { 1148780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, 1149780fb4a2SCy Schubert "nl80211: Add NL80211_SCAN_FLAG_RANDOM_ADDR"); 1150780fb4a2SCy Schubert scan_flags |= NL80211_SCAN_FLAG_RANDOM_ADDR; 1151780fb4a2SCy Schubert 1152780fb4a2SCy Schubert if (params->mac_addr) { 1153780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "nl80211: MAC address: " MACSTR, 1154780fb4a2SCy Schubert MAC2STR(params->mac_addr)); 1155780fb4a2SCy Schubert if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_SCAN_MAC, 1156780fb4a2SCy Schubert ETH_ALEN, params->mac_addr)) 1157780fb4a2SCy Schubert goto fail; 1158780fb4a2SCy Schubert } 1159780fb4a2SCy Schubert 1160780fb4a2SCy Schubert if (params->mac_addr_mask) { 1161780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "nl80211: MAC address mask: " 1162780fb4a2SCy Schubert MACSTR, MAC2STR(params->mac_addr_mask)); 1163780fb4a2SCy Schubert if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK, 1164780fb4a2SCy Schubert ETH_ALEN, params->mac_addr_mask)) 1165780fb4a2SCy Schubert goto fail; 1166780fb4a2SCy Schubert } 1167780fb4a2SCy Schubert } 1168780fb4a2SCy Schubert 1169780fb4a2SCy Schubert if (scan_flags && 117085732ac8SCy Schubert nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS, scan_flags)) 1171780fb4a2SCy Schubert goto fail; 1172780fb4a2SCy Schubert 1173780fb4a2SCy Schubert if (params->p2p_probe) { 1174780fb4a2SCy Schubert struct nlattr *rates; 1175780fb4a2SCy Schubert 1176780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates"); 1177780fb4a2SCy Schubert 1178780fb4a2SCy Schubert rates = nla_nest_start(msg, 1179780fb4a2SCy Schubert QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES); 1180780fb4a2SCy Schubert if (rates == NULL) 1181780fb4a2SCy Schubert goto fail; 1182780fb4a2SCy Schubert 1183780fb4a2SCy Schubert /* 1184780fb4a2SCy Schubert * Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates 1185780fb4a2SCy Schubert * by masking out everything else apart from the OFDM rates 6, 1186780fb4a2SCy Schubert * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz 1187780fb4a2SCy Schubert * rates are left enabled. 1188780fb4a2SCy Schubert */ 1189780fb4a2SCy Schubert if (nla_put(msg, NL80211_BAND_2GHZ, 8, 1190780fb4a2SCy Schubert "\x0c\x12\x18\x24\x30\x48\x60\x6c")) 1191780fb4a2SCy Schubert goto fail; 1192780fb4a2SCy Schubert nla_nest_end(msg, rates); 1193780fb4a2SCy Schubert 1194780fb4a2SCy Schubert if (nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE)) 1195780fb4a2SCy Schubert goto fail; 1196780fb4a2SCy Schubert } 1197780fb4a2SCy Schubert 119885732ac8SCy Schubert if (params->bssid) { 119985732ac8SCy Schubert wpa_printf(MSG_DEBUG, "nl80211: Scan for a specific BSSID: " 120085732ac8SCy Schubert MACSTR, MAC2STR(params->bssid)); 120185732ac8SCy Schubert if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_SCAN_BSSID, ETH_ALEN, 120285732ac8SCy Schubert params->bssid)) 120385732ac8SCy Schubert goto fail; 120485732ac8SCy Schubert } 120585732ac8SCy Schubert 1206780fb4a2SCy Schubert nla_nest_end(msg, attr); 1207780fb4a2SCy Schubert 1208780fb4a2SCy Schubert ret = send_and_recv_msgs(drv, msg, scan_cookie_handler, &cookie); 1209780fb4a2SCy Schubert msg = NULL; 1210780fb4a2SCy Schubert if (ret) { 1211780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, 1212780fb4a2SCy Schubert "nl80211: Vendor scan trigger failed: ret=%d (%s)", 1213780fb4a2SCy Schubert ret, strerror(-ret)); 1214780fb4a2SCy Schubert goto fail; 1215780fb4a2SCy Schubert } 1216780fb4a2SCy Schubert 1217780fb4a2SCy Schubert drv->vendor_scan_cookie = cookie; 1218780fb4a2SCy Schubert drv->scan_state = SCAN_REQUESTED; 121985732ac8SCy Schubert /* Pass the cookie to the caller to help distinguish the scans. */ 122085732ac8SCy Schubert params->scan_cookie = cookie; 1221780fb4a2SCy Schubert 1222780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, 1223780fb4a2SCy Schubert "nl80211: Vendor scan requested (ret=%d) - scan timeout 30 seconds, scan cookie:0x%llx", 1224780fb4a2SCy Schubert ret, (long long unsigned int) cookie); 1225780fb4a2SCy Schubert eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx); 1226780fb4a2SCy Schubert eloop_register_timeout(30, 0, wpa_driver_nl80211_scan_timeout, 1227780fb4a2SCy Schubert drv, drv->ctx); 1228780fb4a2SCy Schubert drv->last_scan_cmd = NL80211_CMD_VENDOR; 1229780fb4a2SCy Schubert 1230780fb4a2SCy Schubert fail: 1231780fb4a2SCy Schubert nlmsg_free(msg); 1232780fb4a2SCy Schubert return ret; 1233780fb4a2SCy Schubert } 1234780fb4a2SCy Schubert 1235780fb4a2SCy Schubert 1236780fb4a2SCy Schubert /** 1237780fb4a2SCy Schubert * nl80211_set_default_scan_ies - Set the scan default IEs to the driver 1238780fb4a2SCy Schubert * @priv: Pointer to private driver data from wpa_driver_nl80211_init() 1239780fb4a2SCy Schubert * @ies: Pointer to IEs buffer 1240780fb4a2SCy Schubert * @ies_len: Length of IEs in bytes 1241780fb4a2SCy Schubert * Returns: 0 on success, -1 on failure 1242780fb4a2SCy Schubert */ 1243780fb4a2SCy Schubert int nl80211_set_default_scan_ies(void *priv, const u8 *ies, size_t ies_len) 1244780fb4a2SCy Schubert { 1245780fb4a2SCy Schubert struct i802_bss *bss = priv; 1246780fb4a2SCy Schubert struct wpa_driver_nl80211_data *drv = bss->drv; 1247780fb4a2SCy Schubert struct nl_msg *msg = NULL; 1248780fb4a2SCy Schubert struct nlattr *attr; 1249780fb4a2SCy Schubert int ret = -1; 1250780fb4a2SCy Schubert 1251780fb4a2SCy Schubert if (!drv->set_wifi_conf_vendor_cmd_avail) 1252780fb4a2SCy Schubert return -1; 1253780fb4a2SCy Schubert 1254780fb4a2SCy Schubert if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) || 1255780fb4a2SCy Schubert nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) || 1256780fb4a2SCy Schubert nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, 1257780fb4a2SCy Schubert QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION)) 1258780fb4a2SCy Schubert goto fail; 1259780fb4a2SCy Schubert 1260780fb4a2SCy Schubert attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA); 1261780fb4a2SCy Schubert if (attr == NULL) 1262780fb4a2SCy Schubert goto fail; 1263780fb4a2SCy Schubert 1264780fb4a2SCy Schubert wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan default IEs", ies, ies_len); 1265780fb4a2SCy Schubert if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_CONFIG_SCAN_DEFAULT_IES, 1266780fb4a2SCy Schubert ies_len, ies)) 1267780fb4a2SCy Schubert goto fail; 1268780fb4a2SCy Schubert 1269780fb4a2SCy Schubert nla_nest_end(msg, attr); 1270780fb4a2SCy Schubert 1271780fb4a2SCy Schubert ret = send_and_recv_msgs(drv, msg, NULL, NULL); 1272780fb4a2SCy Schubert msg = NULL; 1273780fb4a2SCy Schubert if (ret) { 1274780fb4a2SCy Schubert wpa_printf(MSG_ERROR, 1275780fb4a2SCy Schubert "nl80211: Set scan default IEs failed: ret=%d (%s)", 1276780fb4a2SCy Schubert ret, strerror(-ret)); 1277780fb4a2SCy Schubert goto fail; 1278780fb4a2SCy Schubert } 1279780fb4a2SCy Schubert 1280780fb4a2SCy Schubert fail: 1281780fb4a2SCy Schubert nlmsg_free(msg); 1282780fb4a2SCy Schubert return ret; 1283780fb4a2SCy Schubert } 1284780fb4a2SCy Schubert 1285780fb4a2SCy Schubert #endif /* CONFIG_DRIVER_NL80211_QCA */ 1286