mirror of
https://github.com/nxp-imx/mwifiex.git
synced 2024-11-15 03:25:35 +00:00
13b6fdb0b4
changes: 1. WCSWREL-191: Fixed the error when loading module param from user config for SD8801 2. WCSWREL-186: Fixed the issue of mlanutl failing on kernel higher than L5.15 3. Fixed low throughput issue for WPA3 SAE 4. Added driver change for WLAN throughput improvement on 8997 SoC 5. Updated README to recommend not to use WEP/TKIP for all chipsets 6. WCSWREL-180: Fix P2P test fail on kernel higher than L5.12 7. WCSWREL-156: kernel_write/kernel_read not allowed by drivers for L5.10 kernel GKI buildou 8. Alternative for pm_qos_add_request/pm_qos_remove_request Signed-off-by: Sherry Sun <sherry.sun@nxp.com> Approved-by: Tian Yang <yang.tian@nxp.com>
6971 lines
215 KiB
C
6971 lines
215 KiB
C
/** @file mlan_scan.c
|
|
*
|
|
* @brief Functions implementing wlan scan IOCTL and firmware command APIs
|
|
*
|
|
* IOCTL handlers as well as command preparation and response routines
|
|
* for sending scan commands to the firmware.
|
|
*
|
|
*
|
|
* Copyright 2008-2021 NXP
|
|
*
|
|
* This software file (the File) is distributed by NXP
|
|
* under the terms of the GNU General Public License Version 2, June 1991
|
|
* (the License). You may use, redistribute and/or modify the File in
|
|
* accordance with the terms and conditions of the License, a copy of which
|
|
* is available by writing to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
|
|
* worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
|
|
*
|
|
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
|
|
* this warranty disclaimer.
|
|
*
|
|
*/
|
|
|
|
/******************************************************
|
|
Change log:
|
|
10/28/2008: initial version
|
|
******************************************************/
|
|
|
|
#include "mlan.h"
|
|
#include "mlan_join.h"
|
|
#include "mlan_util.h"
|
|
#include "mlan_fw.h"
|
|
#include "mlan_main.h"
|
|
#include "mlan_11n.h"
|
|
#include "mlan_11ac.h"
|
|
#include "mlan_11ax.h"
|
|
#include "mlan_11h.h"
|
|
#ifdef DRV_EMBEDDED_SUPPLICANT
|
|
#include "authenticator_api.h"
|
|
#endif
|
|
/********************************************************
|
|
Local Constants
|
|
********************************************************/
|
|
/** minimum scan time for passive to active scan */
|
|
#define MIN_PASSIVE_TO_ACTIVE_SCAN_TIME 150
|
|
|
|
#define MRVDRV_MAX_CHANNELS_PER_SCAN 38
|
|
/** The maximum number of channels the firmware can scan per command */
|
|
#define MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN 4
|
|
|
|
/**
|
|
* Number of channels to scan per firmware scan command issuance.
|
|
*
|
|
* Number restricted to prevent hitting the limit on the amount of scan data
|
|
* returned in a single firmware scan command.
|
|
*/
|
|
#define MRVDRV_CHANNELS_PER_SCAN_CMD 4
|
|
|
|
/** Memory needed to store a max sized Channel List TLV for a firmware scan */
|
|
#define CHAN_TLV_MAX_SIZE \
|
|
(sizeof(MrvlIEtypesHeader_t) + \
|
|
(MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN * sizeof(ChanScanParamSet_t)))
|
|
|
|
/** Memory needed to store supported rate */
|
|
#define RATE_TLV_MAX_SIZE \
|
|
(sizeof(MrvlIEtypes_RatesParamSet_t) + HOSTCMD_SUPPORTED_RATES)
|
|
|
|
/** Memory needed to store a max number/size WildCard
|
|
* SSID TLV for a firmware scan */
|
|
#define WILDCARD_SSID_TLV_MAX_SIZE \
|
|
(MRVDRV_MAX_SSID_LIST_LENGTH * \
|
|
(sizeof(MrvlIEtypes_WildCardSsIdParamSet_t) + \
|
|
MRVDRV_MAX_SSID_LENGTH))
|
|
|
|
/** Memory needed to store a max number/size BSSID TLV for a firmware scan */
|
|
#define BSSID_LIST_TLV_MAX_SIZE \
|
|
(sizeof(MrvlIEtypesHeader_t) + \
|
|
(MRVDRV_MAX_BSSID_LIST * MLAN_MAC_ADDR_LENGTH))
|
|
|
|
/** WPS TLV MAX size is MAX IE size plus 2 bytes for
|
|
* t_u16 MRVL TLV extension */
|
|
#define WPS_TLV_MAX_SIZE (sizeof(IEEEtypes_VendorSpecific_t) + 2)
|
|
/** Maximum memory needed for a wlan_scan_cmd_config
|
|
* with all TLVs at max */
|
|
#define MAX_SCAN_CFG_ALLOC \
|
|
(sizeof(wlan_scan_cmd_config) + sizeof(MrvlIEtypes_NumProbes_t) + \
|
|
sizeof(MrvlIETypes_HTCap_t) + CHAN_TLV_MAX_SIZE + RATE_TLV_MAX_SIZE + \
|
|
WILDCARD_SSID_TLV_MAX_SIZE + BSSID_LIST_TLV_MAX_SIZE + \
|
|
WPS_TLV_MAX_SIZE)
|
|
|
|
/********************************************************
|
|
Local Variables
|
|
********************************************************/
|
|
|
|
/**
|
|
* Interally used to send a configured scan cmd between
|
|
* driver routines
|
|
*/
|
|
typedef union {
|
|
/** Scan configuration (variable length) */
|
|
wlan_scan_cmd_config config;
|
|
/** Max allocated block */
|
|
t_u8 config_alloc_buf[MAX_SCAN_CFG_ALLOC];
|
|
} wlan_scan_cmd_config_tlv;
|
|
|
|
/********************************************************
|
|
Global Variables
|
|
********************************************************/
|
|
|
|
/********************************************************
|
|
Local Functions
|
|
********************************************************/
|
|
/** Cipher suite definition */
|
|
enum cipher_suite {
|
|
CIPHER_SUITE_WEP40,
|
|
CIPHER_SUITE_TKIP,
|
|
CIPHER_SUITE_CCMP,
|
|
CIPHER_SUITE_WEP104,
|
|
CIPHER_SUITE_GCMP,
|
|
CIPHER_SUITE_GCMP_256,
|
|
CIPHER_SUITE_CCMP_256,
|
|
CIPHER_SUITE_MAX
|
|
};
|
|
|
|
static t_u8 wpa_ouis[CIPHER_SUITE_MAX][4] = {
|
|
{0x00, 0x50, 0xf2, 0x01}, /* WEP40 */
|
|
{0x00, 0x50, 0xf2, 0x02}, /* TKIP */
|
|
{0x00, 0x50, 0xf2, 0x04}, /* AES */
|
|
{0x00, 0x50, 0xf2, 0x05}, /* WEP104 */
|
|
};
|
|
|
|
static t_u8 rsn_oui[CIPHER_SUITE_MAX][4] = {
|
|
{0x00, 0x0f, 0xac, 0x01}, /* WEP40 */
|
|
{0x00, 0x0f, 0xac, 0x02}, /* TKIP */
|
|
{0x00, 0x0f, 0xac, 0x04}, /* AES */
|
|
{0x00, 0x0f, 0xac, 0x05}, /* WEP104 */
|
|
{0x00, 0x0f, 0xac, 0x08}, /* GCMP */
|
|
{0x00, 0x0f, 0xac, 0x09}, /* GCMP-256 */
|
|
{0x00, 0x0f, 0xac, 0x0a}, /* CCMP-256 */
|
|
};
|
|
|
|
/**
|
|
* @brief Convert radio type scan parameter to a band config used in join cmd
|
|
*
|
|
* @param radio_type Scan parameter indicating the radio used for a channel
|
|
* in a scan command.
|
|
*
|
|
* @return Band type conversion of scanBand used in join/assoc cmds
|
|
*
|
|
*/
|
|
t_u8 radio_type_to_band(t_u8 radio_type)
|
|
{
|
|
t_u8 ret_band;
|
|
|
|
switch (radio_type) {
|
|
case BAND_5GHZ:
|
|
ret_band = BAND_A;
|
|
break;
|
|
case BAND_2GHZ:
|
|
default:
|
|
ret_band = BAND_G;
|
|
break;
|
|
}
|
|
|
|
return ret_band;
|
|
}
|
|
|
|
/**
|
|
* @brief This function will update the channel statistics from scan result
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @param pchanstats_tlv A pointer to MrvlIEtypes_ChannelStats_t tlv
|
|
*
|
|
* @return NA
|
|
*/
|
|
static void
|
|
wlan_update_chan_statistics(mlan_private *pmpriv,
|
|
MrvlIEtypes_ChannelStats_t *pchanstats_tlv)
|
|
{
|
|
mlan_adapter *pmadapter = pmpriv->adapter;
|
|
t_u8 i;
|
|
chan_statistics_t *pchan_stats =
|
|
(chan_statistics_t *)((t_u8 *)pchanstats_tlv +
|
|
sizeof(MrvlIEtypesHeader_t));
|
|
t_u8 num_chan = wlan_le16_to_cpu(pchanstats_tlv->header.len) /
|
|
sizeof(chan_statistics_t);
|
|
|
|
ENTER();
|
|
|
|
for (i = 0; i < num_chan; i++) {
|
|
if (pmadapter->idx_chan_stats >= pmadapter->num_in_chan_stats) {
|
|
PRINTM(MERROR,
|
|
"Over flow: idx_chan_stats=%d, num_in_chan_stats=%d\n",
|
|
pmadapter->idx_chan_stats,
|
|
pmadapter->num_in_chan_stats);
|
|
break;
|
|
}
|
|
pchan_stats->total_networks =
|
|
wlan_le16_to_cpu(pchan_stats->total_networks);
|
|
pchan_stats->cca_scan_duration =
|
|
wlan_le16_to_cpu(pchan_stats->cca_scan_duration);
|
|
pchan_stats->cca_busy_duration =
|
|
wlan_le16_to_cpu(pchan_stats->cca_busy_duration);
|
|
PRINTM(MCMND,
|
|
"chan=%d, noise=%d, total_network=%d scan_duration=%d, busy_duration=%d\n",
|
|
pchan_stats->chan_num, pchan_stats->noise,
|
|
pchan_stats->total_networks,
|
|
pchan_stats->cca_scan_duration,
|
|
pchan_stats->cca_busy_duration);
|
|
memcpy_ext(pmadapter,
|
|
(chan_statistics_t *)&pmadapter
|
|
->pchan_stats[pmadapter->idx_chan_stats],
|
|
pchan_stats, sizeof(chan_statistics_t),
|
|
sizeof(chan_statistics_t));
|
|
pmadapter->idx_chan_stats++;
|
|
pchan_stats++;
|
|
}
|
|
LEAVE();
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* @brief This function will parse a given IE for a given OUI
|
|
*
|
|
* Parse a given WPA/RSN IE to find if it has a given oui in PTK,
|
|
* if no OUI found for PTK it returns 0.
|
|
*
|
|
* @param pbss_desc A pointer to current BSS descriptor
|
|
* @return 0 on failure to find OUI, 1 on success.
|
|
*/
|
|
static t_u8 search_oui_in_ie(mlan_adapter *pmadapter, IEBody *ie_body,
|
|
t_u8 *oui)
|
|
{
|
|
t_u8 count;
|
|
|
|
count = ie_body->PtkCnt[0];
|
|
|
|
ENTER();
|
|
/* There could be multiple OUIs for PTK hence
|
|
* 1) Take the length.
|
|
* 2) Check all the OUIs for AES.
|
|
* 3) If one of them is AES then pass success.
|
|
*/
|
|
while (count) {
|
|
if (!memcmp(pmadapter, ie_body->PtkBody, oui,
|
|
sizeof(ie_body->PtkBody))) {
|
|
LEAVE();
|
|
return MLAN_OUI_PRESENT;
|
|
}
|
|
|
|
--count;
|
|
if (count) {
|
|
ie_body = (IEBody *)((t_u8 *)ie_body +
|
|
sizeof(ie_body->PtkBody));
|
|
}
|
|
}
|
|
|
|
PRINTM(MINFO, "The OUI %x:%x:%x:%x is not found in PTK\n", oui[0],
|
|
oui[1], oui[2], oui[3]);
|
|
LEAVE();
|
|
return MLAN_OUI_NOT_PRESENT;
|
|
}
|
|
|
|
/**
|
|
* @brief This function will pass the correct ie and oui to search_oui_in_ie
|
|
*
|
|
* Check the pbss_desc for appropriate IE and then check if RSN IE has AES
|
|
* OUI in it. If RSN IE does not have AES in PTK then return 0;
|
|
*
|
|
* @param pbss_desc A pointer to current BSS descriptor
|
|
* @return 0 on failure to find AES OUI, 1 on success.
|
|
*/
|
|
static t_u8 is_rsn_oui_present(mlan_adapter *pmadapter,
|
|
BSSDescriptor_t *pbss_desc, t_u32 cipher_suite)
|
|
{
|
|
t_u8 *oui = MNULL;
|
|
IEBody *ie_body = MNULL;
|
|
t_u8 ret = MLAN_OUI_NOT_PRESENT;
|
|
|
|
ENTER();
|
|
if (pbss_desc->prsn_ie &&
|
|
(pbss_desc->prsn_ie->ieee_hdr.element_id == RSN_IE) &&
|
|
(pbss_desc->prsn_ie->ieee_hdr.len > RSN_GTK_OUI_OFFSET)) {
|
|
ie_body = (IEBody *)(((t_u8 *)pbss_desc->prsn_ie->data) +
|
|
RSN_GTK_OUI_OFFSET);
|
|
oui = &rsn_oui[cipher_suite][0];
|
|
ret = search_oui_in_ie(pmadapter, ie_body, oui);
|
|
if (ret) {
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
}
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief This function will pass the correct ie and oui to search_oui_in_ie
|
|
*
|
|
* Check the wpa_ie for appropriate IE and then check if RSN IE has AES
|
|
* OUI in it. If RSN IE does not have AES in PTK then return 0;
|
|
*
|
|
* @param pmadapter A pointer to mlan adapter.
|
|
* @return 0 on failure to find AES OUI, 1 on success.
|
|
*/
|
|
static t_u8 is_rsn_oui_present_in_wpa_ie(mlan_private *pmpriv,
|
|
t_u32 cipher_suite)
|
|
{
|
|
mlan_adapter *pmadapter = pmpriv->adapter;
|
|
t_u8 *oui = MNULL;
|
|
IEBody *ie_body = MNULL;
|
|
IEEEtypes_Generic_t *prsn_ie = MNULL;
|
|
t_u8 ret = MLAN_OUI_NOT_PRESENT;
|
|
|
|
ENTER();
|
|
prsn_ie = (IEEEtypes_Generic_t *)pmpriv->wpa_ie;
|
|
|
|
if (prsn_ie && (prsn_ie->ieee_hdr.element_id == RSN_IE) &&
|
|
(prsn_ie->ieee_hdr.len > RSN_GTK_OUI_OFFSET)) {
|
|
ie_body = (IEBody *)(prsn_ie->data + RSN_GTK_OUI_OFFSET);
|
|
oui = &rsn_oui[cipher_suite][0];
|
|
ret = search_oui_in_ie(pmadapter, ie_body, oui);
|
|
if (ret) {
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief This function will pass the correct ie and oui to search_oui_in_ie
|
|
*
|
|
* Check the pbss_desc for appropriate IE and then check if WPA IE has AES
|
|
* OUI in it. If WPA IE does not have AES in PTK then return 0;
|
|
*
|
|
* @param pbss_desc A pointer to current BSS descriptor
|
|
* @return 0 on failure to find AES OUI, 1 on success.
|
|
*/
|
|
static t_u8 is_wpa_oui_present(mlan_adapter *pmadapter,
|
|
BSSDescriptor_t *pbss_desc, t_u32 cipher_suite)
|
|
{
|
|
t_u8 *oui = MNULL;
|
|
IEBody *ie_body = MNULL;
|
|
t_u8 ret = MLAN_OUI_NOT_PRESENT;
|
|
|
|
ENTER();
|
|
if (((pbss_desc->pwpa_ie) &&
|
|
((*(pbss_desc->pwpa_ie)).vend_hdr.element_id == WPA_IE))) {
|
|
ie_body = (IEBody *)pbss_desc->pwpa_ie->data;
|
|
oui = &wpa_ouis[cipher_suite][0];
|
|
ret = search_oui_in_ie(pmadapter, ie_body, oui);
|
|
if (ret) {
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
}
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief compare config band and a band from the scan result,
|
|
* which is defined by functiion radio_type_to_band(t_u8 radio_type) above
|
|
*
|
|
* @param cfg_band: band configured
|
|
* scan_band: band from scan result
|
|
*
|
|
* @return matched: non-zero. unmatched: 0
|
|
*
|
|
*/
|
|
static t_u8 wlan_is_band_compatible(t_u8 cfg_band, t_u8 scan_band)
|
|
{
|
|
t_u8 band;
|
|
switch (scan_band) {
|
|
case BAND_A:
|
|
band = BAND_A | BAND_AN | BAND_AAC;
|
|
break;
|
|
case BAND_G:
|
|
default:
|
|
band = BAND_B | BAND_G | BAND_GN | BAND_GAC;
|
|
}
|
|
return cfg_band & band;
|
|
}
|
|
|
|
/**
|
|
* @brief This function finds the best SSID in the Scan List
|
|
*
|
|
* Search the scan table for the best SSID that also matches the current
|
|
* adapter network preference (infrastructure or adhoc)
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @return index in BSSID list
|
|
*/
|
|
static t_s32 wlan_find_best_network_in_list(mlan_private *pmpriv)
|
|
{
|
|
mlan_adapter *pmadapter = pmpriv->adapter;
|
|
t_u32 mode = pmpriv->bss_mode;
|
|
t_s32 best_net = -1;
|
|
t_s32 best_rssi = 0;
|
|
t_u32 i;
|
|
|
|
ENTER();
|
|
|
|
PRINTM(MINFO, "Num of BSSIDs = %d\n", pmadapter->num_in_scan_table);
|
|
|
|
for (i = 0; i < pmadapter->num_in_scan_table; i++) {
|
|
switch (mode) {
|
|
case MLAN_BSS_MODE_INFRA:
|
|
case MLAN_BSS_MODE_IBSS:
|
|
if (wlan_is_network_compatible(pmpriv, i, mode) >= 0) {
|
|
if (SCAN_RSSI(pmadapter->pscan_table[i].rssi) >
|
|
best_rssi) {
|
|
best_rssi = SCAN_RSSI(
|
|
pmadapter->pscan_table[i].rssi);
|
|
best_net = i;
|
|
}
|
|
}
|
|
break;
|
|
case MLAN_BSS_MODE_AUTO:
|
|
default:
|
|
if (SCAN_RSSI(pmadapter->pscan_table[i].rssi) >
|
|
best_rssi) {
|
|
best_rssi = SCAN_RSSI(
|
|
pmadapter->pscan_table[i].rssi);
|
|
best_net = i;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
LEAVE();
|
|
return best_net;
|
|
}
|
|
|
|
/**
|
|
* @brief Create a channel list for the driver to scan based on region info
|
|
*
|
|
* Use the driver region/band information to construct a comprehensive list
|
|
* of channels to scan. This routine is used for any scan that is not
|
|
* provided a specific channel list to scan.
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @param puser_scan_in MNULL or pointer to scan configuration parameters
|
|
* @param pscan_chan_list Output parameter: Resulting channel list to scan
|
|
* @param filtered_scan Flag indicating whether or not a BSSID or SSID
|
|
* filter is being sent in the command to firmware. Used to increase the number
|
|
* of channels sent in a scan command and to disable the firmware channel scan
|
|
* filter.
|
|
*
|
|
* @return N/A
|
|
*/
|
|
static t_void wlan_scan_create_channel_list(
|
|
mlan_private *pmpriv, const wlan_user_scan_cfg *puser_scan_in,
|
|
ChanScanParamSet_t *pscan_chan_list, t_u8 filtered_scan)
|
|
{
|
|
mlan_adapter *pmadapter = pmpriv->adapter;
|
|
region_chan_t *pscan_region;
|
|
chan_freq_power_t *cfp;
|
|
t_u32 region_idx;
|
|
t_u32 chan_idx = 0;
|
|
t_u32 next_chan;
|
|
t_u8 scan_type;
|
|
t_u8 radio_type;
|
|
t_u8 band;
|
|
t_u16 scan_dur = 0;
|
|
|
|
ENTER();
|
|
|
|
for (region_idx = 0; region_idx < NELEMENTS(pmadapter->region_channel);
|
|
region_idx++) {
|
|
if (wlan_11d_is_enabled(pmpriv) &&
|
|
pmpriv->media_connected != MTRUE) {
|
|
/* Scan all the supported chan for the first scan */
|
|
if (!pmadapter->universal_channel[region_idx].valid)
|
|
continue;
|
|
pscan_region =
|
|
&pmadapter->universal_channel[region_idx];
|
|
} else {
|
|
if (!pmadapter->region_channel[region_idx].valid)
|
|
continue;
|
|
pscan_region = &pmadapter->region_channel[region_idx];
|
|
}
|
|
|
|
if (puser_scan_in && !puser_scan_in->chan_list[0].chan_number &&
|
|
puser_scan_in->chan_list[0].radio_type & BAND_SPECIFIED) {
|
|
radio_type = puser_scan_in->chan_list[0].radio_type &
|
|
~BAND_SPECIFIED;
|
|
if (!radio_type && (pscan_region->band != BAND_B) &&
|
|
(pscan_region->band != BAND_G))
|
|
continue;
|
|
if (radio_type && (pscan_region->band != BAND_A))
|
|
continue;
|
|
}
|
|
PRINTM(MCMD_D,
|
|
"create_channel_list: region=%d band=%d num_cfp=%d\n",
|
|
pscan_region->region, pscan_region->band,
|
|
pscan_region->num_cfp);
|
|
if ((puser_scan_in &&
|
|
(puser_scan_in->bss_mode == MLAN_SCAN_MODE_IBSS)) ||
|
|
pmpriv->bss_mode == MLAN_BSS_MODE_IBSS)
|
|
band = pmadapter->adhoc_start_band;
|
|
else
|
|
band = pmpriv->config_bands;
|
|
if (!wlan_is_band_compatible(band, pscan_region->band))
|
|
continue;
|
|
for (next_chan = 0; next_chan < pscan_region->num_cfp;
|
|
next_chan++) {
|
|
/* Set the default scan type to the user specified type,
|
|
* will later be changed to passive on a per channel
|
|
* basis if restricted by regulatory requirements (11d
|
|
* or 11h)
|
|
*/
|
|
scan_type = pmadapter->scan_type;
|
|
cfp = pscan_region->pcfp + next_chan;
|
|
if (cfp->dynamic.flags & NXP_CHANNEL_DISABLED)
|
|
continue;
|
|
|
|
if (wlan_is_chan_passive(pmpriv, pscan_region->band,
|
|
(t_u8)cfp->channel)) {
|
|
/* do not send probe requests on this channel */
|
|
scan_type = MLAN_SCAN_TYPE_PASSIVE;
|
|
}
|
|
switch (pscan_region->band) {
|
|
case BAND_A:
|
|
pscan_chan_list[chan_idx].bandcfg.chanBand =
|
|
BAND_5GHZ;
|
|
/* Passive scan on DFS channels */
|
|
if (wlan_11h_radar_detect_required(
|
|
pmpriv, (t_u8)cfp->channel) &&
|
|
scan_type != MLAN_SCAN_TYPE_PASSIVE)
|
|
scan_type =
|
|
MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE;
|
|
break;
|
|
case BAND_B:
|
|
case BAND_G:
|
|
if (wlan_bg_scan_type_is_passive(
|
|
pmpriv, (t_u8)cfp->channel)) {
|
|
scan_type = MLAN_SCAN_TYPE_PASSIVE;
|
|
}
|
|
pscan_chan_list[chan_idx].bandcfg.chanBand =
|
|
BAND_2GHZ;
|
|
break;
|
|
default:
|
|
pscan_chan_list[chan_idx].bandcfg.chanBand =
|
|
BAND_2GHZ;
|
|
break;
|
|
}
|
|
|
|
if (puser_scan_in &&
|
|
puser_scan_in->chan_list[0].scan_time) {
|
|
scan_dur = (t_u16)puser_scan_in->chan_list[0]
|
|
.scan_time;
|
|
} else if (scan_type == MLAN_SCAN_TYPE_PASSIVE ||
|
|
scan_type ==
|
|
MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE) {
|
|
scan_dur = pmadapter->passive_scan_time;
|
|
} else if (filtered_scan) {
|
|
scan_dur = pmadapter->specific_scan_time;
|
|
} else {
|
|
scan_dur = pmadapter->active_scan_time;
|
|
}
|
|
if (scan_type == MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE &&
|
|
pmadapter->passive_to_active_scan ==
|
|
MLAN_PASS_TO_ACT_SCAN_EN) {
|
|
scan_dur = MAX(scan_dur,
|
|
MIN_PASSIVE_TO_ACTIVE_SCAN_TIME);
|
|
pscan_chan_list[chan_idx]
|
|
.chan_scan_mode.passive_to_active_scan =
|
|
MTRUE;
|
|
}
|
|
pscan_chan_list[chan_idx].max_scan_time =
|
|
wlan_cpu_to_le16(scan_dur);
|
|
|
|
if (scan_type == MLAN_SCAN_TYPE_PASSIVE ||
|
|
scan_type == MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE) {
|
|
pscan_chan_list[chan_idx]
|
|
.chan_scan_mode.passive_scan = MTRUE;
|
|
pscan_chan_list[chan_idx]
|
|
.chan_scan_mode.hidden_ssid_report =
|
|
MTRUE;
|
|
} else {
|
|
pscan_chan_list[chan_idx]
|
|
.chan_scan_mode.passive_scan = MFALSE;
|
|
}
|
|
|
|
pscan_chan_list[chan_idx].chan_number =
|
|
(t_u8)cfp->channel;
|
|
PRINTM(MCMD_D,
|
|
"chan=%d, mode=%d, passive_to_active=%d\n",
|
|
pscan_chan_list[chan_idx].chan_number,
|
|
pscan_chan_list[chan_idx]
|
|
.chan_scan_mode.passive_scan,
|
|
pscan_chan_list[chan_idx]
|
|
.chan_scan_mode.passive_to_active_scan);
|
|
chan_idx++;
|
|
}
|
|
}
|
|
|
|
LEAVE();
|
|
}
|
|
|
|
/**
|
|
* @brief Add WPS IE to probe request frame
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @param pptlv_out A pointer to TLV to fill in
|
|
*
|
|
* @return N/A
|
|
*/
|
|
static void wlan_add_wps_probe_request_ie(mlan_private *pmpriv,
|
|
t_u8 **pptlv_out)
|
|
{
|
|
MrvlIEtypesHeader_t *tlv;
|
|
|
|
ENTER();
|
|
|
|
if (pmpriv->wps.wps_ie.vend_hdr.len) {
|
|
tlv = (MrvlIEtypesHeader_t *)*pptlv_out;
|
|
tlv->type = wlan_cpu_to_le16(VENDOR_SPECIFIC_221);
|
|
tlv->len = wlan_cpu_to_le16(pmpriv->wps.wps_ie.vend_hdr.len);
|
|
*pptlv_out += sizeof(MrvlIEtypesHeader_t);
|
|
memcpy_ext(pmpriv->adapter, *pptlv_out,
|
|
pmpriv->wps.wps_ie.vend_hdr.oui,
|
|
pmpriv->wps.wps_ie.vend_hdr.len,
|
|
pmpriv->wps.wps_ie.vend_hdr.len);
|
|
*pptlv_out += (pmpriv->wps.wps_ie.vend_hdr.len +
|
|
sizeof(MrvlIEtypesHeader_t));
|
|
}
|
|
LEAVE();
|
|
}
|
|
|
|
/**
|
|
* @brief Construct and send multiple scan config commands to the firmware
|
|
*
|
|
* Previous routines have created a wlan_scan_cmd_config with any requested
|
|
* TLVs. This function splits the channel TLV into max_chan_per_scan lists
|
|
* and sends the portion of the channel TLV along with the other TLVs
|
|
* to the wlan_cmd routines for execution in the firmware.
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @param pioctl_buf A pointer to MLAN IOCTL Request buffer
|
|
* @param max_chan_per_scan Maximum number channels to be included in each
|
|
* scan command sent to firmware
|
|
* @param filtered_scan Flag indicating whether or not a BSSID or SSID
|
|
* filter is being used for the firmware command
|
|
* scan command sent to firmware
|
|
* @param pscan_cfg_out Scan configuration used for this scan.
|
|
* @param pchan_tlv_out Pointer in the pscan_cfg_out where the channel TLV
|
|
* should start. This is past any other TLVs that
|
|
* must be sent down in each firmware command.
|
|
* @param pscan_chan_list List of channels to scan in max_chan_per_scan
|
|
* segments
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or error return otherwise
|
|
*/
|
|
static mlan_status
|
|
wlan_scan_channel_list(mlan_private *pmpriv, t_void *pioctl_buf,
|
|
t_u32 max_chan_per_scan, t_u8 filtered_scan,
|
|
wlan_scan_cmd_config *pscan_cfg_out,
|
|
MrvlIEtypes_ChanListParamSet_t *pchan_tlv_out,
|
|
ChanScanParamSet_t *pscan_chan_list)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_adapter *pmadapter = pmpriv->adapter;
|
|
ChanScanParamSet_t *ptmp_chan_list;
|
|
ChanScanParamSet_t *pstart_chan;
|
|
pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *)pioctl_buf;
|
|
t_u8 *pchan_tlv_out_temp = MNULL;
|
|
t_u8 *ptlv_temp = MNULL;
|
|
t_bool foundJPch14 = MFALSE;
|
|
t_u16 tlv_buf_len = 0;
|
|
t_u32 tlv_idx;
|
|
t_u32 total_scan_time;
|
|
t_u32 done_early;
|
|
t_u32 cmd_no;
|
|
t_u32 first_chan = 1;
|
|
mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks;
|
|
|
|
ENTER();
|
|
|
|
if (!pscan_cfg_out || !pchan_tlv_out || !pscan_chan_list) {
|
|
PRINTM(MINFO, "Scan: Null detect: %p, %p, %p\n", pscan_cfg_out,
|
|
pchan_tlv_out, pscan_chan_list);
|
|
if (pioctl_req)
|
|
pioctl_req->status_code = MLAN_ERROR_CMD_SCAN_FAIL;
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
if (!pscan_chan_list->chan_number) {
|
|
PRINTM(MERROR, "Scan: No channel configured\n");
|
|
if (pioctl_req)
|
|
pioctl_req->status_code = MLAN_ERROR_CMD_SCAN_FAIL;
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
/* check expiry before preparing scan list - may affect blacklist */
|
|
wlan_11h_get_csa_closed_channel(pmpriv);
|
|
|
|
pchan_tlv_out->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
|
|
|
|
/* Set the temp channel struct pointer to the start of the desired list
|
|
*/
|
|
ptmp_chan_list = pscan_chan_list;
|
|
|
|
/*
|
|
* Loop through the desired channel list, sending a new firmware scan
|
|
* commands for each max_chan_per_scan channels (or for 1,6,11
|
|
* individually if configured accordingly)
|
|
*/
|
|
while (ptmp_chan_list->chan_number) {
|
|
tlv_idx = 0;
|
|
total_scan_time = 0;
|
|
pchan_tlv_out->header.len = 0;
|
|
pstart_chan = ptmp_chan_list;
|
|
done_early = MFALSE;
|
|
|
|
/*
|
|
* Construct the Channel TLV for the scan command. Continue to
|
|
* insert channel TLVs until:
|
|
* - the tlv_idx hits the maximum configured per scan command
|
|
* - the next channel to insert is 0 (end of desired
|
|
* channel list)
|
|
* - done_early is set (controlling individual
|
|
* scanning of 1,6,11)
|
|
*/
|
|
while (tlv_idx < max_chan_per_scan &&
|
|
ptmp_chan_list->chan_number && !done_early) {
|
|
if (wlan_is_chan_blacklisted(
|
|
pmpriv,
|
|
radio_type_to_band(
|
|
ptmp_chan_list->bandcfg.chanBand),
|
|
ptmp_chan_list->chan_number) ||
|
|
wlan_is_chan_disabled(
|
|
pmpriv,
|
|
radio_type_to_band(
|
|
ptmp_chan_list->bandcfg.chanBand),
|
|
ptmp_chan_list->chan_number)) {
|
|
PRINTM(MCMND, "Block scan chan = %d\n",
|
|
ptmp_chan_list->chan_number);
|
|
ptmp_chan_list++;
|
|
continue;
|
|
}
|
|
|
|
if (first_chan) {
|
|
ptmp_chan_list->chan_scan_mode.first_chan =
|
|
MTRUE;
|
|
first_chan = 0;
|
|
}
|
|
|
|
PRINTM(MCMD_D,
|
|
"Scan: Chan(%3d), bandcfg(%x), Mode(%d,%d), Dur(%d)\n",
|
|
ptmp_chan_list->chan_number,
|
|
ptmp_chan_list->bandcfg,
|
|
ptmp_chan_list->chan_scan_mode.passive_scan,
|
|
ptmp_chan_list->chan_scan_mode.disable_chan_filt,
|
|
wlan_le16_to_cpu(ptmp_chan_list->max_scan_time));
|
|
|
|
if (foundJPch14 == MTRUE) {
|
|
foundJPch14 = MFALSE;
|
|
/* Restore the TLV buffer */
|
|
pchan_tlv_out =
|
|
(MrvlIEtypes_ChanListParamSet_t *)
|
|
pchan_tlv_out_temp;
|
|
pchan_tlv_out->header.type =
|
|
wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
|
|
pchan_tlv_out->header.len = 0;
|
|
if (ptlv_temp) {
|
|
memcpy_ext(pmadapter,
|
|
pscan_cfg_out->tlv_buf,
|
|
ptlv_temp, tlv_buf_len,
|
|
tlv_buf_len);
|
|
pcb->moal_mfree(pmadapter->pmoal_handle,
|
|
ptlv_temp);
|
|
ptlv_temp = MNULL;
|
|
}
|
|
}
|
|
|
|
/* Special Case: For Japan, Scan on CH14 for 11G rates
|
|
is not allowed
|
|
Hence Rates TLV needs to be updated to support only
|
|
11B rates */
|
|
if ((pmadapter->region_code == COUNTRY_CODE_JP_40 ||
|
|
pmadapter->region_code == COUNTRY_CODE_JP_FF) &&
|
|
(ptmp_chan_list->chan_number == 14) &&
|
|
(pmadapter->ext_scan_type != EXT_SCAN_ENHANCE)) {
|
|
t_u8 *ptlv_pos = pscan_cfg_out->tlv_buf;
|
|
t_u16 old_ratetlv_len, new_ratetlv_len;
|
|
MrvlIEtypesHeader_t *header;
|
|
MrvlIEtypes_RatesParamSet_t *prates_tlv;
|
|
|
|
/* Preserve the current TLV buffer */
|
|
ret = pcb->moal_malloc(
|
|
pmadapter->pmoal_handle,
|
|
MAX_SCAN_CFG_ALLOC - CHAN_TLV_MAX_SIZE,
|
|
MLAN_MEM_DEF, (t_u8 **)&ptlv_temp);
|
|
if (ret != MLAN_STATUS_SUCCESS || !ptlv_temp) {
|
|
PRINTM(MERROR,
|
|
"Memory allocation for pscan_cfg_out failed!\n");
|
|
if (pioctl_req)
|
|
pioctl_req->status_code =
|
|
MLAN_ERROR_NO_MEM;
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
pchan_tlv_out_temp = (t_u8 *)pchan_tlv_out;
|
|
tlv_buf_len = (t_u32)(pchan_tlv_out_temp -
|
|
pscan_cfg_out->tlv_buf);
|
|
memcpy_ext(pmadapter, ptlv_temp, ptlv_pos,
|
|
tlv_buf_len,
|
|
MAX_SCAN_CFG_ALLOC -
|
|
CHAN_TLV_MAX_SIZE);
|
|
|
|
/* Search for Rates TLV */
|
|
while ((!foundJPch14) &&
|
|
(ptlv_pos < pchan_tlv_out_temp)) {
|
|
header =
|
|
(MrvlIEtypesHeader_t *)ptlv_pos;
|
|
if (header->type ==
|
|
wlan_cpu_to_le16(TLV_TYPE_RATES))
|
|
foundJPch14 = MTRUE;
|
|
else
|
|
ptlv_pos +=
|
|
(sizeof(MrvlIEtypesHeader_t) +
|
|
wlan_le16_to_cpu(
|
|
header->len));
|
|
}
|
|
|
|
if (foundJPch14) {
|
|
/* Update the TLV buffer with *new*
|
|
* Rates TLV and rearrange remaining TLV
|
|
* buffer*/
|
|
prates_tlv =
|
|
(MrvlIEtypes_RatesParamSet_t *)
|
|
ptlv_pos;
|
|
old_ratetlv_len =
|
|
sizeof(MrvlIEtypesHeader_t) +
|
|
wlan_le16_to_cpu(
|
|
prates_tlv->header.len);
|
|
|
|
prates_tlv->header.len = wlan_copy_rates(
|
|
prates_tlv->rates, 0,
|
|
SupportedRates_B,
|
|
sizeof(SupportedRates_B));
|
|
new_ratetlv_len =
|
|
sizeof(MrvlIEtypesHeader_t) +
|
|
prates_tlv->header.len;
|
|
prates_tlv->header.len =
|
|
wlan_cpu_to_le16(
|
|
prates_tlv->header.len);
|
|
|
|
memmove(pmadapter,
|
|
ptlv_pos + new_ratetlv_len,
|
|
ptlv_pos + old_ratetlv_len,
|
|
(t_u32)(pchan_tlv_out_temp -
|
|
(ptlv_pos +
|
|
old_ratetlv_len)));
|
|
pchan_tlv_out =
|
|
(MrvlIEtypes_ChanListParamSet_t
|
|
*)(pchan_tlv_out_temp -
|
|
(old_ratetlv_len -
|
|
new_ratetlv_len));
|
|
pchan_tlv_out->header.type =
|
|
wlan_cpu_to_le16(
|
|
TLV_TYPE_CHANLIST);
|
|
pchan_tlv_out->header.len = 0;
|
|
}
|
|
}
|
|
|
|
/* Copy the current channel TLV to the command being
|
|
* prepared */
|
|
memcpy_ext(pmadapter,
|
|
pchan_tlv_out->chan_scan_param + tlv_idx,
|
|
ptmp_chan_list,
|
|
sizeof(pchan_tlv_out->chan_scan_param),
|
|
sizeof(pchan_tlv_out->chan_scan_param));
|
|
|
|
/* Increment the TLV header length by the size appended
|
|
*/
|
|
pchan_tlv_out->header.len +=
|
|
sizeof(pchan_tlv_out->chan_scan_param);
|
|
|
|
/*
|
|
* The tlv buffer length is set to the number of
|
|
* bytes of the between the channel tlv pointer
|
|
* and the start of the tlv buffer. This
|
|
* compensates for any TLVs that were appended
|
|
* before the channel list.
|
|
*/
|
|
pscan_cfg_out->tlv_buf_len = (t_u32)(
|
|
(t_u8 *)pchan_tlv_out - pscan_cfg_out->tlv_buf);
|
|
|
|
/* Add the size of the channel tlv header and the data
|
|
* length */
|
|
pscan_cfg_out->tlv_buf_len +=
|
|
(sizeof(pchan_tlv_out->header) +
|
|
pchan_tlv_out->header.len);
|
|
|
|
/* Increment the index to the channel tlv we are
|
|
* constructing */
|
|
tlv_idx++;
|
|
|
|
/* Count the total scan time per command */
|
|
total_scan_time +=
|
|
wlan_le16_to_cpu(ptmp_chan_list->max_scan_time);
|
|
|
|
done_early = MFALSE;
|
|
|
|
/*
|
|
* Stop the loop if the *current* channel is in the
|
|
* 1,6,11 set and we are not filtering on a BSSID or
|
|
* SSID.
|
|
*/
|
|
if (!filtered_scan &&
|
|
(ptmp_chan_list->chan_number == 1 ||
|
|
ptmp_chan_list->chan_number == 6 ||
|
|
ptmp_chan_list->chan_number == 11)) {
|
|
done_early = MTRUE;
|
|
}
|
|
|
|
/*
|
|
* Stop the loop if the *current* channel is 14
|
|
* and region code is Japan (0x40 or 0xFF)
|
|
*/
|
|
if ((pmadapter->region_code == COUNTRY_CODE_JP_40 ||
|
|
pmadapter->region_code == COUNTRY_CODE_JP_FF) &&
|
|
(ptmp_chan_list->chan_number == 14)) {
|
|
done_early = MTRUE;
|
|
}
|
|
|
|
/* Increment the tmp pointer to the next channel to be
|
|
* scanned */
|
|
ptmp_chan_list++;
|
|
|
|
/*
|
|
* Stop the loop if the *next* channel is in the 1,6,11
|
|
* set. This will cause it to be the only channel
|
|
* scanned on the next interation
|
|
*/
|
|
if (!filtered_scan &&
|
|
(ptmp_chan_list->chan_number == 1 ||
|
|
ptmp_chan_list->chan_number == 6 ||
|
|
ptmp_chan_list->chan_number == 11)) {
|
|
done_early = MTRUE;
|
|
}
|
|
|
|
/*
|
|
* Stop the loop if the *next* channel is 14
|
|
* and region code is Japan (0x40 or 0xFF)
|
|
*/
|
|
if ((pmadapter->region_code == COUNTRY_CODE_JP_40 ||
|
|
pmadapter->region_code == COUNTRY_CODE_JP_FF) &&
|
|
(ptmp_chan_list->chan_number == 14)) {
|
|
done_early = MTRUE;
|
|
}
|
|
if (pmadapter->ext_scan && pmadapter->ext_scan_enh &&
|
|
pmadapter->ext_scan_type == EXT_SCAN_ENHANCE)
|
|
done_early = MFALSE;
|
|
}
|
|
|
|
/* The total scan time should be less than scan command timeout
|
|
* value */
|
|
if (total_scan_time > MRVDRV_MAX_TOTAL_SCAN_TIME) {
|
|
PRINTM(MMSG,
|
|
"Total scan time %d ms is over limit (%d ms), scan skipped\n",
|
|
total_scan_time, MRVDRV_MAX_TOTAL_SCAN_TIME);
|
|
if (pioctl_req)
|
|
pioctl_req->status_code =
|
|
MLAN_ERROR_CMD_SCAN_FAIL;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
pchan_tlv_out->header.len =
|
|
wlan_cpu_to_le16(pchan_tlv_out->header.len);
|
|
|
|
pmadapter->pscan_channels = pstart_chan;
|
|
|
|
/* Send the scan command to the firmware with the specified cfg
|
|
*/
|
|
if (pmadapter->ext_scan
|
|
#ifdef USB8801
|
|
&& !IS_USB8801(pmadapter->card_type)
|
|
#endif
|
|
)
|
|
cmd_no = HostCmd_CMD_802_11_SCAN_EXT;
|
|
else
|
|
cmd_no = HostCmd_CMD_802_11_SCAN;
|
|
ret = wlan_prepare_cmd(pmpriv, cmd_no, HostCmd_ACT_GEN_SET, 0,
|
|
MNULL, pscan_cfg_out);
|
|
if (ret)
|
|
break;
|
|
}
|
|
|
|
LEAVE();
|
|
|
|
if (ptlv_temp)
|
|
pcb->moal_mfree(pmadapter->pmoal_handle, ptlv_temp);
|
|
|
|
if (ret)
|
|
return MLAN_STATUS_FAILURE;
|
|
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief Construct a wlan_scan_cmd_config structure to use in scan commands
|
|
*
|
|
* Application layer or other functions can invoke wlan_scan_networks
|
|
* with a scan configuration supplied in a wlan_ioctl_user_scan_cfg struct.
|
|
* This structure is used as the basis of one or many wlan_scan_cmd_config
|
|
* commands that are sent to the command processing module and sent to
|
|
* firmware.
|
|
*
|
|
* Create a wlan_scan_cmd_config based on the following user supplied
|
|
* parameters (if present):
|
|
* - SSID filter
|
|
* - BSSID filter
|
|
* - Number of Probes to be sent
|
|
* - Channel list
|
|
*
|
|
* If the SSID or BSSID filter is not present, disable/clear the filter.
|
|
* If the number of probes is not set, use the adapter default setting
|
|
* Qualify the channel
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @param puser_scan_in MNULL or pointer to scan config parameters
|
|
* @param pscan_cfg_out Output parameter: Resulting scan configuration
|
|
* @param ppchan_list_out Output parameter: Pointer to the start of the
|
|
* channel TLV portion of the output scan config
|
|
* @param pscan_chan_list Output parameter: Pointer to the resulting
|
|
* channel list to scan
|
|
* @param pmax_chan_per_scan Output parameter: Number of channels to scan for
|
|
* each issuance of the firmware scan command
|
|
* @param pfiltered_scan Output parameter: Flag indicating whether or not
|
|
* a BSSID or SSID filter is being sent in the
|
|
* command to firmware. Used to increase the number
|
|
* of channels sent in a scan command and to
|
|
* disable the firmware channel scan filter.
|
|
* @param pscan_current_only Output parameter: Flag indicating whether or not
|
|
* we are only scanning our current active channel
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_scan_setup_scan_config(
|
|
mlan_private *pmpriv, wlan_user_scan_cfg *puser_scan_in,
|
|
wlan_scan_cmd_config *pscan_cfg_out,
|
|
MrvlIEtypes_ChanListParamSet_t **ppchan_list_out,
|
|
ChanScanParamSet_t *pscan_chan_list, t_u8 *pmax_chan_per_scan,
|
|
t_u8 *pfiltered_scan, t_u8 *pscan_current_only)
|
|
{
|
|
mlan_adapter *pmadapter = pmpriv->adapter;
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
MrvlIEtypes_NumProbes_t *pnum_probes_tlv;
|
|
MrvlIEtypes_WildCardSsIdParamSet_t *pwildcard_ssid_tlv;
|
|
MrvlIEtypes_RatesParamSet_t *prates_tlv;
|
|
MrvlIEtypes_Bssid_List_t *pbssid_tlv;
|
|
|
|
const t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = {0, 0, 0, 0, 0, 0};
|
|
t_u8 *ptlv_pos;
|
|
t_u32 num_probes;
|
|
t_u32 ssid_len;
|
|
t_u32 chan_idx;
|
|
t_u32 chan_list_idx = 0;
|
|
t_u32 scan_type;
|
|
t_u16 scan_dur;
|
|
t_u8 channel;
|
|
t_u8 radio_type;
|
|
t_u32 ssid_idx;
|
|
t_u8 ssid_filter;
|
|
WLAN_802_11_RATES rates;
|
|
t_u32 rates_size;
|
|
MrvlIETypes_HTCap_t *pht_cap;
|
|
|
|
MrvlIETypes_VHTCap_t *pvht_cap;
|
|
MrvlIEtypes_ScanChanGap_t *pscan_gap_tlv;
|
|
MrvlIEtypes_BssMode_t *pbss_mode;
|
|
MrvlIEtypes_Extension_t *phe_cap;
|
|
t_u16 len = 0;
|
|
|
|
ENTER();
|
|
|
|
/* The tlv_buf_len is calculated for each scan command. The TLVs added
|
|
* in this routine will be preserved since the routine that sends
|
|
* the command will append channelTLVs at *ppchan_list_out. The
|
|
* difference between the *ppchan_list_out and the tlv_buf start will
|
|
* be used to calculate the size of anything we add in this routine.
|
|
*/
|
|
pscan_cfg_out->tlv_buf_len = 0;
|
|
|
|
/* Running tlv pointer. Assigned to ppchan_list_out at end of function
|
|
* so later routines know where channels can be added to the command
|
|
* buf
|
|
*/
|
|
ptlv_pos = pscan_cfg_out->tlv_buf;
|
|
|
|
/* Initialize the scan as un-filtered; the flag is later set to
|
|
* TRUE below if a SSID or BSSID filter is sent in the command
|
|
*/
|
|
*pfiltered_scan = MFALSE;
|
|
|
|
/* Initialize the scan as not being only on the current channel. If
|
|
* the channel list is customized, only contains one channel, and
|
|
* is the active channel, this is set true and data flow is not
|
|
* halted.
|
|
*/
|
|
*pscan_current_only = MFALSE;
|
|
|
|
if (puser_scan_in) {
|
|
ssid_filter = MFALSE;
|
|
|
|
/* Set the bss type scan filter, use Adapter setting if unset */
|
|
pscan_cfg_out->bss_mode =
|
|
(puser_scan_in->bss_mode ?
|
|
(t_u8)puser_scan_in->bss_mode :
|
|
(t_u8)pmadapter->scan_mode);
|
|
|
|
/* Set the number of probes to send, use Adapter setting if
|
|
* unset */
|
|
num_probes =
|
|
(puser_scan_in->num_probes ? puser_scan_in->num_probes :
|
|
pmadapter->scan_probes);
|
|
/*
|
|
* Set the BSSID filter to the incoming configuration,
|
|
* if non-zero. If not set, it will remain disabled
|
|
* (all zeros).
|
|
*/
|
|
memcpy_ext(pmadapter, pscan_cfg_out->specific_bssid,
|
|
puser_scan_in->specific_bssid,
|
|
sizeof(pscan_cfg_out->specific_bssid),
|
|
sizeof(pscan_cfg_out->specific_bssid));
|
|
|
|
if (pmadapter->ext_scan) {
|
|
if (puser_scan_in->bssid_num) {
|
|
pbssid_tlv =
|
|
(MrvlIEtypes_Bssid_List_t *)ptlv_pos;
|
|
pbssid_tlv->header.type = TLV_TYPE_BSSID;
|
|
pbssid_tlv->header.len = wlan_cpu_to_le16(
|
|
MLAN_MAC_ADDR_LENGTH *
|
|
puser_scan_in->bssid_num);
|
|
memcpy_ext(pmadapter, pbssid_tlv->bssid,
|
|
puser_scan_in->bssid_list,
|
|
MLAN_MAC_ADDR_LENGTH *
|
|
puser_scan_in->bssid_num,
|
|
MLAN_MAC_ADDR_LENGTH *
|
|
puser_scan_in->bssid_num);
|
|
ptlv_pos += sizeof(MrvlIEtypesHeader_t) +
|
|
MLAN_MAC_ADDR_LENGTH *
|
|
puser_scan_in->bssid_num;
|
|
DBG_HEXDUMP(
|
|
MCMD_D, "scan bssid filter", pbssid_tlv,
|
|
sizeof(MrvlIEtypesHeader_t) +
|
|
MLAN_MAC_ADDR_LENGTH *
|
|
puser_scan_in
|
|
->bssid_num);
|
|
} else if (memcmp(pmadapter,
|
|
pscan_cfg_out->specific_bssid,
|
|
&zero_mac, sizeof(zero_mac))) {
|
|
pbssid_tlv =
|
|
(MrvlIEtypes_Bssid_List_t *)ptlv_pos;
|
|
pbssid_tlv->header.type = TLV_TYPE_BSSID;
|
|
pbssid_tlv->header.len =
|
|
wlan_cpu_to_le16(MLAN_MAC_ADDR_LENGTH);
|
|
memcpy_ext(pmadapter, pbssid_tlv->bssid,
|
|
puser_scan_in->specific_bssid,
|
|
MLAN_MAC_ADDR_LENGTH,
|
|
MLAN_MAC_ADDR_LENGTH);
|
|
ptlv_pos += sizeof(MrvlIEtypes_Bssid_List_t);
|
|
}
|
|
}
|
|
|
|
for (ssid_idx = 0;
|
|
((ssid_idx < NELEMENTS(puser_scan_in->ssid_list)) &&
|
|
(*puser_scan_in->ssid_list[ssid_idx].ssid ||
|
|
puser_scan_in->ssid_list[ssid_idx].max_len));
|
|
ssid_idx++) {
|
|
ssid_len = wlan_strlen(
|
|
(char *)puser_scan_in->ssid_list[ssid_idx].ssid);
|
|
|
|
pwildcard_ssid_tlv =
|
|
(MrvlIEtypes_WildCardSsIdParamSet_t *)ptlv_pos;
|
|
pwildcard_ssid_tlv->header.type =
|
|
wlan_cpu_to_le16(TLV_TYPE_WILDCARDSSID);
|
|
pwildcard_ssid_tlv->header.len = (t_u16)(
|
|
ssid_len +
|
|
sizeof(pwildcard_ssid_tlv->max_ssid_length));
|
|
pwildcard_ssid_tlv->max_ssid_length =
|
|
puser_scan_in->ssid_list[ssid_idx].max_len;
|
|
|
|
memcpy_ext(pmadapter, pwildcard_ssid_tlv->ssid,
|
|
puser_scan_in->ssid_list[ssid_idx].ssid,
|
|
ssid_len, MLAN_MAX_SSID_LENGTH);
|
|
|
|
ptlv_pos += (sizeof(pwildcard_ssid_tlv->header) +
|
|
pwildcard_ssid_tlv->header.len);
|
|
|
|
pwildcard_ssid_tlv->header.len = wlan_cpu_to_le16(
|
|
pwildcard_ssid_tlv->header.len);
|
|
|
|
PRINTM(MINFO, "Scan: ssid_list[%d]: %s, %d\n", ssid_idx,
|
|
pwildcard_ssid_tlv->ssid,
|
|
pwildcard_ssid_tlv->max_ssid_length);
|
|
|
|
if (ssid_len) {
|
|
ssid_filter = MTRUE;
|
|
if (!puser_scan_in->ssid_list[ssid_idx].max_len) {
|
|
PRINTM(MCMND, "user scan: %s\n",
|
|
pwildcard_ssid_tlv->ssid);
|
|
puser_scan_in->ssid_filter = MTRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* The default number of channels sent in the command is low to
|
|
* ensure the response buffer from the firmware does not
|
|
* truncate scan results. That is not an issue with an SSID or
|
|
* BSSID filter applied to the scan results in the firmware.
|
|
*/
|
|
if ((ssid_idx && ssid_filter) ||
|
|
memcmp(pmadapter, pscan_cfg_out->specific_bssid, &zero_mac,
|
|
sizeof(zero_mac))) {
|
|
*pfiltered_scan = MTRUE;
|
|
}
|
|
|
|
} else {
|
|
pscan_cfg_out->bss_mode = (t_u8)pmadapter->scan_mode;
|
|
num_probes = pmadapter->scan_probes;
|
|
}
|
|
|
|
/*
|
|
* If a specific BSSID or SSID is used, the number of channels in
|
|
* the scan command will be increased to the absolute maximum.
|
|
*/
|
|
if (*pfiltered_scan)
|
|
*pmax_chan_per_scan = MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN;
|
|
else
|
|
*pmax_chan_per_scan = MRVDRV_CHANNELS_PER_SCAN_CMD;
|
|
|
|
if (puser_scan_in) {
|
|
if (puser_scan_in->scan_chan_gap) {
|
|
*pmax_chan_per_scan =
|
|
MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN;
|
|
PRINTM(MCMND, "Scan: channel gap = 0x%x\n",
|
|
puser_scan_in->scan_chan_gap);
|
|
pscan_gap_tlv = (MrvlIEtypes_ScanChanGap_t *)ptlv_pos;
|
|
pscan_gap_tlv->header.type =
|
|
wlan_cpu_to_le16(TLV_TYPE_SCAN_CHANNEL_GAP);
|
|
pscan_gap_tlv->header.len = sizeof(pscan_gap_tlv->gap);
|
|
pscan_gap_tlv->gap = wlan_cpu_to_le16(
|
|
(t_u16)puser_scan_in->scan_chan_gap);
|
|
ptlv_pos += sizeof(pscan_gap_tlv->header) +
|
|
pscan_gap_tlv->header.len;
|
|
pscan_gap_tlv->header.len =
|
|
wlan_cpu_to_le16(pscan_gap_tlv->header.len);
|
|
}
|
|
} else if (pmadapter->scan_chan_gap) {
|
|
*pmax_chan_per_scan = MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN;
|
|
PRINTM(MCMND, "Scan: channel gap = 0x%x\n",
|
|
pmadapter->scan_chan_gap);
|
|
pscan_gap_tlv = (MrvlIEtypes_ScanChanGap_t *)ptlv_pos;
|
|
pscan_gap_tlv->header.type =
|
|
wlan_cpu_to_le16(TLV_TYPE_SCAN_CHANNEL_GAP);
|
|
pscan_gap_tlv->header.len = sizeof(pscan_gap_tlv->gap);
|
|
pscan_gap_tlv->gap =
|
|
wlan_cpu_to_le16((t_u16)pmadapter->scan_chan_gap);
|
|
ptlv_pos += sizeof(pscan_gap_tlv->header) +
|
|
pscan_gap_tlv->header.len;
|
|
}
|
|
if (pmadapter->ext_scan) {
|
|
pbss_mode = (MrvlIEtypes_BssMode_t *)ptlv_pos;
|
|
pbss_mode->header.type = wlan_cpu_to_le16(TLV_TYPE_BSS_MODE);
|
|
pbss_mode->header.len = sizeof(pbss_mode->bss_mode);
|
|
pbss_mode->bss_mode = pscan_cfg_out->bss_mode;
|
|
ptlv_pos += sizeof(pbss_mode->header) + pbss_mode->header.len;
|
|
pbss_mode->header.len = wlan_cpu_to_le16(pbss_mode->header.len);
|
|
if (pmadapter->ext_scan_enh) {
|
|
if (puser_scan_in) {
|
|
if (puser_scan_in->ext_scan_type ==
|
|
EXT_SCAN_ENHANCE)
|
|
pmadapter->ext_scan_type =
|
|
EXT_SCAN_ENHANCE;
|
|
else
|
|
pmadapter->ext_scan_type =
|
|
EXT_SCAN_DEFAULT;
|
|
} else if (pmadapter->ext_scan == EXT_SCAN_TYPE_ENH)
|
|
pmadapter->ext_scan_type = EXT_SCAN_ENHANCE;
|
|
else
|
|
pmadapter->ext_scan_type = EXT_SCAN_DEFAULT;
|
|
if (pmadapter->ext_scan_type == EXT_SCAN_ENHANCE)
|
|
*pmax_chan_per_scan =
|
|
MRVDRV_MAX_CHANNELS_PER_SCAN;
|
|
}
|
|
}
|
|
/* If the input config or adapter has the number of Probes set, add tlv
|
|
*/
|
|
if (num_probes) {
|
|
PRINTM(MINFO, "Scan: num_probes = %d\n", num_probes);
|
|
|
|
pnum_probes_tlv = (MrvlIEtypes_NumProbes_t *)ptlv_pos;
|
|
pnum_probes_tlv->header.type =
|
|
wlan_cpu_to_le16(TLV_TYPE_NUMPROBES);
|
|
pnum_probes_tlv->header.len =
|
|
sizeof(pnum_probes_tlv->num_probes);
|
|
pnum_probes_tlv->num_probes =
|
|
wlan_cpu_to_le16((t_u16)num_probes);
|
|
|
|
ptlv_pos += sizeof(pnum_probes_tlv->header) +
|
|
pnum_probes_tlv->header.len;
|
|
|
|
pnum_probes_tlv->header.len =
|
|
wlan_cpu_to_le16(pnum_probes_tlv->header.len);
|
|
}
|
|
|
|
/* Append rates tlv */
|
|
memset(pmadapter, rates, 0, sizeof(rates));
|
|
|
|
rates_size = wlan_get_supported_rates(
|
|
pmpriv, pmpriv->bss_mode,
|
|
(pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) ?
|
|
pmpriv->config_bands :
|
|
pmadapter->adhoc_start_band,
|
|
rates);
|
|
|
|
prates_tlv = (MrvlIEtypes_RatesParamSet_t *)ptlv_pos;
|
|
prates_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_RATES);
|
|
prates_tlv->header.len = wlan_cpu_to_le16((t_u16)rates_size);
|
|
memcpy_ext(pmadapter, prates_tlv->rates, rates, rates_size, rates_size);
|
|
ptlv_pos += sizeof(prates_tlv->header) + rates_size;
|
|
|
|
PRINTM(MINFO, "SCAN_CMD: Rates size = %d\n", rates_size);
|
|
|
|
if (ISSUPP_11NENABLED(pmpriv->adapter->fw_cap_info) &&
|
|
(pmpriv->config_bands & BAND_GN ||
|
|
pmpriv->config_bands & BAND_AN)) {
|
|
pht_cap = (MrvlIETypes_HTCap_t *)ptlv_pos;
|
|
memset(pmadapter, pht_cap, 0, sizeof(MrvlIETypes_HTCap_t));
|
|
pht_cap->header.type = wlan_cpu_to_le16(HT_CAPABILITY);
|
|
pht_cap->header.len = sizeof(HTCap_t);
|
|
wlan_fill_ht_cap_tlv(pmpriv, pht_cap, pmpriv->config_bands,
|
|
MTRUE);
|
|
HEXDUMP("SCAN: HT_CAPABILITIES IE", (t_u8 *)pht_cap,
|
|
sizeof(MrvlIETypes_HTCap_t));
|
|
ptlv_pos += sizeof(MrvlIETypes_HTCap_t);
|
|
pht_cap->header.len = wlan_cpu_to_le16(pht_cap->header.len);
|
|
}
|
|
|
|
if (ISSUPP_11ACENABLED(pmpriv->adapter->fw_cap_info) &&
|
|
(pmpriv->config_bands & BAND_AAC)) {
|
|
pvht_cap = (MrvlIETypes_VHTCap_t *)ptlv_pos;
|
|
memset(pmadapter, pvht_cap, 0, sizeof(MrvlIETypes_VHTCap_t));
|
|
pvht_cap->header.type = wlan_cpu_to_le16(VHT_CAPABILITY);
|
|
pvht_cap->header.len = sizeof(VHT_capa_t);
|
|
wlan_fill_vht_cap_tlv(pmpriv, pvht_cap, pmpriv->config_bands,
|
|
MFALSE, MFALSE);
|
|
HEXDUMP("SCAN: VHT_CAPABILITIES IE", (t_u8 *)pvht_cap,
|
|
sizeof(MrvlIETypes_VHTCap_t));
|
|
ptlv_pos += sizeof(MrvlIETypes_VHTCap_t);
|
|
pvht_cap->header.len = wlan_cpu_to_le16(pvht_cap->header.len);
|
|
}
|
|
|
|
if (IS_FW_SUPPORT_11AX(pmadapter) &&
|
|
(pmpriv->config_bands & BAND_AAX)) {
|
|
phe_cap = (MrvlIEtypes_Extension_t *)ptlv_pos;
|
|
len = wlan_fill_he_cap_tlv(pmpriv, BAND_A, phe_cap, MFALSE);
|
|
HEXDUMP("SCAN: HE_CAPABILITIES IE", (t_u8 *)phe_cap, len);
|
|
ptlv_pos += len;
|
|
}
|
|
|
|
if (wlan_is_ext_capa_support(pmpriv))
|
|
wlan_add_ext_capa_info_ie(pmpriv, MNULL, &ptlv_pos);
|
|
if (pmpriv->adapter->ecsa_enable) {
|
|
t_u8 bandwidth = BW_20MHZ;
|
|
t_u8 oper_class = 1;
|
|
t_u32 usr_dot_11n_dev_cap;
|
|
if (pmpriv->media_connected) {
|
|
if (pmpriv->config_bands & BAND_A)
|
|
usr_dot_11n_dev_cap =
|
|
pmpriv->usr_dot_11n_dev_cap_a;
|
|
else
|
|
usr_dot_11n_dev_cap =
|
|
pmpriv->usr_dot_11n_dev_cap_bg;
|
|
if (usr_dot_11n_dev_cap & MBIT(17)) {
|
|
bandwidth = BW_40MHZ;
|
|
if (ISSUPP_11ACENABLED(
|
|
pmadapter->fw_cap_info) &&
|
|
(pmpriv->config_bands & BAND_AAC))
|
|
bandwidth = BW_80MHZ;
|
|
}
|
|
wlan_get_curr_oper_class(
|
|
pmpriv,
|
|
pmpriv->curr_bss_params.bss_descriptor.channel,
|
|
bandwidth, &oper_class);
|
|
}
|
|
wlan_add_supported_oper_class_ie(pmpriv, &ptlv_pos, oper_class);
|
|
}
|
|
wlan_add_wps_probe_request_ie(pmpriv, &ptlv_pos);
|
|
|
|
if (puser_scan_in && puser_scan_in->proberesp_only) {
|
|
MrvlIEtypes_OnlyProberesp_t *proberesp_only =
|
|
(MrvlIEtypes_OnlyProberesp_t *)ptlv_pos;
|
|
memset(pmadapter, proberesp_only, 0,
|
|
sizeof(MrvlIEtypes_OnlyProberesp_t));
|
|
proberesp_only->header.type =
|
|
wlan_cpu_to_le16(TLV_TYPE_ONLYPROBERESP);
|
|
proberesp_only->header.len = wlan_cpu_to_le16(sizeof(t_u8));
|
|
proberesp_only->proberesp_only = puser_scan_in->proberesp_only;
|
|
ptlv_pos += sizeof(MrvlIEtypes_OnlyProberesp_t);
|
|
}
|
|
|
|
if (puser_scan_in && memcmp(pmadapter, puser_scan_in->random_mac,
|
|
zero_mac, MLAN_MAC_ADDR_LENGTH)) {
|
|
MrvlIEtypes_MacAddr_t *randomMacParam =
|
|
(MrvlIEtypes_MacAddr_t *)ptlv_pos;
|
|
memset(pmadapter, randomMacParam, 0,
|
|
sizeof(MrvlIEtypes_MacAddr_t));
|
|
randomMacParam->header.type =
|
|
wlan_cpu_to_le16(TLV_TYPE_RANDOM_MAC);
|
|
randomMacParam->header.len =
|
|
wlan_cpu_to_le16(MLAN_MAC_ADDR_LENGTH);
|
|
memcpy_ext(pmadapter, randomMacParam->mac,
|
|
puser_scan_in->random_mac, MLAN_MAC_ADDR_LENGTH,
|
|
MLAN_MAC_ADDR_LENGTH);
|
|
ptlv_pos += sizeof(MrvlIEtypes_MacAddr_t);
|
|
}
|
|
/*
|
|
* Set the output for the channel TLV to the address in the tlv buffer
|
|
* past any TLVs that were added in this function (SSID, num_probes).
|
|
* Channel TLVs will be added past this for each scan command,
|
|
* preserving the TLVs that were previously added.
|
|
*/
|
|
*ppchan_list_out = (MrvlIEtypes_ChanListParamSet_t *)ptlv_pos;
|
|
|
|
if (puser_scan_in && puser_scan_in->chan_list[0].chan_number) {
|
|
PRINTM(MINFO, "Scan: Using supplied channel list\n");
|
|
|
|
for (chan_idx = 0;
|
|
chan_idx < WLAN_USER_SCAN_CHAN_MAX &&
|
|
puser_scan_in->chan_list[chan_idx].chan_number;
|
|
chan_idx++) {
|
|
radio_type =
|
|
puser_scan_in->chan_list[chan_idx].radio_type;
|
|
/*Ignore 5G/2G channels if radio_type do not match
|
|
* band*/
|
|
if (!wlan_is_band_compatible(
|
|
pmpriv->config_bands,
|
|
radio_type_to_band(radio_type)))
|
|
continue;
|
|
(pscan_chan_list + chan_list_idx)->bandcfg.chanBand =
|
|
radio_type;
|
|
|
|
channel =
|
|
puser_scan_in->chan_list[chan_idx].chan_number;
|
|
(pscan_chan_list + chan_list_idx)->chan_number =
|
|
channel;
|
|
|
|
scan_type =
|
|
puser_scan_in->chan_list[chan_idx].scan_type;
|
|
if (scan_type == MLAN_SCAN_TYPE_UNCHANGED)
|
|
scan_type = pmadapter->scan_type;
|
|
|
|
if (radio_type == BAND_5GHZ) {
|
|
if (pmadapter->fw_bands & BAND_A)
|
|
PRINTM(MINFO,
|
|
"UserScan request for A Band channel %d!!\n",
|
|
channel);
|
|
else {
|
|
PRINTM(MERROR,
|
|
"Scan in A band is not allowed!!\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
if (wlan_is_chan_passive(pmpriv, radio_type, channel)) {
|
|
/* do not send probe requests on this channel */
|
|
scan_type = MLAN_SCAN_TYPE_PASSIVE;
|
|
}
|
|
/* Prevent active scanning on a radar controlled channel
|
|
*/
|
|
if (radio_type == BAND_5GHZ &&
|
|
scan_type != MLAN_SCAN_TYPE_PASSIVE) {
|
|
if (pmadapter->active_scan_triggered == MFALSE)
|
|
if (wlan_11h_radar_detect_required(
|
|
pmpriv, channel)) {
|
|
scan_type =
|
|
MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE;
|
|
}
|
|
}
|
|
if (radio_type == BAND_2GHZ &&
|
|
scan_type != MLAN_SCAN_TYPE_PASSIVE) {
|
|
if (pmadapter->active_scan_triggered == MFALSE)
|
|
if (wlan_bg_scan_type_is_passive(
|
|
pmpriv, channel)) {
|
|
scan_type =
|
|
MLAN_SCAN_TYPE_PASSIVE;
|
|
}
|
|
}
|
|
if (scan_type == MLAN_SCAN_TYPE_PASSIVE ||
|
|
scan_type == MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE) {
|
|
(pscan_chan_list + chan_list_idx)
|
|
->chan_scan_mode.passive_scan = MTRUE;
|
|
(pscan_chan_list + chan_list_idx)
|
|
->chan_scan_mode.hidden_ssid_report =
|
|
MTRUE;
|
|
} else {
|
|
(pscan_chan_list + chan_list_idx)
|
|
->chan_scan_mode.passive_scan = MFALSE;
|
|
}
|
|
|
|
if (puser_scan_in->chan_list[chan_idx].scan_time) {
|
|
scan_dur = (t_u16)puser_scan_in
|
|
->chan_list[chan_idx]
|
|
.scan_time;
|
|
} else {
|
|
if (scan_type == MLAN_SCAN_TYPE_PASSIVE ||
|
|
scan_type ==
|
|
MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE) {
|
|
scan_dur = pmadapter->passive_scan_time;
|
|
} else if (*pfiltered_scan) {
|
|
scan_dur =
|
|
pmadapter->specific_scan_time;
|
|
} else {
|
|
scan_dur = pmadapter->active_scan_time;
|
|
}
|
|
}
|
|
|
|
if (pmadapter->coex_scan &&
|
|
pmadapter->coex_min_scan_time &&
|
|
(pmadapter->coex_min_scan_time > scan_dur))
|
|
scan_dur = pmadapter->coex_min_scan_time;
|
|
if (scan_type == MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE &&
|
|
pmadapter->passive_to_active_scan ==
|
|
MLAN_PASS_TO_ACT_SCAN_EN) {
|
|
(pscan_chan_list + chan_list_idx)
|
|
->chan_scan_mode.passive_to_active_scan =
|
|
MTRUE;
|
|
scan_dur = MAX(MIN_PASSIVE_TO_ACTIVE_SCAN_TIME,
|
|
scan_dur);
|
|
}
|
|
PRINTM(MINFO,
|
|
"chan=%d, mode=%d, passive_to_active=%d\n",
|
|
(pscan_chan_list + chan_list_idx)->chan_number,
|
|
(pscan_chan_list + chan_list_idx)
|
|
->chan_scan_mode.passive_scan,
|
|
(pscan_chan_list + chan_list_idx)
|
|
->chan_scan_mode.passive_to_active_scan);
|
|
|
|
(pscan_chan_list + chan_list_idx)->min_scan_time =
|
|
wlan_cpu_to_le16(scan_dur);
|
|
(pscan_chan_list + chan_list_idx)->max_scan_time =
|
|
wlan_cpu_to_le16(scan_dur);
|
|
chan_list_idx++;
|
|
}
|
|
|
|
/* Check if we are only scanning the current channel */
|
|
if ((chan_idx == 1) &&
|
|
(puser_scan_in->chan_list[0].chan_number ==
|
|
pmpriv->curr_bss_params.bss_descriptor.channel)) {
|
|
*pscan_current_only = MTRUE;
|
|
PRINTM(MINFO, "Scan: Scanning current channel only\n");
|
|
}
|
|
|
|
} else {
|
|
PRINTM(MINFO, "Scan: Creating full region channel list\n");
|
|
wlan_scan_create_channel_list(pmpriv, puser_scan_in,
|
|
pscan_chan_list, *pfiltered_scan);
|
|
}
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Inspect the scan response buffer for pointers to expected TLVs
|
|
*
|
|
* TLVs can be included at the end of the scan response BSS information.
|
|
* Parse the data in the buffer for pointers to TLVs that can potentially
|
|
* be passed back in the response
|
|
*
|
|
* @param pmadapter Pointer to the mlan_adapter structure
|
|
* @param ptlv Pointer to the start of the TLV buffer to parse
|
|
* @param tlv_buf_size Size of the TLV buffer
|
|
* @param req_tlv_type Request TLV's type
|
|
* @param pptlv Output parameter: Pointer to the request TLV if
|
|
* found
|
|
*
|
|
* @return N/A
|
|
*/
|
|
static t_void wlan_ret_802_11_scan_get_tlv_ptrs(pmlan_adapter pmadapter,
|
|
MrvlIEtypes_Data_t *ptlv,
|
|
t_u32 tlv_buf_size,
|
|
t_u32 req_tlv_type,
|
|
MrvlIEtypes_Data_t **pptlv)
|
|
{
|
|
MrvlIEtypes_Data_t *pcurrent_tlv;
|
|
t_u32 tlv_buf_left;
|
|
t_u32 tlv_type;
|
|
t_u32 tlv_len;
|
|
|
|
ENTER();
|
|
|
|
pcurrent_tlv = ptlv;
|
|
tlv_buf_left = tlv_buf_size;
|
|
*pptlv = MNULL;
|
|
|
|
PRINTM(MINFO, "SCAN_RESP: tlv_buf_size = %d\n", tlv_buf_size);
|
|
|
|
while (tlv_buf_left >= sizeof(MrvlIEtypesHeader_t)) {
|
|
tlv_type = wlan_le16_to_cpu(pcurrent_tlv->header.type);
|
|
tlv_len = wlan_le16_to_cpu(pcurrent_tlv->header.len);
|
|
|
|
if (sizeof(ptlv->header) + tlv_len > tlv_buf_left) {
|
|
PRINTM(MERROR, "SCAN_RESP: TLV buffer corrupt\n");
|
|
break;
|
|
}
|
|
|
|
if (req_tlv_type == tlv_type) {
|
|
switch (tlv_type) {
|
|
case TLV_TYPE_TSFTIMESTAMP:
|
|
PRINTM(MINFO,
|
|
"SCAN_RESP: TSF Timestamp TLV, len = %d\n",
|
|
tlv_len);
|
|
*pptlv = (MrvlIEtypes_Data_t *)pcurrent_tlv;
|
|
break;
|
|
case TLV_TYPE_CHANNELBANDLIST:
|
|
PRINTM(MINFO,
|
|
"SCAN_RESP: CHANNEL BAND LIST TLV, len = %d\n",
|
|
tlv_len);
|
|
*pptlv = (MrvlIEtypes_Data_t *)pcurrent_tlv;
|
|
break;
|
|
case TLV_TYPE_CHANNEL_STATS:
|
|
PRINTM(MINFO,
|
|
"SCAN_RESP: CHANNEL STATS TLV, len = %d\n",
|
|
tlv_len);
|
|
*pptlv = (MrvlIEtypes_Data_t *)pcurrent_tlv;
|
|
break;
|
|
default:
|
|
PRINTM(MERROR,
|
|
"SCAN_RESP: Unhandled TLV = %d\n",
|
|
tlv_type);
|
|
/* Give up, this seems corrupted */
|
|
LEAVE();
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (*pptlv) {
|
|
/* HEXDUMP("SCAN_RESP: TLV Buf", (t_u8 *)*pptlv+4,
|
|
* tlv_len); */
|
|
break;
|
|
}
|
|
|
|
tlv_buf_left -= (sizeof(ptlv->header) + tlv_len);
|
|
pcurrent_tlv =
|
|
(MrvlIEtypes_Data_t *)(pcurrent_tlv->data + tlv_len);
|
|
|
|
} /* while */
|
|
|
|
LEAVE();
|
|
}
|
|
|
|
/**
|
|
* @brief Interpret a BSS scan response returned from the firmware
|
|
*
|
|
* Parse the various fixed fields and IEs passed back for a BSS probe
|
|
* response or beacon from the scan command. Record information as needed
|
|
* in the scan table BSSDescriptor_t for that entry.
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param pbss_entry Output parameter: Pointer to the BSS Entry
|
|
* @param pbeacon_info Pointer to the Beacon information
|
|
* @param bytes_left Number of bytes left to parse
|
|
* @param ext_scan extended scan
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_interpret_bss_desc_with_ie(pmlan_adapter pmadapter,
|
|
BSSDescriptor_t *pbss_entry,
|
|
t_u8 **pbeacon_info,
|
|
t_u32 *bytes_left,
|
|
t_u8 ext_scan)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
IEEEtypes_ElementId_e element_id;
|
|
IEEEtypes_FhParamSet_t *pfh_param_set;
|
|
IEEEtypes_DsParamSet_t *pds_param_set;
|
|
IEEEtypes_CfParamSet_t *pcf_param_set;
|
|
IEEEtypes_IbssParamSet_t *pibss_param_set;
|
|
IEEEtypes_CapInfo_t *pcap_info;
|
|
WLAN_802_11_FIXED_IEs fixed_ie;
|
|
t_u8 *pcurrent_ptr;
|
|
t_u8 *prate;
|
|
t_u8 element_len;
|
|
t_u16 total_ie_len;
|
|
t_u8 bytes_to_copy;
|
|
t_u8 rate_size;
|
|
t_u16 beacon_size;
|
|
t_u8 found_data_rate_ie;
|
|
t_u32 bytes_left_for_current_beacon;
|
|
IEEEtypes_ERPInfo_t *perp_info;
|
|
|
|
IEEEtypes_VendorSpecific_t *pvendor_ie;
|
|
const t_u8 wpa_oui[4] = {0x00, 0x50, 0xf2, 0x01};
|
|
const t_u8 wmm_oui[4] = {0x00, 0x50, 0xf2, 0x02};
|
|
const t_u8 osen_oui[] = {0x50, 0x6f, 0x9a, 0x12};
|
|
|
|
IEEEtypes_CountryInfoSet_t *pcountry_info;
|
|
IEEEtypes_Extension_t *pext_tlv;
|
|
|
|
ENTER();
|
|
|
|
found_data_rate_ie = MFALSE;
|
|
rate_size = 0;
|
|
beacon_size = 0;
|
|
|
|
if (*bytes_left >= sizeof(beacon_size)) {
|
|
/* Extract & convert beacon size from the command buffer */
|
|
memcpy_ext(pmadapter, &beacon_size, *pbeacon_info,
|
|
sizeof(beacon_size), sizeof(beacon_size));
|
|
beacon_size = wlan_le16_to_cpu(beacon_size);
|
|
*bytes_left -= sizeof(beacon_size);
|
|
*pbeacon_info += sizeof(beacon_size);
|
|
}
|
|
|
|
if (!beacon_size || beacon_size > *bytes_left) {
|
|
*pbeacon_info += *bytes_left;
|
|
*bytes_left = 0;
|
|
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
/* Initialize the current working beacon pointer for this BSS iteration
|
|
*/
|
|
pcurrent_ptr = *pbeacon_info;
|
|
|
|
/* Advance the return beacon pointer past the current beacon */
|
|
*pbeacon_info += beacon_size;
|
|
*bytes_left -= beacon_size;
|
|
|
|
bytes_left_for_current_beacon = beacon_size;
|
|
|
|
if (bytes_left_for_current_beacon <
|
|
(MLAN_MAC_ADDR_LENGTH + sizeof(t_u8) +
|
|
sizeof(WLAN_802_11_FIXED_IEs))) {
|
|
PRINTM(MERROR, "InterpretIE: Not enough bytes left\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
memcpy_ext(pmadapter, pbss_entry->mac_address, pcurrent_ptr,
|
|
MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
|
|
PRINTM(MINFO, "InterpretIE: AP MAC Addr-" MACSTR "\n",
|
|
MAC2STR(pbss_entry->mac_address));
|
|
|
|
pcurrent_ptr += MLAN_MAC_ADDR_LENGTH;
|
|
bytes_left_for_current_beacon -= MLAN_MAC_ADDR_LENGTH;
|
|
|
|
/*
|
|
* Next 4 fields are RSSI (for legacy scan only), time stamp,
|
|
* beacon interval, and capability information
|
|
*/
|
|
if (!ext_scan) {
|
|
/* RSSI is 1 byte long */
|
|
pbss_entry->rssi = (t_s32)(*pcurrent_ptr);
|
|
PRINTM(MINFO, "InterpretIE: RSSI=%02X\n", *pcurrent_ptr);
|
|
pcurrent_ptr += 1;
|
|
bytes_left_for_current_beacon -= 1;
|
|
}
|
|
|
|
/*
|
|
* The RSSI is not part of the beacon/probe response. After we have
|
|
* advanced pcurrent_ptr past the RSSI field, save the remaining
|
|
* data for use at the application layer
|
|
*/
|
|
pbss_entry->pbeacon_buf = pcurrent_ptr;
|
|
pbss_entry->beacon_buf_size = bytes_left_for_current_beacon;
|
|
|
|
/* Time stamp is 8 bytes long */
|
|
memcpy_ext(pmadapter, fixed_ie.time_stamp, pcurrent_ptr, 8,
|
|
sizeof(fixed_ie.time_stamp));
|
|
memcpy_ext(pmadapter, pbss_entry->time_stamp, pcurrent_ptr, 8,
|
|
sizeof(pbss_entry->time_stamp));
|
|
pcurrent_ptr += 8;
|
|
bytes_left_for_current_beacon -= 8;
|
|
|
|
/* Beacon interval is 2 bytes long */
|
|
memcpy_ext(pmadapter, &fixed_ie.beacon_interval, pcurrent_ptr, 2,
|
|
sizeof(fixed_ie.beacon_interval));
|
|
pbss_entry->beacon_period = wlan_le16_to_cpu(fixed_ie.beacon_interval);
|
|
pcurrent_ptr += 2;
|
|
bytes_left_for_current_beacon -= 2;
|
|
|
|
/* Capability information is 2 bytes long */
|
|
memcpy_ext(pmadapter, &fixed_ie.capabilities, pcurrent_ptr, 2,
|
|
sizeof(fixed_ie.capabilities));
|
|
PRINTM(MINFO, "InterpretIE: fixed_ie.capabilities=0x%X\n",
|
|
fixed_ie.capabilities);
|
|
fixed_ie.capabilities = wlan_le16_to_cpu(fixed_ie.capabilities);
|
|
pcap_info = (IEEEtypes_CapInfo_t *)&fixed_ie.capabilities;
|
|
memcpy_ext(pmadapter, &pbss_entry->cap_info, pcap_info,
|
|
sizeof(IEEEtypes_CapInfo_t), sizeof(IEEEtypes_CapInfo_t));
|
|
pcurrent_ptr += 2;
|
|
bytes_left_for_current_beacon -= 2;
|
|
|
|
/* Rest of the current buffer are IE's */
|
|
PRINTM(MINFO, "InterpretIE: IELength for this AP = %d\n",
|
|
bytes_left_for_current_beacon);
|
|
|
|
HEXDUMP("InterpretIE: IE info", (t_u8 *)pcurrent_ptr,
|
|
bytes_left_for_current_beacon);
|
|
|
|
if (pcap_info->privacy) {
|
|
PRINTM(MINFO, "InterpretIE: AP WEP enabled\n");
|
|
pbss_entry->privacy = Wlan802_11PrivFilter8021xWEP;
|
|
} else {
|
|
pbss_entry->privacy = Wlan802_11PrivFilterAcceptAll;
|
|
}
|
|
|
|
if (pcap_info->ibss == 1)
|
|
pbss_entry->bss_mode = MLAN_BSS_MODE_IBSS;
|
|
else
|
|
pbss_entry->bss_mode = MLAN_BSS_MODE_INFRA;
|
|
|
|
if (pcap_info->spectrum_mgmt == 1) {
|
|
PRINTM(MINFO, "InterpretIE: 11h- Spectrum Management "
|
|
"capability bit found\n");
|
|
pbss_entry->wlan_11h_bss_info.sensed_11h = 1;
|
|
}
|
|
|
|
/* Process variable IE */
|
|
while (bytes_left_for_current_beacon >= 2) {
|
|
element_id = (IEEEtypes_ElementId_e)(*((t_u8 *)pcurrent_ptr));
|
|
element_len = *((t_u8 *)pcurrent_ptr + 1);
|
|
total_ie_len = element_len + sizeof(IEEEtypes_Header_t);
|
|
|
|
if (bytes_left_for_current_beacon < total_ie_len) {
|
|
PRINTM(MERROR, "InterpretIE: Error in processing IE, "
|
|
"bytes left < IE length\n");
|
|
bytes_left_for_current_beacon = 0;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
continue;
|
|
}
|
|
|
|
switch (element_id) {
|
|
case SSID:
|
|
if (element_len > MRVDRV_MAX_SSID_LENGTH) {
|
|
bytes_left_for_current_beacon = 0;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
continue;
|
|
}
|
|
if (!pbss_entry->ssid.ssid_len) {
|
|
pbss_entry->ssid.ssid_len = element_len;
|
|
memcpy_ext(pmadapter, pbss_entry->ssid.ssid,
|
|
(pcurrent_ptr + 2), element_len,
|
|
sizeof(pbss_entry->ssid.ssid));
|
|
}
|
|
PRINTM(MINFO, "InterpretIE: ssid: %-32s\n",
|
|
pbss_entry->ssid.ssid);
|
|
break;
|
|
|
|
case SUPPORTED_RATES:
|
|
if (element_len > WLAN_SUPPORTED_RATES) {
|
|
bytes_left_for_current_beacon = 0;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
continue;
|
|
}
|
|
memcpy_ext(pmadapter, pbss_entry->data_rates,
|
|
pcurrent_ptr + 2, element_len,
|
|
sizeof(pbss_entry->data_rates));
|
|
memcpy_ext(pmadapter, pbss_entry->supported_rates,
|
|
pcurrent_ptr + 2, element_len,
|
|
sizeof(pbss_entry->supported_rates));
|
|
HEXDUMP("InterpretIE: SupportedRates:",
|
|
pbss_entry->supported_rates, element_len);
|
|
rate_size = element_len;
|
|
found_data_rate_ie = MTRUE;
|
|
break;
|
|
|
|
case FH_PARAM_SET:
|
|
pfh_param_set = (IEEEtypes_FhParamSet_t *)pcurrent_ptr;
|
|
pbss_entry->network_type_use = Wlan802_11FH;
|
|
memcpy_ext(pmadapter,
|
|
&pbss_entry->phy_param_set.fh_param_set,
|
|
pfh_param_set, total_ie_len,
|
|
sizeof(IEEEtypes_FhParamSet_t));
|
|
pbss_entry->phy_param_set.fh_param_set.len = MIN(
|
|
element_len, (sizeof(IEEEtypes_FhParamSet_t) -
|
|
sizeof(IEEEtypes_Header_t)));
|
|
pbss_entry->phy_param_set.fh_param_set.dwell_time =
|
|
wlan_le16_to_cpu(
|
|
pbss_entry->phy_param_set.fh_param_set
|
|
.dwell_time);
|
|
break;
|
|
|
|
case DS_PARAM_SET:
|
|
pds_param_set = (IEEEtypes_DsParamSet_t *)pcurrent_ptr;
|
|
|
|
pbss_entry->network_type_use = Wlan802_11DS;
|
|
pbss_entry->channel = pds_param_set->current_chan;
|
|
|
|
memcpy_ext(pmadapter,
|
|
&pbss_entry->phy_param_set.ds_param_set,
|
|
pds_param_set, total_ie_len,
|
|
sizeof(IEEEtypes_DsParamSet_t));
|
|
pbss_entry->phy_param_set.ds_param_set.len = MIN(
|
|
element_len, (sizeof(IEEEtypes_DsParamSet_t) -
|
|
sizeof(IEEEtypes_Header_t)));
|
|
break;
|
|
|
|
case CF_PARAM_SET:
|
|
pcf_param_set = (IEEEtypes_CfParamSet_t *)pcurrent_ptr;
|
|
memcpy_ext(pmadapter,
|
|
&pbss_entry->ss_param_set.cf_param_set,
|
|
pcf_param_set, total_ie_len,
|
|
sizeof(IEEEtypes_CfParamSet_t));
|
|
pbss_entry->ss_param_set.cf_param_set.len = MIN(
|
|
element_len, (sizeof(IEEEtypes_CfParamSet_t) -
|
|
sizeof(IEEEtypes_Header_t)));
|
|
break;
|
|
|
|
case IBSS_PARAM_SET:
|
|
pibss_param_set =
|
|
(IEEEtypes_IbssParamSet_t *)pcurrent_ptr;
|
|
pbss_entry->atim_window =
|
|
wlan_le16_to_cpu(pibss_param_set->atim_window);
|
|
memcpy_ext(pmadapter,
|
|
&pbss_entry->ss_param_set.ibss_param_set,
|
|
pibss_param_set, total_ie_len,
|
|
sizeof(IEEEtypes_IbssParamSet_t));
|
|
pbss_entry->ss_param_set.ibss_param_set.len = MIN(
|
|
element_len, (sizeof(IEEEtypes_IbssParamSet_t) -
|
|
sizeof(IEEEtypes_Header_t)));
|
|
break;
|
|
|
|
/* Handle Country Info IE */
|
|
case COUNTRY_INFO:
|
|
pcountry_info =
|
|
(IEEEtypes_CountryInfoSet_t *)pcurrent_ptr;
|
|
|
|
if (pcountry_info->len <
|
|
sizeof(pcountry_info->country_code) ||
|
|
(unsigned)(pcountry_info->len + 2) >
|
|
sizeof(IEEEtypes_CountryInfoFullSet_t)) {
|
|
PRINTM(MERROR,
|
|
"InterpretIE: 11D- Err "
|
|
"country_info len =%d min=%d max=%d\n",
|
|
pcountry_info->len,
|
|
sizeof(pcountry_info->country_code),
|
|
sizeof(IEEEtypes_CountryInfoFullSet_t));
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
memcpy_ext(pmadapter, &pbss_entry->country_info,
|
|
pcountry_info, pcountry_info->len + 2,
|
|
sizeof(pbss_entry->country_info));
|
|
HEXDUMP("InterpretIE: 11D- country_info:",
|
|
(t_u8 *)pcountry_info,
|
|
(t_u32)(pcountry_info->len + 2));
|
|
break;
|
|
|
|
case ERP_INFO:
|
|
perp_info = (IEEEtypes_ERPInfo_t *)pcurrent_ptr;
|
|
pbss_entry->erp_flags = perp_info->erp_flags;
|
|
break;
|
|
|
|
case POWER_CONSTRAINT:
|
|
case POWER_CAPABILITY:
|
|
case TPC_REPORT:
|
|
case CHANNEL_SWITCH_ANN:
|
|
case QUIET:
|
|
case IBSS_DFS:
|
|
case SUPPORTED_CHANNELS:
|
|
case TPC_REQUEST:
|
|
wlan_11h_process_bss_elem(
|
|
pmadapter, &pbss_entry->wlan_11h_bss_info,
|
|
pcurrent_ptr);
|
|
break;
|
|
case EXTENDED_SUPPORTED_RATES:
|
|
/*
|
|
* Only process extended supported rate
|
|
* if data rate is already found.
|
|
* Data rate IE should come before
|
|
* extended supported rate IE
|
|
*/
|
|
if (found_data_rate_ie) {
|
|
if ((element_len + rate_size) >
|
|
WLAN_SUPPORTED_RATES) {
|
|
bytes_to_copy = (WLAN_SUPPORTED_RATES -
|
|
rate_size);
|
|
} else {
|
|
bytes_to_copy = element_len;
|
|
}
|
|
|
|
prate = (t_u8 *)pbss_entry->data_rates;
|
|
prate += rate_size;
|
|
memcpy_ext(pmadapter, prate, pcurrent_ptr + 2,
|
|
bytes_to_copy, bytes_to_copy);
|
|
|
|
prate = (t_u8 *)pbss_entry->supported_rates;
|
|
prate += rate_size;
|
|
memcpy_ext(pmadapter, prate, pcurrent_ptr + 2,
|
|
bytes_to_copy, bytes_to_copy);
|
|
}
|
|
HEXDUMP("InterpretIE: ExtSupportedRates:",
|
|
pbss_entry->supported_rates,
|
|
element_len + rate_size);
|
|
break;
|
|
|
|
case VENDOR_SPECIFIC_221:
|
|
pvendor_ie = (IEEEtypes_VendorSpecific_t *)pcurrent_ptr;
|
|
|
|
if (!memcmp(pmadapter, pvendor_ie->vend_hdr.oui,
|
|
wpa_oui, sizeof(wpa_oui))) {
|
|
pbss_entry->pwpa_ie =
|
|
(IEEEtypes_VendorSpecific_t *)
|
|
pcurrent_ptr;
|
|
pbss_entry->wpa_offset = (t_u16)(
|
|
pcurrent_ptr - pbss_entry->pbeacon_buf);
|
|
HEXDUMP("InterpretIE: Resp WPA_IE",
|
|
(t_u8 *)pbss_entry->pwpa_ie,
|
|
((*(pbss_entry->pwpa_ie)).vend_hdr.len +
|
|
sizeof(IEEEtypes_Header_t)));
|
|
} else if (!memcmp(pmadapter, pvendor_ie->vend_hdr.oui,
|
|
wmm_oui, sizeof(wmm_oui))) {
|
|
if (total_ie_len ==
|
|
sizeof(IEEEtypes_WmmParameter_t) ||
|
|
total_ie_len ==
|
|
sizeof(IEEEtypes_WmmInfo_t)) {
|
|
/*
|
|
* Only accept and copy the WMM IE if
|
|
* it matches the size expected for the
|
|
* WMM Info IE or the WMM Parameter IE.
|
|
*/
|
|
memcpy_ext(pmadapter,
|
|
(t_u8 *)&pbss_entry->wmm_ie,
|
|
pcurrent_ptr, total_ie_len,
|
|
sizeof(pbss_entry->wmm_ie));
|
|
HEXDUMP("InterpretIE: Resp WMM_IE",
|
|
(t_u8 *)&pbss_entry->wmm_ie,
|
|
total_ie_len);
|
|
}
|
|
} else if (!memcmp(pmadapter, pvendor_ie->vend_hdr.oui,
|
|
osen_oui, sizeof(osen_oui))) {
|
|
pbss_entry->posen_ie =
|
|
(IEEEtypes_Generic_t *)pcurrent_ptr;
|
|
pbss_entry->osen_offset = (t_u16)(
|
|
pcurrent_ptr - pbss_entry->pbeacon_buf);
|
|
HEXDUMP("InterpretIE: Resp OSEN_IE",
|
|
(t_u8 *)pbss_entry->posen_ie,
|
|
(*(pbss_entry->posen_ie)).ieee_hdr.len +
|
|
sizeof(IEEEtypes_Header_t));
|
|
}
|
|
break;
|
|
case RSN_IE:
|
|
pbss_entry->prsn_ie =
|
|
(IEEEtypes_Generic_t *)pcurrent_ptr;
|
|
pbss_entry->rsn_offset =
|
|
(t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
|
|
HEXDUMP("InterpretIE: Resp RSN_IE",
|
|
(t_u8 *)pbss_entry->prsn_ie,
|
|
(*(pbss_entry->prsn_ie)).ieee_hdr.len +
|
|
sizeof(IEEEtypes_Header_t));
|
|
break;
|
|
case WAPI_IE:
|
|
pbss_entry->pwapi_ie =
|
|
(IEEEtypes_Generic_t *)pcurrent_ptr;
|
|
pbss_entry->wapi_offset =
|
|
(t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
|
|
HEXDUMP("InterpretIE: Resp WAPI_IE",
|
|
(t_u8 *)pbss_entry->pwapi_ie,
|
|
(*(pbss_entry->pwapi_ie)).ieee_hdr.len +
|
|
sizeof(IEEEtypes_Header_t));
|
|
break;
|
|
case MULTI_BSSID:
|
|
if (IS_FW_SUPPORT_MULTIBSSID(pmadapter)) {
|
|
pbss_entry->multi_bssid_ap = MULTI_BSSID_AP;
|
|
HEXDUMP("InterpretIE: Multi BSSID IE",
|
|
(t_u8 *)pcurrent_ptr, total_ie_len);
|
|
}
|
|
break;
|
|
case HT_CAPABILITY:
|
|
pbss_entry->pht_cap = (IEEEtypes_HTCap_t *)pcurrent_ptr;
|
|
pbss_entry->ht_cap_offset =
|
|
(t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
|
|
HEXDUMP("InterpretIE: Resp HTCAP_IE",
|
|
(t_u8 *)pbss_entry->pht_cap,
|
|
(*(pbss_entry->pht_cap)).ieee_hdr.len +
|
|
sizeof(IEEEtypes_Header_t));
|
|
break;
|
|
case HT_OPERATION:
|
|
pbss_entry->pht_info =
|
|
(IEEEtypes_HTInfo_t *)pcurrent_ptr;
|
|
pbss_entry->ht_info_offset =
|
|
(t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
|
|
HEXDUMP("InterpretIE: Resp HTINFO_IE",
|
|
(t_u8 *)pbss_entry->pht_info,
|
|
(*(pbss_entry->pht_info)).ieee_hdr.len +
|
|
sizeof(IEEEtypes_Header_t));
|
|
break;
|
|
case BSSCO_2040:
|
|
pbss_entry->pbss_co_2040 =
|
|
(IEEEtypes_2040BSSCo_t *)pcurrent_ptr;
|
|
pbss_entry->bss_co_2040_offset =
|
|
(t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
|
|
HEXDUMP("InterpretIE: Resp 2040BSSCOEXISTANCE_IE",
|
|
(t_u8 *)pbss_entry->pbss_co_2040,
|
|
(*(pbss_entry->pbss_co_2040)).ieee_hdr.len +
|
|
sizeof(IEEEtypes_Header_t));
|
|
break;
|
|
case EXT_CAPABILITY:
|
|
pbss_entry->pext_cap =
|
|
(IEEEtypes_ExtCap_t *)pcurrent_ptr;
|
|
pbss_entry->ext_cap_offset =
|
|
(t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
|
|
HEXDUMP("InterpretIE: Resp EXTCAP_IE",
|
|
(t_u8 *)pbss_entry->pext_cap,
|
|
(*(pbss_entry->pext_cap)).ieee_hdr.len +
|
|
sizeof(IEEEtypes_Header_t));
|
|
break;
|
|
case OVERLAPBSSSCANPARAM:
|
|
pbss_entry->poverlap_bss_scan_param =
|
|
(IEEEtypes_OverlapBSSScanParam_t *)pcurrent_ptr;
|
|
pbss_entry->overlap_bss_offset =
|
|
(t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
|
|
HEXDUMP("InterpretIE: Resp OBSS_IE",
|
|
(t_u8 *)pbss_entry->poverlap_bss_scan_param,
|
|
(*(pbss_entry->poverlap_bss_scan_param))
|
|
.ieee_hdr.len +
|
|
sizeof(IEEEtypes_Header_t));
|
|
break;
|
|
case VHT_CAPABILITY:
|
|
pbss_entry->pvht_cap =
|
|
(IEEEtypes_VHTCap_t *)pcurrent_ptr;
|
|
pbss_entry->vht_cap_offset =
|
|
(t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
|
|
HEXDUMP("InterpretIE: Resp VHTCAP_IE",
|
|
(t_u8 *)pbss_entry->pvht_cap,
|
|
(*(pbss_entry->pvht_cap)).ieee_hdr.len +
|
|
sizeof(IEEEtypes_Header_t));
|
|
break;
|
|
case VHT_OPERATION:
|
|
pbss_entry->pvht_oprat =
|
|
(IEEEtypes_VHTOprat_t *)pcurrent_ptr;
|
|
pbss_entry->vht_oprat_offset =
|
|
(t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
|
|
HEXDUMP("InterpretIE: Resp VHTOPER_IE",
|
|
(t_u8 *)pbss_entry->pvht_oprat,
|
|
(*(pbss_entry->pvht_oprat)).ieee_hdr.len +
|
|
sizeof(IEEEtypes_Header_t));
|
|
break;
|
|
case EXT_BSS_LOAD:
|
|
pbss_entry->pext_bssload =
|
|
(IEEEtypes_ExtBSSload_t *)pcurrent_ptr;
|
|
pbss_entry->ext_bssload_offset =
|
|
(t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
|
|
HEXDUMP("InterpretIE: Resp EXTBSSLOAD_IE",
|
|
(t_u8 *)pbss_entry->pext_bssload,
|
|
(*(pbss_entry->pext_bssload)).ieee_hdr.len +
|
|
sizeof(IEEEtypes_Header_t));
|
|
break;
|
|
case VHT_TX_POWER_ENV:
|
|
pbss_entry->pvht_txpower =
|
|
(IEEEtypes_VHTtxpower_t *)pcurrent_ptr;
|
|
pbss_entry->vht_txpower_offset =
|
|
(t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
|
|
HEXDUMP("InterpretIE: Resp TXPOW_IE",
|
|
(t_u8 *)pbss_entry->pvht_txpower,
|
|
(*(pbss_entry->pvht_txpower)).ieee_hdr.len +
|
|
sizeof(IEEEtypes_Header_t));
|
|
break;
|
|
case EXT_POWER_CONSTR:
|
|
pbss_entry->pext_pwer =
|
|
(IEEEtypes_ExtPwerCons_t *)pcurrent_ptr;
|
|
pbss_entry->ext_pwer_offset =
|
|
(t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
|
|
HEXDUMP("InterpretIE: Resp EXTPOW_IE",
|
|
(t_u8 *)pbss_entry->pext_pwer,
|
|
(*(pbss_entry->pext_pwer)).ieee_hdr.len +
|
|
sizeof(IEEEtypes_Header_t));
|
|
break;
|
|
case QUIET_CHAN:
|
|
pbss_entry->pquiet_chan =
|
|
(IEEEtypes_QuietChan_t *)pcurrent_ptr;
|
|
pbss_entry->quiet_chan_offset =
|
|
(t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
|
|
HEXDUMP("InterpretIE: Resp QUIETCHAN_IE",
|
|
(t_u8 *)pbss_entry->pquiet_chan,
|
|
(*(pbss_entry->pquiet_chan)).ieee_hdr.len +
|
|
sizeof(IEEEtypes_Header_t));
|
|
break;
|
|
case BW_CHANNEL_SWITCH:
|
|
/* RANDYTODO */
|
|
break;
|
|
case AID_INFO:
|
|
break;
|
|
case OPER_MODE_NTF:
|
|
pbss_entry->poper_mode =
|
|
(IEEEtypes_OperModeNtf_t *)pcurrent_ptr;
|
|
pbss_entry->oper_mode_offset =
|
|
(t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
|
|
HEXDUMP("InterpretIE: Resp OPERMODENTF_IE",
|
|
(t_u8 *)pbss_entry->poper_mode,
|
|
(*(pbss_entry->poper_mode)).ieee_hdr.len +
|
|
sizeof(IEEEtypes_Header_t));
|
|
break;
|
|
case EXTENSION:
|
|
pext_tlv = (IEEEtypes_Extension_t *)pcurrent_ptr;
|
|
switch (pext_tlv->ext_id) {
|
|
case HE_CAPABILITY:
|
|
pbss_entry->phe_cap =
|
|
(IEEEtypes_HECap_t *)pcurrent_ptr;
|
|
pbss_entry->he_cap_offset = (t_u16)(
|
|
pcurrent_ptr - pbss_entry->pbeacon_buf);
|
|
break;
|
|
case HE_OPERATION:
|
|
pbss_entry->phe_oprat = pext_tlv;
|
|
pbss_entry->he_oprat_offset = (t_u16)(
|
|
pcurrent_ptr - pbss_entry->pbeacon_buf);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case MOBILITY_DOMAIN:
|
|
PRINTM(MCMND, "Mobility Domain IE received in Scan\n");
|
|
pbss_entry->pmd_ie =
|
|
(IEEEtypes_MobilityDomain_t *)pcurrent_ptr;
|
|
pbss_entry->md_offset =
|
|
(t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
|
|
HEXDUMP("InterpretIE: Resp Mobility Domain IE",
|
|
(t_u8 *)pbss_entry->pmd_ie,
|
|
(*(pbss_entry->pmd_ie)).ieee_hdr.len +
|
|
sizeof(IEEEtypes_Header_t));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
pcurrent_ptr += element_len + 2;
|
|
|
|
/* Need to account for IE ID and IE Len */
|
|
bytes_left_for_current_beacon -= (element_len + 2);
|
|
|
|
} /* while (bytes_left_for_current_beacon > 2) */
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Adjust ie's position in BSSDescriptor_t
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @param pbss_entry A pointer to BSSDescriptor_t structure
|
|
*
|
|
* @return N/A
|
|
*/
|
|
static t_void wlan_adjust_ie_in_bss_entry(mlan_private *pmpriv,
|
|
BSSDescriptor_t *pbss_entry)
|
|
{
|
|
ENTER();
|
|
if (pbss_entry->pbeacon_buf) {
|
|
if (pbss_entry->pwpa_ie) {
|
|
pbss_entry->pwpa_ie =
|
|
(IEEEtypes_VendorSpecific_t
|
|
*)(pbss_entry->pbeacon_buf +
|
|
pbss_entry->wpa_offset);
|
|
}
|
|
if (pbss_entry->prsn_ie) {
|
|
pbss_entry->prsn_ie =
|
|
(IEEEtypes_Generic_t *)(pbss_entry->pbeacon_buf +
|
|
pbss_entry->rsn_offset);
|
|
}
|
|
if (pbss_entry->pwapi_ie) {
|
|
pbss_entry->pwapi_ie =
|
|
(IEEEtypes_Generic_t *)(pbss_entry->pbeacon_buf +
|
|
pbss_entry->wapi_offset);
|
|
}
|
|
|
|
if (pbss_entry->posen_ie) {
|
|
pbss_entry->posen_ie =
|
|
(IEEEtypes_Generic_t *)(pbss_entry->pbeacon_buf +
|
|
pbss_entry->osen_offset);
|
|
}
|
|
if (pbss_entry->pmd_ie) {
|
|
pbss_entry->pmd_ie =
|
|
(IEEEtypes_MobilityDomain_t
|
|
*)(pbss_entry->pbeacon_buf +
|
|
pbss_entry->md_offset);
|
|
}
|
|
if (pbss_entry->pht_cap) {
|
|
pbss_entry->pht_cap =
|
|
(IEEEtypes_HTCap_t *)(pbss_entry->pbeacon_buf +
|
|
pbss_entry->ht_cap_offset);
|
|
}
|
|
if (pbss_entry->pht_info) {
|
|
pbss_entry->pht_info =
|
|
(IEEEtypes_HTInfo_t
|
|
*)(pbss_entry->pbeacon_buf +
|
|
pbss_entry->ht_info_offset);
|
|
}
|
|
if (pbss_entry->pbss_co_2040) {
|
|
pbss_entry->pbss_co_2040 =
|
|
(IEEEtypes_2040BSSCo_t
|
|
*)(pbss_entry->pbeacon_buf +
|
|
pbss_entry->bss_co_2040_offset);
|
|
}
|
|
if (pbss_entry->pext_cap) {
|
|
pbss_entry->pext_cap =
|
|
(IEEEtypes_ExtCap_t
|
|
*)(pbss_entry->pbeacon_buf +
|
|
pbss_entry->ext_cap_offset);
|
|
}
|
|
if (pbss_entry->poverlap_bss_scan_param) {
|
|
pbss_entry->poverlap_bss_scan_param =
|
|
(IEEEtypes_OverlapBSSScanParam_t
|
|
*)(pbss_entry->pbeacon_buf +
|
|
pbss_entry->overlap_bss_offset);
|
|
}
|
|
if (pbss_entry->pvht_cap) {
|
|
pbss_entry->pvht_cap =
|
|
(IEEEtypes_VHTCap_t
|
|
*)(pbss_entry->pbeacon_buf +
|
|
pbss_entry->vht_cap_offset);
|
|
}
|
|
if (pbss_entry->pvht_oprat) {
|
|
pbss_entry->pvht_oprat =
|
|
(IEEEtypes_VHTOprat_t
|
|
*)(pbss_entry->pbeacon_buf +
|
|
pbss_entry->vht_oprat_offset);
|
|
}
|
|
if (pbss_entry->pvht_txpower) {
|
|
pbss_entry->pvht_txpower =
|
|
(IEEEtypes_VHTtxpower_t
|
|
*)(pbss_entry->pbeacon_buf +
|
|
pbss_entry->vht_txpower_offset);
|
|
}
|
|
if (pbss_entry->pext_pwer) {
|
|
pbss_entry->pext_pwer =
|
|
(IEEEtypes_ExtPwerCons_t
|
|
*)(pbss_entry->pbeacon_buf +
|
|
pbss_entry->ext_pwer_offset);
|
|
}
|
|
if (pbss_entry->pext_bssload) {
|
|
pbss_entry->pext_bssload =
|
|
(IEEEtypes_ExtBSSload_t
|
|
*)(pbss_entry->pbeacon_buf +
|
|
pbss_entry->ext_bssload_offset);
|
|
}
|
|
if (pbss_entry->pquiet_chan) {
|
|
pbss_entry->pquiet_chan =
|
|
(IEEEtypes_QuietChan_t
|
|
*)(pbss_entry->pbeacon_buf +
|
|
pbss_entry->quiet_chan_offset);
|
|
}
|
|
if (pbss_entry->poper_mode) {
|
|
pbss_entry->poper_mode =
|
|
(IEEEtypes_OperModeNtf_t
|
|
*)(pbss_entry->pbeacon_buf +
|
|
pbss_entry->oper_mode_offset);
|
|
}
|
|
if (pbss_entry->phe_cap) {
|
|
pbss_entry->phe_cap =
|
|
(IEEEtypes_HECap_t *)(pbss_entry->pbeacon_buf +
|
|
pbss_entry->he_cap_offset);
|
|
}
|
|
|
|
if (pbss_entry->phe_oprat) {
|
|
pbss_entry->phe_oprat =
|
|
(IEEEtypes_Extension_t
|
|
*)(pbss_entry->pbeacon_buf +
|
|
pbss_entry->he_oprat_offset);
|
|
}
|
|
} else {
|
|
pbss_entry->pwpa_ie = MNULL;
|
|
pbss_entry->wpa_offset = 0;
|
|
pbss_entry->prsn_ie = MNULL;
|
|
pbss_entry->rsn_offset = 0;
|
|
pbss_entry->pwapi_ie = MNULL;
|
|
pbss_entry->wapi_offset = 0;
|
|
|
|
pbss_entry->posen_ie = MNULL;
|
|
pbss_entry->osen_offset = 0;
|
|
pbss_entry->pmd_ie = MNULL;
|
|
pbss_entry->md_offset = 0;
|
|
pbss_entry->pht_cap = MNULL;
|
|
pbss_entry->ht_cap_offset = 0;
|
|
pbss_entry->pht_info = MNULL;
|
|
pbss_entry->ht_info_offset = 0;
|
|
pbss_entry->pbss_co_2040 = MNULL;
|
|
pbss_entry->bss_co_2040_offset = 0;
|
|
pbss_entry->pext_cap = MNULL;
|
|
pbss_entry->ext_cap_offset = 0;
|
|
pbss_entry->poverlap_bss_scan_param = MNULL;
|
|
pbss_entry->overlap_bss_offset = 0;
|
|
}
|
|
LEAVE();
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* @brief Store a beacon or probe response for a BSS returned in the scan
|
|
*
|
|
* Store a new scan response or an update for a previous scan response. New
|
|
* entries need to verify that they do not exceed the total amount of
|
|
* memory allocated for the table.
|
|
|
|
* Replacement entries need to take into consideration the amount of space
|
|
* currently allocated for the beacon/probe response and adjust the entry
|
|
* as needed.
|
|
*
|
|
* A small amount of extra pad (SCAN_BEACON_ENTRY_PAD) is generally reserved
|
|
* for an entry in case it is a beacon since a probe response for the
|
|
* network will by larger per the standard. This helps to reduce the
|
|
* amount of memory copying to fit a new probe response into an entry
|
|
* already occupied by a network's previously stored beacon.
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @param beacon_idx Index in the scan table to store this entry; may be
|
|
* replacing an older duplicate entry for this BSS
|
|
* @param num_of_ent Number of entries currently in the table
|
|
* @param pnew_beacon Pointer to the new beacon/probe response to save
|
|
*
|
|
* @return N/A
|
|
*/
|
|
static t_void wlan_ret_802_11_scan_store_beacon(mlan_private *pmpriv,
|
|
t_u32 beacon_idx,
|
|
t_u32 num_of_ent,
|
|
BSSDescriptor_t *pnew_beacon)
|
|
{
|
|
mlan_adapter *pmadapter = pmpriv->adapter;
|
|
t_u8 *pbcn_store;
|
|
t_u32 new_bcn_size;
|
|
t_u32 old_bcn_size;
|
|
t_u32 bcn_space;
|
|
t_u32 adj_idx;
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
t_u8 *tmp_buf;
|
|
t_u32 bcn_size = 0;
|
|
t_u32 bcn_offset = 0;
|
|
|
|
ENTER();
|
|
|
|
if (pmadapter->pscan_table[beacon_idx].pbeacon_buf) {
|
|
new_bcn_size = pnew_beacon->beacon_buf_size;
|
|
old_bcn_size =
|
|
pmadapter->pscan_table[beacon_idx].beacon_buf_size;
|
|
bcn_space =
|
|
pmadapter->pscan_table[beacon_idx].beacon_buf_size_max;
|
|
pbcn_store = pmadapter->pscan_table[beacon_idx].pbeacon_buf;
|
|
|
|
/* Set the max to be the same as current entry unless changed
|
|
* below */
|
|
pnew_beacon->beacon_buf_size_max = bcn_space;
|
|
|
|
if (new_bcn_size == old_bcn_size) {
|
|
/*
|
|
* Beacon is the same size as the previous entry.
|
|
* Replace the previous contents with the scan result
|
|
*/
|
|
memcpy_ext(pmadapter, pbcn_store,
|
|
pnew_beacon->pbeacon_buf,
|
|
pnew_beacon->beacon_buf_size,
|
|
pnew_beacon->beacon_buf_size);
|
|
|
|
} else if (new_bcn_size <= bcn_space) {
|
|
/*
|
|
* New beacon size will fit in the amount of space
|
|
* we have previously allocated for it
|
|
*/
|
|
|
|
/* Copy the new beacon buffer entry over the old one */
|
|
memcpy_ext(pmadapter, pbcn_store,
|
|
pnew_beacon->pbeacon_buf, new_bcn_size,
|
|
new_bcn_size);
|
|
|
|
/*
|
|
* If the old beacon size was less than the
|
|
* maximum we had allotted for the entry, and
|
|
* the new entry is even smaller, reset the
|
|
* max size to the old beacon entry and compress
|
|
* the storage space (leaving a new pad space of
|
|
* (old_bcn_size - new_bcn_size).
|
|
*/
|
|
if (old_bcn_size < bcn_space &&
|
|
new_bcn_size <= old_bcn_size) {
|
|
/*
|
|
* Old Beacon size is smaller than the
|
|
* allotted storage size. Shrink the
|
|
* allotted storage space.
|
|
*/
|
|
PRINTM(MINFO,
|
|
"AppControl: Smaller Duplicate Beacon (%d), "
|
|
"old = %d, new = %d, space = %d, left = %d\n",
|
|
beacon_idx, old_bcn_size, new_bcn_size,
|
|
bcn_space,
|
|
(pmadapter->bcn_buf_size -
|
|
(pmadapter->pbcn_buf_end -
|
|
pmadapter->bcn_buf)));
|
|
|
|
/*
|
|
* memmove (since the memory overlaps) the data
|
|
* after the beacon we just stored to the end
|
|
* of the current beacon. This cleans up any
|
|
* unused space the old larger beacon was using
|
|
* in the buffer
|
|
*/
|
|
memmove(pmadapter,
|
|
(void *)((t_ptr)pbcn_store +
|
|
(t_ptr)old_bcn_size),
|
|
(void *)((t_ptr)pbcn_store +
|
|
(t_ptr)bcn_space),
|
|
(t_u32)((t_ptr)pmadapter->pbcn_buf_end -
|
|
((t_ptr)pbcn_store +
|
|
(t_ptr)bcn_space)));
|
|
|
|
/*
|
|
* Decrement the end pointer by the difference
|
|
* between the old larger size and the new
|
|
* smaller size since we are using less space
|
|
* due to the new beacon being smaller
|
|
*/
|
|
pmadapter->pbcn_buf_end -=
|
|
(bcn_space - old_bcn_size);
|
|
|
|
/*
|
|
* Set the maximum storage size to the old
|
|
* beacon size
|
|
*/
|
|
pnew_beacon->beacon_buf_size_max = old_bcn_size;
|
|
|
|
/* Adjust beacon buffer pointers that are past
|
|
* the current */
|
|
for (adj_idx = 0; adj_idx < num_of_ent;
|
|
adj_idx++) {
|
|
if (pmadapter->pscan_table[adj_idx]
|
|
.pbeacon_buf > pbcn_store) {
|
|
pmadapter->pscan_table[adj_idx]
|
|
.pbeacon_buf -=
|
|
(bcn_space -
|
|
old_bcn_size);
|
|
wlan_adjust_ie_in_bss_entry(
|
|
pmpriv,
|
|
&pmadapter->pscan_table
|
|
[adj_idx]);
|
|
}
|
|
}
|
|
}
|
|
} else if (pmadapter->pbcn_buf_end +
|
|
(new_bcn_size - bcn_space) <
|
|
(pmadapter->bcn_buf + pmadapter->bcn_buf_size)) {
|
|
/*
|
|
* Beacon is larger than space previously allocated
|
|
* (bcn_space) and there is enough space left in the
|
|
* beaconBuffer to store the additional data
|
|
*/
|
|
PRINTM(MINFO,
|
|
"AppControl: Larger Duplicate Beacon (%d), "
|
|
"old = %d, new = %d, space = %d, left = %d\n",
|
|
beacon_idx, old_bcn_size, new_bcn_size,
|
|
bcn_space,
|
|
(pmadapter->bcn_buf_size -
|
|
(pmadapter->pbcn_buf_end - pmadapter->bcn_buf)));
|
|
|
|
/*
|
|
* memmove (since the memory overlaps) the data
|
|
* after the beacon we just stored to the end of
|
|
* the current beacon. This moves the data for
|
|
* the beacons after this further in memory to
|
|
* make space for the new larger beacon we are
|
|
* about to copy in.
|
|
*/
|
|
memmove(pmadapter,
|
|
(void *)((t_ptr)pbcn_store +
|
|
(t_ptr)new_bcn_size),
|
|
(void *)((t_ptr)pbcn_store + (t_ptr)bcn_space),
|
|
(t_u32)((t_ptr)pmadapter->pbcn_buf_end -
|
|
((t_ptr)pbcn_store + (t_ptr)bcn_space)));
|
|
|
|
/* Copy the new beacon buffer entry over the old one */
|
|
memcpy_ext(pmadapter, pbcn_store,
|
|
pnew_beacon->pbeacon_buf, new_bcn_size,
|
|
new_bcn_size);
|
|
|
|
/*
|
|
* Move the beacon end pointer by the amount of new
|
|
* beacon data we are adding
|
|
*/
|
|
pmadapter->pbcn_buf_end += (new_bcn_size - bcn_space);
|
|
|
|
/*
|
|
* This entry is bigger than the allotted max space
|
|
* previously reserved. Increase the max space to
|
|
* be equal to the new beacon size
|
|
*/
|
|
pnew_beacon->beacon_buf_size_max = new_bcn_size;
|
|
|
|
/* Adjust beacon buffer pointers that are past the
|
|
* current */
|
|
for (adj_idx = 0; adj_idx < num_of_ent; adj_idx++) {
|
|
if (pmadapter->pscan_table[adj_idx].pbeacon_buf >
|
|
pbcn_store) {
|
|
pmadapter->pscan_table[adj_idx]
|
|
.pbeacon_buf +=
|
|
(new_bcn_size - bcn_space);
|
|
wlan_adjust_ie_in_bss_entry(
|
|
pmpriv,
|
|
&pmadapter->pscan_table[adj_idx]);
|
|
}
|
|
}
|
|
} else {
|
|
/*
|
|
* Beacon is larger than the previously allocated
|
|
* space, but there is not enough free space to
|
|
* store the additional data
|
|
*/
|
|
PRINTM(MERROR,
|
|
"AppControl: Failed: Larger Duplicate Beacon (%d),"
|
|
" old = %d, new = %d, space = %d, left = %d\n",
|
|
beacon_idx, old_bcn_size, new_bcn_size,
|
|
bcn_space,
|
|
(pmadapter->bcn_buf_size -
|
|
(pmadapter->pbcn_buf_end - pmadapter->bcn_buf)));
|
|
|
|
/* Storage failure, keep old beacon intact */
|
|
pnew_beacon->beacon_buf_size = old_bcn_size;
|
|
if (pnew_beacon->pwpa_ie)
|
|
pnew_beacon->wpa_offset =
|
|
pmadapter->pscan_table[beacon_idx]
|
|
.wpa_offset;
|
|
if (pnew_beacon->prsn_ie)
|
|
pnew_beacon->rsn_offset =
|
|
pmadapter->pscan_table[beacon_idx]
|
|
.rsn_offset;
|
|
if (pnew_beacon->pwapi_ie)
|
|
pnew_beacon->wapi_offset =
|
|
pmadapter->pscan_table[beacon_idx]
|
|
.wapi_offset;
|
|
|
|
if (pnew_beacon->posen_ie)
|
|
pnew_beacon->osen_offset =
|
|
pmadapter->pscan_table[beacon_idx]
|
|
.osen_offset;
|
|
if (pnew_beacon->pmd_ie)
|
|
pnew_beacon->md_offset =
|
|
pmadapter->pscan_table[beacon_idx]
|
|
.md_offset;
|
|
if (pnew_beacon->pht_cap)
|
|
pnew_beacon->ht_cap_offset =
|
|
pmadapter->pscan_table[beacon_idx]
|
|
.ht_cap_offset;
|
|
if (pnew_beacon->pht_info)
|
|
pnew_beacon->ht_info_offset =
|
|
pmadapter->pscan_table[beacon_idx]
|
|
.ht_info_offset;
|
|
if (pnew_beacon->pbss_co_2040)
|
|
pnew_beacon->bss_co_2040_offset =
|
|
pmadapter->pscan_table[beacon_idx]
|
|
.bss_co_2040_offset;
|
|
if (pnew_beacon->pext_cap)
|
|
pnew_beacon->ext_cap_offset =
|
|
pmadapter->pscan_table[beacon_idx]
|
|
.ext_cap_offset;
|
|
if (pnew_beacon->poverlap_bss_scan_param)
|
|
pnew_beacon->overlap_bss_offset =
|
|
pmadapter->pscan_table[beacon_idx]
|
|
.overlap_bss_offset;
|
|
if (pnew_beacon->pvht_cap)
|
|
pnew_beacon->vht_cap_offset =
|
|
pmadapter->pscan_table[beacon_idx]
|
|
.vht_cap_offset;
|
|
if (pnew_beacon->pvht_oprat)
|
|
pnew_beacon->vht_oprat_offset =
|
|
pmadapter->pscan_table[beacon_idx]
|
|
.vht_oprat_offset;
|
|
if (pnew_beacon->pvht_txpower)
|
|
pnew_beacon->vht_txpower_offset =
|
|
pmadapter->pscan_table[beacon_idx]
|
|
.vht_txpower_offset;
|
|
if (pnew_beacon->pext_pwer)
|
|
pnew_beacon->ext_pwer_offset =
|
|
pmadapter->pscan_table[beacon_idx]
|
|
.ext_pwer_offset;
|
|
if (pnew_beacon->pext_bssload)
|
|
pnew_beacon->ext_bssload_offset =
|
|
pmadapter->pscan_table[beacon_idx]
|
|
.ext_bssload_offset;
|
|
if (pnew_beacon->pquiet_chan)
|
|
pnew_beacon->quiet_chan_offset =
|
|
pmadapter->pscan_table[beacon_idx]
|
|
.quiet_chan_offset;
|
|
if (pnew_beacon->poper_mode)
|
|
pnew_beacon->oper_mode_offset =
|
|
pmadapter->pscan_table[beacon_idx]
|
|
.oper_mode_offset;
|
|
if (pnew_beacon->phe_cap)
|
|
pnew_beacon->he_cap_offset =
|
|
pmadapter->pscan_table[beacon_idx]
|
|
.he_cap_offset;
|
|
if (pnew_beacon->phe_oprat)
|
|
pnew_beacon->he_oprat_offset =
|
|
pmadapter->pscan_table[beacon_idx]
|
|
.he_oprat_offset;
|
|
}
|
|
/* Point the new entry to its permanent storage space */
|
|
pnew_beacon->pbeacon_buf = pbcn_store;
|
|
wlan_adjust_ie_in_bss_entry(pmpriv, pnew_beacon);
|
|
} else {
|
|
if ((pmadapter->pbcn_buf_end + pnew_beacon->beacon_buf_size +
|
|
SCAN_BEACON_ENTRY_PAD >
|
|
(pmadapter->bcn_buf + pmadapter->bcn_buf_size)) &&
|
|
(pmadapter->bcn_buf_size < MAX_SCAN_BEACON_BUFFER)) {
|
|
/* no space for this entry, realloc bcn buffer */
|
|
if (pmadapter->callbacks.moal_vmalloc &&
|
|
pmadapter->callbacks.moal_vfree)
|
|
ret = pmadapter->callbacks.moal_vmalloc(
|
|
pmadapter->pmoal_handle,
|
|
pmadapter->bcn_buf_size +
|
|
DEFAULT_SCAN_BEACON_BUFFER,
|
|
(t_u8 **)&tmp_buf);
|
|
else
|
|
ret = pmadapter->callbacks.moal_malloc(
|
|
pmadapter->pmoal_handle,
|
|
pmadapter->bcn_buf_size +
|
|
DEFAULT_SCAN_BEACON_BUFFER,
|
|
MLAN_MEM_DEF, (t_u8 **)&tmp_buf);
|
|
|
|
if ((ret == MLAN_STATUS_SUCCESS) && (tmp_buf)) {
|
|
PRINTM(MCMND,
|
|
"Realloc Beacon buffer, old size=%d, new_size=%d\n",
|
|
pmadapter->bcn_buf_size,
|
|
pmadapter->bcn_buf_size +
|
|
DEFAULT_SCAN_BEACON_BUFFER);
|
|
bcn_size = pmadapter->pbcn_buf_end -
|
|
pmadapter->bcn_buf;
|
|
memcpy_ext(pmadapter, tmp_buf,
|
|
pmadapter->bcn_buf, bcn_size,
|
|
bcn_size);
|
|
/* Adjust beacon buffer pointers that are past
|
|
* the current */
|
|
for (adj_idx = 0; adj_idx < num_of_ent;
|
|
adj_idx++) {
|
|
bcn_offset =
|
|
pmadapter->pscan_table[adj_idx]
|
|
.pbeacon_buf -
|
|
pmadapter->bcn_buf;
|
|
pmadapter->pscan_table[adj_idx]
|
|
.pbeacon_buf =
|
|
tmp_buf + bcn_offset;
|
|
wlan_adjust_ie_in_bss_entry(
|
|
pmpriv,
|
|
&pmadapter->pscan_table[adj_idx]);
|
|
}
|
|
pmadapter->pbcn_buf_end = tmp_buf + bcn_size;
|
|
if (pmadapter->callbacks.moal_vmalloc &&
|
|
pmadapter->callbacks.moal_vfree)
|
|
pmadapter->callbacks.moal_vfree(
|
|
pmadapter->pmoal_handle,
|
|
(t_u8 *)pmadapter->bcn_buf);
|
|
else
|
|
pmadapter->callbacks.moal_mfree(
|
|
pmadapter->pmoal_handle,
|
|
(t_u8 *)pmadapter->bcn_buf);
|
|
pmadapter->bcn_buf = tmp_buf;
|
|
pmadapter->bcn_buf_size +=
|
|
DEFAULT_SCAN_BEACON_BUFFER;
|
|
}
|
|
}
|
|
/*
|
|
* No existing beacon data exists for this entry, check to see
|
|
* if we can fit it in the remaining space
|
|
*/
|
|
if (pmadapter->pbcn_buf_end + pnew_beacon->beacon_buf_size +
|
|
SCAN_BEACON_ENTRY_PAD <
|
|
(pmadapter->bcn_buf + pmadapter->bcn_buf_size)) {
|
|
/*
|
|
* Copy the beacon buffer data from the local entry
|
|
* to the adapter dev struct buffer space used to
|
|
* store the raw beacon data for each entry in the
|
|
* scan table
|
|
*/
|
|
memcpy_ext(pmadapter, pmadapter->pbcn_buf_end,
|
|
pnew_beacon->pbeacon_buf,
|
|
pnew_beacon->beacon_buf_size,
|
|
pnew_beacon->beacon_buf_size);
|
|
|
|
/*
|
|
* Update the beacon ptr to point to the table
|
|
* save area
|
|
*/
|
|
pnew_beacon->pbeacon_buf = pmadapter->pbcn_buf_end;
|
|
pnew_beacon->beacon_buf_size_max =
|
|
(pnew_beacon->beacon_buf_size +
|
|
SCAN_BEACON_ENTRY_PAD);
|
|
wlan_adjust_ie_in_bss_entry(pmpriv, pnew_beacon);
|
|
|
|
/* Increment the end pointer by the size reserved */
|
|
pmadapter->pbcn_buf_end +=
|
|
pnew_beacon->beacon_buf_size_max;
|
|
|
|
PRINTM(MINFO,
|
|
"AppControl: Beacon[%02d] sz=%03d,"
|
|
" used = %04d, left = %04d\n",
|
|
beacon_idx, pnew_beacon->beacon_buf_size,
|
|
(pmadapter->pbcn_buf_end - pmadapter->bcn_buf),
|
|
(pmadapter->bcn_buf_size -
|
|
(pmadapter->pbcn_buf_end - pmadapter->bcn_buf)));
|
|
} else {
|
|
/*
|
|
* No space for new beacon
|
|
*/
|
|
PRINTM(MCMND,
|
|
"AppControl: No space beacon (%d): " MACSTR
|
|
"; sz=%03d, left=%03d\n",
|
|
beacon_idx, MAC2STR(pnew_beacon->mac_address),
|
|
pnew_beacon->beacon_buf_size,
|
|
(pmadapter->bcn_buf_size -
|
|
(pmadapter->pbcn_buf_end - pmadapter->bcn_buf)));
|
|
|
|
/*
|
|
* Storage failure; clear storage records
|
|
* for this bcn
|
|
*/
|
|
pnew_beacon->pbeacon_buf = MNULL;
|
|
pnew_beacon->beacon_buf_size = 0;
|
|
pnew_beacon->beacon_buf_size_max = 0;
|
|
wlan_adjust_ie_in_bss_entry(pmpriv, pnew_beacon);
|
|
}
|
|
}
|
|
|
|
LEAVE();
|
|
}
|
|
|
|
/**
|
|
* @brief update beacon buffer of the current bss descriptor
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS, otherwise failure
|
|
*/
|
|
static mlan_status wlan_update_curr_bcn(mlan_private *pmpriv)
|
|
{
|
|
BSSDescriptor_t *pcurr_bss = &pmpriv->curr_bss_params.bss_descriptor;
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
|
|
ENTER();
|
|
|
|
if (pmpriv->pcurr_bcn_buf && pmpriv->curr_bcn_size) {
|
|
pcurr_bss->pbeacon_buf = pmpriv->pcurr_bcn_buf;
|
|
pcurr_bss->beacon_buf_size = pmpriv->curr_bcn_size;
|
|
pcurr_bss->beacon_buf_size_max = pmpriv->curr_bcn_size;
|
|
|
|
/* adjust the pointers in the current bss descriptor */
|
|
if (pcurr_bss->pwpa_ie) {
|
|
pcurr_bss->pwpa_ie =
|
|
(IEEEtypes_VendorSpecific_t
|
|
*)(pcurr_bss->pbeacon_buf +
|
|
pcurr_bss->wpa_offset);
|
|
}
|
|
if (pcurr_bss->prsn_ie) {
|
|
pcurr_bss->prsn_ie =
|
|
(IEEEtypes_Generic_t *)(pcurr_bss->pbeacon_buf +
|
|
pcurr_bss->rsn_offset);
|
|
}
|
|
if (pcurr_bss->pmd_ie) {
|
|
pcurr_bss->pmd_ie = (IEEEtypes_MobilityDomain_t
|
|
*)(pcurr_bss->pbeacon_buf +
|
|
pcurr_bss->md_offset);
|
|
}
|
|
if (pcurr_bss->pht_cap) {
|
|
pcurr_bss->pht_cap =
|
|
(IEEEtypes_HTCap_t *)(pcurr_bss->pbeacon_buf +
|
|
pcurr_bss->ht_cap_offset);
|
|
}
|
|
|
|
if (pcurr_bss->pht_info) {
|
|
pcurr_bss->pht_info =
|
|
(IEEEtypes_HTInfo_t
|
|
*)(pcurr_bss->pbeacon_buf +
|
|
pcurr_bss->ht_info_offset);
|
|
}
|
|
|
|
if (pcurr_bss->pbss_co_2040) {
|
|
pcurr_bss->pbss_co_2040 =
|
|
(IEEEtypes_2040BSSCo_t
|
|
*)(pcurr_bss->pbeacon_buf +
|
|
pcurr_bss->bss_co_2040_offset);
|
|
}
|
|
|
|
if (pcurr_bss->pext_cap) {
|
|
pcurr_bss->pext_cap =
|
|
(IEEEtypes_ExtCap_t
|
|
*)(pcurr_bss->pbeacon_buf +
|
|
pcurr_bss->ext_cap_offset);
|
|
}
|
|
|
|
if (pcurr_bss->poverlap_bss_scan_param) {
|
|
pcurr_bss->poverlap_bss_scan_param =
|
|
(IEEEtypes_OverlapBSSScanParam_t
|
|
*)(pcurr_bss->pbeacon_buf +
|
|
pcurr_bss->overlap_bss_offset);
|
|
}
|
|
|
|
if (pcurr_bss->pvht_cap) {
|
|
pcurr_bss->pvht_cap =
|
|
(IEEEtypes_VHTCap_t
|
|
*)(pcurr_bss->pbeacon_buf +
|
|
pcurr_bss->vht_cap_offset);
|
|
}
|
|
|
|
if (pcurr_bss->pvht_oprat) {
|
|
pcurr_bss->pvht_oprat =
|
|
(IEEEtypes_VHTOprat_t
|
|
*)(pcurr_bss->pbeacon_buf +
|
|
pcurr_bss->vht_oprat_offset);
|
|
}
|
|
|
|
if (pcurr_bss->pvht_txpower) {
|
|
pcurr_bss->pvht_txpower =
|
|
(IEEEtypes_VHTtxpower_t
|
|
*)(pcurr_bss->pbeacon_buf +
|
|
pcurr_bss->vht_txpower_offset);
|
|
}
|
|
|
|
if (pcurr_bss->pext_pwer) {
|
|
pcurr_bss->pext_pwer =
|
|
(IEEEtypes_ExtPwerCons_t
|
|
*)(pcurr_bss->pbeacon_buf +
|
|
pcurr_bss->ext_pwer_offset);
|
|
}
|
|
|
|
if (pcurr_bss->pext_bssload) {
|
|
pcurr_bss->pext_bssload =
|
|
(IEEEtypes_ExtBSSload_t
|
|
*)(pcurr_bss->pbeacon_buf +
|
|
pcurr_bss->ext_bssload_offset);
|
|
}
|
|
|
|
if (pcurr_bss->pquiet_chan) {
|
|
pcurr_bss->pquiet_chan =
|
|
(IEEEtypes_QuietChan_t
|
|
*)(pcurr_bss->pbeacon_buf +
|
|
pcurr_bss->quiet_chan_offset);
|
|
}
|
|
|
|
if (pcurr_bss->poper_mode) {
|
|
pcurr_bss->poper_mode =
|
|
(IEEEtypes_OperModeNtf_t
|
|
*)(pcurr_bss->pbeacon_buf +
|
|
pcurr_bss->oper_mode_offset);
|
|
}
|
|
if (pcurr_bss->phe_cap) {
|
|
pcurr_bss->phe_cap =
|
|
(IEEEtypes_HECap_t *)(pcurr_bss->pbeacon_buf +
|
|
pcurr_bss->he_cap_offset);
|
|
}
|
|
|
|
if (pcurr_bss->phe_oprat) {
|
|
pcurr_bss->phe_oprat =
|
|
(IEEEtypes_Extension_t
|
|
*)(pcurr_bss->pbeacon_buf +
|
|
pcurr_bss->he_oprat_offset);
|
|
}
|
|
|
|
PRINTM(MINFO, "current beacon restored %d\n",
|
|
pmpriv->curr_bcn_size);
|
|
} else {
|
|
PRINTM(MERROR, "curr_bcn_buf not saved\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief get the chan load from chan stats.
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param channel channel *
|
|
*
|
|
* @return channel load
|
|
*/
|
|
static t_u16 wlan_get_chan_load(mlan_adapter *pmadapter, t_u8 channel)
|
|
{
|
|
t_u16 chan_load = 0;
|
|
int i;
|
|
for (i = 0; i < (int)pmadapter->num_in_chan_stats; i++) {
|
|
if ((pmadapter->pchan_stats[i].chan_num == channel) &&
|
|
pmadapter->pchan_stats[i].cca_scan_duration) {
|
|
chan_load =
|
|
(pmadapter->pchan_stats[i].cca_busy_duration *
|
|
100) /
|
|
pmadapter->pchan_stats[i].cca_scan_duration;
|
|
break;
|
|
}
|
|
}
|
|
return chan_load;
|
|
}
|
|
|
|
/**
|
|
* @brief get the chan min/max rssi
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param channel channel *
|
|
* @param min_flag flag to get min rssi
|
|
* @return rssi
|
|
*/
|
|
static t_u8 wlan_get_chan_rssi(mlan_adapter *pmadapter, t_u8 channel,
|
|
t_u8 min_flag)
|
|
{
|
|
t_u8 rssi = 0;
|
|
int i;
|
|
for (i = 0; i < (int)pmadapter->num_in_scan_table; i++) {
|
|
if (pmadapter->pscan_table[i].channel == channel) {
|
|
if (rssi == 0)
|
|
rssi = (t_s32)pmadapter->pscan_table[i].rssi;
|
|
else {
|
|
if (min_flag)
|
|
rssi = MIN(
|
|
rssi,
|
|
pmadapter->pscan_table[i].rssi);
|
|
else
|
|
rssi = MAX(
|
|
rssi,
|
|
pmadapter->pscan_table[i].rssi);
|
|
}
|
|
}
|
|
}
|
|
return rssi;
|
|
}
|
|
|
|
/**
|
|
* @brief update the min/max rssi for channel statistics.
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @return N/A
|
|
*/
|
|
static t_void wlan_update_chan_rssi(mlan_adapter *pmadapter)
|
|
{
|
|
int i;
|
|
t_s8 min_rssi = 0;
|
|
t_s8 max_rssi = 0;
|
|
t_s8 rss = 0;
|
|
for (i = 0; i < (int)pmadapter->num_in_chan_stats; i++) {
|
|
if (pmadapter->pchan_stats[i].chan_num &&
|
|
pmadapter->pchan_stats[i].cca_scan_duration) {
|
|
min_rssi = -wlan_get_chan_rssi(
|
|
pmadapter, pmadapter->pchan_stats[i].chan_num,
|
|
MFALSE);
|
|
max_rssi = -wlan_get_chan_rssi(
|
|
pmadapter, pmadapter->pchan_stats[i].chan_num,
|
|
MTRUE);
|
|
rss = min_rssi - pmadapter->pchan_stats[i].noise;
|
|
// rss should always > 0, FW need fix the wrong
|
|
// rssi/noise in scantable
|
|
if (rss > 0)
|
|
pmadapter->pchan_stats[i].min_rss = rss;
|
|
else
|
|
pmadapter->pchan_stats[i].min_rss = 0;
|
|
|
|
rss = max_rssi - pmadapter->pchan_stats[i].noise;
|
|
if (rss > 0)
|
|
pmadapter->pchan_stats[i].max_rss = rss;
|
|
else
|
|
pmadapter->pchan_stats[i].max_rss = 0;
|
|
PRINTM(MCMND,
|
|
"chan=%d, min_rssi=%d, max_rssi=%d noise=%d min_rss=%d, max_rss=%d\n",
|
|
pmadapter->pchan_stats[i].chan_num, min_rssi,
|
|
max_rssi, pmadapter->pchan_stats[i].noise,
|
|
pmadapter->pchan_stats[i].min_rss,
|
|
pmadapter->pchan_stats[i].max_rss);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* @brief Post process the scan table after a new scan command has completed
|
|
*
|
|
* Inspect each entry of the scan table and try to find an entry that
|
|
* matches our current associated/joined network from the scan. If
|
|
* one is found, update the stored copy of the BSSDescriptor for our
|
|
* current network.
|
|
*
|
|
* Debug dump the current scan table contents if compiled accordingly.
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
*
|
|
* @return N/A
|
|
*/
|
|
static t_void wlan_scan_process_results(mlan_private *pmpriv)
|
|
{
|
|
mlan_adapter *pmadapter = pmpriv->adapter;
|
|
t_s32 j;
|
|
t_u32 i;
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
BSSDescriptor_t *bss_new_entry = MNULL;
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
|
|
ENTER();
|
|
|
|
if (pmpriv->media_connected == MTRUE) {
|
|
j = wlan_find_bssid_in_list(
|
|
pmpriv,
|
|
pmpriv->curr_bss_params.bss_descriptor.mac_address,
|
|
pmpriv->bss_mode);
|
|
|
|
if (j >= 0) {
|
|
memcpy_ext(pmadapter, &pmadapter->pscan_table[j].ssid,
|
|
&pmpriv->curr_bss_params.bss_descriptor.ssid,
|
|
sizeof(mlan_802_11_ssid),
|
|
sizeof(mlan_802_11_ssid));
|
|
pmadapter->callbacks.moal_spin_lock(
|
|
pmadapter->pmoal_handle,
|
|
pmpriv->curr_bcn_buf_lock);
|
|
pmpriv->curr_bss_params.bss_descriptor.pwpa_ie = MNULL;
|
|
pmpriv->curr_bss_params.bss_descriptor.wpa_offset = 0;
|
|
pmpriv->curr_bss_params.bss_descriptor.prsn_ie = MNULL;
|
|
pmpriv->curr_bss_params.bss_descriptor.rsn_offset = 0;
|
|
pmpriv->curr_bss_params.bss_descriptor.pwapi_ie = MNULL;
|
|
pmpriv->curr_bss_params.bss_descriptor.wapi_offset = 0;
|
|
|
|
pmpriv->curr_bss_params.bss_descriptor.posen_ie = MNULL;
|
|
pmpriv->curr_bss_params.bss_descriptor.osen_offset = 0;
|
|
pmpriv->curr_bss_params.bss_descriptor.pmd_ie = MNULL;
|
|
pmpriv->curr_bss_params.bss_descriptor.md_offset = 0;
|
|
pmpriv->curr_bss_params.bss_descriptor.pht_cap = MNULL;
|
|
pmpriv->curr_bss_params.bss_descriptor.ht_cap_offset =
|
|
0;
|
|
pmpriv->curr_bss_params.bss_descriptor.pht_info = MNULL;
|
|
pmpriv->curr_bss_params.bss_descriptor.ht_info_offset =
|
|
0;
|
|
pmpriv->curr_bss_params.bss_descriptor.pbss_co_2040 =
|
|
MNULL;
|
|
pmpriv->curr_bss_params.bss_descriptor
|
|
.bss_co_2040_offset = 0;
|
|
pmpriv->curr_bss_params.bss_descriptor.pext_cap = MNULL;
|
|
pmpriv->curr_bss_params.bss_descriptor.ext_cap_offset =
|
|
0;
|
|
pmpriv->curr_bss_params.bss_descriptor
|
|
.poverlap_bss_scan_param = MNULL;
|
|
pmpriv->curr_bss_params.bss_descriptor
|
|
.overlap_bss_offset = 0;
|
|
pmpriv->curr_bss_params.bss_descriptor.pvht_cap = MNULL;
|
|
pmpriv->curr_bss_params.bss_descriptor.vht_cap_offset =
|
|
0;
|
|
pmpriv->curr_bss_params.bss_descriptor.pvht_oprat =
|
|
MNULL;
|
|
pmpriv->curr_bss_params.bss_descriptor.vht_oprat_offset =
|
|
0;
|
|
pmpriv->curr_bss_params.bss_descriptor.pvht_txpower =
|
|
MNULL;
|
|
pmpriv->curr_bss_params.bss_descriptor
|
|
.vht_txpower_offset = 0;
|
|
pmpriv->curr_bss_params.bss_descriptor.pext_pwer =
|
|
MNULL;
|
|
pmpriv->curr_bss_params.bss_descriptor.ext_pwer_offset =
|
|
0;
|
|
pmpriv->curr_bss_params.bss_descriptor.pext_bssload =
|
|
MNULL;
|
|
pmpriv->curr_bss_params.bss_descriptor
|
|
.ext_bssload_offset = 0;
|
|
pmpriv->curr_bss_params.bss_descriptor.pquiet_chan =
|
|
MNULL;
|
|
pmpriv->curr_bss_params.bss_descriptor
|
|
.quiet_chan_offset = 0;
|
|
pmpriv->curr_bss_params.bss_descriptor.poper_mode =
|
|
MNULL;
|
|
pmpriv->curr_bss_params.bss_descriptor.oper_mode_offset =
|
|
0;
|
|
pmpriv->curr_bss_params.bss_descriptor.phe_cap = MNULL;
|
|
pmpriv->curr_bss_params.bss_descriptor.he_cap_offset =
|
|
0;
|
|
pmpriv->curr_bss_params.bss_descriptor.phe_oprat =
|
|
MNULL;
|
|
pmpriv->curr_bss_params.bss_descriptor.he_oprat_offset =
|
|
0;
|
|
pmpriv->curr_bss_params.bss_descriptor.pbeacon_buf =
|
|
MNULL;
|
|
pmpriv->curr_bss_params.bss_descriptor.beacon_buf_size =
|
|
0;
|
|
pmpriv->curr_bss_params.bss_descriptor
|
|
.beacon_buf_size_max = 0;
|
|
|
|
PRINTM(MINFO,
|
|
"Found current ssid/bssid in list @ index #%d\n",
|
|
j);
|
|
/* Make a copy of current BSSID descriptor */
|
|
memcpy_ext(
|
|
pmadapter,
|
|
&pmpriv->curr_bss_params.bss_descriptor,
|
|
&pmadapter->pscan_table[j],
|
|
sizeof(pmpriv->curr_bss_params.bss_descriptor),
|
|
sizeof(pmpriv->curr_bss_params.bss_descriptor));
|
|
|
|
pmadapter->callbacks.moal_spin_unlock(
|
|
pmadapter->pmoal_handle,
|
|
pmpriv->curr_bcn_buf_lock);
|
|
wlan_save_curr_bcn(pmpriv);
|
|
} else {
|
|
// Apend to the end of scan table
|
|
if (pmpriv->pcurr_bcn_buf && pmpriv->curr_bcn_size) {
|
|
ret = pcb->moal_malloc(pmadapter->pmoal_handle,
|
|
sizeof(BSSDescriptor_t),
|
|
MLAN_MEM_DEF,
|
|
(t_u8 **)&bss_new_entry);
|
|
if (ret == MLAN_STATUS_SUCCESS &&
|
|
bss_new_entry) {
|
|
memcpy_ext(
|
|
pmadapter, bss_new_entry,
|
|
&pmpriv->curr_bss_params
|
|
.bss_descriptor,
|
|
sizeof(pmpriv->curr_bss_params
|
|
.bss_descriptor),
|
|
sizeof(BSSDescriptor_t));
|
|
if (pmadapter->num_in_scan_table <
|
|
MRVDRV_MAX_BSSID_LIST)
|
|
pmadapter->num_in_scan_table++;
|
|
pmadapter
|
|
->pscan_table
|
|
[pmadapter->num_in_scan_table -
|
|
1]
|
|
.pbeacon_buf = MNULL;
|
|
wlan_ret_802_11_scan_store_beacon(
|
|
pmpriv,
|
|
pmadapter->num_in_scan_table -
|
|
1,
|
|
pmadapter->num_in_scan_table,
|
|
bss_new_entry);
|
|
if (bss_new_entry->pbeacon_buf == MNULL)
|
|
pmadapter->num_in_scan_table--;
|
|
else
|
|
memcpy_ext(
|
|
pmadapter,
|
|
&pmadapter->pscan_table
|
|
[pmadapter->num_in_scan_table -
|
|
1],
|
|
bss_new_entry,
|
|
sizeof(BSSDescriptor_t),
|
|
sizeof(BSSDescriptor_t));
|
|
pcb->moal_mfree(pmadapter->pmoal_handle,
|
|
(t_u8 *)bss_new_entry);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < pmadapter->num_in_scan_table; i++) {
|
|
PRINTM(MINFO,
|
|
"Scan:(%02d) " MACSTR ", "
|
|
"RSSI[%03d], SSID[%s]\n",
|
|
i, MAC2STR(pmadapter->pscan_table[i].mac_address),
|
|
(t_s32)pmadapter->pscan_table[i].rssi,
|
|
pmadapter->pscan_table[i].ssid.ssid);
|
|
pmadapter->pscan_table[i].chan_load = wlan_get_chan_load(
|
|
pmadapter, pmadapter->pscan_table[i].channel);
|
|
}
|
|
wlan_update_chan_rssi(pmadapter);
|
|
|
|
/*
|
|
* Prepares domain info from scan table and downloads the
|
|
* domain info command to the FW.
|
|
*/
|
|
wlan_11d_prepare_dnld_domain_info_cmd(pmpriv);
|
|
PRINTM(MMSG, "wlan: SCAN COMPLETED: scanned AP count=%d\n",
|
|
pmadapter->num_in_scan_table);
|
|
LEAVE();
|
|
}
|
|
|
|
/**
|
|
* @brief Delete a specific indexed entry from the scan table.
|
|
*
|
|
* Delete the scan table entry indexed by table_idx. Compact the remaining
|
|
* entries and adjust any buffering of beacon/probe response data
|
|
* if needed.
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @param table_idx Scan table entry index to delete from the table
|
|
*
|
|
* @return N/A
|
|
*
|
|
* @pre table_idx must be an index to a valid entry
|
|
*/
|
|
static t_void wlan_scan_delete_table_entry(mlan_private *pmpriv,
|
|
t_s32 table_idx)
|
|
{
|
|
mlan_adapter *pmadapter = pmpriv->adapter;
|
|
t_u32 del_idx;
|
|
t_u32 beacon_buf_adj;
|
|
t_u8 *pbeacon_buf;
|
|
|
|
ENTER();
|
|
|
|
/*
|
|
* Shift the saved beacon buffer data for the scan table back over the
|
|
* entry being removed. Update the end of buffer pointer. Save the
|
|
* deleted buffer allocation size for pointer adjustments for entries
|
|
* compacted after the deleted index.
|
|
*/
|
|
beacon_buf_adj = pmadapter->pscan_table[table_idx].beacon_buf_size_max;
|
|
|
|
PRINTM(MINFO,
|
|
"Scan: Delete Entry %d, beacon buffer removal = %d bytes\n",
|
|
table_idx, beacon_buf_adj);
|
|
|
|
/* Check if the table entry had storage allocated for its beacon */
|
|
if (beacon_buf_adj) {
|
|
pbeacon_buf = pmadapter->pscan_table[table_idx].pbeacon_buf;
|
|
|
|
/*
|
|
* Remove the entry's buffer space, decrement the table
|
|
* end pointer by the amount we are removing
|
|
*/
|
|
pmadapter->pbcn_buf_end -= beacon_buf_adj;
|
|
|
|
PRINTM(MINFO,
|
|
"Scan: Delete Entry %d, compact data: %p <- %p (sz = %d)\n",
|
|
table_idx, pbeacon_buf, pbeacon_buf + beacon_buf_adj,
|
|
pmadapter->pbcn_buf_end - pbeacon_buf);
|
|
|
|
/*
|
|
* Compact data storage. Copy all data after the deleted
|
|
* entry's end address (pbeacon_buf + beacon_buf_adj) back to
|
|
* the original start address (pbeacon_buf).
|
|
*
|
|
* Scan table entries affected by the move will have their entry
|
|
* pointer adjusted below.
|
|
*
|
|
* Use memmove since the dest/src memory regions overlap.
|
|
*/
|
|
memmove(pmadapter, pbeacon_buf,
|
|
(void *)((t_ptr)pbeacon_buf + (t_ptr)beacon_buf_adj),
|
|
(t_u32)((t_ptr)pmadapter->pbcn_buf_end -
|
|
(t_ptr)pbeacon_buf));
|
|
}
|
|
|
|
PRINTM(MINFO, "Scan: Delete Entry %d, num_in_scan_table = %d\n",
|
|
table_idx, pmadapter->num_in_scan_table);
|
|
|
|
/*
|
|
* Shift all of the entries after the table_idx back by one, compacting
|
|
* the table and removing the requested entry
|
|
*/
|
|
for (del_idx = table_idx; (del_idx + 1) < pmadapter->num_in_scan_table;
|
|
del_idx++) {
|
|
/* Copy the next entry over this one */
|
|
memcpy_ext(pmadapter, pmadapter->pscan_table + del_idx,
|
|
pmadapter->pscan_table + del_idx + 1,
|
|
sizeof(BSSDescriptor_t), sizeof(BSSDescriptor_t));
|
|
|
|
/*
|
|
* Adjust this entry's pointer to its beacon buffer based on the
|
|
* removed/compacted entry from the deleted index. Don't
|
|
* decrement if the buffer pointer is MNULL (no data stored for
|
|
* this entry).
|
|
*/
|
|
if (pmadapter->pscan_table[del_idx].pbeacon_buf) {
|
|
pmadapter->pscan_table[del_idx].pbeacon_buf -=
|
|
beacon_buf_adj;
|
|
if (pmadapter->pscan_table[del_idx].pwpa_ie) {
|
|
pmadapter->pscan_table[del_idx].pwpa_ie =
|
|
(IEEEtypes_VendorSpecific_t
|
|
*)(pmadapter
|
|
->pscan_table[del_idx]
|
|
.pbeacon_buf +
|
|
pmadapter
|
|
->pscan_table[del_idx]
|
|
.wpa_offset);
|
|
}
|
|
if (pmadapter->pscan_table[del_idx].prsn_ie) {
|
|
pmadapter->pscan_table[del_idx].prsn_ie =
|
|
(IEEEtypes_Generic_t
|
|
*)(pmadapter
|
|
->pscan_table[del_idx]
|
|
.pbeacon_buf +
|
|
pmadapter
|
|
->pscan_table[del_idx]
|
|
.rsn_offset);
|
|
}
|
|
if (pmadapter->pscan_table[del_idx].pwapi_ie) {
|
|
pmadapter->pscan_table[del_idx].pwapi_ie =
|
|
(IEEEtypes_Generic_t
|
|
*)(pmadapter
|
|
->pscan_table[del_idx]
|
|
.pbeacon_buf +
|
|
pmadapter
|
|
->pscan_table[del_idx]
|
|
.wapi_offset);
|
|
}
|
|
|
|
if (pmadapter->pscan_table[del_idx].posen_ie) {
|
|
pmadapter->pscan_table[del_idx].posen_ie =
|
|
(IEEEtypes_Generic_t
|
|
*)(pmadapter
|
|
->pscan_table[del_idx]
|
|
.pbeacon_buf +
|
|
pmadapter
|
|
->pscan_table[del_idx]
|
|
.osen_offset);
|
|
}
|
|
if (pmadapter->pscan_table[del_idx].pmd_ie) {
|
|
pmadapter->pscan_table[del_idx].pmd_ie =
|
|
(IEEEtypes_MobilityDomain_t
|
|
*)(pmadapter
|
|
->pscan_table[del_idx]
|
|
.pbeacon_buf +
|
|
pmadapter
|
|
->pscan_table[del_idx]
|
|
.md_offset);
|
|
}
|
|
if (pmadapter->pscan_table[del_idx].pht_cap) {
|
|
pmadapter->pscan_table[del_idx].pht_cap =
|
|
(IEEEtypes_HTCap_t
|
|
*)(pmadapter
|
|
->pscan_table[del_idx]
|
|
.pbeacon_buf +
|
|
pmadapter
|
|
->pscan_table[del_idx]
|
|
.ht_cap_offset);
|
|
}
|
|
|
|
if (pmadapter->pscan_table[del_idx].pht_info) {
|
|
pmadapter->pscan_table[del_idx].pht_info =
|
|
(IEEEtypes_HTInfo_t
|
|
*)(pmadapter
|
|
->pscan_table[del_idx]
|
|
.pbeacon_buf +
|
|
pmadapter
|
|
->pscan_table[del_idx]
|
|
.ht_info_offset);
|
|
}
|
|
if (pmadapter->pscan_table[del_idx].pbss_co_2040) {
|
|
pmadapter->pscan_table[del_idx].pbss_co_2040 =
|
|
(IEEEtypes_2040BSSCo_t
|
|
*)(pmadapter
|
|
->pscan_table[del_idx]
|
|
.pbeacon_buf +
|
|
pmadapter
|
|
->pscan_table[del_idx]
|
|
.bss_co_2040_offset);
|
|
}
|
|
if (pmadapter->pscan_table[del_idx].pext_cap) {
|
|
pmadapter->pscan_table[del_idx].pext_cap =
|
|
(IEEEtypes_ExtCap_t
|
|
*)(pmadapter
|
|
->pscan_table[del_idx]
|
|
.pbeacon_buf +
|
|
pmadapter
|
|
->pscan_table[del_idx]
|
|
.ext_cap_offset);
|
|
}
|
|
if (pmadapter->pscan_table[del_idx]
|
|
.poverlap_bss_scan_param) {
|
|
pmadapter->pscan_table[del_idx]
|
|
.poverlap_bss_scan_param =
|
|
(IEEEtypes_OverlapBSSScanParam_t
|
|
*)(pmadapter
|
|
->pscan_table[del_idx]
|
|
.pbeacon_buf +
|
|
pmadapter
|
|
->pscan_table[del_idx]
|
|
.overlap_bss_offset);
|
|
}
|
|
|
|
if (pmadapter->pscan_table[del_idx].pvht_cap) {
|
|
pmadapter->pscan_table[del_idx].pvht_cap =
|
|
(IEEEtypes_VHTCap_t
|
|
*)(pmadapter
|
|
->pscan_table[del_idx]
|
|
.pbeacon_buf +
|
|
pmadapter
|
|
->pscan_table[del_idx]
|
|
.vht_cap_offset);
|
|
}
|
|
|
|
if (pmadapter->pscan_table[del_idx].pvht_oprat) {
|
|
pmadapter->pscan_table[del_idx].pvht_oprat =
|
|
(IEEEtypes_VHTOprat_t
|
|
*)(pmadapter
|
|
->pscan_table[del_idx]
|
|
.pbeacon_buf +
|
|
pmadapter
|
|
->pscan_table[del_idx]
|
|
.vht_oprat_offset);
|
|
}
|
|
if (pmadapter->pscan_table[del_idx].pvht_txpower) {
|
|
pmadapter->pscan_table[del_idx].pvht_txpower =
|
|
(IEEEtypes_VHTtxpower_t
|
|
*)(pmadapter
|
|
->pscan_table[del_idx]
|
|
.pbeacon_buf +
|
|
pmadapter
|
|
->pscan_table[del_idx]
|
|
.vht_txpower_offset);
|
|
}
|
|
if (pmadapter->pscan_table[del_idx].pext_pwer) {
|
|
pmadapter->pscan_table[del_idx].pext_pwer =
|
|
(IEEEtypes_ExtPwerCons_t
|
|
*)(pmadapter
|
|
->pscan_table[del_idx]
|
|
.pbeacon_buf +
|
|
pmadapter
|
|
->pscan_table[del_idx]
|
|
.ext_pwer_offset);
|
|
}
|
|
if (pmadapter->pscan_table[del_idx].pext_bssload) {
|
|
pmadapter->pscan_table[del_idx].pext_bssload =
|
|
(IEEEtypes_ExtBSSload_t
|
|
*)(pmadapter
|
|
->pscan_table[del_idx]
|
|
.pbeacon_buf +
|
|
pmadapter
|
|
->pscan_table[del_idx]
|
|
.ext_bssload_offset);
|
|
}
|
|
if (pmadapter->pscan_table[del_idx].pquiet_chan) {
|
|
pmadapter->pscan_table[del_idx].pquiet_chan =
|
|
(IEEEtypes_QuietChan_t
|
|
*)(pmadapter
|
|
->pscan_table[del_idx]
|
|
.pbeacon_buf +
|
|
pmadapter
|
|
->pscan_table[del_idx]
|
|
.quiet_chan_offset);
|
|
}
|
|
if (pmadapter->pscan_table[del_idx].poper_mode) {
|
|
pmadapter->pscan_table[del_idx].poper_mode =
|
|
(IEEEtypes_OperModeNtf_t
|
|
*)(pmadapter
|
|
->pscan_table[del_idx]
|
|
.pbeacon_buf +
|
|
pmadapter
|
|
->pscan_table[del_idx]
|
|
.oper_mode_offset);
|
|
}
|
|
if (pmadapter->pscan_table[del_idx].phe_cap) {
|
|
pmadapter->pscan_table[del_idx].phe_cap =
|
|
(IEEEtypes_HECap_t
|
|
*)(pmadapter
|
|
->pscan_table[del_idx]
|
|
.pbeacon_buf +
|
|
pmadapter
|
|
->pscan_table[del_idx]
|
|
.he_cap_offset);
|
|
}
|
|
if (pmadapter->pscan_table[del_idx].phe_oprat) {
|
|
pmadapter->pscan_table[del_idx].phe_oprat =
|
|
(IEEEtypes_Extension_t
|
|
*)(pmadapter
|
|
->pscan_table[del_idx]
|
|
.pbeacon_buf +
|
|
pmadapter
|
|
->pscan_table[del_idx]
|
|
.he_oprat_offset);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* The last entry is invalid now that it has been deleted or moved back
|
|
*/
|
|
memset(pmadapter,
|
|
pmadapter->pscan_table + pmadapter->num_in_scan_table - 1, 0x00,
|
|
sizeof(BSSDescriptor_t));
|
|
|
|
pmadapter->num_in_scan_table--;
|
|
|
|
LEAVE();
|
|
}
|
|
|
|
/**
|
|
* @brief Delete all entry's age out
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
*
|
|
* @return N/A
|
|
*/
|
|
static void wlan_scan_delete_ageout_entry(mlan_private *pmpriv)
|
|
{
|
|
BSSDescriptor_t *pbss_entry;
|
|
mlan_adapter *pmadapter = pmpriv->adapter;
|
|
t_s32 table_idx = pmadapter->num_in_scan_table - 1;
|
|
t_u32 i = 0;
|
|
t_u32 age_in_secs = 0;
|
|
t_u32 age_ts_usec = 0;
|
|
|
|
ENTER();
|
|
#define SCAN_RESULT_AGEOUT 10
|
|
pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
|
|
&age_in_secs, &age_ts_usec);
|
|
|
|
for (i = 0; i < pmadapter->num_in_scan_table; i++) {
|
|
pbss_entry = &pmadapter->pscan_table[table_idx];
|
|
if (age_in_secs >
|
|
(pbss_entry->age_in_secs + SCAN_RESULT_AGEOUT)) {
|
|
PRINTM(MCMND,
|
|
"SCAN: ageout AP MAC Addr-" MACSTR
|
|
" ssid: %-32s\n",
|
|
MAC2STR(pbss_entry->mac_address),
|
|
pbss_entry->ssid.ssid);
|
|
wlan_scan_delete_table_entry(pmpriv, table_idx);
|
|
}
|
|
table_idx--;
|
|
}
|
|
LEAVE();
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* @brief Delete all occurrences of a given SSID from the scan table
|
|
*
|
|
* Iterate through the scan table and delete all entries that match a given
|
|
* SSID. Compact the remaining scan table entries.
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @param pdel_ssid Pointer to an SSID to be used in deleting all
|
|
* matching SSIDs from the scan table
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status
|
|
wlan_scan_delete_ssid_table_entry(mlan_private *pmpriv,
|
|
mlan_802_11_ssid *pdel_ssid)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_FAILURE;
|
|
t_s32 table_idx;
|
|
|
|
ENTER();
|
|
|
|
PRINTM(MINFO, "Scan: Delete Ssid Entry: %-32s\n", pdel_ssid->ssid);
|
|
|
|
/*
|
|
* If the requested SSID is found in the table, delete it. Then keep
|
|
* searching the table for multiple entries for the SSID until no
|
|
* more are found
|
|
*/
|
|
while ((table_idx = wlan_find_ssid_in_list(pmpriv, pdel_ssid, MNULL,
|
|
MLAN_BSS_MODE_AUTO)) >= 0) {
|
|
PRINTM(MINFO, "Scan: Delete SSID Entry: Found Idx = %d\n",
|
|
table_idx);
|
|
ret = MLAN_STATUS_SUCCESS;
|
|
wlan_scan_delete_table_entry(pmpriv, table_idx);
|
|
}
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/********************************************************
|
|
Global Functions
|
|
********************************************************/
|
|
|
|
/**
|
|
* @brief Check if a scanned network compatible with the driver settings
|
|
*
|
|
* WEP WPA WPA2 ad-hoc encrypt Network
|
|
* enabled enabled enabled AES mode Privacy WPA WPA2 Compatible
|
|
* 0 0 0 0 NONE 0 0 0 yes No security
|
|
* 0 1 0 0 x 1x 1 x yes WPA (disable
|
|
* HT if no AES) 0 0 1 0 x 1x x 1 yes
|
|
* WPA2 (disable HT if no AES) 0 0 0 1 NONE 1 0 0
|
|
* yes Ad-hoc AES 1 0 0 0 NONE 1 0 0 yes
|
|
* Static WEP (disable HT) 0 0 0 0 !=NONE 1 0 0
|
|
* yes Dynamic WEP
|
|
*
|
|
* @param pmpriv A pointer to mlan_private
|
|
* @param index Index in scan table to check against current driver settings
|
|
* @param mode Network mode: Infrastructure or IBSS
|
|
*
|
|
* @return Index in ScanTable, or negative value if error
|
|
*/
|
|
t_s32 wlan_is_network_compatible(mlan_private *pmpriv, t_u32 index, t_u32 mode)
|
|
{
|
|
mlan_adapter *pmadapter = pmpriv->adapter;
|
|
BSSDescriptor_t *pbss_desc;
|
|
|
|
ENTER();
|
|
|
|
pbss_desc = &pmadapter->pscan_table[index];
|
|
/* Don't check for compatibility if roaming */
|
|
if ((pmpriv->media_connected == MTRUE) &&
|
|
(pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) &&
|
|
(pbss_desc->bss_mode == MLAN_BSS_MODE_INFRA)) {
|
|
LEAVE();
|
|
return index;
|
|
}
|
|
|
|
pbss_desc->disable_11n = MFALSE;
|
|
|
|
/* if the HE CAP IE exists, HT CAP IE should exist too */
|
|
/* 2.4G AX AP, don't have VHT CAP */
|
|
if (pbss_desc->phe_cap && !pbss_desc->pht_cap) {
|
|
PRINTM(MINFO,
|
|
"Disable 11n if VHT CAP/HT CAP IE is not found from the 11AX AP\n");
|
|
pbss_desc->disable_11n = MTRUE;
|
|
}
|
|
|
|
/* if the VHT CAP IE exists, the HT CAP IE should exist too */
|
|
if (pbss_desc->pvht_cap && !pbss_desc->pht_cap) {
|
|
PRINTM(MINFO,
|
|
"Disable 11n if HT CAP IE is not found from the 11AC AP\n");
|
|
pbss_desc->disable_11n = MTRUE;
|
|
}
|
|
|
|
if (pbss_desc->wlan_11h_bss_info.chan_switch_ann.element_id ==
|
|
CHANNEL_SWITCH_ANN) {
|
|
PRINTM(MINFO,
|
|
"Don't connect to AP with CHANNEL_SWITCH_ANN IE.\n");
|
|
LEAVE();
|
|
return -1;
|
|
}
|
|
|
|
if (pmpriv->wps.session_enable == MTRUE) {
|
|
PRINTM(MINFO, "Return success directly in WPS period\n");
|
|
LEAVE();
|
|
return index;
|
|
}
|
|
|
|
if (pmpriv->sec_info.osen_enabled && pbss_desc->posen_ie &&
|
|
((*(pbss_desc->posen_ie)).ieee_hdr.element_id ==
|
|
VENDOR_SPECIFIC_221)) {
|
|
/* Hotspot 2.0 OSEN AKM */
|
|
PRINTM(MMSG,
|
|
"Return success directly in Hotspot OSEN: index=%d "
|
|
"encryption_mode=%#x\n",
|
|
index, pmpriv->sec_info.encryption_mode);
|
|
LEAVE();
|
|
return index;
|
|
}
|
|
|
|
if ((pbss_desc->bss_mode == mode) &&
|
|
(pmpriv->sec_info.ewpa_enabled == MTRUE
|
|
#ifdef DRV_EMBEDDED_SUPPLICANT
|
|
|| supplicantIsEnabled(pmpriv->psapriv)
|
|
#endif
|
|
)) {
|
|
if (((pbss_desc->pwpa_ie) &&
|
|
((*(pbss_desc->pwpa_ie)).vend_hdr.element_id == WPA_IE)) ||
|
|
((pbss_desc->prsn_ie) &&
|
|
((*(pbss_desc->prsn_ie)).ieee_hdr.element_id == RSN_IE))) {
|
|
if (((pmpriv->adapter->config_bands & BAND_GN ||
|
|
pmpriv->adapter->config_bands & BAND_AN) &&
|
|
pbss_desc->pht_cap) &&
|
|
(pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) &&
|
|
!is_wpa_oui_present(pmpriv->adapter, pbss_desc,
|
|
CIPHER_SUITE_CCMP) &&
|
|
!is_rsn_oui_present(pmpriv->adapter, pbss_desc,
|
|
CIPHER_SUITE_CCMP) &&
|
|
!is_rsn_oui_present(pmpriv->adapter, pbss_desc,
|
|
CIPHER_SUITE_GCMP) &&
|
|
!is_rsn_oui_present(pmpriv->adapter, pbss_desc,
|
|
CIPHER_SUITE_GCMP_256) &&
|
|
!is_rsn_oui_present(pmpriv->adapter, pbss_desc,
|
|
CIPHER_SUITE_CCMP_256)) {
|
|
if (is_wpa_oui_present(pmpriv->adapter,
|
|
pbss_desc,
|
|
CIPHER_SUITE_TKIP) ||
|
|
is_rsn_oui_present(pmpriv->adapter,
|
|
pbss_desc,
|
|
CIPHER_SUITE_TKIP)) {
|
|
PRINTM(MINFO,
|
|
"Disable 11n if AES is not supported by AP\n");
|
|
pbss_desc->disable_11n = MTRUE;
|
|
} else {
|
|
LEAVE();
|
|
return -1;
|
|
}
|
|
}
|
|
LEAVE();
|
|
return index;
|
|
} else {
|
|
PRINTM(MINFO,
|
|
"ewpa_enabled: Ignore none WPA/WPA2 AP\n");
|
|
LEAVE();
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if (pmpriv->sec_info.wapi_enabled &&
|
|
(pbss_desc->pwapi_ie &&
|
|
((*(pbss_desc->pwapi_ie)).ieee_hdr.element_id == WAPI_IE))) {
|
|
PRINTM(MINFO, "Return success for WAPI AP\n");
|
|
LEAVE();
|
|
return index;
|
|
}
|
|
|
|
if (pbss_desc->bss_mode == mode) {
|
|
if (pmpriv->sec_info.wep_status == Wlan802_11WEPDisabled &&
|
|
!pmpriv->sec_info.wpa_enabled &&
|
|
!pmpriv->sec_info.wpa2_enabled &&
|
|
((!pbss_desc->pwpa_ie) ||
|
|
((*(pbss_desc->pwpa_ie)).vend_hdr.element_id != WPA_IE)) &&
|
|
((!pbss_desc->prsn_ie) ||
|
|
((*(pbss_desc->prsn_ie)).ieee_hdr.element_id != RSN_IE)) &&
|
|
pmpriv->sec_info.encryption_mode ==
|
|
MLAN_ENCRYPTION_MODE_NONE &&
|
|
!pbss_desc->privacy) {
|
|
/* No security */
|
|
LEAVE();
|
|
return index;
|
|
} else if (pmpriv->sec_info.wep_status ==
|
|
Wlan802_11WEPEnabled &&
|
|
!pmpriv->sec_info.wpa_enabled &&
|
|
!pmpriv->sec_info.wpa2_enabled &&
|
|
pbss_desc->privacy) {
|
|
/* Static WEP enabled */
|
|
PRINTM(MINFO, "Disable 11n in WEP mode\n");
|
|
pbss_desc->disable_11n = MTRUE;
|
|
/* Reject the following cases: */
|
|
/*
|
|
* case 1: RSN IE w/o WEP OUI and WPA IE w/o WEP OUI
|
|
* case 2: RSN IE w/o WEP OUI and No WPA IE
|
|
* case 3: WPA IE w/o WEP OUI and No RSN IE
|
|
*/
|
|
if (((pbss_desc->prsn_ie) &&
|
|
((*(pbss_desc->prsn_ie)).ieee_hdr.element_id ==
|
|
RSN_IE)) ||
|
|
((pbss_desc->pwpa_ie) &&
|
|
((*(pbss_desc->pwpa_ie)).vend_hdr.element_id ==
|
|
WPA_IE))) {
|
|
if (!is_rsn_oui_present(pmpriv->adapter,
|
|
pbss_desc,
|
|
CIPHER_SUITE_WEP40) &&
|
|
!is_rsn_oui_present(pmpriv->adapter,
|
|
pbss_desc,
|
|
CIPHER_SUITE_WEP104) &&
|
|
!is_wpa_oui_present(pmpriv->adapter,
|
|
pbss_desc,
|
|
CIPHER_SUITE_WEP40) &&
|
|
!is_wpa_oui_present(pmpriv->adapter,
|
|
pbss_desc,
|
|
CIPHER_SUITE_WEP104))
|
|
index = -1;
|
|
}
|
|
|
|
LEAVE();
|
|
return index;
|
|
} else if (pmpriv->sec_info.wep_status ==
|
|
Wlan802_11WEPDisabled &&
|
|
pmpriv->sec_info.wpa_enabled &&
|
|
!pmpriv->sec_info.wpa2_enabled &&
|
|
((pbss_desc->pwpa_ie) &&
|
|
((*(pbss_desc->pwpa_ie)).vend_hdr.element_id ==
|
|
WPA_IE))
|
|
/*
|
|
* Privacy bit may NOT be set in some APs like
|
|
* LinkSys WRT54G && pbss_desc->privacy
|
|
*/
|
|
) {
|
|
PRINTM(MINFO,
|
|
"wlan_is_network_compatible() WPA: index=%d wpa_ie=%#x "
|
|
"rsn_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode=%#x "
|
|
"privacy=%#x\n",
|
|
index,
|
|
(pbss_desc->pwpa_ie) ?
|
|
(*(pbss_desc->pwpa_ie))
|
|
.vend_hdr.element_id :
|
|
0,
|
|
(pbss_desc->prsn_ie) ?
|
|
(*(pbss_desc->prsn_ie))
|
|
.ieee_hdr.element_id :
|
|
0,
|
|
(pmpriv->sec_info.wep_status ==
|
|
Wlan802_11WEPEnabled) ?
|
|
"e" :
|
|
"d",
|
|
(pmpriv->sec_info.wpa_enabled) ? "e" : "d",
|
|
(pmpriv->sec_info.wpa2_enabled) ? "e" : "d",
|
|
pmpriv->sec_info.encryption_mode,
|
|
pbss_desc->privacy);
|
|
if (((pmpriv->adapter->config_bands & BAND_GN ||
|
|
pmpriv->adapter->config_bands & BAND_AN) &&
|
|
pbss_desc->pht_cap) &&
|
|
(pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) &&
|
|
!is_wpa_oui_present(pmpriv->adapter, pbss_desc,
|
|
CIPHER_SUITE_CCMP)) {
|
|
if (is_wpa_oui_present(pmpriv->adapter,
|
|
pbss_desc,
|
|
CIPHER_SUITE_TKIP)) {
|
|
PRINTM(MINFO,
|
|
"Disable 11n if AES is not supported by AP\n");
|
|
pbss_desc->disable_11n = MTRUE;
|
|
} else {
|
|
LEAVE();
|
|
return -1;
|
|
}
|
|
}
|
|
LEAVE();
|
|
return index;
|
|
} else if (pmpriv->sec_info.wep_status ==
|
|
Wlan802_11WEPDisabled &&
|
|
!pmpriv->sec_info.wpa_enabled &&
|
|
pmpriv->sec_info.wpa2_enabled &&
|
|
((pbss_desc->prsn_ie) &&
|
|
((*(pbss_desc->prsn_ie)).ieee_hdr.element_id ==
|
|
RSN_IE))
|
|
/*
|
|
* Privacy bit may NOT be set in some APs like
|
|
* LinkSys WRT54G && pbss_desc->privacy
|
|
*/
|
|
) {
|
|
/* WPA2 enabled */
|
|
PRINTM(MINFO,
|
|
"wlan_is_network_compatible() WPA2: index=%d wpa_ie=%#x "
|
|
"rsn_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode=%#x "
|
|
"privacy=%#x\n",
|
|
index,
|
|
(pbss_desc->pwpa_ie) ?
|
|
(*(pbss_desc->pwpa_ie))
|
|
.vend_hdr.element_id :
|
|
0,
|
|
(pbss_desc->prsn_ie) ?
|
|
(*(pbss_desc->prsn_ie))
|
|
.ieee_hdr.element_id :
|
|
0,
|
|
(pmpriv->sec_info.wep_status ==
|
|
Wlan802_11WEPEnabled) ?
|
|
"e" :
|
|
"d",
|
|
(pmpriv->sec_info.wpa_enabled) ? "e" : "d",
|
|
(pmpriv->sec_info.wpa2_enabled) ? "e" : "d",
|
|
pmpriv->sec_info.encryption_mode,
|
|
pbss_desc->privacy);
|
|
if (((pmpriv->adapter->config_bands & BAND_GN ||
|
|
pmpriv->adapter->config_bands & BAND_AN) &&
|
|
pbss_desc->pht_cap) &&
|
|
(pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) &&
|
|
!is_rsn_oui_present(pmpriv->adapter, pbss_desc,
|
|
CIPHER_SUITE_CCMP) &&
|
|
!is_rsn_oui_present(pmpriv->adapter, pbss_desc,
|
|
CIPHER_SUITE_GCMP) &&
|
|
!is_rsn_oui_present(pmpriv->adapter, pbss_desc,
|
|
CIPHER_SUITE_GCMP_256) &&
|
|
!is_rsn_oui_present(pmpriv->adapter, pbss_desc,
|
|
CIPHER_SUITE_CCMP_256)) {
|
|
if (is_rsn_oui_present(pmpriv->adapter,
|
|
pbss_desc,
|
|
CIPHER_SUITE_TKIP)) {
|
|
PRINTM(MINFO,
|
|
"Disable 11n if AES is not supported by AP\n");
|
|
pbss_desc->disable_11n = MTRUE;
|
|
} else if (is_rsn_oui_present_in_wpa_ie(
|
|
pmpriv, CIPHER_SUITE_CCMP) ||
|
|
is_rsn_oui_present_in_wpa_ie(
|
|
pmpriv, CIPHER_SUITE_GCMP) ||
|
|
is_rsn_oui_present_in_wpa_ie(
|
|
pmpriv,
|
|
CIPHER_SUITE_GCMP_256) ||
|
|
is_rsn_oui_present_in_wpa_ie(
|
|
pmpriv,
|
|
CIPHER_SUITE_CCMP_256)) {
|
|
LEAVE();
|
|
return index;
|
|
} else {
|
|
LEAVE();
|
|
return -1;
|
|
}
|
|
}
|
|
LEAVE();
|
|
return index;
|
|
} else if (pmpriv->sec_info.wep_status ==
|
|
Wlan802_11WEPDisabled &&
|
|
!pmpriv->sec_info.wpa_enabled &&
|
|
!pmpriv->sec_info.wpa2_enabled &&
|
|
((!pbss_desc->pwpa_ie) ||
|
|
((*(pbss_desc->pwpa_ie)).vend_hdr.element_id !=
|
|
WPA_IE)) &&
|
|
((!pbss_desc->prsn_ie) ||
|
|
((*(pbss_desc->prsn_ie)).ieee_hdr.element_id !=
|
|
RSN_IE)) &&
|
|
pmpriv->sec_info.encryption_mode !=
|
|
MLAN_ENCRYPTION_MODE_NONE &&
|
|
pbss_desc->privacy) {
|
|
/* Dynamic WEP enabled */
|
|
pbss_desc->disable_11n = MTRUE;
|
|
PRINTM(MINFO,
|
|
"wlan_is_network_compatible() dynamic WEP: index=%d "
|
|
"wpa_ie=%#x rsn_ie=%#x EncMode=%#x privacy=%#x\n",
|
|
index,
|
|
(pbss_desc->pwpa_ie) ?
|
|
(*(pbss_desc->pwpa_ie))
|
|
.vend_hdr.element_id :
|
|
0,
|
|
(pbss_desc->prsn_ie) ?
|
|
(*(pbss_desc->prsn_ie))
|
|
.ieee_hdr.element_id :
|
|
0,
|
|
pmpriv->sec_info.encryption_mode,
|
|
pbss_desc->privacy);
|
|
LEAVE();
|
|
return index;
|
|
}
|
|
/* Security doesn't match */
|
|
PRINTM(MINFO,
|
|
"wlan_is_network_compatible() FAILED: index=%d wpa_ie=%#x "
|
|
"rsn_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode=%#x privacy=%#x\n",
|
|
index,
|
|
(pbss_desc->pwpa_ie) ?
|
|
(*(pbss_desc->pwpa_ie)).vend_hdr.element_id :
|
|
0,
|
|
(pbss_desc->prsn_ie) ?
|
|
(*(pbss_desc->prsn_ie)).ieee_hdr.element_id :
|
|
0,
|
|
(pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled) ?
|
|
"e" :
|
|
"d",
|
|
(pmpriv->sec_info.wpa_enabled) ? "e" : "d",
|
|
(pmpriv->sec_info.wpa2_enabled) ? "e" : "d",
|
|
pmpriv->sec_info.encryption_mode, pbss_desc->privacy);
|
|
LEAVE();
|
|
return -1;
|
|
}
|
|
/* Mode doesn't match */
|
|
LEAVE();
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* @brief Internal function used to flush the scan list
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS
|
|
*/
|
|
mlan_status wlan_flush_scan_table(pmlan_adapter pmadapter)
|
|
{
|
|
t_u8 i = 0;
|
|
ENTER();
|
|
|
|
PRINTM(MINFO, "Flushing scan table\n");
|
|
|
|
memset(pmadapter, pmadapter->pscan_table, 0,
|
|
(sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST));
|
|
pmadapter->num_in_scan_table = 0;
|
|
|
|
memset(pmadapter, pmadapter->bcn_buf, 0, pmadapter->bcn_buf_size);
|
|
pmadapter->pbcn_buf_end = pmadapter->bcn_buf;
|
|
|
|
for (i = 0; i < pmadapter->num_in_chan_stats; i++)
|
|
pmadapter->pchan_stats[i].cca_scan_duration = 0;
|
|
pmadapter->idx_chan_stats = 0;
|
|
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief Internal function used to start a scan based on an input config
|
|
*
|
|
* Use the input user scan configuration information when provided in
|
|
* order to send the appropriate scan commands to firmware to populate or
|
|
* update the internal driver scan table
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @param pioctl_buf A pointer to MLAN IOCTL Request buffer
|
|
* @param puser_scan_in Pointer to the input configuration for the requested
|
|
* scan.
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or < 0 if error
|
|
*/
|
|
mlan_status wlan_scan_networks(mlan_private *pmpriv, t_void *pioctl_buf,
|
|
wlan_user_scan_cfg *puser_scan_in)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_adapter *pmadapter = pmpriv->adapter;
|
|
mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks;
|
|
cmd_ctrl_node *pcmd_node = MNULL;
|
|
pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *)pioctl_buf;
|
|
|
|
wlan_scan_cmd_config_tlv *pscan_cfg_out = MNULL;
|
|
MrvlIEtypes_ChanListParamSet_t *pchan_list_out;
|
|
t_u32 buf_size;
|
|
ChanScanParamSet_t *pscan_chan_list;
|
|
|
|
t_u8 keep_previous_scan;
|
|
t_u8 filtered_scan;
|
|
t_u8 scan_current_chan_only;
|
|
t_u8 max_chan_per_scan;
|
|
t_u8 i;
|
|
|
|
ENTER();
|
|
|
|
ret = pcb->moal_malloc(pmadapter->pmoal_handle,
|
|
sizeof(wlan_scan_cmd_config_tlv), MLAN_MEM_DEF,
|
|
(t_u8 **)&pscan_cfg_out);
|
|
if (ret != MLAN_STATUS_SUCCESS || !pscan_cfg_out) {
|
|
PRINTM(MERROR, "Memory allocation for pscan_cfg_out failed!\n");
|
|
if (pioctl_req)
|
|
pioctl_req->status_code = MLAN_ERROR_NO_MEM;
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
buf_size = sizeof(ChanScanParamSet_t) * WLAN_USER_SCAN_CHAN_MAX;
|
|
ret = pcb->moal_malloc(pmadapter->pmoal_handle, buf_size, MLAN_MEM_DEF,
|
|
(t_u8 **)&pscan_chan_list);
|
|
if (ret != MLAN_STATUS_SUCCESS || !pscan_chan_list) {
|
|
PRINTM(MERROR, "Failed to allocate scan_chan_list\n");
|
|
if (pscan_cfg_out)
|
|
pcb->moal_mfree(pmadapter->pmoal_handle,
|
|
(t_u8 *)pscan_cfg_out);
|
|
if (pioctl_req)
|
|
pioctl_req->status_code = MLAN_ERROR_NO_MEM;
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
memset(pmadapter, pscan_chan_list, 0x00, buf_size);
|
|
memset(pmadapter, pscan_cfg_out, 0x00,
|
|
sizeof(wlan_scan_cmd_config_tlv));
|
|
|
|
keep_previous_scan = MFALSE;
|
|
|
|
ret = wlan_scan_setup_scan_config(pmpriv, puser_scan_in,
|
|
&pscan_cfg_out->config,
|
|
&pchan_list_out, pscan_chan_list,
|
|
&max_chan_per_scan, &filtered_scan,
|
|
&scan_current_chan_only);
|
|
if (ret != MLAN_STATUS_SUCCESS) {
|
|
PRINTM(MERROR, "Failed to setup scan config\n");
|
|
if (pscan_cfg_out)
|
|
pcb->moal_mfree(pmadapter->pmoal_handle,
|
|
(t_u8 *)pscan_cfg_out);
|
|
if (pscan_chan_list)
|
|
pcb->moal_mfree(pmadapter->pmoal_handle,
|
|
(t_u8 *)pscan_chan_list);
|
|
if (pioctl_req)
|
|
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
if (puser_scan_in)
|
|
keep_previous_scan = puser_scan_in->keep_previous_scan;
|
|
|
|
if (keep_previous_scan == MFALSE) {
|
|
memset(pmadapter, pmadapter->pscan_table, 0x00,
|
|
sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST);
|
|
pmadapter->num_in_scan_table = 0;
|
|
pmadapter->pbcn_buf_end = pmadapter->bcn_buf;
|
|
} else {
|
|
wlan_scan_delete_ageout_entry(pmpriv);
|
|
}
|
|
for (i = 0; i < pmadapter->num_in_chan_stats; i++)
|
|
pmadapter->pchan_stats[i].cca_scan_duration = 0;
|
|
pmadapter->idx_chan_stats = 0;
|
|
|
|
ret = wlan_scan_channel_list(pmpriv, pioctl_buf, max_chan_per_scan,
|
|
filtered_scan, &pscan_cfg_out->config,
|
|
pchan_list_out, pscan_chan_list);
|
|
|
|
/* Get scan command from scan_pending_q and put to cmd_pending_q */
|
|
if (ret == MLAN_STATUS_SUCCESS) {
|
|
if (pmadapter->ext_scan && pmadapter->ext_scan_enh &&
|
|
pmadapter->ext_scan_type == EXT_SCAN_ENHANCE) {
|
|
wlan_request_cmd_lock(pmadapter);
|
|
pmadapter->pscan_ioctl_req = pioctl_req;
|
|
pmadapter->scan_processing = MTRUE;
|
|
wlan_release_cmd_lock(pmadapter);
|
|
} else {
|
|
wlan_request_cmd_lock(pmadapter);
|
|
if (util_peek_list(pmadapter->pmoal_handle,
|
|
&pmadapter->scan_pending_q, MNULL,
|
|
MNULL)) {
|
|
pcmd_node = (cmd_ctrl_node *)util_dequeue_list(
|
|
pmadapter->pmoal_handle,
|
|
&pmadapter->scan_pending_q, MNULL,
|
|
MNULL);
|
|
pmadapter->pscan_ioctl_req = pioctl_req;
|
|
pmadapter->scan_processing = MTRUE;
|
|
wlan_insert_cmd_to_pending_q(pmadapter,
|
|
pcmd_node, MTRUE);
|
|
}
|
|
wlan_release_cmd_lock(pmadapter);
|
|
}
|
|
}
|
|
if (pscan_cfg_out)
|
|
pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)pscan_cfg_out);
|
|
|
|
if (pscan_chan_list)
|
|
pcb->moal_mfree(pmadapter->pmoal_handle,
|
|
(t_u8 *)pscan_chan_list);
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Prepare a scan command to be sent to the firmware
|
|
*
|
|
* Use the wlan_scan_cmd_config sent to the command processing module in
|
|
* the wlan_prepare_cmd to configure a HostCmd_DS_802_11_SCAN command
|
|
* struct to send to firmware.
|
|
*
|
|
* The fixed fields specifying the BSS type and BSSID filters as well as a
|
|
* variable number/length of TLVs are sent in the command to firmware.
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @param pcmd A pointer to HostCmd_DS_COMMAND structure to be sent to
|
|
* firmware with the HostCmd_DS_801_11_SCAN structure
|
|
* @param pdata_buf Void pointer cast of a wlan_scan_cmd_config struct used
|
|
* to set the fields/TLVs for the command sent to firmware
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS
|
|
*/
|
|
mlan_status wlan_cmd_802_11_scan(mlan_private *pmpriv, HostCmd_DS_COMMAND *pcmd,
|
|
t_void *pdata_buf)
|
|
{
|
|
HostCmd_DS_802_11_SCAN *pscan_cmd = &pcmd->params.scan;
|
|
wlan_scan_cmd_config *pscan_cfg;
|
|
|
|
ENTER();
|
|
|
|
pscan_cfg = (wlan_scan_cmd_config *)pdata_buf;
|
|
|
|
/* Set fixed field variables in scan command */
|
|
pscan_cmd->bss_mode = pscan_cfg->bss_mode;
|
|
memcpy_ext(pmpriv->adapter, pscan_cmd->bssid, pscan_cfg->specific_bssid,
|
|
sizeof(pscan_cmd->bssid), sizeof(pscan_cmd->bssid));
|
|
memcpy_ext(pmpriv->adapter, pscan_cmd->tlv_buffer, pscan_cfg->tlv_buf,
|
|
pscan_cfg->tlv_buf_len, pscan_cfg->tlv_buf_len);
|
|
|
|
pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SCAN);
|
|
|
|
/* Size is equal to the sizeof(fixed portions) + the TLV len + header */
|
|
pcmd->size = (t_u16)wlan_cpu_to_le16(
|
|
(t_u16)(sizeof(pscan_cmd->bss_mode) + sizeof(pscan_cmd->bssid) +
|
|
pscan_cfg->tlv_buf_len + S_DS_GEN));
|
|
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief Check if any hidden SSID found in passive scan channels
|
|
* and do specific SSID active scan for those channels
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @param pioctl_buf A pointer to mlan_ioctl_req structure
|
|
*
|
|
* @return MTRUE/MFALSE
|
|
*/
|
|
|
|
static t_bool wlan_active_scan_req_for_passive_chan(mlan_private *pmpriv,
|
|
mlan_ioctl_req *pioctl_buf)
|
|
{
|
|
t_bool ret = MFALSE;
|
|
mlan_adapter *pmadapter = pmpriv->adapter;
|
|
t_bool scan_reqd = MFALSE;
|
|
t_bool chan_listed = MFALSE;
|
|
t_u8 id = 0;
|
|
t_u32 bss_idx, i;
|
|
t_u8 null_ssid[MLAN_MAX_SSID_LENGTH] = {0};
|
|
mlan_callbacks *pcb = (mlan_callbacks *)&pmpriv->adapter->callbacks;
|
|
wlan_user_scan_cfg *user_scan_cfg;
|
|
mlan_ds_scan *pscan = (mlan_ds_scan *)pioctl_buf->pbuf;
|
|
mlan_scan_req *pscan_req = MNULL;
|
|
wlan_user_scan_cfg *puser_scan_in = MNULL;
|
|
|
|
ENTER();
|
|
|
|
if (pscan->sub_command == MLAN_OID_SCAN_USER_CONFIG) {
|
|
puser_scan_in = (wlan_user_scan_cfg *)
|
|
pscan->param.user_scan.scan_cfg_buf;
|
|
if (!puser_scan_in->ssid_filter)
|
|
goto done;
|
|
}
|
|
|
|
if (pmadapter->active_scan_triggered) {
|
|
pmadapter->active_scan_triggered = MFALSE;
|
|
goto done;
|
|
}
|
|
|
|
if ((pcb->moal_malloc(pmadapter->pmoal_handle,
|
|
sizeof(wlan_user_scan_cfg), MLAN_MEM_DEF,
|
|
(t_u8 **)&user_scan_cfg) !=
|
|
MLAN_STATUS_SUCCESS) ||
|
|
!user_scan_cfg) {
|
|
PRINTM(MERROR, "Memory allocation for user_scan_cfg failed\n");
|
|
goto done;
|
|
}
|
|
memset(pmadapter, user_scan_cfg, 0, sizeof(wlan_user_scan_cfg));
|
|
for (bss_idx = 0; bss_idx < pmadapter->num_in_scan_table; bss_idx++) {
|
|
scan_reqd = MFALSE;
|
|
if (!memcmp(pmadapter,
|
|
pmadapter->pscan_table[bss_idx].ssid.ssid,
|
|
null_ssid,
|
|
pmadapter->pscan_table[bss_idx].ssid.ssid_len)) {
|
|
if (puser_scan_in &&
|
|
puser_scan_in->chan_list[0].chan_number) {
|
|
for (i = 0;
|
|
i < WLAN_USER_SCAN_CHAN_MAX &&
|
|
puser_scan_in->chan_list[i].chan_number;
|
|
i++) {
|
|
if (puser_scan_in->chan_list[i]
|
|
.chan_number ==
|
|
pmadapter->pscan_table[bss_idx]
|
|
.channel) {
|
|
if (puser_scan_in->chan_list[i]
|
|
.scan_type ==
|
|
MLAN_SCAN_TYPE_PASSIVE)
|
|
scan_reqd = MTRUE;
|
|
break;
|
|
}
|
|
}
|
|
} else if (pmadapter->scan_type ==
|
|
MLAN_SCAN_TYPE_PASSIVE) {
|
|
scan_reqd = MTRUE;
|
|
} else {
|
|
if ((pmadapter->pscan_table[bss_idx].bss_band &
|
|
BAND_A) &&
|
|
wlan_11h_radar_detect_required(
|
|
pmpriv,
|
|
pmadapter->pscan_table[bss_idx]
|
|
.channel))
|
|
scan_reqd = MTRUE;
|
|
if (pmadapter->pscan_table[bss_idx].bss_band &
|
|
(BAND_B | BAND_G) &&
|
|
wlan_bg_scan_type_is_passive(
|
|
pmpriv,
|
|
pmadapter->pscan_table[bss_idx]
|
|
.channel))
|
|
scan_reqd = MTRUE;
|
|
}
|
|
|
|
if (scan_reqd) {
|
|
chan_listed = MFALSE;
|
|
for (i = 0; i < id; i++) {
|
|
if ((user_scan_cfg->chan_list[i]
|
|
.chan_number ==
|
|
pmadapter->pscan_table[bss_idx]
|
|
.channel) &&
|
|
(user_scan_cfg->chan_list[i]
|
|
.radio_type &
|
|
pmadapter->pscan_table[bss_idx]
|
|
.bss_band)) {
|
|
chan_listed = MTRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (chan_listed == MTRUE)
|
|
continue;
|
|
user_scan_cfg->chan_list[id].chan_number =
|
|
pmadapter->pscan_table[bss_idx].channel;
|
|
if (pmadapter->pscan_table[bss_idx].bss_band &
|
|
(BAND_B | BAND_G))
|
|
user_scan_cfg->chan_list[id].radio_type =
|
|
BAND_2GHZ;
|
|
if (pmadapter->pscan_table[bss_idx].bss_band &
|
|
BAND_A)
|
|
user_scan_cfg->chan_list[id].radio_type =
|
|
BAND_5GHZ;
|
|
user_scan_cfg->chan_list[id].scan_type =
|
|
MLAN_SCAN_TYPE_ACTIVE;
|
|
id++;
|
|
}
|
|
}
|
|
}
|
|
if (id) {
|
|
pmadapter->active_scan_triggered = MTRUE;
|
|
if (pscan->sub_command == MLAN_OID_SCAN_USER_CONFIG) {
|
|
memcpy_ext(pmpriv->adapter, user_scan_cfg->ssid_list,
|
|
puser_scan_in->ssid_list,
|
|
sizeof(user_scan_cfg->ssid_list),
|
|
sizeof(user_scan_cfg->ssid_list));
|
|
} else {
|
|
pscan_req = &pscan->param.scan_req;
|
|
memcpy_ext(pmpriv->adapter,
|
|
user_scan_cfg->ssid_list[0].ssid,
|
|
pscan_req->scan_ssid.ssid,
|
|
pscan_req->scan_ssid.ssid_len,
|
|
MLAN_MAX_SSID_LENGTH);
|
|
}
|
|
user_scan_cfg->keep_previous_scan = MTRUE;
|
|
if (MLAN_STATUS_SUCCESS !=
|
|
wlan_scan_networks(pmpriv, pioctl_buf, user_scan_cfg)) {
|
|
goto done;
|
|
}
|
|
ret = MTRUE;
|
|
}
|
|
if (user_scan_cfg)
|
|
pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)user_scan_cfg);
|
|
|
|
done:
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief This function handles the command response of scan
|
|
*
|
|
* The response buffer for the scan command has the following
|
|
* memory layout:
|
|
*
|
|
* .-------------------------------------------------------------.
|
|
* | Header (4 * sizeof(t_u16)): Standard command response hdr |
|
|
* .-------------------------------------------------------------.
|
|
* | BufSize (t_u16) : sizeof the BSS Description data |
|
|
* .-------------------------------------------------------------.
|
|
* | NumOfSet (t_u8) : Number of BSS Descs returned |
|
|
* .-------------------------------------------------------------.
|
|
* | BSSDescription data (variable, size given in BufSize) |
|
|
* .-------------------------------------------------------------.
|
|
* | TLV data (variable, size calculated using Header->Size, |
|
|
* | BufSize and sizeof the fixed fields above) |
|
|
* .-------------------------------------------------------------.
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @param resp A pointer to HostCmd_DS_COMMAND
|
|
* @param pioctl_buf A pointer to mlan_ioctl_req structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status wlan_ret_802_11_scan(mlan_private *pmpriv, HostCmd_DS_COMMAND *resp,
|
|
t_void *pioctl_buf)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_adapter *pmadapter = pmpriv->adapter;
|
|
mlan_callbacks *pcb = MNULL;
|
|
cmd_ctrl_node *pcmd_node = MNULL;
|
|
HostCmd_DS_802_11_SCAN_RSP *pscan_rsp = MNULL;
|
|
BSSDescriptor_t *bss_new_entry = MNULL;
|
|
MrvlIEtypes_Data_t *ptlv;
|
|
MrvlIEtypes_TsfTimestamp_t *ptsf_tlv = MNULL;
|
|
MrvlIEtypes_ChannelStats_t *pchanstats_tlv = MNULL;
|
|
t_u8 *pbss_info;
|
|
t_u32 scan_resp_size;
|
|
t_u32 bytes_left;
|
|
t_u32 num_in_table;
|
|
t_u32 bss_idx;
|
|
t_u32 idx;
|
|
t_u32 tlv_buf_size;
|
|
t_u64 tsf_val;
|
|
chan_freq_power_t *cfp;
|
|
MrvlIEtypes_ChanBandListParamSet_t *pchan_band_tlv = MNULL;
|
|
ChanBandParamSet_t *pchan_band;
|
|
t_u8 band;
|
|
t_u8 is_bgscan_resp;
|
|
t_u32 age_ts_usec;
|
|
t_u8 null_ssid[MLAN_MAX_SSID_LENGTH] = {0};
|
|
t_u32 status_code = 0;
|
|
pmlan_ioctl_req pscan_ioctl_req = MNULL;
|
|
|
|
ENTER();
|
|
pcb = (pmlan_callbacks)&pmadapter->callbacks;
|
|
|
|
is_bgscan_resp = (resp->command == HostCmd_CMD_802_11_BG_SCAN_QUERY);
|
|
if (is_bgscan_resp)
|
|
pscan_rsp = &resp->params.bg_scan_query_resp.scan_resp;
|
|
else
|
|
pscan_rsp = &resp->params.scan_resp;
|
|
|
|
if (pscan_rsp->number_of_sets > MRVDRV_MAX_BSSID_LIST) {
|
|
PRINTM(MERROR,
|
|
"SCAN_RESP: Invalid number of AP returned (%d)!!\n",
|
|
pscan_rsp->number_of_sets);
|
|
status_code = MLAN_ERROR_CMD_SCAN_FAIL;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
bytes_left = wlan_le16_to_cpu(pscan_rsp->bss_descript_size);
|
|
PRINTM(MINFO, "SCAN_RESP: bss_descript_size %d\n", bytes_left);
|
|
|
|
scan_resp_size = resp->size;
|
|
|
|
PRINTM(MINFO, "SCAN_RESP: returned %d APs before parsing\n",
|
|
pscan_rsp->number_of_sets);
|
|
|
|
/* Update the age_in_second */
|
|
pmadapter->callbacks.moal_get_system_time(
|
|
pmadapter->pmoal_handle, &pmadapter->age_in_secs, &age_ts_usec);
|
|
|
|
num_in_table = pmadapter->num_in_scan_table;
|
|
pbss_info = pscan_rsp->bss_desc_and_tlv_buffer;
|
|
|
|
/*
|
|
* The size of the TLV buffer is equal to the entire command response
|
|
* size (scan_resp_size) minus the fixed fields (sizeof()'s), the
|
|
* BSS Descriptions (bss_descript_size as bytesLef) and the command
|
|
* response header (S_DS_GEN)
|
|
*/
|
|
tlv_buf_size = scan_resp_size -
|
|
(bytes_left + sizeof(pscan_rsp->bss_descript_size) +
|
|
sizeof(pscan_rsp->number_of_sets) + S_DS_GEN);
|
|
if (is_bgscan_resp)
|
|
tlv_buf_size -= sizeof(
|
|
resp->params.bg_scan_query_resp.report_condition);
|
|
|
|
ptlv = (MrvlIEtypes_Data_t *)(pscan_rsp->bss_desc_and_tlv_buffer +
|
|
bytes_left);
|
|
|
|
/*
|
|
* Search the TLV buffer space in the scan response
|
|
* for any valid TLVs
|
|
*/
|
|
wlan_ret_802_11_scan_get_tlv_ptrs(pmadapter, ptlv, tlv_buf_size,
|
|
TLV_TYPE_TSFTIMESTAMP,
|
|
(MrvlIEtypes_Data_t **)&ptsf_tlv);
|
|
|
|
/*
|
|
* Search the TLV buffer space in the scan response
|
|
* for any valid TLVs
|
|
*/
|
|
wlan_ret_802_11_scan_get_tlv_ptrs(
|
|
pmadapter, ptlv, tlv_buf_size, TLV_TYPE_CHANNELBANDLIST,
|
|
(MrvlIEtypes_Data_t **)&pchan_band_tlv);
|
|
wlan_ret_802_11_scan_get_tlv_ptrs(
|
|
pmadapter, ptlv, tlv_buf_size, TLV_TYPE_CHANNEL_STATS,
|
|
(MrvlIEtypes_Data_t **)&pchanstats_tlv);
|
|
|
|
if (pchanstats_tlv)
|
|
wlan_update_chan_statistics(pmpriv, pchanstats_tlv);
|
|
|
|
/*
|
|
* Process each scan response returned (pscan_rsp->number_of_sets).
|
|
* Save the information in the bss_new_entry and then insert into
|
|
* the driver scan table either as an update to an existing entry
|
|
* or as an addition at the end of the table
|
|
*/
|
|
ret = pcb->moal_malloc(pmadapter->pmoal_handle, sizeof(BSSDescriptor_t),
|
|
MLAN_MEM_DEF, (t_u8 **)&bss_new_entry);
|
|
|
|
if (ret != MLAN_STATUS_SUCCESS || !bss_new_entry) {
|
|
PRINTM(MERROR, "Memory allocation for bss_new_entry failed!\n");
|
|
status_code = MLAN_ERROR_NO_MEM;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
for (idx = 0; idx < pscan_rsp->number_of_sets && bytes_left; idx++) {
|
|
/* Zero out the bss_new_entry we are about to store info in */
|
|
memset(pmadapter, bss_new_entry, 0x00, sizeof(BSSDescriptor_t));
|
|
|
|
/* Process the data fields and IEs returned for this BSS */
|
|
if (wlan_interpret_bss_desc_with_ie(
|
|
pmadapter, bss_new_entry, &pbss_info, &bytes_left,
|
|
MFALSE) == MLAN_STATUS_SUCCESS) {
|
|
PRINTM(MINFO, "SCAN_RESP: BSSID = " MACSTR "\n",
|
|
MAC2STR(bss_new_entry->mac_address));
|
|
|
|
band = BAND_G;
|
|
if (pchan_band_tlv) {
|
|
pchan_band =
|
|
&pchan_band_tlv->chan_band_param[idx];
|
|
band = radio_type_to_band(
|
|
pchan_band->bandcfg.chanBand);
|
|
if (!bss_new_entry->channel)
|
|
bss_new_entry->channel =
|
|
pchan_band->chan_number;
|
|
}
|
|
/*
|
|
* Save the band designation for this entry
|
|
* for use in join
|
|
*/
|
|
bss_new_entry->bss_band = band;
|
|
bss_new_entry->age_in_secs = pmadapter->age_in_secs;
|
|
cfp = wlan_find_cfp_by_band_and_channel(
|
|
pmadapter, (t_u8)bss_new_entry->bss_band,
|
|
(t_u16)bss_new_entry->channel);
|
|
if (cfp)
|
|
bss_new_entry->freq = cfp->freq;
|
|
else
|
|
bss_new_entry->freq = 0;
|
|
|
|
/* Skip entry if on blacklisted channel */
|
|
if (cfp && cfp->dynamic.blacklist) {
|
|
PRINTM(MINFO,
|
|
"SCAN_RESP: dropping entry on blacklist channel.\n");
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* Search the scan table for the same bssid
|
|
*/
|
|
for (bss_idx = 0; bss_idx < num_in_table; bss_idx++) {
|
|
if (!memcmp(pmadapter,
|
|
bss_new_entry->mac_address,
|
|
pmadapter->pscan_table[bss_idx]
|
|
.mac_address,
|
|
sizeof(bss_new_entry->mac_address))) {
|
|
/*
|
|
* If the SSID matches as well, it is a
|
|
* duplicate of this entry. Keep the
|
|
* bss_idx set to this entry so we
|
|
* replace the old contents in the table
|
|
*/
|
|
if ((bss_new_entry->ssid.ssid_len ==
|
|
pmadapter->pscan_table[bss_idx]
|
|
.ssid.ssid_len) &&
|
|
(!memcmp(
|
|
pmadapter,
|
|
bss_new_entry->ssid.ssid,
|
|
pmadapter
|
|
->pscan_table[bss_idx]
|
|
.ssid.ssid,
|
|
bss_new_entry->ssid
|
|
.ssid_len))) {
|
|
PRINTM(MINFO,
|
|
"SCAN_RESP: Duplicate of index: %d\n",
|
|
bss_idx);
|
|
|
|
break;
|
|
}
|
|
/*
|
|
* If the SSID is NULL for same BSSID
|
|
* keep the bss_idx set to this entry
|
|
* so we replace the old contents in
|
|
* the table
|
|
*/
|
|
if (!memcmp(pmadapter,
|
|
pmadapter
|
|
->pscan_table[bss_idx]
|
|
.ssid.ssid,
|
|
null_ssid,
|
|
pmadapter
|
|
->pscan_table[bss_idx]
|
|
.ssid.ssid_len)) {
|
|
PRINTM(MINFO,
|
|
"SCAN_RESP: Duplicate of index: %d\n",
|
|
bss_idx);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* If the bss_idx is equal to the number of entries
|
|
* in the table, the new entry was not a duplicate;
|
|
* append it to the scan table
|
|
*/
|
|
if (bss_idx == num_in_table) {
|
|
/*
|
|
* Range check the bss_idx, keep it limited
|
|
* to the last entry
|
|
*/
|
|
if (bss_idx == MRVDRV_MAX_BSSID_LIST)
|
|
bss_idx--;
|
|
else
|
|
num_in_table++;
|
|
} else {
|
|
if ((bss_new_entry->channel !=
|
|
pmadapter->pscan_table[bss_idx].channel) &&
|
|
(bss_new_entry->rssi >
|
|
pmadapter->pscan_table[bss_idx].rssi)) {
|
|
PRINTM(MCMND,
|
|
"skip update the duplicate entry with low rssi\n");
|
|
continue;
|
|
}
|
|
}
|
|
/*
|
|
* Save the beacon/probe response returned for later
|
|
* application retrieval. Duplicate beacon/probe
|
|
* responses are updated if possible
|
|
*/
|
|
wlan_ret_802_11_scan_store_beacon(
|
|
pmpriv, bss_idx, num_in_table, bss_new_entry);
|
|
if (bss_new_entry->pbeacon_buf == MNULL) {
|
|
PRINTM(MCMND,
|
|
"No space for beacon, drop this entry\n");
|
|
num_in_table--;
|
|
continue;
|
|
}
|
|
/*
|
|
* If the TSF TLV was appended to the scan results, save
|
|
* this entry's TSF value in the networkTSF field. The
|
|
* networkTSF is the firmware's TSF value at the time
|
|
* the beacon or probe response was received.
|
|
*/
|
|
if (ptsf_tlv) {
|
|
memcpy_ext(
|
|
pmpriv->adapter, &tsf_val,
|
|
&ptsf_tlv->tsf_data[idx * TSF_DATA_SIZE],
|
|
sizeof(tsf_val), sizeof(tsf_val));
|
|
tsf_val = wlan_le64_to_cpu(tsf_val);
|
|
memcpy_ext(pmpriv->adapter,
|
|
&bss_new_entry->network_tsf,
|
|
&tsf_val,
|
|
sizeof(bss_new_entry->network_tsf),
|
|
sizeof(bss_new_entry->network_tsf));
|
|
}
|
|
|
|
/* Copy the locally created bss_new_entry to the scan
|
|
* table */
|
|
memcpy_ext(pmadapter, &pmadapter->pscan_table[bss_idx],
|
|
bss_new_entry,
|
|
sizeof(pmadapter->pscan_table[bss_idx]),
|
|
sizeof(pmadapter->pscan_table[bss_idx]));
|
|
|
|
} else {
|
|
/* Error parsing/interpreting the scan response, skipped
|
|
*/
|
|
PRINTM(MERROR,
|
|
"SCAN_RESP: wlan_interpret_bss_desc_with_ie returned error\n");
|
|
}
|
|
}
|
|
|
|
PRINTM(MINFO, "SCAN_RESP: Scanned %2d APs, %d valid, %d total\n",
|
|
pscan_rsp->number_of_sets,
|
|
num_in_table - pmadapter->num_in_scan_table, num_in_table);
|
|
|
|
/* Update the total number of BSSIDs in the scan table */
|
|
pmadapter->num_in_scan_table = num_in_table;
|
|
if (is_bgscan_resp)
|
|
goto done;
|
|
wlan_request_cmd_lock(pmadapter);
|
|
if (!util_peek_list(pmadapter->pmoal_handle, &pmadapter->scan_pending_q,
|
|
MNULL, MNULL)) {
|
|
wlan_release_cmd_lock(pmadapter);
|
|
if (pmadapter->pscan_ioctl_req) {
|
|
if (((mlan_ds_scan *)pmadapter->pscan_ioctl_req->pbuf)
|
|
->sub_command ==
|
|
MLAN_OID_SCAN_SPECIFIC_SSID ||
|
|
((mlan_ds_scan *)pmadapter->pscan_ioctl_req->pbuf)
|
|
->sub_command ==
|
|
MLAN_OID_SCAN_USER_CONFIG) {
|
|
if (wlan_active_scan_req_for_passive_chan(
|
|
pmpriv,
|
|
pmadapter->pscan_ioctl_req)) {
|
|
goto done;
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* Process the resulting scan table:
|
|
* - Remove any bad ssids
|
|
* - Update our current BSS information from scan data
|
|
*/
|
|
wlan_scan_process_results(pmpriv);
|
|
|
|
wlan_request_cmd_lock(pmadapter);
|
|
pmadapter->scan_processing = MFALSE;
|
|
pscan_ioctl_req = pmadapter->pscan_ioctl_req;
|
|
pmadapter->pscan_ioctl_req = MNULL;
|
|
/* Need to indicate IOCTL complete */
|
|
if (pscan_ioctl_req) {
|
|
pscan_ioctl_req->status_code = MLAN_ERROR_NO_ERROR;
|
|
/* Indicate ioctl complete */
|
|
pcb->moal_ioctl_complete(
|
|
pmadapter->pmoal_handle,
|
|
(pmlan_ioctl_req)pscan_ioctl_req,
|
|
MLAN_STATUS_SUCCESS);
|
|
}
|
|
wlan_release_cmd_lock(pmadapter);
|
|
pmadapter->bgscan_reported = MFALSE;
|
|
wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_SCAN_REPORT, MNULL);
|
|
} else {
|
|
/* If firmware not ready, do not issue any more scan commands */
|
|
if (pmadapter->hw_status != WlanHardwareStatusReady) {
|
|
wlan_release_cmd_lock(pmadapter);
|
|
status_code = MLAN_ERROR_FW_NOT_READY;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
} else {
|
|
/* Get scan command from scan_pending_q and put to
|
|
* cmd_pending_q */
|
|
pcmd_node = (cmd_ctrl_node *)util_dequeue_list(
|
|
pmadapter->pmoal_handle,
|
|
&pmadapter->scan_pending_q, MNULL, MNULL);
|
|
wlan_insert_cmd_to_pending_q(pmadapter, pcmd_node,
|
|
MTRUE);
|
|
wlan_release_cmd_lock(pmadapter);
|
|
}
|
|
}
|
|
|
|
done:
|
|
if (bss_new_entry)
|
|
pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)bss_new_entry);
|
|
if (ret) {
|
|
/* Flush all pending scan commands */
|
|
wlan_flush_scan_queue(pmadapter);
|
|
wlan_request_cmd_lock(pmadapter);
|
|
pmadapter->scan_processing = MFALSE;
|
|
pscan_ioctl_req = pmadapter->pscan_ioctl_req;
|
|
pmadapter->pscan_ioctl_req = MNULL;
|
|
if (pscan_ioctl_req) {
|
|
pscan_ioctl_req->status_code = status_code;
|
|
/* Indicate ioctl complete */
|
|
pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
|
|
pscan_ioctl_req,
|
|
MLAN_STATUS_FAILURE);
|
|
}
|
|
wlan_release_cmd_lock(pmadapter);
|
|
}
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Prepare an extended scan command to be sent to the firmware
|
|
*
|
|
* Use the wlan_scan_cmd_config sent to the command processing module in
|
|
* the wlan_prepare_cmd to configure a HostCmd_DS_802_11_SCAN_EXT command
|
|
* struct to send to firmware.
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @param pcmd A pointer to HostCmd_DS_COMMAND structure to be sent to
|
|
* firmware with the HostCmd_DS_802_11_SCAN_EXT structure
|
|
* @param pdata_buf Void pointer cast of a wlan_scan_cmd_config struct used
|
|
* to set the fields/TLVs for the command sent to firmware
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS
|
|
*/
|
|
mlan_status wlan_cmd_802_11_scan_ext(mlan_private *pmpriv,
|
|
HostCmd_DS_COMMAND *pcmd,
|
|
t_void *pdata_buf)
|
|
{
|
|
HostCmd_DS_802_11_SCAN_EXT *pext_scan_cmd = &pcmd->params.ext_scan;
|
|
wlan_scan_cmd_config *pscan_cfg = MNULL;
|
|
|
|
ENTER();
|
|
|
|
pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SCAN_EXT);
|
|
|
|
if (pmpriv->adapter->ext_scan_enh == MTRUE) {
|
|
if (pdata_buf) {
|
|
if (pmpriv->adapter->ext_scan_type == EXT_SCAN_ENHANCE)
|
|
pext_scan_cmd->ext_scan_type = EXT_SCAN_ENHANCE;
|
|
else
|
|
pext_scan_cmd->ext_scan_type = EXT_SCAN_DEFAULT;
|
|
} else {
|
|
pcmd->size = wlan_cpu_to_le16((t_u16)(
|
|
sizeof(pext_scan_cmd->ext_scan_type) +
|
|
(t_u16)(sizeof(pext_scan_cmd->reserved)) +
|
|
S_DS_GEN));
|
|
pext_scan_cmd->ext_scan_type = EXT_SCAN_CANCEL;
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
}
|
|
if (!pdata_buf) {
|
|
PRINTM(MERROR, "wlan_cmd_802_11_scan_ext: pdata_buf is null\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
pscan_cfg = (wlan_scan_cmd_config *)pdata_buf;
|
|
|
|
memcpy_ext(pmpriv->adapter, pext_scan_cmd->tlv_buffer,
|
|
pscan_cfg->tlv_buf, pscan_cfg->tlv_buf_len,
|
|
pscan_cfg->tlv_buf_len);
|
|
|
|
/* Size is equal to the sizeof(fixed portions) + the TLV len + header */
|
|
pcmd->size = wlan_cpu_to_le16(
|
|
(t_u16)(sizeof(pext_scan_cmd->ext_scan_type) +
|
|
(t_u16)sizeof(pext_scan_cmd->reserved) +
|
|
pscan_cfg->tlv_buf_len + S_DS_GEN));
|
|
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function handles the command response of extended scan
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @param resp A pointer to HostCmd_DS_COMMAND
|
|
* @param pioctl_buf A pointer to mlan_ioctl_req structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status wlan_ret_802_11_scan_ext(mlan_private *pmpriv,
|
|
HostCmd_DS_COMMAND *resp,
|
|
t_void *pioctl_buf)
|
|
{
|
|
HostCmd_DS_802_11_SCAN_EXT *pext_scan_cmd = &(resp->params.ext_scan);
|
|
MrvlIEtypesHeader_t *tlv = MNULL;
|
|
MrvlIEtypes_ChannelStats_t *tlv_chanstats = MNULL;
|
|
t_u16 tlv_buf_left = 0;
|
|
t_u16 tlv_type = 0;
|
|
t_u16 tlv_len = 0;
|
|
t_u32 ext_scan_type;
|
|
mlan_callbacks *pcb = (mlan_callbacks *)&pmpriv->adapter->callbacks;
|
|
pmlan_ioctl_req pioctl_req = (pmlan_ioctl_req)pioctl_buf;
|
|
mlan_adapter *pmadapter = pmpriv->adapter;
|
|
ENTER();
|
|
|
|
PRINTM(MINFO, "EXT scan returns successfully\n");
|
|
ext_scan_type = pext_scan_cmd->ext_scan_type;
|
|
if (ext_scan_type == EXT_SCAN_CANCEL) {
|
|
PRINTM(MCMND, "Cancel scan command completed!\n");
|
|
wlan_request_cmd_lock(pmadapter);
|
|
pmadapter->scan_processing = MFALSE;
|
|
pmadapter->ext_scan_type = EXT_SCAN_DEFAULT;
|
|
wlan_release_cmd_lock(pmadapter);
|
|
/* Need to indicate IOCTL complete */
|
|
if (pioctl_req != MNULL) {
|
|
pioctl_req->status_code = MLAN_STATUS_SUCCESS;
|
|
/* Indicate ioctl complete */
|
|
pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
|
|
(pmlan_ioctl_req)pioctl_req,
|
|
MLAN_STATUS_SUCCESS);
|
|
}
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
} else if (ext_scan_type == EXT_SCAN_ENHANCE) {
|
|
/* Setup the timer after scan command response */
|
|
pcb->moal_start_timer(pmpriv->adapter->pmoal_handle,
|
|
pmpriv->adapter->pmlan_cmd_timer, MFALSE,
|
|
MRVDRV_TIMER_10S * 2);
|
|
pmpriv->adapter->cmd_timer_is_set = MTRUE;
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
tlv = (MrvlIEtypesHeader_t *)pext_scan_cmd->tlv_buffer;
|
|
tlv_buf_left = resp->size -
|
|
(sizeof(HostCmd_DS_802_11_SCAN_EXT) - 1 + S_DS_GEN);
|
|
while (tlv_buf_left >= sizeof(MrvlIEtypesHeader_t)) {
|
|
tlv_type = wlan_le16_to_cpu(tlv->type);
|
|
tlv_len = wlan_le16_to_cpu(tlv->len);
|
|
if (tlv_buf_left < (tlv_len + sizeof(MrvlIEtypesHeader_t))) {
|
|
PRINTM(MERROR, "Error processing scan gap TLV\n");
|
|
break;
|
|
}
|
|
switch (tlv_type) {
|
|
case TLV_TYPE_CHANNEL_STATS:
|
|
tlv_chanstats = (MrvlIEtypes_ChannelStats_t *)tlv;
|
|
wlan_update_chan_statistics(pmpriv, tlv_chanstats);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
tlv_buf_left -= tlv_len + sizeof(MrvlIEtypesHeader_t);
|
|
tlv = (MrvlIEtypesHeader_t *)((t_u8 *)tlv + tlv_len +
|
|
sizeof(MrvlIEtypesHeader_t));
|
|
}
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function add a new entry to scan_table
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @param bss_new_entry A pointer to the bss_new_entry
|
|
* @param num_in_tbl number of scan entry in scan_table
|
|
*
|
|
* @return N/A
|
|
*/
|
|
static t_void wlan_add_new_entry_to_scan_table(mlan_private *pmpriv,
|
|
BSSDescriptor_t *bss_new_entry,
|
|
t_u32 *num_in_tbl)
|
|
{
|
|
mlan_adapter *pmadapter = pmpriv->adapter;
|
|
t_u32 bss_idx;
|
|
t_u32 num_in_table = *num_in_tbl;
|
|
t_u8 null_ssid[MLAN_MAX_SSID_LENGTH] = {0};
|
|
|
|
/*
|
|
* Search the scan table for the same bssid
|
|
*/
|
|
for (bss_idx = 0; bss_idx < num_in_table; bss_idx++) {
|
|
if (!memcmp(pmadapter, bss_new_entry->mac_address,
|
|
pmadapter->pscan_table[bss_idx].mac_address,
|
|
sizeof(bss_new_entry->mac_address))) {
|
|
/*
|
|
* If the SSID matches as well, it is a
|
|
* duplicate of this entry. Keep the
|
|
* bss_idx set to this entry so we
|
|
* replace the old contents in the table
|
|
*/
|
|
if ((bss_new_entry->ssid.ssid_len ==
|
|
pmadapter->pscan_table[bss_idx].ssid.ssid_len) &&
|
|
(!memcmp(pmadapter, bss_new_entry->ssid.ssid,
|
|
pmadapter->pscan_table[bss_idx].ssid.ssid,
|
|
bss_new_entry->ssid.ssid_len))) {
|
|
PRINTM(MINFO,
|
|
"EXT_SCAN: Duplicate of index: %d\n",
|
|
bss_idx);
|
|
break;
|
|
}
|
|
/*
|
|
* If the SSID is NULL for same BSSID
|
|
* keep the bss_idx set to this entry
|
|
* so we replace the old contents in
|
|
* the table
|
|
*/
|
|
if (!memcmp(pmadapter,
|
|
pmadapter->pscan_table[bss_idx].ssid.ssid,
|
|
null_ssid,
|
|
pmadapter->pscan_table[bss_idx]
|
|
.ssid.ssid_len)) {
|
|
PRINTM(MINFO,
|
|
"EXT_SCAN: Duplicate of index: %d\n",
|
|
bss_idx);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/* If the bss_idx is equal to the number of entries
|
|
* in the table, the new entry was not a duplicate;
|
|
* append it to the scan table
|
|
*/
|
|
if (bss_idx == num_in_table) {
|
|
/* Range check the bss_idx, keep it limited to the last entry */
|
|
if (bss_idx == MRVDRV_MAX_BSSID_LIST)
|
|
bss_idx--;
|
|
else
|
|
num_in_table++;
|
|
} else {
|
|
if ((bss_new_entry->channel !=
|
|
pmadapter->pscan_table[bss_idx].channel) &&
|
|
(bss_new_entry->rssi >
|
|
pmadapter->pscan_table[bss_idx].rssi)) {
|
|
PRINTM(MCMND,
|
|
"skip update the duplicate entry with low rssi\n");
|
|
return;
|
|
}
|
|
}
|
|
/*
|
|
* Save the beacon/probe response returned for later
|
|
* application retrieval. Duplicate beacon/probe
|
|
* responses are updated if possible
|
|
*/
|
|
wlan_ret_802_11_scan_store_beacon(pmpriv, bss_idx, num_in_table,
|
|
bss_new_entry);
|
|
if (bss_new_entry->pbeacon_buf == MNULL) {
|
|
PRINTM(MCMND, "No space for beacon, drop this entry\n");
|
|
num_in_table--;
|
|
goto done;
|
|
} else {
|
|
/* Copy the locally created bss_new_entry to the scan table */
|
|
memcpy_ext(pmadapter, &pmadapter->pscan_table[bss_idx],
|
|
bss_new_entry,
|
|
sizeof(pmadapter->pscan_table[bss_idx]),
|
|
sizeof(pmadapter->pscan_table[bss_idx]));
|
|
}
|
|
done:
|
|
*num_in_tbl = num_in_table;
|
|
return;
|
|
}
|
|
|
|
/** 8 bytes timestamp, 2 bytest interval, 2 bytes capability */
|
|
#define BEACON_FIX_SIZE 12
|
|
|
|
/**
|
|
* @brief This function realloc the beacon buffer and update ssid for new entry
|
|
*
|
|
* @param pmadpater A pointer to mlan_adapter structure
|
|
* @param pbss_entry A pointer to the bss_entry which has multi-bssid IE
|
|
* @param pnew_entry A pinter to new entry
|
|
* @param pssid A pointer to ssid IE
|
|
*
|
|
* @return MLAN_STATUS_FAILURE/MLAN_STATUS_SUCCESS
|
|
*/
|
|
static mlan_status wlan_update_ssid_in_beacon_buf(
|
|
mlan_adapter *pmadapter, BSSDescriptor_t *pbss_entry,
|
|
BSSDescriptor_t *pnew_entry, IEEEtypes_Ssid_t *pssid,
|
|
IEEEtypes_ExtCap_t *pnew_extcap, IEEEtypes_Generic_t *pnew_rsnx)
|
|
{
|
|
mlan_callbacks *pcb = (pmlan_callbacks)&pmadapter->callbacks;
|
|
t_u8 *pbeacon_buf = MNULL;
|
|
t_u32 beacon_buf_size = 0;
|
|
t_s8 offset = pnew_entry->ssid.ssid_len - pbss_entry->ssid.ssid_len;
|
|
IEEEtypes_ExtCap_t *pextcap;
|
|
mlan_status ret = MLAN_STATUS_FAILURE;
|
|
t_u32 rsnx_offset = 0;
|
|
|
|
if (pnew_entry->ssid.ssid_len >= pbss_entry->ssid.ssid_len)
|
|
beacon_buf_size =
|
|
pbss_entry->beacon_buf_size +
|
|
(pnew_entry->ssid.ssid_len - pbss_entry->ssid.ssid_len);
|
|
else
|
|
beacon_buf_size =
|
|
pbss_entry->beacon_buf_size -
|
|
(pbss_entry->ssid.ssid_len - pnew_entry->ssid.ssid_len);
|
|
|
|
rsnx_offset = beacon_buf_size;
|
|
if (pnew_rsnx)
|
|
beacon_buf_size +=
|
|
pnew_rsnx->ieee_hdr.len + sizeof(IEEEtypes_Header_t);
|
|
|
|
ret = pcb->moal_malloc(pmadapter->pmoal_handle, beacon_buf_size,
|
|
MLAN_MEM_DEF, (t_u8 **)&pbeacon_buf);
|
|
if (ret != MLAN_STATUS_SUCCESS || !pbeacon_buf) {
|
|
PRINTM(MERROR,
|
|
"Memory allocation for beacon buf for bss_new_entry\n");
|
|
goto done;
|
|
}
|
|
pnew_entry->beacon_buf_size = beacon_buf_size;
|
|
pnew_entry->pbeacon_buf = pbeacon_buf;
|
|
/** copy fixed IE */
|
|
memcpy_ext(pmadapter, pbeacon_buf, pbss_entry->pbeacon_buf,
|
|
BEACON_FIX_SIZE, BEACON_FIX_SIZE);
|
|
/** copy new ssid ie */
|
|
memcpy_ext(pmadapter, pbeacon_buf + BEACON_FIX_SIZE, (t_u8 *)pssid,
|
|
pssid->len + sizeof(IEEEtypes_Header_t),
|
|
pssid->len + sizeof(IEEEtypes_Header_t));
|
|
/** copy left IE to new beacon buffer */
|
|
memcpy_ext(pmadapter,
|
|
pbeacon_buf + BEACON_FIX_SIZE + pssid->len +
|
|
sizeof(IEEEtypes_Header_t),
|
|
pbss_entry->pbeacon_buf + BEACON_FIX_SIZE +
|
|
pbss_entry->ssid.ssid_len +
|
|
sizeof(IEEEtypes_Header_t),
|
|
pbss_entry->beacon_buf_size - BEACON_FIX_SIZE -
|
|
(pbss_entry->ssid.ssid_len +
|
|
sizeof(IEEEtypes_Header_t)),
|
|
pbss_entry->beacon_buf_size - BEACON_FIX_SIZE -
|
|
(pbss_entry->ssid.ssid_len +
|
|
sizeof(IEEEtypes_Header_t)));
|
|
|
|
/* adjust the ie pointer */
|
|
if (pnew_entry->pwpa_ie)
|
|
pnew_entry->wpa_offset += offset;
|
|
if (pnew_entry->prsn_ie)
|
|
pnew_entry->rsn_offset += offset;
|
|
if (pnew_entry->pwapi_ie)
|
|
pnew_entry->wapi_offset += offset;
|
|
|
|
if (pnew_entry->posen_ie)
|
|
pnew_entry->osen_offset += offset;
|
|
if (pnew_entry->pmd_ie)
|
|
pnew_entry->md_offset += offset;
|
|
if (pnew_entry->pht_cap)
|
|
pnew_entry->ht_cap_offset += offset;
|
|
if (pnew_entry->pht_info)
|
|
pnew_entry->ht_info_offset += offset;
|
|
if (pnew_entry->pbss_co_2040)
|
|
pnew_entry->bss_co_2040_offset += offset;
|
|
if (pnew_entry->pext_cap) {
|
|
pnew_entry->ext_cap_offset += offset;
|
|
if (pnew_extcap) {
|
|
pextcap = (IEEEtypes_ExtCap_t
|
|
*)(pnew_entry->pbeacon_buf +
|
|
pnew_entry->ext_cap_offset);
|
|
memcpy_ext(pmadapter,
|
|
pbeacon_buf + pnew_entry->ext_cap_offset,
|
|
(t_u8 *)pnew_extcap,
|
|
pnew_extcap->ieee_hdr.len +
|
|
sizeof(IEEEtypes_Header_t),
|
|
pextcap->ieee_hdr.len +
|
|
sizeof(IEEEtypes_Header_t));
|
|
}
|
|
}
|
|
if (pnew_entry->poverlap_bss_scan_param)
|
|
pnew_entry->overlap_bss_offset += offset;
|
|
if (pnew_entry->pvht_cap)
|
|
pnew_entry->vht_cap_offset += offset;
|
|
if (pnew_entry->pvht_oprat)
|
|
pnew_entry->vht_oprat_offset += offset;
|
|
if (pnew_entry->pvht_txpower)
|
|
pnew_entry->vht_txpower_offset += offset;
|
|
if (pnew_entry->pext_pwer)
|
|
pnew_entry->ext_pwer_offset += offset;
|
|
if (pnew_entry->pext_bssload)
|
|
pnew_entry->ext_bssload_offset += offset;
|
|
if (pnew_entry->pquiet_chan)
|
|
pnew_entry->quiet_chan_offset += offset;
|
|
if (pnew_entry->poper_mode)
|
|
pnew_entry->oper_mode_offset += offset;
|
|
if (pnew_entry->phe_cap)
|
|
pnew_entry->he_cap_offset += offset;
|
|
if (pnew_entry->phe_oprat)
|
|
pnew_entry->he_oprat_offset += offset;
|
|
if (pnew_rsnx)
|
|
memcpy_ext(
|
|
pmadapter, pbeacon_buf + rsnx_offset, (t_u8 *)pnew_rsnx,
|
|
pnew_rsnx->ieee_hdr.len + sizeof(IEEEtypes_Header_t),
|
|
pnew_rsnx->ieee_hdr.len + sizeof(IEEEtypes_Header_t));
|
|
DBG_HEXDUMP(MCMD_D, "MBSSID beacon buf", pbeacon_buf, beacon_buf_size);
|
|
ret = MLAN_STATUS_SUCCESS;
|
|
done:
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief This function generate the bssid from bssid_idx
|
|
*
|
|
* @param pmadpater A pointer to mlan_adapter structure
|
|
* @param pbss_entry A pointer to the bss_entry which has multi-bssid IE
|
|
* @param pnew_entry A pinter to new entry
|
|
* @param bssid_index bssid_index from BSSID_IDX IE
|
|
*
|
|
* @return N/A
|
|
*/
|
|
static void wlan_gen_multi_bssid_by_bssid_index(pmlan_adapter pmadapter,
|
|
BSSDescriptor_t *pbss_entry,
|
|
BSSDescriptor_t *pnew_entry,
|
|
t_u8 bssid_index,
|
|
t_u8 max_bssid_indicator)
|
|
{
|
|
t_u8 mask = 0xff;
|
|
t_u8 new_bssid[6];
|
|
t_u8 bssid_a;
|
|
t_u8 src_bssid[6];
|
|
|
|
memcpy_ext(pmadapter, (t_u8 *)src_bssid, pbss_entry->mac_address,
|
|
sizeof(mlan_802_11_mac_addr), sizeof(src_bssid));
|
|
memcpy_ext(pmadapter, (t_u8 *)new_bssid,
|
|
(t_u8 *)&pbss_entry->mac_address,
|
|
sizeof(mlan_802_11_mac_addr), sizeof(new_bssid));
|
|
|
|
mask = (mask >> (8 - max_bssid_indicator));
|
|
bssid_a = src_bssid[5] & (~mask);
|
|
src_bssid[5] = (src_bssid[5] + bssid_index) & mask;
|
|
new_bssid[5] = bssid_a | src_bssid[5];
|
|
|
|
memcpy_ext(pmadapter, (t_u8 *)&pnew_entry->mac_address, new_bssid,
|
|
sizeof(new_bssid), sizeof(mlan_802_11_mac_addr));
|
|
memcpy_ext(pmadapter, (t_u8 *)&pnew_entry->multi_bssid_ap_addr,
|
|
(t_u8 *)&pbss_entry->mac_address,
|
|
sizeof(mlan_802_11_mac_addr), sizeof(mlan_802_11_mac_addr));
|
|
}
|
|
|
|
/**
|
|
* @brief This function parse the non_trans_bssid_profile
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param pbss_entry A pointer to BSSDescriptor_t which has multi-bssid
|
|
* IE
|
|
* @param pbss_profile A pointer to IEEEtypes_NonTransBSSIDprofile_t
|
|
* @param num_in_table A pointer to buffer to save num of entry in scan
|
|
* table.
|
|
* @param max_bssid_indicator max bssid indicator
|
|
*
|
|
* @return N/A
|
|
*/
|
|
static t_void wlan_parse_non_trans_bssid_profile(
|
|
mlan_private *pmpriv, BSSDescriptor_t *pbss_entry,
|
|
IEEEtypes_NonTransBSSIDProfile_t *pbss_profile, t_u32 *num_in_table,
|
|
t_u8 max_bssid_indicator)
|
|
{
|
|
mlan_adapter *pmadapter = pmpriv->adapter;
|
|
IEEEtypes_Header_t *pheader =
|
|
(IEEEtypes_Header_t *)pbss_profile->profile_data;
|
|
IEEEtypes_MultiBSSIDIndex_t *pbssid_index = MNULL;
|
|
IEEEtypes_Ssid_t *pssid = MNULL;
|
|
IEEEtypes_NotxBssCap_t *pcap =
|
|
(IEEEtypes_NotxBssCap_t *)pbss_profile->profile_data;
|
|
t_u8 *pos = pbss_profile->profile_data;
|
|
t_s8 left_len = pbss_profile->ieee_hdr.len;
|
|
t_u8 ret = MFALSE;
|
|
mlan_callbacks *pcb = (pmlan_callbacks)&pmadapter->callbacks;
|
|
BSSDescriptor_t *bss_new_entry = MNULL;
|
|
t_u8 *pbeacon_buf = MNULL;
|
|
IEEEtypes_ExtCap_t *pextcap = MNULL;
|
|
IEEEtypes_Generic_t *prsnx = MNULL;
|
|
|
|
ENTER();
|
|
|
|
/* The first element within the Nontransmitted
|
|
* BSSID Profile is not the Nontransmitted
|
|
* BSSID Capability element.
|
|
*/
|
|
if (pcap->element_id != NONTX_BSSID_CAP || pcap->len != 2) {
|
|
PRINTM(MERROR,
|
|
"The first element within the Nontransmitted BSSID Profile is not the NontransmittedBSSID Capability element\n");
|
|
LEAVE();
|
|
return;
|
|
}
|
|
|
|
while (left_len >= 2) {
|
|
pheader = (IEEEtypes_Header_t *)pos;
|
|
if ((t_s8)(pheader->len + sizeof(IEEEtypes_Header_t)) >
|
|
left_len) {
|
|
PRINTM(MMSG, "invalid IE length = %d left len %d\n",
|
|
pheader->len, left_len);
|
|
break;
|
|
}
|
|
switch (pheader->element_id) {
|
|
case MBSSID_INDEX:
|
|
pbssid_index = (IEEEtypes_MultiBSSIDIndex_t *)pos;
|
|
if (pbssid_index->bssid_index == 0 ||
|
|
pbssid_index->bssid_index > 46) {
|
|
PRINTM(MERROR,
|
|
" No valid Multiple BSSID-Index element\n");
|
|
goto done;
|
|
}
|
|
PRINTM(MCMND, "MBSSID: Find mbssid_index=%d\n",
|
|
pbssid_index->bssid_index);
|
|
ret = MTRUE;
|
|
break;
|
|
case EXT_CAPABILITY:
|
|
pextcap = (IEEEtypes_ExtCap_t *)pos;
|
|
DBG_HEXDUMP(MCMD_D, "MBSSID extcap", pos,
|
|
pextcap->ieee_hdr.len +
|
|
sizeof(IEEEtypes_Header_t));
|
|
break;
|
|
case RSNX_IE:
|
|
prsnx = (IEEEtypes_Generic_t *)pos;
|
|
DBG_HEXDUMP(MCMD_D, "MBSSID RSNX", pos,
|
|
prsnx->ieee_hdr.len +
|
|
sizeof(IEEEtypes_Header_t));
|
|
break;
|
|
case SSID:
|
|
pssid = (IEEEtypes_Ssid_t *)pos;
|
|
PRINTM(MCMND, "MBSSID: Find mbssid ssid=%s\n",
|
|
pssid->ssid);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
left_len -= pheader->len + sizeof(IEEEtypes_Header_t);
|
|
pos += pheader->len + sizeof(IEEEtypes_Header_t);
|
|
}
|
|
if (ret == MTRUE) {
|
|
ret = pcb->moal_malloc(pmadapter->pmoal_handle,
|
|
sizeof(BSSDescriptor_t), MLAN_MEM_DEF,
|
|
(t_u8 **)&bss_new_entry);
|
|
if (ret != MLAN_STATUS_SUCCESS || !bss_new_entry) {
|
|
PRINTM(MERROR,
|
|
"Memory allocation for bss_new_entry failed!\n");
|
|
goto done;
|
|
}
|
|
memcpy_ext(pmadapter, bss_new_entry, pbss_entry,
|
|
sizeof(BSSDescriptor_t), sizeof(BSSDescriptor_t));
|
|
wlan_gen_multi_bssid_by_bssid_index(pmadapter, pbss_entry,
|
|
bss_new_entry,
|
|
pbssid_index->bssid_index,
|
|
max_bssid_indicator);
|
|
if (pssid) {
|
|
memset(pmadapter, (t_u8 *)&bss_new_entry->ssid, 0,
|
|
sizeof(mlan_802_11_ssid));
|
|
bss_new_entry->ssid.ssid_len = pssid->len;
|
|
memcpy_ext(pmadapter, bss_new_entry->ssid.ssid,
|
|
pssid->ssid, pssid->len,
|
|
MLAN_MAX_SSID_LENGTH);
|
|
if (MLAN_STATUS_SUCCESS !=
|
|
wlan_update_ssid_in_beacon_buf(
|
|
pmadapter, pbss_entry, bss_new_entry, pssid,
|
|
pextcap, prsnx)) {
|
|
PRINTM(MERROR,
|
|
"Fail to update MBSSID beacon buf\n");
|
|
pcb->moal_mfree(pmadapter->pmoal_handle,
|
|
(t_u8 *)bss_new_entry);
|
|
goto done;
|
|
}
|
|
pbeacon_buf = bss_new_entry->pbeacon_buf;
|
|
}
|
|
memcpy_ext(pmadapter, &bss_new_entry->cap_info, &pcap->cap,
|
|
sizeof(IEEEtypes_CapInfo_t),
|
|
sizeof(IEEEtypes_CapInfo_t));
|
|
bss_new_entry->multi_bssid_ap = MULTI_BSSID_SUB_AP;
|
|
wlan_add_new_entry_to_scan_table(pmpriv, bss_new_entry,
|
|
num_in_table);
|
|
if (pssid && pbeacon_buf)
|
|
pcb->moal_mfree(pmadapter->pmoal_handle,
|
|
(t_u8 *)pbeacon_buf);
|
|
pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)bss_new_entry);
|
|
}
|
|
done:
|
|
LEAVE();
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* @brief This function parse the multi_bssid IE from pbss_entry
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @param pbss_entry A pointer to BSSDescriptor_t which has multi-bssid
|
|
* IE
|
|
* @param num_in_table A pointer to buffer to save num of entry in scan
|
|
* table.
|
|
*
|
|
* @return number entry in scan table
|
|
*/
|
|
static t_void wlan_parse_multi_bssid_ie(mlan_private *pmpriv,
|
|
BSSDescriptor_t *pbss_entry,
|
|
IEEEtypes_MultiBSSID_t *pmulti_bssid,
|
|
t_u32 *num_in_table)
|
|
{
|
|
t_u32 bytes_left = 0;
|
|
t_u8 *pcurrent_ptr = MNULL;
|
|
IEEEtypes_NonTransBSSIDProfile_t *pbssid_profile = MNULL;
|
|
|
|
if (!pmulti_bssid)
|
|
return;
|
|
bytes_left = pmulti_bssid->ieee_hdr.len - 1;
|
|
pcurrent_ptr = pmulti_bssid->sub_elem_data;
|
|
while (bytes_left >= 2) {
|
|
pbssid_profile =
|
|
(IEEEtypes_NonTransBSSIDProfile_t *)pcurrent_ptr;
|
|
if (pbssid_profile->ieee_hdr.element_id !=
|
|
NONTRANS_BSSID_PROFILE_SUBELEM_ID) {
|
|
PRINTM(MERROR, "Invalid multi-bssid IE\n");
|
|
break;
|
|
}
|
|
if (bytes_left < (t_u32)(pbssid_profile->ieee_hdr.len + 2)) {
|
|
PRINTM(MERROR, "Invalid multi-bssid IE\n");
|
|
break;
|
|
}
|
|
wlan_parse_non_trans_bssid_profile(
|
|
pmpriv, pbss_entry, pbssid_profile, num_in_table,
|
|
pmulti_bssid->max_bssid_indicator);
|
|
pcurrent_ptr += pbssid_profile->ieee_hdr.len + 2;
|
|
bytes_left -= pbssid_profile->ieee_hdr.len + 2;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* @brief This function search all the mbssid IE in the beacon buffer
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @param pbss_entry A pointer to BSSDescriptor_t which has multi-bssid
|
|
* IE
|
|
* @param num_in_table A pointer to buffer to save num of entry in scan
|
|
* table.
|
|
*
|
|
* @return N/A
|
|
*/
|
|
static void wlan_parse_multi_bssid_ap(mlan_private *pmpriv,
|
|
BSSDescriptor_t *pbss_entry,
|
|
t_u32 *num_in_table)
|
|
{
|
|
IEEEtypes_ElementId_e element_id;
|
|
t_u8 element_len;
|
|
t_u16 total_ie_len;
|
|
t_u32 bytes_left = pbss_entry->beacon_buf_size - BEACON_FIX_SIZE;
|
|
t_u8 *pcurrent_ptr = pbss_entry->pbeacon_buf + BEACON_FIX_SIZE;
|
|
IEEEtypes_Ssid_t *pssid = (IEEEtypes_Ssid_t *)pcurrent_ptr;
|
|
|
|
if (pssid->element_id != SSID) {
|
|
PRINTM(MERROR,
|
|
"Invalid beacon ie, ssid should be in the first element\n");
|
|
return;
|
|
}
|
|
/* Process variable IE */
|
|
while (bytes_left >= 2) {
|
|
element_id = (IEEEtypes_ElementId_e)(*((t_u8 *)pcurrent_ptr));
|
|
element_len = *((t_u8 *)pcurrent_ptr + 1);
|
|
total_ie_len = element_len + sizeof(IEEEtypes_Header_t);
|
|
|
|
if (bytes_left < total_ie_len) {
|
|
PRINTM(MERROR, "InterpretIE: Error in processing IE, "
|
|
"bytes left < IE length\n");
|
|
bytes_left = 0;
|
|
continue;
|
|
}
|
|
if (element_id == MULTI_BSSID)
|
|
wlan_parse_multi_bssid_ie(
|
|
pmpriv, pbss_entry,
|
|
(IEEEtypes_MultiBSSID_t *)pcurrent_ptr,
|
|
num_in_table);
|
|
pcurrent_ptr += total_ie_len;
|
|
bytes_left -= total_ie_len;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* @brief This function parse and store the extended scan results
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @param number_of_sets Number of BSS
|
|
* @param pscan_resp A pointer to scan response buffer
|
|
* @param scan_resp_size Size of scan response buffer
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_parse_ext_scan_result(mlan_private *pmpriv,
|
|
t_u8 number_of_sets,
|
|
t_u8 *pscan_resp,
|
|
t_u16 scan_resp_size)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_adapter *pmadapter = pmpriv->adapter;
|
|
mlan_callbacks *pcb = MNULL;
|
|
BSSDescriptor_t *bss_new_entry = MNULL;
|
|
t_u8 *pbss_info;
|
|
t_u32 bytes_left;
|
|
t_u32 bytes_left_for_tlv;
|
|
t_u32 num_in_table;
|
|
t_u32 idx;
|
|
t_u64 tsf_val;
|
|
chan_freq_power_t *cfp;
|
|
t_u16 tlv_type, tlv_len;
|
|
MrvlIEtypes_Data_t *ptlv = MNULL;
|
|
MrvlIEtypes_Bss_Scan_Rsp_t *pscan_rsp_tlv = MNULL;
|
|
MrvlIEtypes_Bss_Scan_Info_t *pscan_info_tlv = MNULL;
|
|
t_u8 band;
|
|
t_u32 age_ts_usec;
|
|
|
|
ENTER();
|
|
pcb = (pmlan_callbacks)&pmadapter->callbacks;
|
|
|
|
if (number_of_sets > MRVDRV_MAX_BSSID_LIST) {
|
|
PRINTM(MERROR,
|
|
"EXT_SCAN: Invalid number of AP returned (%d)!!\n",
|
|
number_of_sets);
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
bytes_left = scan_resp_size;
|
|
PRINTM(MINFO, "EXT_SCAN: bss_descript_size %d\n", scan_resp_size);
|
|
PRINTM(MINFO, "EXT_SCAN: returned %d APs before parsing\n",
|
|
number_of_sets);
|
|
/* Update the age_in_second */
|
|
pmadapter->callbacks.moal_get_system_time(
|
|
pmadapter->pmoal_handle, &pmadapter->age_in_secs, &age_ts_usec);
|
|
|
|
num_in_table = pmadapter->num_in_scan_table;
|
|
ptlv = (MrvlIEtypes_Data_t *)pscan_resp;
|
|
|
|
/*
|
|
* Process each scan response returned number_of_sets. Save
|
|
* the information in the bss_new_entry and then insert into the
|
|
* driver scan table either as an update to an existing entry
|
|
* or as an addition at the end of the table
|
|
*/
|
|
ret = pcb->moal_malloc(pmadapter->pmoal_handle, sizeof(BSSDescriptor_t),
|
|
MLAN_MEM_DEF, (t_u8 **)&bss_new_entry);
|
|
|
|
if (ret != MLAN_STATUS_SUCCESS || !bss_new_entry) {
|
|
PRINTM(MERROR, "Memory allocation for bss_new_entry failed!\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
for (idx = 0;
|
|
idx < number_of_sets && bytes_left > sizeof(MrvlIEtypesHeader_t);
|
|
idx++) {
|
|
tlv_type = wlan_le16_to_cpu(ptlv->header.type);
|
|
tlv_len = wlan_le16_to_cpu(ptlv->header.len);
|
|
if (bytes_left < sizeof(MrvlIEtypesHeader_t) + tlv_len) {
|
|
PRINTM(MERROR,
|
|
"EXT_SCAN: Error bytes left < TLV length\n");
|
|
break;
|
|
}
|
|
pscan_rsp_tlv = MNULL;
|
|
pscan_info_tlv = MNULL;
|
|
bytes_left_for_tlv = bytes_left;
|
|
/*
|
|
* BSS response TLV with beacon or probe response buffer
|
|
* at the initial position of each descriptor
|
|
*/
|
|
if (tlv_type == TLV_TYPE_BSS_SCAN_RSP) {
|
|
pbss_info = (t_u8 *)ptlv;
|
|
pscan_rsp_tlv = (MrvlIEtypes_Bss_Scan_Rsp_t *)ptlv;
|
|
ptlv = (MrvlIEtypes_Data_t *)(ptlv->data + tlv_len);
|
|
bytes_left_for_tlv -=
|
|
(tlv_len + sizeof(MrvlIEtypesHeader_t));
|
|
} else
|
|
break;
|
|
|
|
/* Process variable TLV */
|
|
while (bytes_left_for_tlv >= sizeof(MrvlIEtypesHeader_t) &&
|
|
wlan_le16_to_cpu(ptlv->header.type) !=
|
|
TLV_TYPE_BSS_SCAN_RSP) {
|
|
tlv_type = wlan_le16_to_cpu(ptlv->header.type);
|
|
tlv_len = wlan_le16_to_cpu(ptlv->header.len);
|
|
if (bytes_left_for_tlv <
|
|
sizeof(MrvlIEtypesHeader_t) + tlv_len) {
|
|
PRINTM(MERROR,
|
|
"EXT_SCAN: Error in processing TLV, "
|
|
"bytes left < TLV length\n");
|
|
pscan_rsp_tlv = MNULL;
|
|
bytes_left_for_tlv = 0;
|
|
continue;
|
|
}
|
|
switch (tlv_type) {
|
|
case TLV_TYPE_BSS_SCAN_INFO:
|
|
pscan_info_tlv =
|
|
(MrvlIEtypes_Bss_Scan_Info_t *)ptlv;
|
|
if (tlv_len !=
|
|
sizeof(MrvlIEtypes_Bss_Scan_Info_t) -
|
|
sizeof(MrvlIEtypesHeader_t)) {
|
|
bytes_left_for_tlv = 0;
|
|
continue;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
ptlv = (MrvlIEtypes_Data_t *)(ptlv->data + tlv_len);
|
|
bytes_left -= (tlv_len + sizeof(MrvlIEtypesHeader_t));
|
|
bytes_left_for_tlv -=
|
|
(tlv_len + sizeof(MrvlIEtypesHeader_t));
|
|
}
|
|
/* No BSS response TLV */
|
|
if (pscan_rsp_tlv == MNULL)
|
|
break;
|
|
|
|
/*
|
|
* Advance pointer to the beacon buffer length and
|
|
* update the bytes count so that the function
|
|
* wlan_interpret_bss_desc_with_ie() can handle the
|
|
* scan buffer withut any change
|
|
*/
|
|
pbss_info += sizeof(t_u16);
|
|
bytes_left -= sizeof(t_u16);
|
|
|
|
/* Zero out the bss_new_entry we are about to store info in */
|
|
memset(pmadapter, bss_new_entry, 0x00, sizeof(BSSDescriptor_t));
|
|
|
|
/* Process the data fields and IEs returned for this BSS */
|
|
if (wlan_interpret_bss_desc_with_ie(
|
|
pmadapter, bss_new_entry, &pbss_info, &bytes_left,
|
|
MTRUE) == MLAN_STATUS_SUCCESS) {
|
|
PRINTM(MINFO, "EXT_SCAN: BSSID = " MACSTR "\n",
|
|
MAC2STR(bss_new_entry->mac_address));
|
|
|
|
band = BAND_G;
|
|
/*
|
|
* If the BSS info TLV was appended to the scan results,
|
|
* save this entry's TSF value in the networkTSF field.
|
|
* The networkTSF is the firmware's TSF value at the
|
|
* time the beacon or probe response was received.
|
|
*/
|
|
if (pscan_info_tlv) {
|
|
/* RSSI is 2 byte long */
|
|
bss_new_entry->rssi = -(t_s32)(
|
|
wlan_le16_to_cpu(pscan_info_tlv->rssi));
|
|
PRINTM(MINFO, "EXT_SCAN: RSSI=%d\n",
|
|
bss_new_entry->rssi);
|
|
memcpy_ext(pmpriv->adapter, &tsf_val,
|
|
&pscan_info_tlv->tsf,
|
|
sizeof(tsf_val), sizeof(tsf_val));
|
|
tsf_val = wlan_le64_to_cpu(tsf_val);
|
|
memcpy_ext(pmpriv->adapter,
|
|
&bss_new_entry->network_tsf,
|
|
&tsf_val,
|
|
sizeof(bss_new_entry->network_tsf),
|
|
sizeof(bss_new_entry->network_tsf));
|
|
band = radio_type_to_band(
|
|
pscan_info_tlv->bandcfg.chanBand);
|
|
if (!bss_new_entry->channel)
|
|
bss_new_entry->channel =
|
|
pscan_info_tlv->channel;
|
|
}
|
|
/* Save the band designation for this entry for use in
|
|
* join */
|
|
bss_new_entry->bss_band = band;
|
|
bss_new_entry->age_in_secs = pmadapter->age_in_secs;
|
|
|
|
cfp = wlan_find_cfp_by_band_and_channel(
|
|
pmadapter, (t_u8)bss_new_entry->bss_band,
|
|
(t_u16)bss_new_entry->channel);
|
|
if (cfp)
|
|
bss_new_entry->freq = cfp->freq;
|
|
else
|
|
bss_new_entry->freq = 0;
|
|
|
|
/* Skip entry if on blacklisted channel */
|
|
if (cfp && cfp->dynamic.blacklist) {
|
|
PRINTM(MINFO,
|
|
"EXT_SCAN: dropping entry on blacklist channel.\n");
|
|
continue;
|
|
}
|
|
if (IS_FW_SUPPORT_MULTIBSSID(pmadapter)) {
|
|
if (bss_new_entry->multi_bssid_ap ==
|
|
MULTI_BSSID_AP)
|
|
wlan_parse_multi_bssid_ap(
|
|
pmpriv, bss_new_entry,
|
|
&num_in_table);
|
|
}
|
|
wlan_add_new_entry_to_scan_table(pmpriv, bss_new_entry,
|
|
&num_in_table);
|
|
|
|
} else {
|
|
/* Error parsing/interpreting the scan response, skipped
|
|
*/
|
|
PRINTM(MERROR,
|
|
"EXT_SCAN: wlan_interpret_bss_desc_with_ie returned error\n");
|
|
}
|
|
}
|
|
|
|
PRINTM(MCMND, "EXT_SCAN: Scanned %2d APs, %d valid, %d total\n",
|
|
number_of_sets, num_in_table - pmadapter->num_in_scan_table,
|
|
num_in_table);
|
|
|
|
/* Update the total number of BSSIDs in the scan table */
|
|
pmadapter->num_in_scan_table = num_in_table;
|
|
/* Update the age_in_second */
|
|
pmadapter->callbacks.moal_get_system_time(
|
|
pmadapter->pmoal_handle, &pmadapter->age_in_secs, &age_ts_usec);
|
|
|
|
done:
|
|
if (bss_new_entry)
|
|
pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)bss_new_entry);
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief This function handles the event extended scan report
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @param pmbuf A pointer to mlan_buffer
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status wlan_handle_event_ext_scan_report(mlan_private *pmpriv,
|
|
mlan_buffer *pmbuf)
|
|
{
|
|
mlan_adapter *pmadapter = pmpriv->adapter;
|
|
mlan_callbacks *pcb = &pmadapter->callbacks;
|
|
mlan_ioctl_req *pioctl_req = MNULL;
|
|
cmd_ctrl_node *pcmd_node = MNULL;
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
|
|
mlan_event_scan_result *pevent_scan =
|
|
(pmlan_event_scan_result)(pmbuf->pbuf + pmbuf->data_offset);
|
|
t_u8 *ptlv = (pmbuf->pbuf + pmbuf->data_offset +
|
|
sizeof(mlan_event_scan_result));
|
|
t_u16 tlv_buf_left = wlan_le16_to_cpu(pevent_scan->buf_size);
|
|
|
|
DBG_HEXDUMP(MCMD_D, "EVENT EXT_SCAN", pmbuf->pbuf + pmbuf->data_offset,
|
|
pmbuf->data_len);
|
|
wlan_parse_ext_scan_result(pmpriv, pevent_scan->num_of_set, ptlv,
|
|
tlv_buf_left);
|
|
if (!pevent_scan->more_event &&
|
|
(pmadapter->ext_scan_type != EXT_SCAN_ENHANCE)) {
|
|
wlan_request_cmd_lock(pmadapter);
|
|
if (!util_peek_list(pmadapter->pmoal_handle,
|
|
&pmadapter->scan_pending_q, MNULL, MNULL)) {
|
|
wlan_release_cmd_lock(pmadapter);
|
|
if (pmadapter->pscan_ioctl_req) {
|
|
if (((mlan_ds_scan *)
|
|
pmadapter->pscan_ioctl_req->pbuf)
|
|
->sub_command ==
|
|
MLAN_OID_SCAN_SPECIFIC_SSID ||
|
|
((mlan_ds_scan *)
|
|
pmadapter->pscan_ioctl_req->pbuf)
|
|
->sub_command ==
|
|
MLAN_OID_SCAN_USER_CONFIG) {
|
|
if (wlan_active_scan_req_for_passive_chan(
|
|
pmpriv,
|
|
pmadapter->pscan_ioctl_req)) {
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* Process the resulting scan table:
|
|
* - Remove any bad ssids
|
|
* - Update our current BSS information from scan data
|
|
*/
|
|
wlan_scan_process_results(pmpriv);
|
|
wlan_request_cmd_lock(pmadapter);
|
|
pmadapter->scan_processing = MFALSE;
|
|
pioctl_req = pmadapter->pscan_ioctl_req;
|
|
pmadapter->pscan_ioctl_req = MNULL;
|
|
/* Need to indicate IOCTL complete */
|
|
if (pioctl_req != MNULL) {
|
|
pioctl_req->status_code = MLAN_ERROR_NO_ERROR;
|
|
/* Indicate ioctl complete */
|
|
pcb->moal_ioctl_complete(
|
|
pmadapter->pmoal_handle,
|
|
(pmlan_ioctl_req)pioctl_req,
|
|
MLAN_STATUS_SUCCESS);
|
|
}
|
|
wlan_release_cmd_lock(pmadapter);
|
|
|
|
pmadapter->bgscan_reported = MFALSE;
|
|
wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_SCAN_REPORT,
|
|
MNULL);
|
|
} else {
|
|
/* If firmware not ready, do not issue any more scan
|
|
* commands */
|
|
if (pmadapter->hw_status != WlanHardwareStatusReady) {
|
|
wlan_release_cmd_lock(pmadapter);
|
|
/* Flush all pending scan commands */
|
|
wlan_flush_scan_queue(pmadapter);
|
|
wlan_request_cmd_lock(pmadapter);
|
|
pmadapter->scan_processing = MFALSE;
|
|
pioctl_req = pmadapter->pscan_ioctl_req;
|
|
pmadapter->pscan_ioctl_req = MNULL;
|
|
/* Indicate IOCTL complete */
|
|
if (pioctl_req != MNULL) {
|
|
pioctl_req->status_code =
|
|
MLAN_ERROR_FW_NOT_READY;
|
|
|
|
/* Indicate ioctl complete */
|
|
pcb->moal_ioctl_complete(
|
|
pmadapter->pmoal_handle,
|
|
(pmlan_ioctl_req)pioctl_req,
|
|
MLAN_STATUS_FAILURE);
|
|
}
|
|
wlan_release_cmd_lock(pmadapter);
|
|
} else {
|
|
/* Get scan command from scan_pending_q and put
|
|
* to cmd_pending_q */
|
|
pcmd_node = (cmd_ctrl_node *)util_dequeue_list(
|
|
pmadapter->pmoal_handle,
|
|
&pmadapter->scan_pending_q, MNULL,
|
|
MNULL);
|
|
wlan_insert_cmd_to_pending_q(pmadapter,
|
|
pcmd_node, MTRUE);
|
|
wlan_release_cmd_lock(pmadapter);
|
|
}
|
|
}
|
|
}
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief This function handles the event extended scan status
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @param pmbuf A pointer to mlan_buffer
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status wlan_handle_event_ext_scan_status(mlan_private *pmpriv,
|
|
mlan_buffer *pmbuf)
|
|
{
|
|
mlan_adapter *pmadapter = pmpriv->adapter;
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_event_scan_status *scan_event;
|
|
mlan_ioctl_req *pioctl_req;
|
|
mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks;
|
|
t_u16 tlv_buf_left, tlv_len, tlv_type;
|
|
MrvlIEtypesHeader_t *tlv;
|
|
MrvlIEtypes_ChannelStats_t *tlv_chan_stats;
|
|
t_u8 status;
|
|
|
|
ENTER();
|
|
|
|
if (pmbuf->data_len < sizeof(mlan_event_scan_status)) {
|
|
PRINTM(MERROR, "Wrong ext scan status event data length\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
scan_event =
|
|
(pmlan_event_scan_status)(pmbuf->pbuf + pmbuf->data_offset);
|
|
DBG_HEXDUMP(MCMD_D, "EVENT: Ext_Scan_Status", scan_event,
|
|
pmbuf->data_len);
|
|
status = scan_event->scan_status;
|
|
PRINTM(MEVENT, "ext_scan_status: status %d (scan %s), buf_len %d\n",
|
|
status, status ? "cancelled" : "success", scan_event->buf_len);
|
|
|
|
tlv = (MrvlIEtypesHeader_t *)scan_event->event_buf;
|
|
tlv_buf_left = pmbuf->data_len - sizeof(mlan_event_scan_status);
|
|
while (tlv_buf_left >= sizeof(MrvlIEtypesHeader_t)) {
|
|
tlv_type = wlan_le16_to_cpu(tlv->type);
|
|
tlv_len = wlan_le16_to_cpu(tlv->len);
|
|
if (tlv_buf_left < (tlv_len + sizeof(MrvlIEtypesHeader_t))) {
|
|
PRINTM(MERROR,
|
|
"Error process scan gap tlv: length %d type 0x%x\n",
|
|
tlv_len, tlv_type);
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
switch (tlv_type) {
|
|
case TLV_TYPE_CHANNEL_STATS:
|
|
tlv_chan_stats = (MrvlIEtypes_ChannelStats_t *)tlv;
|
|
wlan_update_chan_statistics(pmpriv, tlv_chan_stats);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
tlv_buf_left -= tlv_len + sizeof(MrvlIEtypesHeader_t);
|
|
tlv = (MrvlIEtypesHeader_t *)((t_u8 *)tlv + tlv_len +
|
|
sizeof(MrvlIEtypesHeader_t));
|
|
}
|
|
|
|
done:
|
|
/* Now we got response from FW, cancel the command timer */
|
|
if (!pmadapter->curr_cmd && pmadapter->cmd_timer_is_set) {
|
|
/* Cancel command timeout timer */
|
|
pcb->moal_stop_timer(pmadapter->pmoal_handle,
|
|
pmadapter->pmlan_cmd_timer);
|
|
/* Cancel command timeout timer */
|
|
pmadapter->cmd_timer_is_set = MFALSE;
|
|
}
|
|
if (pmadapter->pscan_ioctl_req) {
|
|
if (((mlan_ds_scan *)pmadapter->pscan_ioctl_req->pbuf)
|
|
->sub_command ==
|
|
MLAN_OID_SCAN_SPECIFIC_SSID ||
|
|
((mlan_ds_scan *)pmadapter->pscan_ioctl_req->pbuf)
|
|
->sub_command ==
|
|
MLAN_OID_SCAN_USER_CONFIG) {
|
|
if (wlan_active_scan_req_for_passive_chan(
|
|
pmpriv, pmadapter->pscan_ioctl_req)) {
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* Process the resulting scan table:
|
|
* - Remove any bad ssids
|
|
* - Update our current BSS information from scan data
|
|
*/
|
|
wlan_scan_process_results(pmpriv);
|
|
/** Complete scan ioctl */
|
|
wlan_request_cmd_lock(pmadapter);
|
|
pmadapter->scan_processing = MFALSE;
|
|
pioctl_req = pmadapter->pscan_ioctl_req;
|
|
pmadapter->pscan_ioctl_req = MNULL;
|
|
/* Need to indicate IOCTL complete */
|
|
if (pioctl_req != MNULL) {
|
|
pioctl_req->status_code = MLAN_ERROR_NO_ERROR;
|
|
/* Indicate ioctl complete */
|
|
pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_req,
|
|
MLAN_STATUS_SUCCESS);
|
|
}
|
|
wlan_release_cmd_lock(pmadapter);
|
|
wlan_move_cmd_to_cmd_pending_q(pmadapter);
|
|
pmadapter->bgscan_reported = MFALSE;
|
|
wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_SCAN_REPORT, MNULL);
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief This function prepares command of bg_scan_query.
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @param pcmd A pointer to HostCmd_DS_COMMAND structure
|
|
* @param pdata_buf Void pointer cast of a wlan_scan_cmd_config struct used
|
|
* to set the fields/TLVs for the command sent to firmware
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS
|
|
*/
|
|
mlan_status wlan_cmd_802_11_bg_scan_query(mlan_private *pmpriv,
|
|
HostCmd_DS_COMMAND *pcmd,
|
|
t_void *pdata_buf)
|
|
{
|
|
HostCmd_DS_802_11_BG_SCAN_QUERY *bg_query = &pcmd->params.bg_scan_query;
|
|
|
|
ENTER();
|
|
|
|
pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_QUERY);
|
|
pcmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_BG_SCAN_QUERY) +
|
|
S_DS_GEN);
|
|
|
|
bg_query->flush = MTRUE;
|
|
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief Create a channel list for the driver to scan based on region info
|
|
*
|
|
* Use the driver region/band information to construct a comprehensive list
|
|
* of channels to scan. This routine is used for any scan that is not
|
|
* provided a specific channel list to scan.
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @param pbg_scan_in pointer to scan configuration parameters
|
|
* @param tlv_chan_list A pointer to structure
|
|
* MrvlIEtypes_ChanListParamSet_t
|
|
*
|
|
* @return channel number
|
|
*/
|
|
static t_u8
|
|
wlan_bgscan_create_channel_list(mlan_private *pmpriv,
|
|
const wlan_bgscan_cfg *pbg_scan_in,
|
|
MrvlIEtypes_ChanListParamSet_t *tlv_chan_list)
|
|
{
|
|
mlan_adapter *pmadapter = pmpriv->adapter;
|
|
region_chan_t *pscan_region;
|
|
chan_freq_power_t *cfp;
|
|
t_u32 region_idx;
|
|
t_u32 chan_idx = 0;
|
|
t_u32 next_chan;
|
|
t_u8 scan_type;
|
|
t_u8 radio_type;
|
|
t_u8 band;
|
|
|
|
ENTER();
|
|
|
|
for (region_idx = 0; region_idx < NELEMENTS(pmadapter->region_channel);
|
|
region_idx++) {
|
|
if (wlan_11d_is_enabled(pmpriv) &&
|
|
pmpriv->media_connected != MTRUE) {
|
|
/* Scan all the supported chan for the first scan */
|
|
if (!pmadapter->universal_channel[region_idx].valid)
|
|
continue;
|
|
pscan_region =
|
|
&pmadapter->universal_channel[region_idx];
|
|
} else {
|
|
if (!pmadapter->region_channel[region_idx].valid)
|
|
continue;
|
|
pscan_region = &pmadapter->region_channel[region_idx];
|
|
}
|
|
|
|
if (pbg_scan_in && !pbg_scan_in->chan_list[0].chan_number &&
|
|
pbg_scan_in->chan_list[0].radio_type & BAND_SPECIFIED) {
|
|
radio_type = pbg_scan_in->chan_list[0].radio_type &
|
|
~BAND_SPECIFIED;
|
|
if (!radio_type && (pscan_region->band != BAND_B) &&
|
|
(pscan_region->band != BAND_G))
|
|
continue;
|
|
if (radio_type && (pscan_region->band != BAND_A))
|
|
continue;
|
|
}
|
|
if ((pbg_scan_in &&
|
|
(pbg_scan_in->bss_type == MLAN_SCAN_MODE_IBSS)) ||
|
|
pmpriv->bss_mode == MLAN_BSS_MODE_IBSS)
|
|
band = pmadapter->adhoc_start_band;
|
|
else
|
|
band = pmpriv->config_bands;
|
|
if (!wlan_is_band_compatible(band, pscan_region->band))
|
|
continue;
|
|
for (next_chan = 0; next_chan < pscan_region->num_cfp;
|
|
next_chan++, chan_idx++) {
|
|
if (chan_idx >= WLAN_BG_SCAN_CHAN_MAX)
|
|
break;
|
|
/*
|
|
* Set the default scan type to ACTIVE SCAN type, will
|
|
* later be changed to passive on a per channel basis
|
|
* if restricted by regulatory requirements (11d or 11h)
|
|
*/
|
|
scan_type = MLAN_SCAN_TYPE_ACTIVE;
|
|
cfp = pscan_region->pcfp + next_chan;
|
|
|
|
switch (pscan_region->band) {
|
|
case BAND_A:
|
|
tlv_chan_list->chan_scan_param[chan_idx]
|
|
.bandcfg.chanBand = BAND_5GHZ;
|
|
/* Passive scan on DFS channels */
|
|
if (wlan_11h_radar_detect_required(
|
|
pmpriv, (t_u8)cfp->channel))
|
|
scan_type = MLAN_SCAN_TYPE_PASSIVE;
|
|
break;
|
|
case BAND_B:
|
|
case BAND_G:
|
|
if (wlan_bg_scan_type_is_passive(
|
|
pmpriv, (t_u8)cfp->channel))
|
|
scan_type = MLAN_SCAN_TYPE_PASSIVE;
|
|
tlv_chan_list->chan_scan_param[chan_idx]
|
|
.bandcfg.chanBand = BAND_2GHZ;
|
|
break;
|
|
default:
|
|
tlv_chan_list->chan_scan_param[chan_idx]
|
|
.bandcfg.chanBand = BAND_2GHZ;
|
|
break;
|
|
}
|
|
|
|
if (pbg_scan_in &&
|
|
pbg_scan_in->chan_list[0].scan_time) {
|
|
tlv_chan_list->chan_scan_param[chan_idx]
|
|
.max_scan_time = wlan_cpu_to_le16(
|
|
(t_u16)pbg_scan_in->chan_list[0]
|
|
.scan_time);
|
|
tlv_chan_list->chan_scan_param[chan_idx]
|
|
.min_scan_time = wlan_cpu_to_le16(
|
|
(t_u16)pbg_scan_in->chan_list[0]
|
|
.scan_time);
|
|
} else if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
|
|
tlv_chan_list->chan_scan_param[chan_idx]
|
|
.max_scan_time = wlan_cpu_to_le16(
|
|
pmadapter->passive_scan_time);
|
|
tlv_chan_list->chan_scan_param[chan_idx]
|
|
.min_scan_time = wlan_cpu_to_le16(
|
|
pmadapter->passive_scan_time);
|
|
} else {
|
|
tlv_chan_list->chan_scan_param[chan_idx]
|
|
.max_scan_time = wlan_cpu_to_le16(
|
|
pmadapter->specific_scan_time);
|
|
tlv_chan_list->chan_scan_param[chan_idx]
|
|
.min_scan_time = wlan_cpu_to_le16(
|
|
pmadapter->specific_scan_time);
|
|
}
|
|
|
|
if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
|
|
tlv_chan_list->chan_scan_param[chan_idx]
|
|
.chan_scan_mode.passive_scan = MTRUE;
|
|
} else {
|
|
tlv_chan_list->chan_scan_param[chan_idx]
|
|
.chan_scan_mode.passive_scan = MFALSE;
|
|
}
|
|
|
|
tlv_chan_list->chan_scan_param[chan_idx].chan_number =
|
|
(t_u8)cfp->channel;
|
|
}
|
|
}
|
|
|
|
LEAVE();
|
|
return chan_idx;
|
|
}
|
|
|
|
/**
|
|
* @brief This function prepares command of bg_scan_config
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @param pcmd A pointer to HostCmd_DS_COMMAND structure
|
|
* @param pdata_buf Void pointer cast of a wlan_scan_cmd_config struct used
|
|
* to set the fields/TLVs for the command sent to firmware
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS
|
|
*/
|
|
mlan_status wlan_cmd_bgscan_config(mlan_private *pmpriv,
|
|
HostCmd_DS_COMMAND *pcmd, t_void *pdata_buf)
|
|
{
|
|
mlan_adapter *pmadapter = pmpriv->adapter;
|
|
HostCmd_DS_802_11_BG_SCAN_CONFIG *bg_scan =
|
|
&pcmd->params.bg_scan_config;
|
|
wlan_bgscan_cfg *bg_scan_in = (wlan_bgscan_cfg *)pdata_buf;
|
|
t_u16 cmd_size = 0;
|
|
MrvlIEtypes_NumProbes_t *pnum_probes_tlv = MNULL;
|
|
MrvlIEtypes_BeaconLowRssiThreshold_t *rssi_tlv = MNULL;
|
|
MrvlIEtypes_BeaconLowSnrThreshold_t *snr_tlv = MNULL;
|
|
MrvlIEtypes_WildCardSsIdParamSet_t *pwildcard_ssid_tlv = MNULL;
|
|
MrvlIEtypes_ChanListParamSet_t *tlv_chan_list = MNULL;
|
|
MrvlIEtypes_StartLater_t *tlv_start_later = MNULL;
|
|
MrvlIEtypes_RepeatCount_t *tlv_repeat = MNULL;
|
|
MrvlIEtypes_EESParamSet_t *tlv_ees_cfg = MNULL;
|
|
MrvlIEtype_EESNetworkCfg_t *tlv_ees_net_cfg = MNULL;
|
|
MrvlIEtypes_Cipher_t *tlv_ees_cipher = MNULL;
|
|
MrvlIEtypes_SsIdParamSet_t *tlv_ssid = MNULL;
|
|
MrvlIETypes_HTCap_t *pht_cap = MNULL;
|
|
MrvlIETypes_VHTCap_t *pvht_cap = MNULL;
|
|
MrvlIEtypes_Extension_t *phe_cap = MNULL;
|
|
t_u16 len = 0;
|
|
|
|
t_u8 index;
|
|
t_u8 *tlv = MNULL;
|
|
t_u16 num_probes = 0;
|
|
t_u32 ssid_idx;
|
|
t_u32 ssid_len = 0;
|
|
t_u32 chan_idx;
|
|
t_u32 chan_num;
|
|
t_u8 radio_type;
|
|
t_u16 scan_dur;
|
|
t_u8 scan_type;
|
|
t_u8 band;
|
|
const t_u8 zero_mac[6] = {0, 0, 0, 0, 0, 0};
|
|
|
|
ENTER();
|
|
|
|
pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_CONFIG);
|
|
bg_scan->action = wlan_cpu_to_le16(bg_scan_in->action);
|
|
bg_scan->enable = bg_scan_in->enable;
|
|
bg_scan->bss_type = bg_scan_in->bss_type;
|
|
cmd_size = sizeof(HostCmd_DS_802_11_BG_SCAN_CONFIG) + S_DS_GEN;
|
|
if (bg_scan_in->scan_interval)
|
|
bg_scan->scan_interval =
|
|
wlan_cpu_to_le32(bg_scan_in->scan_interval);
|
|
else
|
|
bg_scan->scan_interval =
|
|
wlan_cpu_to_le32(DEFAULT_BGSCAN_INTERVAL);
|
|
bg_scan->report_condition =
|
|
wlan_cpu_to_le32(bg_scan_in->report_condition);
|
|
|
|
if ((bg_scan_in->action == BG_SCAN_ACT_GET) ||
|
|
(bg_scan_in->action == BG_SCAN_ACT_GET_PPS_UAPSD) ||
|
|
(!bg_scan->enable))
|
|
goto done;
|
|
|
|
tlv = (t_u8 *)bg_scan + sizeof(HostCmd_DS_802_11_BG_SCAN_CONFIG);
|
|
num_probes = (bg_scan_in->num_probes ? bg_scan_in->num_probes :
|
|
pmadapter->scan_probes);
|
|
if (num_probes) {
|
|
pnum_probes_tlv = (MrvlIEtypes_NumProbes_t *)tlv;
|
|
pnum_probes_tlv->header.type =
|
|
wlan_cpu_to_le16(TLV_TYPE_NUMPROBES);
|
|
pnum_probes_tlv->header.len =
|
|
wlan_cpu_to_le16(sizeof(pnum_probes_tlv->num_probes));
|
|
pnum_probes_tlv->num_probes =
|
|
wlan_cpu_to_le16((t_u16)num_probes);
|
|
tlv += sizeof(MrvlIEtypes_NumProbes_t);
|
|
cmd_size += sizeof(MrvlIEtypes_NumProbes_t);
|
|
}
|
|
if (bg_scan_in->rssi_threshold) {
|
|
rssi_tlv = (MrvlIEtypes_BeaconLowRssiThreshold_t *)tlv;
|
|
rssi_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_RSSI_LOW);
|
|
rssi_tlv->header.len = wlan_cpu_to_le16(
|
|
sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t) -
|
|
sizeof(MrvlIEtypesHeader_t));
|
|
rssi_tlv->value = bg_scan_in->rssi_threshold;
|
|
rssi_tlv->frequency = 0;
|
|
tlv += sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t);
|
|
cmd_size += sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t);
|
|
}
|
|
if (bg_scan_in->snr_threshold) {
|
|
snr_tlv = (MrvlIEtypes_BeaconLowSnrThreshold_t *)tlv;
|
|
snr_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_SNR_LOW);
|
|
snr_tlv->header.len = wlan_cpu_to_le16(
|
|
sizeof(MrvlIEtypes_BeaconLowSnrThreshold_t) -
|
|
sizeof(MrvlIEtypesHeader_t));
|
|
snr_tlv->value = bg_scan_in->snr_threshold;
|
|
snr_tlv->frequency = 0;
|
|
tlv += sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t);
|
|
cmd_size += sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t);
|
|
}
|
|
if (bg_scan_in->repeat_count) {
|
|
tlv_repeat = (MrvlIEtypes_RepeatCount_t *)tlv;
|
|
tlv_repeat->header.type =
|
|
wlan_cpu_to_le16(TLV_TYPE_REPEAT_COUNT);
|
|
tlv_repeat->header.len =
|
|
wlan_cpu_to_le16(sizeof(MrvlIEtypes_RepeatCount_t) -
|
|
sizeof(MrvlIEtypesHeader_t));
|
|
tlv_repeat->repeat_count =
|
|
wlan_cpu_to_le16(bg_scan_in->repeat_count);
|
|
tlv += sizeof(MrvlIEtypes_RepeatCount_t);
|
|
cmd_size += sizeof(MrvlIEtypes_RepeatCount_t);
|
|
}
|
|
for (ssid_idx = 0; ((ssid_idx < NELEMENTS(bg_scan_in->ssid_list)) &&
|
|
(*bg_scan_in->ssid_list[ssid_idx].ssid ||
|
|
bg_scan_in->ssid_list[ssid_idx].max_len));
|
|
ssid_idx++) {
|
|
ssid_len = wlan_strlen(
|
|
(char *)bg_scan_in->ssid_list[ssid_idx].ssid);
|
|
pwildcard_ssid_tlv = (MrvlIEtypes_WildCardSsIdParamSet_t *)tlv;
|
|
pwildcard_ssid_tlv->header.type =
|
|
wlan_cpu_to_le16(TLV_TYPE_WILDCARDSSID);
|
|
pwildcard_ssid_tlv->header.len = (t_u16)(
|
|
ssid_len + sizeof(pwildcard_ssid_tlv->max_ssid_length));
|
|
pwildcard_ssid_tlv->max_ssid_length =
|
|
bg_scan_in->ssid_list[ssid_idx].max_len;
|
|
memcpy_ext(pmadapter, pwildcard_ssid_tlv->ssid,
|
|
bg_scan_in->ssid_list[ssid_idx].ssid, ssid_len,
|
|
MLAN_MAX_SSID_LENGTH);
|
|
tlv += sizeof(pwildcard_ssid_tlv->header) +
|
|
pwildcard_ssid_tlv->header.len;
|
|
cmd_size += sizeof(pwildcard_ssid_tlv->header) +
|
|
pwildcard_ssid_tlv->header.len;
|
|
pwildcard_ssid_tlv->header.len =
|
|
wlan_cpu_to_le16(pwildcard_ssid_tlv->header.len);
|
|
PRINTM(MINFO, "Scan: ssid_list[%d]: %s, %d\n", ssid_idx,
|
|
pwildcard_ssid_tlv->ssid,
|
|
pwildcard_ssid_tlv->max_ssid_length);
|
|
}
|
|
if (bg_scan_in->chan_list[0].chan_number) {
|
|
tlv_chan_list = (MrvlIEtypes_ChanListParamSet_t *)tlv;
|
|
PRINTM(MINFO, "Scan: Using supplied channel list\n");
|
|
chan_num = 0;
|
|
for (chan_idx = 0; chan_idx < WLAN_BG_SCAN_CHAN_MAX &&
|
|
bg_scan_in->chan_list[chan_idx].chan_number;
|
|
chan_idx++) {
|
|
radio_type = bg_scan_in->chan_list[chan_idx].radio_type;
|
|
if (bg_scan_in->bss_type == MLAN_SCAN_MODE_IBSS ||
|
|
pmpriv->bss_mode == MLAN_BSS_MODE_IBSS)
|
|
band = pmadapter->adhoc_start_band;
|
|
else
|
|
band = pmpriv->config_bands;
|
|
if (!wlan_is_band_compatible(
|
|
band, radio_type_to_band(radio_type)))
|
|
continue;
|
|
scan_type = bg_scan_in->chan_list[chan_idx].scan_type;
|
|
/* Prevent active scanning on a radar controlled channel
|
|
*/
|
|
if (radio_type == BAND_5GHZ) {
|
|
if (wlan_11h_radar_detect_required(
|
|
pmpriv,
|
|
bg_scan_in->chan_list[chan_idx]
|
|
.chan_number)) {
|
|
scan_type = MLAN_SCAN_TYPE_PASSIVE;
|
|
}
|
|
}
|
|
if (radio_type == BAND_2GHZ) {
|
|
if (wlan_bg_scan_type_is_passive(
|
|
pmpriv,
|
|
bg_scan_in->chan_list[chan_idx]
|
|
.chan_number)) {
|
|
scan_type = MLAN_SCAN_TYPE_PASSIVE;
|
|
}
|
|
}
|
|
tlv_chan_list->chan_scan_param[chan_num].chan_number =
|
|
bg_scan_in->chan_list[chan_idx].chan_number;
|
|
tlv_chan_list->chan_scan_param[chan_num]
|
|
.bandcfg.chanBand =
|
|
bg_scan_in->chan_list[chan_idx].radio_type;
|
|
|
|
if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
|
|
tlv_chan_list->chan_scan_param[chan_num]
|
|
.chan_scan_mode.passive_scan = MTRUE;
|
|
} else {
|
|
tlv_chan_list->chan_scan_param[chan_num]
|
|
.chan_scan_mode.passive_scan = MFALSE;
|
|
}
|
|
if (bg_scan_in->chan_list[chan_idx].scan_time) {
|
|
scan_dur =
|
|
(t_u16)bg_scan_in->chan_list[chan_idx]
|
|
.scan_time;
|
|
} else {
|
|
if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
|
|
scan_dur = pmadapter->passive_scan_time;
|
|
} else {
|
|
scan_dur =
|
|
pmadapter->specific_scan_time;
|
|
}
|
|
}
|
|
tlv_chan_list->chan_scan_param[chan_num].min_scan_time =
|
|
wlan_cpu_to_le16(scan_dur);
|
|
tlv_chan_list->chan_scan_param[chan_num].max_scan_time =
|
|
wlan_cpu_to_le16(scan_dur);
|
|
chan_num++;
|
|
}
|
|
tlv_chan_list->header.type =
|
|
wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
|
|
tlv_chan_list->header.len =
|
|
wlan_cpu_to_le16(sizeof(ChanScanParamSet_t) * chan_num);
|
|
tlv += sizeof(MrvlIEtypesHeader_t) +
|
|
sizeof(ChanScanParamSet_t) * chan_num;
|
|
cmd_size += sizeof(MrvlIEtypesHeader_t) +
|
|
sizeof(ChanScanParamSet_t) * chan_num;
|
|
} else {
|
|
tlv_chan_list = (MrvlIEtypes_ChanListParamSet_t *)tlv;
|
|
chan_num = wlan_bgscan_create_channel_list(pmpriv, bg_scan_in,
|
|
tlv_chan_list);
|
|
tlv_chan_list->header.type =
|
|
wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
|
|
tlv_chan_list->header.len =
|
|
wlan_cpu_to_le16(sizeof(ChanScanParamSet_t) * chan_num);
|
|
tlv += sizeof(MrvlIEtypesHeader_t) +
|
|
sizeof(ChanScanParamSet_t) * chan_num;
|
|
cmd_size += sizeof(MrvlIEtypesHeader_t) +
|
|
sizeof(ChanScanParamSet_t) * chan_num;
|
|
}
|
|
if (bg_scan_in->chan_per_scan) {
|
|
bg_scan->chan_per_scan = bg_scan_in->chan_per_scan;
|
|
} else {
|
|
if (bg_scan_in->report_condition & BG_SCAN_WAIT_ALL_CHAN_DONE)
|
|
bg_scan->chan_per_scan = chan_num;
|
|
else
|
|
bg_scan->chan_per_scan =
|
|
MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN;
|
|
}
|
|
if (ISSUPP_11NENABLED(pmpriv->adapter->fw_cap_info) &&
|
|
(pmpriv->config_bands & BAND_GN ||
|
|
pmpriv->config_bands & BAND_AN)) {
|
|
pht_cap = (MrvlIETypes_HTCap_t *)tlv;
|
|
memset(pmadapter, pht_cap, 0, sizeof(MrvlIETypes_HTCap_t));
|
|
pht_cap->header.type = wlan_cpu_to_le16(HT_CAPABILITY);
|
|
pht_cap->header.len = sizeof(HTCap_t);
|
|
wlan_fill_ht_cap_tlv(pmpriv, pht_cap, pmpriv->config_bands,
|
|
MTRUE);
|
|
DBG_HEXDUMP(MCMD_D, "BGSCAN: HT_CAPABILITIES IE",
|
|
(t_u8 *)pht_cap, sizeof(MrvlIETypes_HTCap_t));
|
|
tlv += sizeof(MrvlIETypes_HTCap_t);
|
|
cmd_size += sizeof(MrvlIETypes_HTCap_t);
|
|
pht_cap->header.len = wlan_cpu_to_le16(pht_cap->header.len);
|
|
}
|
|
if (ISSUPP_11ACENABLED(pmpriv->adapter->fw_cap_info) &&
|
|
(pmpriv->config_bands & BAND_AAC)) {
|
|
pvht_cap = (MrvlIETypes_VHTCap_t *)tlv;
|
|
memset(pmadapter, pvht_cap, 0, sizeof(MrvlIETypes_VHTCap_t));
|
|
pvht_cap->header.type = wlan_cpu_to_le16(VHT_CAPABILITY);
|
|
pvht_cap->header.len = sizeof(VHT_capa_t);
|
|
wlan_fill_vht_cap_tlv(pmpriv, pvht_cap, pmpriv->config_bands,
|
|
MFALSE, MFALSE);
|
|
DBG_HEXDUMP(MCMD_D, "BGSCAN: VHT_CAPABILITIES IE",
|
|
(t_u8 *)pvht_cap, sizeof(MrvlIETypes_VHTCap_t));
|
|
tlv += sizeof(MrvlIETypes_VHTCap_t);
|
|
cmd_size += sizeof(MrvlIETypes_VHTCap_t);
|
|
pvht_cap->header.len = wlan_cpu_to_le16(pvht_cap->header.len);
|
|
}
|
|
|
|
if (IS_FW_SUPPORT_11AX(pmadapter) &&
|
|
(pmpriv->config_bands & BAND_AAX)) {
|
|
phe_cap = (MrvlIEtypes_Extension_t *)tlv;
|
|
len = wlan_fill_he_cap_tlv(pmpriv, BAND_A, phe_cap, MFALSE);
|
|
DBG_HEXDUMP(MCMD_D, "BGSCAN: HE_CAPABILITIES IE",
|
|
(t_u8 *)phe_cap, len);
|
|
tlv += len;
|
|
cmd_size += len;
|
|
}
|
|
if (wlan_is_ext_capa_support(pmpriv)) {
|
|
wlan_add_ext_capa_info_ie(pmpriv, MNULL, &tlv);
|
|
cmd_size += sizeof(MrvlIETypes_ExtCap_t);
|
|
}
|
|
if (pmpriv->adapter->ecsa_enable) {
|
|
t_u8 bandwidth = BW_20MHZ;
|
|
t_u8 oper_class = 1;
|
|
t_u32 usr_dot_11n_dev_cap;
|
|
if (pmpriv->media_connected) {
|
|
if (pmpriv->config_bands & BAND_A)
|
|
usr_dot_11n_dev_cap =
|
|
pmpriv->usr_dot_11n_dev_cap_a;
|
|
else
|
|
usr_dot_11n_dev_cap =
|
|
pmpriv->usr_dot_11n_dev_cap_bg;
|
|
if (usr_dot_11n_dev_cap & MBIT(17)) {
|
|
bandwidth = BW_40MHZ;
|
|
if (ISSUPP_11ACENABLED(
|
|
pmadapter->fw_cap_info) &&
|
|
(pmpriv->config_bands & BAND_AAC))
|
|
bandwidth = BW_80MHZ;
|
|
}
|
|
wlan_get_curr_oper_class(
|
|
pmpriv,
|
|
pmpriv->curr_bss_params.bss_descriptor.channel,
|
|
bandwidth, &oper_class);
|
|
}
|
|
len = wlan_add_supported_oper_class_ie(pmpriv, &tlv,
|
|
oper_class);
|
|
cmd_size += len;
|
|
}
|
|
|
|
tlv_start_later = (MrvlIEtypes_StartLater_t *)tlv;
|
|
tlv_start_later->header.type =
|
|
wlan_cpu_to_le16(TLV_TYPE_STARTBGSCANLATER);
|
|
tlv_start_later->header.len = wlan_cpu_to_le16(
|
|
sizeof(MrvlIEtypes_StartLater_t) - sizeof(MrvlIEtypesHeader_t));
|
|
tlv_start_later->value = wlan_cpu_to_le16(bg_scan_in->start_later);
|
|
tlv += sizeof(MrvlIEtypes_StartLater_t);
|
|
cmd_size += sizeof(MrvlIEtypes_StartLater_t);
|
|
|
|
if (bg_scan_in->config_ees) {
|
|
/* Fill EES configuration */
|
|
tlv_ees_cfg = (MrvlIEtypes_EESParamSet_t *)tlv;
|
|
tlv_ees_cfg->header.type = wlan_cpu_to_le16(TLV_TYPE_EES_CFG);
|
|
tlv_ees_cfg->header.len =
|
|
wlan_cpu_to_le16(sizeof(MrvlIEtypes_EESParamSet_t) -
|
|
sizeof(MrvlIEtypesHeader_t));
|
|
tlv_ees_cfg->ees_mode = wlan_cpu_to_le16(bg_scan_in->ees_mode);
|
|
tlv_ees_cfg->report_cond =
|
|
wlan_cpu_to_le16(bg_scan_in->report_cond);
|
|
tlv_ees_cfg->high_period =
|
|
wlan_cpu_to_le16(bg_scan_in->high_period);
|
|
tlv_ees_cfg->high_period_count =
|
|
wlan_cpu_to_le16(bg_scan_in->high_period_count);
|
|
tlv_ees_cfg->mid_period =
|
|
wlan_cpu_to_le16(bg_scan_in->mid_period);
|
|
tlv_ees_cfg->mid_period_count =
|
|
wlan_cpu_to_le16(bg_scan_in->mid_period_count);
|
|
tlv_ees_cfg->low_period =
|
|
wlan_cpu_to_le16(bg_scan_in->low_period);
|
|
tlv_ees_cfg->low_period_count =
|
|
wlan_cpu_to_le16(bg_scan_in->low_period_count);
|
|
tlv += sizeof(MrvlIEtypes_EESParamSet_t);
|
|
cmd_size += sizeof(MrvlIEtypes_EESParamSet_t);
|
|
|
|
if (bg_scan_in->network_count) {
|
|
/* Fill EES network configuration */
|
|
tlv_ees_net_cfg = (MrvlIEtype_EESNetworkCfg_t *)tlv;
|
|
tlv_ees_net_cfg->header.type =
|
|
wlan_cpu_to_le16(TLV_TYPE_EES_NET_CFG);
|
|
tlv_ees_net_cfg->header.len = wlan_cpu_to_le16(
|
|
sizeof(MrvlIEtype_EESNetworkCfg_t) -
|
|
sizeof(MrvlIEtypesHeader_t));
|
|
tlv_ees_net_cfg->network_count =
|
|
bg_scan_in->network_count;
|
|
tlv_ees_net_cfg->max_conn_count =
|
|
bg_scan_in->max_conn_count;
|
|
tlv_ees_net_cfg->black_list_exp =
|
|
bg_scan_in->black_list_exp;
|
|
tlv += sizeof(MrvlIEtype_EESNetworkCfg_t);
|
|
cmd_size += sizeof(MrvlIEtype_EESNetworkCfg_t);
|
|
for (index = 0; index < bg_scan_in->network_count;
|
|
index++) {
|
|
if (wlan_strlen((char *)bg_scan_in
|
|
->ees_ssid_cfg[index]
|
|
.ssid)) {
|
|
/* Fill SSID settings */
|
|
tlv_ssid =
|
|
(MrvlIEtypes_SsIdParamSet_t *)
|
|
tlv;
|
|
tlv_ssid->header.type =
|
|
wlan_cpu_to_le16(TLV_TYPE_SSID);
|
|
tlv_ssid->header.len = wlan_cpu_to_le16(
|
|
(t_u16)bg_scan_in
|
|
->ees_ssid_cfg[index]
|
|
.max_len);
|
|
memcpy_ext(
|
|
pmadapter, tlv_ssid->ssid,
|
|
bg_scan_in->ees_ssid_cfg[index]
|
|
.ssid,
|
|
bg_scan_in->ees_ssid_cfg[index]
|
|
.max_len,
|
|
MLAN_MAX_SSID_LENGTH);
|
|
tlv += sizeof(MrvlIEtypesHeader_t) +
|
|
tlv_ssid->header.len;
|
|
cmd_size +=
|
|
sizeof(MrvlIEtypesHeader_t) +
|
|
tlv_ssid->header.len;
|
|
} else {
|
|
/* Fill Wildcard SSID settings */
|
|
pwildcard_ssid_tlv =
|
|
(MrvlIEtypes_WildCardSsIdParamSet_t
|
|
*)tlv;
|
|
pwildcard_ssid_tlv->header.type =
|
|
wlan_cpu_to_le16(
|
|
TLV_TYPE_WILDCARDSSID);
|
|
pwildcard_ssid_tlv->header
|
|
.len = wlan_cpu_to_le16(
|
|
sizeof(MrvlIEtypes_WildCardSsIdParamSet_t) -
|
|
sizeof(MrvlIEtypesHeader_t));
|
|
pwildcard_ssid_tlv->max_ssid_length =
|
|
MLAN_MAX_SSID_LENGTH;
|
|
tlv += sizeof(MrvlIEtypesHeader_t) +
|
|
sizeof(pwildcard_ssid_tlv
|
|
->max_ssid_length);
|
|
cmd_size +=
|
|
sizeof(MrvlIEtypesHeader_t) +
|
|
sizeof(pwildcard_ssid_tlv
|
|
->max_ssid_length);
|
|
}
|
|
/* Fill Cipher settings */
|
|
tlv_ees_cipher = (MrvlIEtypes_Cipher_t *)tlv;
|
|
tlv_ees_cipher->header.type =
|
|
wlan_cpu_to_le16(TLV_TYPE_CIPHER);
|
|
tlv_ees_cipher->header.len = wlan_cpu_to_le16(
|
|
sizeof(MrvlIEtypes_Cipher_t) -
|
|
sizeof(MrvlIEtypesHeader_t));
|
|
tlv_ees_cipher->pair_cipher =
|
|
bg_scan_in->ees_ssid_cfg[index]
|
|
.pair_cipher;
|
|
tlv_ees_cipher->group_cipher =
|
|
bg_scan_in->ees_ssid_cfg[index]
|
|
.group_cipher;
|
|
tlv += sizeof(MrvlIEtypes_Cipher_t);
|
|
cmd_size += sizeof(MrvlIEtypes_Cipher_t);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (memcmp(pmadapter, bg_scan_in->random_mac, zero_mac,
|
|
MLAN_MAC_ADDR_LENGTH)) {
|
|
MrvlIEtypes_MacAddr_t *randomMacParam =
|
|
(MrvlIEtypes_MacAddr_t *)tlv;
|
|
memset(pmadapter, randomMacParam, 0,
|
|
sizeof(MrvlIEtypes_MacAddr_t));
|
|
randomMacParam->header.type =
|
|
wlan_cpu_to_le16(TLV_TYPE_RANDOM_MAC);
|
|
randomMacParam->header.len =
|
|
wlan_cpu_to_le16(MLAN_MAC_ADDR_LENGTH);
|
|
memcpy_ext(pmadapter, randomMacParam->mac,
|
|
bg_scan_in->random_mac, MLAN_MAC_ADDR_LENGTH,
|
|
MLAN_MAC_ADDR_LENGTH);
|
|
tlv += sizeof(MrvlIEtypes_MacAddr_t);
|
|
cmd_size += sizeof(MrvlIEtypes_MacAddr_t);
|
|
}
|
|
done:
|
|
pcmd->size = wlan_cpu_to_le16(cmd_size);
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function handles the command response of extended scan
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @param resp A pointer to HostCmd_DS_COMMAND
|
|
* @param pioctl_buf A pointer to mlan_ioctl_req structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status wlan_ret_bgscan_config(mlan_private *pmpriv,
|
|
HostCmd_DS_COMMAND *resp,
|
|
mlan_ioctl_req *pioctl_buf)
|
|
{
|
|
mlan_ds_scan *pscan = MNULL;
|
|
HostCmd_DS_802_11_BG_SCAN_CONFIG *bg_scan =
|
|
&resp->params.bg_scan_config;
|
|
wlan_bgscan_cfg *bg_scan_out = MNULL;
|
|
|
|
ENTER();
|
|
if (pioctl_buf) {
|
|
pscan = (mlan_ds_scan *)pioctl_buf->pbuf;
|
|
bg_scan_out =
|
|
(wlan_bgscan_cfg *)pscan->param.user_scan.scan_cfg_buf;
|
|
bg_scan_out->action = wlan_le16_to_cpu(bg_scan->action);
|
|
if ((bg_scan_out->action == BG_SCAN_ACT_GET) ||
|
|
(bg_scan_out->action == BG_SCAN_ACT_GET_PPS_UAPSD)) {
|
|
bg_scan_out->enable = bg_scan->enable;
|
|
bg_scan_out->bss_type = bg_scan->bss_type;
|
|
bg_scan_out->chan_per_scan = bg_scan->chan_per_scan;
|
|
bg_scan_out->scan_interval =
|
|
wlan_le32_to_cpu(bg_scan->scan_interval);
|
|
bg_scan_out->report_condition =
|
|
wlan_le32_to_cpu(bg_scan->report_condition);
|
|
pioctl_buf->data_read_written =
|
|
sizeof(mlan_ds_scan) + MLAN_SUB_COMMAND_SIZE;
|
|
}
|
|
}
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function handles the command response of bgscan_query
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @param resp A pointer to HostCmd_DS_COMMAND
|
|
* @param pioctl_buf A pointer to mlan_ioctl_req structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status wlan_ret_802_11_bgscan_query(mlan_private *pmpriv,
|
|
HostCmd_DS_COMMAND *resp,
|
|
mlan_ioctl_req *pioctl_buf)
|
|
{
|
|
mlan_ds_scan *pscan = MNULL;
|
|
mlan_adapter *pmadapter = pmpriv->adapter;
|
|
t_u8 i;
|
|
ENTER();
|
|
for (i = 0; i < pmadapter->num_in_chan_stats; i++)
|
|
pmadapter->pchan_stats[i].cca_scan_duration = 0;
|
|
pmadapter->idx_chan_stats = 0;
|
|
|
|
wlan_ret_802_11_scan(pmpriv, resp, MNULL);
|
|
if (pioctl_buf) {
|
|
pscan = (mlan_ds_scan *)pioctl_buf->pbuf;
|
|
pscan->param.scan_resp.pscan_table =
|
|
(t_u8 *)pmadapter->pscan_table;
|
|
pscan->param.scan_resp.num_in_scan_table =
|
|
pmadapter->num_in_scan_table;
|
|
pscan->param.scan_resp.age_in_secs = pmadapter->age_in_secs;
|
|
pscan->param.scan_resp.pchan_stats =
|
|
(t_u8 *)pmadapter->pchan_stats;
|
|
pscan->param.scan_resp.num_in_chan_stats =
|
|
pmadapter->num_in_chan_stats;
|
|
|
|
pioctl_buf->data_read_written =
|
|
sizeof(mlan_scan_resp) + MLAN_SUB_COMMAND_SIZE;
|
|
}
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function finds ssid in ssid list.
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @param ssid SSID to find in the list
|
|
* @param bssid BSSID to qualify the SSID selection (if provided)
|
|
* @param mode Network mode: Infrastructure or IBSS
|
|
*
|
|
* @return index in BSSID list or < 0 if error
|
|
*/
|
|
t_s32 wlan_find_ssid_in_list(mlan_private *pmpriv, mlan_802_11_ssid *ssid,
|
|
t_u8 *bssid, t_u32 mode)
|
|
{
|
|
mlan_adapter *pmadapter = pmpriv->adapter;
|
|
t_s32 net = -1, j;
|
|
t_u8 best_rssi = 0;
|
|
t_u32 i;
|
|
|
|
ENTER();
|
|
PRINTM(MINFO, "Num of entries in scan table = %d\n",
|
|
pmadapter->num_in_scan_table);
|
|
|
|
/*
|
|
* Loop through the table until the maximum is reached or until a match
|
|
* is found based on the bssid field comparison
|
|
*/
|
|
for (i = 0;
|
|
i < pmadapter->num_in_scan_table && (!bssid || (bssid && net < 0));
|
|
i++) {
|
|
if (!wlan_ssid_cmp(pmadapter, &pmadapter->pscan_table[i].ssid,
|
|
ssid) &&
|
|
(!bssid ||
|
|
!memcmp(pmadapter, pmadapter->pscan_table[i].mac_address,
|
|
bssid, MLAN_MAC_ADDR_LENGTH))) {
|
|
if ((mode == MLAN_BSS_MODE_INFRA) &&
|
|
!wlan_is_band_compatible(
|
|
pmpriv->config_bands,
|
|
pmadapter->pscan_table[i].bss_band))
|
|
continue;
|
|
|
|
switch (mode) {
|
|
case MLAN_BSS_MODE_INFRA:
|
|
case MLAN_BSS_MODE_IBSS:
|
|
j = wlan_is_network_compatible(pmpriv, i, mode);
|
|
|
|
if (j >= 0) {
|
|
if (SCAN_RSSI(pmadapter->pscan_table[i]
|
|
.rssi) >
|
|
best_rssi) {
|
|
best_rssi = SCAN_RSSI(
|
|
pmadapter
|
|
->pscan_table[i]
|
|
.rssi);
|
|
net = i;
|
|
}
|
|
} else {
|
|
if (net == -1)
|
|
net = j;
|
|
}
|
|
break;
|
|
case MLAN_BSS_MODE_AUTO:
|
|
default:
|
|
/*
|
|
* Do not check compatibility if the mode
|
|
* requested is Auto/Unknown. Allows generic
|
|
* find to work without verifying against the
|
|
* Adapter security settings
|
|
*/
|
|
if (SCAN_RSSI(pmadapter->pscan_table[i].rssi) >
|
|
best_rssi) {
|
|
best_rssi = SCAN_RSSI(
|
|
pmadapter->pscan_table[i].rssi);
|
|
net = i;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
LEAVE();
|
|
return net;
|
|
}
|
|
|
|
/**
|
|
* @brief This function finds a specific compatible BSSID in the scan list
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @param bssid BSSID to find in the scan list
|
|
* @param mode Network mode: Infrastructure or IBSS
|
|
*
|
|
* @return index in BSSID list or < 0 if error
|
|
*/
|
|
t_s32 wlan_find_bssid_in_list(mlan_private *pmpriv, t_u8 *bssid, t_u32 mode)
|
|
{
|
|
mlan_adapter *pmadapter = pmpriv->adapter;
|
|
t_s32 net = -1;
|
|
t_u32 i;
|
|
|
|
ENTER();
|
|
|
|
if (!bssid) {
|
|
LEAVE();
|
|
return -1;
|
|
}
|
|
|
|
PRINTM(MINFO, "FindBSSID: Num of BSSIDs = %d\n",
|
|
pmadapter->num_in_scan_table);
|
|
|
|
/*
|
|
* Look through the scan table for a compatible match. The ret return
|
|
* variable will be equal to the index in the scan table (greater
|
|
* than zero) if the network is compatible. The loop will continue
|
|
* past a matched bssid that is not compatible in case there is an
|
|
* AP with multiple SSIDs assigned to the same BSSID
|
|
*/
|
|
for (i = 0; net < 0 && i < pmadapter->num_in_scan_table; i++) {
|
|
if (!memcmp(pmadapter, pmadapter->pscan_table[i].mac_address,
|
|
bssid, MLAN_MAC_ADDR_LENGTH)) {
|
|
if ((mode == MLAN_BSS_MODE_INFRA) &&
|
|
!wlan_is_band_compatible(
|
|
pmpriv->config_bands,
|
|
pmadapter->pscan_table[i].bss_band))
|
|
continue;
|
|
switch (mode) {
|
|
case MLAN_BSS_MODE_INFRA:
|
|
case MLAN_BSS_MODE_IBSS:
|
|
net = wlan_is_network_compatible(pmpriv, i,
|
|
mode);
|
|
break;
|
|
default:
|
|
net = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
LEAVE();
|
|
return net;
|
|
}
|
|
|
|
/**
|
|
* @brief Compare two SSIDs
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param ssid1 A pointer to ssid to compare
|
|
* @param ssid2 A pointer to ssid to compare
|
|
*
|
|
* @return 0--ssid is same, otherwise is different
|
|
*/
|
|
t_s32 wlan_ssid_cmp(pmlan_adapter pmadapter, mlan_802_11_ssid *ssid1,
|
|
mlan_802_11_ssid *ssid2)
|
|
{
|
|
ENTER();
|
|
|
|
if (!ssid1 || !ssid2) {
|
|
LEAVE();
|
|
return -1;
|
|
}
|
|
|
|
if (ssid1->ssid_len != ssid2->ssid_len) {
|
|
LEAVE();
|
|
return -1;
|
|
}
|
|
|
|
LEAVE();
|
|
return memcmp(pmadapter, ssid1->ssid, ssid2->ssid, ssid1->ssid_len);
|
|
}
|
|
|
|
/**
|
|
* @brief Find the AP with specific ssid in the scan list
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @param preq_ssid_bssid A pointer to AP's ssid returned
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS--success, otherwise--fail
|
|
*/
|
|
mlan_status wlan_find_best_network(mlan_private *pmpriv,
|
|
mlan_ssid_bssid *preq_ssid_bssid)
|
|
{
|
|
mlan_adapter *pmadapter = pmpriv->adapter;
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
BSSDescriptor_t *preq_bss;
|
|
t_s32 i;
|
|
|
|
ENTER();
|
|
|
|
memset(pmadapter, preq_ssid_bssid, 0, sizeof(mlan_ssid_bssid));
|
|
|
|
i = wlan_find_best_network_in_list(pmpriv);
|
|
|
|
if (i >= 0) {
|
|
preq_bss = &pmadapter->pscan_table[i];
|
|
memcpy_ext(pmadapter, &preq_ssid_bssid->ssid, &preq_bss->ssid,
|
|
sizeof(mlan_802_11_ssid),
|
|
sizeof(preq_ssid_bssid->ssid));
|
|
memcpy_ext(pmadapter, (t_u8 *)&preq_ssid_bssid->bssid,
|
|
(t_u8 *)&preq_bss->mac_address, MLAN_MAC_ADDR_LENGTH,
|
|
MLAN_MAC_ADDR_LENGTH);
|
|
|
|
/* Make sure we are in the right mode */
|
|
if (pmpriv->bss_mode == MLAN_BSS_MODE_AUTO)
|
|
pmpriv->bss_mode = preq_bss->bss_mode;
|
|
preq_ssid_bssid->channel = (t_u16)preq_bss->channel;
|
|
if (preq_bss->pmd_ie &&
|
|
wlan_ft_akm_is_used(pmpriv, (t_u8 *)preq_bss->prsn_ie)) {
|
|
preq_ssid_bssid->ft_md = preq_bss->pmd_ie->mdid;
|
|
preq_ssid_bssid->ft_cap = preq_bss->pmd_ie->ft_cap;
|
|
}
|
|
preq_ssid_bssid->bss_band = preq_bss->bss_band;
|
|
preq_ssid_bssid->idx = i + 1;
|
|
}
|
|
|
|
if (!preq_ssid_bssid->ssid.ssid_len) {
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
PRINTM(MINFO,
|
|
"Best network found = [%s], "
|
|
"[" MACSTR "]\n",
|
|
preq_ssid_bssid->ssid.ssid, MAC2STR(preq_ssid_bssid->bssid));
|
|
|
|
done:
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Send a scan command for all available channels filtered on a spec
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @param pioctl_buf A pointer to MLAN IOCTL Request buffer
|
|
* @param preq_ssid A pointer to AP's ssid returned
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS--success, otherwise--fail
|
|
*/
|
|
mlan_status wlan_scan_specific_ssid(mlan_private *pmpriv, t_void *pioctl_buf,
|
|
mlan_802_11_ssid *preq_ssid)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
mlan_callbacks *pcb = (mlan_callbacks *)&pmpriv->adapter->callbacks;
|
|
wlan_user_scan_cfg *pscan_cfg;
|
|
pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *)pioctl_buf;
|
|
|
|
ENTER();
|
|
|
|
if (!preq_ssid) {
|
|
if (pioctl_req)
|
|
pioctl_req->status_code = MLAN_ERROR_CMD_SCAN_FAIL;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
wlan_scan_delete_ssid_table_entry(pmpriv, preq_ssid);
|
|
|
|
ret = pcb->moal_malloc(pmpriv->adapter->pmoal_handle,
|
|
sizeof(wlan_user_scan_cfg), MLAN_MEM_DEF,
|
|
(t_u8 **)&pscan_cfg);
|
|
|
|
if (ret != MLAN_STATUS_SUCCESS || !pscan_cfg) {
|
|
PRINTM(MERROR, "Memory allocation for pscan_cfg failed!\n");
|
|
if (pioctl_req)
|
|
pioctl_req->status_code = MLAN_ERROR_NO_MEM;
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
memset(pmpriv->adapter, pscan_cfg, 0x00, sizeof(wlan_user_scan_cfg));
|
|
|
|
memcpy_ext(pmpriv->adapter, pscan_cfg->ssid_list[0].ssid,
|
|
preq_ssid->ssid, preq_ssid->ssid_len, MLAN_MAX_SSID_LENGTH);
|
|
pscan_cfg->keep_previous_scan = MFALSE;
|
|
|
|
ret = wlan_scan_networks(pmpriv, pioctl_buf, pscan_cfg);
|
|
|
|
if (pscan_cfg)
|
|
pcb->moal_mfree(pmpriv->adapter->pmoal_handle,
|
|
(t_u8 *)pscan_cfg);
|
|
|
|
done:
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Save a beacon buffer of the current bss descriptor
|
|
* Save the current beacon buffer to restore in the following cases that
|
|
* makes the bcn_buf not to contain the current ssid's beacon buffer.
|
|
* - the current ssid was not found somehow in the last scan.
|
|
* - the current ssid was the last entry of the scan table and overloaded.
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
*
|
|
* @return N/A
|
|
*/
|
|
t_void wlan_save_curr_bcn(mlan_private *pmpriv)
|
|
{
|
|
mlan_adapter *pmadapter = pmpriv->adapter;
|
|
mlan_callbacks *pcb = (pmlan_callbacks)&pmadapter->callbacks;
|
|
BSSDescriptor_t *pcurr_bss = &pmpriv->curr_bss_params.bss_descriptor;
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
|
|
ENTER();
|
|
pcb->moal_spin_lock(pmadapter->pmoal_handle, pmpriv->curr_bcn_buf_lock);
|
|
/* save the beacon buffer if it is not saved or updated */
|
|
if ((pmpriv->pcurr_bcn_buf == MNULL) ||
|
|
(pmpriv->curr_bcn_size != pcurr_bss->beacon_buf_size) ||
|
|
(memcmp(pmpriv->adapter, pmpriv->pcurr_bcn_buf,
|
|
pcurr_bss->pbeacon_buf, pcurr_bss->beacon_buf_size))) {
|
|
if (pmpriv->pcurr_bcn_buf) {
|
|
pcb->moal_mfree(pmadapter->pmoal_handle,
|
|
pmpriv->pcurr_bcn_buf);
|
|
pmpriv->pcurr_bcn_buf = MNULL;
|
|
}
|
|
pmpriv->curr_bcn_size = pcurr_bss->beacon_buf_size;
|
|
|
|
if (pmpriv->curr_bcn_size) {
|
|
ret = pcb->moal_malloc(pmadapter->pmoal_handle,
|
|
pcurr_bss->beacon_buf_size,
|
|
MLAN_MEM_DEF,
|
|
&pmpriv->pcurr_bcn_buf);
|
|
|
|
if ((ret == MLAN_STATUS_SUCCESS) &&
|
|
pmpriv->pcurr_bcn_buf) {
|
|
memcpy_ext(pmpriv->adapter,
|
|
pmpriv->pcurr_bcn_buf,
|
|
pcurr_bss->pbeacon_buf,
|
|
pcurr_bss->beacon_buf_size,
|
|
pcurr_bss->beacon_buf_size);
|
|
PRINTM(MINFO, "current beacon saved %d\n",
|
|
pmpriv->curr_bcn_size);
|
|
} else {
|
|
PRINTM(MERROR,
|
|
"Fail to allocate curr_bcn_buf\n");
|
|
}
|
|
}
|
|
}
|
|
wlan_update_curr_bcn(pmpriv);
|
|
pcb->moal_spin_unlock(pmadapter->pmoal_handle,
|
|
pmpriv->curr_bcn_buf_lock);
|
|
|
|
LEAVE();
|
|
}
|
|
|
|
/**
|
|
* @brief Free a beacon buffer of the current bss descriptor
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
*
|
|
* @return N/A
|
|
*/
|
|
t_void wlan_free_curr_bcn(mlan_private *pmpriv)
|
|
{
|
|
mlan_adapter *pmadapter = pmpriv->adapter;
|
|
mlan_callbacks *pcb = (pmlan_callbacks)&pmadapter->callbacks;
|
|
|
|
ENTER();
|
|
if (pmpriv->pcurr_bcn_buf) {
|
|
pcb->moal_mfree(pmadapter->pmoal_handle, pmpriv->pcurr_bcn_buf);
|
|
pmpriv->pcurr_bcn_buf = MNULL;
|
|
}
|
|
LEAVE();
|
|
}
|