18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * NXP Wireless LAN device driver: scan ioctl and command handling 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright 2011-2020 NXP 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This software file (the "File") is distributed by NXP 78c2ecf20Sopenharmony_ci * under the terms of the GNU General Public License Version 2, June 1991 88c2ecf20Sopenharmony_ci * (the "License"). You may use, redistribute and/or modify this File in 98c2ecf20Sopenharmony_ci * accordance with the terms and conditions of the License, a copy of which 108c2ecf20Sopenharmony_ci * is available by writing to the Free Software Foundation, Inc., 118c2ecf20Sopenharmony_ci * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the 128c2ecf20Sopenharmony_ci * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 158c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 168c2ecf20Sopenharmony_ci * ARE EXPRESSLY DISCLAIMED. The License provides additional details about 178c2ecf20Sopenharmony_ci * this warranty disclaimer. 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "decl.h" 218c2ecf20Sopenharmony_ci#include "ioctl.h" 228c2ecf20Sopenharmony_ci#include "util.h" 238c2ecf20Sopenharmony_ci#include "fw.h" 248c2ecf20Sopenharmony_ci#include "main.h" 258c2ecf20Sopenharmony_ci#include "11n.h" 268c2ecf20Sopenharmony_ci#include "cfg80211.h" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* The maximum number of channels the firmware can scan per command */ 298c2ecf20Sopenharmony_ci#define MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN 14 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define MWIFIEX_DEF_CHANNELS_PER_SCAN_CMD 4 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* Memory needed to store a max sized Channel List TLV for a firmware scan */ 348c2ecf20Sopenharmony_ci#define CHAN_TLV_MAX_SIZE (sizeof(struct mwifiex_ie_types_header) \ 358c2ecf20Sopenharmony_ci + (MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN \ 368c2ecf20Sopenharmony_ci *sizeof(struct mwifiex_chan_scan_param_set))) 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* Memory needed to store supported rate */ 398c2ecf20Sopenharmony_ci#define RATE_TLV_MAX_SIZE (sizeof(struct mwifiex_ie_types_rates_param_set) \ 408c2ecf20Sopenharmony_ci + HOSTCMD_SUPPORTED_RATES) 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* Memory needed to store a max number/size WildCard SSID TLV for a firmware 438c2ecf20Sopenharmony_ci scan */ 448c2ecf20Sopenharmony_ci#define WILDCARD_SSID_TLV_MAX_SIZE \ 458c2ecf20Sopenharmony_ci (MWIFIEX_MAX_SSID_LIST_LENGTH * \ 468c2ecf20Sopenharmony_ci (sizeof(struct mwifiex_ie_types_wildcard_ssid_params) \ 478c2ecf20Sopenharmony_ci + IEEE80211_MAX_SSID_LEN)) 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* Maximum memory needed for a mwifiex_scan_cmd_config with all TLVs at max */ 508c2ecf20Sopenharmony_ci#define MAX_SCAN_CFG_ALLOC (sizeof(struct mwifiex_scan_cmd_config) \ 518c2ecf20Sopenharmony_ci + sizeof(struct mwifiex_ie_types_num_probes) \ 528c2ecf20Sopenharmony_ci + sizeof(struct mwifiex_ie_types_htcap) \ 538c2ecf20Sopenharmony_ci + CHAN_TLV_MAX_SIZE \ 548c2ecf20Sopenharmony_ci + RATE_TLV_MAX_SIZE \ 558c2ecf20Sopenharmony_ci + WILDCARD_SSID_TLV_MAX_SIZE) 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ciunion mwifiex_scan_cmd_config_tlv { 598c2ecf20Sopenharmony_ci /* Scan configuration (variable length) */ 608c2ecf20Sopenharmony_ci struct mwifiex_scan_cmd_config config; 618c2ecf20Sopenharmony_ci /* Max allocated block */ 628c2ecf20Sopenharmony_ci u8 config_alloc_buf[MAX_SCAN_CFG_ALLOC]; 638c2ecf20Sopenharmony_ci}; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cienum cipher_suite { 668c2ecf20Sopenharmony_ci CIPHER_SUITE_TKIP, 678c2ecf20Sopenharmony_ci CIPHER_SUITE_CCMP, 688c2ecf20Sopenharmony_ci CIPHER_SUITE_MAX 698c2ecf20Sopenharmony_ci}; 708c2ecf20Sopenharmony_cistatic u8 mwifiex_wpa_oui[CIPHER_SUITE_MAX][4] = { 718c2ecf20Sopenharmony_ci { 0x00, 0x50, 0xf2, 0x02 }, /* TKIP */ 728c2ecf20Sopenharmony_ci { 0x00, 0x50, 0xf2, 0x04 }, /* AES */ 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_cistatic u8 mwifiex_rsn_oui[CIPHER_SUITE_MAX][4] = { 758c2ecf20Sopenharmony_ci { 0x00, 0x0f, 0xac, 0x02 }, /* TKIP */ 768c2ecf20Sopenharmony_ci { 0x00, 0x0f, 0xac, 0x04 }, /* AES */ 778c2ecf20Sopenharmony_ci}; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic void 808c2ecf20Sopenharmony_ci_dbg_security_flags(int log_level, const char *func, const char *desc, 818c2ecf20Sopenharmony_ci struct mwifiex_private *priv, 828c2ecf20Sopenharmony_ci struct mwifiex_bssdescriptor *bss_desc) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci _mwifiex_dbg(priv->adapter, log_level, 858c2ecf20Sopenharmony_ci "info: %s: %s:\twpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s\tEncMode=%#x privacy=%#x\n", 868c2ecf20Sopenharmony_ci func, desc, 878c2ecf20Sopenharmony_ci bss_desc->bcn_wpa_ie ? 888c2ecf20Sopenharmony_ci bss_desc->bcn_wpa_ie->vend_hdr.element_id : 0, 898c2ecf20Sopenharmony_ci bss_desc->bcn_rsn_ie ? 908c2ecf20Sopenharmony_ci bss_desc->bcn_rsn_ie->ieee_hdr.element_id : 0, 918c2ecf20Sopenharmony_ci priv->sec_info.wep_enabled ? "e" : "d", 928c2ecf20Sopenharmony_ci priv->sec_info.wpa_enabled ? "e" : "d", 938c2ecf20Sopenharmony_ci priv->sec_info.wpa2_enabled ? "e" : "d", 948c2ecf20Sopenharmony_ci priv->sec_info.encryption_mode, 958c2ecf20Sopenharmony_ci bss_desc->privacy); 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci#define dbg_security_flags(mask, desc, priv, bss_desc) \ 988c2ecf20Sopenharmony_ci _dbg_security_flags(MWIFIEX_DBG_##mask, desc, __func__, priv, bss_desc) 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic bool 1018c2ecf20Sopenharmony_cihas_ieee_hdr(struct ieee_types_generic *ie, u8 key) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci return (ie && ie->ieee_hdr.element_id == key); 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic bool 1078c2ecf20Sopenharmony_cihas_vendor_hdr(struct ieee_types_vendor_specific *ie, u8 key) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci return (ie && ie->vend_hdr.element_id == key); 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci/* 1138c2ecf20Sopenharmony_ci * This function parses a given IE for a given OUI. 1148c2ecf20Sopenharmony_ci * 1158c2ecf20Sopenharmony_ci * This is used to parse a WPA/RSN IE to find if it has 1168c2ecf20Sopenharmony_ci * a given oui in PTK. 1178c2ecf20Sopenharmony_ci */ 1188c2ecf20Sopenharmony_cistatic u8 1198c2ecf20Sopenharmony_cimwifiex_search_oui_in_ie(struct ie_body *iebody, u8 *oui) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci u8 count; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci count = iebody->ptk_cnt[0]; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci /* There could be multiple OUIs for PTK hence 1268c2ecf20Sopenharmony_ci 1) Take the length. 1278c2ecf20Sopenharmony_ci 2) Check all the OUIs for AES. 1288c2ecf20Sopenharmony_ci 3) If one of them is AES then pass success. */ 1298c2ecf20Sopenharmony_ci while (count) { 1308c2ecf20Sopenharmony_ci if (!memcmp(iebody->ptk_body, oui, sizeof(iebody->ptk_body))) 1318c2ecf20Sopenharmony_ci return MWIFIEX_OUI_PRESENT; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci --count; 1348c2ecf20Sopenharmony_ci if (count) 1358c2ecf20Sopenharmony_ci iebody = (struct ie_body *) ((u8 *) iebody + 1368c2ecf20Sopenharmony_ci sizeof(iebody->ptk_body)); 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci pr_debug("info: %s: OUI is not found in PTK\n", __func__); 1408c2ecf20Sopenharmony_ci return MWIFIEX_OUI_NOT_PRESENT; 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci/* 1448c2ecf20Sopenharmony_ci * This function checks if a given OUI is present in a RSN IE. 1458c2ecf20Sopenharmony_ci * 1468c2ecf20Sopenharmony_ci * The function first checks if a RSN IE is present or not in the 1478c2ecf20Sopenharmony_ci * BSS descriptor. It tries to locate the OUI only if such an IE is 1488c2ecf20Sopenharmony_ci * present. 1498c2ecf20Sopenharmony_ci */ 1508c2ecf20Sopenharmony_cistatic u8 1518c2ecf20Sopenharmony_cimwifiex_is_rsn_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci u8 *oui; 1548c2ecf20Sopenharmony_ci struct ie_body *iebody; 1558c2ecf20Sopenharmony_ci u8 ret = MWIFIEX_OUI_NOT_PRESENT; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (has_ieee_hdr(bss_desc->bcn_rsn_ie, WLAN_EID_RSN)) { 1588c2ecf20Sopenharmony_ci iebody = (struct ie_body *) 1598c2ecf20Sopenharmony_ci (((u8 *) bss_desc->bcn_rsn_ie->data) + 1608c2ecf20Sopenharmony_ci RSN_GTK_OUI_OFFSET); 1618c2ecf20Sopenharmony_ci oui = &mwifiex_rsn_oui[cipher][0]; 1628c2ecf20Sopenharmony_ci ret = mwifiex_search_oui_in_ie(iebody, oui); 1638c2ecf20Sopenharmony_ci if (ret) 1648c2ecf20Sopenharmony_ci return ret; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci return ret; 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci/* 1708c2ecf20Sopenharmony_ci * This function checks if a given OUI is present in a WPA IE. 1718c2ecf20Sopenharmony_ci * 1728c2ecf20Sopenharmony_ci * The function first checks if a WPA IE is present or not in the 1738c2ecf20Sopenharmony_ci * BSS descriptor. It tries to locate the OUI only if such an IE is 1748c2ecf20Sopenharmony_ci * present. 1758c2ecf20Sopenharmony_ci */ 1768c2ecf20Sopenharmony_cistatic u8 1778c2ecf20Sopenharmony_cimwifiex_is_wpa_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci u8 *oui; 1808c2ecf20Sopenharmony_ci struct ie_body *iebody; 1818c2ecf20Sopenharmony_ci u8 ret = MWIFIEX_OUI_NOT_PRESENT; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if (has_vendor_hdr(bss_desc->bcn_wpa_ie, WLAN_EID_VENDOR_SPECIFIC)) { 1848c2ecf20Sopenharmony_ci iebody = (struct ie_body *)((u8 *)bss_desc->bcn_wpa_ie->data + 1858c2ecf20Sopenharmony_ci WPA_GTK_OUI_OFFSET); 1868c2ecf20Sopenharmony_ci oui = &mwifiex_wpa_oui[cipher][0]; 1878c2ecf20Sopenharmony_ci ret = mwifiex_search_oui_in_ie(iebody, oui); 1888c2ecf20Sopenharmony_ci if (ret) 1898c2ecf20Sopenharmony_ci return ret; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci return ret; 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci/* 1958c2ecf20Sopenharmony_ci * This function compares two SSIDs and checks if they match. 1968c2ecf20Sopenharmony_ci */ 1978c2ecf20Sopenharmony_cis32 1988c2ecf20Sopenharmony_cimwifiex_ssid_cmp(struct cfg80211_ssid *ssid1, struct cfg80211_ssid *ssid2) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci if (!ssid1 || !ssid2 || (ssid1->ssid_len != ssid2->ssid_len)) 2018c2ecf20Sopenharmony_ci return -1; 2028c2ecf20Sopenharmony_ci return memcmp(ssid1->ssid, ssid2->ssid, ssid1->ssid_len); 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci/* 2068c2ecf20Sopenharmony_ci * This function checks if wapi is enabled in driver and scanned network is 2078c2ecf20Sopenharmony_ci * compatible with it. 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_cistatic bool 2108c2ecf20Sopenharmony_cimwifiex_is_bss_wapi(struct mwifiex_private *priv, 2118c2ecf20Sopenharmony_ci struct mwifiex_bssdescriptor *bss_desc) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci if (priv->sec_info.wapi_enabled && 2148c2ecf20Sopenharmony_ci has_ieee_hdr(bss_desc->bcn_wapi_ie, WLAN_EID_BSS_AC_ACCESS_DELAY)) 2158c2ecf20Sopenharmony_ci return true; 2168c2ecf20Sopenharmony_ci return false; 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci/* 2208c2ecf20Sopenharmony_ci * This function checks if driver is configured with no security mode and 2218c2ecf20Sopenharmony_ci * scanned network is compatible with it. 2228c2ecf20Sopenharmony_ci */ 2238c2ecf20Sopenharmony_cistatic bool 2248c2ecf20Sopenharmony_cimwifiex_is_bss_no_sec(struct mwifiex_private *priv, 2258c2ecf20Sopenharmony_ci struct mwifiex_bssdescriptor *bss_desc) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled && 2288c2ecf20Sopenharmony_ci !priv->sec_info.wpa2_enabled && 2298c2ecf20Sopenharmony_ci !has_vendor_hdr(bss_desc->bcn_wpa_ie, WLAN_EID_VENDOR_SPECIFIC) && 2308c2ecf20Sopenharmony_ci !has_ieee_hdr(bss_desc->bcn_rsn_ie, WLAN_EID_RSN) && 2318c2ecf20Sopenharmony_ci !priv->sec_info.encryption_mode && !bss_desc->privacy) { 2328c2ecf20Sopenharmony_ci return true; 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci return false; 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci/* 2388c2ecf20Sopenharmony_ci * This function checks if static WEP is enabled in driver and scanned network 2398c2ecf20Sopenharmony_ci * is compatible with it. 2408c2ecf20Sopenharmony_ci */ 2418c2ecf20Sopenharmony_cistatic bool 2428c2ecf20Sopenharmony_cimwifiex_is_bss_static_wep(struct mwifiex_private *priv, 2438c2ecf20Sopenharmony_ci struct mwifiex_bssdescriptor *bss_desc) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci if (priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled && 2468c2ecf20Sopenharmony_ci !priv->sec_info.wpa2_enabled && bss_desc->privacy) { 2478c2ecf20Sopenharmony_ci return true; 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci return false; 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci/* 2538c2ecf20Sopenharmony_ci * This function checks if wpa is enabled in driver and scanned network is 2548c2ecf20Sopenharmony_ci * compatible with it. 2558c2ecf20Sopenharmony_ci */ 2568c2ecf20Sopenharmony_cistatic bool 2578c2ecf20Sopenharmony_cimwifiex_is_bss_wpa(struct mwifiex_private *priv, 2588c2ecf20Sopenharmony_ci struct mwifiex_bssdescriptor *bss_desc) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci if (!priv->sec_info.wep_enabled && priv->sec_info.wpa_enabled && 2618c2ecf20Sopenharmony_ci !priv->sec_info.wpa2_enabled && 2628c2ecf20Sopenharmony_ci has_vendor_hdr(bss_desc->bcn_wpa_ie, WLAN_EID_VENDOR_SPECIFIC) 2638c2ecf20Sopenharmony_ci /* 2648c2ecf20Sopenharmony_ci * Privacy bit may NOT be set in some APs like 2658c2ecf20Sopenharmony_ci * LinkSys WRT54G && bss_desc->privacy 2668c2ecf20Sopenharmony_ci */ 2678c2ecf20Sopenharmony_ci ) { 2688c2ecf20Sopenharmony_ci dbg_security_flags(INFO, "WPA", priv, bss_desc); 2698c2ecf20Sopenharmony_ci return true; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci return false; 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci/* 2758c2ecf20Sopenharmony_ci * This function checks if wpa2 is enabled in driver and scanned network is 2768c2ecf20Sopenharmony_ci * compatible with it. 2778c2ecf20Sopenharmony_ci */ 2788c2ecf20Sopenharmony_cistatic bool 2798c2ecf20Sopenharmony_cimwifiex_is_bss_wpa2(struct mwifiex_private *priv, 2808c2ecf20Sopenharmony_ci struct mwifiex_bssdescriptor *bss_desc) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled && 2838c2ecf20Sopenharmony_ci priv->sec_info.wpa2_enabled && 2848c2ecf20Sopenharmony_ci has_ieee_hdr(bss_desc->bcn_rsn_ie, WLAN_EID_RSN)) { 2858c2ecf20Sopenharmony_ci /* 2868c2ecf20Sopenharmony_ci * Privacy bit may NOT be set in some APs like 2878c2ecf20Sopenharmony_ci * LinkSys WRT54G && bss_desc->privacy 2888c2ecf20Sopenharmony_ci */ 2898c2ecf20Sopenharmony_ci dbg_security_flags(INFO, "WAP2", priv, bss_desc); 2908c2ecf20Sopenharmony_ci return true; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci return false; 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci/* 2968c2ecf20Sopenharmony_ci * This function checks if adhoc AES is enabled in driver and scanned network is 2978c2ecf20Sopenharmony_ci * compatible with it. 2988c2ecf20Sopenharmony_ci */ 2998c2ecf20Sopenharmony_cistatic bool 3008c2ecf20Sopenharmony_cimwifiex_is_bss_adhoc_aes(struct mwifiex_private *priv, 3018c2ecf20Sopenharmony_ci struct mwifiex_bssdescriptor *bss_desc) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled && 3048c2ecf20Sopenharmony_ci !priv->sec_info.wpa2_enabled && 3058c2ecf20Sopenharmony_ci !has_vendor_hdr(bss_desc->bcn_wpa_ie, WLAN_EID_VENDOR_SPECIFIC) && 3068c2ecf20Sopenharmony_ci !has_ieee_hdr(bss_desc->bcn_rsn_ie, WLAN_EID_RSN) && 3078c2ecf20Sopenharmony_ci !priv->sec_info.encryption_mode && bss_desc->privacy) { 3088c2ecf20Sopenharmony_ci return true; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci return false; 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci/* 3148c2ecf20Sopenharmony_ci * This function checks if dynamic WEP is enabled in driver and scanned network 3158c2ecf20Sopenharmony_ci * is compatible with it. 3168c2ecf20Sopenharmony_ci */ 3178c2ecf20Sopenharmony_cistatic bool 3188c2ecf20Sopenharmony_cimwifiex_is_bss_dynamic_wep(struct mwifiex_private *priv, 3198c2ecf20Sopenharmony_ci struct mwifiex_bssdescriptor *bss_desc) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled && 3228c2ecf20Sopenharmony_ci !priv->sec_info.wpa2_enabled && 3238c2ecf20Sopenharmony_ci !has_vendor_hdr(bss_desc->bcn_wpa_ie, WLAN_EID_VENDOR_SPECIFIC) && 3248c2ecf20Sopenharmony_ci !has_ieee_hdr(bss_desc->bcn_rsn_ie, WLAN_EID_RSN) && 3258c2ecf20Sopenharmony_ci priv->sec_info.encryption_mode && bss_desc->privacy) { 3268c2ecf20Sopenharmony_ci dbg_security_flags(INFO, "dynamic", priv, bss_desc); 3278c2ecf20Sopenharmony_ci return true; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci return false; 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci/* 3338c2ecf20Sopenharmony_ci * This function checks if a scanned network is compatible with the driver 3348c2ecf20Sopenharmony_ci * settings. 3358c2ecf20Sopenharmony_ci * 3368c2ecf20Sopenharmony_ci * WEP WPA WPA2 ad-hoc encrypt Network 3378c2ecf20Sopenharmony_ci * enabled enabled enabled AES mode Privacy WPA WPA2 Compatible 3388c2ecf20Sopenharmony_ci * 0 0 0 0 NONE 0 0 0 yes No security 3398c2ecf20Sopenharmony_ci * 0 1 0 0 x 1x 1 x yes WPA (disable 3408c2ecf20Sopenharmony_ci * HT if no AES) 3418c2ecf20Sopenharmony_ci * 0 0 1 0 x 1x x 1 yes WPA2 (disable 3428c2ecf20Sopenharmony_ci * HT if no AES) 3438c2ecf20Sopenharmony_ci * 0 0 0 1 NONE 1 0 0 yes Ad-hoc AES 3448c2ecf20Sopenharmony_ci * 1 0 0 0 NONE 1 0 0 yes Static WEP 3458c2ecf20Sopenharmony_ci * (disable HT) 3468c2ecf20Sopenharmony_ci * 0 0 0 0 !=NONE 1 0 0 yes Dynamic WEP 3478c2ecf20Sopenharmony_ci * 3488c2ecf20Sopenharmony_ci * Compatibility is not matched while roaming, except for mode. 3498c2ecf20Sopenharmony_ci */ 3508c2ecf20Sopenharmony_cistatic s32 3518c2ecf20Sopenharmony_cimwifiex_is_network_compatible(struct mwifiex_private *priv, 3528c2ecf20Sopenharmony_ci struct mwifiex_bssdescriptor *bss_desc, u32 mode) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci bss_desc->disable_11n = false; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci /* Don't check for compatibility if roaming */ 3598c2ecf20Sopenharmony_ci if (priv->media_connected && 3608c2ecf20Sopenharmony_ci (priv->bss_mode == NL80211_IFTYPE_STATION) && 3618c2ecf20Sopenharmony_ci (bss_desc->bss_mode == NL80211_IFTYPE_STATION)) 3628c2ecf20Sopenharmony_ci return 0; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci if (priv->wps.session_enable) { 3658c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, IOCTL, 3668c2ecf20Sopenharmony_ci "info: return success directly in WPS period\n"); 3678c2ecf20Sopenharmony_ci return 0; 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (bss_desc->chan_sw_ie_present) { 3718c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, 3728c2ecf20Sopenharmony_ci "Don't connect to AP with WLAN_EID_CHANNEL_SWITCH\n"); 3738c2ecf20Sopenharmony_ci return -1; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci if (mwifiex_is_bss_wapi(priv, bss_desc)) { 3778c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, 3788c2ecf20Sopenharmony_ci "info: return success for WAPI AP\n"); 3798c2ecf20Sopenharmony_ci return 0; 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci if (bss_desc->bss_mode == mode) { 3838c2ecf20Sopenharmony_ci if (mwifiex_is_bss_no_sec(priv, bss_desc)) { 3848c2ecf20Sopenharmony_ci /* No security */ 3858c2ecf20Sopenharmony_ci return 0; 3868c2ecf20Sopenharmony_ci } else if (mwifiex_is_bss_static_wep(priv, bss_desc)) { 3878c2ecf20Sopenharmony_ci /* Static WEP enabled */ 3888c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, 3898c2ecf20Sopenharmony_ci "info: Disable 11n in WEP mode.\n"); 3908c2ecf20Sopenharmony_ci bss_desc->disable_11n = true; 3918c2ecf20Sopenharmony_ci return 0; 3928c2ecf20Sopenharmony_ci } else if (mwifiex_is_bss_wpa(priv, bss_desc)) { 3938c2ecf20Sopenharmony_ci /* WPA enabled */ 3948c2ecf20Sopenharmony_ci if (((priv->adapter->config_bands & BAND_GN || 3958c2ecf20Sopenharmony_ci priv->adapter->config_bands & BAND_AN) && 3968c2ecf20Sopenharmony_ci bss_desc->bcn_ht_cap) && 3978c2ecf20Sopenharmony_ci !mwifiex_is_wpa_oui_present(bss_desc, 3988c2ecf20Sopenharmony_ci CIPHER_SUITE_CCMP)) { 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if (mwifiex_is_wpa_oui_present 4018c2ecf20Sopenharmony_ci (bss_desc, CIPHER_SUITE_TKIP)) { 4028c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, 4038c2ecf20Sopenharmony_ci "info: Disable 11n if AES\t" 4048c2ecf20Sopenharmony_ci "is not supported by AP\n"); 4058c2ecf20Sopenharmony_ci bss_desc->disable_11n = true; 4068c2ecf20Sopenharmony_ci } else { 4078c2ecf20Sopenharmony_ci return -1; 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci return 0; 4118c2ecf20Sopenharmony_ci } else if (mwifiex_is_bss_wpa2(priv, bss_desc)) { 4128c2ecf20Sopenharmony_ci /* WPA2 enabled */ 4138c2ecf20Sopenharmony_ci if (((priv->adapter->config_bands & BAND_GN || 4148c2ecf20Sopenharmony_ci priv->adapter->config_bands & BAND_AN) && 4158c2ecf20Sopenharmony_ci bss_desc->bcn_ht_cap) && 4168c2ecf20Sopenharmony_ci !mwifiex_is_rsn_oui_present(bss_desc, 4178c2ecf20Sopenharmony_ci CIPHER_SUITE_CCMP)) { 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (mwifiex_is_rsn_oui_present 4208c2ecf20Sopenharmony_ci (bss_desc, CIPHER_SUITE_TKIP)) { 4218c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, 4228c2ecf20Sopenharmony_ci "info: Disable 11n if AES\t" 4238c2ecf20Sopenharmony_ci "is not supported by AP\n"); 4248c2ecf20Sopenharmony_ci bss_desc->disable_11n = true; 4258c2ecf20Sopenharmony_ci } else { 4268c2ecf20Sopenharmony_ci return -1; 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci return 0; 4308c2ecf20Sopenharmony_ci } else if (mwifiex_is_bss_adhoc_aes(priv, bss_desc)) { 4318c2ecf20Sopenharmony_ci /* Ad-hoc AES enabled */ 4328c2ecf20Sopenharmony_ci return 0; 4338c2ecf20Sopenharmony_ci } else if (mwifiex_is_bss_dynamic_wep(priv, bss_desc)) { 4348c2ecf20Sopenharmony_ci /* Dynamic WEP enabled */ 4358c2ecf20Sopenharmony_ci return 0; 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci /* Security doesn't match */ 4398c2ecf20Sopenharmony_ci dbg_security_flags(ERROR, "failed", priv, bss_desc); 4408c2ecf20Sopenharmony_ci return -1; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci /* Mode doesn't match */ 4448c2ecf20Sopenharmony_ci return -1; 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci/* 4488c2ecf20Sopenharmony_ci * This function creates a channel list for the driver to scan, based 4498c2ecf20Sopenharmony_ci * on region/band information. 4508c2ecf20Sopenharmony_ci * 4518c2ecf20Sopenharmony_ci * This routine is used for any scan that is not provided with a 4528c2ecf20Sopenharmony_ci * specific channel list to scan. 4538c2ecf20Sopenharmony_ci */ 4548c2ecf20Sopenharmony_cistatic int 4558c2ecf20Sopenharmony_cimwifiex_scan_create_channel_list(struct mwifiex_private *priv, 4568c2ecf20Sopenharmony_ci const struct mwifiex_user_scan_cfg 4578c2ecf20Sopenharmony_ci *user_scan_in, 4588c2ecf20Sopenharmony_ci struct mwifiex_chan_scan_param_set 4598c2ecf20Sopenharmony_ci *scan_chan_list, 4608c2ecf20Sopenharmony_ci u8 filtered_scan) 4618c2ecf20Sopenharmony_ci{ 4628c2ecf20Sopenharmony_ci enum nl80211_band band; 4638c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband; 4648c2ecf20Sopenharmony_ci struct ieee80211_channel *ch; 4658c2ecf20Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 4668c2ecf20Sopenharmony_ci int chan_idx = 0, i; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci for (band = 0; (band < NUM_NL80211_BANDS) ; band++) { 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci if (!priv->wdev.wiphy->bands[band]) 4718c2ecf20Sopenharmony_ci continue; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci sband = priv->wdev.wiphy->bands[band]; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci for (i = 0; (i < sband->n_channels) ; i++) { 4768c2ecf20Sopenharmony_ci ch = &sband->channels[i]; 4778c2ecf20Sopenharmony_ci if (ch->flags & IEEE80211_CHAN_DISABLED) 4788c2ecf20Sopenharmony_ci continue; 4798c2ecf20Sopenharmony_ci scan_chan_list[chan_idx].radio_type = band; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci if (user_scan_in && 4828c2ecf20Sopenharmony_ci user_scan_in->chan_list[0].scan_time) 4838c2ecf20Sopenharmony_ci scan_chan_list[chan_idx].max_scan_time = 4848c2ecf20Sopenharmony_ci cpu_to_le16((u16) user_scan_in-> 4858c2ecf20Sopenharmony_ci chan_list[0].scan_time); 4868c2ecf20Sopenharmony_ci else if ((ch->flags & IEEE80211_CHAN_NO_IR) || 4878c2ecf20Sopenharmony_ci (ch->flags & IEEE80211_CHAN_RADAR)) 4888c2ecf20Sopenharmony_ci scan_chan_list[chan_idx].max_scan_time = 4898c2ecf20Sopenharmony_ci cpu_to_le16(adapter->passive_scan_time); 4908c2ecf20Sopenharmony_ci else 4918c2ecf20Sopenharmony_ci scan_chan_list[chan_idx].max_scan_time = 4928c2ecf20Sopenharmony_ci cpu_to_le16(adapter->active_scan_time); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci if (ch->flags & IEEE80211_CHAN_NO_IR) 4958c2ecf20Sopenharmony_ci scan_chan_list[chan_idx].chan_scan_mode_bitmap 4968c2ecf20Sopenharmony_ci |= (MWIFIEX_PASSIVE_SCAN | 4978c2ecf20Sopenharmony_ci MWIFIEX_HIDDEN_SSID_REPORT); 4988c2ecf20Sopenharmony_ci else 4998c2ecf20Sopenharmony_ci scan_chan_list[chan_idx].chan_scan_mode_bitmap 5008c2ecf20Sopenharmony_ci &= ~MWIFIEX_PASSIVE_SCAN; 5018c2ecf20Sopenharmony_ci scan_chan_list[chan_idx].chan_number = 5028c2ecf20Sopenharmony_ci (u32) ch->hw_value; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci scan_chan_list[chan_idx].chan_scan_mode_bitmap 5058c2ecf20Sopenharmony_ci |= MWIFIEX_DISABLE_CHAN_FILT; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci if (filtered_scan && 5088c2ecf20Sopenharmony_ci !((ch->flags & IEEE80211_CHAN_NO_IR) || 5098c2ecf20Sopenharmony_ci (ch->flags & IEEE80211_CHAN_RADAR))) 5108c2ecf20Sopenharmony_ci scan_chan_list[chan_idx].max_scan_time = 5118c2ecf20Sopenharmony_ci cpu_to_le16(adapter->specific_scan_time); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci chan_idx++; 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci return chan_idx; 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci/* This function creates a channel list tlv for bgscan config, based 5218c2ecf20Sopenharmony_ci * on region/band information. 5228c2ecf20Sopenharmony_ci */ 5238c2ecf20Sopenharmony_cistatic int 5248c2ecf20Sopenharmony_cimwifiex_bgscan_create_channel_list(struct mwifiex_private *priv, 5258c2ecf20Sopenharmony_ci const struct mwifiex_bg_scan_cfg 5268c2ecf20Sopenharmony_ci *bgscan_cfg_in, 5278c2ecf20Sopenharmony_ci struct mwifiex_chan_scan_param_set 5288c2ecf20Sopenharmony_ci *scan_chan_list) 5298c2ecf20Sopenharmony_ci{ 5308c2ecf20Sopenharmony_ci enum nl80211_band band; 5318c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband; 5328c2ecf20Sopenharmony_ci struct ieee80211_channel *ch; 5338c2ecf20Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 5348c2ecf20Sopenharmony_ci int chan_idx = 0, i; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci for (band = 0; (band < NUM_NL80211_BANDS); band++) { 5378c2ecf20Sopenharmony_ci if (!priv->wdev.wiphy->bands[band]) 5388c2ecf20Sopenharmony_ci continue; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci sband = priv->wdev.wiphy->bands[band]; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci for (i = 0; (i < sband->n_channels) ; i++) { 5438c2ecf20Sopenharmony_ci ch = &sband->channels[i]; 5448c2ecf20Sopenharmony_ci if (ch->flags & IEEE80211_CHAN_DISABLED) 5458c2ecf20Sopenharmony_ci continue; 5468c2ecf20Sopenharmony_ci scan_chan_list[chan_idx].radio_type = band; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci if (bgscan_cfg_in->chan_list[0].scan_time) 5498c2ecf20Sopenharmony_ci scan_chan_list[chan_idx].max_scan_time = 5508c2ecf20Sopenharmony_ci cpu_to_le16((u16)bgscan_cfg_in-> 5518c2ecf20Sopenharmony_ci chan_list[0].scan_time); 5528c2ecf20Sopenharmony_ci else if (ch->flags & IEEE80211_CHAN_NO_IR) 5538c2ecf20Sopenharmony_ci scan_chan_list[chan_idx].max_scan_time = 5548c2ecf20Sopenharmony_ci cpu_to_le16(adapter->passive_scan_time); 5558c2ecf20Sopenharmony_ci else 5568c2ecf20Sopenharmony_ci scan_chan_list[chan_idx].max_scan_time = 5578c2ecf20Sopenharmony_ci cpu_to_le16(adapter-> 5588c2ecf20Sopenharmony_ci specific_scan_time); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci if (ch->flags & IEEE80211_CHAN_NO_IR) 5618c2ecf20Sopenharmony_ci scan_chan_list[chan_idx].chan_scan_mode_bitmap 5628c2ecf20Sopenharmony_ci |= MWIFIEX_PASSIVE_SCAN; 5638c2ecf20Sopenharmony_ci else 5648c2ecf20Sopenharmony_ci scan_chan_list[chan_idx].chan_scan_mode_bitmap 5658c2ecf20Sopenharmony_ci &= ~MWIFIEX_PASSIVE_SCAN; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci scan_chan_list[chan_idx].chan_number = 5688c2ecf20Sopenharmony_ci (u32)ch->hw_value; 5698c2ecf20Sopenharmony_ci chan_idx++; 5708c2ecf20Sopenharmony_ci } 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci return chan_idx; 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci/* This function appends rate TLV to scan config command. */ 5768c2ecf20Sopenharmony_cistatic int 5778c2ecf20Sopenharmony_cimwifiex_append_rate_tlv(struct mwifiex_private *priv, 5788c2ecf20Sopenharmony_ci struct mwifiex_scan_cmd_config *scan_cfg_out, 5798c2ecf20Sopenharmony_ci u8 radio) 5808c2ecf20Sopenharmony_ci{ 5818c2ecf20Sopenharmony_ci struct mwifiex_ie_types_rates_param_set *rates_tlv; 5828c2ecf20Sopenharmony_ci u8 rates[MWIFIEX_SUPPORTED_RATES], *tlv_pos; 5838c2ecf20Sopenharmony_ci u32 rates_size; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci memset(rates, 0, sizeof(rates)); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci tlv_pos = (u8 *)scan_cfg_out->tlv_buf + scan_cfg_out->tlv_buf_len; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci if (priv->scan_request) 5908c2ecf20Sopenharmony_ci rates_size = mwifiex_get_rates_from_cfg80211(priv, rates, 5918c2ecf20Sopenharmony_ci radio); 5928c2ecf20Sopenharmony_ci else 5938c2ecf20Sopenharmony_ci rates_size = mwifiex_get_supported_rates(priv, rates); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, CMD, 5968c2ecf20Sopenharmony_ci "info: SCAN_CMD: Rates size = %d\n", 5978c2ecf20Sopenharmony_ci rates_size); 5988c2ecf20Sopenharmony_ci rates_tlv = (struct mwifiex_ie_types_rates_param_set *)tlv_pos; 5998c2ecf20Sopenharmony_ci rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES); 6008c2ecf20Sopenharmony_ci rates_tlv->header.len = cpu_to_le16((u16) rates_size); 6018c2ecf20Sopenharmony_ci memcpy(rates_tlv->rates, rates, rates_size); 6028c2ecf20Sopenharmony_ci scan_cfg_out->tlv_buf_len += sizeof(rates_tlv->header) + rates_size; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci return rates_size; 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci/* 6088c2ecf20Sopenharmony_ci * This function constructs and sends multiple scan config commands to 6098c2ecf20Sopenharmony_ci * the firmware. 6108c2ecf20Sopenharmony_ci * 6118c2ecf20Sopenharmony_ci * Previous routines in the code flow have created a scan command configuration 6128c2ecf20Sopenharmony_ci * with any requested TLVs. This function splits the channel TLV into maximum 6138c2ecf20Sopenharmony_ci * channels supported per scan lists and sends the portion of the channel TLV, 6148c2ecf20Sopenharmony_ci * along with the other TLVs, to the firmware. 6158c2ecf20Sopenharmony_ci */ 6168c2ecf20Sopenharmony_cistatic int 6178c2ecf20Sopenharmony_cimwifiex_scan_channel_list(struct mwifiex_private *priv, 6188c2ecf20Sopenharmony_ci u32 max_chan_per_scan, u8 filtered_scan, 6198c2ecf20Sopenharmony_ci struct mwifiex_scan_cmd_config *scan_cfg_out, 6208c2ecf20Sopenharmony_ci struct mwifiex_ie_types_chan_list_param_set 6218c2ecf20Sopenharmony_ci *chan_tlv_out, 6228c2ecf20Sopenharmony_ci struct mwifiex_chan_scan_param_set *scan_chan_list) 6238c2ecf20Sopenharmony_ci{ 6248c2ecf20Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 6258c2ecf20Sopenharmony_ci int ret = 0; 6268c2ecf20Sopenharmony_ci struct mwifiex_chan_scan_param_set *tmp_chan_list; 6278c2ecf20Sopenharmony_ci struct mwifiex_chan_scan_param_set *start_chan; 6288c2ecf20Sopenharmony_ci u32 tlv_idx, rates_size, cmd_no; 6298c2ecf20Sopenharmony_ci u32 total_scan_time; 6308c2ecf20Sopenharmony_ci u32 done_early; 6318c2ecf20Sopenharmony_ci u8 radio_type; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci if (!scan_cfg_out || !chan_tlv_out || !scan_chan_list) { 6348c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 6358c2ecf20Sopenharmony_ci "info: Scan: Null detect: %p, %p, %p\n", 6368c2ecf20Sopenharmony_ci scan_cfg_out, chan_tlv_out, scan_chan_list); 6378c2ecf20Sopenharmony_ci return -1; 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci /* Check csa channel expiry before preparing scan list */ 6418c2ecf20Sopenharmony_ci mwifiex_11h_get_csa_closed_channel(priv); 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci chan_tlv_out->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci /* Set the temp channel struct pointer to the start of the desired 6468c2ecf20Sopenharmony_ci list */ 6478c2ecf20Sopenharmony_ci tmp_chan_list = scan_chan_list; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci /* Loop through the desired channel list, sending a new firmware scan 6508c2ecf20Sopenharmony_ci commands for each max_chan_per_scan channels (or for 1,6,11 6518c2ecf20Sopenharmony_ci individually if configured accordingly) */ 6528c2ecf20Sopenharmony_ci while (tmp_chan_list->chan_number) { 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci tlv_idx = 0; 6558c2ecf20Sopenharmony_ci total_scan_time = 0; 6568c2ecf20Sopenharmony_ci radio_type = 0; 6578c2ecf20Sopenharmony_ci chan_tlv_out->header.len = 0; 6588c2ecf20Sopenharmony_ci start_chan = tmp_chan_list; 6598c2ecf20Sopenharmony_ci done_early = false; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci /* 6628c2ecf20Sopenharmony_ci * Construct the Channel TLV for the scan command. Continue to 6638c2ecf20Sopenharmony_ci * insert channel TLVs until: 6648c2ecf20Sopenharmony_ci * - the tlv_idx hits the maximum configured per scan command 6658c2ecf20Sopenharmony_ci * - the next channel to insert is 0 (end of desired channel 6668c2ecf20Sopenharmony_ci * list) 6678c2ecf20Sopenharmony_ci * - done_early is set (controlling individual scanning of 6688c2ecf20Sopenharmony_ci * 1,6,11) 6698c2ecf20Sopenharmony_ci */ 6708c2ecf20Sopenharmony_ci while (tlv_idx < max_chan_per_scan && 6718c2ecf20Sopenharmony_ci tmp_chan_list->chan_number && !done_early) { 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci if (tmp_chan_list->chan_number == priv->csa_chan) { 6748c2ecf20Sopenharmony_ci tmp_chan_list++; 6758c2ecf20Sopenharmony_ci continue; 6768c2ecf20Sopenharmony_ci } 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci radio_type = tmp_chan_list->radio_type; 6798c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 6808c2ecf20Sopenharmony_ci "info: Scan: Chan(%3d), Radio(%d),\t" 6818c2ecf20Sopenharmony_ci "Mode(%d, %d), Dur(%d)\n", 6828c2ecf20Sopenharmony_ci tmp_chan_list->chan_number, 6838c2ecf20Sopenharmony_ci tmp_chan_list->radio_type, 6848c2ecf20Sopenharmony_ci tmp_chan_list->chan_scan_mode_bitmap 6858c2ecf20Sopenharmony_ci & MWIFIEX_PASSIVE_SCAN, 6868c2ecf20Sopenharmony_ci (tmp_chan_list->chan_scan_mode_bitmap 6878c2ecf20Sopenharmony_ci & MWIFIEX_DISABLE_CHAN_FILT) >> 1, 6888c2ecf20Sopenharmony_ci le16_to_cpu(tmp_chan_list->max_scan_time)); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci /* Copy the current channel TLV to the command being 6918c2ecf20Sopenharmony_ci prepared */ 6928c2ecf20Sopenharmony_ci memcpy(chan_tlv_out->chan_scan_param + tlv_idx, 6938c2ecf20Sopenharmony_ci tmp_chan_list, 6948c2ecf20Sopenharmony_ci sizeof(chan_tlv_out->chan_scan_param)); 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci /* Increment the TLV header length by the size 6978c2ecf20Sopenharmony_ci appended */ 6988c2ecf20Sopenharmony_ci le16_unaligned_add_cpu(&chan_tlv_out->header.len, 6998c2ecf20Sopenharmony_ci sizeof( 7008c2ecf20Sopenharmony_ci chan_tlv_out->chan_scan_param)); 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci /* 7038c2ecf20Sopenharmony_ci * The tlv buffer length is set to the number of bytes 7048c2ecf20Sopenharmony_ci * of the between the channel tlv pointer and the start 7058c2ecf20Sopenharmony_ci * of the tlv buffer. This compensates for any TLVs 7068c2ecf20Sopenharmony_ci * that were appended before the channel list. 7078c2ecf20Sopenharmony_ci */ 7088c2ecf20Sopenharmony_ci scan_cfg_out->tlv_buf_len = (u32) ((u8 *) chan_tlv_out - 7098c2ecf20Sopenharmony_ci scan_cfg_out->tlv_buf); 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci /* Add the size of the channel tlv header and the data 7128c2ecf20Sopenharmony_ci length */ 7138c2ecf20Sopenharmony_ci scan_cfg_out->tlv_buf_len += 7148c2ecf20Sopenharmony_ci (sizeof(chan_tlv_out->header) 7158c2ecf20Sopenharmony_ci + le16_to_cpu(chan_tlv_out->header.len)); 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci /* Increment the index to the channel tlv we are 7188c2ecf20Sopenharmony_ci constructing */ 7198c2ecf20Sopenharmony_ci tlv_idx++; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci /* Count the total scan time per command */ 7228c2ecf20Sopenharmony_ci total_scan_time += 7238c2ecf20Sopenharmony_ci le16_to_cpu(tmp_chan_list->max_scan_time); 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci done_early = false; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci /* Stop the loop if the *current* channel is in the 7288c2ecf20Sopenharmony_ci 1,6,11 set and we are not filtering on a BSSID 7298c2ecf20Sopenharmony_ci or SSID. */ 7308c2ecf20Sopenharmony_ci if (!filtered_scan && 7318c2ecf20Sopenharmony_ci (tmp_chan_list->chan_number == 1 || 7328c2ecf20Sopenharmony_ci tmp_chan_list->chan_number == 6 || 7338c2ecf20Sopenharmony_ci tmp_chan_list->chan_number == 11)) 7348c2ecf20Sopenharmony_ci done_early = true; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci /* Increment the tmp pointer to the next channel to 7378c2ecf20Sopenharmony_ci be scanned */ 7388c2ecf20Sopenharmony_ci tmp_chan_list++; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci /* Stop the loop if the *next* channel is in the 1,6,11 7418c2ecf20Sopenharmony_ci set. This will cause it to be the only channel 7428c2ecf20Sopenharmony_ci scanned on the next interation */ 7438c2ecf20Sopenharmony_ci if (!filtered_scan && 7448c2ecf20Sopenharmony_ci (tmp_chan_list->chan_number == 1 || 7458c2ecf20Sopenharmony_ci tmp_chan_list->chan_number == 6 || 7468c2ecf20Sopenharmony_ci tmp_chan_list->chan_number == 11)) 7478c2ecf20Sopenharmony_ci done_early = true; 7488c2ecf20Sopenharmony_ci } 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci /* The total scan time should be less than scan command timeout 7518c2ecf20Sopenharmony_ci value */ 7528c2ecf20Sopenharmony_ci if (total_scan_time > MWIFIEX_MAX_TOTAL_SCAN_TIME) { 7538c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 7548c2ecf20Sopenharmony_ci "total scan time %dms\t" 7558c2ecf20Sopenharmony_ci "is over limit (%dms), scan skipped\n", 7568c2ecf20Sopenharmony_ci total_scan_time, 7578c2ecf20Sopenharmony_ci MWIFIEX_MAX_TOTAL_SCAN_TIME); 7588c2ecf20Sopenharmony_ci ret = -1; 7598c2ecf20Sopenharmony_ci break; 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci rates_size = mwifiex_append_rate_tlv(priv, scan_cfg_out, 7638c2ecf20Sopenharmony_ci radio_type); 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci priv->adapter->scan_channels = start_chan; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci /* Send the scan command to the firmware with the specified 7688c2ecf20Sopenharmony_ci cfg */ 7698c2ecf20Sopenharmony_ci if (priv->adapter->ext_scan) 7708c2ecf20Sopenharmony_ci cmd_no = HostCmd_CMD_802_11_SCAN_EXT; 7718c2ecf20Sopenharmony_ci else 7728c2ecf20Sopenharmony_ci cmd_no = HostCmd_CMD_802_11_SCAN; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci ret = mwifiex_send_cmd(priv, cmd_no, HostCmd_ACT_GEN_SET, 7758c2ecf20Sopenharmony_ci 0, scan_cfg_out, false); 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci /* rate IE is updated per scan command but same starting 7788c2ecf20Sopenharmony_ci * pointer is used each time so that rate IE from earlier 7798c2ecf20Sopenharmony_ci * scan_cfg_out->buf is overwritten with new one. 7808c2ecf20Sopenharmony_ci */ 7818c2ecf20Sopenharmony_ci scan_cfg_out->tlv_buf_len -= 7828c2ecf20Sopenharmony_ci sizeof(struct mwifiex_ie_types_header) + rates_size; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci if (ret) { 7858c2ecf20Sopenharmony_ci mwifiex_cancel_pending_scan_cmd(adapter); 7868c2ecf20Sopenharmony_ci break; 7878c2ecf20Sopenharmony_ci } 7888c2ecf20Sopenharmony_ci } 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci if (ret) 7918c2ecf20Sopenharmony_ci return -1; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci return 0; 7948c2ecf20Sopenharmony_ci} 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci/* 7978c2ecf20Sopenharmony_ci * This function constructs a scan command configuration structure to use 7988c2ecf20Sopenharmony_ci * in scan commands. 7998c2ecf20Sopenharmony_ci * 8008c2ecf20Sopenharmony_ci * Application layer or other functions can invoke network scanning 8018c2ecf20Sopenharmony_ci * with a scan configuration supplied in a user scan configuration structure. 8028c2ecf20Sopenharmony_ci * This structure is used as the basis of one or many scan command configuration 8038c2ecf20Sopenharmony_ci * commands that are sent to the command processing module and eventually to the 8048c2ecf20Sopenharmony_ci * firmware. 8058c2ecf20Sopenharmony_ci * 8068c2ecf20Sopenharmony_ci * This function creates a scan command configuration structure based on the 8078c2ecf20Sopenharmony_ci * following user supplied parameters (if present): 8088c2ecf20Sopenharmony_ci * - SSID filter 8098c2ecf20Sopenharmony_ci * - BSSID filter 8108c2ecf20Sopenharmony_ci * - Number of Probes to be sent 8118c2ecf20Sopenharmony_ci * - Channel list 8128c2ecf20Sopenharmony_ci * 8138c2ecf20Sopenharmony_ci * If the SSID or BSSID filter is not present, the filter is disabled/cleared. 8148c2ecf20Sopenharmony_ci * If the number of probes is not set, adapter default setting is used. 8158c2ecf20Sopenharmony_ci */ 8168c2ecf20Sopenharmony_cistatic void 8178c2ecf20Sopenharmony_cimwifiex_config_scan(struct mwifiex_private *priv, 8188c2ecf20Sopenharmony_ci const struct mwifiex_user_scan_cfg *user_scan_in, 8198c2ecf20Sopenharmony_ci struct mwifiex_scan_cmd_config *scan_cfg_out, 8208c2ecf20Sopenharmony_ci struct mwifiex_ie_types_chan_list_param_set **chan_list_out, 8218c2ecf20Sopenharmony_ci struct mwifiex_chan_scan_param_set *scan_chan_list, 8228c2ecf20Sopenharmony_ci u8 *max_chan_per_scan, u8 *filtered_scan, 8238c2ecf20Sopenharmony_ci u8 *scan_current_only) 8248c2ecf20Sopenharmony_ci{ 8258c2ecf20Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 8268c2ecf20Sopenharmony_ci struct mwifiex_ie_types_num_probes *num_probes_tlv; 8278c2ecf20Sopenharmony_ci struct mwifiex_ie_types_scan_chan_gap *chan_gap_tlv; 8288c2ecf20Sopenharmony_ci struct mwifiex_ie_types_random_mac *random_mac_tlv; 8298c2ecf20Sopenharmony_ci struct mwifiex_ie_types_wildcard_ssid_params *wildcard_ssid_tlv; 8308c2ecf20Sopenharmony_ci struct mwifiex_ie_types_bssid_list *bssid_tlv; 8318c2ecf20Sopenharmony_ci u8 *tlv_pos; 8328c2ecf20Sopenharmony_ci u32 num_probes; 8338c2ecf20Sopenharmony_ci u32 ssid_len; 8348c2ecf20Sopenharmony_ci u32 chan_idx; 8358c2ecf20Sopenharmony_ci u32 scan_type; 8368c2ecf20Sopenharmony_ci u16 scan_dur; 8378c2ecf20Sopenharmony_ci u8 channel; 8388c2ecf20Sopenharmony_ci u8 radio_type; 8398c2ecf20Sopenharmony_ci int i; 8408c2ecf20Sopenharmony_ci u8 ssid_filter; 8418c2ecf20Sopenharmony_ci struct mwifiex_ie_types_htcap *ht_cap; 8428c2ecf20Sopenharmony_ci struct mwifiex_ie_types_bss_mode *bss_mode; 8438c2ecf20Sopenharmony_ci const u8 zero_mac[6] = {0, 0, 0, 0, 0, 0}; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci /* The tlv_buf_len is calculated for each scan command. The TLVs added 8468c2ecf20Sopenharmony_ci in this routine will be preserved since the routine that sends the 8478c2ecf20Sopenharmony_ci command will append channelTLVs at *chan_list_out. The difference 8488c2ecf20Sopenharmony_ci between the *chan_list_out and the tlv_buf start will be used to 8498c2ecf20Sopenharmony_ci calculate the size of anything we add in this routine. */ 8508c2ecf20Sopenharmony_ci scan_cfg_out->tlv_buf_len = 0; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci /* Running tlv pointer. Assigned to chan_list_out at end of function 8538c2ecf20Sopenharmony_ci so later routines know where channels can be added to the command 8548c2ecf20Sopenharmony_ci buf */ 8558c2ecf20Sopenharmony_ci tlv_pos = scan_cfg_out->tlv_buf; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci /* Initialize the scan as un-filtered; the flag is later set to TRUE 8588c2ecf20Sopenharmony_ci below if a SSID or BSSID filter is sent in the command */ 8598c2ecf20Sopenharmony_ci *filtered_scan = false; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci /* Initialize the scan as not being only on the current channel. If 8628c2ecf20Sopenharmony_ci the channel list is customized, only contains one channel, and is 8638c2ecf20Sopenharmony_ci the active channel, this is set true and data flow is not halted. */ 8648c2ecf20Sopenharmony_ci *scan_current_only = false; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci if (user_scan_in) { 8678c2ecf20Sopenharmony_ci u8 tmpaddr[ETH_ALEN]; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci /* Default the ssid_filter flag to TRUE, set false under 8708c2ecf20Sopenharmony_ci certain wildcard conditions and qualified by the existence 8718c2ecf20Sopenharmony_ci of an SSID list before marking the scan as filtered */ 8728c2ecf20Sopenharmony_ci ssid_filter = true; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci /* Set the BSS type scan filter, use Adapter setting if 8758c2ecf20Sopenharmony_ci unset */ 8768c2ecf20Sopenharmony_ci scan_cfg_out->bss_mode = 8778c2ecf20Sopenharmony_ci (u8)(user_scan_in->bss_mode ?: adapter->scan_mode); 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci /* Set the number of probes to send, use Adapter setting 8808c2ecf20Sopenharmony_ci if unset */ 8818c2ecf20Sopenharmony_ci num_probes = user_scan_in->num_probes ?: adapter->scan_probes; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci /* 8848c2ecf20Sopenharmony_ci * Set the BSSID filter to the incoming configuration, 8858c2ecf20Sopenharmony_ci * if non-zero. If not set, it will remain disabled 8868c2ecf20Sopenharmony_ci * (all zeros). 8878c2ecf20Sopenharmony_ci */ 8888c2ecf20Sopenharmony_ci memcpy(scan_cfg_out->specific_bssid, 8898c2ecf20Sopenharmony_ci user_scan_in->specific_bssid, 8908c2ecf20Sopenharmony_ci sizeof(scan_cfg_out->specific_bssid)); 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci memcpy(tmpaddr, scan_cfg_out->specific_bssid, ETH_ALEN); 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci if (adapter->ext_scan && 8958c2ecf20Sopenharmony_ci !is_zero_ether_addr(tmpaddr)) { 8968c2ecf20Sopenharmony_ci bssid_tlv = 8978c2ecf20Sopenharmony_ci (struct mwifiex_ie_types_bssid_list *)tlv_pos; 8988c2ecf20Sopenharmony_ci bssid_tlv->header.type = cpu_to_le16(TLV_TYPE_BSSID); 8998c2ecf20Sopenharmony_ci bssid_tlv->header.len = cpu_to_le16(ETH_ALEN); 9008c2ecf20Sopenharmony_ci memcpy(bssid_tlv->bssid, user_scan_in->specific_bssid, 9018c2ecf20Sopenharmony_ci ETH_ALEN); 9028c2ecf20Sopenharmony_ci tlv_pos += sizeof(struct mwifiex_ie_types_bssid_list); 9038c2ecf20Sopenharmony_ci } 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci for (i = 0; i < user_scan_in->num_ssids; i++) { 9068c2ecf20Sopenharmony_ci ssid_len = user_scan_in->ssid_list[i].ssid_len; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci wildcard_ssid_tlv = 9098c2ecf20Sopenharmony_ci (struct mwifiex_ie_types_wildcard_ssid_params *) 9108c2ecf20Sopenharmony_ci tlv_pos; 9118c2ecf20Sopenharmony_ci wildcard_ssid_tlv->header.type = 9128c2ecf20Sopenharmony_ci cpu_to_le16(TLV_TYPE_WILDCARDSSID); 9138c2ecf20Sopenharmony_ci wildcard_ssid_tlv->header.len = cpu_to_le16( 9148c2ecf20Sopenharmony_ci (u16) (ssid_len + sizeof(wildcard_ssid_tlv-> 9158c2ecf20Sopenharmony_ci max_ssid_length))); 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci /* 9188c2ecf20Sopenharmony_ci * max_ssid_length = 0 tells firmware to perform 9198c2ecf20Sopenharmony_ci * specific scan for the SSID filled, whereas 9208c2ecf20Sopenharmony_ci * max_ssid_length = IEEE80211_MAX_SSID_LEN is for 9218c2ecf20Sopenharmony_ci * wildcard scan. 9228c2ecf20Sopenharmony_ci */ 9238c2ecf20Sopenharmony_ci if (ssid_len) 9248c2ecf20Sopenharmony_ci wildcard_ssid_tlv->max_ssid_length = 0; 9258c2ecf20Sopenharmony_ci else 9268c2ecf20Sopenharmony_ci wildcard_ssid_tlv->max_ssid_length = 9278c2ecf20Sopenharmony_ci IEEE80211_MAX_SSID_LEN; 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci if (!memcmp(user_scan_in->ssid_list[i].ssid, 9308c2ecf20Sopenharmony_ci "DIRECT-", 7)) 9318c2ecf20Sopenharmony_ci wildcard_ssid_tlv->max_ssid_length = 0xfe; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci memcpy(wildcard_ssid_tlv->ssid, 9348c2ecf20Sopenharmony_ci user_scan_in->ssid_list[i].ssid, ssid_len); 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci tlv_pos += (sizeof(wildcard_ssid_tlv->header) 9378c2ecf20Sopenharmony_ci + le16_to_cpu(wildcard_ssid_tlv->header.len)); 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, 9408c2ecf20Sopenharmony_ci "info: scan: ssid[%d]: %s, %d\n", 9418c2ecf20Sopenharmony_ci i, wildcard_ssid_tlv->ssid, 9428c2ecf20Sopenharmony_ci wildcard_ssid_tlv->max_ssid_length); 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci /* Empty wildcard ssid with a maxlen will match many or 9458c2ecf20Sopenharmony_ci potentially all SSIDs (maxlen == 32), therefore do 9468c2ecf20Sopenharmony_ci not treat the scan as 9478c2ecf20Sopenharmony_ci filtered. */ 9488c2ecf20Sopenharmony_ci if (!ssid_len && wildcard_ssid_tlv->max_ssid_length) 9498c2ecf20Sopenharmony_ci ssid_filter = false; 9508c2ecf20Sopenharmony_ci } 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci /* 9538c2ecf20Sopenharmony_ci * The default number of channels sent in the command is low to 9548c2ecf20Sopenharmony_ci * ensure the response buffer from the firmware does not 9558c2ecf20Sopenharmony_ci * truncate scan results. That is not an issue with an SSID 9568c2ecf20Sopenharmony_ci * or BSSID filter applied to the scan results in the firmware. 9578c2ecf20Sopenharmony_ci */ 9588c2ecf20Sopenharmony_ci memcpy(tmpaddr, scan_cfg_out->specific_bssid, ETH_ALEN); 9598c2ecf20Sopenharmony_ci if ((i && ssid_filter) || 9608c2ecf20Sopenharmony_ci !is_zero_ether_addr(tmpaddr)) 9618c2ecf20Sopenharmony_ci *filtered_scan = true; 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci if (user_scan_in->scan_chan_gap) { 9648c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, 9658c2ecf20Sopenharmony_ci "info: scan: channel gap = %d\n", 9668c2ecf20Sopenharmony_ci user_scan_in->scan_chan_gap); 9678c2ecf20Sopenharmony_ci *max_chan_per_scan = 9688c2ecf20Sopenharmony_ci MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci chan_gap_tlv = (void *)tlv_pos; 9718c2ecf20Sopenharmony_ci chan_gap_tlv->header.type = 9728c2ecf20Sopenharmony_ci cpu_to_le16(TLV_TYPE_SCAN_CHANNEL_GAP); 9738c2ecf20Sopenharmony_ci chan_gap_tlv->header.len = 9748c2ecf20Sopenharmony_ci cpu_to_le16(sizeof(chan_gap_tlv->chan_gap)); 9758c2ecf20Sopenharmony_ci chan_gap_tlv->chan_gap = 9768c2ecf20Sopenharmony_ci cpu_to_le16((user_scan_in->scan_chan_gap)); 9778c2ecf20Sopenharmony_ci tlv_pos += 9788c2ecf20Sopenharmony_ci sizeof(struct mwifiex_ie_types_scan_chan_gap); 9798c2ecf20Sopenharmony_ci } 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci if (!ether_addr_equal(user_scan_in->random_mac, zero_mac)) { 9828c2ecf20Sopenharmony_ci random_mac_tlv = (void *)tlv_pos; 9838c2ecf20Sopenharmony_ci random_mac_tlv->header.type = 9848c2ecf20Sopenharmony_ci cpu_to_le16(TLV_TYPE_RANDOM_MAC); 9858c2ecf20Sopenharmony_ci random_mac_tlv->header.len = 9868c2ecf20Sopenharmony_ci cpu_to_le16(sizeof(random_mac_tlv->mac)); 9878c2ecf20Sopenharmony_ci ether_addr_copy(random_mac_tlv->mac, 9888c2ecf20Sopenharmony_ci user_scan_in->random_mac); 9898c2ecf20Sopenharmony_ci tlv_pos += 9908c2ecf20Sopenharmony_ci sizeof(struct mwifiex_ie_types_random_mac); 9918c2ecf20Sopenharmony_ci } 9928c2ecf20Sopenharmony_ci } else { 9938c2ecf20Sopenharmony_ci scan_cfg_out->bss_mode = (u8) adapter->scan_mode; 9948c2ecf20Sopenharmony_ci num_probes = adapter->scan_probes; 9958c2ecf20Sopenharmony_ci } 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci /* 9988c2ecf20Sopenharmony_ci * If a specific BSSID or SSID is used, the number of channels in the 9998c2ecf20Sopenharmony_ci * scan command will be increased to the absolute maximum. 10008c2ecf20Sopenharmony_ci */ 10018c2ecf20Sopenharmony_ci if (*filtered_scan) { 10028c2ecf20Sopenharmony_ci *max_chan_per_scan = MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN; 10038c2ecf20Sopenharmony_ci } else { 10048c2ecf20Sopenharmony_ci if (!priv->media_connected) 10058c2ecf20Sopenharmony_ci *max_chan_per_scan = MWIFIEX_DEF_CHANNELS_PER_SCAN_CMD; 10068c2ecf20Sopenharmony_ci else 10078c2ecf20Sopenharmony_ci *max_chan_per_scan = 10088c2ecf20Sopenharmony_ci MWIFIEX_DEF_CHANNELS_PER_SCAN_CMD / 2; 10098c2ecf20Sopenharmony_ci } 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci if (adapter->ext_scan) { 10128c2ecf20Sopenharmony_ci bss_mode = (struct mwifiex_ie_types_bss_mode *)tlv_pos; 10138c2ecf20Sopenharmony_ci bss_mode->header.type = cpu_to_le16(TLV_TYPE_BSS_MODE); 10148c2ecf20Sopenharmony_ci bss_mode->header.len = cpu_to_le16(sizeof(bss_mode->bss_mode)); 10158c2ecf20Sopenharmony_ci bss_mode->bss_mode = scan_cfg_out->bss_mode; 10168c2ecf20Sopenharmony_ci tlv_pos += sizeof(bss_mode->header) + 10178c2ecf20Sopenharmony_ci le16_to_cpu(bss_mode->header.len); 10188c2ecf20Sopenharmony_ci } 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci /* If the input config or adapter has the number of Probes set, 10218c2ecf20Sopenharmony_ci add tlv */ 10228c2ecf20Sopenharmony_ci if (num_probes) { 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, 10258c2ecf20Sopenharmony_ci "info: scan: num_probes = %d\n", 10268c2ecf20Sopenharmony_ci num_probes); 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci num_probes_tlv = (struct mwifiex_ie_types_num_probes *) tlv_pos; 10298c2ecf20Sopenharmony_ci num_probes_tlv->header.type = cpu_to_le16(TLV_TYPE_NUMPROBES); 10308c2ecf20Sopenharmony_ci num_probes_tlv->header.len = 10318c2ecf20Sopenharmony_ci cpu_to_le16(sizeof(num_probes_tlv->num_probes)); 10328c2ecf20Sopenharmony_ci num_probes_tlv->num_probes = cpu_to_le16((u16) num_probes); 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci tlv_pos += sizeof(num_probes_tlv->header) + 10358c2ecf20Sopenharmony_ci le16_to_cpu(num_probes_tlv->header.len); 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci } 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info) && 10408c2ecf20Sopenharmony_ci (priv->adapter->config_bands & BAND_GN || 10418c2ecf20Sopenharmony_ci priv->adapter->config_bands & BAND_AN)) { 10428c2ecf20Sopenharmony_ci ht_cap = (struct mwifiex_ie_types_htcap *) tlv_pos; 10438c2ecf20Sopenharmony_ci memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap)); 10448c2ecf20Sopenharmony_ci ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY); 10458c2ecf20Sopenharmony_ci ht_cap->header.len = 10468c2ecf20Sopenharmony_ci cpu_to_le16(sizeof(struct ieee80211_ht_cap)); 10478c2ecf20Sopenharmony_ci radio_type = 10488c2ecf20Sopenharmony_ci mwifiex_band_to_radio_type(priv->adapter->config_bands); 10498c2ecf20Sopenharmony_ci mwifiex_fill_cap_info(priv, radio_type, &ht_cap->ht_cap); 10508c2ecf20Sopenharmony_ci tlv_pos += sizeof(struct mwifiex_ie_types_htcap); 10518c2ecf20Sopenharmony_ci } 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci /* Append vendor specific IE TLV */ 10548c2ecf20Sopenharmony_ci mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_SCAN, &tlv_pos); 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci /* 10578c2ecf20Sopenharmony_ci * Set the output for the channel TLV to the address in the tlv buffer 10588c2ecf20Sopenharmony_ci * past any TLVs that were added in this function (SSID, num_probes). 10598c2ecf20Sopenharmony_ci * Channel TLVs will be added past this for each scan command, 10608c2ecf20Sopenharmony_ci * preserving the TLVs that were previously added. 10618c2ecf20Sopenharmony_ci */ 10628c2ecf20Sopenharmony_ci *chan_list_out = 10638c2ecf20Sopenharmony_ci (struct mwifiex_ie_types_chan_list_param_set *) tlv_pos; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci if (user_scan_in && user_scan_in->chan_list[0].chan_number) { 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, 10688c2ecf20Sopenharmony_ci "info: Scan: Using supplied channel list\n"); 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci for (chan_idx = 0; 10718c2ecf20Sopenharmony_ci chan_idx < MWIFIEX_USER_SCAN_CHAN_MAX && 10728c2ecf20Sopenharmony_ci user_scan_in->chan_list[chan_idx].chan_number; 10738c2ecf20Sopenharmony_ci chan_idx++) { 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci channel = user_scan_in->chan_list[chan_idx].chan_number; 10768c2ecf20Sopenharmony_ci scan_chan_list[chan_idx].chan_number = channel; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci radio_type = 10798c2ecf20Sopenharmony_ci user_scan_in->chan_list[chan_idx].radio_type; 10808c2ecf20Sopenharmony_ci scan_chan_list[chan_idx].radio_type = radio_type; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci scan_type = user_scan_in->chan_list[chan_idx].scan_type; 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE) 10858c2ecf20Sopenharmony_ci scan_chan_list[chan_idx].chan_scan_mode_bitmap 10868c2ecf20Sopenharmony_ci |= (MWIFIEX_PASSIVE_SCAN | 10878c2ecf20Sopenharmony_ci MWIFIEX_HIDDEN_SSID_REPORT); 10888c2ecf20Sopenharmony_ci else 10898c2ecf20Sopenharmony_ci scan_chan_list[chan_idx].chan_scan_mode_bitmap 10908c2ecf20Sopenharmony_ci &= ~MWIFIEX_PASSIVE_SCAN; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci scan_chan_list[chan_idx].chan_scan_mode_bitmap 10938c2ecf20Sopenharmony_ci |= MWIFIEX_DISABLE_CHAN_FILT; 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci if (user_scan_in->chan_list[chan_idx].scan_time) { 10968c2ecf20Sopenharmony_ci scan_dur = (u16) user_scan_in-> 10978c2ecf20Sopenharmony_ci chan_list[chan_idx].scan_time; 10988c2ecf20Sopenharmony_ci } else { 10998c2ecf20Sopenharmony_ci if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE) 11008c2ecf20Sopenharmony_ci scan_dur = adapter->passive_scan_time; 11018c2ecf20Sopenharmony_ci else if (*filtered_scan) 11028c2ecf20Sopenharmony_ci scan_dur = adapter->specific_scan_time; 11038c2ecf20Sopenharmony_ci else 11048c2ecf20Sopenharmony_ci scan_dur = adapter->active_scan_time; 11058c2ecf20Sopenharmony_ci } 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci scan_chan_list[chan_idx].min_scan_time = 11088c2ecf20Sopenharmony_ci cpu_to_le16(scan_dur); 11098c2ecf20Sopenharmony_ci scan_chan_list[chan_idx].max_scan_time = 11108c2ecf20Sopenharmony_ci cpu_to_le16(scan_dur); 11118c2ecf20Sopenharmony_ci } 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci /* Check if we are only scanning the current channel */ 11148c2ecf20Sopenharmony_ci if ((chan_idx == 1) && 11158c2ecf20Sopenharmony_ci (user_scan_in->chan_list[0].chan_number == 11168c2ecf20Sopenharmony_ci priv->curr_bss_params.bss_descriptor.channel)) { 11178c2ecf20Sopenharmony_ci *scan_current_only = true; 11188c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, 11198c2ecf20Sopenharmony_ci "info: Scan: Scanning current channel only\n"); 11208c2ecf20Sopenharmony_ci } 11218c2ecf20Sopenharmony_ci } else { 11228c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, 11238c2ecf20Sopenharmony_ci "info: Scan: Creating full region channel list\n"); 11248c2ecf20Sopenharmony_ci mwifiex_scan_create_channel_list(priv, user_scan_in, 11258c2ecf20Sopenharmony_ci scan_chan_list, 11268c2ecf20Sopenharmony_ci *filtered_scan); 11278c2ecf20Sopenharmony_ci } 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci} 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci/* 11328c2ecf20Sopenharmony_ci * This function inspects the scan response buffer for pointers to 11338c2ecf20Sopenharmony_ci * expected TLVs. 11348c2ecf20Sopenharmony_ci * 11358c2ecf20Sopenharmony_ci * TLVs can be included at the end of the scan response BSS information. 11368c2ecf20Sopenharmony_ci * 11378c2ecf20Sopenharmony_ci * Data in the buffer is parsed pointers to TLVs that can potentially 11388c2ecf20Sopenharmony_ci * be passed back in the response. 11398c2ecf20Sopenharmony_ci */ 11408c2ecf20Sopenharmony_cistatic void 11418c2ecf20Sopenharmony_cimwifiex_ret_802_11_scan_get_tlv_ptrs(struct mwifiex_adapter *adapter, 11428c2ecf20Sopenharmony_ci struct mwifiex_ie_types_data *tlv, 11438c2ecf20Sopenharmony_ci u32 tlv_buf_size, u32 req_tlv_type, 11448c2ecf20Sopenharmony_ci struct mwifiex_ie_types_data **tlv_data) 11458c2ecf20Sopenharmony_ci{ 11468c2ecf20Sopenharmony_ci struct mwifiex_ie_types_data *current_tlv; 11478c2ecf20Sopenharmony_ci u32 tlv_buf_left; 11488c2ecf20Sopenharmony_ci u32 tlv_type; 11498c2ecf20Sopenharmony_ci u32 tlv_len; 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci current_tlv = tlv; 11528c2ecf20Sopenharmony_ci tlv_buf_left = tlv_buf_size; 11538c2ecf20Sopenharmony_ci *tlv_data = NULL; 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, 11568c2ecf20Sopenharmony_ci "info: SCAN_RESP: tlv_buf_size = %d\n", 11578c2ecf20Sopenharmony_ci tlv_buf_size); 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci while (tlv_buf_left >= sizeof(struct mwifiex_ie_types_header)) { 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci tlv_type = le16_to_cpu(current_tlv->header.type); 11628c2ecf20Sopenharmony_ci tlv_len = le16_to_cpu(current_tlv->header.len); 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci if (sizeof(tlv->header) + tlv_len > tlv_buf_left) { 11658c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 11668c2ecf20Sopenharmony_ci "SCAN_RESP: TLV buffer corrupt\n"); 11678c2ecf20Sopenharmony_ci break; 11688c2ecf20Sopenharmony_ci } 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci if (req_tlv_type == tlv_type) { 11718c2ecf20Sopenharmony_ci switch (tlv_type) { 11728c2ecf20Sopenharmony_ci case TLV_TYPE_TSFTIMESTAMP: 11738c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, 11748c2ecf20Sopenharmony_ci "info: SCAN_RESP: TSF\t" 11758c2ecf20Sopenharmony_ci "timestamp TLV, len = %d\n", 11768c2ecf20Sopenharmony_ci tlv_len); 11778c2ecf20Sopenharmony_ci *tlv_data = current_tlv; 11788c2ecf20Sopenharmony_ci break; 11798c2ecf20Sopenharmony_ci case TLV_TYPE_CHANNELBANDLIST: 11808c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, 11818c2ecf20Sopenharmony_ci "info: SCAN_RESP: channel\t" 11828c2ecf20Sopenharmony_ci "band list TLV, len = %d\n", 11838c2ecf20Sopenharmony_ci tlv_len); 11848c2ecf20Sopenharmony_ci *tlv_data = current_tlv; 11858c2ecf20Sopenharmony_ci break; 11868c2ecf20Sopenharmony_ci default: 11878c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 11888c2ecf20Sopenharmony_ci "SCAN_RESP: unhandled TLV = %d\n", 11898c2ecf20Sopenharmony_ci tlv_type); 11908c2ecf20Sopenharmony_ci /* Give up, this seems corrupted */ 11918c2ecf20Sopenharmony_ci return; 11928c2ecf20Sopenharmony_ci } 11938c2ecf20Sopenharmony_ci } 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci if (*tlv_data) 11968c2ecf20Sopenharmony_ci break; 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci tlv_buf_left -= (sizeof(tlv->header) + tlv_len); 12008c2ecf20Sopenharmony_ci current_tlv = 12018c2ecf20Sopenharmony_ci (struct mwifiex_ie_types_data *) (current_tlv->data + 12028c2ecf20Sopenharmony_ci tlv_len); 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci } /* while */ 12058c2ecf20Sopenharmony_ci} 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci/* 12088c2ecf20Sopenharmony_ci * This function parses provided beacon buffer and updates 12098c2ecf20Sopenharmony_ci * respective fields in bss descriptor structure. 12108c2ecf20Sopenharmony_ci */ 12118c2ecf20Sopenharmony_ciint mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, 12128c2ecf20Sopenharmony_ci struct mwifiex_bssdescriptor *bss_entry) 12138c2ecf20Sopenharmony_ci{ 12148c2ecf20Sopenharmony_ci int ret = 0; 12158c2ecf20Sopenharmony_ci u8 element_id; 12168c2ecf20Sopenharmony_ci struct ieee_types_fh_param_set *fh_param_set; 12178c2ecf20Sopenharmony_ci struct ieee_types_ds_param_set *ds_param_set; 12188c2ecf20Sopenharmony_ci struct ieee_types_cf_param_set *cf_param_set; 12198c2ecf20Sopenharmony_ci struct ieee_types_ibss_param_set *ibss_param_set; 12208c2ecf20Sopenharmony_ci u8 *current_ptr; 12218c2ecf20Sopenharmony_ci u8 *rate; 12228c2ecf20Sopenharmony_ci u8 element_len; 12238c2ecf20Sopenharmony_ci u16 total_ie_len; 12248c2ecf20Sopenharmony_ci u8 bytes_to_copy; 12258c2ecf20Sopenharmony_ci u8 rate_size; 12268c2ecf20Sopenharmony_ci u8 found_data_rate_ie; 12278c2ecf20Sopenharmony_ci u32 bytes_left; 12288c2ecf20Sopenharmony_ci struct ieee_types_vendor_specific *vendor_ie; 12298c2ecf20Sopenharmony_ci const u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 }; 12308c2ecf20Sopenharmony_ci const u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 }; 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci found_data_rate_ie = false; 12338c2ecf20Sopenharmony_ci rate_size = 0; 12348c2ecf20Sopenharmony_ci current_ptr = bss_entry->beacon_buf; 12358c2ecf20Sopenharmony_ci bytes_left = bss_entry->beacon_buf_size; 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci /* Process variable IE */ 12388c2ecf20Sopenharmony_ci while (bytes_left >= 2) { 12398c2ecf20Sopenharmony_ci element_id = *current_ptr; 12408c2ecf20Sopenharmony_ci element_len = *(current_ptr + 1); 12418c2ecf20Sopenharmony_ci total_ie_len = element_len + sizeof(struct ieee_types_header); 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci if (bytes_left < total_ie_len) { 12448c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 12458c2ecf20Sopenharmony_ci "err: InterpretIE: in processing\t" 12468c2ecf20Sopenharmony_ci "IE, bytes left < IE length\n"); 12478c2ecf20Sopenharmony_ci return -EINVAL; 12488c2ecf20Sopenharmony_ci } 12498c2ecf20Sopenharmony_ci switch (element_id) { 12508c2ecf20Sopenharmony_ci case WLAN_EID_SSID: 12518c2ecf20Sopenharmony_ci if (element_len > IEEE80211_MAX_SSID_LEN) 12528c2ecf20Sopenharmony_ci return -EINVAL; 12538c2ecf20Sopenharmony_ci bss_entry->ssid.ssid_len = element_len; 12548c2ecf20Sopenharmony_ci memcpy(bss_entry->ssid.ssid, (current_ptr + 2), 12558c2ecf20Sopenharmony_ci element_len); 12568c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, 12578c2ecf20Sopenharmony_ci "info: InterpretIE: ssid: %-32s\n", 12588c2ecf20Sopenharmony_ci bss_entry->ssid.ssid); 12598c2ecf20Sopenharmony_ci break; 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci case WLAN_EID_SUPP_RATES: 12628c2ecf20Sopenharmony_ci if (element_len > MWIFIEX_SUPPORTED_RATES) 12638c2ecf20Sopenharmony_ci return -EINVAL; 12648c2ecf20Sopenharmony_ci memcpy(bss_entry->data_rates, current_ptr + 2, 12658c2ecf20Sopenharmony_ci element_len); 12668c2ecf20Sopenharmony_ci memcpy(bss_entry->supported_rates, current_ptr + 2, 12678c2ecf20Sopenharmony_ci element_len); 12688c2ecf20Sopenharmony_ci rate_size = element_len; 12698c2ecf20Sopenharmony_ci found_data_rate_ie = true; 12708c2ecf20Sopenharmony_ci break; 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci case WLAN_EID_FH_PARAMS: 12738c2ecf20Sopenharmony_ci if (total_ie_len < sizeof(*fh_param_set)) 12748c2ecf20Sopenharmony_ci return -EINVAL; 12758c2ecf20Sopenharmony_ci fh_param_set = 12768c2ecf20Sopenharmony_ci (struct ieee_types_fh_param_set *) current_ptr; 12778c2ecf20Sopenharmony_ci memcpy(&bss_entry->phy_param_set.fh_param_set, 12788c2ecf20Sopenharmony_ci fh_param_set, 12798c2ecf20Sopenharmony_ci sizeof(struct ieee_types_fh_param_set)); 12808c2ecf20Sopenharmony_ci break; 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci case WLAN_EID_DS_PARAMS: 12838c2ecf20Sopenharmony_ci if (total_ie_len < sizeof(*ds_param_set)) 12848c2ecf20Sopenharmony_ci return -EINVAL; 12858c2ecf20Sopenharmony_ci ds_param_set = 12868c2ecf20Sopenharmony_ci (struct ieee_types_ds_param_set *) current_ptr; 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci bss_entry->channel = ds_param_set->current_chan; 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci memcpy(&bss_entry->phy_param_set.ds_param_set, 12918c2ecf20Sopenharmony_ci ds_param_set, 12928c2ecf20Sopenharmony_ci sizeof(struct ieee_types_ds_param_set)); 12938c2ecf20Sopenharmony_ci break; 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci case WLAN_EID_CF_PARAMS: 12968c2ecf20Sopenharmony_ci if (total_ie_len < sizeof(*cf_param_set)) 12978c2ecf20Sopenharmony_ci return -EINVAL; 12988c2ecf20Sopenharmony_ci cf_param_set = 12998c2ecf20Sopenharmony_ci (struct ieee_types_cf_param_set *) current_ptr; 13008c2ecf20Sopenharmony_ci memcpy(&bss_entry->ss_param_set.cf_param_set, 13018c2ecf20Sopenharmony_ci cf_param_set, 13028c2ecf20Sopenharmony_ci sizeof(struct ieee_types_cf_param_set)); 13038c2ecf20Sopenharmony_ci break; 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci case WLAN_EID_IBSS_PARAMS: 13068c2ecf20Sopenharmony_ci if (total_ie_len < sizeof(*ibss_param_set)) 13078c2ecf20Sopenharmony_ci return -EINVAL; 13088c2ecf20Sopenharmony_ci ibss_param_set = 13098c2ecf20Sopenharmony_ci (struct ieee_types_ibss_param_set *) 13108c2ecf20Sopenharmony_ci current_ptr; 13118c2ecf20Sopenharmony_ci memcpy(&bss_entry->ss_param_set.ibss_param_set, 13128c2ecf20Sopenharmony_ci ibss_param_set, 13138c2ecf20Sopenharmony_ci sizeof(struct ieee_types_ibss_param_set)); 13148c2ecf20Sopenharmony_ci break; 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci case WLAN_EID_ERP_INFO: 13178c2ecf20Sopenharmony_ci if (!element_len) 13188c2ecf20Sopenharmony_ci return -EINVAL; 13198c2ecf20Sopenharmony_ci bss_entry->erp_flags = *(current_ptr + 2); 13208c2ecf20Sopenharmony_ci break; 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci case WLAN_EID_PWR_CONSTRAINT: 13238c2ecf20Sopenharmony_ci if (!element_len) 13248c2ecf20Sopenharmony_ci return -EINVAL; 13258c2ecf20Sopenharmony_ci bss_entry->local_constraint = *(current_ptr + 2); 13268c2ecf20Sopenharmony_ci bss_entry->sensed_11h = true; 13278c2ecf20Sopenharmony_ci break; 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci case WLAN_EID_CHANNEL_SWITCH: 13308c2ecf20Sopenharmony_ci bss_entry->chan_sw_ie_present = true; 13318c2ecf20Sopenharmony_ci fallthrough; 13328c2ecf20Sopenharmony_ci case WLAN_EID_PWR_CAPABILITY: 13338c2ecf20Sopenharmony_ci case WLAN_EID_TPC_REPORT: 13348c2ecf20Sopenharmony_ci case WLAN_EID_QUIET: 13358c2ecf20Sopenharmony_ci bss_entry->sensed_11h = true; 13368c2ecf20Sopenharmony_ci break; 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci case WLAN_EID_EXT_SUPP_RATES: 13398c2ecf20Sopenharmony_ci /* 13408c2ecf20Sopenharmony_ci * Only process extended supported rate 13418c2ecf20Sopenharmony_ci * if data rate is already found. 13428c2ecf20Sopenharmony_ci * Data rate IE should come before 13438c2ecf20Sopenharmony_ci * extended supported rate IE 13448c2ecf20Sopenharmony_ci */ 13458c2ecf20Sopenharmony_ci if (found_data_rate_ie) { 13468c2ecf20Sopenharmony_ci if ((element_len + rate_size) > 13478c2ecf20Sopenharmony_ci MWIFIEX_SUPPORTED_RATES) 13488c2ecf20Sopenharmony_ci bytes_to_copy = 13498c2ecf20Sopenharmony_ci (MWIFIEX_SUPPORTED_RATES - 13508c2ecf20Sopenharmony_ci rate_size); 13518c2ecf20Sopenharmony_ci else 13528c2ecf20Sopenharmony_ci bytes_to_copy = element_len; 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci rate = (u8 *) bss_entry->data_rates; 13558c2ecf20Sopenharmony_ci rate += rate_size; 13568c2ecf20Sopenharmony_ci memcpy(rate, current_ptr + 2, bytes_to_copy); 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci rate = (u8 *) bss_entry->supported_rates; 13598c2ecf20Sopenharmony_ci rate += rate_size; 13608c2ecf20Sopenharmony_ci memcpy(rate, current_ptr + 2, bytes_to_copy); 13618c2ecf20Sopenharmony_ci } 13628c2ecf20Sopenharmony_ci break; 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci case WLAN_EID_VENDOR_SPECIFIC: 13658c2ecf20Sopenharmony_ci vendor_ie = (struct ieee_types_vendor_specific *) 13668c2ecf20Sopenharmony_ci current_ptr; 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci /* 802.11 requires at least 3-byte OUI. */ 13698c2ecf20Sopenharmony_ci if (element_len < sizeof(vendor_ie->vend_hdr.oui.oui)) 13708c2ecf20Sopenharmony_ci return -EINVAL; 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci /* Not long enough for a match? Skip it. */ 13738c2ecf20Sopenharmony_ci if (element_len < sizeof(wpa_oui)) 13748c2ecf20Sopenharmony_ci break; 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci if (!memcmp(&vendor_ie->vend_hdr.oui, wpa_oui, 13778c2ecf20Sopenharmony_ci sizeof(wpa_oui))) { 13788c2ecf20Sopenharmony_ci bss_entry->bcn_wpa_ie = 13798c2ecf20Sopenharmony_ci (struct ieee_types_vendor_specific *) 13808c2ecf20Sopenharmony_ci current_ptr; 13818c2ecf20Sopenharmony_ci bss_entry->wpa_offset = (u16) 13828c2ecf20Sopenharmony_ci (current_ptr - bss_entry->beacon_buf); 13838c2ecf20Sopenharmony_ci } else if (!memcmp(&vendor_ie->vend_hdr.oui, wmm_oui, 13848c2ecf20Sopenharmony_ci sizeof(wmm_oui))) { 13858c2ecf20Sopenharmony_ci if (total_ie_len == 13868c2ecf20Sopenharmony_ci sizeof(struct ieee_types_wmm_parameter) || 13878c2ecf20Sopenharmony_ci total_ie_len == 13888c2ecf20Sopenharmony_ci sizeof(struct ieee_types_wmm_info)) 13898c2ecf20Sopenharmony_ci /* 13908c2ecf20Sopenharmony_ci * Only accept and copy the WMM IE if 13918c2ecf20Sopenharmony_ci * it matches the size expected for the 13928c2ecf20Sopenharmony_ci * WMM Info IE or the WMM Parameter IE. 13938c2ecf20Sopenharmony_ci */ 13948c2ecf20Sopenharmony_ci memcpy((u8 *) &bss_entry->wmm_ie, 13958c2ecf20Sopenharmony_ci current_ptr, total_ie_len); 13968c2ecf20Sopenharmony_ci } 13978c2ecf20Sopenharmony_ci break; 13988c2ecf20Sopenharmony_ci case WLAN_EID_RSN: 13998c2ecf20Sopenharmony_ci bss_entry->bcn_rsn_ie = 14008c2ecf20Sopenharmony_ci (struct ieee_types_generic *) current_ptr; 14018c2ecf20Sopenharmony_ci bss_entry->rsn_offset = (u16) (current_ptr - 14028c2ecf20Sopenharmony_ci bss_entry->beacon_buf); 14038c2ecf20Sopenharmony_ci break; 14048c2ecf20Sopenharmony_ci case WLAN_EID_BSS_AC_ACCESS_DELAY: 14058c2ecf20Sopenharmony_ci bss_entry->bcn_wapi_ie = 14068c2ecf20Sopenharmony_ci (struct ieee_types_generic *) current_ptr; 14078c2ecf20Sopenharmony_ci bss_entry->wapi_offset = (u16) (current_ptr - 14088c2ecf20Sopenharmony_ci bss_entry->beacon_buf); 14098c2ecf20Sopenharmony_ci break; 14108c2ecf20Sopenharmony_ci case WLAN_EID_HT_CAPABILITY: 14118c2ecf20Sopenharmony_ci bss_entry->bcn_ht_cap = (struct ieee80211_ht_cap *) 14128c2ecf20Sopenharmony_ci (current_ptr + 14138c2ecf20Sopenharmony_ci sizeof(struct ieee_types_header)); 14148c2ecf20Sopenharmony_ci bss_entry->ht_cap_offset = (u16) (current_ptr + 14158c2ecf20Sopenharmony_ci sizeof(struct ieee_types_header) - 14168c2ecf20Sopenharmony_ci bss_entry->beacon_buf); 14178c2ecf20Sopenharmony_ci break; 14188c2ecf20Sopenharmony_ci case WLAN_EID_HT_OPERATION: 14198c2ecf20Sopenharmony_ci bss_entry->bcn_ht_oper = 14208c2ecf20Sopenharmony_ci (struct ieee80211_ht_operation *)(current_ptr + 14218c2ecf20Sopenharmony_ci sizeof(struct ieee_types_header)); 14228c2ecf20Sopenharmony_ci bss_entry->ht_info_offset = (u16) (current_ptr + 14238c2ecf20Sopenharmony_ci sizeof(struct ieee_types_header) - 14248c2ecf20Sopenharmony_ci bss_entry->beacon_buf); 14258c2ecf20Sopenharmony_ci break; 14268c2ecf20Sopenharmony_ci case WLAN_EID_VHT_CAPABILITY: 14278c2ecf20Sopenharmony_ci bss_entry->disable_11ac = false; 14288c2ecf20Sopenharmony_ci bss_entry->bcn_vht_cap = 14298c2ecf20Sopenharmony_ci (void *)(current_ptr + 14308c2ecf20Sopenharmony_ci sizeof(struct ieee_types_header)); 14318c2ecf20Sopenharmony_ci bss_entry->vht_cap_offset = 14328c2ecf20Sopenharmony_ci (u16)((u8 *)bss_entry->bcn_vht_cap - 14338c2ecf20Sopenharmony_ci bss_entry->beacon_buf); 14348c2ecf20Sopenharmony_ci break; 14358c2ecf20Sopenharmony_ci case WLAN_EID_VHT_OPERATION: 14368c2ecf20Sopenharmony_ci bss_entry->bcn_vht_oper = 14378c2ecf20Sopenharmony_ci (void *)(current_ptr + 14388c2ecf20Sopenharmony_ci sizeof(struct ieee_types_header)); 14398c2ecf20Sopenharmony_ci bss_entry->vht_info_offset = 14408c2ecf20Sopenharmony_ci (u16)((u8 *)bss_entry->bcn_vht_oper - 14418c2ecf20Sopenharmony_ci bss_entry->beacon_buf); 14428c2ecf20Sopenharmony_ci break; 14438c2ecf20Sopenharmony_ci case WLAN_EID_BSS_COEX_2040: 14448c2ecf20Sopenharmony_ci bss_entry->bcn_bss_co_2040 = current_ptr; 14458c2ecf20Sopenharmony_ci bss_entry->bss_co_2040_offset = 14468c2ecf20Sopenharmony_ci (u16) (current_ptr - bss_entry->beacon_buf); 14478c2ecf20Sopenharmony_ci break; 14488c2ecf20Sopenharmony_ci case WLAN_EID_EXT_CAPABILITY: 14498c2ecf20Sopenharmony_ci bss_entry->bcn_ext_cap = current_ptr; 14508c2ecf20Sopenharmony_ci bss_entry->ext_cap_offset = 14518c2ecf20Sopenharmony_ci (u16) (current_ptr - bss_entry->beacon_buf); 14528c2ecf20Sopenharmony_ci break; 14538c2ecf20Sopenharmony_ci case WLAN_EID_OPMODE_NOTIF: 14548c2ecf20Sopenharmony_ci bss_entry->oper_mode = (void *)current_ptr; 14558c2ecf20Sopenharmony_ci bss_entry->oper_mode_offset = 14568c2ecf20Sopenharmony_ci (u16)((u8 *)bss_entry->oper_mode - 14578c2ecf20Sopenharmony_ci bss_entry->beacon_buf); 14588c2ecf20Sopenharmony_ci break; 14598c2ecf20Sopenharmony_ci default: 14608c2ecf20Sopenharmony_ci break; 14618c2ecf20Sopenharmony_ci } 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci current_ptr += total_ie_len; 14648c2ecf20Sopenharmony_ci bytes_left -= total_ie_len; 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci } /* while (bytes_left > 2) */ 14678c2ecf20Sopenharmony_ci return ret; 14688c2ecf20Sopenharmony_ci} 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci/* 14718c2ecf20Sopenharmony_ci * This function converts radio type scan parameter to a band configuration 14728c2ecf20Sopenharmony_ci * to be used in join command. 14738c2ecf20Sopenharmony_ci */ 14748c2ecf20Sopenharmony_cistatic u8 14758c2ecf20Sopenharmony_cimwifiex_radio_type_to_band(u8 radio_type) 14768c2ecf20Sopenharmony_ci{ 14778c2ecf20Sopenharmony_ci switch (radio_type) { 14788c2ecf20Sopenharmony_ci case HostCmd_SCAN_RADIO_TYPE_A: 14798c2ecf20Sopenharmony_ci return BAND_A; 14808c2ecf20Sopenharmony_ci case HostCmd_SCAN_RADIO_TYPE_BG: 14818c2ecf20Sopenharmony_ci default: 14828c2ecf20Sopenharmony_ci return BAND_G; 14838c2ecf20Sopenharmony_ci } 14848c2ecf20Sopenharmony_ci} 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci/* 14878c2ecf20Sopenharmony_ci * This is an internal function used to start a scan based on an input 14888c2ecf20Sopenharmony_ci * configuration. 14898c2ecf20Sopenharmony_ci * 14908c2ecf20Sopenharmony_ci * This uses the input user scan configuration information when provided in 14918c2ecf20Sopenharmony_ci * order to send the appropriate scan commands to firmware to populate or 14928c2ecf20Sopenharmony_ci * update the internal driver scan table. 14938c2ecf20Sopenharmony_ci */ 14948c2ecf20Sopenharmony_ciint mwifiex_scan_networks(struct mwifiex_private *priv, 14958c2ecf20Sopenharmony_ci const struct mwifiex_user_scan_cfg *user_scan_in) 14968c2ecf20Sopenharmony_ci{ 14978c2ecf20Sopenharmony_ci int ret; 14988c2ecf20Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 14998c2ecf20Sopenharmony_ci struct cmd_ctrl_node *cmd_node; 15008c2ecf20Sopenharmony_ci union mwifiex_scan_cmd_config_tlv *scan_cfg_out; 15018c2ecf20Sopenharmony_ci struct mwifiex_ie_types_chan_list_param_set *chan_list_out; 15028c2ecf20Sopenharmony_ci struct mwifiex_chan_scan_param_set *scan_chan_list; 15038c2ecf20Sopenharmony_ci u8 filtered_scan; 15048c2ecf20Sopenharmony_ci u8 scan_current_chan_only; 15058c2ecf20Sopenharmony_ci u8 max_chan_per_scan; 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci if (adapter->scan_processing) { 15088c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, WARN, 15098c2ecf20Sopenharmony_ci "cmd: Scan already in process...\n"); 15108c2ecf20Sopenharmony_ci return -EBUSY; 15118c2ecf20Sopenharmony_ci } 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci if (priv->scan_block) { 15148c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, WARN, 15158c2ecf20Sopenharmony_ci "cmd: Scan is blocked during association...\n"); 15168c2ecf20Sopenharmony_ci return -EBUSY; 15178c2ecf20Sopenharmony_ci } 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci if (test_bit(MWIFIEX_SURPRISE_REMOVED, &adapter->work_flags) || 15208c2ecf20Sopenharmony_ci test_bit(MWIFIEX_IS_CMD_TIMEDOUT, &adapter->work_flags)) { 15218c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 15228c2ecf20Sopenharmony_ci "Ignore scan. Card removed or firmware in bad state\n"); 15238c2ecf20Sopenharmony_ci return -EFAULT; 15248c2ecf20Sopenharmony_ci } 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci spin_lock_bh(&adapter->mwifiex_cmd_lock); 15278c2ecf20Sopenharmony_ci adapter->scan_processing = true; 15288c2ecf20Sopenharmony_ci spin_unlock_bh(&adapter->mwifiex_cmd_lock); 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci scan_cfg_out = kzalloc(sizeof(union mwifiex_scan_cmd_config_tlv), 15318c2ecf20Sopenharmony_ci GFP_KERNEL); 15328c2ecf20Sopenharmony_ci if (!scan_cfg_out) { 15338c2ecf20Sopenharmony_ci ret = -ENOMEM; 15348c2ecf20Sopenharmony_ci goto done; 15358c2ecf20Sopenharmony_ci } 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci scan_chan_list = kcalloc(MWIFIEX_USER_SCAN_CHAN_MAX, 15388c2ecf20Sopenharmony_ci sizeof(struct mwifiex_chan_scan_param_set), 15398c2ecf20Sopenharmony_ci GFP_KERNEL); 15408c2ecf20Sopenharmony_ci if (!scan_chan_list) { 15418c2ecf20Sopenharmony_ci kfree(scan_cfg_out); 15428c2ecf20Sopenharmony_ci ret = -ENOMEM; 15438c2ecf20Sopenharmony_ci goto done; 15448c2ecf20Sopenharmony_ci } 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci mwifiex_config_scan(priv, user_scan_in, &scan_cfg_out->config, 15478c2ecf20Sopenharmony_ci &chan_list_out, scan_chan_list, &max_chan_per_scan, 15488c2ecf20Sopenharmony_ci &filtered_scan, &scan_current_chan_only); 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci ret = mwifiex_scan_channel_list(priv, max_chan_per_scan, filtered_scan, 15518c2ecf20Sopenharmony_ci &scan_cfg_out->config, chan_list_out, 15528c2ecf20Sopenharmony_ci scan_chan_list); 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci /* Get scan command from scan_pending_q and put to cmd_pending_q */ 15558c2ecf20Sopenharmony_ci if (!ret) { 15568c2ecf20Sopenharmony_ci spin_lock_bh(&adapter->scan_pending_q_lock); 15578c2ecf20Sopenharmony_ci if (!list_empty(&adapter->scan_pending_q)) { 15588c2ecf20Sopenharmony_ci cmd_node = list_first_entry(&adapter->scan_pending_q, 15598c2ecf20Sopenharmony_ci struct cmd_ctrl_node, list); 15608c2ecf20Sopenharmony_ci list_del(&cmd_node->list); 15618c2ecf20Sopenharmony_ci spin_unlock_bh(&adapter->scan_pending_q_lock); 15628c2ecf20Sopenharmony_ci mwifiex_insert_cmd_to_pending_q(adapter, cmd_node); 15638c2ecf20Sopenharmony_ci queue_work(adapter->workqueue, &adapter->main_work); 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci /* Perform internal scan synchronously */ 15668c2ecf20Sopenharmony_ci if (!priv->scan_request) { 15678c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, 15688c2ecf20Sopenharmony_ci "wait internal scan\n"); 15698c2ecf20Sopenharmony_ci mwifiex_wait_queue_complete(adapter, cmd_node); 15708c2ecf20Sopenharmony_ci } 15718c2ecf20Sopenharmony_ci } else { 15728c2ecf20Sopenharmony_ci spin_unlock_bh(&adapter->scan_pending_q_lock); 15738c2ecf20Sopenharmony_ci } 15748c2ecf20Sopenharmony_ci } 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci kfree(scan_cfg_out); 15778c2ecf20Sopenharmony_ci kfree(scan_chan_list); 15788c2ecf20Sopenharmony_cidone: 15798c2ecf20Sopenharmony_ci if (ret) { 15808c2ecf20Sopenharmony_ci spin_lock_bh(&adapter->mwifiex_cmd_lock); 15818c2ecf20Sopenharmony_ci adapter->scan_processing = false; 15828c2ecf20Sopenharmony_ci spin_unlock_bh(&adapter->mwifiex_cmd_lock); 15838c2ecf20Sopenharmony_ci } 15848c2ecf20Sopenharmony_ci return ret; 15858c2ecf20Sopenharmony_ci} 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci/* 15888c2ecf20Sopenharmony_ci * This function prepares a scan command to be sent to the firmware. 15898c2ecf20Sopenharmony_ci * 15908c2ecf20Sopenharmony_ci * This uses the scan command configuration sent to the command processing 15918c2ecf20Sopenharmony_ci * module in command preparation stage to configure a scan command structure 15928c2ecf20Sopenharmony_ci * to send to firmware. 15938c2ecf20Sopenharmony_ci * 15948c2ecf20Sopenharmony_ci * The fixed fields specifying the BSS type and BSSID filters as well as a 15958c2ecf20Sopenharmony_ci * variable number/length of TLVs are sent in the command to firmware. 15968c2ecf20Sopenharmony_ci * 15978c2ecf20Sopenharmony_ci * Preparation also includes - 15988c2ecf20Sopenharmony_ci * - Setting command ID, and proper size 15998c2ecf20Sopenharmony_ci * - Ensuring correct endian-ness 16008c2ecf20Sopenharmony_ci */ 16018c2ecf20Sopenharmony_ciint mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd, 16028c2ecf20Sopenharmony_ci struct mwifiex_scan_cmd_config *scan_cfg) 16038c2ecf20Sopenharmony_ci{ 16048c2ecf20Sopenharmony_ci struct host_cmd_ds_802_11_scan *scan_cmd = &cmd->params.scan; 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci /* Set fixed field variables in scan command */ 16078c2ecf20Sopenharmony_ci scan_cmd->bss_mode = scan_cfg->bss_mode; 16088c2ecf20Sopenharmony_ci memcpy(scan_cmd->bssid, scan_cfg->specific_bssid, 16098c2ecf20Sopenharmony_ci sizeof(scan_cmd->bssid)); 16108c2ecf20Sopenharmony_ci memcpy(scan_cmd->tlv_buffer, scan_cfg->tlv_buf, scan_cfg->tlv_buf_len); 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SCAN); 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci /* Size is equal to the sizeof(fixed portions) + the TLV len + header */ 16158c2ecf20Sopenharmony_ci cmd->size = cpu_to_le16((u16) (sizeof(scan_cmd->bss_mode) 16168c2ecf20Sopenharmony_ci + sizeof(scan_cmd->bssid) 16178c2ecf20Sopenharmony_ci + scan_cfg->tlv_buf_len + S_DS_GEN)); 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci return 0; 16208c2ecf20Sopenharmony_ci} 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci/* 16238c2ecf20Sopenharmony_ci * This function checks compatibility of requested network with current 16248c2ecf20Sopenharmony_ci * driver settings. 16258c2ecf20Sopenharmony_ci */ 16268c2ecf20Sopenharmony_ciint mwifiex_check_network_compatibility(struct mwifiex_private *priv, 16278c2ecf20Sopenharmony_ci struct mwifiex_bssdescriptor *bss_desc) 16288c2ecf20Sopenharmony_ci{ 16298c2ecf20Sopenharmony_ci int ret = -1; 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci if (!bss_desc) 16328c2ecf20Sopenharmony_ci return -1; 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ci if ((mwifiex_get_cfp(priv, (u8) bss_desc->bss_band, 16358c2ecf20Sopenharmony_ci (u16) bss_desc->channel, 0))) { 16368c2ecf20Sopenharmony_ci switch (priv->bss_mode) { 16378c2ecf20Sopenharmony_ci case NL80211_IFTYPE_STATION: 16388c2ecf20Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 16398c2ecf20Sopenharmony_ci ret = mwifiex_is_network_compatible(priv, bss_desc, 16408c2ecf20Sopenharmony_ci priv->bss_mode); 16418c2ecf20Sopenharmony_ci if (ret) 16428c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 16438c2ecf20Sopenharmony_ci "Incompatible network settings\n"); 16448c2ecf20Sopenharmony_ci break; 16458c2ecf20Sopenharmony_ci default: 16468c2ecf20Sopenharmony_ci ret = 0; 16478c2ecf20Sopenharmony_ci } 16488c2ecf20Sopenharmony_ci } 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci return ret; 16518c2ecf20Sopenharmony_ci} 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci/* This function checks if SSID string contains all zeroes or length is zero */ 16548c2ecf20Sopenharmony_cistatic bool mwifiex_is_hidden_ssid(struct cfg80211_ssid *ssid) 16558c2ecf20Sopenharmony_ci{ 16568c2ecf20Sopenharmony_ci int idx; 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci for (idx = 0; idx < ssid->ssid_len; idx++) { 16598c2ecf20Sopenharmony_ci if (ssid->ssid[idx]) 16608c2ecf20Sopenharmony_ci return false; 16618c2ecf20Sopenharmony_ci } 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci return true; 16648c2ecf20Sopenharmony_ci} 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci/* This function checks if any hidden SSID found in passive scan channels 16678c2ecf20Sopenharmony_ci * and save those channels for specific SSID active scan 16688c2ecf20Sopenharmony_ci */ 16698c2ecf20Sopenharmony_cistatic int mwifiex_save_hidden_ssid_channels(struct mwifiex_private *priv, 16708c2ecf20Sopenharmony_ci struct cfg80211_bss *bss) 16718c2ecf20Sopenharmony_ci{ 16728c2ecf20Sopenharmony_ci struct mwifiex_bssdescriptor *bss_desc; 16738c2ecf20Sopenharmony_ci int ret; 16748c2ecf20Sopenharmony_ci int chid; 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci /* Allocate and fill new bss descriptor */ 16778c2ecf20Sopenharmony_ci bss_desc = kzalloc(sizeof(*bss_desc), GFP_KERNEL); 16788c2ecf20Sopenharmony_ci if (!bss_desc) 16798c2ecf20Sopenharmony_ci return -ENOMEM; 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci ret = mwifiex_fill_new_bss_desc(priv, bss, bss_desc); 16828c2ecf20Sopenharmony_ci if (ret) 16838c2ecf20Sopenharmony_ci goto done; 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci if (mwifiex_is_hidden_ssid(&bss_desc->ssid)) { 16868c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, "found hidden SSID\n"); 16878c2ecf20Sopenharmony_ci for (chid = 0 ; chid < MWIFIEX_USER_SCAN_CHAN_MAX; chid++) { 16888c2ecf20Sopenharmony_ci if (priv->hidden_chan[chid].chan_number == 16898c2ecf20Sopenharmony_ci bss->channel->hw_value) 16908c2ecf20Sopenharmony_ci break; 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci if (!priv->hidden_chan[chid].chan_number) { 16938c2ecf20Sopenharmony_ci priv->hidden_chan[chid].chan_number = 16948c2ecf20Sopenharmony_ci bss->channel->hw_value; 16958c2ecf20Sopenharmony_ci priv->hidden_chan[chid].radio_type = 16968c2ecf20Sopenharmony_ci bss->channel->band; 16978c2ecf20Sopenharmony_ci priv->hidden_chan[chid].scan_type = 16988c2ecf20Sopenharmony_ci MWIFIEX_SCAN_TYPE_ACTIVE; 16998c2ecf20Sopenharmony_ci break; 17008c2ecf20Sopenharmony_ci } 17018c2ecf20Sopenharmony_ci } 17028c2ecf20Sopenharmony_ci } 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_cidone: 17058c2ecf20Sopenharmony_ci /* beacon_ie buffer was allocated in function 17068c2ecf20Sopenharmony_ci * mwifiex_fill_new_bss_desc(). Free it now. 17078c2ecf20Sopenharmony_ci */ 17088c2ecf20Sopenharmony_ci kfree(bss_desc->beacon_buf); 17098c2ecf20Sopenharmony_ci kfree(bss_desc); 17108c2ecf20Sopenharmony_ci return 0; 17118c2ecf20Sopenharmony_ci} 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_cistatic int mwifiex_update_curr_bss_params(struct mwifiex_private *priv, 17148c2ecf20Sopenharmony_ci struct cfg80211_bss *bss) 17158c2ecf20Sopenharmony_ci{ 17168c2ecf20Sopenharmony_ci struct mwifiex_bssdescriptor *bss_desc; 17178c2ecf20Sopenharmony_ci int ret; 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci /* Allocate and fill new bss descriptor */ 17208c2ecf20Sopenharmony_ci bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor), GFP_KERNEL); 17218c2ecf20Sopenharmony_ci if (!bss_desc) 17228c2ecf20Sopenharmony_ci return -ENOMEM; 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci ret = mwifiex_fill_new_bss_desc(priv, bss, bss_desc); 17258c2ecf20Sopenharmony_ci if (ret) 17268c2ecf20Sopenharmony_ci goto done; 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci ret = mwifiex_check_network_compatibility(priv, bss_desc); 17298c2ecf20Sopenharmony_ci if (ret) 17308c2ecf20Sopenharmony_ci goto done; 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci spin_lock_bh(&priv->curr_bcn_buf_lock); 17338c2ecf20Sopenharmony_ci /* Make a copy of current BSSID descriptor */ 17348c2ecf20Sopenharmony_ci memcpy(&priv->curr_bss_params.bss_descriptor, bss_desc, 17358c2ecf20Sopenharmony_ci sizeof(priv->curr_bss_params.bss_descriptor)); 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci /* The contents of beacon_ie will be copied to its own buffer 17388c2ecf20Sopenharmony_ci * in mwifiex_save_curr_bcn() 17398c2ecf20Sopenharmony_ci */ 17408c2ecf20Sopenharmony_ci mwifiex_save_curr_bcn(priv); 17418c2ecf20Sopenharmony_ci spin_unlock_bh(&priv->curr_bcn_buf_lock); 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_cidone: 17448c2ecf20Sopenharmony_ci /* beacon_ie buffer was allocated in function 17458c2ecf20Sopenharmony_ci * mwifiex_fill_new_bss_desc(). Free it now. 17468c2ecf20Sopenharmony_ci */ 17478c2ecf20Sopenharmony_ci kfree(bss_desc->beacon_buf); 17488c2ecf20Sopenharmony_ci kfree(bss_desc); 17498c2ecf20Sopenharmony_ci return 0; 17508c2ecf20Sopenharmony_ci} 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_cistatic int 17538c2ecf20Sopenharmony_cimwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info, 17548c2ecf20Sopenharmony_ci u32 *bytes_left, u64 fw_tsf, u8 *radio_type, 17558c2ecf20Sopenharmony_ci bool ext_scan, s32 rssi_val) 17568c2ecf20Sopenharmony_ci{ 17578c2ecf20Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 17588c2ecf20Sopenharmony_ci struct mwifiex_chan_freq_power *cfp; 17598c2ecf20Sopenharmony_ci struct cfg80211_bss *bss; 17608c2ecf20Sopenharmony_ci u8 bssid[ETH_ALEN]; 17618c2ecf20Sopenharmony_ci s32 rssi; 17628c2ecf20Sopenharmony_ci const u8 *ie_buf; 17638c2ecf20Sopenharmony_ci size_t ie_len; 17648c2ecf20Sopenharmony_ci u16 channel = 0; 17658c2ecf20Sopenharmony_ci u16 beacon_size = 0; 17668c2ecf20Sopenharmony_ci u32 curr_bcn_bytes; 17678c2ecf20Sopenharmony_ci u32 freq; 17688c2ecf20Sopenharmony_ci u16 beacon_period; 17698c2ecf20Sopenharmony_ci u16 cap_info_bitmap; 17708c2ecf20Sopenharmony_ci u8 *current_ptr; 17718c2ecf20Sopenharmony_ci u64 timestamp; 17728c2ecf20Sopenharmony_ci struct mwifiex_fixed_bcn_param *bcn_param; 17738c2ecf20Sopenharmony_ci struct mwifiex_bss_priv *bss_priv; 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci if (*bytes_left >= sizeof(beacon_size)) { 17768c2ecf20Sopenharmony_ci /* Extract & convert beacon size from command buffer */ 17778c2ecf20Sopenharmony_ci beacon_size = get_unaligned_le16((*bss_info)); 17788c2ecf20Sopenharmony_ci *bytes_left -= sizeof(beacon_size); 17798c2ecf20Sopenharmony_ci *bss_info += sizeof(beacon_size); 17808c2ecf20Sopenharmony_ci } 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_ci if (!beacon_size || beacon_size > *bytes_left) { 17838c2ecf20Sopenharmony_ci *bss_info += *bytes_left; 17848c2ecf20Sopenharmony_ci *bytes_left = 0; 17858c2ecf20Sopenharmony_ci return -EFAULT; 17868c2ecf20Sopenharmony_ci } 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci /* Initialize the current working beacon pointer for this BSS 17898c2ecf20Sopenharmony_ci * iteration 17908c2ecf20Sopenharmony_ci */ 17918c2ecf20Sopenharmony_ci current_ptr = *bss_info; 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_ci /* Advance the return beacon pointer past the current beacon */ 17948c2ecf20Sopenharmony_ci *bss_info += beacon_size; 17958c2ecf20Sopenharmony_ci *bytes_left -= beacon_size; 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci curr_bcn_bytes = beacon_size; 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci /* First 5 fields are bssid, RSSI(for legacy scan only), 18008c2ecf20Sopenharmony_ci * time stamp, beacon interval, and capability information 18018c2ecf20Sopenharmony_ci */ 18028c2ecf20Sopenharmony_ci if (curr_bcn_bytes < ETH_ALEN + sizeof(u8) + 18038c2ecf20Sopenharmony_ci sizeof(struct mwifiex_fixed_bcn_param)) { 18048c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 18058c2ecf20Sopenharmony_ci "InterpretIE: not enough bytes left\n"); 18068c2ecf20Sopenharmony_ci return -EFAULT; 18078c2ecf20Sopenharmony_ci } 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_ci memcpy(bssid, current_ptr, ETH_ALEN); 18108c2ecf20Sopenharmony_ci current_ptr += ETH_ALEN; 18118c2ecf20Sopenharmony_ci curr_bcn_bytes -= ETH_ALEN; 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci if (!ext_scan) { 18148c2ecf20Sopenharmony_ci rssi = (s32) *current_ptr; 18158c2ecf20Sopenharmony_ci rssi = (-rssi) * 100; /* Convert dBm to mBm */ 18168c2ecf20Sopenharmony_ci current_ptr += sizeof(u8); 18178c2ecf20Sopenharmony_ci curr_bcn_bytes -= sizeof(u8); 18188c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, 18198c2ecf20Sopenharmony_ci "info: InterpretIE: RSSI=%d\n", rssi); 18208c2ecf20Sopenharmony_ci } else { 18218c2ecf20Sopenharmony_ci rssi = rssi_val; 18228c2ecf20Sopenharmony_ci } 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ci bcn_param = (struct mwifiex_fixed_bcn_param *)current_ptr; 18258c2ecf20Sopenharmony_ci current_ptr += sizeof(*bcn_param); 18268c2ecf20Sopenharmony_ci curr_bcn_bytes -= sizeof(*bcn_param); 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci timestamp = le64_to_cpu(bcn_param->timestamp); 18298c2ecf20Sopenharmony_ci beacon_period = le16_to_cpu(bcn_param->beacon_period); 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_ci cap_info_bitmap = le16_to_cpu(bcn_param->cap_info_bitmap); 18328c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, 18338c2ecf20Sopenharmony_ci "info: InterpretIE: capabilities=0x%X\n", 18348c2ecf20Sopenharmony_ci cap_info_bitmap); 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ci /* Rest of the current buffer are IE's */ 18378c2ecf20Sopenharmony_ci ie_buf = current_ptr; 18388c2ecf20Sopenharmony_ci ie_len = curr_bcn_bytes; 18398c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, 18408c2ecf20Sopenharmony_ci "info: InterpretIE: IELength for this AP = %d\n", 18418c2ecf20Sopenharmony_ci curr_bcn_bytes); 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ci while (curr_bcn_bytes >= sizeof(struct ieee_types_header)) { 18448c2ecf20Sopenharmony_ci u8 element_id, element_len; 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_ci element_id = *current_ptr; 18478c2ecf20Sopenharmony_ci element_len = *(current_ptr + 1); 18488c2ecf20Sopenharmony_ci if (curr_bcn_bytes < element_len + 18498c2ecf20Sopenharmony_ci sizeof(struct ieee_types_header)) { 18508c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 18518c2ecf20Sopenharmony_ci "%s: bytes left < IE length\n", __func__); 18528c2ecf20Sopenharmony_ci return -EFAULT; 18538c2ecf20Sopenharmony_ci } 18548c2ecf20Sopenharmony_ci if (element_id == WLAN_EID_DS_PARAMS) { 18558c2ecf20Sopenharmony_ci channel = *(current_ptr + 18568c2ecf20Sopenharmony_ci sizeof(struct ieee_types_header)); 18578c2ecf20Sopenharmony_ci break; 18588c2ecf20Sopenharmony_ci } 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci current_ptr += element_len + sizeof(struct ieee_types_header); 18618c2ecf20Sopenharmony_ci curr_bcn_bytes -= element_len + 18628c2ecf20Sopenharmony_ci sizeof(struct ieee_types_header); 18638c2ecf20Sopenharmony_ci } 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci if (channel) { 18668c2ecf20Sopenharmony_ci struct ieee80211_channel *chan; 18678c2ecf20Sopenharmony_ci u8 band; 18688c2ecf20Sopenharmony_ci 18698c2ecf20Sopenharmony_ci /* Skip entry if on csa closed channel */ 18708c2ecf20Sopenharmony_ci if (channel == priv->csa_chan) { 18718c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, WARN, 18728c2ecf20Sopenharmony_ci "Dropping entry on csa closed channel\n"); 18738c2ecf20Sopenharmony_ci return 0; 18748c2ecf20Sopenharmony_ci } 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_ci band = BAND_G; 18778c2ecf20Sopenharmony_ci if (radio_type) 18788c2ecf20Sopenharmony_ci band = mwifiex_radio_type_to_band(*radio_type & 18798c2ecf20Sopenharmony_ci (BIT(0) | BIT(1))); 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci cfp = mwifiex_get_cfp(priv, band, channel, 0); 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_ci freq = cfp ? cfp->freq : 0; 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ci chan = ieee80211_get_channel(priv->wdev.wiphy, freq); 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) { 18888c2ecf20Sopenharmony_ci bss = cfg80211_inform_bss(priv->wdev.wiphy, 18898c2ecf20Sopenharmony_ci chan, CFG80211_BSS_FTYPE_UNKNOWN, 18908c2ecf20Sopenharmony_ci bssid, timestamp, 18918c2ecf20Sopenharmony_ci cap_info_bitmap, beacon_period, 18928c2ecf20Sopenharmony_ci ie_buf, ie_len, rssi, GFP_ATOMIC); 18938c2ecf20Sopenharmony_ci if (bss) { 18948c2ecf20Sopenharmony_ci bss_priv = (struct mwifiex_bss_priv *)bss->priv; 18958c2ecf20Sopenharmony_ci bss_priv->band = band; 18968c2ecf20Sopenharmony_ci bss_priv->fw_tsf = fw_tsf; 18978c2ecf20Sopenharmony_ci if (priv->media_connected && 18988c2ecf20Sopenharmony_ci !memcmp(bssid, priv->curr_bss_params. 18998c2ecf20Sopenharmony_ci bss_descriptor.mac_address, 19008c2ecf20Sopenharmony_ci ETH_ALEN)) 19018c2ecf20Sopenharmony_ci mwifiex_update_curr_bss_params(priv, 19028c2ecf20Sopenharmony_ci bss); 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci if ((chan->flags & IEEE80211_CHAN_RADAR) || 19058c2ecf20Sopenharmony_ci (chan->flags & IEEE80211_CHAN_NO_IR)) { 19068c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, 19078c2ecf20Sopenharmony_ci "radar or passive channel %d\n", 19088c2ecf20Sopenharmony_ci channel); 19098c2ecf20Sopenharmony_ci mwifiex_save_hidden_ssid_channels(priv, 19108c2ecf20Sopenharmony_ci bss); 19118c2ecf20Sopenharmony_ci } 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci cfg80211_put_bss(priv->wdev.wiphy, bss); 19148c2ecf20Sopenharmony_ci } 19158c2ecf20Sopenharmony_ci } 19168c2ecf20Sopenharmony_ci } else { 19178c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, WARN, "missing BSS channel IE\n"); 19188c2ecf20Sopenharmony_ci } 19198c2ecf20Sopenharmony_ci 19208c2ecf20Sopenharmony_ci return 0; 19218c2ecf20Sopenharmony_ci} 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_cistatic void mwifiex_complete_scan(struct mwifiex_private *priv) 19248c2ecf20Sopenharmony_ci{ 19258c2ecf20Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci adapter->survey_idx = 0; 19288c2ecf20Sopenharmony_ci if (adapter->curr_cmd->wait_q_enabled) { 19298c2ecf20Sopenharmony_ci adapter->cmd_wait_q.status = 0; 19308c2ecf20Sopenharmony_ci if (!priv->scan_request) { 19318c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, 19328c2ecf20Sopenharmony_ci "complete internal scan\n"); 19338c2ecf20Sopenharmony_ci mwifiex_complete_cmd(adapter, adapter->curr_cmd); 19348c2ecf20Sopenharmony_ci } 19358c2ecf20Sopenharmony_ci } 19368c2ecf20Sopenharmony_ci} 19378c2ecf20Sopenharmony_ci 19388c2ecf20Sopenharmony_ci/* This function checks if any hidden SSID found in passive scan channels 19398c2ecf20Sopenharmony_ci * and do specific SSID active scan for those channels 19408c2ecf20Sopenharmony_ci */ 19418c2ecf20Sopenharmony_cistatic int 19428c2ecf20Sopenharmony_cimwifiex_active_scan_req_for_passive_chan(struct mwifiex_private *priv) 19438c2ecf20Sopenharmony_ci{ 19448c2ecf20Sopenharmony_ci int ret; 19458c2ecf20Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 19468c2ecf20Sopenharmony_ci u8 id = 0; 19478c2ecf20Sopenharmony_ci struct mwifiex_user_scan_cfg *user_scan_cfg; 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci if (adapter->active_scan_triggered || !priv->scan_request || 19508c2ecf20Sopenharmony_ci priv->scan_aborting) { 19518c2ecf20Sopenharmony_ci adapter->active_scan_triggered = false; 19528c2ecf20Sopenharmony_ci return 0; 19538c2ecf20Sopenharmony_ci } 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_ci if (!priv->hidden_chan[0].chan_number) { 19568c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, "No BSS with hidden SSID found on DFS channels\n"); 19578c2ecf20Sopenharmony_ci return 0; 19588c2ecf20Sopenharmony_ci } 19598c2ecf20Sopenharmony_ci user_scan_cfg = kzalloc(sizeof(*user_scan_cfg), GFP_KERNEL); 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci if (!user_scan_cfg) 19628c2ecf20Sopenharmony_ci return -ENOMEM; 19638c2ecf20Sopenharmony_ci 19648c2ecf20Sopenharmony_ci for (id = 0; id < MWIFIEX_USER_SCAN_CHAN_MAX; id++) { 19658c2ecf20Sopenharmony_ci if (!priv->hidden_chan[id].chan_number) 19668c2ecf20Sopenharmony_ci break; 19678c2ecf20Sopenharmony_ci memcpy(&user_scan_cfg->chan_list[id], 19688c2ecf20Sopenharmony_ci &priv->hidden_chan[id], 19698c2ecf20Sopenharmony_ci sizeof(struct mwifiex_user_scan_chan)); 19708c2ecf20Sopenharmony_ci } 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_ci adapter->active_scan_triggered = true; 19738c2ecf20Sopenharmony_ci if (priv->scan_request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) 19748c2ecf20Sopenharmony_ci ether_addr_copy(user_scan_cfg->random_mac, 19758c2ecf20Sopenharmony_ci priv->scan_request->mac_addr); 19768c2ecf20Sopenharmony_ci user_scan_cfg->num_ssids = priv->scan_request->n_ssids; 19778c2ecf20Sopenharmony_ci user_scan_cfg->ssid_list = priv->scan_request->ssids; 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_ci ret = mwifiex_scan_networks(priv, user_scan_cfg); 19808c2ecf20Sopenharmony_ci kfree(user_scan_cfg); 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci memset(&priv->hidden_chan, 0, sizeof(priv->hidden_chan)); 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci if (ret) { 19858c2ecf20Sopenharmony_ci dev_err(priv->adapter->dev, "scan failed: %d\n", ret); 19868c2ecf20Sopenharmony_ci return ret; 19878c2ecf20Sopenharmony_ci } 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_ci return 0; 19908c2ecf20Sopenharmony_ci} 19918c2ecf20Sopenharmony_cistatic void mwifiex_check_next_scan_command(struct mwifiex_private *priv) 19928c2ecf20Sopenharmony_ci{ 19938c2ecf20Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 19948c2ecf20Sopenharmony_ci struct cmd_ctrl_node *cmd_node; 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_ci spin_lock_bh(&adapter->scan_pending_q_lock); 19978c2ecf20Sopenharmony_ci if (list_empty(&adapter->scan_pending_q)) { 19988c2ecf20Sopenharmony_ci spin_unlock_bh(&adapter->scan_pending_q_lock); 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci spin_lock_bh(&adapter->mwifiex_cmd_lock); 20018c2ecf20Sopenharmony_ci adapter->scan_processing = false; 20028c2ecf20Sopenharmony_ci spin_unlock_bh(&adapter->mwifiex_cmd_lock); 20038c2ecf20Sopenharmony_ci 20048c2ecf20Sopenharmony_ci mwifiex_active_scan_req_for_passive_chan(priv); 20058c2ecf20Sopenharmony_ci 20068c2ecf20Sopenharmony_ci if (!adapter->ext_scan) 20078c2ecf20Sopenharmony_ci mwifiex_complete_scan(priv); 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci if (priv->scan_request) { 20108c2ecf20Sopenharmony_ci struct cfg80211_scan_info info = { 20118c2ecf20Sopenharmony_ci .aborted = false, 20128c2ecf20Sopenharmony_ci }; 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, 20158c2ecf20Sopenharmony_ci "info: notifying scan done\n"); 20168c2ecf20Sopenharmony_ci cfg80211_scan_done(priv->scan_request, &info); 20178c2ecf20Sopenharmony_ci priv->scan_request = NULL; 20188c2ecf20Sopenharmony_ci priv->scan_aborting = false; 20198c2ecf20Sopenharmony_ci } else { 20208c2ecf20Sopenharmony_ci priv->scan_aborting = false; 20218c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, 20228c2ecf20Sopenharmony_ci "info: scan already aborted\n"); 20238c2ecf20Sopenharmony_ci } 20248c2ecf20Sopenharmony_ci } else if ((priv->scan_aborting && !priv->scan_request) || 20258c2ecf20Sopenharmony_ci priv->scan_block) { 20268c2ecf20Sopenharmony_ci spin_unlock_bh(&adapter->scan_pending_q_lock); 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_ci mwifiex_cancel_pending_scan_cmd(adapter); 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci spin_lock_bh(&adapter->mwifiex_cmd_lock); 20318c2ecf20Sopenharmony_ci adapter->scan_processing = false; 20328c2ecf20Sopenharmony_ci spin_unlock_bh(&adapter->mwifiex_cmd_lock); 20338c2ecf20Sopenharmony_ci 20348c2ecf20Sopenharmony_ci if (!adapter->active_scan_triggered) { 20358c2ecf20Sopenharmony_ci if (priv->scan_request) { 20368c2ecf20Sopenharmony_ci struct cfg80211_scan_info info = { 20378c2ecf20Sopenharmony_ci .aborted = true, 20388c2ecf20Sopenharmony_ci }; 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, 20418c2ecf20Sopenharmony_ci "info: aborting scan\n"); 20428c2ecf20Sopenharmony_ci cfg80211_scan_done(priv->scan_request, &info); 20438c2ecf20Sopenharmony_ci priv->scan_request = NULL; 20448c2ecf20Sopenharmony_ci priv->scan_aborting = false; 20458c2ecf20Sopenharmony_ci } else { 20468c2ecf20Sopenharmony_ci priv->scan_aborting = false; 20478c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, 20488c2ecf20Sopenharmony_ci "info: scan already aborted\n"); 20498c2ecf20Sopenharmony_ci } 20508c2ecf20Sopenharmony_ci } 20518c2ecf20Sopenharmony_ci } else { 20528c2ecf20Sopenharmony_ci /* Get scan command from scan_pending_q and put to 20538c2ecf20Sopenharmony_ci * cmd_pending_q 20548c2ecf20Sopenharmony_ci */ 20558c2ecf20Sopenharmony_ci cmd_node = list_first_entry(&adapter->scan_pending_q, 20568c2ecf20Sopenharmony_ci struct cmd_ctrl_node, list); 20578c2ecf20Sopenharmony_ci list_del(&cmd_node->list); 20588c2ecf20Sopenharmony_ci spin_unlock_bh(&adapter->scan_pending_q_lock); 20598c2ecf20Sopenharmony_ci mwifiex_insert_cmd_to_pending_q(adapter, cmd_node); 20608c2ecf20Sopenharmony_ci } 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ci return; 20638c2ecf20Sopenharmony_ci} 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_civoid mwifiex_cancel_scan(struct mwifiex_adapter *adapter) 20668c2ecf20Sopenharmony_ci{ 20678c2ecf20Sopenharmony_ci struct mwifiex_private *priv; 20688c2ecf20Sopenharmony_ci int i; 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_ci mwifiex_cancel_pending_scan_cmd(adapter); 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci if (adapter->scan_processing) { 20738c2ecf20Sopenharmony_ci spin_lock_bh(&adapter->mwifiex_cmd_lock); 20748c2ecf20Sopenharmony_ci adapter->scan_processing = false; 20758c2ecf20Sopenharmony_ci spin_unlock_bh(&adapter->mwifiex_cmd_lock); 20768c2ecf20Sopenharmony_ci for (i = 0; i < adapter->priv_num; i++) { 20778c2ecf20Sopenharmony_ci priv = adapter->priv[i]; 20788c2ecf20Sopenharmony_ci if (!priv) 20798c2ecf20Sopenharmony_ci continue; 20808c2ecf20Sopenharmony_ci if (priv->scan_request) { 20818c2ecf20Sopenharmony_ci struct cfg80211_scan_info info = { 20828c2ecf20Sopenharmony_ci .aborted = true, 20838c2ecf20Sopenharmony_ci }; 20848c2ecf20Sopenharmony_ci 20858c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, 20868c2ecf20Sopenharmony_ci "info: aborting scan\n"); 20878c2ecf20Sopenharmony_ci cfg80211_scan_done(priv->scan_request, &info); 20888c2ecf20Sopenharmony_ci priv->scan_request = NULL; 20898c2ecf20Sopenharmony_ci priv->scan_aborting = false; 20908c2ecf20Sopenharmony_ci } 20918c2ecf20Sopenharmony_ci } 20928c2ecf20Sopenharmony_ci } 20938c2ecf20Sopenharmony_ci} 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_ci/* 20968c2ecf20Sopenharmony_ci * This function handles the command response of scan. 20978c2ecf20Sopenharmony_ci * 20988c2ecf20Sopenharmony_ci * The response buffer for the scan command has the following 20998c2ecf20Sopenharmony_ci * memory layout: 21008c2ecf20Sopenharmony_ci * 21018c2ecf20Sopenharmony_ci * .-------------------------------------------------------------. 21028c2ecf20Sopenharmony_ci * | Header (4 * sizeof(t_u16)): Standard command response hdr | 21038c2ecf20Sopenharmony_ci * .-------------------------------------------------------------. 21048c2ecf20Sopenharmony_ci * | BufSize (t_u16) : sizeof the BSS Description data | 21058c2ecf20Sopenharmony_ci * .-------------------------------------------------------------. 21068c2ecf20Sopenharmony_ci * | NumOfSet (t_u8) : Number of BSS Descs returned | 21078c2ecf20Sopenharmony_ci * .-------------------------------------------------------------. 21088c2ecf20Sopenharmony_ci * | BSSDescription data (variable, size given in BufSize) | 21098c2ecf20Sopenharmony_ci * .-------------------------------------------------------------. 21108c2ecf20Sopenharmony_ci * | TLV data (variable, size calculated using Header->Size, | 21118c2ecf20Sopenharmony_ci * | BufSize and sizeof the fixed fields above) | 21128c2ecf20Sopenharmony_ci * .-------------------------------------------------------------. 21138c2ecf20Sopenharmony_ci */ 21148c2ecf20Sopenharmony_ciint mwifiex_ret_802_11_scan(struct mwifiex_private *priv, 21158c2ecf20Sopenharmony_ci struct host_cmd_ds_command *resp) 21168c2ecf20Sopenharmony_ci{ 21178c2ecf20Sopenharmony_ci int ret = 0; 21188c2ecf20Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 21198c2ecf20Sopenharmony_ci struct host_cmd_ds_802_11_scan_rsp *scan_rsp; 21208c2ecf20Sopenharmony_ci struct mwifiex_ie_types_data *tlv_data; 21218c2ecf20Sopenharmony_ci struct mwifiex_ie_types_tsf_timestamp *tsf_tlv; 21228c2ecf20Sopenharmony_ci u8 *bss_info; 21238c2ecf20Sopenharmony_ci u32 scan_resp_size; 21248c2ecf20Sopenharmony_ci u32 bytes_left; 21258c2ecf20Sopenharmony_ci u32 idx; 21268c2ecf20Sopenharmony_ci u32 tlv_buf_size; 21278c2ecf20Sopenharmony_ci struct mwifiex_ie_types_chan_band_list_param_set *chan_band_tlv; 21288c2ecf20Sopenharmony_ci struct chan_band_param_set *chan_band; 21298c2ecf20Sopenharmony_ci u8 is_bgscan_resp; 21308c2ecf20Sopenharmony_ci __le64 fw_tsf = 0; 21318c2ecf20Sopenharmony_ci u8 *radio_type; 21328c2ecf20Sopenharmony_ci struct cfg80211_wowlan_nd_match *pmatch; 21338c2ecf20Sopenharmony_ci struct cfg80211_sched_scan_request *nd_config = NULL; 21348c2ecf20Sopenharmony_ci 21358c2ecf20Sopenharmony_ci is_bgscan_resp = (le16_to_cpu(resp->command) 21368c2ecf20Sopenharmony_ci == HostCmd_CMD_802_11_BG_SCAN_QUERY); 21378c2ecf20Sopenharmony_ci if (is_bgscan_resp) 21388c2ecf20Sopenharmony_ci scan_rsp = &resp->params.bg_scan_query_resp.scan_resp; 21398c2ecf20Sopenharmony_ci else 21408c2ecf20Sopenharmony_ci scan_rsp = &resp->params.scan_resp; 21418c2ecf20Sopenharmony_ci 21428c2ecf20Sopenharmony_ci 21438c2ecf20Sopenharmony_ci if (scan_rsp->number_of_sets > MWIFIEX_MAX_AP) { 21448c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 21458c2ecf20Sopenharmony_ci "SCAN_RESP: too many AP returned (%d)\n", 21468c2ecf20Sopenharmony_ci scan_rsp->number_of_sets); 21478c2ecf20Sopenharmony_ci ret = -1; 21488c2ecf20Sopenharmony_ci goto check_next_scan; 21498c2ecf20Sopenharmony_ci } 21508c2ecf20Sopenharmony_ci 21518c2ecf20Sopenharmony_ci /* Check csa channel expiry before parsing scan response */ 21528c2ecf20Sopenharmony_ci mwifiex_11h_get_csa_closed_channel(priv); 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci bytes_left = le16_to_cpu(scan_rsp->bss_descript_size); 21558c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, 21568c2ecf20Sopenharmony_ci "info: SCAN_RESP: bss_descript_size %d\n", 21578c2ecf20Sopenharmony_ci bytes_left); 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_ci scan_resp_size = le16_to_cpu(resp->size); 21608c2ecf20Sopenharmony_ci 21618c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, 21628c2ecf20Sopenharmony_ci "info: SCAN_RESP: returned %d APs before parsing\n", 21638c2ecf20Sopenharmony_ci scan_rsp->number_of_sets); 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci bss_info = scan_rsp->bss_desc_and_tlv_buffer; 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci /* 21688c2ecf20Sopenharmony_ci * The size of the TLV buffer is equal to the entire command response 21698c2ecf20Sopenharmony_ci * size (scan_resp_size) minus the fixed fields (sizeof()'s), the 21708c2ecf20Sopenharmony_ci * BSS Descriptions (bss_descript_size as bytesLef) and the command 21718c2ecf20Sopenharmony_ci * response header (S_DS_GEN) 21728c2ecf20Sopenharmony_ci */ 21738c2ecf20Sopenharmony_ci tlv_buf_size = scan_resp_size - (bytes_left 21748c2ecf20Sopenharmony_ci + sizeof(scan_rsp->bss_descript_size) 21758c2ecf20Sopenharmony_ci + sizeof(scan_rsp->number_of_sets) 21768c2ecf20Sopenharmony_ci + S_DS_GEN); 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_ci tlv_data = (struct mwifiex_ie_types_data *) (scan_rsp-> 21798c2ecf20Sopenharmony_ci bss_desc_and_tlv_buffer + 21808c2ecf20Sopenharmony_ci bytes_left); 21818c2ecf20Sopenharmony_ci 21828c2ecf20Sopenharmony_ci /* Search the TLV buffer space in the scan response for any valid 21838c2ecf20Sopenharmony_ci TLVs */ 21848c2ecf20Sopenharmony_ci mwifiex_ret_802_11_scan_get_tlv_ptrs(adapter, tlv_data, tlv_buf_size, 21858c2ecf20Sopenharmony_ci TLV_TYPE_TSFTIMESTAMP, 21868c2ecf20Sopenharmony_ci (struct mwifiex_ie_types_data **) 21878c2ecf20Sopenharmony_ci &tsf_tlv); 21888c2ecf20Sopenharmony_ci 21898c2ecf20Sopenharmony_ci /* Search the TLV buffer space in the scan response for any valid 21908c2ecf20Sopenharmony_ci TLVs */ 21918c2ecf20Sopenharmony_ci mwifiex_ret_802_11_scan_get_tlv_ptrs(adapter, tlv_data, tlv_buf_size, 21928c2ecf20Sopenharmony_ci TLV_TYPE_CHANNELBANDLIST, 21938c2ecf20Sopenharmony_ci (struct mwifiex_ie_types_data **) 21948c2ecf20Sopenharmony_ci &chan_band_tlv); 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 21978c2ecf20Sopenharmony_ci if (priv->wdev.wiphy->wowlan_config) 21988c2ecf20Sopenharmony_ci nd_config = priv->wdev.wiphy->wowlan_config->nd_config; 21998c2ecf20Sopenharmony_ci#endif 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_ci if (nd_config) { 22028c2ecf20Sopenharmony_ci adapter->nd_info = 22038c2ecf20Sopenharmony_ci kzalloc(struct_size(adapter->nd_info, matches, 22048c2ecf20Sopenharmony_ci scan_rsp->number_of_sets), 22058c2ecf20Sopenharmony_ci GFP_ATOMIC); 22068c2ecf20Sopenharmony_ci 22078c2ecf20Sopenharmony_ci if (adapter->nd_info) 22088c2ecf20Sopenharmony_ci adapter->nd_info->n_matches = scan_rsp->number_of_sets; 22098c2ecf20Sopenharmony_ci } 22108c2ecf20Sopenharmony_ci 22118c2ecf20Sopenharmony_ci for (idx = 0; idx < scan_rsp->number_of_sets && bytes_left; idx++) { 22128c2ecf20Sopenharmony_ci /* 22138c2ecf20Sopenharmony_ci * If the TSF TLV was appended to the scan results, save this 22148c2ecf20Sopenharmony_ci * entry's TSF value in the fw_tsf field. It is the firmware's 22158c2ecf20Sopenharmony_ci * TSF value at the time the beacon or probe response was 22168c2ecf20Sopenharmony_ci * received. 22178c2ecf20Sopenharmony_ci */ 22188c2ecf20Sopenharmony_ci if (tsf_tlv) 22198c2ecf20Sopenharmony_ci memcpy(&fw_tsf, &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE], 22208c2ecf20Sopenharmony_ci sizeof(fw_tsf)); 22218c2ecf20Sopenharmony_ci 22228c2ecf20Sopenharmony_ci if (chan_band_tlv) { 22238c2ecf20Sopenharmony_ci chan_band = &chan_band_tlv->chan_band_param[idx]; 22248c2ecf20Sopenharmony_ci radio_type = &chan_band->radio_type; 22258c2ecf20Sopenharmony_ci } else { 22268c2ecf20Sopenharmony_ci radio_type = NULL; 22278c2ecf20Sopenharmony_ci } 22288c2ecf20Sopenharmony_ci 22298c2ecf20Sopenharmony_ci if (chan_band_tlv && adapter->nd_info) { 22308c2ecf20Sopenharmony_ci adapter->nd_info->matches[idx] = 22318c2ecf20Sopenharmony_ci kzalloc(sizeof(*pmatch) + sizeof(u32), 22328c2ecf20Sopenharmony_ci GFP_ATOMIC); 22338c2ecf20Sopenharmony_ci 22348c2ecf20Sopenharmony_ci pmatch = adapter->nd_info->matches[idx]; 22358c2ecf20Sopenharmony_ci 22368c2ecf20Sopenharmony_ci if (pmatch) { 22378c2ecf20Sopenharmony_ci pmatch->n_channels = 1; 22388c2ecf20Sopenharmony_ci pmatch->channels[0] = chan_band->chan_number; 22398c2ecf20Sopenharmony_ci } 22408c2ecf20Sopenharmony_ci } 22418c2ecf20Sopenharmony_ci 22428c2ecf20Sopenharmony_ci ret = mwifiex_parse_single_response_buf(priv, &bss_info, 22438c2ecf20Sopenharmony_ci &bytes_left, 22448c2ecf20Sopenharmony_ci le64_to_cpu(fw_tsf), 22458c2ecf20Sopenharmony_ci radio_type, false, 0); 22468c2ecf20Sopenharmony_ci if (ret) 22478c2ecf20Sopenharmony_ci goto check_next_scan; 22488c2ecf20Sopenharmony_ci } 22498c2ecf20Sopenharmony_ci 22508c2ecf20Sopenharmony_cicheck_next_scan: 22518c2ecf20Sopenharmony_ci mwifiex_check_next_scan_command(priv); 22528c2ecf20Sopenharmony_ci return ret; 22538c2ecf20Sopenharmony_ci} 22548c2ecf20Sopenharmony_ci 22558c2ecf20Sopenharmony_ci/* 22568c2ecf20Sopenharmony_ci * This function prepares an extended scan command to be sent to the firmware 22578c2ecf20Sopenharmony_ci * 22588c2ecf20Sopenharmony_ci * This uses the scan command configuration sent to the command processing 22598c2ecf20Sopenharmony_ci * module in command preparation stage to configure a extended scan command 22608c2ecf20Sopenharmony_ci * structure to send to firmware. 22618c2ecf20Sopenharmony_ci */ 22628c2ecf20Sopenharmony_ciint mwifiex_cmd_802_11_scan_ext(struct mwifiex_private *priv, 22638c2ecf20Sopenharmony_ci struct host_cmd_ds_command *cmd, 22648c2ecf20Sopenharmony_ci void *data_buf) 22658c2ecf20Sopenharmony_ci{ 22668c2ecf20Sopenharmony_ci struct host_cmd_ds_802_11_scan_ext *ext_scan = &cmd->params.ext_scan; 22678c2ecf20Sopenharmony_ci struct mwifiex_scan_cmd_config *scan_cfg = data_buf; 22688c2ecf20Sopenharmony_ci 22698c2ecf20Sopenharmony_ci memcpy(ext_scan->tlv_buffer, scan_cfg->tlv_buf, scan_cfg->tlv_buf_len); 22708c2ecf20Sopenharmony_ci 22718c2ecf20Sopenharmony_ci cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SCAN_EXT); 22728c2ecf20Sopenharmony_ci 22738c2ecf20Sopenharmony_ci /* Size is equal to the sizeof(fixed portions) + the TLV len + header */ 22748c2ecf20Sopenharmony_ci cmd->size = cpu_to_le16((u16)(sizeof(ext_scan->reserved) 22758c2ecf20Sopenharmony_ci + scan_cfg->tlv_buf_len + S_DS_GEN)); 22768c2ecf20Sopenharmony_ci 22778c2ecf20Sopenharmony_ci return 0; 22788c2ecf20Sopenharmony_ci} 22798c2ecf20Sopenharmony_ci 22808c2ecf20Sopenharmony_ci/* This function prepares an background scan config command to be sent 22818c2ecf20Sopenharmony_ci * to the firmware 22828c2ecf20Sopenharmony_ci */ 22838c2ecf20Sopenharmony_ciint mwifiex_cmd_802_11_bg_scan_config(struct mwifiex_private *priv, 22848c2ecf20Sopenharmony_ci struct host_cmd_ds_command *cmd, 22858c2ecf20Sopenharmony_ci void *data_buf) 22868c2ecf20Sopenharmony_ci{ 22878c2ecf20Sopenharmony_ci struct host_cmd_ds_802_11_bg_scan_config *bgscan_config = 22888c2ecf20Sopenharmony_ci &cmd->params.bg_scan_config; 22898c2ecf20Sopenharmony_ci struct mwifiex_bg_scan_cfg *bgscan_cfg_in = data_buf; 22908c2ecf20Sopenharmony_ci u8 *tlv_pos = bgscan_config->tlv; 22918c2ecf20Sopenharmony_ci u8 num_probes; 22928c2ecf20Sopenharmony_ci u32 ssid_len, chan_idx, scan_type, scan_dur, chan_num; 22938c2ecf20Sopenharmony_ci int i; 22948c2ecf20Sopenharmony_ci struct mwifiex_ie_types_num_probes *num_probes_tlv; 22958c2ecf20Sopenharmony_ci struct mwifiex_ie_types_repeat_count *repeat_count_tlv; 22968c2ecf20Sopenharmony_ci struct mwifiex_ie_types_min_rssi_threshold *rssi_threshold_tlv; 22978c2ecf20Sopenharmony_ci struct mwifiex_ie_types_bgscan_start_later *start_later_tlv; 22988c2ecf20Sopenharmony_ci struct mwifiex_ie_types_wildcard_ssid_params *wildcard_ssid_tlv; 22998c2ecf20Sopenharmony_ci struct mwifiex_ie_types_chan_list_param_set *chan_list_tlv; 23008c2ecf20Sopenharmony_ci struct mwifiex_chan_scan_param_set *temp_chan; 23018c2ecf20Sopenharmony_ci 23028c2ecf20Sopenharmony_ci cmd->command = cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_CONFIG); 23038c2ecf20Sopenharmony_ci cmd->size = cpu_to_le16(sizeof(*bgscan_config) + S_DS_GEN); 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_ci bgscan_config->action = cpu_to_le16(bgscan_cfg_in->action); 23068c2ecf20Sopenharmony_ci bgscan_config->enable = bgscan_cfg_in->enable; 23078c2ecf20Sopenharmony_ci bgscan_config->bss_type = bgscan_cfg_in->bss_type; 23088c2ecf20Sopenharmony_ci bgscan_config->scan_interval = 23098c2ecf20Sopenharmony_ci cpu_to_le32(bgscan_cfg_in->scan_interval); 23108c2ecf20Sopenharmony_ci bgscan_config->report_condition = 23118c2ecf20Sopenharmony_ci cpu_to_le32(bgscan_cfg_in->report_condition); 23128c2ecf20Sopenharmony_ci 23138c2ecf20Sopenharmony_ci /* stop sched scan */ 23148c2ecf20Sopenharmony_ci if (!bgscan_config->enable) 23158c2ecf20Sopenharmony_ci return 0; 23168c2ecf20Sopenharmony_ci 23178c2ecf20Sopenharmony_ci bgscan_config->chan_per_scan = bgscan_cfg_in->chan_per_scan; 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_ci num_probes = (bgscan_cfg_in->num_probes ? bgscan_cfg_in-> 23208c2ecf20Sopenharmony_ci num_probes : priv->adapter->scan_probes); 23218c2ecf20Sopenharmony_ci 23228c2ecf20Sopenharmony_ci if (num_probes) { 23238c2ecf20Sopenharmony_ci num_probes_tlv = (struct mwifiex_ie_types_num_probes *)tlv_pos; 23248c2ecf20Sopenharmony_ci num_probes_tlv->header.type = cpu_to_le16(TLV_TYPE_NUMPROBES); 23258c2ecf20Sopenharmony_ci num_probes_tlv->header.len = 23268c2ecf20Sopenharmony_ci cpu_to_le16(sizeof(num_probes_tlv->num_probes)); 23278c2ecf20Sopenharmony_ci num_probes_tlv->num_probes = cpu_to_le16((u16)num_probes); 23288c2ecf20Sopenharmony_ci 23298c2ecf20Sopenharmony_ci tlv_pos += sizeof(num_probes_tlv->header) + 23308c2ecf20Sopenharmony_ci le16_to_cpu(num_probes_tlv->header.len); 23318c2ecf20Sopenharmony_ci } 23328c2ecf20Sopenharmony_ci 23338c2ecf20Sopenharmony_ci if (bgscan_cfg_in->repeat_count) { 23348c2ecf20Sopenharmony_ci repeat_count_tlv = 23358c2ecf20Sopenharmony_ci (struct mwifiex_ie_types_repeat_count *)tlv_pos; 23368c2ecf20Sopenharmony_ci repeat_count_tlv->header.type = 23378c2ecf20Sopenharmony_ci cpu_to_le16(TLV_TYPE_REPEAT_COUNT); 23388c2ecf20Sopenharmony_ci repeat_count_tlv->header.len = 23398c2ecf20Sopenharmony_ci cpu_to_le16(sizeof(repeat_count_tlv->repeat_count)); 23408c2ecf20Sopenharmony_ci repeat_count_tlv->repeat_count = 23418c2ecf20Sopenharmony_ci cpu_to_le16(bgscan_cfg_in->repeat_count); 23428c2ecf20Sopenharmony_ci 23438c2ecf20Sopenharmony_ci tlv_pos += sizeof(repeat_count_tlv->header) + 23448c2ecf20Sopenharmony_ci le16_to_cpu(repeat_count_tlv->header.len); 23458c2ecf20Sopenharmony_ci } 23468c2ecf20Sopenharmony_ci 23478c2ecf20Sopenharmony_ci if (bgscan_cfg_in->rssi_threshold) { 23488c2ecf20Sopenharmony_ci rssi_threshold_tlv = 23498c2ecf20Sopenharmony_ci (struct mwifiex_ie_types_min_rssi_threshold *)tlv_pos; 23508c2ecf20Sopenharmony_ci rssi_threshold_tlv->header.type = 23518c2ecf20Sopenharmony_ci cpu_to_le16(TLV_TYPE_RSSI_LOW); 23528c2ecf20Sopenharmony_ci rssi_threshold_tlv->header.len = 23538c2ecf20Sopenharmony_ci cpu_to_le16(sizeof(rssi_threshold_tlv->rssi_threshold)); 23548c2ecf20Sopenharmony_ci rssi_threshold_tlv->rssi_threshold = 23558c2ecf20Sopenharmony_ci cpu_to_le16(bgscan_cfg_in->rssi_threshold); 23568c2ecf20Sopenharmony_ci 23578c2ecf20Sopenharmony_ci tlv_pos += sizeof(rssi_threshold_tlv->header) + 23588c2ecf20Sopenharmony_ci le16_to_cpu(rssi_threshold_tlv->header.len); 23598c2ecf20Sopenharmony_ci } 23608c2ecf20Sopenharmony_ci 23618c2ecf20Sopenharmony_ci for (i = 0; i < bgscan_cfg_in->num_ssids; i++) { 23628c2ecf20Sopenharmony_ci ssid_len = bgscan_cfg_in->ssid_list[i].ssid.ssid_len; 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_ci wildcard_ssid_tlv = 23658c2ecf20Sopenharmony_ci (struct mwifiex_ie_types_wildcard_ssid_params *)tlv_pos; 23668c2ecf20Sopenharmony_ci wildcard_ssid_tlv->header.type = 23678c2ecf20Sopenharmony_ci cpu_to_le16(TLV_TYPE_WILDCARDSSID); 23688c2ecf20Sopenharmony_ci wildcard_ssid_tlv->header.len = cpu_to_le16( 23698c2ecf20Sopenharmony_ci (u16)(ssid_len + sizeof(wildcard_ssid_tlv-> 23708c2ecf20Sopenharmony_ci max_ssid_length))); 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_ci /* max_ssid_length = 0 tells firmware to perform 23738c2ecf20Sopenharmony_ci * specific scan for the SSID filled, whereas 23748c2ecf20Sopenharmony_ci * max_ssid_length = IEEE80211_MAX_SSID_LEN is for 23758c2ecf20Sopenharmony_ci * wildcard scan. 23768c2ecf20Sopenharmony_ci */ 23778c2ecf20Sopenharmony_ci if (ssid_len) 23788c2ecf20Sopenharmony_ci wildcard_ssid_tlv->max_ssid_length = 0; 23798c2ecf20Sopenharmony_ci else 23808c2ecf20Sopenharmony_ci wildcard_ssid_tlv->max_ssid_length = 23818c2ecf20Sopenharmony_ci IEEE80211_MAX_SSID_LEN; 23828c2ecf20Sopenharmony_ci 23838c2ecf20Sopenharmony_ci memcpy(wildcard_ssid_tlv->ssid, 23848c2ecf20Sopenharmony_ci bgscan_cfg_in->ssid_list[i].ssid.ssid, ssid_len); 23858c2ecf20Sopenharmony_ci 23868c2ecf20Sopenharmony_ci tlv_pos += (sizeof(wildcard_ssid_tlv->header) 23878c2ecf20Sopenharmony_ci + le16_to_cpu(wildcard_ssid_tlv->header.len)); 23888c2ecf20Sopenharmony_ci } 23898c2ecf20Sopenharmony_ci 23908c2ecf20Sopenharmony_ci chan_list_tlv = (struct mwifiex_ie_types_chan_list_param_set *)tlv_pos; 23918c2ecf20Sopenharmony_ci 23928c2ecf20Sopenharmony_ci if (bgscan_cfg_in->chan_list[0].chan_number) { 23938c2ecf20Sopenharmony_ci dev_dbg(priv->adapter->dev, "info: bgscan: Using supplied channel list\n"); 23948c2ecf20Sopenharmony_ci 23958c2ecf20Sopenharmony_ci chan_list_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); 23968c2ecf20Sopenharmony_ci 23978c2ecf20Sopenharmony_ci for (chan_idx = 0; 23988c2ecf20Sopenharmony_ci chan_idx < MWIFIEX_BG_SCAN_CHAN_MAX && 23998c2ecf20Sopenharmony_ci bgscan_cfg_in->chan_list[chan_idx].chan_number; 24008c2ecf20Sopenharmony_ci chan_idx++) { 24018c2ecf20Sopenharmony_ci temp_chan = chan_list_tlv->chan_scan_param + chan_idx; 24028c2ecf20Sopenharmony_ci 24038c2ecf20Sopenharmony_ci /* Increment the TLV header length by size appended */ 24048c2ecf20Sopenharmony_ci le16_unaligned_add_cpu(&chan_list_tlv->header.len, 24058c2ecf20Sopenharmony_ci sizeof( 24068c2ecf20Sopenharmony_ci chan_list_tlv->chan_scan_param)); 24078c2ecf20Sopenharmony_ci 24088c2ecf20Sopenharmony_ci temp_chan->chan_number = 24098c2ecf20Sopenharmony_ci bgscan_cfg_in->chan_list[chan_idx].chan_number; 24108c2ecf20Sopenharmony_ci temp_chan->radio_type = 24118c2ecf20Sopenharmony_ci bgscan_cfg_in->chan_list[chan_idx].radio_type; 24128c2ecf20Sopenharmony_ci 24138c2ecf20Sopenharmony_ci scan_type = 24148c2ecf20Sopenharmony_ci bgscan_cfg_in->chan_list[chan_idx].scan_type; 24158c2ecf20Sopenharmony_ci 24168c2ecf20Sopenharmony_ci if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE) 24178c2ecf20Sopenharmony_ci temp_chan->chan_scan_mode_bitmap 24188c2ecf20Sopenharmony_ci |= MWIFIEX_PASSIVE_SCAN; 24198c2ecf20Sopenharmony_ci else 24208c2ecf20Sopenharmony_ci temp_chan->chan_scan_mode_bitmap 24218c2ecf20Sopenharmony_ci &= ~MWIFIEX_PASSIVE_SCAN; 24228c2ecf20Sopenharmony_ci 24238c2ecf20Sopenharmony_ci if (bgscan_cfg_in->chan_list[chan_idx].scan_time) { 24248c2ecf20Sopenharmony_ci scan_dur = (u16)bgscan_cfg_in-> 24258c2ecf20Sopenharmony_ci chan_list[chan_idx].scan_time; 24268c2ecf20Sopenharmony_ci } else { 24278c2ecf20Sopenharmony_ci scan_dur = (scan_type == 24288c2ecf20Sopenharmony_ci MWIFIEX_SCAN_TYPE_PASSIVE) ? 24298c2ecf20Sopenharmony_ci priv->adapter->passive_scan_time : 24308c2ecf20Sopenharmony_ci priv->adapter->specific_scan_time; 24318c2ecf20Sopenharmony_ci } 24328c2ecf20Sopenharmony_ci 24338c2ecf20Sopenharmony_ci temp_chan->min_scan_time = cpu_to_le16(scan_dur); 24348c2ecf20Sopenharmony_ci temp_chan->max_scan_time = cpu_to_le16(scan_dur); 24358c2ecf20Sopenharmony_ci } 24368c2ecf20Sopenharmony_ci } else { 24378c2ecf20Sopenharmony_ci dev_dbg(priv->adapter->dev, 24388c2ecf20Sopenharmony_ci "info: bgscan: Creating full region channel list\n"); 24398c2ecf20Sopenharmony_ci chan_num = 24408c2ecf20Sopenharmony_ci mwifiex_bgscan_create_channel_list(priv, bgscan_cfg_in, 24418c2ecf20Sopenharmony_ci chan_list_tlv-> 24428c2ecf20Sopenharmony_ci chan_scan_param); 24438c2ecf20Sopenharmony_ci le16_unaligned_add_cpu(&chan_list_tlv->header.len, 24448c2ecf20Sopenharmony_ci chan_num * 24458c2ecf20Sopenharmony_ci sizeof(chan_list_tlv->chan_scan_param[0])); 24468c2ecf20Sopenharmony_ci } 24478c2ecf20Sopenharmony_ci 24488c2ecf20Sopenharmony_ci tlv_pos += (sizeof(chan_list_tlv->header) 24498c2ecf20Sopenharmony_ci + le16_to_cpu(chan_list_tlv->header.len)); 24508c2ecf20Sopenharmony_ci 24518c2ecf20Sopenharmony_ci if (bgscan_cfg_in->start_later) { 24528c2ecf20Sopenharmony_ci start_later_tlv = 24538c2ecf20Sopenharmony_ci (struct mwifiex_ie_types_bgscan_start_later *)tlv_pos; 24548c2ecf20Sopenharmony_ci start_later_tlv->header.type = 24558c2ecf20Sopenharmony_ci cpu_to_le16(TLV_TYPE_BGSCAN_START_LATER); 24568c2ecf20Sopenharmony_ci start_later_tlv->header.len = 24578c2ecf20Sopenharmony_ci cpu_to_le16(sizeof(start_later_tlv->start_later)); 24588c2ecf20Sopenharmony_ci start_later_tlv->start_later = 24598c2ecf20Sopenharmony_ci cpu_to_le16(bgscan_cfg_in->start_later); 24608c2ecf20Sopenharmony_ci 24618c2ecf20Sopenharmony_ci tlv_pos += sizeof(start_later_tlv->header) + 24628c2ecf20Sopenharmony_ci le16_to_cpu(start_later_tlv->header.len); 24638c2ecf20Sopenharmony_ci } 24648c2ecf20Sopenharmony_ci 24658c2ecf20Sopenharmony_ci /* Append vendor specific IE TLV */ 24668c2ecf20Sopenharmony_ci mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_BGSCAN, &tlv_pos); 24678c2ecf20Sopenharmony_ci 24688c2ecf20Sopenharmony_ci le16_unaligned_add_cpu(&cmd->size, tlv_pos - bgscan_config->tlv); 24698c2ecf20Sopenharmony_ci 24708c2ecf20Sopenharmony_ci return 0; 24718c2ecf20Sopenharmony_ci} 24728c2ecf20Sopenharmony_ci 24738c2ecf20Sopenharmony_ciint mwifiex_stop_bg_scan(struct mwifiex_private *priv) 24748c2ecf20Sopenharmony_ci{ 24758c2ecf20Sopenharmony_ci struct mwifiex_bg_scan_cfg *bgscan_cfg; 24768c2ecf20Sopenharmony_ci 24778c2ecf20Sopenharmony_ci if (!priv->sched_scanning) { 24788c2ecf20Sopenharmony_ci dev_dbg(priv->adapter->dev, "bgscan already stopped!\n"); 24798c2ecf20Sopenharmony_ci return 0; 24808c2ecf20Sopenharmony_ci } 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_ci bgscan_cfg = kzalloc(sizeof(*bgscan_cfg), GFP_KERNEL); 24838c2ecf20Sopenharmony_ci if (!bgscan_cfg) 24848c2ecf20Sopenharmony_ci return -ENOMEM; 24858c2ecf20Sopenharmony_ci 24868c2ecf20Sopenharmony_ci bgscan_cfg->bss_type = MWIFIEX_BSS_MODE_INFRA; 24878c2ecf20Sopenharmony_ci bgscan_cfg->action = MWIFIEX_BGSCAN_ACT_SET; 24888c2ecf20Sopenharmony_ci bgscan_cfg->enable = false; 24898c2ecf20Sopenharmony_ci 24908c2ecf20Sopenharmony_ci if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11_BG_SCAN_CONFIG, 24918c2ecf20Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, bgscan_cfg, true)) { 24928c2ecf20Sopenharmony_ci kfree(bgscan_cfg); 24938c2ecf20Sopenharmony_ci return -EFAULT; 24948c2ecf20Sopenharmony_ci } 24958c2ecf20Sopenharmony_ci 24968c2ecf20Sopenharmony_ci kfree(bgscan_cfg); 24978c2ecf20Sopenharmony_ci priv->sched_scanning = false; 24988c2ecf20Sopenharmony_ci 24998c2ecf20Sopenharmony_ci return 0; 25008c2ecf20Sopenharmony_ci} 25018c2ecf20Sopenharmony_ci 25028c2ecf20Sopenharmony_cistatic void 25038c2ecf20Sopenharmony_cimwifiex_update_chan_statistics(struct mwifiex_private *priv, 25048c2ecf20Sopenharmony_ci struct mwifiex_ietypes_chanstats *tlv_stat) 25058c2ecf20Sopenharmony_ci{ 25068c2ecf20Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 25078c2ecf20Sopenharmony_ci u8 i, num_chan; 25088c2ecf20Sopenharmony_ci struct mwifiex_fw_chan_stats *fw_chan_stats; 25098c2ecf20Sopenharmony_ci struct mwifiex_chan_stats chan_stats; 25108c2ecf20Sopenharmony_ci 25118c2ecf20Sopenharmony_ci fw_chan_stats = (void *)((u8 *)tlv_stat + 25128c2ecf20Sopenharmony_ci sizeof(struct mwifiex_ie_types_header)); 25138c2ecf20Sopenharmony_ci num_chan = le16_to_cpu(tlv_stat->header.len) / 25148c2ecf20Sopenharmony_ci sizeof(struct mwifiex_chan_stats); 25158c2ecf20Sopenharmony_ci 25168c2ecf20Sopenharmony_ci for (i = 0 ; i < num_chan; i++) { 25178c2ecf20Sopenharmony_ci if (adapter->survey_idx >= adapter->num_in_chan_stats) { 25188c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, WARN, 25198c2ecf20Sopenharmony_ci "FW reported too many channel results (max %d)\n", 25208c2ecf20Sopenharmony_ci adapter->num_in_chan_stats); 25218c2ecf20Sopenharmony_ci return; 25228c2ecf20Sopenharmony_ci } 25238c2ecf20Sopenharmony_ci chan_stats.chan_num = fw_chan_stats->chan_num; 25248c2ecf20Sopenharmony_ci chan_stats.bandcfg = fw_chan_stats->bandcfg; 25258c2ecf20Sopenharmony_ci chan_stats.flags = fw_chan_stats->flags; 25268c2ecf20Sopenharmony_ci chan_stats.noise = fw_chan_stats->noise; 25278c2ecf20Sopenharmony_ci chan_stats.total_bss = le16_to_cpu(fw_chan_stats->total_bss); 25288c2ecf20Sopenharmony_ci chan_stats.cca_scan_dur = 25298c2ecf20Sopenharmony_ci le16_to_cpu(fw_chan_stats->cca_scan_dur); 25308c2ecf20Sopenharmony_ci chan_stats.cca_busy_dur = 25318c2ecf20Sopenharmony_ci le16_to_cpu(fw_chan_stats->cca_busy_dur); 25328c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, 25338c2ecf20Sopenharmony_ci "chan=%d, noise=%d, total_network=%d scan_duration=%d, busy_duration=%d\n", 25348c2ecf20Sopenharmony_ci chan_stats.chan_num, 25358c2ecf20Sopenharmony_ci chan_stats.noise, 25368c2ecf20Sopenharmony_ci chan_stats.total_bss, 25378c2ecf20Sopenharmony_ci chan_stats.cca_scan_dur, 25388c2ecf20Sopenharmony_ci chan_stats.cca_busy_dur); 25398c2ecf20Sopenharmony_ci memcpy(&adapter->chan_stats[adapter->survey_idx++], &chan_stats, 25408c2ecf20Sopenharmony_ci sizeof(struct mwifiex_chan_stats)); 25418c2ecf20Sopenharmony_ci fw_chan_stats++; 25428c2ecf20Sopenharmony_ci } 25438c2ecf20Sopenharmony_ci} 25448c2ecf20Sopenharmony_ci 25458c2ecf20Sopenharmony_ci/* This function handles the command response of extended scan */ 25468c2ecf20Sopenharmony_ciint mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv, 25478c2ecf20Sopenharmony_ci struct host_cmd_ds_command *resp) 25488c2ecf20Sopenharmony_ci{ 25498c2ecf20Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 25508c2ecf20Sopenharmony_ci struct host_cmd_ds_802_11_scan_ext *ext_scan_resp; 25518c2ecf20Sopenharmony_ci struct mwifiex_ie_types_header *tlv; 25528c2ecf20Sopenharmony_ci struct mwifiex_ietypes_chanstats *tlv_stat; 25538c2ecf20Sopenharmony_ci u16 buf_left, type, len; 25548c2ecf20Sopenharmony_ci 25558c2ecf20Sopenharmony_ci struct host_cmd_ds_command *cmd_ptr; 25568c2ecf20Sopenharmony_ci struct cmd_ctrl_node *cmd_node; 25578c2ecf20Sopenharmony_ci bool complete_scan = false; 25588c2ecf20Sopenharmony_ci 25598c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, "info: EXT scan returns successfully\n"); 25608c2ecf20Sopenharmony_ci 25618c2ecf20Sopenharmony_ci ext_scan_resp = &resp->params.ext_scan; 25628c2ecf20Sopenharmony_ci 25638c2ecf20Sopenharmony_ci tlv = (void *)ext_scan_resp->tlv_buffer; 25648c2ecf20Sopenharmony_ci buf_left = le16_to_cpu(resp->size) - (sizeof(*ext_scan_resp) + S_DS_GEN 25658c2ecf20Sopenharmony_ci - 1); 25668c2ecf20Sopenharmony_ci 25678c2ecf20Sopenharmony_ci while (buf_left >= sizeof(struct mwifiex_ie_types_header)) { 25688c2ecf20Sopenharmony_ci type = le16_to_cpu(tlv->type); 25698c2ecf20Sopenharmony_ci len = le16_to_cpu(tlv->len); 25708c2ecf20Sopenharmony_ci 25718c2ecf20Sopenharmony_ci if (buf_left < (sizeof(struct mwifiex_ie_types_header) + len)) { 25728c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 25738c2ecf20Sopenharmony_ci "error processing scan response TLVs"); 25748c2ecf20Sopenharmony_ci break; 25758c2ecf20Sopenharmony_ci } 25768c2ecf20Sopenharmony_ci 25778c2ecf20Sopenharmony_ci switch (type) { 25788c2ecf20Sopenharmony_ci case TLV_TYPE_CHANNEL_STATS: 25798c2ecf20Sopenharmony_ci tlv_stat = (void *)tlv; 25808c2ecf20Sopenharmony_ci mwifiex_update_chan_statistics(priv, tlv_stat); 25818c2ecf20Sopenharmony_ci break; 25828c2ecf20Sopenharmony_ci default: 25838c2ecf20Sopenharmony_ci break; 25848c2ecf20Sopenharmony_ci } 25858c2ecf20Sopenharmony_ci 25868c2ecf20Sopenharmony_ci buf_left -= len + sizeof(struct mwifiex_ie_types_header); 25878c2ecf20Sopenharmony_ci tlv = (void *)((u8 *)tlv + len + 25888c2ecf20Sopenharmony_ci sizeof(struct mwifiex_ie_types_header)); 25898c2ecf20Sopenharmony_ci } 25908c2ecf20Sopenharmony_ci 25918c2ecf20Sopenharmony_ci spin_lock_bh(&adapter->cmd_pending_q_lock); 25928c2ecf20Sopenharmony_ci spin_lock_bh(&adapter->scan_pending_q_lock); 25938c2ecf20Sopenharmony_ci if (list_empty(&adapter->scan_pending_q)) { 25948c2ecf20Sopenharmony_ci complete_scan = true; 25958c2ecf20Sopenharmony_ci list_for_each_entry(cmd_node, &adapter->cmd_pending_q, list) { 25968c2ecf20Sopenharmony_ci cmd_ptr = (void *)cmd_node->cmd_skb->data; 25978c2ecf20Sopenharmony_ci if (le16_to_cpu(cmd_ptr->command) == 25988c2ecf20Sopenharmony_ci HostCmd_CMD_802_11_SCAN_EXT) { 25998c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, 26008c2ecf20Sopenharmony_ci "Scan pending in command pending list"); 26018c2ecf20Sopenharmony_ci complete_scan = false; 26028c2ecf20Sopenharmony_ci break; 26038c2ecf20Sopenharmony_ci } 26048c2ecf20Sopenharmony_ci } 26058c2ecf20Sopenharmony_ci } 26068c2ecf20Sopenharmony_ci spin_unlock_bh(&adapter->scan_pending_q_lock); 26078c2ecf20Sopenharmony_ci spin_unlock_bh(&adapter->cmd_pending_q_lock); 26088c2ecf20Sopenharmony_ci 26098c2ecf20Sopenharmony_ci if (complete_scan) 26108c2ecf20Sopenharmony_ci mwifiex_complete_scan(priv); 26118c2ecf20Sopenharmony_ci 26128c2ecf20Sopenharmony_ci return 0; 26138c2ecf20Sopenharmony_ci} 26148c2ecf20Sopenharmony_ci 26158c2ecf20Sopenharmony_ci/* This function This function handles the event extended scan report. It 26168c2ecf20Sopenharmony_ci * parses extended scan results and informs to cfg80211 stack. 26178c2ecf20Sopenharmony_ci */ 26188c2ecf20Sopenharmony_ciint mwifiex_handle_event_ext_scan_report(struct mwifiex_private *priv, 26198c2ecf20Sopenharmony_ci void *buf) 26208c2ecf20Sopenharmony_ci{ 26218c2ecf20Sopenharmony_ci int ret = 0; 26228c2ecf20Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 26238c2ecf20Sopenharmony_ci u8 *bss_info; 26248c2ecf20Sopenharmony_ci u32 bytes_left, bytes_left_for_tlv, idx; 26258c2ecf20Sopenharmony_ci u16 type, len; 26268c2ecf20Sopenharmony_ci struct mwifiex_ie_types_data *tlv; 26278c2ecf20Sopenharmony_ci struct mwifiex_ie_types_bss_scan_rsp *scan_rsp_tlv; 26288c2ecf20Sopenharmony_ci struct mwifiex_ie_types_bss_scan_info *scan_info_tlv; 26298c2ecf20Sopenharmony_ci u8 *radio_type; 26308c2ecf20Sopenharmony_ci u64 fw_tsf = 0; 26318c2ecf20Sopenharmony_ci s32 rssi = 0; 26328c2ecf20Sopenharmony_ci struct mwifiex_event_scan_result *event_scan = buf; 26338c2ecf20Sopenharmony_ci u8 num_of_set = event_scan->num_of_set; 26348c2ecf20Sopenharmony_ci u8 *scan_resp = buf + sizeof(struct mwifiex_event_scan_result); 26358c2ecf20Sopenharmony_ci u16 scan_resp_size = le16_to_cpu(event_scan->buf_size); 26368c2ecf20Sopenharmony_ci 26378c2ecf20Sopenharmony_ci if (num_of_set > MWIFIEX_MAX_AP) { 26388c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 26398c2ecf20Sopenharmony_ci "EXT_SCAN: Invalid number of AP returned (%d)!!\n", 26408c2ecf20Sopenharmony_ci num_of_set); 26418c2ecf20Sopenharmony_ci ret = -1; 26428c2ecf20Sopenharmony_ci goto check_next_scan; 26438c2ecf20Sopenharmony_ci } 26448c2ecf20Sopenharmony_ci 26458c2ecf20Sopenharmony_ci bytes_left = scan_resp_size; 26468c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, 26478c2ecf20Sopenharmony_ci "EXT_SCAN: size %d, returned %d APs...", 26488c2ecf20Sopenharmony_ci scan_resp_size, num_of_set); 26498c2ecf20Sopenharmony_ci mwifiex_dbg_dump(adapter, CMD_D, "EXT_SCAN buffer:", buf, 26508c2ecf20Sopenharmony_ci scan_resp_size + 26518c2ecf20Sopenharmony_ci sizeof(struct mwifiex_event_scan_result)); 26528c2ecf20Sopenharmony_ci 26538c2ecf20Sopenharmony_ci tlv = (struct mwifiex_ie_types_data *)scan_resp; 26548c2ecf20Sopenharmony_ci 26558c2ecf20Sopenharmony_ci for (idx = 0; idx < num_of_set && bytes_left; idx++) { 26568c2ecf20Sopenharmony_ci type = le16_to_cpu(tlv->header.type); 26578c2ecf20Sopenharmony_ci len = le16_to_cpu(tlv->header.len); 26588c2ecf20Sopenharmony_ci if (bytes_left < sizeof(struct mwifiex_ie_types_header) + len) { 26598c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 26608c2ecf20Sopenharmony_ci "EXT_SCAN: Error bytes left < TLV length\n"); 26618c2ecf20Sopenharmony_ci break; 26628c2ecf20Sopenharmony_ci } 26638c2ecf20Sopenharmony_ci scan_rsp_tlv = NULL; 26648c2ecf20Sopenharmony_ci scan_info_tlv = NULL; 26658c2ecf20Sopenharmony_ci bytes_left_for_tlv = bytes_left; 26668c2ecf20Sopenharmony_ci 26678c2ecf20Sopenharmony_ci /* BSS response TLV with beacon or probe response buffer 26688c2ecf20Sopenharmony_ci * at the initial position of each descriptor 26698c2ecf20Sopenharmony_ci */ 26708c2ecf20Sopenharmony_ci if (type != TLV_TYPE_BSS_SCAN_RSP) 26718c2ecf20Sopenharmony_ci break; 26728c2ecf20Sopenharmony_ci 26738c2ecf20Sopenharmony_ci bss_info = (u8 *)tlv; 26748c2ecf20Sopenharmony_ci scan_rsp_tlv = (struct mwifiex_ie_types_bss_scan_rsp *)tlv; 26758c2ecf20Sopenharmony_ci tlv = (struct mwifiex_ie_types_data *)(tlv->data + len); 26768c2ecf20Sopenharmony_ci bytes_left_for_tlv -= 26778c2ecf20Sopenharmony_ci (len + sizeof(struct mwifiex_ie_types_header)); 26788c2ecf20Sopenharmony_ci 26798c2ecf20Sopenharmony_ci while (bytes_left_for_tlv >= 26808c2ecf20Sopenharmony_ci sizeof(struct mwifiex_ie_types_header) && 26818c2ecf20Sopenharmony_ci le16_to_cpu(tlv->header.type) != TLV_TYPE_BSS_SCAN_RSP) { 26828c2ecf20Sopenharmony_ci type = le16_to_cpu(tlv->header.type); 26838c2ecf20Sopenharmony_ci len = le16_to_cpu(tlv->header.len); 26848c2ecf20Sopenharmony_ci if (bytes_left_for_tlv < 26858c2ecf20Sopenharmony_ci sizeof(struct mwifiex_ie_types_header) + len) { 26868c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 26878c2ecf20Sopenharmony_ci "EXT_SCAN: Error in processing TLV,\t" 26888c2ecf20Sopenharmony_ci "bytes left < TLV length\n"); 26898c2ecf20Sopenharmony_ci scan_rsp_tlv = NULL; 26908c2ecf20Sopenharmony_ci bytes_left_for_tlv = 0; 26918c2ecf20Sopenharmony_ci continue; 26928c2ecf20Sopenharmony_ci } 26938c2ecf20Sopenharmony_ci switch (type) { 26948c2ecf20Sopenharmony_ci case TLV_TYPE_BSS_SCAN_INFO: 26958c2ecf20Sopenharmony_ci scan_info_tlv = 26968c2ecf20Sopenharmony_ci (struct mwifiex_ie_types_bss_scan_info *)tlv; 26978c2ecf20Sopenharmony_ci if (len != 26988c2ecf20Sopenharmony_ci sizeof(struct mwifiex_ie_types_bss_scan_info) - 26998c2ecf20Sopenharmony_ci sizeof(struct mwifiex_ie_types_header)) { 27008c2ecf20Sopenharmony_ci bytes_left_for_tlv = 0; 27018c2ecf20Sopenharmony_ci continue; 27028c2ecf20Sopenharmony_ci } 27038c2ecf20Sopenharmony_ci break; 27048c2ecf20Sopenharmony_ci default: 27058c2ecf20Sopenharmony_ci break; 27068c2ecf20Sopenharmony_ci } 27078c2ecf20Sopenharmony_ci tlv = (struct mwifiex_ie_types_data *)(tlv->data + len); 27088c2ecf20Sopenharmony_ci bytes_left -= 27098c2ecf20Sopenharmony_ci (len + sizeof(struct mwifiex_ie_types_header)); 27108c2ecf20Sopenharmony_ci bytes_left_for_tlv -= 27118c2ecf20Sopenharmony_ci (len + sizeof(struct mwifiex_ie_types_header)); 27128c2ecf20Sopenharmony_ci } 27138c2ecf20Sopenharmony_ci 27148c2ecf20Sopenharmony_ci if (!scan_rsp_tlv) 27158c2ecf20Sopenharmony_ci break; 27168c2ecf20Sopenharmony_ci 27178c2ecf20Sopenharmony_ci /* Advance pointer to the beacon buffer length and 27188c2ecf20Sopenharmony_ci * update the bytes count so that the function 27198c2ecf20Sopenharmony_ci * wlan_interpret_bss_desc_with_ie() can handle the 27208c2ecf20Sopenharmony_ci * scan buffer withut any change 27218c2ecf20Sopenharmony_ci */ 27228c2ecf20Sopenharmony_ci bss_info += sizeof(u16); 27238c2ecf20Sopenharmony_ci bytes_left -= sizeof(u16); 27248c2ecf20Sopenharmony_ci 27258c2ecf20Sopenharmony_ci if (scan_info_tlv) { 27268c2ecf20Sopenharmony_ci rssi = (s32)(s16)(le16_to_cpu(scan_info_tlv->rssi)); 27278c2ecf20Sopenharmony_ci rssi *= 100; /* Convert dBm to mBm */ 27288c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, INFO, 27298c2ecf20Sopenharmony_ci "info: InterpretIE: RSSI=%d\n", rssi); 27308c2ecf20Sopenharmony_ci fw_tsf = le64_to_cpu(scan_info_tlv->tsf); 27318c2ecf20Sopenharmony_ci radio_type = &scan_info_tlv->radio_type; 27328c2ecf20Sopenharmony_ci } else { 27338c2ecf20Sopenharmony_ci radio_type = NULL; 27348c2ecf20Sopenharmony_ci } 27358c2ecf20Sopenharmony_ci ret = mwifiex_parse_single_response_buf(priv, &bss_info, 27368c2ecf20Sopenharmony_ci &bytes_left, fw_tsf, 27378c2ecf20Sopenharmony_ci radio_type, true, rssi); 27388c2ecf20Sopenharmony_ci if (ret) 27398c2ecf20Sopenharmony_ci goto check_next_scan; 27408c2ecf20Sopenharmony_ci } 27418c2ecf20Sopenharmony_ci 27428c2ecf20Sopenharmony_cicheck_next_scan: 27438c2ecf20Sopenharmony_ci if (!event_scan->more_event) 27448c2ecf20Sopenharmony_ci mwifiex_check_next_scan_command(priv); 27458c2ecf20Sopenharmony_ci 27468c2ecf20Sopenharmony_ci return ret; 27478c2ecf20Sopenharmony_ci} 27488c2ecf20Sopenharmony_ci 27498c2ecf20Sopenharmony_ci/* 27508c2ecf20Sopenharmony_ci * This function prepares command for background scan query. 27518c2ecf20Sopenharmony_ci * 27528c2ecf20Sopenharmony_ci * Preparation includes - 27538c2ecf20Sopenharmony_ci * - Setting command ID and proper size 27548c2ecf20Sopenharmony_ci * - Setting background scan flush parameter 27558c2ecf20Sopenharmony_ci * - Ensuring correct endian-ness 27568c2ecf20Sopenharmony_ci */ 27578c2ecf20Sopenharmony_ciint mwifiex_cmd_802_11_bg_scan_query(struct host_cmd_ds_command *cmd) 27588c2ecf20Sopenharmony_ci{ 27598c2ecf20Sopenharmony_ci struct host_cmd_ds_802_11_bg_scan_query *bg_query = 27608c2ecf20Sopenharmony_ci &cmd->params.bg_scan_query; 27618c2ecf20Sopenharmony_ci 27628c2ecf20Sopenharmony_ci cmd->command = cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_QUERY); 27638c2ecf20Sopenharmony_ci cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_bg_scan_query) 27648c2ecf20Sopenharmony_ci + S_DS_GEN); 27658c2ecf20Sopenharmony_ci 27668c2ecf20Sopenharmony_ci bg_query->flush = 1; 27678c2ecf20Sopenharmony_ci 27688c2ecf20Sopenharmony_ci return 0; 27698c2ecf20Sopenharmony_ci} 27708c2ecf20Sopenharmony_ci 27718c2ecf20Sopenharmony_ci/* 27728c2ecf20Sopenharmony_ci * This function inserts scan command node to the scan pending queue. 27738c2ecf20Sopenharmony_ci */ 27748c2ecf20Sopenharmony_civoid 27758c2ecf20Sopenharmony_cimwifiex_queue_scan_cmd(struct mwifiex_private *priv, 27768c2ecf20Sopenharmony_ci struct cmd_ctrl_node *cmd_node) 27778c2ecf20Sopenharmony_ci{ 27788c2ecf20Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 27798c2ecf20Sopenharmony_ci 27808c2ecf20Sopenharmony_ci cmd_node->wait_q_enabled = true; 27818c2ecf20Sopenharmony_ci cmd_node->condition = &adapter->scan_wait_q_woken; 27828c2ecf20Sopenharmony_ci spin_lock_bh(&adapter->scan_pending_q_lock); 27838c2ecf20Sopenharmony_ci list_add_tail(&cmd_node->list, &adapter->scan_pending_q); 27848c2ecf20Sopenharmony_ci spin_unlock_bh(&adapter->scan_pending_q_lock); 27858c2ecf20Sopenharmony_ci} 27868c2ecf20Sopenharmony_ci 27878c2ecf20Sopenharmony_ci/* 27888c2ecf20Sopenharmony_ci * This function sends a scan command for all available channels to the 27898c2ecf20Sopenharmony_ci * firmware, filtered on a specific SSID. 27908c2ecf20Sopenharmony_ci */ 27918c2ecf20Sopenharmony_cistatic int mwifiex_scan_specific_ssid(struct mwifiex_private *priv, 27928c2ecf20Sopenharmony_ci struct cfg80211_ssid *req_ssid) 27938c2ecf20Sopenharmony_ci{ 27948c2ecf20Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 27958c2ecf20Sopenharmony_ci int ret; 27968c2ecf20Sopenharmony_ci struct mwifiex_user_scan_cfg *scan_cfg; 27978c2ecf20Sopenharmony_ci 27988c2ecf20Sopenharmony_ci if (adapter->scan_processing) { 27998c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, WARN, 28008c2ecf20Sopenharmony_ci "cmd: Scan already in process...\n"); 28018c2ecf20Sopenharmony_ci return -EBUSY; 28028c2ecf20Sopenharmony_ci } 28038c2ecf20Sopenharmony_ci 28048c2ecf20Sopenharmony_ci if (priv->scan_block) { 28058c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, WARN, 28068c2ecf20Sopenharmony_ci "cmd: Scan is blocked during association...\n"); 28078c2ecf20Sopenharmony_ci return -EBUSY; 28088c2ecf20Sopenharmony_ci } 28098c2ecf20Sopenharmony_ci 28108c2ecf20Sopenharmony_ci scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg), GFP_KERNEL); 28118c2ecf20Sopenharmony_ci if (!scan_cfg) 28128c2ecf20Sopenharmony_ci return -ENOMEM; 28138c2ecf20Sopenharmony_ci 28148c2ecf20Sopenharmony_ci scan_cfg->ssid_list = req_ssid; 28158c2ecf20Sopenharmony_ci scan_cfg->num_ssids = 1; 28168c2ecf20Sopenharmony_ci 28178c2ecf20Sopenharmony_ci ret = mwifiex_scan_networks(priv, scan_cfg); 28188c2ecf20Sopenharmony_ci 28198c2ecf20Sopenharmony_ci kfree(scan_cfg); 28208c2ecf20Sopenharmony_ci return ret; 28218c2ecf20Sopenharmony_ci} 28228c2ecf20Sopenharmony_ci 28238c2ecf20Sopenharmony_ci/* 28248c2ecf20Sopenharmony_ci * Sends IOCTL request to start a scan. 28258c2ecf20Sopenharmony_ci * 28268c2ecf20Sopenharmony_ci * This function allocates the IOCTL request buffer, fills it 28278c2ecf20Sopenharmony_ci * with requisite parameters and calls the IOCTL handler. 28288c2ecf20Sopenharmony_ci * 28298c2ecf20Sopenharmony_ci * Scan command can be issued for both normal scan and specific SSID 28308c2ecf20Sopenharmony_ci * scan, depending upon whether an SSID is provided or not. 28318c2ecf20Sopenharmony_ci */ 28328c2ecf20Sopenharmony_ciint mwifiex_request_scan(struct mwifiex_private *priv, 28338c2ecf20Sopenharmony_ci struct cfg80211_ssid *req_ssid) 28348c2ecf20Sopenharmony_ci{ 28358c2ecf20Sopenharmony_ci int ret; 28368c2ecf20Sopenharmony_ci 28378c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&priv->async_mutex)) { 28388c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 28398c2ecf20Sopenharmony_ci "%s: acquire semaphore fail\n", 28408c2ecf20Sopenharmony_ci __func__); 28418c2ecf20Sopenharmony_ci return -1; 28428c2ecf20Sopenharmony_ci } 28438c2ecf20Sopenharmony_ci 28448c2ecf20Sopenharmony_ci priv->adapter->scan_wait_q_woken = false; 28458c2ecf20Sopenharmony_ci 28468c2ecf20Sopenharmony_ci if (req_ssid && req_ssid->ssid_len != 0) 28478c2ecf20Sopenharmony_ci /* Specific SSID scan */ 28488c2ecf20Sopenharmony_ci ret = mwifiex_scan_specific_ssid(priv, req_ssid); 28498c2ecf20Sopenharmony_ci else 28508c2ecf20Sopenharmony_ci /* Normal scan */ 28518c2ecf20Sopenharmony_ci ret = mwifiex_scan_networks(priv, NULL); 28528c2ecf20Sopenharmony_ci 28538c2ecf20Sopenharmony_ci mutex_unlock(&priv->async_mutex); 28548c2ecf20Sopenharmony_ci 28558c2ecf20Sopenharmony_ci return ret; 28568c2ecf20Sopenharmony_ci} 28578c2ecf20Sopenharmony_ci 28588c2ecf20Sopenharmony_ci/* 28598c2ecf20Sopenharmony_ci * This function appends the vendor specific IE TLV to a buffer. 28608c2ecf20Sopenharmony_ci */ 28618c2ecf20Sopenharmony_ciint 28628c2ecf20Sopenharmony_cimwifiex_cmd_append_vsie_tlv(struct mwifiex_private *priv, 28638c2ecf20Sopenharmony_ci u16 vsie_mask, u8 **buffer) 28648c2ecf20Sopenharmony_ci{ 28658c2ecf20Sopenharmony_ci int id, ret_len = 0; 28668c2ecf20Sopenharmony_ci struct mwifiex_ie_types_vendor_param_set *vs_param_set; 28678c2ecf20Sopenharmony_ci 28688c2ecf20Sopenharmony_ci if (!buffer) 28698c2ecf20Sopenharmony_ci return 0; 28708c2ecf20Sopenharmony_ci if (!(*buffer)) 28718c2ecf20Sopenharmony_ci return 0; 28728c2ecf20Sopenharmony_ci 28738c2ecf20Sopenharmony_ci /* 28748c2ecf20Sopenharmony_ci * Traverse through the saved vendor specific IE array and append 28758c2ecf20Sopenharmony_ci * the selected(scan/assoc/adhoc) IE as TLV to the command 28768c2ecf20Sopenharmony_ci */ 28778c2ecf20Sopenharmony_ci for (id = 0; id < MWIFIEX_MAX_VSIE_NUM; id++) { 28788c2ecf20Sopenharmony_ci if (priv->vs_ie[id].mask & vsie_mask) { 28798c2ecf20Sopenharmony_ci vs_param_set = 28808c2ecf20Sopenharmony_ci (struct mwifiex_ie_types_vendor_param_set *) 28818c2ecf20Sopenharmony_ci *buffer; 28828c2ecf20Sopenharmony_ci vs_param_set->header.type = 28838c2ecf20Sopenharmony_ci cpu_to_le16(TLV_TYPE_PASSTHROUGH); 28848c2ecf20Sopenharmony_ci vs_param_set->header.len = 28858c2ecf20Sopenharmony_ci cpu_to_le16((((u16) priv->vs_ie[id].ie[1]) 28868c2ecf20Sopenharmony_ci & 0x00FF) + 2); 28878c2ecf20Sopenharmony_ci if (le16_to_cpu(vs_param_set->header.len) > 28888c2ecf20Sopenharmony_ci MWIFIEX_MAX_VSIE_LEN) { 28898c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 28908c2ecf20Sopenharmony_ci "Invalid param length!\n"); 28918c2ecf20Sopenharmony_ci break; 28928c2ecf20Sopenharmony_ci } 28938c2ecf20Sopenharmony_ci 28948c2ecf20Sopenharmony_ci memcpy(vs_param_set->ie, priv->vs_ie[id].ie, 28958c2ecf20Sopenharmony_ci le16_to_cpu(vs_param_set->header.len)); 28968c2ecf20Sopenharmony_ci *buffer += le16_to_cpu(vs_param_set->header.len) + 28978c2ecf20Sopenharmony_ci sizeof(struct mwifiex_ie_types_header); 28988c2ecf20Sopenharmony_ci ret_len += le16_to_cpu(vs_param_set->header.len) + 28998c2ecf20Sopenharmony_ci sizeof(struct mwifiex_ie_types_header); 29008c2ecf20Sopenharmony_ci } 29018c2ecf20Sopenharmony_ci } 29028c2ecf20Sopenharmony_ci return ret_len; 29038c2ecf20Sopenharmony_ci} 29048c2ecf20Sopenharmony_ci 29058c2ecf20Sopenharmony_ci/* 29068c2ecf20Sopenharmony_ci * This function saves a beacon buffer of the current BSS descriptor. 29078c2ecf20Sopenharmony_ci * 29088c2ecf20Sopenharmony_ci * The current beacon buffer is saved so that it can be restored in the 29098c2ecf20Sopenharmony_ci * following cases that makes the beacon buffer not to contain the current 29108c2ecf20Sopenharmony_ci * ssid's beacon buffer. 29118c2ecf20Sopenharmony_ci * - The current ssid was not found somehow in the last scan. 29128c2ecf20Sopenharmony_ci * - The current ssid was the last entry of the scan table and overloaded. 29138c2ecf20Sopenharmony_ci */ 29148c2ecf20Sopenharmony_civoid 29158c2ecf20Sopenharmony_cimwifiex_save_curr_bcn(struct mwifiex_private *priv) 29168c2ecf20Sopenharmony_ci{ 29178c2ecf20Sopenharmony_ci struct mwifiex_bssdescriptor *curr_bss = 29188c2ecf20Sopenharmony_ci &priv->curr_bss_params.bss_descriptor; 29198c2ecf20Sopenharmony_ci 29208c2ecf20Sopenharmony_ci if (!curr_bss->beacon_buf_size) 29218c2ecf20Sopenharmony_ci return; 29228c2ecf20Sopenharmony_ci 29238c2ecf20Sopenharmony_ci /* allocate beacon buffer at 1st time; or if it's size has changed */ 29248c2ecf20Sopenharmony_ci if (!priv->curr_bcn_buf || 29258c2ecf20Sopenharmony_ci priv->curr_bcn_size != curr_bss->beacon_buf_size) { 29268c2ecf20Sopenharmony_ci priv->curr_bcn_size = curr_bss->beacon_buf_size; 29278c2ecf20Sopenharmony_ci 29288c2ecf20Sopenharmony_ci kfree(priv->curr_bcn_buf); 29298c2ecf20Sopenharmony_ci priv->curr_bcn_buf = kmalloc(curr_bss->beacon_buf_size, 29308c2ecf20Sopenharmony_ci GFP_ATOMIC); 29318c2ecf20Sopenharmony_ci if (!priv->curr_bcn_buf) 29328c2ecf20Sopenharmony_ci return; 29338c2ecf20Sopenharmony_ci } 29348c2ecf20Sopenharmony_ci 29358c2ecf20Sopenharmony_ci memcpy(priv->curr_bcn_buf, curr_bss->beacon_buf, 29368c2ecf20Sopenharmony_ci curr_bss->beacon_buf_size); 29378c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 29388c2ecf20Sopenharmony_ci "info: current beacon saved %d\n", 29398c2ecf20Sopenharmony_ci priv->curr_bcn_size); 29408c2ecf20Sopenharmony_ci 29418c2ecf20Sopenharmony_ci curr_bss->beacon_buf = priv->curr_bcn_buf; 29428c2ecf20Sopenharmony_ci 29438c2ecf20Sopenharmony_ci /* adjust the pointers in the current BSS descriptor */ 29448c2ecf20Sopenharmony_ci if (curr_bss->bcn_wpa_ie) 29458c2ecf20Sopenharmony_ci curr_bss->bcn_wpa_ie = 29468c2ecf20Sopenharmony_ci (struct ieee_types_vendor_specific *) 29478c2ecf20Sopenharmony_ci (curr_bss->beacon_buf + 29488c2ecf20Sopenharmony_ci curr_bss->wpa_offset); 29498c2ecf20Sopenharmony_ci 29508c2ecf20Sopenharmony_ci if (curr_bss->bcn_rsn_ie) 29518c2ecf20Sopenharmony_ci curr_bss->bcn_rsn_ie = (struct ieee_types_generic *) 29528c2ecf20Sopenharmony_ci (curr_bss->beacon_buf + 29538c2ecf20Sopenharmony_ci curr_bss->rsn_offset); 29548c2ecf20Sopenharmony_ci 29558c2ecf20Sopenharmony_ci if (curr_bss->bcn_ht_cap) 29568c2ecf20Sopenharmony_ci curr_bss->bcn_ht_cap = (struct ieee80211_ht_cap *) 29578c2ecf20Sopenharmony_ci (curr_bss->beacon_buf + 29588c2ecf20Sopenharmony_ci curr_bss->ht_cap_offset); 29598c2ecf20Sopenharmony_ci 29608c2ecf20Sopenharmony_ci if (curr_bss->bcn_ht_oper) 29618c2ecf20Sopenharmony_ci curr_bss->bcn_ht_oper = (struct ieee80211_ht_operation *) 29628c2ecf20Sopenharmony_ci (curr_bss->beacon_buf + 29638c2ecf20Sopenharmony_ci curr_bss->ht_info_offset); 29648c2ecf20Sopenharmony_ci 29658c2ecf20Sopenharmony_ci if (curr_bss->bcn_vht_cap) 29668c2ecf20Sopenharmony_ci curr_bss->bcn_vht_cap = (void *)(curr_bss->beacon_buf + 29678c2ecf20Sopenharmony_ci curr_bss->vht_cap_offset); 29688c2ecf20Sopenharmony_ci 29698c2ecf20Sopenharmony_ci if (curr_bss->bcn_vht_oper) 29708c2ecf20Sopenharmony_ci curr_bss->bcn_vht_oper = (void *)(curr_bss->beacon_buf + 29718c2ecf20Sopenharmony_ci curr_bss->vht_info_offset); 29728c2ecf20Sopenharmony_ci 29738c2ecf20Sopenharmony_ci if (curr_bss->bcn_bss_co_2040) 29748c2ecf20Sopenharmony_ci curr_bss->bcn_bss_co_2040 = 29758c2ecf20Sopenharmony_ci (curr_bss->beacon_buf + curr_bss->bss_co_2040_offset); 29768c2ecf20Sopenharmony_ci 29778c2ecf20Sopenharmony_ci if (curr_bss->bcn_ext_cap) 29788c2ecf20Sopenharmony_ci curr_bss->bcn_ext_cap = curr_bss->beacon_buf + 29798c2ecf20Sopenharmony_ci curr_bss->ext_cap_offset; 29808c2ecf20Sopenharmony_ci 29818c2ecf20Sopenharmony_ci if (curr_bss->oper_mode) 29828c2ecf20Sopenharmony_ci curr_bss->oper_mode = (void *)(curr_bss->beacon_buf + 29838c2ecf20Sopenharmony_ci curr_bss->oper_mode_offset); 29848c2ecf20Sopenharmony_ci} 29858c2ecf20Sopenharmony_ci 29868c2ecf20Sopenharmony_ci/* 29878c2ecf20Sopenharmony_ci * This function frees the current BSS descriptor beacon buffer. 29888c2ecf20Sopenharmony_ci */ 29898c2ecf20Sopenharmony_civoid 29908c2ecf20Sopenharmony_cimwifiex_free_curr_bcn(struct mwifiex_private *priv) 29918c2ecf20Sopenharmony_ci{ 29928c2ecf20Sopenharmony_ci kfree(priv->curr_bcn_buf); 29938c2ecf20Sopenharmony_ci priv->curr_bcn_buf = NULL; 29948c2ecf20Sopenharmony_ci} 2995