15b9c547cSRui Paulo /* 25b9c547cSRui Paulo * Driver interaction with Linux nl80211/cfg80211 - Scanning 35b9c547cSRui Paulo * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> 45b9c547cSRui Paulo * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net> 55b9c547cSRui Paulo * Copyright (c) 2009-2010, Atheros Communications 65b9c547cSRui Paulo * 75b9c547cSRui Paulo * This software may be distributed under the terms of the BSD license. 85b9c547cSRui Paulo * See README for more details. 95b9c547cSRui Paulo */ 105b9c547cSRui Paulo 115b9c547cSRui Paulo #include "includes.h" 125b9c547cSRui Paulo #include <netlink/genl/genl.h> 135b9c547cSRui Paulo 145b9c547cSRui Paulo #include "utils/common.h" 155b9c547cSRui Paulo #include "utils/eloop.h" 165b9c547cSRui Paulo #include "common/ieee802_11_defs.h" 175b9c547cSRui Paulo #include "driver_nl80211.h" 185b9c547cSRui Paulo 195b9c547cSRui Paulo 205b9c547cSRui Paulo static int get_noise_for_scan_results(struct nl_msg *msg, void *arg) 215b9c547cSRui Paulo { 225b9c547cSRui Paulo struct nlattr *tb[NL80211_ATTR_MAX + 1]; 235b9c547cSRui Paulo struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); 245b9c547cSRui Paulo struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1]; 255b9c547cSRui Paulo static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = { 265b9c547cSRui Paulo [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 }, 275b9c547cSRui Paulo [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 }, 285b9c547cSRui Paulo }; 295b9c547cSRui Paulo struct wpa_scan_results *scan_results = arg; 305b9c547cSRui Paulo struct wpa_scan_res *scan_res; 315b9c547cSRui Paulo size_t i; 325b9c547cSRui Paulo 335b9c547cSRui Paulo nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), 345b9c547cSRui Paulo genlmsg_attrlen(gnlh, 0), NULL); 355b9c547cSRui Paulo 365b9c547cSRui Paulo if (!tb[NL80211_ATTR_SURVEY_INFO]) { 375b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: Survey data missing"); 385b9c547cSRui Paulo return NL_SKIP; 395b9c547cSRui Paulo } 405b9c547cSRui Paulo 415b9c547cSRui Paulo if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX, 425b9c547cSRui Paulo tb[NL80211_ATTR_SURVEY_INFO], 435b9c547cSRui Paulo survey_policy)) { 445b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: Failed to parse nested " 455b9c547cSRui Paulo "attributes"); 465b9c547cSRui Paulo return NL_SKIP; 475b9c547cSRui Paulo } 485b9c547cSRui Paulo 495b9c547cSRui Paulo if (!sinfo[NL80211_SURVEY_INFO_NOISE]) 505b9c547cSRui Paulo return NL_SKIP; 515b9c547cSRui Paulo 525b9c547cSRui Paulo if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY]) 535b9c547cSRui Paulo return NL_SKIP; 545b9c547cSRui Paulo 555b9c547cSRui Paulo for (i = 0; i < scan_results->num; ++i) { 565b9c547cSRui Paulo scan_res = scan_results->res[i]; 575b9c547cSRui Paulo if (!scan_res) 585b9c547cSRui Paulo continue; 595b9c547cSRui Paulo if ((int) nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) != 605b9c547cSRui Paulo scan_res->freq) 615b9c547cSRui Paulo continue; 625b9c547cSRui Paulo if (!(scan_res->flags & WPA_SCAN_NOISE_INVALID)) 635b9c547cSRui Paulo continue; 645b9c547cSRui Paulo scan_res->noise = (s8) 655b9c547cSRui Paulo nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]); 665b9c547cSRui Paulo scan_res->flags &= ~WPA_SCAN_NOISE_INVALID; 675b9c547cSRui Paulo } 685b9c547cSRui Paulo 695b9c547cSRui Paulo return NL_SKIP; 705b9c547cSRui Paulo } 715b9c547cSRui Paulo 725b9c547cSRui Paulo 735b9c547cSRui Paulo static int nl80211_get_noise_for_scan_results( 745b9c547cSRui Paulo struct wpa_driver_nl80211_data *drv, 755b9c547cSRui Paulo struct wpa_scan_results *scan_res) 765b9c547cSRui Paulo { 775b9c547cSRui Paulo struct nl_msg *msg; 785b9c547cSRui Paulo 795b9c547cSRui Paulo msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY); 805b9c547cSRui Paulo return send_and_recv_msgs(drv, msg, get_noise_for_scan_results, 815b9c547cSRui Paulo scan_res); 825b9c547cSRui Paulo } 835b9c547cSRui Paulo 845b9c547cSRui Paulo 855b9c547cSRui Paulo /** 865b9c547cSRui Paulo * wpa_driver_nl80211_scan_timeout - Scan timeout to report scan completion 875b9c547cSRui Paulo * @eloop_ctx: Driver private data 885b9c547cSRui Paulo * @timeout_ctx: ctx argument given to wpa_driver_nl80211_init() 895b9c547cSRui Paulo * 905b9c547cSRui Paulo * This function can be used as registered timeout when starting a scan to 915b9c547cSRui Paulo * generate a scan completed event if the driver does not report this. 925b9c547cSRui Paulo */ 935b9c547cSRui Paulo void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx) 945b9c547cSRui Paulo { 955b9c547cSRui Paulo struct wpa_driver_nl80211_data *drv = eloop_ctx; 965b9c547cSRui Paulo if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) { 975b9c547cSRui Paulo wpa_driver_nl80211_set_mode(drv->first_bss, 985b9c547cSRui Paulo drv->ap_scan_as_station); 995b9c547cSRui Paulo drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED; 1005b9c547cSRui Paulo } 1015b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Scan timeout - try to get results"); 1025b9c547cSRui Paulo wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); 1035b9c547cSRui Paulo } 1045b9c547cSRui Paulo 1055b9c547cSRui Paulo 1065b9c547cSRui Paulo static struct nl_msg * 1075b9c547cSRui Paulo nl80211_scan_common(struct i802_bss *bss, u8 cmd, 1085b9c547cSRui Paulo struct wpa_driver_scan_params *params) 1095b9c547cSRui Paulo { 1105b9c547cSRui Paulo struct wpa_driver_nl80211_data *drv = bss->drv; 1115b9c547cSRui Paulo struct nl_msg *msg; 1125b9c547cSRui Paulo size_t i; 1135b9c547cSRui Paulo u32 scan_flags = 0; 1145b9c547cSRui Paulo 1155b9c547cSRui Paulo msg = nl80211_cmd_msg(bss, 0, cmd); 1165b9c547cSRui Paulo if (!msg) 1175b9c547cSRui Paulo return NULL; 1185b9c547cSRui Paulo 1195b9c547cSRui Paulo if (params->num_ssids) { 1205b9c547cSRui Paulo struct nlattr *ssids; 1215b9c547cSRui Paulo 1225b9c547cSRui Paulo ssids = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS); 1235b9c547cSRui Paulo if (ssids == NULL) 1245b9c547cSRui Paulo goto fail; 1255b9c547cSRui Paulo for (i = 0; i < params->num_ssids; i++) { 1265b9c547cSRui Paulo wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID", 1275b9c547cSRui Paulo params->ssids[i].ssid, 1285b9c547cSRui Paulo params->ssids[i].ssid_len); 1295b9c547cSRui Paulo if (nla_put(msg, i + 1, params->ssids[i].ssid_len, 1305b9c547cSRui Paulo params->ssids[i].ssid)) 1315b9c547cSRui Paulo goto fail; 1325b9c547cSRui Paulo } 1335b9c547cSRui Paulo nla_nest_end(msg, ssids); 1345b9c547cSRui Paulo } 1355b9c547cSRui Paulo 1365b9c547cSRui Paulo if (params->extra_ies) { 1375b9c547cSRui Paulo wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs", 1385b9c547cSRui Paulo params->extra_ies, params->extra_ies_len); 1395b9c547cSRui Paulo if (nla_put(msg, NL80211_ATTR_IE, params->extra_ies_len, 1405b9c547cSRui Paulo params->extra_ies)) 1415b9c547cSRui Paulo goto fail; 1425b9c547cSRui Paulo } 1435b9c547cSRui Paulo 1445b9c547cSRui Paulo if (params->freqs) { 1455b9c547cSRui Paulo struct nlattr *freqs; 1465b9c547cSRui Paulo freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES); 1475b9c547cSRui Paulo if (freqs == NULL) 1485b9c547cSRui Paulo goto fail; 1495b9c547cSRui Paulo for (i = 0; params->freqs[i]; i++) { 1505b9c547cSRui Paulo wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u " 1515b9c547cSRui Paulo "MHz", params->freqs[i]); 1525b9c547cSRui Paulo if (nla_put_u32(msg, i + 1, params->freqs[i])) 1535b9c547cSRui Paulo goto fail; 1545b9c547cSRui Paulo } 1555b9c547cSRui Paulo nla_nest_end(msg, freqs); 1565b9c547cSRui Paulo } 1575b9c547cSRui Paulo 1585b9c547cSRui Paulo os_free(drv->filter_ssids); 1595b9c547cSRui Paulo drv->filter_ssids = params->filter_ssids; 1605b9c547cSRui Paulo params->filter_ssids = NULL; 1615b9c547cSRui Paulo drv->num_filter_ssids = params->num_filter_ssids; 1625b9c547cSRui Paulo 1635b9c547cSRui Paulo if (params->only_new_results) { 1645b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: Add NL80211_SCAN_FLAG_FLUSH"); 1655b9c547cSRui Paulo scan_flags |= NL80211_SCAN_FLAG_FLUSH; 1665b9c547cSRui Paulo } 1675b9c547cSRui Paulo 1685b9c547cSRui Paulo if (params->low_priority && drv->have_low_prio_scan) { 1695b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 1705b9c547cSRui Paulo "nl80211: Add NL80211_SCAN_FLAG_LOW_PRIORITY"); 1715b9c547cSRui Paulo scan_flags |= NL80211_SCAN_FLAG_LOW_PRIORITY; 1725b9c547cSRui Paulo } 1735b9c547cSRui Paulo 1745b9c547cSRui Paulo if (params->mac_addr_rand) { 1755b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 1765b9c547cSRui Paulo "nl80211: Add NL80211_SCAN_FLAG_RANDOM_ADDR"); 1775b9c547cSRui Paulo scan_flags |= NL80211_SCAN_FLAG_RANDOM_ADDR; 1785b9c547cSRui Paulo 1795b9c547cSRui Paulo if (params->mac_addr) { 1805b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: MAC address: " MACSTR, 1815b9c547cSRui Paulo MAC2STR(params->mac_addr)); 1825b9c547cSRui Paulo if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, 1835b9c547cSRui Paulo params->mac_addr)) 1845b9c547cSRui Paulo goto fail; 1855b9c547cSRui Paulo } 1865b9c547cSRui Paulo 1875b9c547cSRui Paulo if (params->mac_addr_mask) { 1885b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: MAC address mask: " 1895b9c547cSRui Paulo MACSTR, MAC2STR(params->mac_addr_mask)); 1905b9c547cSRui Paulo if (nla_put(msg, NL80211_ATTR_MAC_MASK, ETH_ALEN, 1915b9c547cSRui Paulo params->mac_addr_mask)) 1925b9c547cSRui Paulo goto fail; 1935b9c547cSRui Paulo } 1945b9c547cSRui Paulo } 1955b9c547cSRui Paulo 1965b9c547cSRui Paulo if (scan_flags && 1975b9c547cSRui Paulo nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, scan_flags)) 1985b9c547cSRui Paulo goto fail; 1995b9c547cSRui Paulo 2005b9c547cSRui Paulo return msg; 2015b9c547cSRui Paulo 2025b9c547cSRui Paulo fail: 2035b9c547cSRui Paulo nlmsg_free(msg); 2045b9c547cSRui Paulo return NULL; 2055b9c547cSRui Paulo } 2065b9c547cSRui Paulo 2075b9c547cSRui Paulo 2085b9c547cSRui Paulo /** 2095b9c547cSRui Paulo * wpa_driver_nl80211_scan - Request the driver to initiate scan 2105b9c547cSRui Paulo * @bss: Pointer to private driver data from wpa_driver_nl80211_init() 2115b9c547cSRui Paulo * @params: Scan parameters 2125b9c547cSRui Paulo * Returns: 0 on success, -1 on failure 2135b9c547cSRui Paulo */ 2145b9c547cSRui Paulo int wpa_driver_nl80211_scan(struct i802_bss *bss, 2155b9c547cSRui Paulo struct wpa_driver_scan_params *params) 2165b9c547cSRui Paulo { 2175b9c547cSRui Paulo struct wpa_driver_nl80211_data *drv = bss->drv; 2185b9c547cSRui Paulo int ret = -1, timeout; 2195b9c547cSRui Paulo struct nl_msg *msg = NULL; 2205b9c547cSRui Paulo 2215b9c547cSRui Paulo wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request"); 2225b9c547cSRui Paulo drv->scan_for_auth = 0; 2235b9c547cSRui Paulo 224*325151a3SRui Paulo if (TEST_FAIL()) 225*325151a3SRui Paulo return -1; 226*325151a3SRui Paulo 2275b9c547cSRui Paulo msg = nl80211_scan_common(bss, NL80211_CMD_TRIGGER_SCAN, params); 2285b9c547cSRui Paulo if (!msg) 2295b9c547cSRui Paulo return -1; 2305b9c547cSRui Paulo 2315b9c547cSRui Paulo if (params->p2p_probe) { 2325b9c547cSRui Paulo struct nlattr *rates; 2335b9c547cSRui Paulo 2345b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates"); 2355b9c547cSRui Paulo 2365b9c547cSRui Paulo rates = nla_nest_start(msg, NL80211_ATTR_SCAN_SUPP_RATES); 2375b9c547cSRui Paulo if (rates == NULL) 2385b9c547cSRui Paulo goto fail; 2395b9c547cSRui Paulo 2405b9c547cSRui Paulo /* 2415b9c547cSRui Paulo * Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates 2425b9c547cSRui Paulo * by masking out everything else apart from the OFDM rates 6, 2435b9c547cSRui Paulo * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz 2445b9c547cSRui Paulo * rates are left enabled. 2455b9c547cSRui Paulo */ 2465b9c547cSRui Paulo if (nla_put(msg, NL80211_BAND_2GHZ, 8, 2475b9c547cSRui Paulo "\x0c\x12\x18\x24\x30\x48\x60\x6c")) 2485b9c547cSRui Paulo goto fail; 2495b9c547cSRui Paulo nla_nest_end(msg, rates); 2505b9c547cSRui Paulo 2515b9c547cSRui Paulo if (nla_put_flag(msg, NL80211_ATTR_TX_NO_CCK_RATE)) 2525b9c547cSRui Paulo goto fail; 2535b9c547cSRui Paulo } 2545b9c547cSRui Paulo 2555b9c547cSRui Paulo ret = send_and_recv_msgs(drv, msg, NULL, NULL); 2565b9c547cSRui Paulo msg = NULL; 2575b9c547cSRui Paulo if (ret) { 2585b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d " 2595b9c547cSRui Paulo "(%s)", ret, strerror(-ret)); 2605b9c547cSRui Paulo if (drv->hostapd && is_ap_interface(drv->nlmode)) { 2615b9c547cSRui Paulo enum nl80211_iftype old_mode = drv->nlmode; 2625b9c547cSRui Paulo 2635b9c547cSRui Paulo /* 2645b9c547cSRui Paulo * mac80211 does not allow scan requests in AP mode, so 2655b9c547cSRui Paulo * try to do this in station mode. 2665b9c547cSRui Paulo */ 2675b9c547cSRui Paulo if (wpa_driver_nl80211_set_mode( 2685b9c547cSRui Paulo bss, NL80211_IFTYPE_STATION)) 2695b9c547cSRui Paulo goto fail; 2705b9c547cSRui Paulo 2715b9c547cSRui Paulo if (wpa_driver_nl80211_scan(bss, params)) { 2725b9c547cSRui Paulo wpa_driver_nl80211_set_mode(bss, old_mode); 2735b9c547cSRui Paulo goto fail; 2745b9c547cSRui Paulo } 2755b9c547cSRui Paulo 2765b9c547cSRui Paulo /* Restore AP mode when processing scan results */ 2775b9c547cSRui Paulo drv->ap_scan_as_station = old_mode; 2785b9c547cSRui Paulo ret = 0; 2795b9c547cSRui Paulo } else 2805b9c547cSRui Paulo goto fail; 2815b9c547cSRui Paulo } 2825b9c547cSRui Paulo 2835b9c547cSRui Paulo drv->scan_state = SCAN_REQUESTED; 2845b9c547cSRui Paulo /* Not all drivers generate "scan completed" wireless event, so try to 2855b9c547cSRui Paulo * read results after a timeout. */ 2865b9c547cSRui Paulo timeout = 10; 2875b9c547cSRui Paulo if (drv->scan_complete_events) { 2885b9c547cSRui Paulo /* 2895b9c547cSRui Paulo * The driver seems to deliver events to notify when scan is 2905b9c547cSRui Paulo * complete, so use longer timeout to avoid race conditions 2915b9c547cSRui Paulo * with scanning and following association request. 2925b9c547cSRui Paulo */ 2935b9c547cSRui Paulo timeout = 30; 2945b9c547cSRui Paulo } 2955b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d " 2965b9c547cSRui Paulo "seconds", ret, timeout); 2975b9c547cSRui Paulo eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx); 2985b9c547cSRui Paulo eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout, 2995b9c547cSRui Paulo drv, drv->ctx); 3005b9c547cSRui Paulo 3015b9c547cSRui Paulo fail: 3025b9c547cSRui Paulo nlmsg_free(msg); 3035b9c547cSRui Paulo return ret; 3045b9c547cSRui Paulo } 3055b9c547cSRui Paulo 3065b9c547cSRui Paulo 3075b9c547cSRui Paulo /** 3085b9c547cSRui Paulo * wpa_driver_nl80211_sched_scan - Initiate a scheduled scan 3095b9c547cSRui Paulo * @priv: Pointer to private driver data from wpa_driver_nl80211_init() 3105b9c547cSRui Paulo * @params: Scan parameters 3115b9c547cSRui Paulo * @interval: Interval between scan cycles in milliseconds 3125b9c547cSRui Paulo * Returns: 0 on success, -1 on failure or if not supported 3135b9c547cSRui Paulo */ 3145b9c547cSRui Paulo int wpa_driver_nl80211_sched_scan(void *priv, 3155b9c547cSRui Paulo struct wpa_driver_scan_params *params, 3165b9c547cSRui Paulo u32 interval) 3175b9c547cSRui Paulo { 3185b9c547cSRui Paulo struct i802_bss *bss = priv; 3195b9c547cSRui Paulo struct wpa_driver_nl80211_data *drv = bss->drv; 3205b9c547cSRui Paulo int ret = -1; 3215b9c547cSRui Paulo struct nl_msg *msg; 3225b9c547cSRui Paulo size_t i; 3235b9c547cSRui Paulo 3245b9c547cSRui Paulo wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: sched_scan request"); 3255b9c547cSRui Paulo 3265b9c547cSRui Paulo #ifdef ANDROID 3275b9c547cSRui Paulo if (!drv->capa.sched_scan_supported) 3285b9c547cSRui Paulo return android_pno_start(bss, params); 3295b9c547cSRui Paulo #endif /* ANDROID */ 3305b9c547cSRui Paulo 3315b9c547cSRui Paulo msg = nl80211_scan_common(bss, NL80211_CMD_START_SCHED_SCAN, params); 3325b9c547cSRui Paulo if (!msg || 3335b9c547cSRui Paulo nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, interval)) 3345b9c547cSRui Paulo goto fail; 3355b9c547cSRui Paulo 3365b9c547cSRui Paulo if ((drv->num_filter_ssids && 3375b9c547cSRui Paulo (int) drv->num_filter_ssids <= drv->capa.max_match_sets) || 3385b9c547cSRui Paulo params->filter_rssi) { 3395b9c547cSRui Paulo struct nlattr *match_sets; 3405b9c547cSRui Paulo match_sets = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH); 3415b9c547cSRui Paulo if (match_sets == NULL) 3425b9c547cSRui Paulo goto fail; 3435b9c547cSRui Paulo 3445b9c547cSRui Paulo for (i = 0; i < drv->num_filter_ssids; i++) { 3455b9c547cSRui Paulo struct nlattr *match_set_ssid; 3465b9c547cSRui Paulo wpa_hexdump_ascii(MSG_MSGDUMP, 3475b9c547cSRui Paulo "nl80211: Sched scan filter SSID", 3485b9c547cSRui Paulo drv->filter_ssids[i].ssid, 3495b9c547cSRui Paulo drv->filter_ssids[i].ssid_len); 3505b9c547cSRui Paulo 3515b9c547cSRui Paulo match_set_ssid = nla_nest_start(msg, i + 1); 3525b9c547cSRui Paulo if (match_set_ssid == NULL || 3535b9c547cSRui Paulo nla_put(msg, NL80211_ATTR_SCHED_SCAN_MATCH_SSID, 3545b9c547cSRui Paulo drv->filter_ssids[i].ssid_len, 3555b9c547cSRui Paulo drv->filter_ssids[i].ssid) || 3565b9c547cSRui Paulo (params->filter_rssi && 3575b9c547cSRui Paulo nla_put_u32(msg, 3585b9c547cSRui Paulo NL80211_SCHED_SCAN_MATCH_ATTR_RSSI, 3595b9c547cSRui Paulo params->filter_rssi))) 3605b9c547cSRui Paulo goto fail; 3615b9c547cSRui Paulo 3625b9c547cSRui Paulo nla_nest_end(msg, match_set_ssid); 3635b9c547cSRui Paulo } 3645b9c547cSRui Paulo 3655b9c547cSRui Paulo /* 3665b9c547cSRui Paulo * Due to backward compatibility code, newer kernels treat this 3675b9c547cSRui Paulo * matchset (with only an RSSI filter) as the default for all 3685b9c547cSRui Paulo * other matchsets, unless it's the only one, in which case the 3695b9c547cSRui Paulo * matchset will actually allow all SSIDs above the RSSI. 3705b9c547cSRui Paulo */ 3715b9c547cSRui Paulo if (params->filter_rssi) { 3725b9c547cSRui Paulo struct nlattr *match_set_rssi; 3735b9c547cSRui Paulo match_set_rssi = nla_nest_start(msg, 0); 3745b9c547cSRui Paulo if (match_set_rssi == NULL || 3755b9c547cSRui Paulo nla_put_u32(msg, NL80211_SCHED_SCAN_MATCH_ATTR_RSSI, 3765b9c547cSRui Paulo params->filter_rssi)) 3775b9c547cSRui Paulo goto fail; 3785b9c547cSRui Paulo wpa_printf(MSG_MSGDUMP, 3795b9c547cSRui Paulo "nl80211: Sched scan RSSI filter %d dBm", 3805b9c547cSRui Paulo params->filter_rssi); 3815b9c547cSRui Paulo nla_nest_end(msg, match_set_rssi); 3825b9c547cSRui Paulo } 3835b9c547cSRui Paulo 3845b9c547cSRui Paulo nla_nest_end(msg, match_sets); 3855b9c547cSRui Paulo } 3865b9c547cSRui Paulo 3875b9c547cSRui Paulo ret = send_and_recv_msgs(drv, msg, NULL, NULL); 3885b9c547cSRui Paulo 3895b9c547cSRui Paulo /* TODO: if we get an error here, we should fall back to normal scan */ 3905b9c547cSRui Paulo 3915b9c547cSRui Paulo msg = NULL; 3925b9c547cSRui Paulo if (ret) { 3935b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: Sched scan start failed: " 3945b9c547cSRui Paulo "ret=%d (%s)", ret, strerror(-ret)); 3955b9c547cSRui Paulo goto fail; 3965b9c547cSRui Paulo } 3975b9c547cSRui Paulo 3985b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: Sched scan requested (ret=%d) - " 3995b9c547cSRui Paulo "scan interval %d msec", ret, interval); 4005b9c547cSRui Paulo 4015b9c547cSRui Paulo fail: 4025b9c547cSRui Paulo nlmsg_free(msg); 4035b9c547cSRui Paulo return ret; 4045b9c547cSRui Paulo } 4055b9c547cSRui Paulo 4065b9c547cSRui Paulo 4075b9c547cSRui Paulo /** 4085b9c547cSRui Paulo * wpa_driver_nl80211_stop_sched_scan - Stop a scheduled scan 4095b9c547cSRui Paulo * @priv: Pointer to private driver data from wpa_driver_nl80211_init() 4105b9c547cSRui Paulo * Returns: 0 on success, -1 on failure or if not supported 4115b9c547cSRui Paulo */ 4125b9c547cSRui Paulo int wpa_driver_nl80211_stop_sched_scan(void *priv) 4135b9c547cSRui Paulo { 4145b9c547cSRui Paulo struct i802_bss *bss = priv; 4155b9c547cSRui Paulo struct wpa_driver_nl80211_data *drv = bss->drv; 4165b9c547cSRui Paulo int ret; 4175b9c547cSRui Paulo struct nl_msg *msg; 4185b9c547cSRui Paulo 4195b9c547cSRui Paulo #ifdef ANDROID 4205b9c547cSRui Paulo if (!drv->capa.sched_scan_supported) 4215b9c547cSRui Paulo return android_pno_stop(bss); 4225b9c547cSRui Paulo #endif /* ANDROID */ 4235b9c547cSRui Paulo 4245b9c547cSRui Paulo msg = nl80211_drv_msg(drv, 0, NL80211_CMD_STOP_SCHED_SCAN); 4255b9c547cSRui Paulo ret = send_and_recv_msgs(drv, msg, NULL, NULL); 4265b9c547cSRui Paulo if (ret) { 4275b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 4285b9c547cSRui Paulo "nl80211: Sched scan stop failed: ret=%d (%s)", 4295b9c547cSRui Paulo ret, strerror(-ret)); 4305b9c547cSRui Paulo } else { 4315b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 4325b9c547cSRui Paulo "nl80211: Sched scan stop sent"); 4335b9c547cSRui Paulo } 4345b9c547cSRui Paulo 4355b9c547cSRui Paulo return ret; 4365b9c547cSRui Paulo } 4375b9c547cSRui Paulo 4385b9c547cSRui Paulo 439*325151a3SRui Paulo const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie) 4405b9c547cSRui Paulo { 4415b9c547cSRui Paulo const u8 *end, *pos; 4425b9c547cSRui Paulo 4435b9c547cSRui Paulo if (ies == NULL) 4445b9c547cSRui Paulo return NULL; 4455b9c547cSRui Paulo 4465b9c547cSRui Paulo pos = ies; 4475b9c547cSRui Paulo end = ies + ies_len; 4485b9c547cSRui Paulo 4495b9c547cSRui Paulo while (pos + 1 < end) { 4505b9c547cSRui Paulo if (pos + 2 + pos[1] > end) 4515b9c547cSRui Paulo break; 4525b9c547cSRui Paulo if (pos[0] == ie) 4535b9c547cSRui Paulo return pos; 4545b9c547cSRui Paulo pos += 2 + pos[1]; 4555b9c547cSRui Paulo } 4565b9c547cSRui Paulo 4575b9c547cSRui Paulo return NULL; 4585b9c547cSRui Paulo } 4595b9c547cSRui Paulo 4605b9c547cSRui Paulo 4615b9c547cSRui Paulo static int nl80211_scan_filtered(struct wpa_driver_nl80211_data *drv, 4625b9c547cSRui Paulo const u8 *ie, size_t ie_len) 4635b9c547cSRui Paulo { 4645b9c547cSRui Paulo const u8 *ssid; 4655b9c547cSRui Paulo size_t i; 4665b9c547cSRui Paulo 4675b9c547cSRui Paulo if (drv->filter_ssids == NULL) 4685b9c547cSRui Paulo return 0; 4695b9c547cSRui Paulo 4705b9c547cSRui Paulo ssid = nl80211_get_ie(ie, ie_len, WLAN_EID_SSID); 4715b9c547cSRui Paulo if (ssid == NULL) 4725b9c547cSRui Paulo return 1; 4735b9c547cSRui Paulo 4745b9c547cSRui Paulo for (i = 0; i < drv->num_filter_ssids; i++) { 4755b9c547cSRui Paulo if (ssid[1] == drv->filter_ssids[i].ssid_len && 4765b9c547cSRui Paulo os_memcmp(ssid + 2, drv->filter_ssids[i].ssid, ssid[1]) == 4775b9c547cSRui Paulo 0) 4785b9c547cSRui Paulo return 0; 4795b9c547cSRui Paulo } 4805b9c547cSRui Paulo 4815b9c547cSRui Paulo return 1; 4825b9c547cSRui Paulo } 4835b9c547cSRui Paulo 4845b9c547cSRui Paulo 4855b9c547cSRui Paulo int bss_info_handler(struct nl_msg *msg, void *arg) 4865b9c547cSRui Paulo { 4875b9c547cSRui Paulo struct nlattr *tb[NL80211_ATTR_MAX + 1]; 4885b9c547cSRui Paulo struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); 4895b9c547cSRui Paulo struct nlattr *bss[NL80211_BSS_MAX + 1]; 4905b9c547cSRui Paulo static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = { 4915b9c547cSRui Paulo [NL80211_BSS_BSSID] = { .type = NLA_UNSPEC }, 4925b9c547cSRui Paulo [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 }, 4935b9c547cSRui Paulo [NL80211_BSS_TSF] = { .type = NLA_U64 }, 4945b9c547cSRui Paulo [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 }, 4955b9c547cSRui Paulo [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 }, 4965b9c547cSRui Paulo [NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC }, 4975b9c547cSRui Paulo [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 }, 4985b9c547cSRui Paulo [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 }, 4995b9c547cSRui Paulo [NL80211_BSS_STATUS] = { .type = NLA_U32 }, 5005b9c547cSRui Paulo [NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 }, 5015b9c547cSRui Paulo [NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC }, 5025b9c547cSRui Paulo }; 5035b9c547cSRui Paulo struct nl80211_bss_info_arg *_arg = arg; 5045b9c547cSRui Paulo struct wpa_scan_results *res = _arg->res; 5055b9c547cSRui Paulo struct wpa_scan_res **tmp; 5065b9c547cSRui Paulo struct wpa_scan_res *r; 5075b9c547cSRui Paulo const u8 *ie, *beacon_ie; 5085b9c547cSRui Paulo size_t ie_len, beacon_ie_len; 5095b9c547cSRui Paulo u8 *pos; 5105b9c547cSRui Paulo size_t i; 5115b9c547cSRui Paulo 5125b9c547cSRui Paulo nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), 5135b9c547cSRui Paulo genlmsg_attrlen(gnlh, 0), NULL); 5145b9c547cSRui Paulo if (!tb[NL80211_ATTR_BSS]) 5155b9c547cSRui Paulo return NL_SKIP; 5165b9c547cSRui Paulo if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS], 5175b9c547cSRui Paulo bss_policy)) 5185b9c547cSRui Paulo return NL_SKIP; 5195b9c547cSRui Paulo if (bss[NL80211_BSS_STATUS]) { 5205b9c547cSRui Paulo enum nl80211_bss_status status; 5215b9c547cSRui Paulo status = nla_get_u32(bss[NL80211_BSS_STATUS]); 5225b9c547cSRui Paulo if (status == NL80211_BSS_STATUS_ASSOCIATED && 5235b9c547cSRui Paulo bss[NL80211_BSS_FREQUENCY]) { 5245b9c547cSRui Paulo _arg->assoc_freq = 5255b9c547cSRui Paulo nla_get_u32(bss[NL80211_BSS_FREQUENCY]); 5265b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz", 5275b9c547cSRui Paulo _arg->assoc_freq); 5285b9c547cSRui Paulo } 5295b9c547cSRui Paulo if (status == NL80211_BSS_STATUS_IBSS_JOINED && 5305b9c547cSRui Paulo bss[NL80211_BSS_FREQUENCY]) { 5315b9c547cSRui Paulo _arg->ibss_freq = 5325b9c547cSRui Paulo nla_get_u32(bss[NL80211_BSS_FREQUENCY]); 5335b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: IBSS-joined on %u MHz", 5345b9c547cSRui Paulo _arg->ibss_freq); 5355b9c547cSRui Paulo } 5365b9c547cSRui Paulo if (status == NL80211_BSS_STATUS_ASSOCIATED && 5375b9c547cSRui Paulo bss[NL80211_BSS_BSSID]) { 5385b9c547cSRui Paulo os_memcpy(_arg->assoc_bssid, 5395b9c547cSRui Paulo nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN); 5405b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: Associated with " 5415b9c547cSRui Paulo MACSTR, MAC2STR(_arg->assoc_bssid)); 5425b9c547cSRui Paulo } 5435b9c547cSRui Paulo } 5445b9c547cSRui Paulo if (!res) 5455b9c547cSRui Paulo return NL_SKIP; 5465b9c547cSRui Paulo if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) { 5475b9c547cSRui Paulo ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]); 5485b9c547cSRui Paulo ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]); 5495b9c547cSRui Paulo } else { 5505b9c547cSRui Paulo ie = NULL; 5515b9c547cSRui Paulo ie_len = 0; 5525b9c547cSRui Paulo } 5535b9c547cSRui Paulo if (bss[NL80211_BSS_BEACON_IES]) { 5545b9c547cSRui Paulo beacon_ie = nla_data(bss[NL80211_BSS_BEACON_IES]); 5555b9c547cSRui Paulo beacon_ie_len = nla_len(bss[NL80211_BSS_BEACON_IES]); 5565b9c547cSRui Paulo } else { 5575b9c547cSRui Paulo beacon_ie = NULL; 5585b9c547cSRui Paulo beacon_ie_len = 0; 5595b9c547cSRui Paulo } 5605b9c547cSRui Paulo 5615b9c547cSRui Paulo if (nl80211_scan_filtered(_arg->drv, ie ? ie : beacon_ie, 5625b9c547cSRui Paulo ie ? ie_len : beacon_ie_len)) 5635b9c547cSRui Paulo return NL_SKIP; 5645b9c547cSRui Paulo 5655b9c547cSRui Paulo r = os_zalloc(sizeof(*r) + ie_len + beacon_ie_len); 5665b9c547cSRui Paulo if (r == NULL) 5675b9c547cSRui Paulo return NL_SKIP; 5685b9c547cSRui Paulo if (bss[NL80211_BSS_BSSID]) 5695b9c547cSRui Paulo os_memcpy(r->bssid, nla_data(bss[NL80211_BSS_BSSID]), 5705b9c547cSRui Paulo ETH_ALEN); 5715b9c547cSRui Paulo if (bss[NL80211_BSS_FREQUENCY]) 5725b9c547cSRui Paulo r->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]); 5735b9c547cSRui Paulo if (bss[NL80211_BSS_BEACON_INTERVAL]) 5745b9c547cSRui Paulo r->beacon_int = nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]); 5755b9c547cSRui Paulo if (bss[NL80211_BSS_CAPABILITY]) 5765b9c547cSRui Paulo r->caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]); 5775b9c547cSRui Paulo r->flags |= WPA_SCAN_NOISE_INVALID; 5785b9c547cSRui Paulo if (bss[NL80211_BSS_SIGNAL_MBM]) { 5795b9c547cSRui Paulo r->level = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]); 5805b9c547cSRui Paulo r->level /= 100; /* mBm to dBm */ 5815b9c547cSRui Paulo r->flags |= WPA_SCAN_LEVEL_DBM | WPA_SCAN_QUAL_INVALID; 5825b9c547cSRui Paulo } else if (bss[NL80211_BSS_SIGNAL_UNSPEC]) { 5835b9c547cSRui Paulo r->level = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]); 5845b9c547cSRui Paulo r->flags |= WPA_SCAN_QUAL_INVALID; 5855b9c547cSRui Paulo } else 5865b9c547cSRui Paulo r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID; 5875b9c547cSRui Paulo if (bss[NL80211_BSS_TSF]) 5885b9c547cSRui Paulo r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]); 589*325151a3SRui Paulo if (bss[NL80211_BSS_BEACON_TSF]) { 590*325151a3SRui Paulo u64 tsf = nla_get_u64(bss[NL80211_BSS_BEACON_TSF]); 591*325151a3SRui Paulo if (tsf > r->tsf) 592*325151a3SRui Paulo r->tsf = tsf; 593*325151a3SRui Paulo } 5945b9c547cSRui Paulo if (bss[NL80211_BSS_SEEN_MS_AGO]) 5955b9c547cSRui Paulo r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]); 5965b9c547cSRui Paulo r->ie_len = ie_len; 5975b9c547cSRui Paulo pos = (u8 *) (r + 1); 5985b9c547cSRui Paulo if (ie) { 5995b9c547cSRui Paulo os_memcpy(pos, ie, ie_len); 6005b9c547cSRui Paulo pos += ie_len; 6015b9c547cSRui Paulo } 6025b9c547cSRui Paulo r->beacon_ie_len = beacon_ie_len; 6035b9c547cSRui Paulo if (beacon_ie) 6045b9c547cSRui Paulo os_memcpy(pos, beacon_ie, beacon_ie_len); 6055b9c547cSRui Paulo 6065b9c547cSRui Paulo if (bss[NL80211_BSS_STATUS]) { 6075b9c547cSRui Paulo enum nl80211_bss_status status; 6085b9c547cSRui Paulo status = nla_get_u32(bss[NL80211_BSS_STATUS]); 6095b9c547cSRui Paulo switch (status) { 6105b9c547cSRui Paulo case NL80211_BSS_STATUS_ASSOCIATED: 6115b9c547cSRui Paulo r->flags |= WPA_SCAN_ASSOCIATED; 6125b9c547cSRui Paulo break; 6135b9c547cSRui Paulo default: 6145b9c547cSRui Paulo break; 6155b9c547cSRui Paulo } 6165b9c547cSRui Paulo } 6175b9c547cSRui Paulo 6185b9c547cSRui Paulo /* 6195b9c547cSRui Paulo * cfg80211 maintains separate BSS table entries for APs if the same 6205b9c547cSRui Paulo * BSSID,SSID pair is seen on multiple channels. wpa_supplicant does 6215b9c547cSRui Paulo * not use frequency as a separate key in the BSS table, so filter out 6225b9c547cSRui Paulo * duplicated entries. Prefer associated BSS entry in such a case in 6235b9c547cSRui Paulo * order to get the correct frequency into the BSS table. Similarly, 6245b9c547cSRui Paulo * prefer newer entries over older. 6255b9c547cSRui Paulo */ 6265b9c547cSRui Paulo for (i = 0; i < res->num; i++) { 6275b9c547cSRui Paulo const u8 *s1, *s2; 6285b9c547cSRui Paulo if (os_memcmp(res->res[i]->bssid, r->bssid, ETH_ALEN) != 0) 6295b9c547cSRui Paulo continue; 6305b9c547cSRui Paulo 6315b9c547cSRui Paulo s1 = nl80211_get_ie((u8 *) (res->res[i] + 1), 6325b9c547cSRui Paulo res->res[i]->ie_len, WLAN_EID_SSID); 6335b9c547cSRui Paulo s2 = nl80211_get_ie((u8 *) (r + 1), r->ie_len, WLAN_EID_SSID); 6345b9c547cSRui Paulo if (s1 == NULL || s2 == NULL || s1[1] != s2[1] || 6355b9c547cSRui Paulo os_memcmp(s1, s2, 2 + s1[1]) != 0) 6365b9c547cSRui Paulo continue; 6375b9c547cSRui Paulo 6385b9c547cSRui Paulo /* Same BSSID,SSID was already included in scan results */ 6395b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: Remove duplicated scan result " 6405b9c547cSRui Paulo "for " MACSTR, MAC2STR(r->bssid)); 6415b9c547cSRui Paulo 6425b9c547cSRui Paulo if (((r->flags & WPA_SCAN_ASSOCIATED) && 6435b9c547cSRui Paulo !(res->res[i]->flags & WPA_SCAN_ASSOCIATED)) || 6445b9c547cSRui Paulo r->age < res->res[i]->age) { 6455b9c547cSRui Paulo os_free(res->res[i]); 6465b9c547cSRui Paulo res->res[i] = r; 6475b9c547cSRui Paulo } else 6485b9c547cSRui Paulo os_free(r); 6495b9c547cSRui Paulo return NL_SKIP; 6505b9c547cSRui Paulo } 6515b9c547cSRui Paulo 6525b9c547cSRui Paulo tmp = os_realloc_array(res->res, res->num + 1, 6535b9c547cSRui Paulo sizeof(struct wpa_scan_res *)); 6545b9c547cSRui Paulo if (tmp == NULL) { 6555b9c547cSRui Paulo os_free(r); 6565b9c547cSRui Paulo return NL_SKIP; 6575b9c547cSRui Paulo } 6585b9c547cSRui Paulo tmp[res->num++] = r; 6595b9c547cSRui Paulo res->res = tmp; 6605b9c547cSRui Paulo 6615b9c547cSRui Paulo return NL_SKIP; 6625b9c547cSRui Paulo } 6635b9c547cSRui Paulo 6645b9c547cSRui Paulo 6655b9c547cSRui Paulo static void clear_state_mismatch(struct wpa_driver_nl80211_data *drv, 6665b9c547cSRui Paulo const u8 *addr) 6675b9c547cSRui Paulo { 6685b9c547cSRui Paulo if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) { 6695b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: Clear possible state " 6705b9c547cSRui Paulo "mismatch (" MACSTR ")", MAC2STR(addr)); 6715b9c547cSRui Paulo wpa_driver_nl80211_mlme(drv, addr, 6725b9c547cSRui Paulo NL80211_CMD_DEAUTHENTICATE, 6735b9c547cSRui Paulo WLAN_REASON_PREV_AUTH_NOT_VALID, 1); 6745b9c547cSRui Paulo } 6755b9c547cSRui Paulo } 6765b9c547cSRui Paulo 6775b9c547cSRui Paulo 6785b9c547cSRui Paulo static void wpa_driver_nl80211_check_bss_status( 6795b9c547cSRui Paulo struct wpa_driver_nl80211_data *drv, struct wpa_scan_results *res) 6805b9c547cSRui Paulo { 6815b9c547cSRui Paulo size_t i; 6825b9c547cSRui Paulo 6835b9c547cSRui Paulo for (i = 0; i < res->num; i++) { 6845b9c547cSRui Paulo struct wpa_scan_res *r = res->res[i]; 6855b9c547cSRui Paulo 6865b9c547cSRui Paulo if (r->flags & WPA_SCAN_ASSOCIATED) { 6875b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: Scan results " 6885b9c547cSRui Paulo "indicate BSS status with " MACSTR 6895b9c547cSRui Paulo " as associated", 6905b9c547cSRui Paulo MAC2STR(r->bssid)); 6915b9c547cSRui Paulo if (is_sta_interface(drv->nlmode) && 6925b9c547cSRui Paulo !drv->associated) { 6935b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: Local state " 6945b9c547cSRui Paulo "(not associated) does not match " 6955b9c547cSRui Paulo "with BSS state"); 6965b9c547cSRui Paulo clear_state_mismatch(drv, r->bssid); 6975b9c547cSRui Paulo } else if (is_sta_interface(drv->nlmode) && 6985b9c547cSRui Paulo os_memcmp(drv->bssid, r->bssid, ETH_ALEN) != 6995b9c547cSRui Paulo 0) { 7005b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: Local state " 7015b9c547cSRui Paulo "(associated with " MACSTR ") does " 7025b9c547cSRui Paulo "not match with BSS state", 7035b9c547cSRui Paulo MAC2STR(drv->bssid)); 7045b9c547cSRui Paulo clear_state_mismatch(drv, r->bssid); 7055b9c547cSRui Paulo clear_state_mismatch(drv, drv->bssid); 7065b9c547cSRui Paulo } 7075b9c547cSRui Paulo } 7085b9c547cSRui Paulo } 7095b9c547cSRui Paulo } 7105b9c547cSRui Paulo 7115b9c547cSRui Paulo 7125b9c547cSRui Paulo static struct wpa_scan_results * 7135b9c547cSRui Paulo nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv) 7145b9c547cSRui Paulo { 7155b9c547cSRui Paulo struct nl_msg *msg; 7165b9c547cSRui Paulo struct wpa_scan_results *res; 7175b9c547cSRui Paulo int ret; 7185b9c547cSRui Paulo struct nl80211_bss_info_arg arg; 7195b9c547cSRui Paulo 7205b9c547cSRui Paulo res = os_zalloc(sizeof(*res)); 7215b9c547cSRui Paulo if (res == NULL) 7225b9c547cSRui Paulo return NULL; 7235b9c547cSRui Paulo if (!(msg = nl80211_cmd_msg(drv->first_bss, NLM_F_DUMP, 7245b9c547cSRui Paulo NL80211_CMD_GET_SCAN))) { 7255b9c547cSRui Paulo wpa_scan_results_free(res); 7265b9c547cSRui Paulo return NULL; 7275b9c547cSRui Paulo } 7285b9c547cSRui Paulo 7295b9c547cSRui Paulo arg.drv = drv; 7305b9c547cSRui Paulo arg.res = res; 7315b9c547cSRui Paulo ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg); 7325b9c547cSRui Paulo if (ret == 0) { 7335b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: Received scan results (%lu " 7345b9c547cSRui Paulo "BSSes)", (unsigned long) res->num); 7355b9c547cSRui Paulo nl80211_get_noise_for_scan_results(drv, res); 7365b9c547cSRui Paulo return res; 7375b9c547cSRui Paulo } 7385b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d " 7395b9c547cSRui Paulo "(%s)", ret, strerror(-ret)); 7405b9c547cSRui Paulo wpa_scan_results_free(res); 7415b9c547cSRui Paulo return NULL; 7425b9c547cSRui Paulo } 7435b9c547cSRui Paulo 7445b9c547cSRui Paulo 7455b9c547cSRui Paulo /** 7465b9c547cSRui Paulo * wpa_driver_nl80211_get_scan_results - Fetch the latest scan results 7475b9c547cSRui Paulo * @priv: Pointer to private wext data from wpa_driver_nl80211_init() 7485b9c547cSRui Paulo * Returns: Scan results on success, -1 on failure 7495b9c547cSRui Paulo */ 7505b9c547cSRui Paulo struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv) 7515b9c547cSRui Paulo { 7525b9c547cSRui Paulo struct i802_bss *bss = priv; 7535b9c547cSRui Paulo struct wpa_driver_nl80211_data *drv = bss->drv; 7545b9c547cSRui Paulo struct wpa_scan_results *res; 7555b9c547cSRui Paulo 7565b9c547cSRui Paulo res = nl80211_get_scan_results(drv); 7575b9c547cSRui Paulo if (res) 7585b9c547cSRui Paulo wpa_driver_nl80211_check_bss_status(drv, res); 7595b9c547cSRui Paulo return res; 7605b9c547cSRui Paulo } 7615b9c547cSRui Paulo 7625b9c547cSRui Paulo 7635b9c547cSRui Paulo void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv) 7645b9c547cSRui Paulo { 7655b9c547cSRui Paulo struct wpa_scan_results *res; 7665b9c547cSRui Paulo size_t i; 7675b9c547cSRui Paulo 7685b9c547cSRui Paulo res = nl80211_get_scan_results(drv); 7695b9c547cSRui Paulo if (res == NULL) { 7705b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: Failed to get scan results"); 7715b9c547cSRui Paulo return; 7725b9c547cSRui Paulo } 7735b9c547cSRui Paulo 7745b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: Scan result dump"); 7755b9c547cSRui Paulo for (i = 0; i < res->num; i++) { 7765b9c547cSRui Paulo struct wpa_scan_res *r = res->res[i]; 7775b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "nl80211: %d/%d " MACSTR "%s", 7785b9c547cSRui Paulo (int) i, (int) res->num, MAC2STR(r->bssid), 7795b9c547cSRui Paulo r->flags & WPA_SCAN_ASSOCIATED ? " [assoc]" : ""); 7805b9c547cSRui Paulo } 7815b9c547cSRui Paulo 7825b9c547cSRui Paulo wpa_scan_results_free(res); 7835b9c547cSRui Paulo } 784