MCUXpresso_MIMXRT1021xxxxx/middleware/wifi_nxp/wifidriver/mlan_scan.c
Yilin Sun 763d32be90
Updated SDK to v2.15.000
Signed-off-by: Yilin Sun <imi415@imi.moe>
2024-03-15 22:23:36 +08:00

4935 lines
194 KiB
C

/** @file mlan_scan.c
*
* @brief This file provides wlan scan IOCTL and firmware command APIs
*
* Copyright 2008-2023 NXP
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
/******************************************************
Change log:
10/28/2008: initial version
******************************************************/
#include <mlan_api.h>
/* Additional WMSDK header files */
#include <wmerrno.h>
#include <wm_os.h>
/* Always keep this include at the end of all include files */
#include <mlan_remap_mem_operations.h>
/********************************************************
Local Constants
********************************************************/
#if defined(RW610) || defined(SD9177)
/** minimum scan time for passive to active scan */
#define MIN_PASSIVE_TO_ACTIVE_SCAN_TIME 150
#endif
int get_split_scan_delay_ms(void);
/** The maximum number of channels the firmware can scan per command */
#define MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN 3
/**
* 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
********************************************************/
/* Global data required for split scan requests */
static bool abort_split_scan;
/**
* 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
********************************************************/
bool split_scan_in_progress;
/********************************************************
Local Functions
********************************************************/
/** Cipher suite definition */
typedef enum cipher_suite
{
CIPHER_SUITE_TKIP,
CIPHER_SUITE_CCMP,
CIPHER_SUITE_MAX
} cipher_suite;
static t_u8 wpa_oui[CIPHER_SUITE_MAX][4] = {
{0x00, 0x50, 0xf2, 0x02}, /* TKIP */
{0x00, 0x50, 0xf2, 0x04}, /* AES */
};
static t_u8 rsn_oui[CIPHER_SUITE_MAX][4] = {
{0x00, 0x0f, 0xac, 0x02}, /* TKIP */
{0x00, 0x0f, 0xac, 0x04}, /* AES */
};
static t_u32 wlan_find_worst_network_in_list(const BSSDescriptor_t *pbss_desc, t_u32 num_entries);
bool is_split_scan_complete(void)
{
return (split_scan_in_progress == false);
}
/*
* wmsdk: Split scan needs to be aborted at times by the application. This
* API will help the caller do that.
*/
void wlan_abort_split_scan(void)
{
if (split_scan_in_progress)
{
abort_split_scan = true;
}
}
/**
* @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 != 0U)
{
if (!__memcmp(pmadapter, ie_body->PtkBody, oui, sizeof(ie_body->PtkBody)))
{
LEAVE();
return MLAN_OUI_PRESENT;
}
--count;
if (count != 0U)
{
ie_body = (IEBody *)(void *)((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, cipher_suite cipher)
{
t_u8 *oui = MNULL;
IEBody *ie_body = MNULL;
t_u8 ret = MLAN_OUI_NOT_PRESENT;
ENTER();
if (((pbss_desc->prsn_ie != MNULL) && ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id == RSN_IE)))
{
ie_body = (IEBody *)(void *)(((t_u8 *)pbss_desc->prsn_ie->data) + RSN_GTK_OUI_OFFSET);
oui = &rsn_oui[cipher][0];
if ((ret = search_oui_in_ie(pmadapter, ie_body, oui)) != 0U)
{
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, cipher_suite cipher)
{
t_u8 *oui = MNULL;
IEBody *ie_body = MNULL;
t_u8 ret = MLAN_OUI_NOT_PRESENT;
ENTER();
if (((pbss_desc->pwpa_ie != MNULL) && ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id == WPA_IE)))
{
ie_body = (IEBody *)(void *)pbss_desc->pwpa_ie->data;
oui = &wpa_oui[(int)cipher][0];
if ((ret = search_oui_in_ie(pmadapter, ie_body, oui)) != 0U)
{
LEAVE();
return ret;
}
}
LEAVE();
return ret;
}
/**
* @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
*
*/
static t_u16 radio_type_to_band(t_u8 radio_type)
{
t_u16 ret_band;
switch (radio_type)
{
case HostCmd_SCAN_RADIO_TYPE_A:
ret_band = BAND_A;
break;
case HostCmd_SCAN_RADIO_TYPE_BG:
default:
ret_band = BAND_G;
break;
}
return ret_band;
}
/**
* @brief This function will update the channel statistics from scan result
*
* @param pmpriv A pointer to mlan_private structure
* @param pchanstats_tlv A pointer to MrvlIEtypes_ChannelStats_t tlv
*
* @return NA
*/
static void wlan_update_chan_statistics(mlan_private *pmpriv, MrvlIEtypes_ChannelStats_t *pchanstats_tlv)
{
mlan_adapter *pmadapter = pmpriv->adapter;
t_u8 i;
chan_statistics_t *pchan_stats = (chan_statistics_t *)((t_u8 *)pchanstats_tlv + sizeof(MrvlIEtypesHeader_t));
t_u8 num_chan = wlan_le16_to_cpu(pchanstats_tlv->header.len) / sizeof(chan_statistics_t);
ENTER();
for (i = 0; i < num_chan; i++)
{
if (pchan_stats->chan_num == 0U)
{
break;
}
if (pmadapter->idx_chan_stats >= pmadapter->num_in_chan_stats)
{
wifi_d("Over flow: idx_chan_stats=%d, num_in_chan_stats=%d", 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);
wifi_d("chan=%d, noise=%d, total_network=%d scan_duration=%d, busy_duration=%d", pchan_stats->chan_num,
pchan_stats->noise, pchan_stats->total_networks, pchan_stats->cca_scan_duration,
pchan_stats->cca_busy_duration);
__memcpy(pmadapter, (chan_statistics_t *)&pmadapter->pchan_stats[pmadapter->idx_chan_stats], pchan_stats,
sizeof(chan_statistics_t));
pmadapter->idx_chan_stats++;
pchan_stats++;
}
LEAVE();
return;
}
/**
* @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_u16 cfg_band, t_u16 scan_band)
{
t_u16 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);
break;
}
return (cfg_band & band);
}
/**
* @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;
const chan_freq_power_t *cfp;
t_u32 region_idx;
t_u32 chan_idx = 0;
t_u32 next_chan;
mlan_scan_type scan_type;
t_u8 radio_type;
ENTER();
for (region_idx = 0; region_idx < NELEMENTS(pmadapter->region_channel); region_idx++)
{
if (wlan_11d_support_is_enabled(pmpriv) && 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 != MNULL) && !puser_scan_in->chan_list[0].chan_number &&
puser_scan_in->chan_list[0].radio_type & BAND_SPECIFIED)
{
radio_type = (t_u8)(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 (!wlan_is_band_compatible(pmpriv->config_bands, pscan_region->band))
{
continue;
}
for (next_chan = 0; next_chan < pscan_region->num_cfp; next_chan++)
{
/* Set the default scan type to the user specified type, will later
be changed to passive on a per channel basis if restricted by
regulatory requirements (11d or 11h) */
scan_type = pmadapter->scan_type;
cfp = pscan_region->pcfp + next_chan;
if ((cfp->dynamic.flags & NXP_CHANNEL_DISABLED) != 0U)
{
continue;
}
switch (pscan_region->band)
{
#ifdef CONFIG_5GHz_SUPPORT
case BAND_A:
pscan_chan_list[chan_idx].radio_type = HostCmd_SCAN_RADIO_TYPE_A;
/* 11D not available... play it safe on DFS channels */
if (wlan_11h_radar_detect_required(pmpriv, (t_u8)cfp->channel))
{
/* Skip DFS channels if required */
if (pmadapter->skip_dfs)
continue;
#if defined(RW610) || defined(SD9177)
scan_type = MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE;
#else
scan_type = MLAN_SCAN_TYPE_PASSIVE;
#endif
}
break;
#endif
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].radio_type = HostCmd_SCAN_RADIO_TYPE_BG;
break;
default:
pscan_chan_list[chan_idx].radio_type = HostCmd_SCAN_RADIO_TYPE_BG;
break;
}
if ((puser_scan_in != MNULL) && puser_scan_in->chan_list[0].scan_time)
{
pscan_chan_list[chan_idx].max_scan_time =
wlan_cpu_to_le16((t_u16)puser_scan_in->chan_list[0].scan_time);
}
#if defined(RW610) || defined(SD9177)
else if (scan_type == MLAN_SCAN_TYPE_PASSIVE || scan_type == MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE)
#else
else if (scan_type == MLAN_SCAN_TYPE_PASSIVE)
#endif
{
pscan_chan_list[chan_idx].max_scan_time = wlan_cpu_to_le16(pmadapter->passive_scan_time);
}
else if (filtered_scan != 0U)
{
pscan_chan_list[chan_idx].max_scan_time = wlan_cpu_to_le16(pmadapter->specific_scan_time);
}
else
{
pscan_chan_list[chan_idx].max_scan_time = wlan_cpu_to_le16(pmadapter->active_scan_time);
}
#if defined(RW610) || defined(SD9177)
if (scan_type == MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE)
{
pscan_chan_list[chan_idx].max_scan_time =
wlan_cpu_to_le16(MAX(pmadapter->passive_scan_time, MIN_PASSIVE_TO_ACTIVE_SCAN_TIME));
pscan_chan_list[chan_idx].chan_scan_mode.passive_to_active_scan = MTRUE;
}
#endif
#if defined(RW610) || defined(SD9177)
if (scan_type == MLAN_SCAN_TYPE_PASSIVE || scan_type == MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE)
#else
if (scan_type == MLAN_SCAN_TYPE_PASSIVE)
#endif
{
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;
#if defined(RW610) || defined(SD9177)
wscan_d("Channel: %d Type: %s %d", cfp->channel,
scan_type == MLAN_SCAN_TYPE_PASSIVE ?
"Passive" :
scan_type == MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE ? "PassiveToActive" : "Active",
cfp->max_tx_power);
#else
wscan_d("Channel: %d Type: %s %d", cfp->channel, scan_type == MLAN_SCAN_TYPE_PASSIVE ? "Passive" : "Active",
cfp->max_tx_power);
#endif
chan_idx++;
}
}
LEAVE();
}
#ifdef CONFIG_WPA_SUPP
#ifdef CONFIG_WPA_SUPP_WPS
/**
* @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);
(void)__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));
*pptlv_out += pmpriv->wps.wps_ie.vend_hdr.len;
}
LEAVE();
}
#endif
/**
* @brief Add 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_probe_request_ie(IN mlan_private *pmpriv, OUT t_u8 **pptlv_out)
{
MrvlIEtypesHeader_t *tlv;
t_u8 *ies = MNULL;
t_u8 ies_len = 0;
t_u32 bytes_left = 0;
t_u8 *pcurrent_ptr = MNULL;
IEEEtypes_Header_t *pieee_hdr = MNULL;
ENTER();
if (pmpriv->default_scan_ies_len != 0)
{
ies = pmpriv->default_scan_ies;
ies_len = pmpriv->default_scan_ies_len;
}
else if (pmpriv->gen_ie_buf_len != 0)
{
ies = pmpriv->gen_ie_buf;
ies_len = pmpriv->gen_ie_buf_len;
}
else
{
return;
}
bytes_left = ies_len;
pcurrent_ptr = ies;
while (bytes_left >= sizeof(IEEEtypes_Header_t))
{
pieee_hdr = (IEEEtypes_Header_t *)pcurrent_ptr;
if (pieee_hdr->element_id == EXT_CAPABILITY)
{
goto skip;
}
tlv = (MrvlIEtypesHeader_t *)*pptlv_out;
tlv->type = wlan_cpu_to_le16(pieee_hdr->element_id);
tlv->len = wlan_cpu_to_le16(pieee_hdr->len);
*pptlv_out += sizeof(MrvlIEtypesHeader_t);
(void)__memcpy(pmpriv->adapter, *pptlv_out, pcurrent_ptr + sizeof(IEEEtypes_Header_t), pieee_hdr->len);
*pptlv_out += pieee_hdr->len;
skip:
pcurrent_ptr += pieee_hdr->len + sizeof(IEEEtypes_Header_t);
bytes_left -= pieee_hdr->len + sizeof(IEEEtypes_Header_t);
}
LEAVE();
}
#endif
/**
* @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;
MrvlIEtypes_ChanListParamSet_t *pchan_tlv_out_temp;
ChanScanParamSet_t *ptmp_chan_list;
ChanScanParamSet_t *pstart_chan;
pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *)pioctl_buf;
t_u32 tlv_idx;
t_u32 total_scan_time;
t_u32 done_early;
t_u32 cmd_no;
#ifdef CONFIG_11AX
MrvlIEtypes_Extension_t *phe_cap;
t_u16 len = 0;
#endif
ENTER();
if ((pscan_cfg_out == MNULL) || (pchan_tlv_out == MNULL) || (pscan_chan_list == MNULL))
{
PRINTM(MINFO, "Scan: Null detect: %p, %p, %p\n", pscan_cfg_out, pchan_tlv_out, pscan_chan_list);
if (pioctl_req != MNULL)
{
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 != MNULL)
{
pioctl_req->status_code = MLAN_ERROR_CMD_SCAN_FAIL;
}
LEAVE();
return MLAN_STATUS_FAILURE;
}
pchan_tlv_out->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
pchan_tlv_out_temp = pchan_tlv_out;
/* Set the temp channel struct pointer to the start of the desired list */
ptmp_chan_list = pscan_chan_list;
if (pmpriv->roaming_configured)
{
pmpriv->roaming_configured = MFALSE;
/* Cancel bg scan */
ret = wifi_stop_bgscan();
if (ret)
return MLAN_STATUS_FAILURE;
}
/* 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 != 0U)
{
tlv_idx = 0;
total_scan_time = 0;
pchan_tlv_out->header.len = 0;
pstart_chan = ptmp_chan_list;
done_early = MFALSE;
t_u8 *ptlv_pos = (t_u8 *)pchan_tlv_out_temp;
MrvlIEtypes_RatesParamSet_t *prates_tlv;
t_u16 config_bands;
WLAN_802_11_RATES rates;
t_u32 rates_size;
config_bands = pmpriv->config_bands;
if (pstart_chan->chan_number > MAX_CHANNELS_BG)
{
config_bands &= ~(BAND_B | BAND_G | BAND_GN
#ifdef CONFIG_11AC
| BAND_GAC
#endif
#ifdef CONFIG_11AX
| BAND_GAX
#endif
);
}
else
{
#ifdef CONFIG_11AX
config_bands &= ~(BAND_AAX);
#endif
}
config_bands = (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) ? config_bands : pmadapter->adhoc_start_band;
/* Append rates tlv */
(void)__memset(pmadapter, rates, 0, sizeof(rates));
rates_size = wlan_get_supported_rates(pmpriv, pmpriv->bss_mode, config_bands, 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);
if (rates_size != 0U && rates_size <= sizeof(prates_tlv->rates))
{
(void)__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);
#ifdef CONFIG_11AX
if (IS_FW_SUPPORT_11AX(pmadapter) && ((config_bands & BAND_GAX) || (config_bands & BAND_AAX)))
{
phe_cap = (MrvlIEtypes_Extension_t *)ptlv_pos;
len = wlan_fill_he_cap_tlv(pmpriv, config_bands, phe_cap, MFALSE);
HEXDUMP("SCAN: HE_CAPABILITIES IE", (t_u8 *)phe_cap, len);
ptlv_pos += len;
}
#endif
pchan_tlv_out = (MrvlIEtypes_ChanListParamSet_t *)ptlv_pos;
pchan_tlv_out->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
pchan_tlv_out->header.len = 0;
/*
* 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)
{
wscan_d("Scan: Chan(%3d), Radio(%d), Mode(%d,%d), Dur(%d)", ptmp_chan_list->chan_number,
ptmp_chan_list->radio_type, 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));
/* Copy the current channel TLV to the command being prepared */
(void)__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 += (t_u16)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 == 1U || ptmp_chan_list->chan_number == 6U ||
ptmp_chan_list->chan_number == 11U))
{
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 == 1U || ptmp_chan_list->chan_number == 6U ||
ptmp_chan_list->chan_number == 11U))
{
done_early = MTRUE;
}
/* Stop the loop if the *next* channel is 36. Get supported rates for 2G/5G channels seperately */
if (ptmp_chan_list->chan_number == 36)
{
done_early = MTRUE;
}
}
/* The total scan time should be less than scan command timeout value */
if (total_scan_time > MRVDRV_MAX_TOTAL_SCAN_TIME)
{
wscan_d("Total scan time %d ms is over limit (%d ms), scan skipped", total_scan_time,
MRVDRV_MAX_TOTAL_SCAN_TIME);
if (pioctl_req != MNULL)
{
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;
/* Do sleep confirm handshake if received sleep event.
* Fw will delay all events if handshake is not done
* yet after ps sleep event.
*/
if (mlan_adap->ps_state == PS_STATE_PRE_SLEEP && split_scan_in_progress)
{
send_sleep_confirm_command((mlan_bss_type)WLAN_BSS_TYPE_STA);
}
if (!ptmp_chan_list->chan_number)
{
/* wmsdk: Once we set this the response handling code can
send event to the WLC manager. Since the event is send
only after command response we can be sure that there
is no race condition */
split_scan_in_progress = false;
}
/* Send the scan command to the firmware with the specified cfg */
#ifdef CONFIG_EXT_SCAN_SUPPORT
if (pmadapter->ext_scan)
{
cmd_no = HostCmd_CMD_802_11_SCAN_EXT;
}
else
#endif
{
cmd_no = HostCmd_CMD_802_11_SCAN;
}
ret = wlan_prepare_cmd(pmpriv, (t_u16)cmd_no, HostCmd_ACT_GEN_SET, 0, pioctl_buf, pscan_cfg_out);
if (ret != MLAN_STATUS_SUCCESS)
{
break;
}
if (abort_split_scan)
{
abort_split_scan = false;
split_scan_in_progress = false;
#ifdef CONFIG_WPA_SUPP
pmadapter->num_in_scan_table = 0;
ret = MLAN_STATUS_FAILURE;
#endif
break;
}
}
LEAVE();
if (ret != MLAN_STATUS_SUCCESS)
{
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 const 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;
#ifdef CONFIG_EXT_SCAN_SUPPORT
MrvlIEtypes_Bssid_List_t *pbssid_tlv;
#endif
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;
mlan_scan_type scan_type;
t_u16 scan_dur;
t_u8 channel;
t_u8 radio_type;
t_u32 ssid_idx;
t_u8 ssid_filter;
MrvlIETypes_HTCap_t *pht_cap;
#ifdef CONFIG_11AC
MrvlIETypes_VHTCap_t *pvht_cap;
#endif
MrvlIEtypes_ScanChanGap_t *pscan_gap_tlv;
ENTER();
pmpriv->ssid_filter = MFALSE;
/* 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 != MNULL)
{
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).
*/
(void)__memcpy(pmadapter, pscan_cfg_out->specific_bssid, puser_scan_in->specific_bssid,
sizeof(pscan_cfg_out->specific_bssid));
#ifdef CONFIG_EXT_SCAN_SUPPORT
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;
(void)__memcpy(pmadapter, pbssid_tlv->bssid, puser_scan_in->specific_bssid, MLAN_MAC_ADDR_LENGTH);
ptlv_pos += sizeof(MrvlIEtypes_Bssid_List_t);
}
#endif
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((const char *)puser_scan_in->ssid_list[ssid_idx].ssid);
pwildcard_ssid_tlv = (MrvlIEtypes_WildCardSsIdParamSet_t *)(void *)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;
if ((ssid_len > 0) && (ssid_len <= MLAN_MAX_SSID_LENGTH))
{
(void)__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 != 0U)
{
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)))
{
if (ssid_filter)
{
pmpriv->ssid_filter = ssid_filter;
}
*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 == MTRUE)
{
*pmax_chan_per_scan = MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN;
}
else
{
*pmax_chan_per_scan = MRVDRV_CHANNELS_PER_SCAN_CMD;
}
if (puser_scan_in)
{
if (puser_scan_in->scan_chan_gap)
{
*pmax_chan_per_scan = MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN;
PRINTM(MCMND, "Scan: channel gap = 0x%x\n", puser_scan_in->scan_chan_gap);
pscan_gap_tlv = (MrvlIEtypes_ScanChanGap_t *)ptlv_pos;
pscan_gap_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_SCAN_CHANNEL_GAP);
pscan_gap_tlv->header.len = sizeof(pscan_gap_tlv->gap);
pscan_gap_tlv->gap = wlan_cpu_to_le16((t_u16)puser_scan_in->scan_chan_gap);
ptlv_pos += sizeof(pscan_gap_tlv->header) + pscan_gap_tlv->header.len;
pscan_gap_tlv->header.len = wlan_cpu_to_le16(pscan_gap_tlv->header.len);
}
}
else if (pmadapter->scan_chan_gap)
{
*pmax_chan_per_scan = MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN;
PRINTM(MCMND, "Scan: channel gap = 0x%x\n", pmadapter->scan_chan_gap);
pscan_gap_tlv = (MrvlIEtypes_ScanChanGap_t *)ptlv_pos;
pscan_gap_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_SCAN_CHANNEL_GAP);
pscan_gap_tlv->header.len = sizeof(pscan_gap_tlv->gap);
pscan_gap_tlv->gap = wlan_cpu_to_le16((t_u16)pmadapter->scan_chan_gap);
ptlv_pos += sizeof(pscan_gap_tlv->header) + pscan_gap_tlv->header.len;
pscan_gap_tlv->header.len = wlan_cpu_to_le16(pscan_gap_tlv->header.len);
}
/* If the input config or adapter has the number of Probes set, add tlv */
if (num_probes != 0U)
{
PRINTM(MINFO, "Scan: num_probes = %d\n", num_probes);
pnum_probes_tlv = (MrvlIEtypes_NumProbes_t *)(void *)ptlv_pos;
pnum_probes_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_NUMPROBES);
pnum_probes_tlv->header.len = (t_u16)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);
}
if (ISSUPP_11NENABLED(pmpriv->adapter->fw_cap_info) &&
(pmpriv->config_bands & BAND_GN || pmpriv->config_bands & BAND_AN) && wmsdk_is_11N_enabled())
{
pht_cap = (MrvlIETypes_HTCap_t *)(void *)ptlv_pos;
(void)__memset(pmadapter, pht_cap, 0, sizeof(MrvlIETypes_HTCap_t));
pht_cap->header.type = wlan_cpu_to_le16(HT_CAPABILITY);
pht_cap->header.len = (t_u16)sizeof(HTCap_t);
wlan_fill_ht_cap_tlv(pmpriv, pht_cap, pmpriv->config_bands);
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);
}
#ifdef CONFIG_11AC
if (ISSUPP_11ACENABLED(pmpriv->adapter->fw_cap_info) && (pmpriv->config_bands & BAND_AAC))
{
pvht_cap = (MrvlIETypes_VHTCap_t *)(void *)ptlv_pos;
(void)__memset(pmadapter, pvht_cap, 0, sizeof(MrvlIETypes_VHTCap_t));
pvht_cap->header.type = wlan_cpu_to_le16(VHT_CAPABILITY);
pvht_cap->header.len = (t_u16)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);
}
#endif
/* fixme: enable this later when req. */
#ifdef CONFIG_WPA_SUPP
#ifdef CONFIG_WPA_SUPP_WPS
wlan_add_wps_probe_request_ie(pmpriv, &ptlv_pos);
#endif
wlan_add_probe_request_ie(pmpriv, &ptlv_pos);
#endif
#if defined(CONFIG_DRIVER_MBO) || defined(CONFIG_WPA_SUPP)
wlan_add_ext_capa_info_ie(pmpriv, NULL, &ptlv_pos);
#endif
/*
* 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 *)(void *)ptlv_pos;
if ((puser_scan_in != MNULL) && 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;
if (!wlan_is_band_compatible(pmpriv->config_bands, radio_type_to_band(radio_type)))
{
continue;
}
channel = puser_scan_in->chan_list[chan_idx].chan_number;
(pscan_chan_list + chan_idx)->chan_number = channel;
(pscan_chan_list + chan_idx)->radio_type = radio_type;
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 == HostCmd_SCAN_RADIO_TYPE_A)
{
if ((pmadapter->fw_bands & BAND_A) != 0U)
{
PRINTM(MINFO, "UserScan request for A Band channel %d!!\n", channel);
}
else
{
PRINTM(MERROR, "Scan in A band is not allowed!!\n");
ret = MLAN_STATUS_FAILURE;
LEAVE();
return ret;
}
}
if (pmadapter->active_scan_triggered == MFALSE)
{
/* Prevent active scanning on a radar controlled channel */
#ifdef CONFIG_5GHz_SUPPORT
if (radio_type == HostCmd_SCAN_RADIO_TYPE_A)
{
if (wlan_11h_radar_detect_required(pmpriv, channel))
{
/* Skip DFS channels if required */
if (pmadapter->skip_dfs)
continue;
#if defined(RW610) || defined(SD9177)
scan_type = MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE;
#else
scan_type = MLAN_SCAN_TYPE_PASSIVE;
#endif
}
}
#endif
if (radio_type == HostCmd_SCAN_RADIO_TYPE_BG)
{
if (wlan_bg_scan_type_is_passive(pmpriv, channel))
{
scan_type = MLAN_SCAN_TYPE_PASSIVE;
}
}
}
#if defined(RW610) || defined(SD9177)
if (scan_type == MLAN_SCAN_TYPE_PASSIVE || scan_type == MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE)
#else
if (scan_type == MLAN_SCAN_TYPE_PASSIVE)
#endif
{
(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;
}
if (puser_scan_in->chan_list[chan_idx].scan_time != 0U)
{
scan_dur = (t_u16)puser_scan_in->chan_list[chan_idx].scan_time;
}
else
{
#if defined(RW610) || defined(SD9177)
if (scan_type == MLAN_SCAN_TYPE_PASSIVE || scan_type == MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE)
#else
if (scan_type == MLAN_SCAN_TYPE_PASSIVE)
#endif
{
scan_dur = pmadapter->passive_scan_time;
}
else if (*pfiltered_scan == MTRUE)
{
scan_dur = pmadapter->specific_scan_time;
}
else
{
scan_dur = pmadapter->active_scan_time;
}
}
#if defined(RW610) || defined(SD9177)
if (scan_type == MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE)
{
(pscan_chan_list + chan_idx)->chan_scan_mode.passive_to_active_scan = MTRUE;
scan_dur = MAX(MIN_PASSIVE_TO_ACTIVE_SCAN_TIME, scan_dur);
}
#endif
(pscan_chan_list + chan_idx)->min_scan_time = wlan_cpu_to_le16(scan_dur);
(pscan_chan_list + chan_idx)->max_scan_time = wlan_cpu_to_le16(scan_dur);
#if defined(RW610) || defined(SD9177)
wscan_d("Channel: %d Type: %s ", channel,
scan_type == MLAN_SCAN_TYPE_PASSIVE ?
"Passive" :
scan_type == MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE ? "PassiveToActive" : "Active");
#else
wscan_d("Channel: %d Type: %s ", channel, scan_type == MLAN_SCAN_TYPE_PASSIVE ? "Passive" : "Active");
#endif
}
/* Check if we are only scanning the current channel */
if ((chan_idx == 1U) &&
(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;
}
#if defined(CONFIG_WPS2) || defined(CONFIG_WPA_SUPP_WPS)
void check_for_wps_ie(const uint8_t *poui,
t_u8 oui_type,
bool *wps_IE_exist,
t_u16 *wps_session,
void *element_data,
unsigned element_len);
#endif /* CONFIG_WPA_SUPP_WPS */
/**
* @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
*/
bool wlan_active_scan_req_for_passive_chan(mlan_private *pmpriv, wlan_user_scan_cfg *puser_scan_in)
{
bool ret = MFALSE;
mlan_adapter *pmadapter = pmpriv->adapter;
bool scan_reqd = MFALSE;
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 = MNULL;
t_u16 band;
ENTER();
if (!pmpriv->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)
{
wifi_d("Memory allocation for user_scan_cfg failed\r\n");
goto done;
}
memset(user_scan_cfg, 0x00, sizeof(wlan_user_scan_cfg));
for (bss_idx = 0; bss_idx < pmadapter->num_in_scan_table; bss_idx++)
{
scan_reqd = MFALSE;
if (!memcmp(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
{
#ifdef CONFIG_5GHz_SUPPORT
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;
#endif
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++)
{
band = radio_type_to_band(user_scan_cfg->chan_list[i].radio_type);
if ((user_scan_cfg->chan_list[i].chan_number == pmadapter->pscan_table[bss_idx].channel) &&
(band & 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;
#ifdef CONFIG_5GHz_SUPPORT
if (pmadapter->pscan_table[bss_idx].bss_band & BAND_A)
user_scan_cfg->chan_list[id].radio_type = BAND_5GHZ;
#endif
user_scan_cfg->chan_list[id].scan_type = MLAN_SCAN_TYPE_ACTIVE;
user_scan_cfg->chan_list[id].scan_time = MRVDRV_ACTIVE_SCAN_CHAN_TIME;
id++;
if (id >= WLAN_USER_SCAN_CHAN_MAX)
break;
}
}
}
if (id)
{
pmadapter->active_scan_triggered = MTRUE;
(void)__memcpy(pmadapter, user_scan_cfg->ssid_list, puser_scan_in->ssid_list, sizeof(user_scan_cfg->ssid_list));
user_scan_cfg->keep_previous_scan = MTRUE;
#ifdef EXT_SCAN_ENH
if (pmadapter->ext_scan_type == EXT_SCAN_ENHANCE)
user_scan_cfg->ext_scan_type = EXT_SCAN_ENHANCE;
#endif
wifi_d("active scan request for passive channel %d\r\n", id);
if (MLAN_STATUS_SUCCESS != wlan_scan_networks(pmpriv, NULL, user_scan_cfg))
{
goto done;
}
ret = MTRUE;
}
done:
split_scan_in_progress = false;
if (user_scan_cfg)
pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)user_scan_cfg);
LEAVE();
return ret;
}
/**
* @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
*
* @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_DtimParamSet_t *pdtim_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[3] = {0x00, 0x50, 0xf2};
const t_u8 wpa_type[1] = {0x01};
const t_u8 wmm_oui[3] = {0x00, 0x50, 0xf2};
const t_u8 wmm_type[1] = {0x02};
const t_u8 brcm_oui[3] = {0x00, 0x10, 0x18};
const t_u8 brcm_type[1] = {0x02};
const t_u8 epigram_oui[3] = {0x00, 0x90, 0x4c};
const t_u8 epigram_type1[1] = {0x33};
const t_u8 epigram_type2[1] = {0x34};
#ifdef CONFIG_OWE
const t_u8 owe_oui[3] = {0x50, 0x6f, 0x9a};
const t_u8 owe_type[1] = {0x01c};
#endif
#ifdef CONFIG_DRIVER_MBO
const t_u8 scan_mbo_oui[3] = {0x50, 0x6f, 0x9a};
const t_u8 scan_mbo_type[1] = {0x016};
#endif
IEEEtypes_CountryInfoSet_t *pcountry_info;
#ifdef CONFIG_11AX
IEEEtypes_Extension_t *pext_tlv;
#endif
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 */
(void)__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;
}
(void)__memcpy(pmadapter, pbss_entry->mac_address, pcurrent_ptr, MLAN_MAC_ADDR_LENGTH);
wifi_d("InterpretIE: AP MAC Addr-%02x:%02x:%02x:%02x:%02x:%02x", pbss_entry->mac_address[0],
pbss_entry->mac_address[1], pbss_entry->mac_address[2], pbss_entry->mac_address[3],
pbss_entry->mac_address[4], pbss_entry->mac_address[5]);
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
*/
#ifdef CONFIG_EXT_SCAN_SUPPORT
if (ext_scan == (t_u8)0U)
{
#endif
/* 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 -= 1U;
#ifdef CONFIG_EXT_SCAN_SUPPORT
}
#endif
/*
* 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;
(void)__memcpy(pmadapter, pbss_entry->time_stamp, pcurrent_ptr, 8);
pcurrent_ptr += 8;
bytes_left_for_current_beacon -= 8U;
/* Beacon interval is 2 bytes long */
(void)__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 -= 2U;
/* Capability information is 2 bytes long */
(void)__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 *)(void *)&fixed_ie.capabilities;
(void)__memcpy(pmadapter, &pbss_entry->cap_info, pcap_info, sizeof(IEEEtypes_CapInfo_t));
pcurrent_ptr += 2;
bytes_left_for_current_beacon -= 2U;
/* Rest of the current buffer are IE's */
wifi_d("InterpretIE: IELength for this AP = %d", bytes_left_for_current_beacon);
HEXDUMP("InterpretIE: IE info", (t_u8 *)pcurrent_ptr, bytes_left_for_current_beacon);
#ifdef CONFIG_WPA_SUPP
/* Store IE pointer and len for wpa supplicant scan result, no need to process each IE below*/
if (pmadapter->wpa_supp_scan_triggered == MTRUE)
{
wifi_d("Alloc ies for BSS");
pbss_entry->ies = (u8 *)os_mem_alloc(bytes_left_for_current_beacon);
if (pbss_entry->ies == MNULL)
{
wifi_d("Failed to alloc memory for BSS ies");
return MLAN_STATUS_FAILURE;
}
(void)__memcpy(pmadapter, pbss_entry->ies, (t_u8 *)pcurrent_ptr, bytes_left_for_current_beacon);
pbss_entry->ies_len = bytes_left_for_current_beacon;
}
#endif
if (pcap_info->privacy == MTRUE)
{
PRINTM(MINFO, "InterpretIE: AP WEP enabled\n");
pbss_entry->privacy = (t_u32)Wlan802_11PrivFilter8021xWEP;
}
else
{
pbss_entry->privacy = (t_u32)Wlan802_11PrivFilterAcceptAll;
}
if (pcap_info->ibss == 1U)
{
pbss_entry->bss_mode = MLAN_BSS_MODE_IBSS;
}
else
{
pbss_entry->bss_mode = MLAN_BSS_MODE_INFRA;
}
/* Process variable IE */
while (bytes_left_for_current_beacon >= 2U)
{
element_id = (IEEEtypes_ElementId_e)(*((t_u8 *)pcurrent_ptr));
element_len = *((t_u8 *)pcurrent_ptr + 1);
total_ie_len = (t_u16)(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;
}
pbss_entry->ssid.ssid_len = element_len;
(void)__memcpy(pmadapter, pbss_entry->ssid.ssid, (pcurrent_ptr + 2), element_len);
wscan_d("AP: %s", pbss_entry->ssid.ssid);
PRINTM(MINFO, "InterpretIE: ssid: %-32s\n", pbss_entry->ssid.ssid);
break;
case SUPPORTED_RATES:
if (element_len > WLAN_SUPPORTED_RATES)
{
bytes_left_for_current_beacon = 0;
continue;
}
(void)__memcpy(pmadapter, pbss_entry->data_rates, pcurrent_ptr + 2, element_len);
(void)__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 *)(void *)pcurrent_ptr;
pbss_entry->network_type_use = Wlan802_11FH;
(void)__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 *)(void *)pcurrent_ptr;
pbss_entry->network_type_use = Wlan802_11DS;
pbss_entry->channel = pds_param_set->current_chan;
(void)__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 *)(void *)pcurrent_ptr;
(void)__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 DTIM_PARAM_SET:
pdtim_param_set = (IEEEtypes_DtimParamSet_t *)(void *)pcurrent_ptr;
pbss_entry->dtim_period = pdtim_param_set->dtim_period;
break;
case IBSS_PARAM_SET:
pibss_param_set = (IEEEtypes_IbssParamSet_t *)(void *)pcurrent_ptr;
pbss_entry->atim_window = wlan_le16_to_cpu(pibss_param_set->atim_window);
(void)__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:
/* Disabling this because IEEEtypes_CountryInfoSet_t size
is 254 bytes. Check later if can be optimized */
pcountry_info = (IEEEtypes_CountryInfoSet_t *)(void *)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;
}
(void)__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 POWER_CONSTRAINT:
case POWER_CAPABILITY:
case TPC_REPORT:
case CHANNEL_SWITCH_ANN:
case QUIET:
case IBSS_DFS:
case SUPPORTED_CHANNELS:
case TPC_REQUEST:
/* fixme: Not enabled yet */
/* 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 == MTRUE)
{
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;
(void)__memcpy(pmadapter, prate, pcurrent_ptr + 2, bytes_to_copy);
prate = (t_u8 *)pbss_entry->supported_rates;
prate += rate_size;
(void)__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 *)(void *)pcurrent_ptr;
if ((__memcmp(pmadapter, pvendor_ie->vend_hdr.oui, wpa_oui, sizeof(wpa_oui))) == 0 &&
(pvendor_ie->vend_hdr.oui_type == wpa_type[0]))
{
/* Save it here since we do not have beacon buffer */
/* fixme : Verify if this is the right approach. This had to be
done because IEEEtypes_Rsn_t was not the correct data
structure to map here */
if (element_len <= (sizeof(pbss_entry->wpa_ie_buff) - sizeof(IEEEtypes_Header_t)))
{
(void)__memcpy(NULL, pbss_entry->wpa_ie_buff, pcurrent_ptr,
element_len + sizeof(IEEEtypes_Header_t));
pbss_entry->pwpa_ie = (IEEEtypes_VendorSpecific_t *)(void *)pbss_entry->wpa_ie_buff;
pbss_entry->wpa_ie_buff_len = element_len + sizeof(IEEEtypes_Header_t);
if (wifi_check_bss_entry_wpa2_entp_only(pbss_entry, VENDOR_SPECIFIC_221) != MLAN_STATUS_SUCCESS)
{
return MLAN_STATUS_RESOURCE;
}
}
else
{
wifi_e("Insufficient space to save WPA_IE size: %d", element_len);
}
/* 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))) == 0 &&
(pvendor_ie->vend_hdr.oui_type == wmm_type[0]))
{
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.
*/
(void)__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);
}
}
else if ((__memcmp(pmadapter, pvendor_ie->vend_hdr.oui, brcm_oui, sizeof(brcm_oui))) == 0 &&
(pvendor_ie->vend_hdr.oui_type == brcm_type[0]))
{
pbss_entry->brcm_ie_exist = 1;
}
else if ((__memcmp(pmadapter, pvendor_ie->vend_hdr.oui, epigram_oui, sizeof(epigram_oui))) == 0 &&
(pvendor_ie->vend_hdr.oui_type == epigram_type1[0] ||
pvendor_ie->vend_hdr.oui_type == epigram_type2[0]))
{
pbss_entry->epigram_ie_exist = 1;
}
#ifdef CONFIG_OWE
else if (IS_FW_SUPPORT_EMBEDDED_OWE(pmadapter) &&
(!__memcmp(pmadapter, pvendor_ie->vend_hdr.oui, owe_oui, sizeof(owe_oui)) &&
(pvendor_ie->vend_hdr.oui_type == owe_type[0])))
{
/* Current Format of OWE IE is element_id:element_len:oui:MAC Address:SSID length:SSID */
t_u8 trans_ssid_len =
*(pcurrent_ptr + sizeof(IEEEtypes_Header_t) + sizeof(owe_oui) + MLAN_MAC_ADDR_LENGTH);
if (!trans_ssid_len || trans_ssid_len > MRVDRV_MAX_SSID_LENGTH)
{
bytes_left_for_current_beacon = 0;
continue;
}
if (!pcap_info->privacy)
{
pbss_entry->owe_transition_mode = OWE_TRANS_MODE_OPEN;
}
else
{
pbss_entry->owe_transition_mode = OWE_TRANS_MODE_OWE;
}
(void)__memcpy(pmadapter, pbss_entry->trans_mac_address,
(pcurrent_ptr + sizeof(IEEEtypes_Header_t) + sizeof(owe_oui)), MLAN_MAC_ADDR_LENGTH);
pbss_entry->trans_ssid.ssid_len = trans_ssid_len;
(void)__memcpy(pmadapter, pbss_entry->trans_ssid.ssid,
(pcurrent_ptr + sizeof(IEEEtypes_Header_t) + sizeof(owe_oui) + MLAN_MAC_ADDR_LENGTH +
sizeof(t_u8)),
trans_ssid_len);
PRINTM(MCMND, "InterpretIE: OWE Transition AP privacy=%d MAC Addr-" MACSTR " ssid %s\n",
pbss_entry->owe_transition_mode, MAC2STR(pbss_entry->trans_mac_address),
pbss_entry->trans_ssid.ssid);
}
#endif
#ifdef CONFIG_DRIVER_MBO
else if (__memcmp(pmadapter, pvendor_ie->vend_hdr.oui, scan_mbo_oui, sizeof(scan_mbo_oui)) == 0 &&
(pvendor_ie->vend_hdr.oui_type == scan_mbo_type[0]))
{
t_u8 *pcurrent_attr = pcurrent_ptr + MBO_IE_HEADER_LEN;
t_u8 mbo_attr_id;
t_u8 mbo_attr_len = 0;
t_u8 mbo_cur_len = MBO_IE_HEADER_LEN - sizeof(IEEEtypes_Header_t);
pbss_entry->mbo_assoc_disallowed = false;
while (mbo_cur_len < element_len)
{
mbo_attr_id = *((t_u8 *)pcurrent_attr);
mbo_attr_len = *((t_u8 *)pcurrent_attr + 1);
if (mbo_attr_id == 0x4U)
{
pbss_entry->mbo_assoc_disallowed = true;
}
mbo_cur_len += (t_u8)MBO_ATTR_HEADER_LEN + mbo_attr_len;
pcurrent_attr = pcurrent_attr + MBO_ATTR_HEADER_LEN + mbo_attr_len;
}
}
#endif
#ifdef CONFIG_11K
/* Voice Enterprise Test Plan V1.2, test case 5.4, store other vendor specific ie */
else
{
if (pbss_entry->vendor_ie_len + element_len + (t_u8)sizeof(IEEEtypes_Header_t) <
(t_u8)sizeof(pbss_entry->vendor_ie_buff))
{
(void)__memcpy(pmadapter, pbss_entry->vendor_ie_buff + pbss_entry->vendor_ie_len, pcurrent_ptr,
element_len + sizeof(IEEEtypes_Header_t));
pbss_entry->vendor_ie_len += element_len + (t_u8)sizeof(IEEEtypes_Header_t);
}
}
#else
else
{
/* Do Nothing */
}
#endif
#if defined(CONFIG_WPS2) || defined(CONFIG_WPA_SUPP_WPS)
/* fixme: Added for WMSDK. Check if can be merged properly with
mlan. There should be a better way */
check_for_wps_ie(pvendor_ie->vend_hdr.oui, pvendor_ie->vend_hdr.oui_type, &pbss_entry->wps_IE_exist,
&pbss_entry->wps_session, pcurrent_ptr + 2, element_len);
#endif /* CONFIG_WPA_SUPP_WPS */
break;
case RSN_IE:
/* Save it here since we do not have beacon buffer */
/* fixme : Verify if this is the right approach. This had to be
done because IEEEtypes_Rsn_t was not the correct data
structure to map here */
if (element_len <= (sizeof(pbss_entry->rsn_ie_buff) - sizeof(IEEEtypes_Header_t)))
{
(void)__memcpy(NULL, pbss_entry->rsn_ie_buff, pcurrent_ptr,
element_len + sizeof(IEEEtypes_Header_t));
pbss_entry->rsn_ie_buff_len = element_len + sizeof(IEEEtypes_Header_t);
pbss_entry->prsn_ie = (IEEEtypes_Generic_t *)(void *)pbss_entry->rsn_ie_buff;
if (wifi_check_bss_entry_wpa2_entp_only(pbss_entry, RSN_IE) != MLAN_STATUS_SUCCESS)
{
return MLAN_STATUS_RESOURCE;
}
}
else
{
wifi_e("Insufficient space to save RSN_IE size: %d", element_len);
}
/* 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;
#if defined(CONFIG_11R) || defined(CONFIG_11K)
case MOBILITY_DOMAIN:
if (element_len <= (sizeof(pbss_entry->md_ie_buff) - sizeof(IEEEtypes_Header_t)))
{
(void)__memcpy(NULL, pbss_entry->md_ie_buff, pcurrent_ptr,
element_len + sizeof(IEEEtypes_Header_t));
pbss_entry->md_ie_buff_len = element_len + sizeof(IEEEtypes_Header_t);
pbss_entry->pmd_ie = (IEEEtypes_MobilityDomain_t *)(void *)pbss_entry->md_ie_buff;
pbss_entry->mob_domain_exist = 1;
/* dump_hex(pbss_entry->pmd_ie, pbss_entry->md_ie_buff_len); */
}
else
{
wifi_e("Insufficient space to save MD_IE size: %d", element_len);
}
break;
#endif
#ifdef CONFIG_11K
case RRM_ENABLED_CAP:
/* Save it here since we do not have beacon buffer */
(void)__memcpy(NULL, &pbss_entry->rm_cap_saved, pcurrent_ptr, sizeof(IEEEtypes_RrmElement_t));
pbss_entry->rm_cap_exist = 1;
break;
#endif
case WAPI_IE:
break;
case MULTI_BSSID:
if (IS_FW_SUPPORT_MULTIBSSID(pmadapter))
{
pbss_entry->multi_bssid_ap = MULTI_BSSID_AP;
HEXDUMP("InterpretIE: Multi BSSID IE", (t_u8 *)pcurrent_ptr, total_ie_len);
}
break;
case HT_CAPABILITY:
/* Save it here since we do not have beacon buffer */
(void)__memcpy(NULL, &pbss_entry->ht_cap_saved, pcurrent_ptr, sizeof(IEEEtypes_HTCap_t));
pbss_entry->pht_cap = &pbss_entry->ht_cap_saved;
/* 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:
/* Save it here since we do not have beacon buffer */
(void)__memcpy(NULL, &pbss_entry->ht_info_saved, pcurrent_ptr, sizeof(IEEEtypes_HTInfo_t));
pbss_entry->pht_info = &pbss_entry->ht_info_saved;
/* 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:
/* Save it here since we do not have beacon buffer */
(void)__memcpy(NULL, &pbss_entry->bss_co_2040_saved, pcurrent_ptr, sizeof(IEEEtypes_2040BSSCo_t));
pbss_entry->pbss_co_2040 = &pbss_entry->bss_co_2040_saved;
/* 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;
#ifdef CONFIG_11AC
case VHT_CAPABILITY:
/* Save it here since we do not have beacon buffer */
(void)__memcpy(NULL, &pbss_entry->vht_cap_saved, pcurrent_ptr, sizeof(IEEEtypes_VHTCap_t));
pbss_entry->pvht_cap = &pbss_entry->vht_cap_saved;
break;
case VHT_OPERATION:
/* Save it here since we do not have beacon buffer */
(void)__memcpy(NULL, &pbss_entry->vht_oprat_saved, pcurrent_ptr, sizeof(IEEEtypes_VHTOprat_t));
pbss_entry->pvht_oprat = &pbss_entry->vht_oprat_saved;
break;
case VHT_TX_POWER_ENV:
/* Save it here since we do not have beacon buffer */
(void)__memcpy(NULL, &pbss_entry->vht_txpower_saved, pcurrent_ptr, sizeof(IEEEtypes_VHTtxpower_t));
pbss_entry->pvht_txpower = &pbss_entry->vht_txpower_saved;
break;
case OPER_MODE_NTF:
/* Save it here since we do not have beacon buffer */
(void)__memcpy(NULL, &pbss_entry->poper_mode_saved, pcurrent_ptr, sizeof(IEEEtypes_OperModeNtf_t));
pbss_entry->ppoper_mode = &pbss_entry->poper_mode_saved;
break;
#endif
case EXT_CAPABILITY:
/* Save it here since we do not have beacon buffer */
(void)__memcpy(NULL, &pbss_entry->ext_cap_saved, pcurrent_ptr, sizeof(IEEEtypes_ExtCap_t));
pbss_entry->pext_cap = &pbss_entry->ext_cap_saved;
break;
#ifdef CONFIG_11AX
case EXTENSION:
pext_tlv = (IEEEtypes_Extension_t *)pcurrent_ptr;
switch (pext_tlv->ext_id)
{
case HE_CAPABILITY:
pbss_entry->phe_cap = (IEEEtypes_HECap_t *)pcurrent_ptr;
pbss_entry->he_cap_offset = (t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
break;
case HE_OPERATION:
pbss_entry->phe_oprat = pext_tlv;
pbss_entry->he_oprat_offset = (t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
break;
default:
PRINTM(MINFO, "Unexpected extension id\n");
break;
}
break;
#endif
case RSNX_IE:
(void)__memcpy(NULL, &pbss_entry->rsnx_ie_saved, pcurrent_ptr, sizeof(pbss_entry->rsnx_ie_saved));
pbss_entry->prsnx_ie = &pbss_entry->rsnx_ie_saved;
wscan_d("RSNX_IE: tag len %d data 0x%02x", pbss_entry->prsnx_ie->ieee_hdr.len,
pbss_entry->prsnx_ie->data[0]);
break;
default:
PRINTM(MINFO, "Unexpected IE \n");
break;
}
pcurrent_ptr += element_len + 2U;
/* Need to account for IE ID and IE Len */
bytes_left_for_current_beacon -= (element_len + 2U);
} /* while (bytes_left_for_current_beacon > 2) */
if (wifi_check_bss_entry_wpa2_entp_only(pbss_entry, SSID) != MLAN_STATUS_SUCCESS)
{
return MLAN_STATUS_RESOURCE;
}
LEAVE();
return ret;
}
/**
* @brief get the chan load from chan stats.
*
* @param pmadapter A pointer to mlan_adapter structure
* @param channel channel *
*
* @return channel load
*/
static t_u16 wlan_get_chan_load(mlan_adapter *pmadapter, t_u8 channel)
{
t_u16 chan_load = 0;
int i;
for (i = 0; i < (int)pmadapter->num_in_chan_stats; i++)
{
if ((pmadapter->pchan_stats[i].chan_num == channel) && pmadapter->pchan_stats[i].cca_scan_duration)
{
chan_load =
(pmadapter->pchan_stats[i].cca_busy_duration * 100) / pmadapter->pchan_stats[i].cca_scan_duration;
break;
}
}
return chan_load;
}
static t_u16 wlan_get_chan_noise(mlan_adapter *pmadapter, t_u8 channel)
{
t_u16 chan_noise = 0;
int i;
for (i = 0; i < (int)pmadapter->num_in_chan_stats; i++)
{
if ((pmadapter->pchan_stats[i].chan_num == channel) && pmadapter->pchan_stats[i].noise)
{
chan_noise = pmadapter->pchan_stats[i].noise;
break;
}
}
return chan_noise;
}
/**
* @brief get the chan min/max rssi
*
* @param pmadapter A pointer to mlan_adapter structure
* @param channel channel *
* @param min_flag flag to get min rssi
* @return rssi
*/
static t_u8 wlan_get_chan_rssi(mlan_adapter *pmadapter, t_u8 channel, t_u8 min_flag)
{
t_u8 rssi = 0;
int i;
for (i = 0; i < (int)pmadapter->num_in_scan_table; i++)
{
if (pmadapter->pscan_table[i].channel == channel)
{
if (rssi == 0)
rssi = (t_s32)pmadapter->pscan_table[i].rssi;
else
{
if (min_flag)
rssi = MIN(rssi, pmadapter->pscan_table[i].rssi);
else
rssi = MAX(rssi, pmadapter->pscan_table[i].rssi);
}
}
}
return rssi;
}
/**
* @brief update the min/max rssi for channel statistics.
*
* @param pmadapter A pointer to mlan_adapter structure
* @return N/A
*/
static t_void wlan_update_chan_rssi(mlan_adapter *pmadapter)
{
int i;
t_s8 min_rssi = 0;
t_s8 max_rssi = 0;
t_s8 rss = 0;
for (i = 0; i < (int)pmadapter->num_in_chan_stats; i++)
{
if (pmadapter->pchan_stats[i].chan_num && pmadapter->pchan_stats[i].cca_scan_duration)
{
min_rssi = -wlan_get_chan_rssi(pmadapter, pmadapter->pchan_stats[i].chan_num, MFALSE);
max_rssi = -wlan_get_chan_rssi(pmadapter, pmadapter->pchan_stats[i].chan_num, MTRUE);
rss = min_rssi - pmadapter->pchan_stats[i].noise;
// rss should always > 0, FW need fix the wrong
// rssi/noise in scantable
if (rss > 0)
pmadapter->pchan_stats[i].min_rss = rss;
else
pmadapter->pchan_stats[i].min_rss = 0;
rss = max_rssi - pmadapter->pchan_stats[i].noise;
if (rss > 0)
pmadapter->pchan_stats[i].max_rss = rss;
else
pmadapter->pchan_stats[i].max_rss = 0;
PRINTM(MCMND, "chan=%d, min_rssi=%d, max_rssi=%d noise=%d min_rss=%d, max_rss=%d\n",
pmadapter->pchan_stats[i].chan_num, min_rssi, max_rssi, pmadapter->pchan_stats[i].noise,
pmadapter->pchan_stats[i].min_rss, pmadapter->pchan_stats[i].max_rss);
}
}
return;
}
/**
* @brief Post process the scan table after a new scan command has completed
*
* Inspect each entry of the scan table and try to find an entry that
* matches our current associated/joined network from the scan. If
* one is found, update the stored copy of the BSSDescriptor for our
* current network.
*
* Debug dump the current scan table contents if compiled accordingly.
*
* @param pmpriv A pointer to mlan_private structure
*
* @return N/A
*/
/* static */ void wlan_scan_process_results(IN mlan_private *pmpriv)
{
mlan_adapter *pmadapter = pmpriv->adapter;
t_u32 i;
for (i = 0; i < pmadapter->num_in_scan_table; i++)
{
PRINTM(MINFO,
"Scan:(%02d) %02x:%02x:%02x:%02x:%02x:%02x, "
"RSSI[%03d], SSID[%s]\n",
i, pmadapter->pscan_table[i].mac_address[0], pmadapter->pscan_table[i].mac_address[1],
pmadapter->pscan_table[i].mac_address[2], pmadapter->pscan_table[i].mac_address[3],
pmadapter->pscan_table[i].mac_address[4], pmadapter->pscan_table[i].mac_address[5],
(t_s32)pmadapter->pscan_table[i].rssi, pmadapter->pscan_table[i].ssid.ssid);
pmadapter->pscan_table[i].chan_load = wlan_get_chan_load(pmadapter, pmadapter->pscan_table[i].channel);
pmadapter->pscan_table[i].chan_noise = wlan_get_chan_noise(pmadapter, pmadapter->pscan_table[i].channel);
}
wlan_update_chan_rssi(pmadapter);
/*
* Prepares domain info from scan table and downloads the
* domain info command to the FW.
*/
if (wlan_11d_support_is_enabled(pmpriv))
{
if (pmpriv->support_11d != NULL)
{
(void)pmpriv->support_11d->wlan_11d_prepare_dnld_domain_info_cmd_p(pmpriv);
}
}
LEAVE();
}
/********************************************************
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 mlan_bss_mode mode)
{
mlan_adapter *pmadapter = pmpriv->adapter;
BSSDescriptor_t *pbss_desc;
ENTER();
pbss_desc = &pmadapter->pscan_table[index];
pbss_desc->disable_11n = MFALSE;
/* 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 (t_s32)index;
}
#ifdef CONFIG_11AC
/* if the VHT CAP IE exists, the HT CAP IE should exist too */
if ((pbss_desc->pvht_cap != MNULL) && (pbss_desc->pht_cap == MNULL))
{
PRINTM(MINFO, "Disable 11n if HT CAP IE is not found from the 11AC AP\n");
pbss_desc->disable_11n = MTRUE;
}
#endif
#ifdef CONFIG_11AX
/* if the HE CAP IE exists, HT CAP IE should exist too */
/* 2.4G AX AP, don't have VHT CAP */
if (pbss_desc->phe_cap && !pbss_desc->pht_cap)
{
PRINTM(MINFO, "Disable 11n if VHT CAP/HT CAP IE is not found from the 11AX AP\n");
pbss_desc->disable_11n = MTRUE;
}
#endif
#if defined(CONFIG_WPS2) || defined(CONFIG_WPA_SUPP_WPS)
if (pmpriv->wps.session_enable == MTRUE)
{
PRINTM(MINFO, "Return success directly in WPS period\n");
LEAVE();
return index;
}
#endif /* CONFIG_WPS2 */
#ifdef CONFIG_OWE
if ((pbss_desc->owe_transition_mode == OWE_TRANS_MODE_OPEN) &&
(pmpriv->sec_info.authentication_mode != MLAN_AUTH_MODE_OWE))
{
PRINTM(MINFO, "Return success directly in OWE Transition mode\n");
LEAVE();
return index;
}
#endif
if ((pbss_desc->bss_mode == mode) && (pmpriv->sec_info.ewpa_enabled == MTRUE))
{
if (((pbss_desc->pwpa_ie != MNULL) && ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id == WPA_IE)) ||
((pbss_desc->prsn_ie != MNULL) && ((*(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 != MNULL)) &&
(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))
{
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 (t_s32)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 != MNULL) && ((*(pbss_desc->pwapi_ie)).ieee_hdr.element_id == WAPI_IE)))
{
PRINTM(MINFO, "Return success for WAPI AP\n");
LEAVE();
return (t_s32)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 == MNULL) || ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id != WPA_IE)) &&
((pbss_desc->prsn_ie == MNULL) || ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id != RSN_IE)) &&
!pmpriv->adhoc_aes_enabled && pmpriv->sec_info.encryption_mode == MLAN_ENCRYPTION_MODE_NONE &&
!pbss_desc->privacy)
{
/* No security */
LEAVE();
return (t_s32)index;
}
else if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled && !pmpriv->sec_info.wpa_enabled &&
!pmpriv->sec_info.wpa2_enabled && !pmpriv->adhoc_aes_enabled && pbss_desc->privacy)
{
/* Static WEP enabled */
PRINTM(MINFO, "Disable 11n in WEP mode\n");
pbss_desc->disable_11n = MTRUE;
LEAVE();
return (t_s32)index;
}
else if (pmpriv->sec_info.wep_status == Wlan802_11WEPDisabled && pmpriv->sec_info.wpa_enabled &&
!pmpriv->sec_info.wpa2_enabled &&
((pbss_desc->pwpa_ie != MNULL) && ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id == WPA_IE)) &&
!pmpriv->adhoc_aes_enabled
/*
* 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 != MNULL)) &&
(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) != 0U)
{
PRINTM(MINFO, "Disable 11n if AES is not supported by AP\n");
pbss_desc->disable_11n = MTRUE;
}
else
{
LEAVE();
return -1;
}
}
LEAVE();
return (t_s32)index;
}
else if (pmpriv->sec_info.wep_status == Wlan802_11WEPDisabled && !pmpriv->sec_info.wpa_enabled &&
pmpriv->sec_info.wpa2_enabled &&
((pbss_desc->prsn_ie != MNULL) && ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id == RSN_IE)) &&
!pmpriv->adhoc_aes_enabled
/*
* 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 != MNULL)) &&
(pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) &&
!is_rsn_oui_present(pmpriv->adapter, pbss_desc, CIPHER_SUITE_CCMP))
{
if (is_rsn_oui_present(pmpriv->adapter, pbss_desc, CIPHER_SUITE_TKIP) != 0U)
{
PRINTM(MINFO, "Disable 11n if AES is not supported by AP\n");
pbss_desc->disable_11n = MTRUE;
}
else
{
LEAVE();
return -1;
}
}
LEAVE();
return (t_s32)index;
}
else if (pmpriv->sec_info.wep_status == Wlan802_11WEPDisabled && !pmpriv->sec_info.wpa_enabled &&
!pmpriv->sec_info.wpa2_enabled &&
((pbss_desc->pwpa_ie == MNULL) || ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id != WPA_IE)) &&
((pbss_desc->prsn_ie == MNULL) || ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id != RSN_IE)) &&
pmpriv->adhoc_aes_enabled && pmpriv->sec_info.encryption_mode == MLAN_ENCRYPTION_MODE_NONE &&
pbss_desc->privacy)
{
/* Ad-hoc AES enabled */
LEAVE();
return (t_s32)index;
}
else if (pmpriv->sec_info.wep_status == Wlan802_11WEPDisabled && !pmpriv->sec_info.wpa_enabled &&
!pmpriv->sec_info.wpa2_enabled &&
((pbss_desc->pwpa_ie == MNULL) || ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id != WPA_IE)) &&
((pbss_desc->prsn_ie == MNULL) || ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id != RSN_IE)) &&
!pmpriv->adhoc_aes_enabled && pmpriv->sec_info.encryption_mode != MLAN_ENCRYPTION_MODE_NONE &&
pbss_desc->privacy)
{
/* Dynamic WEP enabled */
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 (t_s32)index;
}
else
{
/* 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 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 const 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;
ENTER();
ret = pcb->moal_malloc(pmadapter->pmoal_handle, sizeof(wlan_scan_cmd_config_tlv), MLAN_MEM_DEF,
(t_u8 **)(void **)&pscan_cfg_out);
if (ret != MLAN_STATUS_SUCCESS || (pscan_cfg_out == MNULL))
{
PRINTM(MERROR, "Memory allocation for pscan_cfg_out failed!\n");
if (pioctl_req != MNULL)
{
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 **)(void **)&pscan_chan_list);
if (ret != MLAN_STATUS_SUCCESS || (pscan_chan_list == MNULL))
{
PRINTM(MERROR, "Failed to allocate scan_chan_list\n");
(void)pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)pscan_cfg_out);
if (pioctl_req != MNULL)
{
pioctl_req->status_code = MLAN_ERROR_NO_MEM;
}
LEAVE();
return MLAN_STATUS_FAILURE;
}
(void)__memset(pmadapter, pscan_chan_list, 0x00, buf_size);
(void)__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");
(void)pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)pscan_cfg_out);
(void)pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)pscan_chan_list);
if (pioctl_req != MNULL)
{
pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
}
LEAVE();
return MLAN_STATUS_FAILURE;
}
if (puser_scan_in != MNULL)
{
keep_previous_scan = puser_scan_in->keep_previous_scan;
}
if (keep_previous_scan == MFALSE)
{
(void)__memset(pmadapter, pmadapter->pscan_table, 0x00, sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST);
pmadapter->num_in_scan_table = 0;
}
pmadapter->idx_chan_stats = 0;
split_scan_in_progress = true;
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)
{
/* fixme: This functionality is not needed. Recheck later */
}
(void)pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)pscan_cfg_out);
(void)pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)pscan_chan_list);
LEAVE();
return ret;
}
#ifndef CONFIG_EXT_SCAN_SUPPORT
/**
* @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;
(void)__memcpy(pmpriv->adapter, pscan_cmd->bssid, pscan_cfg->specific_bssid, sizeof(pscan_cmd->bssid));
(void)__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;
}
#endif
/*
* Fills the pointer variables with correct address.
*
* Original mlan stores the entire beacon. We cannot do that as it would
* take approx 4K RAM per entry. Instead we have added some variables to
* the original BSSDescriptor_t structure. These will keep the data needed
* later. The pointers in this structure which would (ideally) point to
* addresses in beacon buffer now point to these internal variables.
*
* Due beacon parsing a separate structure was used. That is mem-copied
* into an entry in the static BSS_List. After this copy the internal
* pointers still point to buffer addresses in the separate structure. We
* will update them here.
*/
static void adjust_pointers_to_internal_buffers(BSSDescriptor_t *pbss_entry, BSSDescriptor_t *pbss_new_entry)
{
if (pbss_entry->pht_cap != NULL)
{
pbss_entry->pht_cap = &pbss_entry->ht_cap_saved;
}
if (pbss_entry->pht_info != NULL)
{
pbss_entry->pht_info = &pbss_entry->ht_info_saved;
}
#ifdef CONFIG_11AC
if (pbss_entry->pvht_cap != NULL)
{
pbss_entry->pvht_cap = &pbss_entry->vht_cap_saved;
}
if (pbss_entry->pvht_oprat != NULL)
{
pbss_entry->pvht_oprat = &pbss_entry->vht_oprat_saved;
}
if (pbss_entry->pvht_txpower != NULL)
{
pbss_entry->pvht_txpower = &pbss_entry->vht_txpower_saved;
}
if (pbss_entry->ppoper_mode != NULL)
{
pbss_entry->ppoper_mode = &pbss_entry->poper_mode_saved;
}
if (pbss_entry->pext_cap != NULL)
{
pbss_entry->pext_cap = &pbss_entry->ext_cap_saved;
}
#endif
if (pbss_entry->pbss_co_2040 != NULL)
{
pbss_entry->pbss_co_2040 = &pbss_entry->bss_co_2040_saved;
}
if (pbss_entry->pwpa_ie != NULL)
{
pbss_entry->pwpa_ie = (IEEEtypes_VendorSpecific_t *)(void *)pbss_entry->wpa_ie_buff;
}
if (pbss_entry->prsn_ie != NULL)
{
pbss_entry->prsn_ie = (IEEEtypes_Generic_t *)(void *)pbss_entry->rsn_ie_buff;
}
if (pbss_entry->prsnx_ie != NULL)
{
pbss_entry->prsnx_ie = &pbss_entry->rsnx_ie_saved;
}
#ifdef CONFIG_WPA_SUPP
if (pbss_new_entry->ies != NULL)
{
pbss_entry->ies = pbss_new_entry->ies;
}
#endif
}
/**
* @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;
mlan_ioctl_req *pioctl_req = (mlan_ioctl_req *)pioctl_buf;
/* 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;
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;
const chan_freq_power_t *cfp;
MrvlIEtypes_ChanBandListParamSet_t *pchan_band_tlv = MNULL;
ChanBandParamSet_t *pchan_band;
t_u16 band;
t_u8 is_bgscan_resp;
/* t_u32 age_ts_usec; */
t_u32 lowest_rssi_index = 0;
MrvlIEtypes_ChannelStats_t *pchanstats_tlv = MNULL;
t_u8 null_ssid[MLAN_MAX_SSID_LENGTH] = {0};
MrvlIEtypes_Data_t *pcurrent_tlv;
t_u32 tlv_buf_left;
t_u16 tlv_type;
t_u16 tlv_len;
ENTER();
pcb = (pmlan_callbacks)&pmadapter->callbacks;
is_bgscan_resp = ((resp->command & HostCmd_CMD_ID_MASK) == 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;
}
/* Note: We do not expect to have the entire list of AP's with us in
the driver. This is because we are memory constrained. So will
modify the handling of the AP list and keep only AP's with high RSSI */
bytes_left = wlan_le16_to_cpu(pscan_rsp->bss_descript_size);
PRINTM(MINFO, "SCAN_RESP: bss_descript_size %d\n", bytes_left);
if ((pscan_rsp->number_of_sets == 0U) && (bytes_left == 0U))
{
wscan_d("SCAN_RESP: number of sets are zero");
goto done;
}
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)))
{
tlv_buf_size -= sizeof(resp->params.bg_scan_query_resp.report_condition);
}
ptlv = (MrvlIEtypes_Data_t *)(void *)(pscan_rsp->bss_desc_and_tlv_buffer + bytes_left);
pcurrent_tlv = ptlv;
tlv_buf_left = tlv_buf_size;
wscan_d("SCAN_RESP: tlv_buf_size = %d", 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)
{
wscan_d("SCAN_RESP: TLV buffer corrupt");
break;
}
switch (tlv_type)
{
case TLV_TYPE_TSFTIMESTAMP:
wscan_d("SCAN_RESP: TSF Timestamp TLV, len = %d", tlv_len);
ptsf_tlv = (MrvlIEtypes_TsfTimestamp_t *)pcurrent_tlv;
break;
case TLV_TYPE_CHANNELBANDLIST:
wscan_d("SCAN_RESP: CHANNEL BAND LIST TLV, len = %d", tlv_len);
pchan_band_tlv = (MrvlIEtypes_ChanBandListParamSet_t *)pcurrent_tlv;
break;
case TLV_TYPE_CHANNEL_STATS:
wscan_d("SCAN_RESP: CHANNEL STATS TLV, len = %d", tlv_len);
pchanstats_tlv = (MrvlIEtypes_ChannelStats_t *)pcurrent_tlv;
break;
default:
wscan_d("SCAN_RESP: Unhandled TLV = %d", tlv_type);
break;
}
tlv_buf_left -= (sizeof(ptlv->header) + tlv_len);
pcurrent_tlv = (MrvlIEtypes_Data_t *)(void *)(pcurrent_tlv->data + tlv_len);
} /* while */
if (pchanstats_tlv != MNULL)
{
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 **)(void **)&bss_new_entry);
if (ret != MLAN_STATUS_SUCCESS || (bss_new_entry == MNULL))
{
PRINTM(MERROR, "Memory allocation for bss_new_entry failed!\n");
if (pioctl_req != MNULL)
{
pioctl_req->status_code = MLAN_ERROR_NO_MEM;
}
ret = MLAN_STATUS_FAILURE;
goto done;
}
idx = 0;
while (idx < pscan_rsp->number_of_sets && bytes_left)
{
/* Zero out the bss_new_entry we are about to store info in */
(void)__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)
{
wscan_d("SCAN_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x", bss_new_entry->mac_address[0],
bss_new_entry->mac_address[1], bss_new_entry->mac_address[2], bss_new_entry->mac_address[3],
bss_new_entry->mac_address[4], bss_new_entry->mac_address[5]);
#ifdef CONFIG_WPA_SUPP
#ifdef CONFIG_WPA_SUPP_WPS
if (pmpriv->wps.session_enable == MTRUE)
{
if ((bss_new_entry->wps_IE_exist == MFALSE) || (bss_new_entry->wps_session == 0xffff))
{
if (bss_new_entry->ies != NULL)
{
os_mem_free(bss_new_entry->ies);
bss_new_entry->ies = NULL;
}
continue;
}
}
#endif /* CONFIG_WPA_SUPP_WPS */
#endif
/*
* 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)))
{
wscan_d("SCAN_RESP: Duplicate of index: %d", 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))
{
wscan_d("SCAN_RESP: Duplicate of index: %d", 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)
{
lowest_rssi_index = wlan_find_worst_network_in_list(pmadapter->pscan_table, MRVDRV_MAX_BSSID_LIST);
}
else
{
num_in_table++;
}
}
else
{
if ((bss_new_entry->channel != pmadapter->pscan_table[bss_idx].channel) &&
(bss_new_entry->rssi > pmadapter->pscan_table[bss_idx].rssi))
{
wscan_d("skip update the duplicate entry with low rssi");
#ifdef CONFIG_WPA_SUPP
if (bss_new_entry->ies != NULL)
{
os_mem_free(bss_new_entry->ies);
bss_new_entry->ies = NULL;
}
#endif
continue;
}
}
/* fixme: Don't know if we need this right now */
/*
* 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 != MNULL)
{
(void)__memcpy(pmpriv->adapter, &tsf_val, &ptsf_tlv->tsf_data[idx * TSF_DATA_SIZE], sizeof(tsf_val));
tsf_val = wlan_le64_to_cpu(tsf_val);
(void)__memcpy(pmpriv->adapter, &bss_new_entry->network_tsf, &tsf_val,
sizeof(bss_new_entry->network_tsf));
}
band = BAND_G;
if (pchan_band_tlv != MNULL)
{
pchan_band = &pchan_band_tlv->chan_band_param[idx];
if (bss_new_entry->channel == 0)
{
bss_new_entry->channel = pchan_band->chan_number;
}
band = radio_type_to_band(pchan_band->radio_type & (MBIT(0) | MBIT(1)));
}
/* 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, bss_new_entry->bss_band, (t_u16)bss_new_entry->channel);
if (cfp != MNULL)
{
bss_new_entry->freq = cfp->freq;
}
else
{
bss_new_entry->freq = 0;
}
if ((is_bgscan_resp) && (pmpriv->roaming_enabled == MTRUE))
{
if (num_in_table == 2U)
{
if (pmadapter->pscan_table[0].rssi > bss_new_entry->rssi)
{
#ifdef CONFIG_WPA_SUPP
/* If the scan table is full, free ies of the lowest rssi entry before this entry is replaced */
if (pmadapter->pscan_table[0].ies != NULL)
{
os_mem_free(pmadapter->pscan_table[0].ies);
pmadapter->pscan_table[0].ies = NULL;
}
#endif
(void)__memcpy(pmadapter, &pmadapter->pscan_table[0], bss_new_entry,
sizeof(pmadapter->pscan_table[0]));
adjust_pointers_to_internal_buffers(&pmadapter->pscan_table[0], bss_new_entry);
}
#ifdef CONFIG_WPA_SUPP
/* If the scan table is full, free ies of the new entry with lowest rssi, which won't be added into
* table */
else
{
if (bss_new_entry->ies != NULL)
{
os_mem_free(bss_new_entry->ies);
bss_new_entry->ies = NULL;
}
}
#endif
num_in_table--;
continue;
}
}
if (bss_idx == MRVDRV_MAX_BSSID_LIST)
{
if (pmadapter->pscan_table[lowest_rssi_index].rssi > bss_new_entry->rssi)
{
#ifdef CONFIG_WPA_SUPP
/* If the scan table is full, free ies of the lowest rssi entry before this entry is replaced */
if (pmadapter->pscan_table[lowest_rssi_index].ies != NULL)
{
os_mem_free(pmadapter->pscan_table[lowest_rssi_index].ies);
pmadapter->pscan_table[lowest_rssi_index].ies = NULL;
}
#endif
(void)__memcpy(pmadapter, &pmadapter->pscan_table[lowest_rssi_index], bss_new_entry,
sizeof(pmadapter->pscan_table[lowest_rssi_index]));
adjust_pointers_to_internal_buffers(&pmadapter->pscan_table[lowest_rssi_index], bss_new_entry);
}
#ifdef CONFIG_WPA_SUPP
/* If the scan table is full, free ies of the new entry with lowest rssi, which won't be added into
* table */
else
{
if (bss_new_entry->ies != NULL)
{
os_mem_free(bss_new_entry->ies);
bss_new_entry->ies = NULL;
}
}
#endif
}
else
{
#ifdef CONFIG_WPA_SUPP
/* Free ies of the old entry if it's duplicate entry */
if (pmadapter->pscan_table[bss_idx].ies != NULL)
{
os_mem_free(pmadapter->pscan_table[bss_idx].ies);
pmadapter->pscan_table[bss_idx].ies = NULL;
}
#endif
/* Copy the locally created bss_new_entry to the scan table */
(void)__memcpy(pmadapter, &pmadapter->pscan_table[bss_idx], bss_new_entry,
sizeof(pmadapter->pscan_table[bss_idx]));
adjust_pointers_to_internal_buffers(&pmadapter->pscan_table[bss_idx], bss_new_entry);
}
}
else
{
/* Error parsing/interpreting the scan response, skipped */
PRINTM(MERROR, "SCAN_RESP: wlan_interpret_bss_desc_with_ie returned error\n");
#ifdef CONFIG_WPA_SUPP
if (bss_new_entry->ies != NULL)
{
os_mem_free(bss_new_entry->ies);
bss_new_entry->ies = NULL;
}
#endif
}
idx++;
}
wscan_d("SCAN_RESP: Scanned %2d APs, %d valid, %d total", 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;
/* fixme: the following code does not seem relevant */
done:
if (bss_new_entry != MNULL)
{
(void)pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)bss_new_entry);
}
LEAVE();
return ret;
}
#if defined(CONFIG_EXT_SCAN_SUPPORT)
/**
* @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();
pscan_cfg = (wlan_scan_cmd_config *)pdata_buf;
/* Set fixed field variables in scan command */
pext_scan_cmd->reserved = 0x00;
(void)__memcpy(pmpriv->adapter, pext_scan_cmd->tlv_buffer, pscan_cfg->tlv_buf, pscan_cfg->tlv_buf_len);
pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SCAN_EXT);
/* Size is equal to the sizeof(fixed portions) + the TLV len + header */
pcmd->size = wlan_cpu_to_le16((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;
#ifdef EXT_SCAN_ENH
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;
#endif
ENTER();
PRINTM(MINFO, "EXT scan returns successfully\n");
#ifdef EXT_SCAN_ENH
pmadapter->scan_state |= wlan_get_ext_scan_state(resp);
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->scan_state |= SCAN_STATE_SCAN_COMPLETE;
pmadapter->ext_scan_type = EXT_SCAN_DEFAULT;
#ifdef HOST_CCX
pmadapter->scan_data_block = MFALSE;
#endif
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;
}
#endif
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;
}
/** 8 bytes timestamp, 2 bytest interval, 2 bytes capability */
#define BEACON_FIX_SIZE 12
/**
* @brief This function realloc the beacon buffer and update ssid for new entry
*
* @param pmadpater A pointer to mlan_adapter structure
* @param pbss_entry A pointer to the bss_entry which has multi-bssid IE
* @param pnew_entry A pinter to new entry
* @param pssid A pointer to ssid IE
*
* @return MLAN_STATUS_FAILURE/MLAN_STATUS_SUCCESS
*/
static mlan_status wlan_update_ssid_in_beacon_buf(mlan_adapter *pmadapter,
BSSDescriptor_t *pbss_entry,
BSSDescriptor_t *pnew_entry,
IEEEtypes_Ssid_t *pssid,
IEEEtypes_ExtCap_t *pnew_extcap,
IEEEtypes_Generic_t *pnew_rsnx)
{
#ifdef CONFIG_WPA_SUPP
mlan_callbacks *pcb = (pmlan_callbacks)&pmadapter->callbacks;
t_u8 *pbeacon_buf = MNULL;
#endif
t_u32 beacon_buf_size = 0;
t_s8 offset = pnew_entry->ssid.ssid_len - pbss_entry->ssid.ssid_len;
mlan_status ret = MLAN_STATUS_FAILURE;
if (pnew_entry->ssid.ssid_len >= pbss_entry->ssid.ssid_len)
beacon_buf_size = pbss_entry->beacon_buf_size + (pnew_entry->ssid.ssid_len - pbss_entry->ssid.ssid_len);
else
beacon_buf_size = pbss_entry->beacon_buf_size - (pbss_entry->ssid.ssid_len - pnew_entry->ssid.ssid_len);
if (pnew_rsnx)
beacon_buf_size += pnew_rsnx->ieee_hdr.len + sizeof(IEEEtypes_Header_t);
#ifdef CONFIG_WPA_SUPP
ret = pcb->moal_malloc(pmadapter->pmoal_handle, beacon_buf_size, MLAN_MEM_DEF, (t_u8 **)&pbeacon_buf);
if (ret != MLAN_STATUS_SUCCESS || !pbeacon_buf)
{
wifi_d("Memory allocation for beacon buf for bss_new_entry");
goto done;
}
#endif
#ifdef CONFIG_WIFI_IO_DUMP
wifi_d("BSS Entry");
dump_hex(pbss_entry->pbeacon_buf, pbss_entry->beacon_buf_size);
#endif
pnew_entry->beacon_buf_size = beacon_buf_size;
#ifdef CONFIG_WPA_SUPP
pnew_entry->pbeacon_buf = pbeacon_buf;
#else
pnew_entry->pbeacon_buf = pbss_entry->pbeacon_buf;
#endif
if (pnew_entry->pext_cap)
{
pnew_entry->ext_cap_offset += offset;
if (pnew_extcap)
{
(void)__memcpy(pmadapter, &pnew_entry->ext_cap_saved, pnew_extcap, sizeof(IEEEtypes_ExtCap_t));
pnew_entry->pext_cap = &pnew_entry->ext_cap_saved;
}
}
if (pnew_rsnx)
{
(void)__memcpy(pmadapter, &pnew_entry->rsnx_ie_saved, pnew_rsnx,
pnew_rsnx->ieee_hdr.len + sizeof(IEEEtypes_Header_t));
pnew_entry->prsnx_ie = &pnew_entry->rsnx_ie_saved;
}
#ifdef CONFIG_WPA_SUPP
/** copy fixed IE */
(void)__memcpy(pmadapter, pbeacon_buf, pbss_entry->pbeacon_buf, BEACON_FIX_SIZE);
/** copy new ssid ie */
(void)__memcpy(pmadapter, pbeacon_buf + BEACON_FIX_SIZE, (t_u8 *)pssid, pssid->len + sizeof(IEEEtypes_Header_t));
/** copy left IE to new beacon buffer */
(void)__memcpy(
pmadapter, pbeacon_buf + BEACON_FIX_SIZE + pssid->len + sizeof(IEEEtypes_Header_t),
pbss_entry->pbeacon_buf + BEACON_FIX_SIZE + pbss_entry->ssid.ssid_len + sizeof(IEEEtypes_Header_t),
pbss_entry->beacon_buf_size - BEACON_FIX_SIZE - (pbss_entry->ssid.ssid_len + sizeof(IEEEtypes_Header_t)));
#if 0
/* adjust the ie pointer */
if (pnew_entry->pwpa_ie)
pnew_entry->wpa_offset += offset;
if (pnew_entry->prsn_ie)
pnew_entry->rsn_offset += offset;
#ifdef ENABLE_HOTSPOT
if (pnew_entry->posen_ie)
pnew_entry->osen_offset += offset;
#endif /* ENABLE_HOTSPOT */
#ifdef CONFIG_11R
if (pnew_entry->pmd_ie)
pnew_entry->md_offset += offset;
#endif /* ENABLE_HOTSPOT */
if (pnew_entry->pht_cap)
pnew_entry->ht_cap_offset += offset;
if (pnew_entry->pht_info)
pnew_entry->ht_info_offset += offset;
if (pnew_entry->pbss_co_2040)
pnew_entry->bss_co_2040_offset += offset;
if (pnew_entry->poverlap_bss_scan_param)
pnew_entry->overlap_bss_offset += offset;
#ifdef CONFIG_11AC
if (pnew_entry->pvht_cap)
pnew_entry->vht_cap_offset += offset;
if (pnew_entry->pvht_oprat)
pnew_entry->vht_oprat_offset += offset;
if (pnew_entry->pvht_txpower)
pnew_entry->vht_txpower_offset += offset;
if (pnew_entry->pext_pwer)
pnew_entry->ext_pwer_offset += offset;
if (pnew_entry->pext_bssload)
pnew_entry->ext_bssload_offset += offset;
if (pnew_entry->pquiet_chan)
pnew_entry->quiet_chan_offset += offset;
if (pnew_entry->poper_mode)
pnew_entry->oper_mode_offset += offset;
#endif /* CONFIG_11AC */
#ifdef CONFIG_11AX
if (pnew_entry->phe_cap)
pnew_entry->he_cap_offset += offset;
if (pnew_entry->phe_oprat)
pnew_entry->he_oprat_offset += offset;
#endif /* CONFIG_11AX */
#ifdef ENABLE_802_116E
if (pnew_entry->phe_6g_cap)
pnew_entry->he_6g_cap_offset += offset;
#endif
#endif
#ifdef CONFIG_WIFI_IO_DUMP
wifi_d("BSS New Entry");
dump_hex(pbeacon_buf, beacon_buf_size);
#endif
#endif
ret = MLAN_STATUS_SUCCESS;
#ifdef CONFIG_WPA_SUPP
done:
#endif
return ret;
}
/**
* @brief This function generate the bssid from bssid_idx
*
* @param pmadpater A pointer to mlan_adapter structure
* @param pbss_entry A pointer to the bss_entry which has multi-bssid IE
* @param pnew_entry A pinter to new entry
* @param bssid_index bssid_index from BSSID_IDX IE
*
* @return N/A
*/
static void wlan_gen_multi_bssid_by_bssid_index(pmlan_adapter pmadapter,
BSSDescriptor_t *pbss_entry,
BSSDescriptor_t *pnew_entry,
t_u8 bssid_index,
t_u8 max_bssid_indicator)
{
t_u8 mask = 0xff;
t_u8 new_bssid[6];
t_u8 bssid_a;
t_u8 src_bssid[6];
(void)__memcpy(pmadapter, (t_u8 *)src_bssid, pbss_entry->mac_address,
MIN(sizeof(mlan_802_11_mac_addr), sizeof(src_bssid)));
(void)__memcpy(pmadapter, (t_u8 *)new_bssid, (t_u8 *)&pbss_entry->mac_address,
MIN(sizeof(mlan_802_11_mac_addr), sizeof(new_bssid)));
mask = (mask >> (8 - max_bssid_indicator));
bssid_a = src_bssid[5] & (~mask);
src_bssid[5] = (src_bssid[5] + bssid_index) & mask;
new_bssid[5] = bssid_a | src_bssid[5];
(void)__memcpy(pmadapter, (t_u8 *)&pnew_entry->mac_address, new_bssid,
MIN(sizeof(new_bssid), sizeof(mlan_802_11_mac_addr)));
(void)__memcpy(pmadapter, (t_u8 *)&pnew_entry->multi_bssid_ap_addr, (t_u8 *)&pbss_entry->mac_address,
MIN(sizeof(mlan_802_11_mac_addr), sizeof(mlan_802_11_mac_addr)));
}
/**
* @brief This function parse the non_trans_bssid_profile
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pbss_entry A pointer to BSSDescriptor_t which has multi-bssid
* IE
* @param pbss_profile A pointer to IEEEtypes_NonTransBSSIDprofile_t
* @param num_in_table A pointer to buffer to save num of entry in scan
* table.
* @param max_bssid_indicator max bssid indicator
*
* @return N/A
*/
static t_void wlan_parse_non_trans_bssid_profile(mlan_private *pmpriv,
BSSDescriptor_t *pbss_entry,
IEEEtypes_NonTransBSSIDProfile_t *pbss_profile,
t_u32 *num_in_table,
t_u8 max_bssid_indicator)
{
mlan_adapter *pmadapter = pmpriv->adapter;
IEEEtypes_Header_t *pheader = (IEEEtypes_Header_t *)pbss_profile->profile_data;
IEEEtypes_MultiBSSIDIndex_t *pbssid_index = MNULL;
IEEEtypes_Ssid_t *pssid = MNULL;
IEEEtypes_NotxBssCap_t *pcap = (IEEEtypes_NotxBssCap_t *)pbss_profile->profile_data;
t_u8 *pos = pbss_profile->profile_data;
t_s8 left_len = pbss_profile->ieee_hdr.len;
t_u8 ret = MFALSE;
t_u32 bss_idx;
t_u32 lowest_rssi_index = 0;
t_u32 num_in_tbl = *num_in_table;
mlan_callbacks *pcb = (pmlan_callbacks)&pmadapter->callbacks;
BSSDescriptor_t *bss_new_entry = MNULL;
#ifdef CONFIG_WPA_SUPP
t_u8 *pbeacon_buf = MNULL;
#endif
IEEEtypes_ExtCap_t *pextcap = MNULL;
IEEEtypes_Generic_t *prsnx = MNULL;
ENTER();
/* The first element within the Nontransmitted
* BSSID Profile is not the Nontransmitted
* BSSID Capability element.
*/
if (pcap->element_id != NONTX_BSSID_CAP || pcap->len != 2)
{
PRINTM(MERROR,
"The first element within the Nontransmitted BSSID Profile is not the NontransmittedBSSID Capability "
"element\n");
LEAVE();
return;
}
while (left_len >= 2)
{
pheader = (IEEEtypes_Header_t *)pos;
if ((t_s8)(pheader->len + sizeof(IEEEtypes_Header_t)) > left_len)
{
PRINTM(MMSG, "invalid IE length = %d left len %d\n", pheader->len, left_len);
break;
}
switch (pheader->element_id)
{
case MBSSID_INDEX:
pbssid_index = (IEEEtypes_MultiBSSIDIndex_t *)pos;
if (pbssid_index->bssid_index == 0 || pbssid_index->bssid_index > 46)
{
PRINTM(MERROR, " No valid Multiple BSSID-Index element\n");
goto done;
}
PRINTM(MCMND, "MBSSID: Find mbssid_index=%d\n", pbssid_index->bssid_index);
ret = MTRUE;
break;
case EXT_CAPABILITY:
pextcap = (IEEEtypes_ExtCap_t *)pos;
DBG_HEXDUMP(MCMD_D, "MBSSID extcap", pos, pextcap->ieee_hdr.len + sizeof(IEEEtypes_Header_t));
break;
case RSNX_IE:
prsnx = (IEEEtypes_Generic_t *)pos;
DBG_HEXDUMP(MCMD_D, "MBSSID RSNX", pos, prsnx->ieee_hdr.len + sizeof(IEEEtypes_Header_t));
break;
case SSID:
pssid = (IEEEtypes_Ssid_t *)pos;
PRINTM(MCMND, "MBSSID: Find mbssid ssid=%s\n", pssid->ssid);
break;
default:
break;
}
left_len -= pheader->len + sizeof(IEEEtypes_Header_t);
pos += pheader->len + sizeof(IEEEtypes_Header_t);
}
if (ret == MTRUE)
{
ret = pcb->moal_malloc(pmadapter->pmoal_handle, sizeof(BSSDescriptor_t), MLAN_MEM_DEF, (t_u8 **)&bss_new_entry);
if (ret != MLAN_STATUS_SUCCESS || !bss_new_entry)
{
PRINTM(MERROR, "Memory allocation for bss_new_entry failed!\n");
goto done;
}
(void)__memcpy(pmadapter, bss_new_entry, pbss_entry, sizeof(BSSDescriptor_t));
wlan_gen_multi_bssid_by_bssid_index(pmadapter, pbss_entry, bss_new_entry, pbssid_index->bssid_index,
max_bssid_indicator);
if (pssid)
{
__memset(pmadapter, (t_u8 *)&bss_new_entry->ssid, 0, sizeof(mlan_802_11_ssid));
bss_new_entry->ssid.ssid_len = pssid->len;
(void)__memcpy(pmadapter, bss_new_entry->ssid.ssid, pssid->ssid, MIN(pssid->len, MLAN_MAX_SSID_LENGTH));
if (MLAN_STATUS_SUCCESS !=
wlan_update_ssid_in_beacon_buf(pmadapter, pbss_entry, bss_new_entry, pssid, pextcap, prsnx))
{
PRINTM(MERROR, "Fail to update MBSSID beacon buf\n");
pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)bss_new_entry);
goto done;
}
#ifdef CONFIG_WPA_SUPP
pbeacon_buf = bss_new_entry->pbeacon_buf;
#endif
}
(void)__memcpy(pmadapter, &bss_new_entry->cap_info, &pcap->cap,
MIN(sizeof(IEEEtypes_CapInfo_t), sizeof(IEEEtypes_CapInfo_t)));
bss_new_entry->multi_bssid_ap = MULTI_BSSID_SUB_AP;
#ifdef CONFIG_WPA_SUPP
if (pmadapter->wpa_supp_scan_triggered == MTRUE)
{
wifi_d("Alloc ies for Multi BSS. ies_len=%d", bss_new_entry->beacon_buf_size);
bss_new_entry->ies = (u8 *)os_mem_alloc(bss_new_entry->beacon_buf_size - BEACON_FIX_SIZE);
if (bss_new_entry->ies == MNULL)
{
wifi_d("Failed to alloc memory for Multi BSS ies");
goto done;
}
(void)__memcpy(pmadapter, bss_new_entry->ies, bss_new_entry->pbeacon_buf + BEACON_FIX_SIZE,
bss_new_entry->beacon_buf_size - BEACON_FIX_SIZE);
bss_new_entry->ies_len = bss_new_entry->beacon_buf_size;
}
#endif
/*add to scan table*/
/*
* Search the scan table for the same bssid
*/
for (bss_idx = 0; bss_idx < num_in_tbl; 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 (bss_idx == num_in_tbl)
{
/* Range check the bss_idx, keep it limited to the last entry */
if (bss_idx == MRVDRV_MAX_BSSID_LIST)
{
lowest_rssi_index = wlan_find_worst_network_in_list(pmadapter->pscan_table, MRVDRV_MAX_BSSID_LIST);
}
else
{
num_in_tbl++;
}
}
if (bss_idx == MRVDRV_MAX_BSSID_LIST)
{
if (pmadapter->pscan_table[lowest_rssi_index].rssi > bss_new_entry->rssi)
{
#ifdef CONFIG_WPA_SUPP
if (pmadapter->pscan_table[lowest_rssi_index].ies != NULL)
{
os_mem_free(pmadapter->pscan_table[lowest_rssi_index].ies);
pmadapter->pscan_table[lowest_rssi_index].ies = NULL;
}
#endif
(void)__memcpy(pmadapter, &pmadapter->pscan_table[lowest_rssi_index], bss_new_entry,
sizeof(pmadapter->pscan_table[lowest_rssi_index]));
adjust_pointers_to_internal_buffers(&pmadapter->pscan_table[lowest_rssi_index], bss_new_entry);
}
#ifdef CONFIG_WPA_SUPP
/* If the scan table is full, free ies of the new entry with lowest rssi, which won't be added into table */
else
{
if (bss_new_entry->ies != NULL)
{
os_mem_free(bss_new_entry->ies);
bss_new_entry->ies = NULL;
}
}
#endif
}
else
{
/* Copy the locally created bss_new_entry to the scan table */
#ifdef CONFIG_WPA_SUPP
if (pmadapter->pscan_table[bss_idx].ies != NULL)
{
os_mem_free(pmadapter->pscan_table[bss_idx].ies);
pmadapter->pscan_table[bss_idx].ies = NULL;
}
#endif
(void)__memcpy(pmadapter, &pmadapter->pscan_table[bss_idx], bss_new_entry,
sizeof(pmadapter->pscan_table[bss_idx]));
adjust_pointers_to_internal_buffers(&pmadapter->pscan_table[bss_idx], bss_new_entry);
}
#ifdef CONFIG_WPA_SUPP
if (pssid && pbeacon_buf)
pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)pbeacon_buf);
#endif
pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)bss_new_entry);
}
done:
*num_in_table = num_in_tbl;
LEAVE();
return;
}
/**
* @brief This function parse the multi_bssid IE from pbss_entry
*
* @param pmpriv A pointer to mlan_private structure
* @param pbss_entry A pointer to BSSDescriptor_t which has multi-bssid
* IE
* @param num_in_table A pointer to buffer to save num of entry in scan
* table.
*
* @return number entry in scan table
*/
static t_void wlan_parse_multi_bssid_ie(mlan_private *pmpriv,
BSSDescriptor_t *pbss_entry,
IEEEtypes_MultiBSSID_t *pmulti_bssid,
t_u32 *num_in_table)
{
t_u32 bytes_left = 0;
t_u8 *pcurrent_ptr = MNULL;
IEEEtypes_NonTransBSSIDProfile_t *pbssid_profile = MNULL;
if (!pmulti_bssid)
return;
bytes_left = pmulti_bssid->ieee_hdr.len - 1;
pcurrent_ptr = pmulti_bssid->sub_elem_data;
while (bytes_left >= 2)
{
pbssid_profile = (IEEEtypes_NonTransBSSIDProfile_t *)pcurrent_ptr;
if (pbssid_profile->ieee_hdr.element_id != NONTRANS_BSSID_PROFILE_SUBELEM_ID)
{
PRINTM(MERROR, "Invalid multi-bssid IE\n");
break;
}
if (bytes_left < (t_u32)(pbssid_profile->ieee_hdr.len + 2))
{
PRINTM(MERROR, "Invalid multi-bssid IE\n");
break;
}
wlan_parse_non_trans_bssid_profile(pmpriv, pbss_entry, pbssid_profile, num_in_table,
pmulti_bssid->max_bssid_indicator);
pcurrent_ptr += pbssid_profile->ieee_hdr.len + 2;
bytes_left -= pbssid_profile->ieee_hdr.len + 2;
}
return;
}
/**
* @brief This function search all the mbssid IE in the beacon buffer
*
* @param pmpriv A pointer to mlan_private structure
* @param pbss_entry A pointer to BSSDescriptor_t which has multi-bssid
* IE
* @param num_in_table A pointer to buffer to save num of entry in scan
* table.
*
* @return N/A
*/
static void wlan_parse_multi_bssid_ap(mlan_private *pmpriv, BSSDescriptor_t *pbss_entry, t_u32 *num_in_table)
{
IEEEtypes_ElementId_e element_id;
t_u8 element_len;
t_u16 total_ie_len;
t_u32 bytes_left = pbss_entry->beacon_buf_size - BEACON_FIX_SIZE;
t_u8 *pcurrent_ptr = pbss_entry->pbeacon_buf + BEACON_FIX_SIZE;
IEEEtypes_Ssid_t *pssid = (IEEEtypes_Ssid_t *)pcurrent_ptr;
if (pssid->element_id != SSID)
{
PRINTM(MERROR, "Invalid beacon ie, ssid should be in the first element\n");
return;
}
/* Process variable IE */
while (bytes_left >= 2)
{
element_id = (IEEEtypes_ElementId_e)(*((t_u8 *)pcurrent_ptr));
element_len = *((t_u8 *)pcurrent_ptr + 1);
total_ie_len = element_len + sizeof(IEEEtypes_Header_t);
if (bytes_left < total_ie_len)
{
PRINTM(MERROR,
"InterpretIE: Error in processing IE, "
"bytes left < IE length\n");
bytes_left = 0;
continue;
}
if (element_id == MULTI_BSSID)
wlan_parse_multi_bssid_ie(pmpriv, pbss_entry, (IEEEtypes_MultiBSSID_t *)pcurrent_ptr, num_in_table);
pcurrent_ptr += total_ie_len;
bytes_left -= total_ie_len;
}
return;
}
/**
* @brief This function parse and store the extended scan results
*
* @param pmpriv A pointer to mlan_private structure
* @param number_of_sets Number of BSS
* @param pscan_resp A pointer to scan response buffer
* @param scan_resp_size Size of scan response buffer
*
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
static mlan_status wlan_parse_ext_scan_result(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;
const 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_u16 band;
/* t_u32 age_ts_usec; */
t_u32 lowest_rssi_index = 0;
t_u8 null_ssid[MLAN_MAX_SSID_LENGTH] = {0};
ENTER();
pcb = (pmlan_callbacks)&pmadapter->callbacks;
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);
if ((number_of_sets == 0U) && (bytes_left == 0U))
{
wscan_d("SCAN_RESP: number of sets are zero");
goto done;
}
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 */
// coverity[sensitive_memory_access:SUPPRESS]
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:
PRINTM(MINFO, "Unexpected tlv in scan result\n");
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 */
(void)__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 = %02x:%02x:%02x:%02x:%02x:%02x\n", bss_new_entry->mac_address[0],
bss_new_entry->mac_address[1], bss_new_entry->mac_address[2], bss_new_entry->mac_address[3],
bss_new_entry->mac_address[4], bss_new_entry->mac_address[5]);
#ifdef CONFIG_WPA_SUPP
#ifdef CONFIG_WPA_SUPP_WPS
if (pmpriv->wps.session_enable == MTRUE)
{
if ((bss_new_entry->wps_IE_exist == MFALSE) || (bss_new_entry->wps_session == 0xffff))
{
if (bss_new_entry->ies != NULL)
{
os_mem_free(bss_new_entry->ies);
bss_new_entry->ies = NULL;
}
continue;
}
}
#endif /* CONFIG_WPA_SUPP_WPS */
#endif
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));
#if 0
if(bss_new_entry->rssi > 0x7f)
bss_new_entry->rssi = - (256 - bss_new_entry->rssi);
#endif
PRINTM(MINFO, "EXT_SCAN: RSSI=%d\n", bss_new_entry->rssi);
(void)__memcpy(pmpriv->adapter, &tsf_val, &pscan_info_tlv->tsf, sizeof(tsf_val));
tsf_val = wlan_le64_to_cpu(tsf_val);
(void)__memcpy(pmpriv->adapter, &bss_new_entry->network_tsf, &tsf_val,
sizeof(bss_new_entry->network_tsf));
band = radio_type_to_band(pscan_info_tlv->band);
if (bss_new_entry->channel == 0)
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, 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;
if (IS_FW_SUPPORT_MULTIBSSID(pmadapter))
{
if (bss_new_entry->multi_bssid_ap == MULTI_BSSID_AP)
wlan_parse_multi_bssid_ap(pmpriv, bss_new_entry, &num_in_table);
}
/*
* 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, "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)
{
lowest_rssi_index = wlan_find_worst_network_in_list(pmadapter->pscan_table, MRVDRV_MAX_BSSID_LIST);
}
else
{
num_in_table++;
}
}
else
{
if ((bss_new_entry->channel != pmadapter->pscan_table[bss_idx].channel) &&
(bss_new_entry->rssi > pmadapter->pscan_table[bss_idx].rssi))
{
PRINTM(MCMND, "skip update the duplicate entry with low rssi\n");
#ifdef CONFIG_WPA_SUPP
if (bss_new_entry->ies != NULL)
{
os_mem_free(bss_new_entry->ies);
bss_new_entry->ies = NULL;
}
#endif
continue;
}
}
if (bss_idx == MRVDRV_MAX_BSSID_LIST)
{
if (pmadapter->pscan_table[lowest_rssi_index].rssi > bss_new_entry->rssi)
{
#ifdef CONFIG_WPA_SUPP
if (pmadapter->pscan_table[lowest_rssi_index].ies != NULL)
{
os_mem_free(pmadapter->pscan_table[lowest_rssi_index].ies);
pmadapter->pscan_table[lowest_rssi_index].ies = NULL;
}
#endif
(void)__memcpy(pmadapter, &pmadapter->pscan_table[lowest_rssi_index], bss_new_entry,
sizeof(pmadapter->pscan_table[lowest_rssi_index]));
adjust_pointers_to_internal_buffers(&pmadapter->pscan_table[lowest_rssi_index], bss_new_entry);
}
#ifdef CONFIG_WPA_SUPP
/* If the scan table is full, free ies of the new entry with lowest rssi, which won't be added into
* table */
else
{
if (bss_new_entry->ies != NULL)
{
os_mem_free(bss_new_entry->ies);
bss_new_entry->ies = NULL;
}
}
#endif
}
else
{
/* Copy the locally created bss_new_entry to the scan table */
#ifdef CONFIG_WPA_SUPP
if (pmadapter->pscan_table[bss_idx].ies != NULL)
{
os_mem_free(pmadapter->pscan_table[bss_idx].ies);
pmadapter->pscan_table[bss_idx].ies = NULL;
}
#endif
(void)__memcpy(pmadapter, &pmadapter->pscan_table[bss_idx], bss_new_entry,
sizeof(pmadapter->pscan_table[bss_idx]));
adjust_pointers_to_internal_buffers(&pmadapter->pscan_table[bss_idx], bss_new_entry);
}
}
else
{
/* Error parsing/interpreting the scan response, skipped */
PRINTM(MERROR, "EXT_SCAN: wlan_interpret_bss_desc_with_ie returned error\n");
#ifdef CONFIG_WPA_SUPP
if (bss_new_entry->ies != NULL)
{
os_mem_free(bss_new_entry->ies);
bss_new_entry->ies = NULL;
}
#endif
}
}
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;
/* fixme: the following code does not seem relevant */
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 t_u8 *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);
t_u8 *ptlv = (pmbuf + sizeof(mlan_event_scan_result));
t_u16 tlv_buf_left = wlan_cpu_to_le16(pevent_scan->buf_size);
ret = wlan_parse_ext_scan_result(pmpriv, pevent_scan->num_of_set, ptlv, tlv_buf_left);
#if 0
if (!pevent_scan->more_event) {
pioctl_req = pmadapter->pext_scan_ioctl_req;
if (!util_peek_list(pmadapter->pmoal_handle,
&pmadapter->scan_pending_q, pcb->moal_spin_lock,
pcb->moal_spin_unlock)) {
pmadapter->pext_scan_ioctl_req = MNULL;
wlan_request_cmd_lock(pmadapter);
pmadapter->scan_processing = MFALSE;
wlan_release_cmd_lock(pmadapter);
/*
* Process the resulting scan table:
* - Remove any bad ssids
* - Update our current BSS information from scan data
*/
wlan_scan_process_results(pmpriv);
/* 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_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) {
/* Flush all pending scan commands */
wlan_flush_scan_queue(pmadapter);
/* 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);
}
} 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,
pcb->moal_spin_lock,
pcb->moal_spin_unlock);
wlan_insert_cmd_to_pending_q(pmadapter, pcmd_node, MTRUE);
}
}
}
#endif
LEAVE();
return ret;
}
#endif /* CONFIG_EXT_SCAN_SUPPORT */
/**
* @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_u16 cmd_action)
{
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;
const 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;
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 (!wlan_is_band_compatible(pmpriv->config_bands | pmadapter->adhoc_start_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;
if (scan_type == MLAN_SCAN_TYPE_ACTIVE && wlan_11d_support_is_enabled(pmpriv))
{
scan_type = wlan_11d_get_scan_type(pmpriv, pscan_region->band, (t_u8)cfp->channel,
&pmadapter->parsed_region_chan);
}
switch (pscan_region->band)
{
#ifdef CONFIG_5GHz_SUPPORT
case BAND_A:
tlv_chan_list->chan_scan_param[chan_idx].radio_type = HostCmd_SCAN_RADIO_TYPE_A;
if (!wlan_11d_is_enabled(pmpriv))
{
/* 11D not available... play it safe on DFS channels */
if (wlan_11h_radar_detect_required(pmpriv, (t_u8)cfp->channel))
scan_type = MLAN_SCAN_TYPE_PASSIVE;
}
break;
#endif
case BAND_B:
case BAND_G:
if (wlan_bg_scan_type_is_passive(pmpriv, (t_u8)cfp->channel))
scan_type = MLAN_SCAN_TYPE_PASSIVE;
default:
tlv_chan_list->chan_scan_param[chan_idx].radio_type = HostCmd_SCAN_RADIO_TYPE_BG;
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_u16 cmd_action,
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_HTCap_t *pht_cap = MNULL;
#ifdef CONFIG_11AC
MrvlIETypes_VHTCap_t *pvht_cap = MNULL;
#endif
#ifdef CONFIG_11AX
MrvlIEtypes_Extension_t *phe_cap = MNULL;
#endif
MrvlIEtypes_ScanChanGap_t *pscan_gap_tlv;
t_u8 *tlv = MNULL;
t_u16 num_probes = 0;
t_u16 len = 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 max_bgscan_chan = 0;
t_u16 scan_chan_gap = 0;
ENTER();
max_bgscan_chan = WLAN_BG_SCAN_CHAN_MAX;
#ifdef CONFIG_UNII4_BAND_SUPPORT
#if defined(SD9177)
max_bgscan_chan = WLAN_BG_SCAN_CHAN_MAX_UNII_4;
#endif
#endif
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->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;
// coverity[overrun-local:SUPPRESS]
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);
}
scan_chan_gap = (bg_scan_in->scan_chan_gap ? bg_scan_in->scan_chan_gap : pmadapter->scan_chan_gap);
if (scan_chan_gap)
{
pscan_gap_tlv = (MrvlIEtypes_ScanChanGap_t *)tlv;
PRINTM(MCMND, "bgScan: channel gap = 0x%x\n", scan_chan_gap);
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)scan_chan_gap);
/** indicate FW, gap is optional */
pscan_gap_tlv->gap |= GAP_FLAG_OPTIONAL;
tlv += sizeof(pscan_gap_tlv->header) + pscan_gap_tlv->header.len;
cmd_size += sizeof(MrvlIEtypes_ScanChanGap_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((t_s8 *)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;
if (ssid_len != 0U)
{
(void)__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 (!wlan_is_band_compatible(pmpriv->config_bands | pmadapter->adhoc_start_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 */
#ifdef CONFIG_5GHz_SUPPORT
if (radio_type == HostCmd_SCAN_RADIO_TYPE_A)
{
if (wlan_11h_radar_detect_required(pmpriv, bg_scan_in->chan_list[chan_idx].chan_number))
{
scan_type = MLAN_SCAN_TYPE_PASSIVE;
}
}
#endif
if (radio_type == HostCmd_SCAN_RADIO_TYPE_BG)
{
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].radio_type = 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 = MIN(max_bgscan_chan, bg_scan_in->chan_per_scan);
}
else
{
if (bg_scan_in->report_condition & BG_SCAN_WAIT_ALL_CHAN_DONE)
bg_scan->chan_per_scan = chan_num;
else
bg_scan->chan_per_scan = MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN;
}
if (ISSUPP_11NENABLED(pmpriv->adapter->fw_cap_info) && (pmpriv->config_bands & BAND_GN
#ifdef CONFIG_5GHz_SUPPORT
|| pmpriv->config_bands & BAND_AN
#endif
))
{
pht_cap = (MrvlIETypes_HTCap_t *)tlv;
(void)__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);
DBG_HEXDUMP(MCMD_D, "BGSCAN: HT_CAPABILITIES IE", (t_u8 *)pht_cap, sizeof(MrvlIETypes_HTCap_t));
tlv += sizeof(MrvlIETypes_HTCap_t);
cmd_size += sizeof(MrvlIETypes_HTCap_t);
pht_cap->header.len = wlan_cpu_to_le16(pht_cap->header.len);
}
#ifdef CONFIG_11AC
if (ISSUPP_11ACENABLED(pmpriv->adapter->fw_cap_info) && (pmpriv->config_bands & BAND_AAC))
{
pvht_cap = (MrvlIETypes_VHTCap_t *)tlv;
(void)__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);
DBG_HEXDUMP(MCMD_D, "BGSCAN: VHT_CAPABILITIES IE", (t_u8 *)pvht_cap, sizeof(MrvlIETypes_VHTCap_t));
tlv += sizeof(MrvlIETypes_VHTCap_t);
cmd_size += sizeof(MrvlIETypes_VHTCap_t);
pvht_cap->header.len = wlan_cpu_to_le16(pvht_cap->header.len);
}
#endif
#ifdef CONFIG_11AX
if (IS_FW_SUPPORT_11AX(pmadapter) && ((pmpriv->config_bands & BAND_GAX) ||
#ifdef CONFIG_5GHz_SUPPORT
(pmpriv->config_bands & BAND_AAX)
#endif
))
{
phe_cap = (MrvlIEtypes_Extension_t *)tlv;
len = wlan_fill_he_cap_tlv(pmpriv, pmpriv->config_bands, phe_cap, MFALSE);
DBG_HEXDUMP(MCMD_D, "BGSCAN: HE_CAPABILITIES IE", (t_u8 *)phe_cap, len);
tlv += len;
cmd_size += len;
}
#endif
#if defined(CONFIG_DRIVER_MBO) || defined(CONFIG_WPA_SUPP)
wlan_add_ext_capa_info_ie(pmpriv, MNULL, &tlv);
cmd_size += sizeof(MrvlIETypes_ExtCap_t);
#endif
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)
{
#ifdef CONFIG_5GHz_SUPPORT
if (pmpriv->config_bands & BAND_A)
usr_dot_11n_dev_cap = pmadapter->usr_dot_11n_dev_cap_a;
else
#endif
usr_dot_11n_dev_cap = pmadapter->usr_dot_11n_dev_cap_bg;
if (usr_dot_11n_dev_cap & MBIT(17))
{
bandwidth = BW_40MHZ;
#ifdef CONFIG_11AC
if (ISSUPP_11ACENABLED(pmadapter->fw_cap_info) && (pmpriv->config_bands & BAND_AAC))
bandwidth = BW_80MHZ;
#endif
}
wlan_get_curr_oper_class(pmpriv, pmpriv->curr_bss_params.bss_descriptor.channel, bandwidth, &oper_class);
}
len = wlan_add_supported_oper_class_ie(pmpriv, &tlv, oper_class);
cmd_size += len;
}
tlv_start_later = (MrvlIEtypes_StartLater_t *)tlv;
tlv_start_later->header.type = wlan_cpu_to_le16(TLV_TYPE_STARTBGSCANLATER);
tlv_start_later->header.len = wlan_cpu_to_le16(sizeof(MrvlIEtypes_StartLater_t) - sizeof(MrvlIEtypesHeader_t));
tlv_start_later->value = bg_scan_in->start_later;
tlv += sizeof(MrvlIEtypes_StartLater_t);
cmd_size += sizeof(MrvlIEtypes_StartLater_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);
}
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 mlan_bss_mode mode)
{
mlan_adapter *pmadapter = pmpriv->adapter;
t_s32 net = -1, j;
t_u8 best_rssi = 0;
t_u32 i = 0U;
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
*/
while (i < pmadapter->num_in_scan_table && (bssid == MNULL || net < 0))
{
if ((wlan_ssid_cmp(pmadapter, &pmadapter->pscan_table[i].ssid, ssid) == 0) &&
((bssid == MNULL) ||
(__memcmp(pmadapter, pmadapter->pscan_table[i].mac_address, bssid, MLAN_MAC_ADDR_LENGTH) == 0)))
{
if (((mode == MLAN_BSS_MODE_INFRA) &&
(wlan_is_band_compatible(pmpriv->config_bands, pmadapter->pscan_table[i].bss_band) == 0U)) ||
(wlan_find_cfp_by_band_and_channel(pmadapter, pmadapter->pscan_table[i].bss_band,
(t_u16)pmadapter->pscan_table[i].channel) == MNULL))
{
i++;
continue;
}
switch (mode)
{
case MLAN_BSS_MODE_INFRA:
case MLAN_BSS_MODE_IBSS:
j = wlan_is_network_compatible(pmpriv, (t_u32)i, mode);
if (j >= 0)
{
if (SCAN_RSSI(pmadapter->pscan_table[i].rssi) > best_rssi)
{
best_rssi = (t_u8)(SCAN_RSSI(pmadapter->pscan_table[i].rssi));
net = (t_s32)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 = (t_u8)(SCAN_RSSI(pmadapter->pscan_table[i].rssi));
net = (t_s32)i;
}
break;
}
}
i++;
}
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 const t_u8 *bssid, IN mlan_bss_mode mode)
{
mlan_adapter *pmadapter = pmpriv->adapter;
t_s32 net = -1;
t_u32 i = 0U;
ENTER();
if (bssid == MNULL)
{
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
*/
while (i < pmadapter->num_in_scan_table)
{
if ((__memcmp(pmadapter, pmadapter->pscan_table[i].mac_address, bssid, MLAN_MAC_ADDR_LENGTH) == 0))
{
if (((mode == MLAN_BSS_MODE_INFRA) &&
(wlan_is_band_compatible(pmpriv->config_bands, pmadapter->pscan_table[i].bss_band) == 0U)) ||
(wlan_find_cfp_by_band_and_channel(pmadapter, pmadapter->pscan_table[i].bss_band,
(t_u16)pmadapter->pscan_table[i].channel) == MNULL))
{
i++;
continue;
}
switch (mode)
{
case MLAN_BSS_MODE_INFRA:
case MLAN_BSS_MODE_IBSS:
/* fixme: temp disable. enable after below function is enabled */
/* net = wlan_is_network_compatible(pmpriv, i, mode); */
break;
default:
net = (t_s32)i;
if (pmadapter->pscan_table[i].ssid.ssid_len != 0)
break;
}
}
i++;
}
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 == MNULL) || (ssid2 == MNULL))
{
LEAVE();
return -1;
}
if (ssid1->ssid_len != ssid2->ssid_len)
{
LEAVE();
return -1;
}
LEAVE();
return __memcmp(pmadapter, ssid1->ssid, ssid2->ssid, ssid1->ssid_len);
}
static t_u32 wlan_find_worst_network_in_list(const BSSDescriptor_t *pbss_desc, t_u32 num_entries)
{
t_u32 worst_net = 0U;
/* To start with */
t_s32 worst_rssi = pbss_desc[worst_net].rssi;
t_u32 i = 0U;
ENTER();
for (i = 1; i < num_entries; i++)
{
/* Smaller is better i.e. smaller rssi value here means better
signal strength */
if (pbss_desc[i].rssi > worst_rssi)
{
worst_rssi = pbss_desc[i].rssi;
worst_net = i;
}
}
LEAVE();
return worst_net;
}