mirror of
https://github.com/nxp-imx/mwifiex.git
synced 2024-10-31 21:15:22 +00:00
6317 lines
192 KiB
C
6317 lines
192 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 (C) 2008-2019, Marvell International Ltd.
|
||
|
*
|
||
|
* This software file (the "File") is distributed by Marvell International
|
||
|
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
||
|
* (the "License"). You may use, redistribute and/or modify this 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_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 40
|
||
|
/** 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))
|
||
|
|
||
|
/** 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 \
|
||
|
+ 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_oui[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
|
||
|
*/
|
||
|
void
|
||
|
wlan_update_chan_statistics(mlan_private *pmpriv,
|
||
|
MrvlIEtypes_ChannelStats_t *pchanstats_tlv)
|
||
|
{
|
||
|
mlan_adapter *pmadapter = pmpriv->adapter;
|
||
|
t_u8 i;
|
||
|
ChanStatistics_t *pchan_stats =
|
||
|
(ChanStatistics_t *)((t_u8 *)pchanstats_tlv +
|
||
|
sizeof(MrvlIEtypesHeader_t));
|
||
|
t_u8 num_chan =
|
||
|
wlan_le16_to_cpu(pchanstats_tlv->header.len) /
|
||
|
sizeof(ChanStatistics_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(pmadapter,
|
||
|
&pmadapter->pchan_stats[pmadapter->idx_chan_stats],
|
||
|
pchan_stats, sizeof(ChanStatistics_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))) {
|
||
|
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 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_oui[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(IN 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(IN mlan_private *pmpriv,
|
||
|
IN const wlan_user_scan_cfg *puser_scan_in,
|
||
|
OUT ChanScanParamSet_t *pscan_chan_list,
|
||
|
IN 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;
|
||
|
}
|
||
|
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++, chan_idx++) {
|
||
|
/* 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;
|
||
|
|
||
|
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_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(MINFO,
|
||
|
"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);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LEAVE();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief This function prepares command of sending acs.
|
||
|
*
|
||
|
* @param cmd A pointer to HostCmd_DS_COMMAND structure
|
||
|
* @param cmd_action the action: GET or SET
|
||
|
* @param pdata_buf A pointer to data buffer
|
||
|
* @return MLAN_STATUS_SUCCESS
|
||
|
*/
|
||
|
mlan_status
|
||
|
wlan_cmd_acs(IN pmlan_private pmpriv,
|
||
|
IN HostCmd_DS_COMMAND *cmd,
|
||
|
IN t_u16 cmd_action, IN t_void *pdata_buf)
|
||
|
{
|
||
|
mlan_adapter *pmadapter = pmpriv->adapter;
|
||
|
mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks;
|
||
|
mlan_ds_misc_acs *acs_param = (mlan_ds_misc_acs *) pdata_buf;
|
||
|
HostCmd_DS_ACS *acs_cmd = (HostCmd_DS_ACS *) & cmd->params.acs;
|
||
|
t_u8 *ptlv_pos = MNULL;
|
||
|
MrvlIEtypes_ChanListParamSet_t *pchanlist_tlv = MNULL;
|
||
|
MrvlIEtypes_ScanChanGap_t *pscangap_tlv = MNULL;
|
||
|
t_u32 buf_size = 0;
|
||
|
ChanScanParamSet_t *pscan_chan_list = MNULL;
|
||
|
t_u32 i = 0;
|
||
|
t_u32 scan_type = 0;
|
||
|
t_u16 scan_dur = 0;
|
||
|
mlan_status status = MLAN_STATUS_SUCCESS;
|
||
|
|
||
|
ENTER();
|
||
|
|
||
|
cmd->command = wlan_cpu_to_le16(HostCmd_CMD_ACS);
|
||
|
cmd->size = sizeof(HostCmd_DS_ACS) + S_DS_GEN;
|
||
|
|
||
|
buf_size = sizeof(ChanScanParamSet_t) * WLAN_USER_SCAN_CHAN_MAX;
|
||
|
status = pcb->moal_malloc(pmadapter->pmoal_handle, buf_size,
|
||
|
MLAN_MEM_DEF, (t_u8 **)&pscan_chan_list);
|
||
|
if (status != MLAN_STATUS_SUCCESS || !pscan_chan_list) {
|
||
|
PRINTM(MERROR,
|
||
|
"wlan_cmd_acs: Failed to allocate scan_chan_list\n");
|
||
|
goto done;
|
||
|
}
|
||
|
memset(pmadapter, pscan_chan_list, 0x00, buf_size);
|
||
|
|
||
|
/** Prepare channel list, we will use it to fill into MrvlIEtypes_ChanListParamSet_t */
|
||
|
if (acs_param->ch_stats_num) {
|
||
|
PRINTM(MCMND, "ACS using user specified channels\n");
|
||
|
for (i = 0; i < MIN(MAX_CH_STATS, acs_param->ch_stats_num); i++) {
|
||
|
if (!acs_param->ch_stats[i].chan_num)
|
||
|
continue;
|
||
|
|
||
|
/** Set the fields in pscan_chan_list */
|
||
|
/** Set chan_number */
|
||
|
pscan_chan_list[i].chan_number =
|
||
|
acs_param->ch_stats[i].chan_num;
|
||
|
|
||
|
/** Set bandcfg */
|
||
|
if (acs_param->ch_stats[i].chan_num <= 14)
|
||
|
pscan_chan_list[i].bandcfg.chanBand = BAND_2GHZ;
|
||
|
else
|
||
|
pscan_chan_list[i].bandcfg.chanBand = BAND_5GHZ;
|
||
|
if (pscan_chan_list[i].bandcfg.chanBand == BAND_5GHZ) {
|
||
|
if (pmadapter->fw_bands & BAND_A)
|
||
|
PRINTM(MINFO,
|
||
|
"UserScan request for A Band channel %d!!\n",
|
||
|
pscan_chan_list[i].chan_number);
|
||
|
else {
|
||
|
PRINTM(MERROR,
|
||
|
"Scan in A band is not allowed!!\n");
|
||
|
status = MLAN_STATUS_FAILURE;
|
||
|
goto done;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** Set chan_scan_mode */
|
||
|
scan_type = pmadapter->scan_type;
|
||
|
/** Prevent active scanning on a radar controlled channel */
|
||
|
if (pscan_chan_list[i].bandcfg.chanBand == BAND_5GHZ) {
|
||
|
if (pmadapter->active_scan_triggered == MFALSE)
|
||
|
if (wlan_11h_radar_detect_required
|
||
|
(pmpriv,
|
||
|
pscan_chan_list[i].chan_number))
|
||
|
scan_type =
|
||
|
MLAN_SCAN_TYPE_PASSIVE;
|
||
|
}
|
||
|
if (pscan_chan_list[i].bandcfg.chanBand == BAND_2GHZ) {
|
||
|
if (pmadapter->active_scan_triggered == MFALSE)
|
||
|
if (wlan_bg_scan_type_is_passive
|
||
|
(pmpriv,
|
||
|
pscan_chan_list[i].chan_number))
|
||
|
scan_type =
|
||
|
MLAN_SCAN_TYPE_PASSIVE;
|
||
|
}
|
||
|
if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
|
||
|
pscan_chan_list[i].chan_scan_mode.passive_scan =
|
||
|
MTRUE;
|
||
|
pscan_chan_list[i].chan_scan_mode.
|
||
|
hidden_ssid_report = MTRUE;
|
||
|
} else
|
||
|
pscan_chan_list[i].chan_scan_mode.passive_scan =
|
||
|
MFALSE;
|
||
|
|
||
|
/** Set min_scan_time & max_scan_time */
|
||
|
if (scan_type == MLAN_SCAN_TYPE_PASSIVE)
|
||
|
scan_dur = pmadapter->passive_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;
|
||
|
pscan_chan_list[i].min_scan_time =
|
||
|
wlan_cpu_to_le16(scan_dur);
|
||
|
pscan_chan_list[i].max_scan_time =
|
||
|
wlan_cpu_to_le16(scan_dur);
|
||
|
}
|
||
|
} else {
|
||
|
PRINTM(MCMND, "ACS using full region channel list\n");
|
||
|
wlan_scan_create_channel_list(pmpriv, MNULL, pscan_chan_list,
|
||
|
MFALSE);
|
||
|
}
|
||
|
|
||
|
ptlv_pos = acs_cmd->tlv_buffer;
|
||
|
|
||
|
if (!pscan_chan_list[0].chan_number) {
|
||
|
PRINTM(MERROR, "No valid chan_number in pscan_chan_list\n");
|
||
|
status = MLAN_STATUS_FAILURE;
|
||
|
goto done;
|
||
|
}
|
||
|
pchanlist_tlv = (MrvlIEtypes_ChanListParamSet_t *)ptlv_pos;
|
||
|
pchanlist_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
|
||
|
pchanlist_tlv->header.len = 0;
|
||
|
PRINTM(MCMND, "--- pscan_chan_list ---\n");
|
||
|
for (i = 0;
|
||
|
i < WLAN_USER_SCAN_CHAN_MAX && pscan_chan_list[i].chan_number;
|
||
|
i++) {
|
||
|
memcpy(pmadapter, &(pchanlist_tlv->chan_scan_param[i]),
|
||
|
&(pscan_chan_list[i]), sizeof(ChanScanParamSet_t));
|
||
|
pchanlist_tlv->header.len += sizeof(ChanScanParamSet_t);
|
||
|
PRINTM(MCMND,
|
||
|
"[%d] chan_number=%d bandcfg=0x%x chan_scan_mode=0x%x scan_time=%d~%d\n",
|
||
|
i, pscan_chan_list[i].chan_number,
|
||
|
pscan_chan_list[i].bandcfg,
|
||
|
pscan_chan_list[i].chan_scan_mode,
|
||
|
pscan_chan_list[i].min_scan_time,
|
||
|
pscan_chan_list[i].max_scan_time);
|
||
|
}
|
||
|
ptlv_pos += sizeof(pchanlist_tlv->header) + pchanlist_tlv->header.len;
|
||
|
pchanlist_tlv->header.len = wlan_cpu_to_le16(pchanlist_tlv->header.len);
|
||
|
|
||
|
pscangap_tlv = (MrvlIEtypes_ScanChanGap_t *)ptlv_pos;
|
||
|
pscangap_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_SCAN_CHANNEL_GAP);
|
||
|
pscangap_tlv->header.len = sizeof(pscangap_tlv->gap);
|
||
|
pscangap_tlv->gap = wlan_cpu_to_le16(acs_param->scan_chan_gap);
|
||
|
ptlv_pos += sizeof(pscangap_tlv->header) + pscangap_tlv->header.len;
|
||
|
pscangap_tlv->header.len = wlan_cpu_to_le16(pscangap_tlv->header.len);
|
||
|
|
||
|
cmd->size += ptlv_pos - acs_cmd->tlv_buffer;
|
||
|
cmd->size = wlan_cpu_to_le16(cmd->size);
|
||
|
|
||
|
done:
|
||
|
if (pscan_chan_list)
|
||
|
pcb->moal_mfree(pmadapter->pmoal_handle,
|
||
|
(t_u8 *)pscan_chan_list);
|
||
|
LEAVE();
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief This function handles the command response of acs
|
||
|
*
|
||
|
* @param pmpriv A pointer to mlan_private structure
|
||
|
* @param resp A pointer to HostCmd_DS_COMMAND
|
||
|
* @param pioctl_buf A pointer to command buffer
|
||
|
*
|
||
|
* @return MLAN_STATUS_SUCCESS
|
||
|
*/
|
||
|
mlan_status
|
||
|
wlan_ret_acs(IN pmlan_private pmpriv,
|
||
|
IN HostCmd_DS_COMMAND *resp, IN mlan_ioctl_req *pioctl_buf)
|
||
|
{
|
||
|
mlan_ds_misc_cfg *cfg = MNULL;
|
||
|
mlan_ds_misc_acs *acs_param = MNULL;
|
||
|
HostCmd_DS_ACS *acs_cmd = (HostCmd_DS_ACS *) & resp->params.acs;
|
||
|
int left_len = resp->size;
|
||
|
t_u8 *tlv_pos = MNULL;
|
||
|
MrvlIEtypesHeader_t *tlv_ie = MNULL;
|
||
|
MrvlIEtypes_ChannelStats_t *tlv_ch_stats = MNULL;
|
||
|
ChanStatistics_t *ch_stats = MNULL;
|
||
|
int ch_stats_num = 0;
|
||
|
int i = 0;
|
||
|
t_u16 tlv_id = 0;
|
||
|
int tlv_ie_len = 0;
|
||
|
|
||
|
ENTER();
|
||
|
|
||
|
if (pioctl_buf) {
|
||
|
cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
|
||
|
acs_param = &cfg->param.acs;
|
||
|
memset(pmpriv->adapter, acs_param, 0x00, sizeof(*acs_param));
|
||
|
acs_param->best_ch = acs_cmd->best_ch;
|
||
|
|
||
|
left_len -= S_DS_GEN + sizeof(HostCmd_DS_ACS);
|
||
|
tlv_pos = acs_cmd->tlv_buffer;
|
||
|
while (left_len > sizeof(MrvlIEtypesHeader_t)) {
|
||
|
tlv_ie = (MrvlIEtypesHeader_t *)(tlv_pos);
|
||
|
tlv_id = wlan_le16_to_cpu(tlv_ie->type);
|
||
|
tlv_ie_len = wlan_le16_to_cpu(tlv_ie->len);
|
||
|
PRINTM(MCMND, "[TLV: id=0x%x len=%d] left_len=%d\n",
|
||
|
tlv_id, tlv_ie_len, left_len);
|
||
|
if ((tlv_id == TLV_TYPE_CHANNEL_STATS) &&
|
||
|
(tlv_ie_len >= sizeof(ChanStatistics_t))) {
|
||
|
tlv_ch_stats =
|
||
|
(MrvlIEtypes_ChannelStats_t *)tlv_ie;
|
||
|
ch_stats = tlv_ch_stats->chanStat;
|
||
|
ch_stats_num =
|
||
|
tlv_ie_len / sizeof(ChanStatistics_t);
|
||
|
for (i = 0; i < MIN(ch_stats_num, MAX_CH_STATS);
|
||
|
i++) {
|
||
|
if (ch_stats[i].chan_num) {
|
||
|
acs_param->ch_stats[i].
|
||
|
chan_num =
|
||
|
ch_stats[i].chan_num;
|
||
|
acs_param->ch_stats[i].
|
||
|
total_networks =
|
||
|
wlan_le16_to_cpu
|
||
|
(ch_stats[i].
|
||
|
total_networks);
|
||
|
acs_param->ch_stats[i].
|
||
|
cca_busy_duration =
|
||
|
wlan_le16_to_cpu
|
||
|
(ch_stats[i].
|
||
|
cca_busy_duration);
|
||
|
acs_param->ch_stats_num++;
|
||
|
}
|
||
|
}
|
||
|
if (acs_param->ch_stats_num)
|
||
|
break;
|
||
|
}
|
||
|
left_len -= sizeof(*tlv_ie) + tlv_ie_len;
|
||
|
tlv_pos += sizeof(*tlv_ie) + tlv_ie_len;
|
||
|
}
|
||
|
|
||
|
/* Indicate ioctl complete */
|
||
|
pioctl_buf->data_read_written = sizeof(*acs_param);
|
||
|
}
|
||
|
|
||
|
LEAVE();
|
||
|
return MLAN_STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @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(IN mlan_private *pmpriv, OUT 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(pmpriv->adapter, *pptlv_out,
|
||
|
pmpriv->wps.wps_ie.vend_hdr.oui,
|
||
|
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(IN mlan_private *pmpriv,
|
||
|
IN t_void *pioctl_buf,
|
||
|
IN t_u32 max_chan_per_scan,
|
||
|
IN t_u8 filtered_scan,
|
||
|
OUT wlan_scan_cmd_config *pscan_cfg_out,
|
||
|
OUT MrvlIEtypes_ChanListParamSet_t *pchan_tlv_out,
|
||
|
IN 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)) {
|
||
|
ptmp_chan_list++;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (first_chan) {
|
||
|
ptmp_chan_list->chan_scan_mode.first_chan =
|
||
|
MTRUE;
|
||
|
first_chan = 0;
|
||
|
}
|
||
|
|
||
|
PRINTM(MINFO,
|
||
|
"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(pmadapter,
|
||
|
pscan_cfg_out->tlv_buf,
|
||
|
ptlv_temp, 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(pmadapter, ptlv_temp, ptlv_pos,
|
||
|
tlv_buf_len);
|
||
|
|
||
|
/* 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(pmadapter,
|
||
|
pchan_tlv_out->chan_scan_param + tlv_idx,
|
||
|
ptmp_chan_list,
|
||
|
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 ||
|
||
|
!total_scan_time || !pchan_tlv_out->header.len) {
|
||
|
PRINTM(MMSG,
|
||
|
"Total scan time %d ms, limit (%d ms), chan tlv len=%d scan skipped\n",
|
||
|
total_scan_time, MRVDRV_MAX_TOTAL_SCAN_TIME,
|
||
|
pchan_tlv_out->header.len);
|
||
|
|
||
|
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)
|
||
|
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(IN mlan_private *pmpriv,
|
||
|
IN wlan_user_scan_cfg *puser_scan_in,
|
||
|
OUT wlan_scan_cmd_config *pscan_cfg_out,
|
||
|
OUT MrvlIEtypes_ChanListParamSet_t
|
||
|
**ppchan_list_out,
|
||
|
OUT ChanScanParamSet_t *pscan_chan_list,
|
||
|
OUT t_u8 *pmax_chan_per_scan,
|
||
|
OUT t_u8 *pfiltered_scan,
|
||
|
OUT 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;
|
||
|
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(pmadapter, pscan_cfg_out->specific_bssid,
|
||
|
puser_scan_in->specific_bssid,
|
||
|
sizeof(pscan_cfg_out->specific_bssid));
|
||
|
|
||
|
if (pmadapter->ext_scan
|
||
|
&& 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 = MLAN_MAC_ADDR_LENGTH;
|
||
|
memcpy(pmadapter, pbssid_tlv->bssid,
|
||
|
puser_scan_in->specific_bssid,
|
||
|
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(pmadapter, pwildcard_ssid_tlv->ssid,
|
||
|
puser_scan_in->ssid_list[ssid_idx].ssid,
|
||
|
MIN(MLAN_MAX_SSID_LENGTH, ssid_len));
|
||
|
|
||
|
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 && puser_scan_in->scan_chan_gap) {
|
||
|
*pmax_chan_per_scan = MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN;
|
||
|
PRINTM(MINFO, "Scan: channel gap = %d\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);
|
||
|
}
|
||
|
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(pmadapter, prates_tlv->rates, rates, 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);
|
||
|
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 (wlan_is_ext_capa_support(pmpriv))
|
||
|
wlan_add_ext_capa_info_ie(pmpriv, &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(pmadapter, randomMacParam->mac,
|
||
|
puser_scan_in->random_mac, 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;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Prevent active scanning on a radar controlled channel */
|
||
|
if (radio_type == BAND_5GHZ) {
|
||
|
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) {
|
||
|
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(IN pmlan_adapter pmadapter,
|
||
|
IN MrvlIEtypes_Data_t *ptlv,
|
||
|
IN t_u32 tlv_buf_size,
|
||
|
IN t_u32 req_tlv_type,
|
||
|
OUT 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(IN pmlan_adapter pmadapter,
|
||
|
OUT BSSDescriptor_t *pbss_entry,
|
||
|
IN t_u8 **pbeacon_info,
|
||
|
IN t_u32 *bytes_left, IN 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 };
|
||
|
|
||
|
IEEEtypes_CountryInfoSet_t *pcountry_info;
|
||
|
|
||
|
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(pmadapter, &beacon_size, *pbeacon_info,
|
||
|
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(pmadapter, pbss_entry->mac_address, pcurrent_ptr,
|
||
|
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(pmadapter, fixed_ie.time_stamp, pcurrent_ptr, 8);
|
||
|
memcpy(pmadapter, pbss_entry->time_stamp, pcurrent_ptr, 8);
|
||
|
pcurrent_ptr += 8;
|
||
|
bytes_left_for_current_beacon -= 8;
|
||
|
|
||
|
/* Beacon interval is 2 bytes long */
|
||
|
memcpy(pmadapter, &fixed_ie.beacon_interval, pcurrent_ptr, 2);
|
||
|
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(pmadapter, &fixed_ie.capabilities, pcurrent_ptr, 2);
|
||
|
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(pmadapter, &pbss_entry->cap_info, pcap_info,
|
||
|
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;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
switch (element_id) {
|
||
|
|
||
|
case SSID:
|
||
|
if (element_len > MRVDRV_MAX_SSID_LENGTH) {
|
||
|
bytes_left_for_current_beacon = 0;
|
||
|
continue;
|
||
|
}
|
||
|
if (!pbss_entry->ssid.ssid_len) {
|
||
|
pbss_entry->ssid.ssid_len = element_len;
|
||
|
memcpy(pmadapter, pbss_entry->ssid.ssid,
|
||
|
(pcurrent_ptr + 2), element_len);
|
||
|
}
|
||
|
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;
|
||
|
continue;
|
||
|
}
|
||
|
memcpy(pmadapter, pbss_entry->data_rates,
|
||
|
pcurrent_ptr + 2, element_len);
|
||
|
memcpy(pmadapter, pbss_entry->supported_rates,
|
||
|
pcurrent_ptr + 2, element_len);
|
||
|
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(pmadapter,
|
||
|
&pbss_entry->phy_param_set.fh_param_set,
|
||
|
pfh_param_set, MIN(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(pmadapter,
|
||
|
&pbss_entry->phy_param_set.ds_param_set,
|
||
|
pds_param_set, MIN(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(pmadapter,
|
||
|
&pbss_entry->ss_param_set.cf_param_set,
|
||
|
pcf_param_set, MIN(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(pmadapter,
|
||
|
&pbss_entry->ss_param_set.ibss_param_set,
|
||
|
pibss_param_set, MIN(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(pmadapter, &pbss_entry->country_info,
|
||
|
pcountry_info, pcountry_info->len + 2);
|
||
|
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(pmadapter, prate, pcurrent_ptr + 2,
|
||
|
bytes_to_copy);
|
||
|
|
||
|
prate = (t_u8 *)pbss_entry->supported_rates;
|
||
|
prate += rate_size;
|
||
|
memcpy(pmadapter, prate, pcurrent_ptr + 2,
|
||
|
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(pmadapter,
|
||
|
(t_u8 *)&pbss_entry->wmm_ie,
|
||
|
pcurrent_ptr, total_ie_len);
|
||
|
HEXDUMP("InterpretIE: Resp WMM_IE",
|
||
|
(t_u8 *)&pbss_entry->wmm_ie,
|
||
|
total_ie_len);
|
||
|
}
|
||
|
}
|
||
|
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 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 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(IN mlan_private *pmpriv,
|
||
|
IN 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->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);
|
||
|
}
|
||
|
} 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->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(IN mlan_private *pmpriv,
|
||
|
IN t_u32 beacon_idx,
|
||
|
IN t_u32 num_of_ent,
|
||
|
IN 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_u16 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(pmadapter, pbcn_store,
|
||
|
pnew_beacon->pbeacon_buf,
|
||
|
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(pmadapter, pbcn_store, pnew_beacon->pbeacon_buf,
|
||
|
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(pmadapter, pbcn_store, pnew_beacon->pbeacon_buf,
|
||
|
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->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;
|
||
|
}
|
||
|
/* 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 */
|
||
|
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(pmadapter, tmp_buf, pmadapter->bcn_buf,
|
||
|
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;
|
||
|
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(pmadapter, pmadapter->pbcn_buf_end,
|
||
|
pnew_beacon->pbeacon_buf,
|
||
|
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(IN 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);
|
||
|
}
|
||
|
|
||
|
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 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(IN 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(pmadapter, &pmadapter->pscan_table[j].ssid,
|
||
|
&pmpriv->curr_bss_params.bss_descriptor.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.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.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(pmadapter,
|
||
|
&pmpriv->curr_bss_params.bss_descriptor,
|
||
|
&pmadapter->pscan_table[j],
|
||
|
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(pmadapter, bss_new_entry,
|
||
|
&pmpriv->curr_bss_params.
|
||
|
bss_descriptor,
|
||
|
sizeof(pmpriv->curr_bss_params.
|
||
|
bss_descriptor));
|
||
|
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(pmadapter,
|
||
|
&pmadapter->
|
||
|
pscan_table[pmadapter->
|
||
|
num_in_scan_table
|
||
|
- 1],
|
||
|
bss_new_entry,
|
||
|
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);
|
||
|
|
||
|
/*
|
||
|
* 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(IN mlan_private *pmpriv, IN 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(pmadapter, pmadapter->pscan_table + del_idx,
|
||
|
pmadapter->pscan_table + del_idx + 1,
|
||
|
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].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);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* 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 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(IN mlan_private *pmpriv,
|
||
|
IN 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(IN mlan_private *pmpriv,
|
||
|
IN t_u32 index, IN 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 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 ((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
|
||
|
*/
|
||
|
) {
|
||
|
/* WPA enabled */
|
||
|
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 {
|
||
|
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(IN 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(IN mlan_private *pmpriv,
|
||
|
IN t_void *pioctl_buf, IN 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;
|
||
|
|
||
|
}
|
||
|
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(IN mlan_private *pmpriv,
|
||
|
IN HostCmd_DS_COMMAND *pcmd, IN 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(pmpriv->adapter, pscan_cmd->bssid, pscan_cfg->specific_bssid,
|
||
|
sizeof(pscan_cmd->bssid));
|
||
|
memcpy(pmpriv->adapter, pscan_cmd->tlv_buffer, pscan_cfg->tlv_buf,
|
||
|
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
|
||
|
*/
|
||
|
|
||
|
t_bool
|
||
|
wlan_active_scan_req_for_passive_chan(IN mlan_private *pmpriv,
|
||
|
IN 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(pmpriv->adapter, user_scan_cfg->ssid_list,
|
||
|
puser_scan_in->ssid_list,
|
||
|
sizeof(user_scan_cfg->ssid_list));
|
||
|
} else {
|
||
|
pscan_req = &pscan->param.scan_req;
|
||
|
memcpy(pmpriv->adapter,
|
||
|
user_scan_cfg->ssid_list[0].ssid,
|
||
|
pscan_req->scan_ssid.ssid,
|
||
|
pscan_req->scan_ssid.ssid_len);
|
||
|
}
|
||
|
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(IN mlan_private *pmpriv,
|
||
|
IN HostCmd_DS_COMMAND *resp, IN 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);
|
||
|
|
||
|
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;
|
||
|
|
||
|
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++;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* 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(pmpriv->adapter, &tsf_val,
|
||
|
&ptsf_tlv->tsf_data[idx * TSF_DATA_SIZE],
|
||
|
sizeof(tsf_val));
|
||
|
tsf_val = wlan_le64_to_cpu(tsf_val);
|
||
|
memcpy(pmpriv->adapter,
|
||
|
&bss_new_entry->network_tsf, &tsf_val,
|
||
|
sizeof(bss_new_entry->network_tsf));
|
||
|
}
|
||
|
|
||
|
/* Copy the locally created bss_new_entry to the scan table */
|
||
|
memcpy(pmadapter, &pmadapter->pscan_table[bss_idx],
|
||
|
bss_new_entry,
|
||
|
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;
|
||
|
/* Update the age_in_second */
|
||
|
pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
|
||
|
&pmadapter->age_in_secs,
|
||
|
&age_ts_usec);
|
||
|
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(IN mlan_private *pmpriv,
|
||
|
IN HostCmd_DS_COMMAND *pcmd, IN 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;
|
||
|
}
|
||
|
}
|
||
|
pscan_cfg = (wlan_scan_cmd_config *)pdata_buf;
|
||
|
|
||
|
memcpy(pmpriv->adapter, pext_scan_cmd->tlv_buffer,
|
||
|
pscan_cfg->tlv_buf, 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(IN mlan_private *pmpriv,
|
||
|
IN HostCmd_DS_COMMAND *resp, IN 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 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(IN mlan_private *pmpriv,
|
||
|
IN t_u8 number_of_sets,
|
||
|
IN t_u8 *pscan_resp, IN 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 bss_idx;
|
||
|
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;
|
||
|
t_u8 null_ssid[MLAN_MAX_SSID_LENGTH] = { 0 };
|
||
|
|
||
|
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);
|
||
|
|
||
|
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(pmpriv->adapter, &tsf_val,
|
||
|
&pscan_info_tlv->tsf, sizeof(tsf_val));
|
||
|
tsf_val = wlan_le64_to_cpu(tsf_val);
|
||
|
memcpy(pmpriv->adapter,
|
||
|
&bss_new_entry->network_tsf, &tsf_val,
|
||
|
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;
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* 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++;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* 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;
|
||
|
}
|
||
|
|
||
|
/* Copy the locally created bss_new_entry to the scan table */
|
||
|
memcpy(pmadapter, &pmadapter->pscan_table[bss_idx],
|
||
|
bss_new_entry,
|
||
|
sizeof(pmadapter->pscan_table[bss_idx]));
|
||
|
} else {
|
||
|
/* Error parsing/interpreting the scan response, skipped */
|
||
|
PRINTM(MERROR,
|
||
|
"EXT_SCAN: wlan_interpret_bss_desc_with_ie returned error\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PRINTM(MINFO, "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(IN mlan_private *pmpriv,
|
||
|
IN 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(IN mlan_private *pmpriv,
|
||
|
IN 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;
|
||
|
pmadapter->ext_scan_type = EXT_SCAN_DEFAULT;
|
||
|
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);
|
||
|
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(IN mlan_private *pmpriv,
|
||
|
IN HostCmd_DS_COMMAND *pcmd, IN 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(IN mlan_private *pmpriv,
|
||
|
IN 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(IN mlan_private *pmpriv,
|
||
|
IN HostCmd_DS_COMMAND *pcmd, IN 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;
|
||
|
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(pmadapter, pwildcard_ssid_tlv->ssid,
|
||
|
bg_scan_in->ssid_list[ssid_idx].ssid,
|
||
|
MIN(MLAN_MAX_SSID_LENGTH, ssid_len));
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
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(pmadapter, tlv_ssid->ssid,
|
||
|
bg_scan_in->ees_ssid_cfg[index].
|
||
|
ssid, MIN(MLAN_MAX_SSID_LENGTH,
|
||
|
bg_scan_in->
|
||
|
ees_ssid_cfg[index].
|
||
|
max_len));
|
||
|
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(pmadapter, randomMacParam->mac, bg_scan_in->random_mac,
|
||
|
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(IN mlan_private *pmpriv,
|
||
|
IN HostCmd_DS_COMMAND *resp,
|
||
|
IN 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(IN mlan_private *pmpriv,
|
||
|
IN HostCmd_DS_COMMAND *resp,
|
||
|
IN mlan_ioctl_req *pioctl_buf)
|
||
|
{
|
||
|
mlan_ds_scan *pscan = MNULL;
|
||
|
mlan_adapter *pmadapter = pmpriv->adapter;
|
||
|
ENTER();
|
||
|
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(IN mlan_private *pmpriv,
|
||
|
IN mlan_802_11_ssid *ssid, IN t_u8 *bssid, IN 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(IN mlan_private *pmpriv, IN t_u8 *bssid, IN 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(IN pmlan_adapter pmadapter,
|
||
|
IN mlan_802_11_ssid *ssid1, IN 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(IN mlan_private *pmpriv,
|
||
|
OUT 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(pmadapter, &preq_ssid_bssid->ssid, &preq_bss->ssid,
|
||
|
sizeof(mlan_802_11_ssid));
|
||
|
memcpy(pmadapter, (t_u8 *)&preq_ssid_bssid->bssid,
|
||
|
(t_u8 *)&preq_bss->mac_address, 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(IN mlan_private *pmpriv,
|
||
|
IN t_void *pioctl_buf, IN 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(pmpriv->adapter, pscan_cfg->ssid_list[0].ssid,
|
||
|
preq_ssid->ssid, preq_ssid->ssid_len);
|
||
|
pscan_cfg->keep_previous_scan = MTRUE;
|
||
|
|
||
|
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(IN 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(pmpriv->adapter, pmpriv->pcurr_bcn_buf,
|
||
|
pcurr_bss->pbeacon_buf,
|
||
|
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(IN 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();
|
||
|
}
|