mwifiex/mxm_wifiex/wlan_src/mlan/mlan_join.c
Sherry Sun 8ffae47921 mxm_wifiex: update to mxm5x17283 release
changes:
1. WCSWREL-191: Fixed the error when loading module param from user config for SD8801
2. WCSWREL-186: Fixed the issue of mlanutl failing on kernel higher than L5.15
3. Fixed low throughput issue for WPA3 SAE
4. Added driver change for WLAN throughput improvement on 8997 SoC
5. Updated README to recommend not to use WEP/TKIP for all chipsets
6. WCSWREL-180: Fix P2P test fail on kernel higher than L5.12
7. WCSWREL-156: kernel_write/kernel_read not allowed by drivers for L5.10 kernel GKI buildou
8. Alternative for pm_qos_add_request/pm_qos_remove_request

Signed-off-by: Sherry Sun <sherry.sun@nxp.com>
Approved-by: Tian Yang <yang.tian@nxp.com>
2021-10-12 12:16:50 +08:00

2644 lines
85 KiB
C

/** @file mlan_join.c
*
* @brief Functions implementing wlan infrastructure and adhoc join routines
*
* IOCTL handlers as well as command preparation and response routines
* for sending adhoc start, adhoc join, and association commands
* to the firmware.
*
*
* Copyright 2008-2021 NXP
*
* This software file (the File) is distributed by NXP
* under the terms of the GNU General Public License Version 2, June 1991
* (the License). You may use, redistribute and/or modify the File in
* accordance with the terms and conditions of the License, a copy of which
* is available by writing to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
* worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
* this warranty disclaimer.
*
*/
/******************************************************
Change log:
10/30/2008: initial version
******************************************************/
#include "mlan.h"
#include "mlan_join.h"
#include "mlan_util.h"
#include "mlan_fw.h"
#include "mlan_main.h"
#include "mlan_wmm.h"
#include "mlan_11n.h"
#include "mlan_11ac.h"
#include "mlan_11ax.h"
#include "mlan_11h.h"
#ifdef DRV_EMBEDDED_SUPPLICANT
#include "authenticator_api.h"
#endif
/********************************************************
Local Constants
********************************************************/
/********************************************************
Local Variables
********************************************************/
/********************************************************
Global Variables
********************************************************/
/********************************************************
Local Functions
********************************************************/
/**
* @brief Append a generic IE as a pass through TLV to a TLV buffer.
*
* This function is called from the network join command prep. routine.
* If the IE buffer has been setup by the application, this routine appends
* the buffer as a pass through TLV type to the request.
*
* @param priv A pointer to mlan_private structure
* @param ppbuffer pointer to command buffer pointer
*
* @return bytes added to the buffer
*/
static int wlan_cmd_append_generic_ie(mlan_private *priv, t_u8 **ppbuffer)
{
int ret_len = 0;
MrvlIEtypesHeader_t ie_header;
ENTER();
/* Null Checks */
if (ppbuffer == MNULL) {
LEAVE();
return 0;
}
if (*ppbuffer == MNULL) {
LEAVE();
return 0;
}
/*
* If there is a generic ie buffer setup, append it to the return
* parameter buffer pointer.
*/
if (priv->gen_ie_buf_len) {
PRINTM(MINFO, "append generic IE %d to %p\n",
priv->gen_ie_buf_len, *ppbuffer);
/* Wrap the generic IE buffer with a pass through TLV type */
ie_header.type = wlan_cpu_to_le16(TLV_TYPE_PASSTHROUGH);
ie_header.len = wlan_cpu_to_le16(priv->gen_ie_buf_len);
memcpy_ext(priv->adapter, *ppbuffer, &ie_header,
sizeof(ie_header), sizeof(ie_header));
/* Increment the return size and the return buffer pointer param
*/
*ppbuffer += sizeof(ie_header);
ret_len += sizeof(ie_header);
/* Copy the generic IE buffer to the output buffer, advance
* pointer */
memcpy_ext(priv->adapter, *ppbuffer, priv->gen_ie_buf,
priv->gen_ie_buf_len, priv->gen_ie_buf_len);
/* Increment the return size and the return buffer pointer param
*/
*ppbuffer += priv->gen_ie_buf_len;
ret_len += priv->gen_ie_buf_len;
/* Reset the generic IE buffer */
priv->gen_ie_buf_len = 0;
}
/* return the length appended to the buffer */
LEAVE();
return ret_len;
}
/**
* @brief Append IE as a pass through TLV to a TLV buffer.
*
* This routine appends IE as a pass through TLV type to the request.
*
* @param priv A pointer to mlan_private structure
* @param ie A pointer to IE buffer
* @param ppbuffer pointer to command buffer pointer
*
* @return bytes added to the buffer
*/
static int wlan_cmd_append_pass_through_ie(mlan_private *priv,
IEEEtypes_Generic_t *ie,
t_u8 **ppbuffer)
{
int ret_len = 0;
MrvlIEtypesHeader_t ie_header;
ENTER();
/* Null Checks */
if (ppbuffer == MNULL) {
LEAVE();
return 0;
}
if (*ppbuffer == MNULL) {
LEAVE();
return 0;
}
if (ie->ieee_hdr.len) {
PRINTM(MINFO, "append generic IE %d to %p\n", ie->ieee_hdr.len,
*ppbuffer);
/* Wrap the generic IE buffer with a pass through TLV type */
ie_header.type = wlan_cpu_to_le16(TLV_TYPE_PASSTHROUGH);
ie_header.len = wlan_cpu_to_le16(ie->ieee_hdr.len +
sizeof(IEEEtypes_Header_t));
memcpy_ext(priv->adapter, *ppbuffer, &ie_header,
sizeof(ie_header), sizeof(ie_header));
/* Increment the return size and the return buffer pointer param
*/
*ppbuffer += sizeof(ie_header);
ret_len += sizeof(ie_header);
/* Copy the generic IE buffer to the output buffer, advance
* pointer */
memcpy_ext(priv->adapter, *ppbuffer, ie,
ie->ieee_hdr.len + sizeof(IEEEtypes_Header_t),
ie->ieee_hdr.len + sizeof(IEEEtypes_Header_t));
/* Increment the return size and the return buffer pointer param
*/
*ppbuffer += ie->ieee_hdr.len + sizeof(IEEEtypes_Header_t);
ret_len += ie->ieee_hdr.len + sizeof(IEEEtypes_Header_t);
}
/* return the length appended to the buffer */
LEAVE();
return ret_len;
}
/**
* @brief Append TSF tracking info from the scan table for the target AP
*
* This function is called from the network join command prep. routine.
* The TSF table TSF sent to the firmware contains two TSF values:
* - the TSF of the target AP from its previous beacon/probe response
* - the TSF timestamp of our local MAC at the time we observed the
* beacon/probe response.
*
* The firmware uses the timestamp values to set an initial TSF value
* in the MAC for the new association after a reassociation attempt.
*
* @param pmpriv A pointer to mlan_private structure
* @param ppbuffer A pointer to command buffer pointer
* @param pbss_desc A pointer to the BSS Descriptor from the scan table of
* the AP we are trying to join
*
* @return bytes added to the buffer
*/
static int wlan_cmd_append_tsf_tlv(mlan_private *pmriv, t_u8 **ppbuffer,
BSSDescriptor_t *pbss_desc)
{
MrvlIEtypes_TsfTimestamp_t tsf_tlv;
t_u64 tsf_val;
ENTER();
/* Null Checks */
if (ppbuffer == MNULL) {
LEAVE();
return 0;
}
if (*ppbuffer == MNULL) {
LEAVE();
return 0;
}
memset(pmriv->adapter, &tsf_tlv, 0x00,
sizeof(MrvlIEtypes_TsfTimestamp_t));
tsf_tlv.header.type = wlan_cpu_to_le16(TLV_TYPE_TSFTIMESTAMP);
tsf_tlv.header.len = wlan_cpu_to_le16(2 * sizeof(tsf_val));
memcpy_ext(pmriv->adapter, *ppbuffer, &tsf_tlv, sizeof(tsf_tlv.header),
sizeof(tsf_tlv.header));
*ppbuffer += sizeof(tsf_tlv.header);
/* TSF timestamp from the firmware TSF when the bcn/prb rsp was received
*/
tsf_val = wlan_cpu_to_le64(pbss_desc->network_tsf);
memcpy_ext(pmriv->adapter, *ppbuffer, &tsf_val, sizeof(tsf_val),
sizeof(tsf_val));
*ppbuffer += sizeof(tsf_val);
memcpy_ext(pmriv->adapter, &tsf_val, pbss_desc->time_stamp,
sizeof(pbss_desc->time_stamp), sizeof(tsf_val));
PRINTM(MINFO, "ASSOC: TSF offset calc: %016llx - %016llx\n", tsf_val,
pbss_desc->network_tsf);
memcpy_ext(pmriv->adapter, *ppbuffer, &tsf_val, sizeof(tsf_val),
sizeof(tsf_val));
*ppbuffer += sizeof(tsf_val);
LEAVE();
return sizeof(tsf_tlv.header) + (2 * sizeof(tsf_val));
}
/**
* @brief This function finds out the common rates between rate1 and rate2.
*
* It will fill common rates in rate1 as output if found.
*
* NOTE: Setting the MSB of the basic rates needs to be taken
* care of, either before or after calling this function
*
* @param pmpriv A pointer to mlan_private structure
* @param rate1 the buffer which keeps input and output
* @param rate1_size the size of rate1 buffer
* @param rate2 the buffer which keeps rate2
* @param rate2_size the size of rate2 buffer.
*
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
static mlan_status wlan_get_common_rates(mlan_private *pmpriv, t_u8 *rate1,
t_u32 rate1_size, t_u8 *rate2,
t_u32 rate2_size)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_callbacks *pcb = (mlan_callbacks *)&pmpriv->adapter->callbacks;
t_u8 *ptr = rate1;
t_u8 *tmp = MNULL;
t_u32 i, j;
ENTER();
ret = pcb->moal_malloc(pmpriv->adapter->pmoal_handle, rate1_size,
MLAN_MEM_DEF, &tmp);
if (ret != MLAN_STATUS_SUCCESS || !tmp) {
PRINTM(MERROR, "Failed to allocate buffer\n");
ret = MLAN_STATUS_FAILURE;
goto done;
}
memcpy_ext(pmpriv->adapter, tmp, rate1, rate1_size, rate1_size);
memset(pmpriv->adapter, rate1, 0, rate1_size);
for (i = 0; rate2[i] && i < rate2_size; i++) {
for (j = 0; tmp[j] && j < rate1_size; j++) {
/* Check common rate, excluding the bit
* for basic rate */
if ((rate2[i] & 0x7F) == (tmp[j] & 0x7F)) {
*rate1++ = tmp[j];
break;
}
}
}
HEXDUMP("rate1 (AP) Rates", tmp, rate1_size);
HEXDUMP("rate2 (Card) Rates", rate2, rate2_size);
HEXDUMP("Common Rates", ptr, rate1 - ptr);
PRINTM(MINFO, "Tx DataRate is set to 0x%X\n", pmpriv->data_rate);
if (!pmpriv->is_data_rate_auto) {
while (*ptr) {
if ((*ptr & 0x7f) == pmpriv->data_rate) {
ret = MLAN_STATUS_SUCCESS;
goto done;
}
ptr++;
}
PRINTM(MMSG,
"Previously set fixed data rate %#x is not "
"compatible with the network\n",
pmpriv->data_rate);
ret = MLAN_STATUS_FAILURE;
goto done;
}
ret = MLAN_STATUS_SUCCESS;
done:
if (tmp)
pcb->moal_mfree(pmpriv->adapter->pmoal_handle, tmp);
LEAVE();
return ret;
}
/**
* @brief Create the intersection of the rates supported by a target BSS and
* our pmadapter settings for use in an assoc/join command.
*
* @param pmpriv A pointer to mlan_private structure
* @param pbss_desc BSS Descriptor whose rates are used in the setup
* @param pout_rates Output: Octet array of rates common between the BSS
* and the pmadapter supported rates settings
* @param pout_rates_size Output: Number of rates/octets set in pout_rates
*
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
static mlan_status wlan_setup_rates_from_bssdesc(mlan_private *pmpriv,
BSSDescriptor_t *pbss_desc,
t_u8 *pout_rates,
t_u32 *pout_rates_size)
{
t_u8 card_rates[WLAN_SUPPORTED_RATES];
t_u32 card_rates_size = 0;
ENTER();
/* Copy AP supported rates */
memcpy_ext(pmpriv->adapter, pout_rates, pbss_desc->supported_rates,
WLAN_SUPPORTED_RATES, WLAN_SUPPORTED_RATES);
if ((pmpriv->adapter->region_code == COUNTRY_CODE_JP_40 ||
pmpriv->adapter->region_code == COUNTRY_CODE_JP_FF) &&
(pbss_desc->phy_param_set.ds_param_set.current_chan == 14)) {
/* Special Case: For Japan, 11G rates on CH14 are not allowed*/
card_rates_size = wlan_get_supported_rates(
pmpriv, pmpriv->bss_mode, BAND_B, card_rates);
} else {
/* Get the STA supported rates */
card_rates_size =
wlan_get_supported_rates(pmpriv, pmpriv->bss_mode,
pmpriv->config_bands,
card_rates);
}
/* Get the common rates between AP and STA supported rates */
if (wlan_get_common_rates(pmpriv, pout_rates, WLAN_SUPPORTED_RATES,
card_rates, card_rates_size)) {
*pout_rates_size = 0;
PRINTM(MERROR, "wlan_get_common_rates failed\n");
LEAVE();
return MLAN_STATUS_FAILURE;
}
*pout_rates_size =
MIN(wlan_strlen((char *)pout_rates), WLAN_SUPPORTED_RATES);
LEAVE();
return MLAN_STATUS_SUCCESS;
}
/**
* @brief Update the scan entry TSF timestamps to reflect a new association
*
* @param pmpriv A pointer to mlan_private structure
* @param pnew_bss_desc A pointer to the newly associated AP's scan table entry
*
* @return N/A
*/
static t_void wlan_update_tsf_timestamps(mlan_private *pmpriv,
BSSDescriptor_t *pnew_bss_desc)
{
mlan_adapter *pmadapter = pmpriv->adapter;
t_u32 table_idx;
t_u64 new_tsf_base;
t_s64 tsf_delta;
ENTER();
memcpy_ext(pmpriv->adapter, &new_tsf_base, pnew_bss_desc->time_stamp,
sizeof(pnew_bss_desc->time_stamp), sizeof(new_tsf_base));
tsf_delta = new_tsf_base - pnew_bss_desc->network_tsf;
PRINTM(MINFO, "TSF: Update TSF timestamps, 0x%016llx -> 0x%016llx\n",
pnew_bss_desc->network_tsf, new_tsf_base);
for (table_idx = 0; table_idx < pmadapter->num_in_scan_table;
table_idx++) {
pmadapter->pscan_table[table_idx].network_tsf += tsf_delta;
}
LEAVE();
}
/**
* @brief Append a wapi IE
*
* This function is called from the network join command prep. routine.
* If the IE buffer has been setup by the application, this routine appends
* the buffer as a wapi TLV type to the request.
*
* @param priv A pointer to mlan_private structure
* @param ppbuffer pointer to command buffer pointer
*
* @return bytes added to the buffer
*/
static int wlan_cmd_append_wapi_ie(mlan_private *priv, t_u8 **ppbuffer)
{
int retlen = 0;
MrvlIEtypesHeader_t ie_header;
ENTER();
/* Null Checks */
if (ppbuffer == MNULL) {
LEAVE();
return 0;
}
if (*ppbuffer == MNULL) {
LEAVE();
return 0;
}
/*
* If there is a wapi ie buffer setup, append it to the return
* parameter buffer pointer.
*/
if (priv->wapi_ie_len) {
PRINTM(MCMND, "append wapi ie %d to %p\n", priv->wapi_ie_len,
*ppbuffer);
/* Wrap the generic IE buffer with a pass through TLV type */
ie_header.type = wlan_cpu_to_le16(TLV_TYPE_WAPI_IE);
ie_header.len = wlan_cpu_to_le16(priv->wapi_ie_len);
memcpy_ext(priv->adapter, *ppbuffer, &ie_header,
sizeof(ie_header), sizeof(ie_header));
/* Increment the return size and the return buffer pointer param
*/
*ppbuffer += sizeof(ie_header);
retlen += sizeof(ie_header);
/* Copy the wapi IE buffer to the output buffer, advance pointer
*/
memcpy_ext(priv->adapter, *ppbuffer, priv->wapi_ie,
priv->wapi_ie_len, priv->wapi_ie_len);
/* Increment the return size and the return buffer pointer param
*/
*ppbuffer += priv->wapi_ie_len;
retlen += priv->wapi_ie_len;
}
/* return the length appended to the buffer */
LEAVE();
return retlen;
}
/**
* @brief Append a osen IE
*
* This function is called from the network join command prep. routine.
* If the IE buffer has been setup by the application, this routine appends
* the buffer as a osen TLV type to the request.
*
* @param priv A pointer to mlan_private structure
* @param ppbuffer pointer to command buffer pointer
*
* @return bytes added to the buffer
*/
static int wlan_cmd_append_osen_ie(mlan_private *priv, t_u8 **ppbuffer)
{
int retlen = 0;
MrvlIEtypesHeader_t ie_header;
ENTER();
/* Null Checks */
if (ppbuffer == MNULL) {
LEAVE();
return 0;
}
if (*ppbuffer == MNULL) {
LEAVE();
return 0;
}
/*
* If there is a osen ie buffer setup, append it to the return
* parameter buffer pointer.
*/
if (priv->osen_ie_len) {
PRINTM(MCMND, "append osen ie %d to %p\n", priv->osen_ie_len,
*ppbuffer);
/* Wrap the generic IE buffer with a pass through TLV type */
ie_header.type = wlan_cpu_to_le16(TLV_TYPE_VENDOR_SPECIFIC_IE);
ie_header.len = wlan_cpu_to_le16(priv->osen_ie[1]);
memcpy_ext(priv->adapter, *ppbuffer, &ie_header,
sizeof(ie_header), sizeof(ie_header));
/* Increment the return size and the return buffer pointer param
*/
*ppbuffer += sizeof(ie_header);
retlen += sizeof(ie_header);
/* Copy the osen IE buffer to the output buffer, advance pointer
*/
memcpy_ext(priv->adapter, *ppbuffer, &priv->osen_ie[2],
priv->osen_ie[1], priv->osen_ie[1]);
/* Increment the return size and the return buffer pointer param
*/
*ppbuffer += priv->osen_ie[1];
retlen += priv->osen_ie[1];
}
/* return the length appended to the buffer */
LEAVE();
return retlen;
}
/**
* @brief This function get the rsn_cap from RSN ie buffer.
*
* @param pmpriv A pointer to mlan_private structure
*
* @param data A pointer to rsn_ie data after IE header
* @param return rsn_cap
*/
static t_u16 wlan_get_rsn_cap(t_u8 *data)
{
t_u16 rsn_cap = 0;
t_u16 *ptr;
t_u16 pairwise_cipher_count = 0;
t_u16 akm_suite_count = 0;
/* rsn_cap = data + 2 bytes version + 4 bytes
* group_cipher_suite + 2 bytes pairwise_cipher_count +
* pairwise_cipher_count * PAIRWISE_CIPHER_SUITE_LEN + 2 bytes
* akm_suite_count + akm_suite_count * AKM_SUITE_LEN
*/
ptr = (t_u16 *)(data + sizeof(t_u16) + 4 * sizeof(t_u8));
pairwise_cipher_count = wlan_le16_to_cpu(*ptr);
ptr = (t_u16 *)(data + sizeof(t_u16) + 4 * sizeof(t_u8) +
sizeof(t_u16) +
pairwise_cipher_count * PAIRWISE_CIPHER_SUITE_LEN);
akm_suite_count = wlan_le16_to_cpu(*ptr);
ptr = (t_u16 *)(data + sizeof(t_u16) + 4 * sizeof(t_u8) +
sizeof(t_u16) +
pairwise_cipher_count * PAIRWISE_CIPHER_SUITE_LEN +
sizeof(t_u16) + akm_suite_count * AKM_SUITE_LEN);
rsn_cap = wlan_le16_to_cpu(*ptr);
PRINTM(MCMND, "rsn_cap=0x%x\n", rsn_cap);
return rsn_cap;
}
/**
* @brief This function check if we should enable 11w
*
* @param pmpriv A pointer to mlan_private structure
*
* @param BSSDescriptor_t A pointer to BSSDescriptor_t data structure
* @param return MTRUE/MFALSE
*/
static t_u8 wlan_use_mfp(mlan_private *pmpriv, BSSDescriptor_t *pbss_desc)
{
t_u16 ap_rsn_cap = 0;
t_u16 sta_rsn_cap = 0;
t_u8 ap_mfpc, ap_mfpr;
t_u8 sta_mfpc, sta_mfpr;
if (pmpriv->wpa_ie[0] != RSN_IE)
return 0;
sta_rsn_cap = wlan_get_rsn_cap(pmpriv->wpa_ie + 2);
if (!pbss_desc->prsn_ie)
return 0;
ap_rsn_cap = wlan_get_rsn_cap(pbss_desc->prsn_ie->data);
ap_mfpc = ((ap_rsn_cap & (0x1 << MFPC_BIT)) == (0x1 << MFPC_BIT));
ap_mfpr = ((ap_rsn_cap & (0x1 << MFPR_BIT)) == (0x1 << MFPR_BIT));
sta_mfpc = ((sta_rsn_cap & (0x1 << MFPC_BIT)) == (0x1 << MFPC_BIT));
sta_mfpr = ((sta_rsn_cap & (0x1 << MFPR_BIT)) == (0x1 << MFPR_BIT));
if (!ap_mfpc && !ap_mfpr)
return MFALSE;
if (!sta_mfpc && !sta_mfpr)
return MFALSE;
return MTRUE;
}
/********************************************************
Global Functions
********************************************************/
/**
* @brief This function updates RSN IE in the association request.
*
* @param pmpriv A pointer to mlan_private structure
*
* @param ptlv_rsn_ie A pointer to rsn_ie TLV
*/
static int wlan_update_rsn_ie(mlan_private *pmpriv,
MrvlIEtypes_RsnParamSet_t *ptlv_rsn_ie)
{
t_u16 *prsn_cap;
t_u16 *ptr;
t_u16 *akm_suite_count_ptr;
t_u16 pmf_mask = 0x00;
t_u8 *temp;
t_u16 pairwise_cipher_count = 0;
t_u16 akm_suite_count = 0;
t_u16 temp_akm_suite_count = 0;
int found = 0;
t_u8 sha_256_oui[4] = {0x00, 0x0f, 0xac, 0x06};
t_u8 sae_oui[4] = {0x00, 0x0f, 0xac, 0x08};
mlan_adapter *pmadapter = pmpriv->adapter;
int ap_mfpc = 0, ap_mfpr = 0, ret = MLAN_STATUS_SUCCESS;
pmf_mask = (((pmpriv->pmfcfg.mfpc << MFPC_BIT) |
(pmpriv->pmfcfg.mfpr << MFPR_BIT)) |
(~PMF_MASK));
/* prsn_cap = prsn_ie->rsn_ie + 2 bytes version + 4 bytes
* group_cipher_suite + 2 bytes pairwise_cipher_count +
* pairwise_cipher_count * PAIRWISE_CIPHER_SUITE_LEN + 2 bytes
* akm_suite_count + akm_suite_count * AKM_SUITE_LEN
*/
ptr = (t_u16 *)(ptlv_rsn_ie->rsn_ie + sizeof(t_u16) + 4 * sizeof(t_u8));
pairwise_cipher_count = wlan_le16_to_cpu(*ptr);
ptr = (t_u16 *)(ptlv_rsn_ie->rsn_ie + sizeof(t_u16) + 4 * sizeof(t_u8) +
sizeof(t_u16) +
pairwise_cipher_count * PAIRWISE_CIPHER_SUITE_LEN);
temp_akm_suite_count = wlan_le16_to_cpu(*ptr);
akm_suite_count = wlan_le16_to_cpu(*ptr);
/* Save pointer to akm_suite_count in RSN IE to update it later */
akm_suite_count_ptr = ptr;
temp = ptlv_rsn_ie->rsn_ie + sizeof(t_u16) + 4 * sizeof(t_u8) +
sizeof(t_u16) +
pairwise_cipher_count * PAIRWISE_CIPHER_SUITE_LEN +
sizeof(t_u16);
/* ptr now points to the 1st AKM suite */
if (temp_akm_suite_count > 1) {
while (temp_akm_suite_count) {
if (pmpriv->sec_info.authentication_mode ==
MLAN_AUTH_MODE_SAE) {
if (!memcmp(pmadapter, temp, sae_oui,
AKM_SUITE_LEN)) {
found = 1;
break;
}
} else if (!memcmp(pmadapter, temp, sha_256_oui,
AKM_SUITE_LEN)) {
found = 1;
break;
}
temp += AKM_SUITE_LEN;
temp_akm_suite_count--;
}
if (found) {
/* Copy SHA256 as AKM suite */
memcpy_ext(pmadapter,
ptlv_rsn_ie->rsn_ie +
(sizeof(t_u16) + 4 * sizeof(t_u8) +
sizeof(t_u16) +
pairwise_cipher_count *
PAIRWISE_CIPHER_SUITE_LEN +
sizeof(t_u16)),
temp, AKM_SUITE_LEN, AKM_SUITE_LEN);
/* Shift remaining bytes of RSN IE after this */
memmove(pmadapter,
ptlv_rsn_ie->rsn_ie +
(sizeof(t_u16) + 4 * sizeof(t_u8) +
sizeof(t_u16) +
pairwise_cipher_count *
PAIRWISE_CIPHER_SUITE_LEN +
sizeof(t_u16) + AKM_SUITE_LEN),
ptlv_rsn_ie->rsn_ie +
(sizeof(t_u16) + 4 * sizeof(t_u8) +
sizeof(t_u16) +
pairwise_cipher_count *
PAIRWISE_CIPHER_SUITE_LEN +
sizeof(t_u16) +
akm_suite_count * AKM_SUITE_LEN),
ptlv_rsn_ie->header.len -
(sizeof(t_u16) + 4 * sizeof(t_u8) +
sizeof(t_u16) +
pairwise_cipher_count *
PAIRWISE_CIPHER_SUITE_LEN +
sizeof(t_u16) +
akm_suite_count * AKM_SUITE_LEN));
ptlv_rsn_ie->header.len =
ptlv_rsn_ie->header.len -
(akm_suite_count - 1) * AKM_SUITE_LEN;
/* Update akm suite count */
akm_suite_count = 1;
*akm_suite_count_ptr = akm_suite_count;
}
}
ptr = (t_u16 *)(ptlv_rsn_ie->rsn_ie + sizeof(t_u16) + 4 * sizeof(t_u8) +
sizeof(t_u16) +
pairwise_cipher_count * PAIRWISE_CIPHER_SUITE_LEN +
sizeof(t_u16) + akm_suite_count * AKM_SUITE_LEN);
prsn_cap = ptr;
ap_mfpc = ((*prsn_cap & (0x1 << MFPC_BIT)) == (0x1 << MFPC_BIT));
ap_mfpr = ((*prsn_cap & (0x1 << MFPR_BIT)) == (0x1 << MFPR_BIT));
if ((!ap_mfpc && !ap_mfpr && pmpriv->pmfcfg.mfpr) ||
((!ap_mfpc) && ap_mfpr) ||
(ap_mfpc && ap_mfpr && (!pmpriv->pmfcfg.mfpc))) {
PRINTM(MERROR,
"Mismatch in PMF config of STA and AP, can't associate to AP\n");
return MLAN_STATUS_FAILURE;
}
if ((pmpriv->pmfcfg.mfpr && pmpriv->pmfcfg.mfpc) ||
pmpriv->pmfcfg.mfpc) {
*prsn_cap |= PMF_MASK;
*prsn_cap &= pmf_mask;
}
return ret;
}
/**
* @brief This function is to find FT AKM in RSN.
*
* @param pmpriv A pointer to mlan_private structure
*
* @param rsn_ie A pointer to rsn_ie
*
*/
t_u8 wlan_ft_akm_is_used(mlan_private *pmpriv, t_u8 *rsn_ie)
{
t_u8 *temp;
t_u16 count;
t_u16 pairwise_cipher_count = 0;
t_u16 akm_suite_count = 0;
t_u8 found = 0;
t_u8 rsn_ft_1x_oui[4] = {0x00, 0x0f, 0xac, 0x03};
t_u8 rsn_ft_psk_oui[4] = {0x00, 0x0f, 0xac, 0x04};
t_u8 rsn_ft_sae_oui[4] = {0x00, 0x0f, 0xac, 0x09};
mlan_adapter *pmadapter = pmpriv->adapter;
ENTER();
if (!rsn_ie)
goto done;
if (rsn_ie[0] != RSN_IE)
goto done;
/* 2 bytes header + 2 bytes version + 4 bytes group_cipher_suite +
* 2 bytes pairwise_cipher_count + pairwise_cipher_count *
* PAIRWISE_CIPHER_SUITE_LEN (4) + 2 bytes akm_suite_count +
* akm_suite_count * AKM_SUITE_LEN (4)
*/
count = *(t_u16 *)(rsn_ie + 2 + 2 + 4 * sizeof(t_u8));
pairwise_cipher_count = wlan_le16_to_cpu(count);
count = *(t_u16 *)(rsn_ie + 2 + 2 + 4 * sizeof(t_u8) + sizeof(t_u16) +
pairwise_cipher_count * 4);
akm_suite_count = wlan_le16_to_cpu(count);
temp = (t_u8 *)(rsn_ie + 2 + sizeof(t_u16) + 4 * sizeof(t_u8) +
sizeof(t_u16) + pairwise_cipher_count * 4 +
sizeof(t_u16));
while (akm_suite_count) {
if (!memcmp(pmadapter, temp, rsn_ft_1x_oui,
sizeof(rsn_ft_1x_oui)) ||
!memcmp(pmadapter, temp, rsn_ft_psk_oui,
sizeof(rsn_ft_psk_oui)) ||
!memcmp(pmadapter, temp, rsn_ft_sae_oui,
sizeof(rsn_ft_sae_oui))) {
found = 1;
break;
}
temp += 4;
akm_suite_count--;
}
done:
LEAVE();
return found;
}
/**
* @brief This function is to find specific IE.
*
* @param ie A pointer to ie buffer
* @param ie_len Length of ie buffer
* @param ie_type Type of ie that wants to be found in ie buffer
*
* @return MFALSE if not found; MTURE if found
*/
static t_u8 wlan_find_ie(t_u8 *ie, t_u8 ie_len, t_u8 ie_type)
{
IEEEtypes_Header_t *pheader = MNULL;
t_u8 *pos = MNULL;
t_s8 ret_len;
t_u8 ret = MFALSE;
ENTER();
pos = (t_u8 *)ie;
ret_len = ie_len;
while (ret_len >= 2) {
pheader = (IEEEtypes_Header_t *)pos;
if ((t_s8)(pheader->len + sizeof(IEEEtypes_Header_t)) >
ret_len) {
PRINTM(MMSG, "invalid IE length = %d left len %d\n",
pheader->len, ret_len);
break;
}
if (pheader->element_id == ie_type) {
ret = MTRUE;
break;
}
ret_len -= pheader->len + sizeof(IEEEtypes_Header_t);
pos += pheader->len + sizeof(IEEEtypes_Header_t);
}
LEAVE();
return ret;
}
/**
* @brief This function prepares command of association.
*
* @param pmpriv A pointer to mlan_private structure
* @param cmd A pointer to HostCmd_DS_COMMAND structure
* @param pdata_buf A pointer cast of BSSDescriptor_t from the
* scan table to assoc
*
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
mlan_status wlan_cmd_802_11_associate(mlan_private *pmpriv,
HostCmd_DS_COMMAND *cmd,
t_void *pdata_buf)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_adapter *pmadapter = pmpriv->adapter;
HostCmd_DS_802_11_ASSOCIATE *passo = &cmd->params.associate;
BSSDescriptor_t *pbss_desc;
MrvlIEtypes_SsIdParamSet_t *pssid_tlv;
MrvlIEtypes_PhyParamSet_t *pphy_tlv;
MrvlIEtypes_SsParamSet_t *pss_tlv;
MrvlIEtypes_RatesParamSet_t *prates_tlv;
MrvlIEtypes_AuthType_t *pauth_tlv;
MrvlIEtypes_RsnParamSet_t *prsn_ie_tlv = MNULL;
MrvlIEtypes_SecurityCfg_t *psecurity_cfg_ie = MNULL;
MrvlIEtypes_ChanListParamSet_t *pchan_tlv;
WLAN_802_11_RATES rates;
t_u32 rates_size;
t_u16 tmp_cap;
t_u8 *pos;
#ifdef DRV_EMBEDDED_SUPPLICANT
void *rsn_wpa_ie_tmp = MNULL;
#endif
t_u8 ft_akm = 0;
t_u8 oper_class;
t_u8 oper_class_flag = MFALSE;
MrvlIEtypes_HostMlme_t *host_mlme_tlv = MNULL;
MrvlIEtypes_PrevBssid_t *prev_bssid_tlv = MNULL;
t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = {0};
ENTER();
pbss_desc = (BSSDescriptor_t *)pdata_buf;
pos = (t_u8 *)passo;
cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_ASSOCIATE);
/* Save so we know which BSS Desc to use in the response handler */
pmpriv->pattempted_bss_desc = pbss_desc;
/* clear assoc_rsp_size */
pmpriv->assoc_rsp_size = 0;
memcpy_ext(pmadapter, passo->peer_sta_addr, pbss_desc->mac_address,
sizeof(pbss_desc->mac_address),
sizeof(passo->peer_sta_addr));
pos += sizeof(passo->peer_sta_addr);
/* Set the listen interval */
passo->listen_interval = wlan_cpu_to_le16(pmpriv->listen_interval);
/* Set the beacon period */
passo->beacon_period = wlan_cpu_to_le16(pbss_desc->beacon_period);
pos += sizeof(passo->cap_info);
pos += sizeof(passo->listen_interval);
pos += sizeof(passo->beacon_period);
pos += sizeof(passo->dtim_period);
pssid_tlv = (MrvlIEtypes_SsIdParamSet_t *)pos;
pssid_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_SSID);
pssid_tlv->header.len = (t_u16)pbss_desc->ssid.ssid_len;
memcpy_ext(pmadapter, pssid_tlv->ssid, pbss_desc->ssid.ssid,
pssid_tlv->header.len, pssid_tlv->header.len);
pos += sizeof(pssid_tlv->header) + pssid_tlv->header.len;
pssid_tlv->header.len = wlan_cpu_to_le16(pssid_tlv->header.len);
pphy_tlv = (MrvlIEtypes_PhyParamSet_t *)pos;
pphy_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_PHY_DS);
pphy_tlv->header.len = sizeof(pphy_tlv->fh_ds.ds_param_set);
memcpy_ext(pmadapter, &pphy_tlv->fh_ds.ds_param_set,
&pbss_desc->phy_param_set.ds_param_set.current_chan,
sizeof(pphy_tlv->fh_ds.ds_param_set),
sizeof(pphy_tlv->fh_ds.ds_param_set));
pos += sizeof(pphy_tlv->header) + pphy_tlv->header.len;
pphy_tlv->header.len = wlan_cpu_to_le16(pphy_tlv->header.len);
pss_tlv = (MrvlIEtypes_SsParamSet_t *)pos;
pss_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_CF);
pss_tlv->header.len = sizeof(pss_tlv->cf_ibss.cf_param_set);
pos += sizeof(pss_tlv->header) + pss_tlv->header.len;
pss_tlv->header.len = wlan_cpu_to_le16(pss_tlv->header.len);
/* Get the common rates supported between the driver and the BSS Desc */
if (wlan_setup_rates_from_bssdesc(pmpriv, pbss_desc, rates,
&rates_size)) {
ret = MLAN_STATUS_FAILURE;
goto done;
}
/* Save the data rates into Current BSS state structure */
pmpriv->curr_bss_params.num_of_rates = rates_size;
memcpy_ext(pmadapter, &pmpriv->curr_bss_params.data_rates, rates,
rates_size, WLAN_SUPPORTED_RATES);
/* Setup the Rates TLV in the association command */
prates_tlv = (MrvlIEtypes_RatesParamSet_t *)pos;
prates_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_RATES);
prates_tlv->header.len = wlan_cpu_to_le16((t_u16)rates_size);
memcpy_ext(pmadapter, prates_tlv->rates, rates, rates_size, rates_size);
pos += sizeof(prates_tlv->header) + rates_size;
PRINTM(MINFO, "ASSOC_CMD: Rates size = %d\n", rates_size);
/* Add the Authentication type to be used for Auth frames if needed */
if ((pmpriv->sec_info.authentication_mode != MLAN_AUTH_MODE_AUTO)) {
pauth_tlv = (MrvlIEtypes_AuthType_t *)pos;
pauth_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_AUTH_TYPE);
pauth_tlv->header.len = sizeof(pauth_tlv->auth_type);
if ((pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled) ||
(pmpriv->sec_info.authentication_mode ==
MLAN_AUTH_MODE_NETWORKEAP))
pauth_tlv->auth_type = wlan_cpu_to_le16(
(t_u16)pmpriv->sec_info.authentication_mode);
else if (pmpriv->sec_info.authentication_mode ==
MLAN_AUTH_MODE_FT)
pauth_tlv->auth_type =
wlan_cpu_to_le16(AssocAgentAuth_FastBss_Skip);
else if (pmpriv->sec_info.authentication_mode ==
MLAN_AUTH_MODE_SAE)
pauth_tlv->auth_type =
wlan_cpu_to_le16(AssocAgentAuth_Wpa3Sae);
else
pauth_tlv->auth_type =
wlan_cpu_to_le16(MLAN_AUTH_MODE_OPEN);
pos += sizeof(pauth_tlv->header) + pauth_tlv->header.len;
pauth_tlv->header.len = wlan_cpu_to_le16(pauth_tlv->header.len);
}
if (IS_SUPPORT_MULTI_BANDS(pmadapter) &&
(pbss_desc->bss_band & pmpriv->config_bands) &&
!(ISSUPP_11NENABLED(pmadapter->fw_cap_info) &&
(!pbss_desc->disable_11n) &&
(pmpriv->config_bands & BAND_GN ||
pmpriv->config_bands & BAND_AN) &&
(pbss_desc->pht_cap))) {
/* Append a channel TLV for the channel the attempted AP was
* found on */
pchan_tlv = (MrvlIEtypes_ChanListParamSet_t *)pos;
pchan_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
pchan_tlv->header.len =
wlan_cpu_to_le16(sizeof(ChanScanParamSet_t));
memset(pmadapter, pchan_tlv->chan_scan_param, 0x00,
sizeof(ChanScanParamSet_t));
pchan_tlv->chan_scan_param[0].chan_number =
(pbss_desc->phy_param_set.ds_param_set.current_chan);
PRINTM(MINFO, "Assoc: TLV Chan = %d\n",
pchan_tlv->chan_scan_param[0].chan_number);
pchan_tlv->chan_scan_param[0].bandcfg.chanBand =
wlan_band_to_radio_type((t_u8)pbss_desc->bss_band);
PRINTM(MINFO, "Assoc: TLV Bandcfg = %x\n",
pchan_tlv->chan_scan_param[0].bandcfg);
pos += sizeof(pchan_tlv->header) + sizeof(ChanScanParamSet_t);
}
if (!pmpriv->wps.session_enable) {
if ((pmpriv->sec_info.wpa_enabled ||
pmpriv->sec_info.wpa2_enabled)) {
prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *)pos;
/* WPA_IE or RSN_IE */
prsn_ie_tlv->header.type = (t_u16)pmpriv->wpa_ie[0];
prsn_ie_tlv->header.type =
prsn_ie_tlv->header.type & 0x00FF;
prsn_ie_tlv->header.type =
wlan_cpu_to_le16(prsn_ie_tlv->header.type);
prsn_ie_tlv->header.len = (t_u16)pmpriv->wpa_ie[1];
prsn_ie_tlv->header.len =
prsn_ie_tlv->header.len & 0x00FF;
if (prsn_ie_tlv->header.len <=
(sizeof(pmpriv->wpa_ie) - 2))
memcpy_ext(pmadapter, prsn_ie_tlv->rsn_ie,
&pmpriv->wpa_ie[2],
prsn_ie_tlv->header.len,
prsn_ie_tlv->header.len);
else {
ret = MLAN_STATUS_FAILURE;
goto done;
}
HEXDUMP("ASSOC_CMD: RSN IE", (t_u8 *)prsn_ie_tlv,
sizeof(prsn_ie_tlv->header) +
prsn_ie_tlv->header.len);
pos += sizeof(prsn_ie_tlv->header) +
prsn_ie_tlv->header.len;
prsn_ie_tlv->header.len =
wlan_cpu_to_le16(prsn_ie_tlv->header.len);
/** parse rsn ie to find whether ft akm is used*/
ft_akm = wlan_ft_akm_is_used(pmpriv, pmpriv->wpa_ie);
/* Append PMF Configuration coming from cfg80211 layer
*/
psecurity_cfg_ie = (MrvlIEtypes_SecurityCfg_t *)pos;
psecurity_cfg_ie->header.type =
wlan_cpu_to_le16(TLV_TYPE_SECURITY_CFG);
pmpriv->curr_bss_params.use_mfp =
wlan_use_mfp(pmpriv, pbss_desc);
PRINTM(MCMND, "use_mfp=%d\n",
pmpriv->curr_bss_params.use_mfp);
if (!pmpriv->curr_bss_params.use_mfp)
psecurity_cfg_ie->use_mfp = MFALSE;
else
psecurity_cfg_ie->use_mfp = MTRUE;
psecurity_cfg_ie->header.len = sizeof(t_u8);
pos += sizeof(psecurity_cfg_ie->header) +
psecurity_cfg_ie->header.len;
}
#ifdef DRV_EMBEDDED_SUPPLICANT
else if (supplicantIsEnabled(pmpriv->psapriv)) {
supplicantClrEncryptKey(pmpriv->psapriv);
if (pbss_desc->prsn_ie)
rsn_wpa_ie_tmp = pbss_desc->prsn_ie;
else if (pbss_desc->pwpa_ie)
rsn_wpa_ie_tmp = pbss_desc->pwpa_ie;
prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *)pos;
pos += supplicantFormatRsnWpaTlv(
pmpriv->psapriv, rsn_wpa_ie_tmp, prsn_ie_tlv);
}
#endif
else if (pmpriv->sec_info.ewpa_enabled) {
prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *)pos;
if (pbss_desc->pwpa_ie) {
prsn_ie_tlv->header.type =
(t_u16)(*(pbss_desc->pwpa_ie))
.vend_hdr.element_id;
prsn_ie_tlv->header.type =
prsn_ie_tlv->header.type & 0x00FF;
prsn_ie_tlv->header.type = wlan_cpu_to_le16(
prsn_ie_tlv->header.type);
prsn_ie_tlv->header.len =
(t_u16)(*(pbss_desc->pwpa_ie))
.vend_hdr.len;
prsn_ie_tlv->header.len =
prsn_ie_tlv->header.len & 0x00FF;
if (prsn_ie_tlv->header.len <=
(sizeof(pmpriv->wpa_ie))) {
memcpy_ext(pmadapter,
prsn_ie_tlv->rsn_ie,
&((*(pbss_desc->pwpa_ie))
.vend_hdr.oui[0]),
prsn_ie_tlv->header.len,
prsn_ie_tlv->header.len);
} else {
ret = MLAN_STATUS_FAILURE;
goto done;
}
HEXDUMP("ASSOC_CMD: RSN IE",
(t_u8 *)prsn_ie_tlv,
sizeof(prsn_ie_tlv->header) +
prsn_ie_tlv->header.len);
pos += sizeof(prsn_ie_tlv->header) +
prsn_ie_tlv->header.len;
prsn_ie_tlv->header.len = wlan_cpu_to_le16(
prsn_ie_tlv->header.len);
}
if (pbss_desc->prsn_ie) {
prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *)pos;
prsn_ie_tlv->header.type =
(t_u16)(*(pbss_desc->prsn_ie))
.ieee_hdr.element_id;
prsn_ie_tlv->header.type =
prsn_ie_tlv->header.type & 0x00FF;
prsn_ie_tlv->header.type = wlan_cpu_to_le16(
prsn_ie_tlv->header.type);
prsn_ie_tlv->header.len =
(t_u16)(*(pbss_desc->prsn_ie))
.ieee_hdr.len;
prsn_ie_tlv->header.len =
prsn_ie_tlv->header.len & 0x00FF;
if (prsn_ie_tlv->header.len <=
(sizeof(pmpriv->wpa_ie))) {
memcpy_ext(pmadapter,
prsn_ie_tlv->rsn_ie,
&((*(pbss_desc->prsn_ie))
.data[0]),
prsn_ie_tlv->header.len,
prsn_ie_tlv->header.len);
ret = wlan_update_rsn_ie(pmpriv,
prsn_ie_tlv);
if (ret != MLAN_STATUS_SUCCESS) {
goto done;
}
} else {
ret = MLAN_STATUS_FAILURE;
goto done;
}
HEXDUMP("ASSOC_CMD: RSN IE",
(t_u8 *)prsn_ie_tlv,
sizeof(prsn_ie_tlv->header) +
prsn_ie_tlv->header.len);
pos += sizeof(prsn_ie_tlv->header) +
prsn_ie_tlv->header.len;
prsn_ie_tlv->header.len = wlan_cpu_to_le16(
prsn_ie_tlv->header.len);
}
}
}
if (ISSUPP_11NENABLED(pmadapter->fw_cap_info) &&
(!pbss_desc->disable_11n) &&
wlan_11n_bandconfig_allowed(pmpriv, pbss_desc->bss_band))
wlan_cmd_append_11n_tlv(pmpriv, pbss_desc, &pos);
else if ((pmpriv->hotspot_cfg & HOTSPOT_ENABLED) &&
!(pmpriv->hotspot_cfg & HOTSPOT_BY_SUPPLICANT))
wlan_add_ext_capa_info_ie(pmpriv, pbss_desc, &pos);
if (pmpriv->adapter->ecsa_enable) {
oper_class_flag =
wlan_find_ie(pmpriv->gen_ie_buf, pmpriv->gen_ie_buf_len,
REGULATORY_CLASS);
if (!oper_class_flag) {
if (MLAN_STATUS_SUCCESS ==
wlan_get_curr_oper_class(
pmpriv,
pbss_desc->phy_param_set.ds_param_set
.current_chan,
pbss_desc->curr_bandwidth, &oper_class))
wlan_add_supported_oper_class_ie(pmpriv, &pos,
oper_class);
}
}
if (ISSUPP_11ACENABLED(pmadapter->fw_cap_info) &&
(!pbss_desc->disable_11n) &&
wlan_11ac_bandconfig_allowed(pmpriv, pbss_desc->bss_band))
wlan_cmd_append_11ac_tlv(pmpriv, pbss_desc, &pos);
if ((IS_FW_SUPPORT_11AX(pmadapter)) && (!pbss_desc->disable_11n) &&
wlan_11ax_bandconfig_allowed(pmpriv, pbss_desc->bss_band))
wlan_cmd_append_11ax_tlv(pmpriv, pbss_desc, &pos);
wlan_wmm_process_association_req(pmpriv, &pos, &pbss_desc->wmm_ie,
pbss_desc->pht_cap);
if (pmpriv->sec_info.wapi_enabled && pmpriv->wapi_ie_len)
wlan_cmd_append_wapi_ie(pmpriv, &pos);
if (pmpriv->sec_info.osen_enabled && pmpriv->osen_ie_len)
wlan_cmd_append_osen_ie(pmpriv, &pos);
wlan_cmd_append_generic_ie(pmpriv, &pos);
if (ft_akm && pbss_desc->pmd_ie)
wlan_cmd_append_pass_through_ie(
pmpriv, (IEEEtypes_Generic_t *)pbss_desc->pmd_ie, &pos);
wlan_cmd_append_tsf_tlv(pmpriv, &pos, pbss_desc);
if (pmpriv->curr_bss_params.host_mlme) {
host_mlme_tlv = (MrvlIEtypes_HostMlme_t *)pos;
host_mlme_tlv->header.type =
wlan_cpu_to_le16(TLV_TYPE_HOST_MLME);
host_mlme_tlv->header.len =
wlan_cpu_to_le16(sizeof(host_mlme_tlv->host_mlme));
host_mlme_tlv->host_mlme = MTRUE;
pos += sizeof(host_mlme_tlv->header) +
host_mlme_tlv->header.len;
}
if (memcmp(pmadapter, &pmpriv->curr_bss_params.prev_bssid, zero_mac,
MLAN_MAC_ADDR_LENGTH)) {
prev_bssid_tlv = (MrvlIEtypes_PrevBssid_t *)pos;
prev_bssid_tlv->header.type =
wlan_cpu_to_le16(TLV_TYPE_PREV_BSSID);
prev_bssid_tlv->header.len = MLAN_MAC_ADDR_LENGTH;
memcpy_ext(pmadapter, prev_bssid_tlv->prev_bssid,
&pmpriv->curr_bss_params.prev_bssid,
MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
PRINTM(MCMND, "ASSOCIATE: PREV_BSSID = " MACSTR "\n",
MAC2STR(pmpriv->curr_bss_params.prev_bssid));
pos += sizeof(prev_bssid_tlv->header) + MLAN_MAC_ADDR_LENGTH;
}
if (wlan_11d_create_dnld_countryinfo(pmpriv,
(t_u8)pbss_desc->bss_band)) {
PRINTM(MERROR, "Dnld_countryinfo_11d failed\n");
ret = MLAN_STATUS_FAILURE;
goto done;
}
if (wlan_11d_parse_dnld_countryinfo(pmpriv,
pmpriv->pattempted_bss_desc)) {
ret = MLAN_STATUS_FAILURE;
goto done;
}
/*
* Call 11h join API after capability bits are set so adhoc/infra 11h
* behavior can be properly triggered. pos modified if data is appended
*/
wlan_11h_process_join(
pmpriv, &pos, &passo->cap_info, (t_u8)pbss_desc->bss_band,
pbss_desc->phy_param_set.ds_param_set.current_chan,
&pbss_desc->wlan_11h_bss_info);
cmd->size = wlan_cpu_to_le16((t_u16)(pos - (t_u8 *)passo) + S_DS_GEN);
/* Set the Capability info at last */
memcpy_ext(pmadapter, &tmp_cap, &pbss_desc->cap_info,
sizeof(passo->cap_info), sizeof(tmp_cap));
if (pmpriv->config_bands == BAND_B)
SHORT_SLOT_TIME_DISABLED(tmp_cap);
tmp_cap &= CAPINFO_MASK;
PRINTM(MINFO, "ASSOC_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n", tmp_cap,
CAPINFO_MASK);
tmp_cap = wlan_cpu_to_le16(tmp_cap);
memcpy_ext(pmadapter, &passo->cap_info, &tmp_cap, sizeof(tmp_cap),
sizeof(passo->cap_info));
done:
LEAVE();
return ret;
}
/**
* @brief Association firmware command response handler
*
* The response buffer for the association command has the following
* memory layout.
*
* For cases where an association response was not received (indicated
* by the CapInfo and AId field):
*
* .------------------------------------------------------------.
* | Header(4 * sizeof(t_u16)): Standard command response hdr |
* .------------------------------------------------------------.
* | cap_info/Error Return(t_u16): |
* | 0xFFFF(-1): Internal error for association |
* | 0xFFFE(-2): Authentication unhandled message |
* | 0xFFFD(-3): Authentication refused |
* | 0xFFFC(-4): Timeout waiting for AP response |
* | 0xFFFB(-5): Internal error for authentication |
* .------------------------------------------------------------.
* | status_code(t_u16): |
* | If cap_info is -1: |
* | An internal firmware failure prevented the |
* | command from being processed. The status code |
* | is 6 if associate response parameter invlaid, |
* | 1 otherwise. |
* | |
* | If cap_info is -2: |
* | An authentication frame was received but was |
* | not handled by the firmware. IEEE Status code |
* | for the failure is returned. |
* | |
* | If cap_info is -3: |
* | An authentication frame was received and the |
* | status_code is the IEEE Status reported in the |
* | response. |
* | |
* | If cap_info is -4: |
* | (1) Association response timeout |
* | (2) Authentication response timeout |
* | |
* | If cap_info is -5: |
* | An internal firmware failure prevented the |
* | command from being processed. The status code |
* | is 6 if authentication parameter invlaid, |
* | 1 otherwise. |
* .------------------------------------------------------------.
* | a_id(t_u16): 0xFFFF |
* .------------------------------------------------------------.
*
*
* For cases where an association response was received, the IEEE
* standard association response frame is returned:
*
* .------------------------------------------------------------.
* | Header(4 * sizeof(t_u16)): Standard command response hdr |
* .------------------------------------------------------------.
* | cap_info(t_u16): IEEE Capability |
* .------------------------------------------------------------.
* | status_code(t_u16): IEEE Status Code |
* .------------------------------------------------------------.
* | a_id(t_u16): IEEE Association ID |
* .------------------------------------------------------------.
* | IEEE IEs(variable): Any received IEs comprising the |
* | remaining portion of a received |
* | association response frame. |
* .------------------------------------------------------------.
*
* For simplistic handling, the status_code field can be used to determine
* an association success (0) or failure (non-zero).
*
* @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_associate(mlan_private *pmpriv,
HostCmd_DS_COMMAND *resp,
t_void *pioctl_buf)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_ioctl_req *pioctl_req = (mlan_ioctl_req *)pioctl_buf;
IEEEtypes_AssocRsp_t *passoc_rsp;
BSSDescriptor_t *pbss_desc;
t_u8 enable_data = MTRUE;
t_u8 event_buf[100];
mlan_event *pevent = (mlan_event *)event_buf;
t_u8 cur_mac[MLAN_MAC_ADDR_LENGTH];
t_u8 media_connected = pmpriv->media_connected;
mlan_adapter *pmadapter = pmpriv->adapter;
assoc_logger_data *assoc_succ;
mlan_ds_bss *bss;
IEEEtypes_MgmtHdr_t *hdr;
ENTER();
if (pmpriv->curr_bss_params.host_mlme) {
hdr = (IEEEtypes_MgmtHdr_t *)&resp->params;
if (!memcmp(pmpriv->adapter, hdr->BssId,
pmpriv->pattempted_bss_desc->mac_address,
MLAN_MAC_ADDR_LENGTH))
passoc_rsp = (IEEEtypes_AssocRsp_t
*)((t_u8 *)(&resp->params) +
sizeof(IEEEtypes_MgmtHdr_t));
else
passoc_rsp = (IEEEtypes_AssocRsp_t *)&resp->params;
} else
passoc_rsp = (IEEEtypes_AssocRsp_t *)&resp->params;
passoc_rsp->status_code = wlan_le16_to_cpu(passoc_rsp->status_code);
if (pmpriv->media_connected == MTRUE)
memcpy_ext(pmpriv->adapter, cur_mac,
pmpriv->curr_bss_params.bss_descriptor.mac_address,
MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
HEXDUMP("ASSOC_RESP:", (t_u8 *)&resp->params, (resp->size - S_DS_GEN));
pmpriv->assoc_rsp_size =
MIN(resp->size - S_DS_GEN, sizeof(pmpriv->assoc_rsp_buf));
memcpy_ext(pmpriv->adapter, pmpriv->assoc_rsp_buf, &resp->params,
pmpriv->assoc_rsp_size, pmpriv->assoc_rsp_size);
if (pioctl_req != MNULL) {
bss = (mlan_ds_bss *)pioctl_req->pbuf;
bss->param.ssid_bssid.assoc_rsp.assoc_resp_len =
pmpriv->assoc_rsp_size;
memcpy_ext(pmpriv->adapter,
bss->param.ssid_bssid.assoc_rsp.assoc_resp_buf,
pmpriv->assoc_rsp_buf, pmpriv->assoc_rsp_size,
ASSOC_RSP_BUF_SIZE);
}
if (passoc_rsp->status_code) {
if (pmpriv->media_connected == MTRUE) {
if (pmpriv->port_ctrl_mode == MTRUE)
pmpriv->port_open = pmpriv->prior_port_status;
if (!memcmp(pmpriv->adapter, cur_mac,
pmpriv->pattempted_bss_desc->mac_address,
MLAN_MAC_ADDR_LENGTH))
wlan_reset_connect_state(pmpriv, MTRUE);
else
wlan_recv_event(
pmpriv,
MLAN_EVENT_ID_DRV_ASSOC_FAILURE_REPORT,
MNULL);
} else
wlan_reset_connect_state(pmpriv, MTRUE);
pmpriv->adapter->dbg.num_cmd_assoc_failure++;
pmpriv->adapter->dbg.num_cons_assoc_failure++;
PRINTM(MERROR,
"ASSOC_RESP: Association Failed, "
"status code = %d, error = 0x%x, a_id = 0x%x\n",
passoc_rsp->status_code,
wlan_le16_to_cpu(*(t_u16 *)&passoc_rsp->capability),
wlan_le16_to_cpu(passoc_rsp->a_id));
memset(pmadapter, event_buf, 0, sizeof(event_buf));
pevent->bss_index = pmpriv->bss_index;
pevent->event_id = MLAN_EVENT_ID_DRV_ASSOC_FAILURE_LOGGER;
pevent->event_len = sizeof(passoc_rsp->status_code);
memcpy_ext(pmpriv->adapter, (t_u8 *)pevent->event_buf,
&passoc_rsp->status_code, pevent->event_len,
pevent->event_len);
wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_ASSOC_FAILURE_LOGGER,
pevent);
ret = MLAN_STATUS_FAILURE;
goto done;
}
/* Send a Media Connected event, according to the Spec */
pmpriv->media_connected = MTRUE;
pmpriv->adapter->pps_uapsd_mode = MFALSE;
pmpriv->adapter->tx_lock_flag = MFALSE;
pmpriv->adapter->delay_null_pkt = MFALSE;
/* Set the attempted BSSID Index to current */
pbss_desc = pmpriv->pattempted_bss_desc;
PRINTM(MCMND, "ASSOC_RESP: %-32s (a_id = 0x%x)\n", pbss_desc->ssid.ssid,
wlan_le16_to_cpu(passoc_rsp->a_id));
/* Restore default extended capabilities */
memcpy_ext(pmpriv->adapter, &pmpriv->ext_cap, &pmpriv->def_ext_cap,
sizeof(pmpriv->ext_cap), sizeof(pmpriv->ext_cap));
/* Make a copy of current BSSID descriptor */
memcpy_ext(pmpriv->adapter, &pmpriv->curr_bss_params.bss_descriptor,
pbss_desc, sizeof(BSSDescriptor_t), sizeof(BSSDescriptor_t));
/* Update curr_bss_params */
pmpriv->curr_bss_params.bss_descriptor.channel =
pbss_desc->phy_param_set.ds_param_set.current_chan;
pmpriv->curr_bss_params.band = (t_u8)pbss_desc->bss_band;
/* Store current channel for further reference.
* This would save one extra call to get current
* channel when disconnect/bw_ch event is raised.
*/
pmpriv->adapter->dfsr_channel =
pmpriv->curr_bss_params.bss_descriptor.channel;
/*
* Adjust the timestamps in the scan table to be relative to the newly
* associated AP's TSF
*/
wlan_update_tsf_timestamps(pmpriv, pbss_desc);
if (pbss_desc->wmm_ie.vend_hdr.element_id == WMM_IE)
pmpriv->curr_bss_params.wmm_enabled = MTRUE;
else
pmpriv->curr_bss_params.wmm_enabled = MFALSE;
if ((pmpriv->wmm_required ||
(pbss_desc->pht_cap &&
(pbss_desc->pht_cap->ieee_hdr.element_id == HT_CAPABILITY))) &&
pmpriv->curr_bss_params.wmm_enabled)
pmpriv->wmm_enabled = MTRUE;
else
pmpriv->wmm_enabled = MFALSE;
pmpriv->curr_bss_params.wmm_uapsd_enabled = MFALSE;
if (pmpriv->wmm_enabled == MTRUE)
pmpriv->curr_bss_params.wmm_uapsd_enabled =
pbss_desc->wmm_ie.qos_info.qos_uapsd;
PRINTM(MINFO, "ASSOC_RESP: curr_pkt_filter is 0x%x\n",
pmpriv->curr_pkt_filter);
if (pmpriv->sec_info.wpa_enabled || pmpriv->sec_info.wpa2_enabled)
pmpriv->wpa_is_gtk_set = MFALSE;
if (pmpriv->wmm_enabled)
/* Don't re-enable carrier until we get the WMM_GET_STATUS event
*/
enable_data = MFALSE;
else
/* Since WMM is not enabled, setup the queues with the defaults
*/
wlan_wmm_setup_queues(pmpriv);
if (enable_data)
PRINTM(MINFO, "Post association, re-enabling data flow\n");
/* Reset SNR/NF/RSSI values */
pmpriv->data_rssi_last = 0;
pmpriv->data_nf_last = 0;
pmpriv->data_rssi_avg = 0;
pmpriv->data_nf_avg = 0;
pmpriv->bcn_rssi_last = 0;
pmpriv->bcn_nf_last = 0;
pmpriv->bcn_rssi_avg = 0;
pmpriv->bcn_nf_avg = 0;
pmpriv->rxpd_rate = 0;
pmpriv->rxpd_rate_info = 0;
/* Reset mib statistics*/
pmpriv->amsdu_rx_cnt = 0;
pmpriv->amsdu_tx_cnt = 0;
pmpriv->msdu_in_rx_amsdu_cnt = 0;
pmpriv->msdu_in_tx_amsdu_cnt = 0;
if (pbss_desc->pvht_cap && pbss_desc->pht_cap) {
if (GET_VHTCAP_MAXMPDULEN(
pbss_desc->pvht_cap->vht_cap.vht_cap_info) == 2)
pmpriv->max_amsdu = MLAN_TX_DATA_BUF_SIZE_12K;
else if (GET_VHTCAP_MAXMPDULEN(
pbss_desc->pvht_cap->vht_cap.vht_cap_info) ==
1)
pmpriv->max_amsdu = MLAN_TX_DATA_BUF_SIZE_8K;
else
pmpriv->max_amsdu = MLAN_TX_DATA_BUF_SIZE_4K;
} else if (pbss_desc->pht_cap) {
if (GETHT_MAXAMSDU(pbss_desc->pht_cap->ht_cap.ht_cap_info))
pmpriv->max_amsdu = MLAN_TX_DATA_BUF_SIZE_8K;
else
pmpriv->max_amsdu = MLAN_TX_DATA_BUF_SIZE_4K;
}
wlan_save_curr_bcn(pmpriv);
pmpriv->adapter->dbg.num_cmd_assoc_success++;
pmpriv->adapter->dbg.num_cons_assoc_failure = 0;
PRINTM(MINFO, "ASSOC_RESP: Associated\n");
pevent->bss_index = pmpriv->bss_index;
pevent->event_id = MLAN_EVENT_ID_DRV_CONNECTED;
pevent->event_len = MLAN_MAC_ADDR_LENGTH;
memcpy_ext(pmpriv->adapter, (t_u8 *)pevent->event_buf,
(t_u8 *)pmpriv->curr_bss_params.bss_descriptor.mac_address,
MLAN_MAC_ADDR_LENGTH, pevent->event_len);
/* Add the ra_list here for infra mode as there will be only 1 ra always
*/
if (media_connected) {
/** replace ralist's mac address with new mac address */
if (0 ==
wlan_ralist_update(
pmpriv, cur_mac,
pmpriv->curr_bss_params.bss_descriptor.mac_address))
wlan_ralist_add(pmpriv,
pmpriv->curr_bss_params.bss_descriptor
.mac_address);
wlan_11n_cleanup_reorder_tbl(pmpriv);
wlan_11n_deleteall_txbastream_tbl(pmpriv);
} else
wlan_ralist_add(
pmpriv,
pmpriv->curr_bss_params.bss_descriptor.mac_address);
wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_CONNECTED, pevent);
/* Send OBSS scan param to the application if available */
wlan_2040_coex_event(pmpriv);
wlan_coex_ampdu_rxwinsize(pmpriv->adapter);
if (!pmpriv->sec_info.wpa_enabled && !pmpriv->sec_info.wpa2_enabled &&
!pmpriv->sec_info.ewpa_enabled && !pmpriv->sec_info.wapi_enabled &&
!pmpriv->wps.session_enable && !pmpriv->sec_info.osen_enabled
#ifdef DRV_EMBEDDED_SUPPLICANT
&& !supplicantIsEnabled(pmpriv->psapriv)
#endif
) {
/* We are in Open/WEP mode, open port immediately */
if (pmpriv->port_ctrl_mode == MTRUE) {
pmpriv->port_open = MTRUE;
PRINTM(MINFO, "ASSOC_RESP: port_status = OPEN\n");
}
}
if (pmpriv->sec_info.wpa_enabled || pmpriv->sec_info.wpa2_enabled ||
pmpriv->sec_info.ewpa_enabled || pmpriv->sec_info.wapi_enabled ||
pmpriv->wps.session_enable || pmpriv->sec_info.osen_enabled
#ifdef DRV_EMBEDDED_SUPPLICANT
|| (supplicantIsEnabled(pmpriv->psapriv))
#endif
)
pmpriv->adapter->scan_block = MTRUE;
#ifdef DRV_EMBEDDED_SUPPLICANT
supplicantInitSession(
pmpriv->psapriv,
(t_u8 *)&pmpriv->curr_bss_params.bss_descriptor.ssid.ssid,
pmpriv->curr_bss_params.bss_descriptor.ssid.ssid_len,
(t_u8 *)&pmpriv->curr_bss_params.bss_descriptor.mac_address,
(t_u8 *)&pmpriv->curr_addr);
#endif
pevent = (mlan_event *)event_buf;
memset(pmadapter, event_buf, 0, sizeof(event_buf));
pevent->bss_index = pmpriv->bss_index;
pevent->event_id = MLAN_EVENT_ID_DRV_ASSOC_SUCC_LOGGER;
pevent->event_len = sizeof(assoc_logger_data);
assoc_succ = (assoc_logger_data *)pevent->event_buf;
memcpy_ext(pmpriv->adapter, (t_u8 *)assoc_succ->bssid,
pbss_desc->mac_address, MLAN_MAC_ADDR_LENGTH,
MLAN_MAC_ADDR_LENGTH);
memcpy_ext(pmpriv->adapter, (t_u8 *)assoc_succ->oui,
pbss_desc->mac_address, MLAN_MAC_ADDR_LENGTH / 2,
MLAN_MAC_ADDR_LENGTH / 2);
memcpy_ext(pmpriv->adapter, (t_u8 *)assoc_succ->ssid,
pbss_desc->ssid.ssid, pbss_desc->ssid.ssid_len,
MLAN_MAX_SSID_LENGTH);
assoc_succ->rssi = pbss_desc->rssi;
assoc_succ->channel = pbss_desc->channel;
wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_ASSOC_SUCC_LOGGER, pevent);
done:
/* Need to indicate IOCTL complete */
if (pioctl_req != MNULL) {
if (ret != MLAN_STATUS_SUCCESS) {
if (passoc_rsp->status_code)
pioctl_req->status_code =
(wlan_le16_to_cpu(*(t_u16 *)&passoc_rsp
->capability)
<< 16) +
passoc_rsp->status_code;
else
pioctl_req->status_code =
MLAN_ERROR_CMD_ASSOC_FAIL;
} else {
pioctl_req->status_code = MLAN_ERROR_NO_ERROR;
}
}
LEAVE();
return ret;
}
/**
* @brief This function prepares command of ad_hoc_start.
*
* @param pmpriv A pointer to mlan_private structure
* @param cmd A pointer to HostCmd_DS_COMMAND structure
* @param pdata_buf A pointer cast of mlan_802_11_ssid structure
*
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
mlan_status wlan_cmd_802_11_ad_hoc_start(mlan_private *pmpriv,
HostCmd_DS_COMMAND *cmd,
t_void *pdata_buf)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_adapter *pmadapter = pmpriv->adapter;
HostCmd_DS_802_11_AD_HOC_START *padhoc_start = &cmd->params.adhoc_start;
BSSDescriptor_t *pbss_desc;
t_u32 cmd_append_size = 0;
t_u32 i;
t_u16 tmp_cap;
MrvlIEtypes_ChanListParamSet_t *pchan_tlv;
MrvlIEtypes_RsnParamSet_t *prsn_ie_tlv;
/* wpa ie for WPA_NONE AES */
const t_u8 wpa_ie[24] = {0xdd, 0x16, 0x00, 0x50, 0xf2, 0x01,
0x01, 0x00, 0x00, 0x50, 0xf2, 0x04,
0x01, 0x00, 0x00, 0x50, 0xf2, 0x00,
0x01, 0x00, 0x00, 0x50, 0xf2, 0x00};
t_s32 append_size_11h = 0;
t_u8 *pos =
(t_u8 *)padhoc_start + sizeof(HostCmd_DS_802_11_AD_HOC_START);
ENTER();
if (!pmadapter) {
ret = MLAN_STATUS_FAILURE;
goto done;
}
cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_START);
pbss_desc = &pmpriv->curr_bss_params.bss_descriptor;
pmpriv->pattempted_bss_desc = pbss_desc;
/*
* Fill in the parameters for 2 data structures:
* 1. HostCmd_DS_802_11_AD_HOC_START command
* 2. pbss_desc
* Driver will fill up SSID, bss_mode,IBSS param, Physical Param,
* probe delay, and Cap info.
* Firmware will fill up beacon period, Basic rates
* and operational rates.
*/
memset(pmadapter, padhoc_start->ssid, 0, MLAN_MAX_SSID_LENGTH);
memcpy_ext(pmadapter, padhoc_start->ssid,
((mlan_802_11_ssid *)pdata_buf)->ssid,
((mlan_802_11_ssid *)pdata_buf)->ssid_len,
MLAN_MAX_SSID_LENGTH);
PRINTM(MINFO, "ADHOC_S_CMD: SSID = %s\n", padhoc_start->ssid);
memset(pmadapter, pbss_desc->ssid.ssid, 0, MLAN_MAX_SSID_LENGTH);
memcpy_ext(pmadapter, pbss_desc->ssid.ssid,
((mlan_802_11_ssid *)pdata_buf)->ssid,
((mlan_802_11_ssid *)pdata_buf)->ssid_len,
MLAN_MAX_SSID_LENGTH);
pbss_desc->ssid.ssid_len =
MIN(MLAN_MAX_SSID_LENGTH,
((mlan_802_11_ssid *)pdata_buf)->ssid_len);
/* Set the BSS mode */
padhoc_start->bss_mode = HostCmd_BSS_MODE_IBSS;
pbss_desc->bss_mode = MLAN_BSS_MODE_IBSS;
padhoc_start->beacon_period = wlan_cpu_to_le16(pmpriv->beacon_period);
pbss_desc->beacon_period = pmpriv->beacon_period;
/* Set Physical param set */
/** Parameter IE Id */
#define DS_PARA_IE_ID 3
/** Parameter IE length */
#define DS_PARA_IE_LEN 1
padhoc_start->phy_param_set.ds_param_set.element_id = DS_PARA_IE_ID;
padhoc_start->phy_param_set.ds_param_set.len = DS_PARA_IE_LEN;
if (!wlan_get_cfp_by_band_and_channel(
pmadapter, pmadapter->adhoc_start_band,
(t_u16)pmpriv->adhoc_channel, pmadapter->region_channel)) {
chan_freq_power_t *cfp;
cfp = wlan_get_cfp_by_band_and_channel(
pmadapter, pmadapter->adhoc_start_band,
FIRST_VALID_CHANNEL, pmadapter->region_channel);
if (cfp)
pmpriv->adhoc_channel = (t_u8)cfp->channel;
}
MASSERT(pmpriv->adhoc_channel);
PRINTM(MINFO, "ADHOC_S_CMD: Creating ADHOC on Channel %d\n",
pmpriv->adhoc_channel);
pmpriv->curr_bss_params.bss_descriptor.channel = pmpriv->adhoc_channel;
pmpriv->curr_bss_params.band = pmadapter->adhoc_start_band;
pbss_desc->channel = pmpriv->adhoc_channel;
padhoc_start->phy_param_set.ds_param_set.current_chan =
pmpriv->adhoc_channel;
memcpy_ext(pmadapter, &pbss_desc->phy_param_set,
&padhoc_start->phy_param_set,
sizeof(IEEEtypes_PhyParamSet_t),
sizeof(IEEEtypes_PhyParamSet_t));
pbss_desc->network_type_use = Wlan802_11DS;
/* Set IBSS param set */
/** IBSS parameter IE Id */
#define IBSS_PARA_IE_ID 6
/** IBSS parameter IE length */
#define IBSS_PARA_IE_LEN 2
padhoc_start->ss_param_set.ibss_param_set.element_id = IBSS_PARA_IE_ID;
padhoc_start->ss_param_set.ibss_param_set.len = IBSS_PARA_IE_LEN;
padhoc_start->ss_param_set.ibss_param_set.atim_window =
wlan_cpu_to_le16(pmpriv->atim_window);
pbss_desc->atim_window = pmpriv->atim_window;
memcpy_ext(pmadapter, &pbss_desc->ss_param_set,
&padhoc_start->ss_param_set, sizeof(IEEEtypes_SsParamSet_t),
sizeof(IEEEtypes_SsParamSet_t));
/* Set Capability info */
padhoc_start->cap.ess = 0;
padhoc_start->cap.ibss = 1;
pbss_desc->cap_info.ibss = 1;
/* Set up privacy in pbss_desc */
if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled ||
pmpriv->sec_info.wpa_enabled || pmpriv->sec_info.ewpa_enabled) {
/** Ad-Hoc capability privacy on */
#define AD_HOC_CAP_PRIVACY_ON 1
PRINTM(MINFO, "ADHOC_S_CMD: wep_status set, Privacy to WEP\n");
pbss_desc->privacy = Wlan802_11PrivFilter8021xWEP;
padhoc_start->cap.privacy = AD_HOC_CAP_PRIVACY_ON;
} else {
PRINTM(MWARN, "ADHOC_S_CMD: wep_status NOT set, Setting "
"Privacy to ACCEPT ALL\n");
pbss_desc->privacy = Wlan802_11PrivFilterAcceptAll;
}
memset(pmadapter, padhoc_start->DataRate, 0,
sizeof(padhoc_start->DataRate));
if ((pmpriv->adapter->region_code == COUNTRY_CODE_JP_40 ||
pmpriv->adapter->region_code == COUNTRY_CODE_JP_FF) &&
(pbss_desc->phy_param_set.ds_param_set.current_chan == 14)) {
wlan_get_active_data_rates(pmpriv, pmpriv->bss_mode, BAND_B,
padhoc_start->DataRate);
} else {
wlan_get_active_data_rates(pmpriv, pmpriv->bss_mode,
pmadapter->adhoc_start_band,
padhoc_start->DataRate);
}
if ((pmadapter->adhoc_start_band & BAND_G) &&
(pmpriv->curr_pkt_filter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON)) {
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MAC_CONTROL,
HostCmd_ACT_GEN_SET, 0, MNULL,
&pmpriv->curr_pkt_filter);
if (ret) {
PRINTM(MERROR,
"ADHOC_S_CMD: G Protection config failed\n");
ret = MLAN_STATUS_FAILURE;
goto done;
}
}
/* Find the last non zero */
for (i = 0;
i < sizeof(padhoc_start->DataRate) && padhoc_start->DataRate[i];
i++)
/* XXX Do not delete no-operation line */
;
pmpriv->curr_bss_params.num_of_rates = i;
/* Copy the ad-hoc creating rates into Current BSS rate structure */
memcpy_ext(pmadapter, &pmpriv->curr_bss_params.data_rates,
&padhoc_start->DataRate,
pmpriv->curr_bss_params.num_of_rates, WLAN_SUPPORTED_RATES);
PRINTM(MINFO, "ADHOC_S_CMD: Rates=%02x %02x %02x %02x\n",
padhoc_start->DataRate[0], padhoc_start->DataRate[1],
padhoc_start->DataRate[2], padhoc_start->DataRate[3]);
PRINTM(MINFO, "ADHOC_S_CMD: AD HOC Start command is ready\n");
if (IS_SUPPORT_MULTI_BANDS(pmadapter)) {
/* Append a channel TLV */
pchan_tlv = (MrvlIEtypes_ChanListParamSet_t *)pos;
pchan_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
pchan_tlv->header.len =
wlan_cpu_to_le16(sizeof(ChanScanParamSet_t));
memset(pmadapter, pchan_tlv->chan_scan_param, 0x00,
sizeof(ChanScanParamSet_t));
pchan_tlv->chan_scan_param[0].chan_number =
(t_u8)pmpriv->curr_bss_params.bss_descriptor.channel;
PRINTM(MINFO, "ADHOC_S_CMD: TLV Chan = %d\n",
pchan_tlv->chan_scan_param[0].chan_number);
pchan_tlv->chan_scan_param[0].bandcfg.chanBand =
wlan_band_to_radio_type(pmpriv->curr_bss_params.band);
PRINTM(MINFO, "ADHOC_S_CMD: TLV Bandcfg = %x\n",
pchan_tlv->chan_scan_param[0].bandcfg);
pos += sizeof(pchan_tlv->header) + sizeof(ChanScanParamSet_t);
cmd_append_size +=
sizeof(pchan_tlv->header) + sizeof(ChanScanParamSet_t);
}
if (wlan_11d_create_dnld_countryinfo(pmpriv,
pmpriv->curr_bss_params.band)) {
PRINTM(MERROR, "ADHOC_S_CMD: dnld_countryinfo_11d failed\n");
ret = MLAN_STATUS_FAILURE;
goto done;
}
/*
* Call 11h start API to add any 11h flags/elements as TLV parameters
*/
append_size_11h =
wlan_11h_process_start(pmpriv, &pos, &padhoc_start->cap,
pmpriv->adhoc_channel,
&pbss_desc->wlan_11h_bss_info);
if (append_size_11h >= 0)
cmd_append_size += append_size_11h;
else {
ret = MLAN_STATUS_FAILURE;
goto done;
}
if (pmpriv->sec_info.ewpa_enabled) {
memcpy_ext(pmadapter, pmpriv->wpa_ie, wpa_ie, sizeof(wpa_ie),
sizeof(pmpriv->wpa_ie));
pmpriv->wpa_ie_len = sizeof(wpa_ie);
}
if (pmpriv->sec_info.wpa_enabled || pmpriv->sec_info.ewpa_enabled) {
prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *)pos;
prsn_ie_tlv->header.type = (t_u16)pmpriv->wpa_ie[0];
/* WPA_IE or RSN_IE */
prsn_ie_tlv->header.type = prsn_ie_tlv->header.type & 0x00FF;
prsn_ie_tlv->header.type =
wlan_cpu_to_le16(prsn_ie_tlv->header.type);
prsn_ie_tlv->header.len = (t_u16)pmpriv->wpa_ie[1];
prsn_ie_tlv->header.len = prsn_ie_tlv->header.len & 0x00FF;
if (prsn_ie_tlv->header.len <= (sizeof(pmpriv->wpa_ie) - 2))
memcpy_ext(pmadapter, prsn_ie_tlv->rsn_ie,
&pmpriv->wpa_ie[2], prsn_ie_tlv->header.len,
prsn_ie_tlv->header.len);
else {
ret = MLAN_STATUS_FAILURE;
goto done;
}
DBG_HEXDUMP(MCMD_D, "ADHOC_S_CMD: RSN IE", (t_u8 *)prsn_ie_tlv,
sizeof(prsn_ie_tlv->header) +
prsn_ie_tlv->header.len);
pos += sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
cmd_append_size +=
sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
prsn_ie_tlv->header.len =
wlan_cpu_to_le16(prsn_ie_tlv->header.len);
}
cmd->size = (t_u16)wlan_cpu_to_le16(
(t_u16)(sizeof(HostCmd_DS_802_11_AD_HOC_START) + S_DS_GEN +
cmd_append_size));
memcpy_ext(pmadapter, &tmp_cap, &padhoc_start->cap, sizeof(t_u16),
sizeof(tmp_cap));
if (pmadapter->adhoc_start_band == BAND_B)
SHORT_SLOT_TIME_DISABLED(tmp_cap);
else
SHORT_SLOT_TIME_ENABLED(tmp_cap);
tmp_cap = wlan_cpu_to_le16(tmp_cap);
memcpy_ext(pmadapter, &padhoc_start->cap, &tmp_cap, sizeof(t_u16),
sizeof(padhoc_start->cap));
ret = MLAN_STATUS_SUCCESS;
done:
LEAVE();
return ret;
}
/**
* @brief This function prepares command of ad_hoc_join.
*
* @param pmpriv A pointer to mlan_private structure
* @param cmd A pointer to HostCmd_DS_COMMAND structure
* @param pdata_buf Void cast of BSSDescriptor_t from the
* scan table to join
*
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
mlan_status wlan_cmd_802_11_ad_hoc_join(mlan_private *pmpriv,
HostCmd_DS_COMMAND *cmd,
t_void *pdata_buf)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_adapter *pmadapter = pmpriv->adapter;
HostCmd_DS_802_11_AD_HOC_JOIN *padhoc_join = &cmd->params.adhoc_join;
BSSDescriptor_t *pbss_desc = (BSSDescriptor_t *)pdata_buf;
MrvlIEtypes_ChanListParamSet_t *pchan_tlv;
MrvlIEtypes_RsnParamSet_t *prsn_ie_tlv;
t_u32 cmd_append_size = 0;
t_u16 tmp_cap;
t_u32 i, rates_size = 0;
t_u32 curr_pkt_filter;
t_u8 *pos = (t_u8 *)padhoc_join + sizeof(HostCmd_DS_802_11_AD_HOC_JOIN);
ENTER();
/** Use G protection */
#define USE_G_PROTECTION 0x02
if (pbss_desc->erp_flags & USE_G_PROTECTION) {
curr_pkt_filter = pmpriv->curr_pkt_filter |
HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON;
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MAC_CONTROL,
HostCmd_ACT_GEN_SET, 0, MNULL,
&curr_pkt_filter);
if (ret) {
PRINTM(MERROR,
"ADHOC_J_CMD: G Protection config failed\n");
ret = MLAN_STATUS_FAILURE;
goto done;
}
}
pmpriv->pattempted_bss_desc = pbss_desc;
cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_JOIN);
padhoc_join->bss_descriptor.bss_mode = HostCmd_BSS_MODE_IBSS;
padhoc_join->bss_descriptor.beacon_period =
wlan_cpu_to_le16(pbss_desc->beacon_period);
memcpy_ext(pmadapter, &padhoc_join->bss_descriptor.bssid,
&pbss_desc->mac_address, MLAN_MAC_ADDR_LENGTH,
MLAN_MAC_ADDR_LENGTH);
memcpy_ext(pmadapter, &padhoc_join->bss_descriptor.ssid,
&pbss_desc->ssid.ssid, pbss_desc->ssid.ssid_len,
MLAN_MAX_SSID_LENGTH);
memcpy_ext(pmadapter, &padhoc_join->bss_descriptor.phy_param_set,
&pbss_desc->phy_param_set, sizeof(IEEEtypes_PhyParamSet_t),
sizeof(IEEEtypes_PhyParamSet_t));
padhoc_join->bss_descriptor.phy_param_set.fh_param_set.dwell_time =
wlan_cpu_to_le16(padhoc_join->bss_descriptor.phy_param_set
.fh_param_set.dwell_time);
memcpy_ext(pmadapter, &padhoc_join->bss_descriptor.ss_param_set,
&pbss_desc->ss_param_set, sizeof(IEEEtypes_SsParamSet_t),
sizeof(IEEEtypes_SsParamSet_t));
padhoc_join->bss_descriptor.ss_param_set.ibss_param_set.atim_window = 0;
padhoc_join->bss_descriptor.ss_param_set.ibss_param_set.atim_window =
wlan_cpu_to_le16(padhoc_join->bss_descriptor.ss_param_set
.ibss_param_set.atim_window);
memcpy_ext(pmadapter, &tmp_cap, &pbss_desc->cap_info,
sizeof(IEEEtypes_CapInfo_t), sizeof(IEEEtypes_CapInfo_t));
tmp_cap &= CAPINFO_MASK;
PRINTM(MINFO, "ADHOC_J_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n", tmp_cap,
CAPINFO_MASK);
memcpy_ext(pmadapter, &padhoc_join->bss_descriptor.cap, &tmp_cap,
sizeof(IEEEtypes_CapInfo_t), sizeof(IEEEtypes_CapInfo_t));
/* Information on BSSID descriptor passed to FW */
PRINTM(MINFO, "ADHOC_J_CMD: BSSID = " MACSTR ", SSID = %s\n",
MAC2STR(padhoc_join->bss_descriptor.bssid),
padhoc_join->bss_descriptor.ssid);
for (i = 0; i < WLAN_SUPPORTED_RATES && pbss_desc->supported_rates[i];
i++)
/* XXX Do not delete no-operation line */
;
rates_size = i;
/* Copy Data Rates from the Rates recorded in scan response */
memset(pmadapter, padhoc_join->bss_descriptor.data_rates, 0,
sizeof(padhoc_join->bss_descriptor.data_rates));
memcpy_ext(pmadapter, padhoc_join->bss_descriptor.data_rates,
pbss_desc->supported_rates, rates_size,
WLAN_SUPPORTED_RATES);
HEXDUMP("Adapted Rates:", padhoc_join->bss_descriptor.data_rates,
rates_size);
/* Copy the adhoc join rates into Current BSS state structure */
pmpriv->curr_bss_params.num_of_rates = rates_size;
memcpy_ext(pmadapter, &pmpriv->curr_bss_params.data_rates,
pbss_desc->supported_rates, rates_size,
WLAN_SUPPORTED_RATES);
/* Copy the channel information */
pmpriv->curr_bss_params.bss_descriptor.channel = pbss_desc->channel;
pmpriv->curr_bss_params.band = (t_u8)pbss_desc->bss_band;
if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled ||
pmpriv->sec_info.wpa_enabled || pmpriv->sec_info.ewpa_enabled)
padhoc_join->bss_descriptor.cap.privacy = AD_HOC_CAP_PRIVACY_ON;
if (IS_SUPPORT_MULTI_BANDS(pmadapter)) {
/* Append a channel TLV */
pchan_tlv = (MrvlIEtypes_ChanListParamSet_t *)pos;
pchan_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
pchan_tlv->header.len =
wlan_cpu_to_le16(sizeof(ChanScanParamSet_t));
memset(pmadapter, pchan_tlv->chan_scan_param, 0x00,
sizeof(ChanScanParamSet_t));
pchan_tlv->chan_scan_param[0].chan_number =
(pbss_desc->phy_param_set.ds_param_set.current_chan);
PRINTM(MINFO, "ADHOC_J_CMD: TLV Chan = %d\n",
pchan_tlv->chan_scan_param[0].chan_number);
pchan_tlv->chan_scan_param[0].bandcfg.chanBand =
wlan_band_to_radio_type((t_u8)pbss_desc->bss_band);
PRINTM(MINFO, "ADHOC_J_CMD: TLV Bandcfg = %x\n",
pchan_tlv->chan_scan_param[0].bandcfg);
pos += sizeof(pchan_tlv->header) + sizeof(ChanScanParamSet_t);
cmd_append_size +=
sizeof(pchan_tlv->header) + sizeof(ChanScanParamSet_t);
}
if (wlan_11d_create_dnld_countryinfo(pmpriv,
(t_u8)pbss_desc->bss_band)) {
PRINTM(MERROR, "Dnld_countryinfo_11d failed\n");
ret = MLAN_STATUS_FAILURE;
goto done;
}
if (wlan_11d_parse_dnld_countryinfo(pmpriv,
pmpriv->pattempted_bss_desc)) {
ret = MLAN_STATUS_FAILURE;
goto done;
}
/*
* Call 11h join API after capability bits are set so
* adhoc/infra 11h behavior can be properly triggered.
* pos modified if data is appended
*/
cmd_append_size += wlan_11h_process_join(
pmpriv, &pos, &padhoc_join->bss_descriptor.cap,
(t_u8)pbss_desc->bss_band, pbss_desc->channel,
&pbss_desc->wlan_11h_bss_info);
if (pmpriv->sec_info.wpa_enabled) {
prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *)pos;
/* WPA_IE or RSN_IE */
prsn_ie_tlv->header.type = (t_u16)pmpriv->wpa_ie[0];
prsn_ie_tlv->header.type = prsn_ie_tlv->header.type & 0x00FF;
prsn_ie_tlv->header.type =
wlan_cpu_to_le16(prsn_ie_tlv->header.type);
prsn_ie_tlv->header.len = (t_u16)pmpriv->wpa_ie[1];
prsn_ie_tlv->header.len = prsn_ie_tlv->header.len & 0x00FF;
if (prsn_ie_tlv->header.len <= (sizeof(pmpriv->wpa_ie) - 2))
memcpy_ext(pmadapter, prsn_ie_tlv->rsn_ie,
&pmpriv->wpa_ie[2], prsn_ie_tlv->header.len,
prsn_ie_tlv->header.len);
else {
ret = MLAN_STATUS_FAILURE;
goto done;
}
HEXDUMP("ADHOC_JOIN: RSN IE", (t_u8 *)prsn_ie_tlv,
sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len);
pos += sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
cmd_append_size +=
sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
prsn_ie_tlv->header.len =
wlan_cpu_to_le16(prsn_ie_tlv->header.len);
} else if (pmpriv->sec_info.ewpa_enabled) {
prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *)pos;
if (pbss_desc->pwpa_ie) {
prsn_ie_tlv->header.type =
(t_u16)(*(pbss_desc->pwpa_ie))
.vend_hdr.element_id;
prsn_ie_tlv->header.type =
prsn_ie_tlv->header.type & 0x00FF;
prsn_ie_tlv->header.type =
wlan_cpu_to_le16(prsn_ie_tlv->header.type);
prsn_ie_tlv->header.len =
(t_u16)(*(pbss_desc->pwpa_ie)).vend_hdr.len;
prsn_ie_tlv->header.len =
prsn_ie_tlv->header.len & 0x00FF;
if (prsn_ie_tlv->header.len <=
(sizeof(pmpriv->wpa_ie))) {
memcpy_ext(pmadapter, prsn_ie_tlv->rsn_ie,
&((*(pbss_desc->pwpa_ie))
.vend_hdr.oui[0]),
prsn_ie_tlv->header.len,
prsn_ie_tlv->header.len);
} else {
ret = MLAN_STATUS_FAILURE;
goto done;
}
HEXDUMP("ADHOC_JOIN: RSN IE", (t_u8 *)prsn_ie_tlv,
sizeof(prsn_ie_tlv->header) +
prsn_ie_tlv->header.len);
pos += sizeof(prsn_ie_tlv->header) +
prsn_ie_tlv->header.len;
cmd_append_size += sizeof(prsn_ie_tlv->header) +
prsn_ie_tlv->header.len;
prsn_ie_tlv->header.len =
wlan_cpu_to_le16(prsn_ie_tlv->header.len);
}
if (pbss_desc->prsn_ie) {
prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *)pos;
prsn_ie_tlv->header.type =
(t_u16)(*(pbss_desc->prsn_ie))
.ieee_hdr.element_id;
prsn_ie_tlv->header.type =
prsn_ie_tlv->header.type & 0x00FF;
prsn_ie_tlv->header.type =
wlan_cpu_to_le16(prsn_ie_tlv->header.type);
prsn_ie_tlv->header.len =
(t_u16)(*(pbss_desc->prsn_ie)).ieee_hdr.len;
prsn_ie_tlv->header.len =
prsn_ie_tlv->header.len & 0x00FF;
if (prsn_ie_tlv->header.len <=
(sizeof(pmpriv->wpa_ie))) {
memcpy_ext(pmadapter, prsn_ie_tlv->rsn_ie,
&((*(pbss_desc->prsn_ie)).data[0]),
prsn_ie_tlv->header.len,
prsn_ie_tlv->header.len);
} else {
ret = MLAN_STATUS_FAILURE;
goto done;
}
HEXDUMP("ADHOC_JOIN: RSN IE", (t_u8 *)prsn_ie_tlv,
sizeof(prsn_ie_tlv->header) +
prsn_ie_tlv->header.len);
pos += sizeof(prsn_ie_tlv->header) +
prsn_ie_tlv->header.len;
cmd_append_size += sizeof(prsn_ie_tlv->header) +
prsn_ie_tlv->header.len;
prsn_ie_tlv->header.len =
wlan_cpu_to_le16(prsn_ie_tlv->header.len);
}
}
cmd->size = (t_u16)wlan_cpu_to_le16(
(t_u16)(sizeof(HostCmd_DS_802_11_AD_HOC_JOIN) + S_DS_GEN +
cmd_append_size));
memcpy_ext(pmadapter, &tmp_cap, &padhoc_join->bss_descriptor.cap,
sizeof(IEEEtypes_CapInfo_t), sizeof(IEEEtypes_CapInfo_t));
tmp_cap = wlan_cpu_to_le16(tmp_cap);
memcpy_ext(pmadapter, &padhoc_join->bss_descriptor.cap, &tmp_cap,
sizeof(IEEEtypes_CapInfo_t), sizeof(IEEEtypes_CapInfo_t));
done:
LEAVE();
return ret;
}
/**
* @brief This function handles the command response of ad_hoc_start and
* ad_hoc_join
*
* @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_ad_hoc(mlan_private *pmpriv,
HostCmd_DS_COMMAND *resp, t_void *pioctl_buf)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_ioctl_req *pioctl_req = (mlan_ioctl_req *)pioctl_buf;
HostCmd_DS_802_11_AD_HOC_START_RESULT *padhoc_start_result =
&resp->params.adhoc_start_result;
HostCmd_DS_802_11_AD_HOC_JOIN_RESULT *padhoc_join_result =
&resp->params.adhoc_join_result;
BSSDescriptor_t *pbss_desc;
t_u16 command = resp->command;
t_u8 result = 0;
t_u8 event_buf[100];
mlan_event *pevent = (mlan_event *)event_buf;
int ie_len = 0;
IEEEtypes_WmmParameter_t *pwmm_param_ie = MNULL;
mlan_adapter *pmadapter = pmpriv->adapter;
const t_u8 wmm_oui[4] = {0x00, 0x50, 0xf2, 0x02};
ENTER();
pmpriv->wmm_enabled = MFALSE;
if (command == HostCmd_CMD_802_11_AD_HOC_START) {
result = padhoc_start_result->result;
ie_len = resp->size -
(sizeof(HostCmd_DS_802_11_AD_HOC_START_RESULT) +
S_DS_GEN);
pwmm_param_ie =
(IEEEtypes_WmmParameter_t
*)((t_u8 *)resp +
(sizeof(HostCmd_DS_802_11_AD_HOC_START_RESULT) +
S_DS_GEN));
} else {
result = padhoc_join_result->result;
ie_len = resp->size -
(sizeof(HostCmd_DS_802_11_AD_HOC_JOIN_RESULT) +
S_DS_GEN);
pwmm_param_ie =
(IEEEtypes_WmmParameter_t
*)((t_u8 *)resp +
(sizeof(HostCmd_DS_802_11_AD_HOC_JOIN_RESULT) +
S_DS_GEN));
}
pbss_desc = pmpriv->pattempted_bss_desc;
/*
* Join result code 0 --> SUCCESS
*/
if (result) {
PRINTM(MERROR, "ADHOC_RESP Failed 0x%x\n", result);
if (pmpriv->media_connected == MTRUE)
wlan_reset_connect_state(pmpriv, MTRUE);
if (pmpriv->adhoc_state == ADHOC_STARTING)
pmpriv->adhoc_state = ADHOC_IDLE;
memset(pmpriv->adapter, &pmpriv->curr_bss_params.bss_descriptor,
0x00, sizeof(BSSDescriptor_t));
ret = MLAN_STATUS_FAILURE;
goto done;
}
/* Send a Media Connected event, according to the Spec */
pmpriv->media_connected = MTRUE;
if (command == HostCmd_CMD_802_11_AD_HOC_START) {
PRINTM(MINFO, "ADHOC_S_RESP %s\n", pbss_desc->ssid.ssid);
/* Update the created network descriptor with the new BSSID */
memcpy_ext(pmpriv->adapter, pbss_desc->mac_address,
padhoc_start_result->bssid, MLAN_MAC_ADDR_LENGTH,
MLAN_MAC_ADDR_LENGTH);
pmpriv->adhoc_state = ADHOC_STARTED;
if (pmpriv->adapter->state_rdh.stage == RDH_RESTART_INTFS)
wlan_11h_radar_detected_callback((t_void *)pmpriv);
} else {
/*
* Now the join cmd should be successful.
* If BSSID has changed use SSID to compare instead of BSSID
*/
PRINTM(MINFO, "ADHOC_J_RESP %s\n", pbss_desc->ssid.ssid);
/*
* Make a copy of current BSSID descriptor, only needed
* for join since the current descriptor is already
* being used for adhoc start
*/
memcpy_ext(pmpriv->adapter,
&pmpriv->curr_bss_params.bss_descriptor, pbss_desc,
sizeof(BSSDescriptor_t), sizeof(BSSDescriptor_t));
pmpriv->adhoc_state = ADHOC_JOINED;
}
/** process wmm ie */
if (ie_len >= (int)sizeof(IEEEtypes_VendorHeader_t)) {
if ((pwmm_param_ie->vend_hdr.element_id ==
VENDOR_SPECIFIC_221) &&
!memcmp(pmadapter, pwmm_param_ie->vend_hdr.oui, wmm_oui,
sizeof(wmm_oui)) &&
(pwmm_param_ie->vend_hdr.len + 2 == ie_len)) {
DBG_HEXDUMP(MCMD_D, "WMM Param", (t_u8 *)pwmm_param_ie,
ie_len);
memcpy_ext(pmpriv->adapter,
(t_u8 *)&pmpriv->curr_bss_params
.bss_descriptor.wmm_ie,
pwmm_param_ie,
(pwmm_param_ie->vend_hdr.len + 2),
sizeof(IEEEtypes_WmmParameter_t));
pmpriv->wmm_enabled = MTRUE;
wlan_wmm_setup_queue_priorities(pmpriv, pwmm_param_ie);
wlan_wmm_setup_ac_downgrade(pmpriv);
}
}
/* Since WMM is not enabled, setup the queues with the defaults */
if (!pmpriv->wmm_enabled)
wlan_wmm_setup_queues(pmpriv);
PRINTM(MINFO, "ADHOC_RESP: Channel = %d\n", pmpriv->adhoc_channel);
PRINTM(MINFO, "ADHOC_RESP: BSSID = " MACSTR "\n",
MAC2STR(pmpriv->curr_bss_params.bss_descriptor.mac_address));
pevent->bss_index = pmpriv->bss_index;
pevent->event_id = MLAN_EVENT_ID_DRV_CONNECTED;
pevent->event_len = MLAN_MAC_ADDR_LENGTH;
memcpy_ext(pmpriv->adapter, (t_u8 *)pevent->event_buf,
(t_u8 *)pmpriv->curr_bss_params.bss_descriptor.mac_address,
MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_CONNECTED, pevent);
wlan_save_curr_bcn(pmpriv);
done:
/* Need to indicate IOCTL complete */
if (pioctl_req != MNULL) {
if (ret != MLAN_STATUS_SUCCESS)
pioctl_req->status_code = MLAN_ERROR_CMD_ASSOC_FAIL;
else
pioctl_req->status_code = MLAN_ERROR_NO_ERROR;
}
LEAVE();
return ret;
}
/**
* @brief Associated to a specific BSS discovered in a scan
*
* @param pmpriv A pointer to mlan_private structure
* @param pioctl_buf A pointer to MLAN IOCTL Request buffer
* @param pbss_desc A pointer to the BSS descriptor to associate with.
*
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
mlan_status wlan_associate(mlan_private *pmpriv, t_void *pioctl_buf,
BSSDescriptor_t *pbss_desc)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
t_u8 current_bssid[MLAN_MAC_ADDR_LENGTH];
pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *)pioctl_buf;
ENTER();
/* Return error if the pmadapter or table entry
* is not marked as infra */
if ((pmpriv->bss_mode != MLAN_BSS_MODE_INFRA) ||
(pbss_desc->bss_mode != MLAN_BSS_MODE_INFRA)) {
if (pioctl_req)
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
LEAVE();
return MLAN_STATUS_FAILURE;
}
memcpy_ext(pmpriv->adapter, &current_bssid,
&pmpriv->curr_bss_params.bss_descriptor.mac_address,
sizeof(current_bssid), sizeof(current_bssid));
/* Clear any past association response stored for application retrieval
*/
pmpriv->assoc_rsp_size = 0;
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_ASSOCIATE,
HostCmd_ACT_GEN_SET, 0, pioctl_buf, pbss_desc);
LEAVE();
return ret;
}
/**
* @brief Start an Adhoc Network
*
* @param pmpriv A pointer to mlan_private structure
* @param pioctl_buf A pointer to MLAN IOCTL Request buffer
* @param padhoc_ssid The ssid of the Adhoc Network
*
* @return MLAN_STATUS_SUCCESS--success, MLAN_STATUS_FAILURE--fail
*/
mlan_status wlan_adhoc_start(mlan_private *pmpriv, t_void *pioctl_buf,
mlan_802_11_ssid *padhoc_ssid)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
wlan_meas_state_t *pmeas_state = &pmpriv->adapter->state_meas;
t_u8 radar = MFALSE;
pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *)pioctl_buf;
ENTER();
/*
* If the report indicates no measurement was done, leave the default
* return value alone.
*/
if (!pmeas_state->meas_rpt_returned.rpt.basic.map.unmeasured) {
radar = pmeas_state->meas_rpt_returned.rpt.basic.map.radar ?
MTRUE :
MFALSE;
}
if (radar) {
if (pioctl_req)
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
ret = MLAN_STATUS_FAILURE;
LEAVE();
return ret;
}
PRINTM(MINFO, "Adhoc Channel = %d\n", pmpriv->adhoc_channel);
PRINTM(MINFO, "curr_bss_params.channel = %d\n",
pmpriv->curr_bss_params.bss_descriptor.channel);
PRINTM(MINFO, "curr_bss_params.band = %d\n",
pmpriv->curr_bss_params.band);
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_AD_HOC_START,
HostCmd_ACT_GEN_SET, 0, pioctl_buf, padhoc_ssid);
#if defined(STA_SUPPORT)
if (ret == MLAN_STATUS_SUCCESS)
memcpy_ext(pmpriv->adapter, &pmpriv->adhoc_last_start_ssid,
padhoc_ssid, sizeof(mlan_802_11_ssid),
sizeof(mlan_802_11_ssid));
#endif
LEAVE();
return ret;
}
/**
* @brief Join an adhoc network found in a previous scan
*
* @param pmpriv A pointer to mlan_private structure
* @param pioctl_buf A pointer to MLAN IOCTL Request buffer
* @param pbss_desc A pointer to the BSS descriptor found in a previous
* scan to attempt to join
*
* @return MLAN_STATUS_SUCCESS--success, MLAN_STATUS_FAILURE--fail
*/
mlan_status wlan_adhoc_join(mlan_private *pmpriv, t_void *pioctl_buf,
BSSDescriptor_t *pbss_desc)
{
pmlan_adapter pmadapter = pmpriv->adapter;
mlan_status ret = MLAN_STATUS_SUCCESS;
pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *)pioctl_buf;
ENTER();
PRINTM(MINFO, "wlan_adhoc_join: CurBss.ssid =%s\n",
pmpriv->curr_bss_params.bss_descriptor.ssid.ssid);
PRINTM(MINFO, "wlan_adhoc_join: CurBss.ssid_len =%u\n",
pmpriv->curr_bss_params.bss_descriptor.ssid.ssid_len);
PRINTM(MINFO, "wlan_adhoc_join: ssid =%s\n", pbss_desc->ssid.ssid);
PRINTM(MINFO, "wlan_adhoc_join: ssid len =%u\n",
pbss_desc->ssid.ssid_len);
/* Check if the requested SSID is already joined */
if (pmpriv->curr_bss_params.bss_descriptor.ssid.ssid_len &&
!wlan_ssid_cmp(pmadapter, &pbss_desc->ssid,
&pmpriv->curr_bss_params.bss_descriptor.ssid) &&
(pmpriv->curr_bss_params.bss_descriptor.bss_mode ==
MLAN_BSS_MODE_IBSS)) {
PRINTM(MINFO,
"ADHOC_J_CMD: New ad-hoc SSID is the same as current, "
"not attempting to re-join\n");
if (pioctl_req)
pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
LEAVE();
return MLAN_STATUS_FAILURE;
}
PRINTM(MINFO, "curr_bss_params.channel = %d\n",
pmpriv->curr_bss_params.bss_descriptor.channel);
PRINTM(MINFO, "curr_bss_params.band = %d\n",
pmpriv->curr_bss_params.band);
ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_AD_HOC_JOIN,
HostCmd_ACT_GEN_SET, 0, pioctl_buf, pbss_desc);
LEAVE();
return ret;
}
/**
* @brief Send Deauthentication Request or Stop the AdHoc network depending on
* mode
*
* @param pmpriv A pointer to mlan_private structure
* @param pioctl_req A pointer to mlan_ioctl_req structure
* @param deauth_param A pointer to mlan_deauth_param structure
*
* @return MLAN_STATUS_SUCCESS--success, MLAN_STATUS_FAILURE--fail,
* MLAN_STATUS_PENDING--pending
*/
mlan_status wlan_disconnect(mlan_private *pmpriv, mlan_ioctl_req *pioctl_req,
mlan_deauth_param *deauth_param)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_deauth_param local_param = {.mac_addr = {0, 0, 0, 0, 0, 0},
.reason_code = DEF_DEAUTH_REASON_CODE};
t_u8 zero_mac[] = {0, 0, 0, 0, 0, 0};
ENTER();
if (deauth_param)
memcpy_ext(pmpriv->adapter, &local_param, deauth_param,
sizeof(*deauth_param), sizeof(local_param));
if (pmpriv->media_connected == MTRUE) {
if (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) {
if (!deauth_param ||
!memcmp(pmpriv->adapter, deauth_param->mac_addr,
zero_mac, sizeof(zero_mac)))
memcpy_ext(pmpriv->adapter,
local_param.mac_addr,
(t_u8 *)&pmpriv->curr_bss_params
.bss_descriptor.mac_address,
MLAN_MAC_ADDR_LENGTH,
MLAN_MAC_ADDR_LENGTH);
#ifdef WIFI_DIRECT_SUPPORT
if (pmpriv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
ret = wlan_prepare_cmd(
pmpriv, HostCmd_CMD_802_11_DISASSOCIATE,
HostCmd_ACT_GEN_SET, 0,
(t_void *)pioctl_req, &local_param);
else
#endif
ret = wlan_prepare_cmd(
pmpriv,
HostCmd_CMD_802_11_DEAUTHENTICATE,
HostCmd_ACT_GEN_SET, 0,
(t_void *)pioctl_req, &local_param);
if (ret == MLAN_STATUS_SUCCESS && pioctl_req)
ret = MLAN_STATUS_PENDING;
} else if (pmpriv->bss_mode == MLAN_BSS_MODE_IBSS) {
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_802_11_AD_HOC_STOP,
HostCmd_ACT_GEN_SET, 0,
(t_void *)pioctl_req, MNULL);
if (ret == MLAN_STATUS_SUCCESS && pioctl_req)
ret = MLAN_STATUS_PENDING;
}
}
LEAVE();
return ret;
}
/**
* @brief Convert band to radio type used in channel TLV
*
* @param band Band enumeration to convert to a channel TLV radio type
*
* @return Radio type designator for use in a channel TLV
*/
t_u8 wlan_band_to_radio_type(t_u8 band)
{
t_u8 ret_radio_type;
ENTER();
switch (band) {
case BAND_A:
case BAND_AN:
case BAND_A | BAND_AN:
case BAND_A | BAND_AN | BAND_AAC:
ret_radio_type = BAND_5GHZ;
break;
case BAND_B:
case BAND_G:
case BAND_B | BAND_G:
default:
ret_radio_type = BAND_2GHZ;
break;
}
LEAVE();
return ret_radio_type;
}