blob: 1972461f0350d8ef873b3a6c294ceb7395a868ce [file] [log] [blame]
/*
* Copyright (c) 2012-2015 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*
* This file was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
/*
* This file lim_process_assoc_req_frame.cc contains the code
* for processing Re/Association Request Frame.
* Author: Chandra Modumudi
* Date: 03/18/02
* History:-
* Date Modified by Modification Information
* --------------------------------------------------------------------
* 05/26/10 js WPA handling in (Re)Assoc frames
*
*/
#include "cds_api.h"
#include "ani_global.h"
#include "wni_cfg.h"
#include "sir_api.h"
#include "cfg_api.h"
#include "sch_api.h"
#include "utils_api.h"
#include "lim_types.h"
#include "lim_utils.h"
#include "lim_assoc_utils.h"
#include "lim_security_utils.h"
#include "lim_ser_des_utils.h"
#include "lim_sta_hash_api.h"
#include "lim_admit_control.h"
#include "cds_packet.h"
#include "lim_session_utils.h"
#include "cdf_types.h"
#include "cds_utils.h"
/**
* lim_convert_supported_channels - Parses channel support IE
*
* @mac_ctx - A pointer to Global MAC structure
* @assoc_ind - A pointer to SME ASSOC/REASSOC IND
* @assoc_req - A pointer to ASSOC/REASSOC Request frame
*
* This function is called by lim_process_assoc_req_frame() to
* parse the channel support IE in the Assoc/Reassoc Request
* frame, and send relevant information in the SME_ASSOC_IND
*
* return None
*/
static void
lim_convert_supported_channels(tpAniSirGlobal mac_ctx,
tpLimMlmAssocInd assoc_ind, tSirAssocReq *assoc_req)
{
uint16_t i, j, index = 0;
uint8_t first_chn_no;
uint8_t chn_count;
uint8_t next_chn_no;
uint8_t channel_offset = 0;
if (assoc_req->supportedChannels.length >=
SIR_MAX_SUPPORTED_CHANNEL_LIST) {
lim_log(mac_ctx, LOG1,
FL("Number of supported channels:%d is more than MAX"),
assoc_req->supportedChannels.length);
assoc_ind->supportedChannels.numChnl = 0;
return;
}
for (i = 0; i < (assoc_req->supportedChannels.length); i++) {
/* Get First Channel Number */
first_chn_no =
assoc_req->supportedChannels.supportedChannels[i];
assoc_ind->supportedChannels.channelList[index] =
first_chn_no;
i++;
index++;
/* Get Number of Channels in a Subband */
chn_count =
assoc_req->supportedChannels.supportedChannels[i];
PELOG2(lim_log(mac_ctx, LOG2,
FL("Rcv assoc_req: chnl=%d, numOfChnl=%d "),
first_chn_no, chn_count);)
if (index >= SIR_MAX_SUPPORTED_CHANNEL_LIST) {
PELOG2(lim_log(mac_ctx, LOGW,
FL("Channel count is more than max supported =%d "),
chn_count);)
assoc_ind->supportedChannels.numChnl = 0;
return;
}
if (chn_count <= 1)
continue;
next_chn_no = first_chn_no;
if (SIR_BAND_5_GHZ == lim_get_rf_band(first_chn_no))
channel_offset = SIR_11A_FREQUENCY_OFFSET;
else if (SIR_BAND_2_4_GHZ == lim_get_rf_band(first_chn_no))
channel_offset = SIR_11B_FREQUENCY_OFFSET;
else
continue;
for (j = 1; j < chn_count; j++) {
next_chn_no += channel_offset;
assoc_ind->supportedChannels.channelList[index]
= next_chn_no;
index++;
if (index >= SIR_MAX_SUPPORTED_CHANNEL_LIST) {
PELOG2(lim_log(mac_ctx, LOGW,
FL("Channel count is more than supported =%d "),
chn_count);)
assoc_ind->supportedChannels.numChnl = 0;
return;
}
}
}
assoc_ind->supportedChannels.numChnl = (uint8_t) index;
PELOG2(lim_log(mac_ctx, LOG2,
FL("Send AssocInd to WSM: minPwr %d, maxPwr %d, numChnl %d"),
assoc_ind->powerCap.minTxPower,
assoc_ind->powerCap.maxTxPower,
assoc_ind->supportedChannels.numChnl);)
}
/**---------------------------------------------------------------
\fn lim_check_sta_in_pe_entries
\brief This function is called by lim_process_assoc_req_frame()
\ to check if STA entry already exists in any of the
\ PE entries of the AP. If it exists, deauth will be
\ sent on that session and the STA deletion will
\ happen. After this, the ASSOC request will be
\ processed
\
\param pMac - A pointer to Global MAC structure
\param pHdr - A pointer to the MAC header
\return None
------------------------------------------------------------------*/
void lim_check_sta_in_pe_entries(tpAniSirGlobal pMac, tpSirMacMgmtHdr pHdr)
{
uint8_t i;
uint16_t assocId = 0;
tpDphHashNode pStaDs = NULL;
tpPESession psessionEntry = NULL;
for (i = 0; i < pMac->lim.maxBssId; i++) {
if ((&pMac->lim.gpSession[i] != NULL) &&
(pMac->lim.gpSession[i].valid) &&
(pMac->lim.gpSession[i].pePersona == CDF_SAP_MODE)) {
psessionEntry = &pMac->lim.gpSession[i];
pStaDs = dph_lookup_hash_entry(pMac, pHdr->sa, &assocId,
&psessionEntry->dph.
dphHashTable);
if (pStaDs
#ifdef WLAN_FEATURE_11W
&& !pStaDs->rmfEnabled
#endif
) {
lim_log(pMac, LOGE,
FL
("Sending Deauth and Deleting existing STA entry: "
MAC_ADDRESS_STR),
MAC_ADDR_ARRAY(psessionEntry->
selfMacAddr));
lim_send_deauth_mgmt_frame(pMac,
eSIR_MAC_UNSPEC_FAILURE_REASON,
(uint8_t *) pHdr->sa,
psessionEntry, false);
lim_trigger_sta_deletion(pMac, pStaDs,
psessionEntry);
break;
}
}
}
}
/**---------------------------------------------------------------
\fn lim_process_assoc_req_frame
\brief This function is called by limProcessMessageQueue()
\ upon Re/Association Request frame reception in
\ BTAMP AP or Soft AP role.
\
\param pMac
\param *pRxPacketInfo - A pointer to Buffer descriptor + associated PDUs
\param subType - Indicates whether it is Association Request(=0)
\ or Reassociation Request(=1) frame
\return None
------------------------------------------------------------------*/
void
lim_process_assoc_req_frame(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo,
uint8_t subType, tpPESession psessionEntry)
{
uint8_t updateContext;
uint8_t *pBody;
uint16_t peerIdx, temp;
uint32_t val;
int32_t framelen;
tSirRetStatus status;
tpSirMacMgmtHdr pHdr;
struct tLimPreAuthNode *pStaPreAuthContext;
tAniAuthType authType;
tSirMacCapabilityInfo localCapabilities;
tpDphHashNode pStaDs = NULL;
tpSirAssocReq pAssocReq, pTempAssocReq;
tLimMlmStates mlmPrevState;
tDot11fIERSN Dot11fIERSN;
tDot11fIEWPA Dot11fIEWPA;
uint32_t phyMode;
tHalBitVal qosMode;
tHalBitVal wsmMode, wmeMode;
uint8_t *wpsIe = NULL;
uint8_t *ht_cap_ie = NULL;
tSirMacRateSet basicRates;
uint8_t i = 0, j = 0;
bool pmfConnection = false;
#ifdef WLAN_FEATURE_11W
tPmfSaQueryTimerId timerId;
uint32_t retryInterval;
#endif
uint16_t assoc_id = 0;
bool assoc_req_copied = false;
lim_get_phy_mode(pMac, &phyMode, psessionEntry);
limGetQosMode(psessionEntry, &qosMode);
pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo);
framelen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo);
lim_log(pMac, LOG1,
FL("Received %s Req Frame on sessionid: %d systemrole %d"
" limMlmState %d from: " MAC_ADDRESS_STR),
(LIM_ASSOC == subType) ? "Assoc" : "ReAssoc",
psessionEntry->peSessionId, GET_LIM_SYSTEM_ROLE(psessionEntry),
psessionEntry->limMlmState, MAC_ADDR_ARRAY(pHdr->sa));
if (LIM_IS_STA_ROLE(psessionEntry) ||
LIM_IS_BT_AMP_STA_ROLE(psessionEntry)) {
lim_log(pMac, LOGE,
FL("received unexpected ASSOC REQ on sessionid: %d "
"sys subType=%d for role=%d from: " MAC_ADDRESS_STR),
psessionEntry->peSessionId, subType,
GET_LIM_SYSTEM_ROLE(psessionEntry),
MAC_ADDR_ARRAY(pHdr->sa));
sir_dump_buf(pMac, SIR_LIM_MODULE_ID, LOG3,
WMA_GET_RX_MPDU_DATA(pRxPacketInfo), framelen);
return;
}
/*
* If a STA is already present in DPH and it
* is initiating a Assoc re-transmit, do not
* process it. This can happen when first Assoc Req frame
* is received but ACK lost at STA side. The ACK for this
* dropped Assoc Req frame should be sent by HW. Host simply
* does not process it once the entry for the STA is already
* present in DPH.
*/
pStaDs = dph_lookup_hash_entry(pMac, pHdr->sa, &assoc_id,
&psessionEntry->dph.dphHashTable);
if ((NULL != pStaDs) && (pHdr->fc.retry > 0)) {
lim_log(pMac, LOGE,
FL("STA is initiating Assoc Req after ACK lost. Do not process"
" sessionid: %d sys subType=%d for role=%d from: "
MAC_ADDRESS_STR), psessionEntry->peSessionId,
subType, GET_LIM_SYSTEM_ROLE(psessionEntry),
MAC_ADDR_ARRAY(pHdr->sa));
return;
}
lim_check_sta_in_pe_entries(pMac, pHdr);
/* Get pointer to Re/Association Request frame body */
pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo);
if (lim_is_group_addr(pHdr->sa)) {
/* Received Re/Assoc Req frame from a BC/MC address */
/* Log error and ignore it */
lim_log(pMac, LOGE,
FL("Received %s Req on sessionid: %d frame from a "
"BC/MC address" MAC_ADDRESS_STR),
(LIM_ASSOC == subType) ? "Assoc" : "ReAssoc",
psessionEntry->peSessionId, MAC_ADDR_ARRAY(pHdr->sa));
return;
}
sir_dump_buf(pMac, SIR_LIM_MODULE_ID, LOG2, (uint8_t *) pBody, framelen);
if (cdf_mem_compare((uint8_t *) pHdr->sa, (uint8_t *) pHdr->da,
(uint8_t) (sizeof(tSirMacAddr)))) {
lim_log(pMac, LOGE,
FL("Rejected Assoc Req frame Since same mac as"
" SAP/GO"));
lim_send_assoc_rsp_mgmt_frame(pMac, eSIR_MAC_UNSPEC_FAILURE_STATUS,
1, pHdr->sa, subType, 0,
psessionEntry);
return;
}
/* If TKIP counter measures active send Assoc Rsp frame to station with eSIR_MAC_MIC_FAILURE_REASON */
if (psessionEntry->bTkipCntrMeasActive &&
LIM_IS_AP_ROLE(psessionEntry)) {
lim_log(pMac, LOGE, FL("TKIP counter measure is active"));
lim_send_assoc_rsp_mgmt_frame(pMac,
eSIR_MAC_MIC_FAILURE_REASON,
1, pHdr->sa, subType,
0, psessionEntry);
return;
}
/* Allocate memory for the Assoc Request frame */
pAssocReq = cdf_mem_malloc(sizeof(*pAssocReq));
if (NULL == pAssocReq) {
lim_log(pMac, LOGP, FL("Allocate Memory failed in assoc_req"));
return;
}
cdf_mem_set((void *)pAssocReq, sizeof(*pAssocReq), 0);
/* Parse Assoc Request frame */
if (subType == LIM_ASSOC)
status =
sir_convert_assoc_req_frame2_struct(pMac, pBody, framelen,
pAssocReq);
else
status =
sir_convert_reassoc_req_frame2_struct(pMac, pBody, framelen,
pAssocReq);
if (status != eSIR_SUCCESS) {
lim_log(pMac, LOGE,
FL("Parse error AssocRequest, length=%d from "
MAC_ADDRESS_STR), framelen, MAC_ADDR_ARRAY(pHdr->sa));
lim_send_assoc_rsp_mgmt_frame(pMac, eSIR_MAC_UNSPEC_FAILURE_STATUS,
1, pHdr->sa, subType, 0,
psessionEntry);
goto error;
}
pAssocReq->assocReqFrame = cdf_mem_malloc(framelen);
if (NULL == pAssocReq->assocReqFrame) {
lim_log(pMac, LOGE,
FL("Unable to allocate memory for the assoc req, "
"length=%d from "), framelen);
goto error;
}
cdf_mem_copy((uint8_t *) pAssocReq->assocReqFrame,
(uint8_t *) pBody, framelen);
pAssocReq->assocReqFrameLength = framelen;
if (cfg_get_capability_info(pMac, &temp, psessionEntry) != eSIR_SUCCESS) {
lim_log(pMac, LOGP, FL("could not retrieve Capabilities"));
goto error;
}
lim_copy_u16((uint8_t *) &localCapabilities, temp);
if (lim_compare_capabilities(pMac,
pAssocReq,
&localCapabilities, psessionEntry) == false)
{
lim_log(pMac, LOGE, FL("local caps mismatch received caps"));
lim_log(pMac, LOGE, FL("Received %s Req with unsupported "
"capabilities from" MAC_ADDRESS_STR),
(LIM_ASSOC == subType) ? "Assoc" : "ReAssoc",
MAC_ADDR_ARRAY(pHdr->sa));
/**
* Capabilities of requesting STA does not match with
* local capabilities. Respond with 'unsupported capabilities'
* status code.
*/
lim_send_assoc_rsp_mgmt_frame(pMac,
eSIR_MAC_CAPABILITIES_NOT_SUPPORTED_STATUS,
1,
pHdr->sa, subType, 0, psessionEntry);
goto error;
}
updateContext = false;
if (lim_cmp_s_sid(pMac, &pAssocReq->ssId, psessionEntry) == false) {
lim_log(pMac, LOGE,
FL("Received %s Req with unmatched ssid ( Received"
" SSID: %.*s current SSID: %.*s ) from "
MAC_ADDRESS_STR),
(LIM_ASSOC == subType) ? "Assoc" : "ReAssoc",
pAssocReq->ssId.length, pAssocReq->ssId.ssId,
psessionEntry->ssId.length, psessionEntry->ssId.ssId,
MAC_ADDR_ARRAY(pHdr->sa));
/**
* Received Re/Association Request with either
* Broadcast SSID OR with SSID that does not
* match with local one.
* Respond with unspecified status code.
*/
lim_send_assoc_rsp_mgmt_frame(pMac,
eSIR_MAC_UNSPEC_FAILURE_STATUS,
1,
pHdr->sa, subType, 0, psessionEntry);
goto error;
}
/***************************************************************
** Verify if the requested rates are available in supported rate
** set or Extended rate set. Some APs are adding basic rates in
** Extended rateset IE
***************************************************************/
basicRates.numRates = 0;
for (i = 0;
i < pAssocReq->supportedRates.numRates
&& (i < SIR_MAC_RATESET_EID_MAX); i++) {
basicRates.rate[i] = pAssocReq->supportedRates.rate[i];
basicRates.numRates++;
}
for (j = 0;
(j < pAssocReq->extendedRates.numRates)
&& (i < SIR_MAC_RATESET_EID_MAX); i++, j++) {
basicRates.rate[i] = pAssocReq->extendedRates.rate[j];
basicRates.numRates++;
}
if (lim_check_rx_basic_rates(pMac, basicRates, psessionEntry) == false) {
lim_log(pMac, LOGE, FL("Received %s Req with unsupported "
"rates from" MAC_ADDRESS_STR),
(LIM_ASSOC == subType) ? "Assoc" : "ReAssoc",
MAC_ADDR_ARRAY(pHdr->sa));
/**
* Requesting STA does not support ALL BSS basic
* rates. Respond with 'basic rates not supported'
* status code.
*/
lim_send_assoc_rsp_mgmt_frame(pMac,
eSIR_MAC_BASIC_RATES_NOT_SUPPORTED_STATUS,
1,
pHdr->sa, subType, 0, psessionEntry);
goto error;
}
if (LIM_IS_AP_ROLE(psessionEntry) &&
(psessionEntry->dot11mode == WNI_CFG_DOT11_MODE_11G_ONLY) &&
(pAssocReq->HTCaps.present))
{
lim_log(pMac, LOGE,
FL("SOFTAP was in 11G only mode, rejecting legacy "
"STA : " MAC_ADDRESS_STR), MAC_ADDR_ARRAY(pHdr->sa));
lim_send_assoc_rsp_mgmt_frame(pMac,
eSIR_MAC_CAPABILITIES_NOT_SUPPORTED_STATUS,
1, pHdr->sa, subType, 0,
psessionEntry);
goto error;
} /* end if phyMode == 11G_only */
if (LIM_IS_AP_ROLE(psessionEntry) &&
(psessionEntry->dot11mode == WNI_CFG_DOT11_MODE_11N_ONLY) &&
(!pAssocReq->HTCaps.present)) {
lim_log(pMac, LOGE,
FL("SOFTAP was in 11N only mode, rejecting legacy "
"STA : " MAC_ADDRESS_STR), MAC_ADDR_ARRAY(pHdr->sa));
lim_send_assoc_rsp_mgmt_frame(pMac,
eSIR_MAC_CAPABILITIES_NOT_SUPPORTED_STATUS,
1, pHdr->sa, subType, 0,
psessionEntry);
goto error;
} /* end if PhyMode == 11N_only */
if (LIM_IS_AP_ROLE(psessionEntry) &&
(psessionEntry->dot11mode == WNI_CFG_DOT11_MODE_11AC_ONLY) &&
(!pAssocReq->VHTCaps.present)) {
lim_send_assoc_rsp_mgmt_frame(pMac,
eSIR_MAC_CAPABILITIES_NOT_SUPPORTED_STATUS,
1, pHdr->sa, subType, 0,
psessionEntry);
lim_log(pMac, LOGE, FL("SOFTAP was in 11AC only mode, reject"));
goto error;
} /* end if PhyMode == 11AC_only */
/* Spectrum Management (11h) specific checks */
if (localCapabilities.spectrumMgt) {
tSirRetStatus status = eSIR_SUCCESS;
/* If station is 11h capable, then it SHOULD send all mandatory
* IEs in assoc request frame. Let us verify that
*/
if (pAssocReq->capabilityInfo.spectrumMgt) {
if (!
((pAssocReq->powerCapabilityPresent)
&& (pAssocReq->supportedChannelsPresent))) {
/* One or more required information elements are missing, log the peers error */
if (!pAssocReq->powerCapabilityPresent) {
lim_log(pMac, LOG1,
FL
("LIM Info: Missing Power capability "
"IE in %s Req from "
MAC_ADDRESS_STR),
(LIM_ASSOC ==
subType) ? "Assoc" : "ReAssoc",
MAC_ADDR_ARRAY(pHdr->sa));
}
if (!pAssocReq->supportedChannelsPresent) {
lim_log(pMac, LOGW,
FL
("LIM Info: Missing Supported channel "
"IE in %s Req from "
MAC_ADDRESS_STR),
(LIM_ASSOC ==
subType) ? "Assoc" : "ReAssoc",
MAC_ADDR_ARRAY(pHdr->sa));
}
} else {
/* Assoc request has mandatory fields */
status =
lim_is_dot11h_power_capabilities_in_range(pMac,
pAssocReq,
psessionEntry);
if (eSIR_SUCCESS != status) {
lim_log(pMac, LOGW,
FL("LIM Info: MinTxPower(STA) > "
"MaxTxPower(AP) in %s Req from "
MAC_ADDRESS_STR),
(LIM_ASSOC ==
subType) ? "Assoc" : "ReAssoc",
MAC_ADDR_ARRAY(pHdr->sa));
}
status =
lim_is_dot11h_supported_channels_valid(pMac,
pAssocReq);
if (eSIR_SUCCESS != status) {
lim_log(pMac, LOGW,
FL("LIM Info: wrong supported "
"channels (STA) in %s Req from "
MAC_ADDRESS_STR),
(LIM_ASSOC ==
subType) ? "Assoc" : "ReAssoc",
MAC_ADDR_ARRAY(pHdr->sa));
}
/* IEs are valid, use them if needed */
}
} /* if(assoc.capabilityInfo.spectrumMgt) */
else {
/* As per the capabiities, the spectrum management is not enabled on the station
* The AP may allow the associations to happen even if spectrum management is not
* allowed, if the transmit power of station is below the regulatory maximum
*/
/* TODO: presently, this is not handled. In the current implemetation, the AP would
* allow the station to associate even if it doesn't support spectrum management.
*/
}
} /* end of spectrum management related processing */
if ((pAssocReq->HTCaps.present)
&& (lim_check_mcs_set(pMac, pAssocReq->HTCaps.supportedMCSSet) ==
false)) {
lim_log(pMac, LOGE,
FL("received %s req with unsupported"
"MCS Rate Set from " MAC_ADDRESS_STR),
(LIM_ASSOC == subType) ? "Assoc" : "ReAssoc",
MAC_ADDR_ARRAY(pHdr->sa));
/**
* Requesting STA does not support ALL BSS MCS basic Rate set rates.
* Spec does not define any status code for this scenario.
*/
lim_send_assoc_rsp_mgmt_frame(pMac,
eSIR_MAC_OUTSIDE_SCOPE_OF_SPEC_STATUS,
1,
pHdr->sa, subType, 0, psessionEntry);
goto error;
}
if (phyMode == WNI_CFG_PHY_MODE_11G) {
if (wlan_cfg_get_int(pMac, WNI_CFG_11G_ONLY_POLICY, &val) !=
eSIR_SUCCESS) {
lim_log(pMac, LOGP,
FL("could not retrieve 11g-only flag"));
goto error;
}
if (!pAssocReq->extendedRatesPresent && val) {
/**
* Received Re/Association Request from
* 11b STA when 11g only policy option
* is set.
* Reject with unspecified status code.
*/
lim_send_assoc_rsp_mgmt_frame(pMac,
eSIR_MAC_BASIC_RATES_NOT_SUPPORTED_STATUS,
1,
pHdr->sa,
subType, 0, psessionEntry);
lim_log(pMac, LOGE,
FL("Rejecting Re/Assoc req from 11b STA: "));
lim_print_mac_addr(pMac, pHdr->sa, LOGW);
#ifdef WLAN_DEBUG
pMac->lim.gLim11bStaAssocRejectCount++;
#endif
goto error;
}
}
/* Check for 802.11n HT caps compatibility; are HT Capabilities */
/* turned on in lim? */
if (psessionEntry->htCapability) {
/* There are; are they turned on in the STA? */
if (pAssocReq->HTCaps.present) {
/* The station *does* support 802.11n HT capability... */
lim_log(pMac, LOG1, FL("AdvCodingCap:%d ChaWidthSet:%d "
"PowerSave:%d greenField:%d "
"shortGI20:%d shortGI40:%d"
"txSTBC:%d rxSTBC:%d delayBA:%d"
"maxAMSDUsize:%d DSSS/CCK:%d "
"PSMP:%d stbcCntl:%d lsigTXProt:%d"),
pAssocReq->HTCaps.advCodingCap,
pAssocReq->HTCaps.supportedChannelWidthSet,
pAssocReq->HTCaps.mimoPowerSave,
pAssocReq->HTCaps.greenField,
pAssocReq->HTCaps.shortGI20MHz,
pAssocReq->HTCaps.shortGI40MHz,
pAssocReq->HTCaps.txSTBC,
pAssocReq->HTCaps.rxSTBC,
pAssocReq->HTCaps.delayedBA,
pAssocReq->HTCaps.maximalAMSDUsize,
pAssocReq->HTCaps.dsssCckMode40MHz,
pAssocReq->HTCaps.psmp,
pAssocReq->HTCaps.stbcControlFrame,
pAssocReq->HTCaps.lsigTXOPProtection);
/* Make sure the STA's caps are compatible with our own: */
/* 11.15.2 Support of DSSS/CCK in 40 MHz */
/* the AP shall refuse association requests from an HT STA that has the DSSS/CCK */
/* Mode in 40 MHz subfield set to 1; */
}
} /* End if on HT caps turned on in lim. */
/* Clear the buffers so that frame parser knows that there isn't a previously decoded IE in these buffers */
cdf_mem_set((uint8_t *) &Dot11fIERSN, sizeof(Dot11fIERSN), 0);
cdf_mem_set((uint8_t *) &Dot11fIEWPA, sizeof(Dot11fIEWPA), 0);
/* if additional IE is present, check if it has WscIE */
if (pAssocReq->addIEPresent && pAssocReq->addIE.length)
wpsIe =
limGetWscIEPtr(pMac, pAssocReq->addIE.addIEdata,
pAssocReq->addIE.length);
else {
lim_log(pMac, LOG1, FL("Assoc req addIEPresent = %d "
"addIE length = %d"),
pAssocReq->addIEPresent, pAssocReq->addIE.length);
}
/* when wpsIe is present, RSN/WPA IE is ignored */
if (wpsIe == NULL) {
/** check whether as RSN IE is present */
if (LIM_IS_AP_ROLE(psessionEntry) &&
psessionEntry->pLimStartBssReq->privacy &&
psessionEntry->pLimStartBssReq->rsnIE.length) {
lim_log(pMac, LOG1,
FL("RSN enabled auth, Re/Assoc req from STA: "
MAC_ADDRESS_STR), MAC_ADDR_ARRAY(pHdr->sa));
if (pAssocReq->rsnPresent) {
if (pAssocReq->rsn.length) {
/* Unpack the RSN IE */
dot11f_unpack_ie_rsn(pMac,
&pAssocReq->rsn.
info[0],
pAssocReq->rsn.length,
&Dot11fIERSN);
/* Check RSN version is supported or not */
if (SIR_MAC_OUI_VERSION_1 ==
Dot11fIERSN.version) {
/* check the groupwise and pairwise cipher suites */
if (eSIR_SUCCESS !=
(status =
lim_check_rx_rsn_ie_match(pMac,
Dot11fIERSN,
psessionEntry,
pAssocReq->
HTCaps.
present,
&pmfConnection)))
{
lim_log(pMac, LOGE,
FL("RSN Mismatch."
"Rejecting Re/Assoc req from "
"STA: "
MAC_ADDRESS_STR),
MAC_ADDR_ARRAY
(pHdr->sa));
/* some IE is not properly sent */
/* received Association req frame with RSN IE but length is 0 */
lim_send_assoc_rsp_mgmt_frame
(pMac, status, 1,
pHdr->sa, subType,
0, psessionEntry);
goto error;
}
} else {
lim_log(pMac, LOGE,
FL("RSN length not correct."
"Rejecting Re/Assoc req from "
"STA: "
MAC_ADDRESS_STR),
MAC_ADDR_ARRAY(pHdr->
sa));
/* received Association req frame with RSN IE version wrong */
lim_send_assoc_rsp_mgmt_frame(pMac,
eSIR_MAC_UNSUPPORTED_RSN_IE_VERSION_STATUS,
1,
pHdr->
sa,
subType,
0,
psessionEntry);
goto error;
}
} else {
lim_log(pMac, LOGW,
FL
("Rejecting Re/Assoc req from STA:"
MAC_ADDRESS_STR),
MAC_ADDR_ARRAY(pHdr->sa));
/* received Association req frame with RSN IE but length is 0 */
lim_send_assoc_rsp_mgmt_frame(pMac,
eSIR_MAC_INVALID_INFORMATION_ELEMENT_STATUS,
1,
pHdr->sa,
subType, 0,
psessionEntry);
goto error;
}
} /* end - if(pAssocReq->rsnPresent) */
if ((!pAssocReq->rsnPresent) && pAssocReq->wpaPresent) {
/* Unpack the WPA IE */
if (pAssocReq->wpa.length) {
dot11f_unpack_ie_wpa(pMac, &pAssocReq->wpa.info[4], /* OUI is not taken care */
pAssocReq->wpa.length,
&Dot11fIEWPA);
/* check the groupwise and pairwise cipher suites */
if (eSIR_SUCCESS !=
(status =
lim_check_rx_wpa_ie_match(pMac,
Dot11fIEWPA,
psessionEntry,
pAssocReq->
HTCaps.
present))) {
lim_log(pMac, LOGW,
FL("WPA IE mismatch"
"Rejecting Re/Assoc req from "
"STA: "
MAC_ADDRESS_STR),
MAC_ADDR_ARRAY(pHdr->
sa));
/* received Association req frame with WPA IE but mismatch */
lim_send_assoc_rsp_mgmt_frame(pMac,
status,
1,
pHdr->
sa,
subType,
0,
psessionEntry);
goto error;
}
} else {
lim_log(pMac, LOGW,
FL("WPA len incorrect."
"Rejecting Re/Assoc req from"
"STA: "MAC_ADDRESS_STR),
MAC_ADDR_ARRAY(pHdr->sa));
/* received Association req frame with invalid WPA IE */
lim_send_assoc_rsp_mgmt_frame(pMac,
eSIR_MAC_INVALID_INFORMATION_ELEMENT_STATUS,
1,
pHdr->sa,
subType, 0,
psessionEntry);
goto error;
} /* end - if(pAssocReq->wpa.length) */
} /* end - if(pAssocReq->wpaPresent) */
}
/* end of if(psessionEntry->pLimStartBssReq->privacy
&& psessionEntry->pLimStartBssReq->rsnIE->length) */
} /* end of if( ! pAssocReq->wscInfo.present ) */
else {
lim_log(pMac, LOG1, FL("Assoc req WSE IE is present"));
}
/**
* Extract 'associated' context for STA, if any.
* This is maintained by DPH and created by LIM.
*/
pStaDs =
dph_lookup_hash_entry(pMac, pHdr->sa, &peerIdx,
&psessionEntry->dph.dphHashTable);
/* / Extract pre-auth context for the STA, if any. */
pStaPreAuthContext = lim_search_pre_auth_list(pMac, pHdr->sa);
if (pStaDs == NULL) {
/* / Requesting STA is not currently associated */
if (pe_get_current_stas_count(pMac) ==
pMac->lim.gLimAssocStaLimit) {
/**
* Maximum number of STAs that AP can handle reached.
* Send Association response to peer MAC entity
*/
lim_log(pMac, LOGE, FL("Max Sta count reached : %d"),
pMac->lim.maxStation);
lim_reject_association(pMac, pHdr->sa,
subType, false,
(tAniAuthType) 0, 0,
false,
(tSirResultCodes)
eSIR_MAC_UNSPEC_FAILURE_STATUS,
psessionEntry);
goto error;
}
/* / Check if STA is pre-authenticated. */
if ((pStaPreAuthContext == NULL) ||
(pStaPreAuthContext &&
(pStaPreAuthContext->mlmState !=
eLIM_MLM_AUTHENTICATED_STATE))) {
/**
* STA is not pre-authenticated yet requesting
* Re/Association before Authentication.
* OR STA is in the process of getting authenticated
* and sent Re/Association request.
* Send Deauthentication frame with 'prior
* authentication required' reason code.
*/
lim_send_deauth_mgmt_frame(pMac, eSIR_MAC_STA_NOT_PRE_AUTHENTICATED_REASON, /* =9 */
pHdr->sa, psessionEntry, false);
lim_log(pMac, LOGE,
FL("received %s req on sessionid: %d from STA "
"that does not have pre-auth context"
MAC_ADDRESS_STR),
(LIM_ASSOC == subType) ? "Assoc" : "ReAssoc",
psessionEntry->peSessionId,
MAC_ADDR_ARRAY(pHdr->sa));
goto error;
}
/* / Delete 'pre-auth' context of STA */
authType = pStaPreAuthContext->authType;
lim_delete_pre_auth_node(pMac, pHdr->sa);
/* All is well. Assign AID (after else part) */
} /* if (pStaDs == NULL) */
else {
/* STA context does exist for this STA */
if (pStaDs->mlmStaContext.mlmState !=
eLIM_MLM_LINK_ESTABLISHED_STATE) {
/**
* Requesting STA is in some 'transient' state?
* Ignore the Re/Assoc Req frame by incrementing
* debug counter & logging error.
*/
if (subType == LIM_ASSOC) {
#ifdef WLAN_DEBUG
pMac->lim.gLimNumAssocReqDropInvldState++;
#endif
lim_log(pMac, LOGE,
FL("received Assoc req in state "
"%X from "),
pStaDs->mlmStaContext.mlmState);
} else {
#ifdef WLAN_DEBUG
pMac->lim.gLimNumReassocReqDropInvldState++;
#endif
lim_log(pMac, LOGE,
FL("received ReAssoc req in state %X"
" from "),
pStaDs->mlmStaContext.mlmState);
}
lim_print_mac_addr(pMac, pHdr->sa, LOG1);
lim_print_mlm_state(pMac, LOG1,
(tLimMlmStates) pStaDs->mlmStaContext.
mlmState);
goto error;
} /* if (pStaDs->mlmStaContext.mlmState != eLIM_MLM_LINK_ESTABLISHED_STATE) */
/* STA sent association Request frame while already in
* 'associated' state */
#ifdef WLAN_FEATURE_11W
lim_log(pMac, LOG1,
FL
("Re/Assoc request from station that is already associated"));
lim_log(pMac, LOG1, FL("PMF enabled %d, SA Query state %d"),
pStaDs->rmfEnabled, pStaDs->pmfSaQueryState);
if (pStaDs->rmfEnabled) {
switch (pStaDs->pmfSaQueryState) {
/* start SA Query procedure, respond to Association Request */
/* with try again later */
case DPH_SA_QUERY_NOT_IN_PROGRESS:
/*
* We should reset the retry counter before we start
* the SA query procedure, otherwise in next set of SA query
* procedure we will end up using the stale value.
*/
pStaDs->pmfSaQueryRetryCount = 0;
lim_send_assoc_rsp_mgmt_frame(pMac,
eSIR_MAC_TRY_AGAIN_LATER,
1, pHdr->sa, subType,
pStaDs, psessionEntry);
lim_send_sa_query_request_frame(pMac,
(uint8_t *) &
(pStaDs->
pmfSaQueryCurrentTransId),
pHdr->sa,
psessionEntry);
pStaDs->pmfSaQueryStartTransId =
pStaDs->pmfSaQueryCurrentTransId;
pStaDs->pmfSaQueryCurrentTransId++;
/* start timer for SA Query retry */
if (tx_timer_activate(&pStaDs->pmfSaQueryTimer)
!= TX_SUCCESS) {
lim_log(pMac, LOGE,
FL
("PMF SA Query timer activation failed!"));
goto error;
}
pStaDs->pmfSaQueryState =
DPH_SA_QUERY_IN_PROGRESS;
goto error;
/* SA Query procedure still going, respond to Association */
/* Request with try again later */
case DPH_SA_QUERY_IN_PROGRESS:
lim_send_assoc_rsp_mgmt_frame(pMac,
eSIR_MAC_TRY_AGAIN_LATER,
1, pHdr->sa, subType,
0, psessionEntry);
goto error;
/* SA Query procedure timed out, accept Association Request */
/* normally */
case DPH_SA_QUERY_TIMED_OUT:
pStaDs->pmfSaQueryState =
DPH_SA_QUERY_NOT_IN_PROGRESS;
break;
}
}
#endif
/* no change in the capability so drop the frame */
if ((true ==
cdf_mem_compare(&pStaDs->mlmStaContext.capabilityInfo,
&pAssocReq->capabilityInfo,
sizeof(tSirMacCapabilityInfo)))
&& (subType == LIM_ASSOC)) {
lim_log(pMac, LOGE,
FL(" Received Assoc req in state %X STAid=%d"),
pStaDs->mlmStaContext.mlmState, peerIdx);
goto error;
} else {
/**
* STA sent Re/association Request frame while already in
* 'associated' state. Update STA capabilities and
* send Association response frame with same AID
*/
lim_log(pMac, LOG1,
FL("Recved Assoc req from STA already connected"
" UpdateConext"));
pStaDs->mlmStaContext.capabilityInfo =
pAssocReq->capabilityInfo;
if (pStaPreAuthContext
&& (pStaPreAuthContext->mlmState ==
eLIM_MLM_AUTHENTICATED_STATE)) {
/* / STA has triggered pre-auth again */
authType = pStaPreAuthContext->authType;
lim_delete_pre_auth_node(pMac, pHdr->sa);
} else
authType = pStaDs->mlmStaContext.authType;
updateContext = true;
if (dph_init_sta_state
(pMac, pHdr->sa, peerIdx, true,
&psessionEntry->dph.dphHashTable)
== NULL) {
lim_log(pMac, LOGE,
FL("could not Init STAid=%d"), peerIdx);
goto error;
}
}
goto sendIndToSme;
} /* end if (lookup for STA in perStaDs fails) */
/* check if sta is allowed per QoS AC rules */
limGetWmeMode(psessionEntry, &wmeMode);
if ((qosMode == eHAL_SET) || (wmeMode == eHAL_SET)) {
/* for a qsta, check if the requested Traffic spec */
/* is admissible */
/* for a non-qsta check if the sta can be admitted */
if (pAssocReq->addtsPresent) {
uint8_t tspecIdx = 0; /* index in the sch tspec table. */
if (lim_admit_control_add_ts
(pMac, pHdr->sa, &(pAssocReq->addtsReq),
&(pAssocReq->qosCapability), 0, false, NULL,
&tspecIdx, psessionEntry) != eSIR_SUCCESS) {
lim_log(pMac, LOGE,
FL("AdmitControl: TSPEC rejected"));
lim_send_assoc_rsp_mgmt_frame(pMac,
eSIR_MAC_QAP_NO_BANDWIDTH_REASON,
1, pHdr->sa, subType,
0, psessionEntry);
#ifdef WLAN_DEBUG
pMac->lim.gLimNumAssocReqDropACRejectTS++;
#endif
goto error;
}
} else if (lim_admit_control_add_sta(pMac, pHdr->sa, false)
!= eSIR_SUCCESS) {
lim_log(pMac, LOGE, FL("AdmitControl: Sta rejected"));
lim_send_assoc_rsp_mgmt_frame(pMac,
eSIR_MAC_QAP_NO_BANDWIDTH_REASON,
1,
pHdr->sa,
subType, 0, psessionEntry);
#ifdef WLAN_DEBUG
pMac->lim.gLimNumAssocReqDropACRejectSta++;
#endif
goto error;
}
/* else all ok */
lim_log(pMac, LOG1, FL("AdmitControl: Sta OK!"));
}
/**
* STA is Associated !
*/
lim_log(pMac, LOGE,
FL("Received %s Req successful from " MAC_ADDRESS_STR),
(LIM_ASSOC == subType) ? "Assoc" : "ReAssoc",
MAC_ADDR_ARRAY(pHdr->sa));
/**
* AID for this association will be same as the peer Index used in DPH table.
* Assign unused/least recently used peer Index from perStaDs.
* NOTE: lim_assign_peer_idx() assigns AID values ranging
* between 1 - cfg_item(WNI_CFG_ASSOC_STA_LIMIT)
*/
peerIdx = lim_assign_peer_idx(pMac, psessionEntry);
if (!peerIdx) {
/* Could not assign AID */
/* Reject association */
lim_log(pMac, LOGE,
FL("PeerIdx not avaialble. Reject associaton"));
lim_reject_association(pMac, pHdr->sa,
subType, true, authType,
peerIdx, false,
(tSirResultCodes)
eSIR_MAC_UNSPEC_FAILURE_STATUS,
psessionEntry);
goto error;
}
/**
* Add an entry to hash table maintained by DPH module
*/
pStaDs =
dph_add_hash_entry(pMac, pHdr->sa, peerIdx,
&psessionEntry->dph.dphHashTable);
if (pStaDs == NULL) {
/* Could not add hash table entry at DPH */
lim_log(pMac, LOGE,
FL("could not add hash entry at DPH for aid=%d, MacAddr:"
MAC_ADDRESS_STR), peerIdx, MAC_ADDR_ARRAY(pHdr->sa));
/* Release AID */
lim_release_peer_idx(pMac, peerIdx, psessionEntry);
lim_reject_association(pMac, pHdr->sa,
subType, true, authType, peerIdx, false,
(tSirResultCodes)
eSIR_MAC_UNSPEC_FAILURE_STATUS,
psessionEntry);
goto error;
}
sendIndToSme:
/*
* check here if the parsedAssocReq already
* pointing to the assoc_req and free it before
* assigning this new pAssocReq
*/
if (psessionEntry->parsedAssocReq != NULL) {
pTempAssocReq = psessionEntry->parsedAssocReq[pStaDs->assocId];
if (pTempAssocReq != NULL) {
if (pTempAssocReq->assocReqFrame) {
cdf_mem_free(pTempAssocReq->assocReqFrame);
pTempAssocReq->assocReqFrame = NULL;
pTempAssocReq->assocReqFrameLength = 0;
}
cdf_mem_free(pTempAssocReq);
pTempAssocReq = NULL;
}
psessionEntry->parsedAssocReq[pStaDs->assocId] = pAssocReq;
assoc_req_copied = true;
}
pStaDs->mlmStaContext.htCapability = pAssocReq->HTCaps.present;
#ifdef WLAN_FEATURE_11AC
pStaDs->mlmStaContext.vhtCapability = pAssocReq->VHTCaps.present;
#endif
pStaDs->qos.addtsPresent =
(pAssocReq->addtsPresent == 0) ? false : true;
pStaDs->qos.addts = pAssocReq->addtsReq;
pStaDs->qos.capability = pAssocReq->qosCapability;
pStaDs->versionPresent = 0;
/* short slot and short preamble should be updated before doing limaddsta */
pStaDs->shortPreambleEnabled =
(uint8_t) pAssocReq->capabilityInfo.shortPreamble;
pStaDs->shortSlotTimeEnabled =
(uint8_t) pAssocReq->capabilityInfo.shortSlotTime;
pStaDs->valid = 0;
pStaDs->mlmStaContext.authType = authType;
pStaDs->staType = STA_ENTRY_PEER;
/* TODO: If listen interval is more than certain limit, reject the association. */
/* Need to check customer requirements and then implement. */
pStaDs->mlmStaContext.listenInterval = pAssocReq->listenInterval;
pStaDs->mlmStaContext.capabilityInfo = pAssocReq->capabilityInfo;
/* The following count will be used to knock-off the station if it doesn't
* come back to receive the buffered data. The AP will wait for numTimSent number
* of beacons after sending TIM information for the station, before assuming that
* the station is no more associated and disassociates it
*/
/** timWaitCount is used by PMM for monitoring the STA's in PS for LINK*/
pStaDs->timWaitCount =
(uint8_t) GET_TIM_WAIT_COUNT(pAssocReq->listenInterval);
/** Initialise the Current successful MPDU's tranfered to this STA count as 0 */
pStaDs->curTxMpduCnt = 0;
if (IS_DOT11_MODE_HT(psessionEntry->dot11mode) &&
pAssocReq->HTCaps.present && pAssocReq->wmeInfoPresent) {
pStaDs->htGreenfield = (uint8_t) pAssocReq->HTCaps.greenField;
pStaDs->htAMpduDensity = pAssocReq->HTCaps.mpduDensity;
pStaDs->htDsssCckRate40MHzSupport =
(uint8_t) pAssocReq->HTCaps.dsssCckMode40MHz;
pStaDs->htLsigTXOPProtection =
(uint8_t) pAssocReq->HTCaps.lsigTXOPProtection;
pStaDs->htMaxAmsduLength =
(uint8_t) pAssocReq->HTCaps.maximalAMSDUsize;
pStaDs->htMaxRxAMpduFactor = pAssocReq->HTCaps.maxRxAMPDUFactor;
pStaDs->htMIMOPSState = pAssocReq->HTCaps.mimoPowerSave;
/* pAssocReq will be copied to psessionEntry->parsedAssocReq
* later
*/
ht_cap_ie = ((uint8_t *) &pAssocReq->HTCaps) + 1;
/* check whether AP is enabled with shortGI */
if (wlan_cfg_get_int(pMac, WNI_CFG_SHORT_GI_20MHZ, &val) !=
eSIR_SUCCESS) {
PELOGE(lim_log(pMac, LOGE,
FL("could not retrieve shortGI 20Mhz CFG"));)
goto error;
}
if (val) {
pStaDs->htShortGI20Mhz =
(uint8_t)pAssocReq->HTCaps.shortGI20MHz;
} else {
/* Unset htShortGI20Mhz in ht_caps*/
*ht_cap_ie &= ~(1 << SIR_MAC_HT_CAP_SHORTGI20MHZ_S);
pStaDs->htShortGI20Mhz = 0;
}
if (wlan_cfg_get_int(pMac, WNI_CFG_SHORT_GI_40MHZ, &val) !=
eSIR_SUCCESS) {
PELOGE(lim_log(pMac, LOGE,
FL("could not retrieve shortGI 40Mhz CFG"));)
goto error;
}
if (val) {
pStaDs->htShortGI40Mhz =
(uint8_t)pAssocReq->HTCaps.shortGI40MHz;
} else {
/* Unset htShortGI40Mhz in ht_caps */
*ht_cap_ie &= ~(1 << SIR_MAC_HT_CAP_SHORTGI40MHZ_S);
pStaDs->htShortGI40Mhz = 0;
}
pStaDs->htSupportedChannelWidthSet =
(uint8_t) pAssocReq->HTCaps.supportedChannelWidthSet;
/*
* peer just follows AP; so when we are softAP/GO,
* we just store our session entry's secondary channel offset
* here in peer INFRA STA. However, if peer's 40MHz channel
* width support is disabled then secondary channel will be zero
*/
pStaDs->htSecondaryChannelOffset =
(pStaDs->htSupportedChannelWidthSet) ? psessionEntry->
htSecondaryChannelOffset : 0;
#ifdef WLAN_FEATURE_11AC
if (pAssocReq->operMode.present) {
pStaDs->vhtSupportedChannelWidthSet =
(uint8_t) ((pAssocReq->operMode.chanWidth ==
eHT_CHANNEL_WIDTH_80MHZ) ?
WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ :
WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ);
pStaDs->htSupportedChannelWidthSet =
(uint8_t) (pAssocReq->operMode.
chanWidth ? eHT_CHANNEL_WIDTH_40MHZ :
eHT_CHANNEL_WIDTH_20MHZ);
} else if (pAssocReq->VHTCaps.present) {
/* Check if STA has enabled it's channel bonding mode. */
/* If channel bonding mode is enabled, we decide based on SAP's current configuration. */
/* else, we set it to VHT20. */
pStaDs->vhtSupportedChannelWidthSet =
(uint8_t) ((pStaDs->htSupportedChannelWidthSet ==
eHT_CHANNEL_WIDTH_20MHZ) ?
WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ :
psessionEntry->ch_width - 1);
pStaDs->htMaxRxAMpduFactor =
pAssocReq->VHTCaps.maxAMPDULenExp;
}
/* Lesser among the AP and STA bandwidth of operation. */
pStaDs->htSupportedChannelWidthSet =
(pStaDs->htSupportedChannelWidthSet <
psessionEntry->htSupportedChannelWidthSet) ?
pStaDs->htSupportedChannelWidthSet :
psessionEntry->htSupportedChannelWidthSet;
#endif
pStaDs->baPolicyFlag = 0xFF;
pStaDs->htLdpcCapable =
(uint8_t) pAssocReq->HTCaps.advCodingCap;
}
if (pAssocReq->VHTCaps.present && pAssocReq->wmeInfoPresent) {
pStaDs->vhtLdpcCapable =
(uint8_t) pAssocReq->VHTCaps.ldpcCodingCap;
}
if (!pAssocReq->wmeInfoPresent) {
pStaDs->mlmStaContext.htCapability = 0;
pStaDs->mlmStaContext.vhtCapability = 0;
}
if (pStaDs->mlmStaContext.vhtCapability) {
if (psessionEntry->txBFIniFeatureEnabled &&
pAssocReq->VHTCaps.suBeamFormerCap)
pStaDs->vhtBeamFormerCapable = 1;
else
pStaDs->vhtBeamFormerCapable = 0;
if (psessionEntry->enable_su_tx_bformer &&
pAssocReq->VHTCaps.suBeamformeeCap)
pStaDs->vht_su_bfee_capable = 1;
else
pStaDs->vht_su_bfee_capable = 0;
}
#ifdef WLAN_FEATURE_11AC
if (lim_populate_matching_rate_set(pMac,
pStaDs,
&(pAssocReq->supportedRates),
&(pAssocReq->extendedRates),
pAssocReq->HTCaps.supportedMCSSet,
psessionEntry, &pAssocReq->VHTCaps)
!= eSIR_SUCCESS)
#else
if (lim_populate_matching_rate_set(pMac,
pStaDs,
&(pAssocReq->supportedRates),
&(pAssocReq->extendedRates),
pAssocReq->HTCaps.supportedMCSSet,
psessionEntry) != eSIR_SUCCESS)
#endif
{
/* Could not update hash table entry at DPH with rateset */
lim_log(pMac, LOGE,
FL
("could not update hash entry at DPH for aid=%d, MacAddr: "
MAC_ADDRESS_STR), peerIdx, MAC_ADDR_ARRAY(pHdr->sa));
/* Release AID */
lim_release_peer_idx(pMac, peerIdx, psessionEntry);
lim_reject_association(pMac, pHdr->sa,
subType, true, authType, peerIdx, true,
(tSirResultCodes)
eSIR_MAC_UNSPEC_FAILURE_STATUS,
psessionEntry);
if (psessionEntry->parsedAssocReq)
pAssocReq =
psessionEntry->parsedAssocReq[pStaDs->assocId];
goto error;
}
#ifdef WLAN_FEATURE_11AC
if (pAssocReq->operMode.present) {
pStaDs->vhtSupportedRxNss = pAssocReq->operMode.rxNSS + 1;
} else {
pStaDs->vhtSupportedRxNss =
((pStaDs->supportedRates.vhtRxMCSMap & MCSMAPMASK2x2)
== MCSMAPMASK2x2) ? 1 : 2;
}
#endif
/* / Add STA context at MAC HW (BMU, RHP & TFP) */
pStaDs->qosMode = false;
pStaDs->lleEnabled = false;
if (pAssocReq->capabilityInfo.qos && (qosMode == eHAL_SET)) {
pStaDs->lleEnabled = true;
pStaDs->qosMode = true;
}
pStaDs->wmeEnabled = false;
pStaDs->wsmEnabled = false;
limGetWmeMode(psessionEntry, &wmeMode);
if ((!pStaDs->lleEnabled) && pAssocReq->wmeInfoPresent
&& (wmeMode == eHAL_SET)) {
pStaDs->wmeEnabled = true;
pStaDs->qosMode = true;
limGetWsmMode(psessionEntry, &wsmMode);
/* WMM_APSD - WMM_SA related processing should be separate; WMM_SA and WMM_APSD
can coexist */
if (pAssocReq->WMMInfoStation.present) {
/* check whether AP supports or not */
if (LIM_IS_AP_ROLE(psessionEntry) &&
(psessionEntry->apUapsdEnable == 0) &&
(pAssocReq->WMMInfoStation.acbe_uapsd ||
pAssocReq->WMMInfoStation.acbk_uapsd ||
pAssocReq->WMMInfoStation.acvo_uapsd ||
pAssocReq->WMMInfoStation.acvi_uapsd)) {
/**
* Received Re/Association Request from
* STA when UPASD is not supported.
*/
lim_log(pMac, LOGE,
FL("AP do not support UAPSD so reply "
"to STA accordingly"));
/* update UAPSD and send it to LIM to add STA */
pStaDs->qos.capability.qosInfo.acbe_uapsd = 0;
pStaDs->qos.capability.qosInfo.acbk_uapsd = 0;
pStaDs->qos.capability.qosInfo.acvo_uapsd = 0;
pStaDs->qos.capability.qosInfo.acvi_uapsd = 0;
pStaDs->qos.capability.qosInfo.maxSpLen = 0;
} else {
/* update UAPSD and send it to LIM to add STA */
pStaDs->qos.capability.qosInfo.acbe_uapsd =
pAssocReq->WMMInfoStation.acbe_uapsd;
pStaDs->qos.capability.qosInfo.acbk_uapsd =
pAssocReq->WMMInfoStation.acbk_uapsd;
pStaDs->qos.capability.qosInfo.acvo_uapsd =
pAssocReq->WMMInfoStation.acvo_uapsd;
pStaDs->qos.capability.qosInfo.acvi_uapsd =
pAssocReq->WMMInfoStation.acvi_uapsd;
pStaDs->qos.capability.qosInfo.maxSpLen =
pAssocReq->WMMInfoStation.max_sp_length;
}
}
if (pAssocReq->wsmCapablePresent && (wsmMode == eHAL_SET))
pStaDs->wsmEnabled = true;
}
/* Re/Assoc Response frame to requesting STA */
pStaDs->mlmStaContext.subType = subType;
#ifdef WLAN_FEATURE_11W
pStaDs->rmfEnabled = (pmfConnection) ? 1 : 0;
pStaDs->pmfSaQueryState = DPH_SA_QUERY_NOT_IN_PROGRESS;
timerId.fields.sessionId = psessionEntry->peSessionId;
timerId.fields.peerIdx = peerIdx;
if (wlan_cfg_get_int(pMac, WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL,
&retryInterval) != eSIR_SUCCESS) {
lim_log(pMac, LOGE,
FL
("Could not retrieve PMF SA Query retry interval value"));
lim_reject_association(pMac, pHdr->sa, subType, true, authType,
peerIdx, false,
(tSirResultCodes)
eSIR_MAC_UNSPEC_FAILURE_STATUS,
psessionEntry);
goto error;
}
if (WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL_STAMIN > retryInterval) {
retryInterval = WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL_STADEF;
}
if (tx_timer_create(&pStaDs->pmfSaQueryTimer, "PMF SA Query timer",
lim_pmf_sa_query_timer_handler, timerId.value,
SYS_MS_TO_TICKS((retryInterval * 1024) / 1000),
0, TX_NO_ACTIVATE) != TX_SUCCESS) {
lim_log(pMac, LOGE, FL("could not create PMF SA Query timer"));
lim_reject_association(pMac, pHdr->sa,
subType, true, authType,
peerIdx, false,
(tSirResultCodes)
eSIR_MAC_UNSPEC_FAILURE_STATUS,
psessionEntry);
goto error;
}
#endif
if (pAssocReq->ExtCap.present) {
lim_set_stads_rtt_cap(pStaDs,
(struct s_ext_cap *) pAssocReq->ExtCap.bytes, pMac);
} else {
pStaDs->timingMeasCap = 0;
PELOG1(lim_log(pMac, LOG1, FL("ExtCap not present"));)
}
/* BTAMP: Storing the parsed assoc request in the psessionEntry array */
if (psessionEntry->parsedAssocReq)
psessionEntry->parsedAssocReq[pStaDs->assocId] = pAssocReq;
assoc_req_copied = true;
/* BTAMP: If STA context already exist (ie. updateContext = 1)
* for this STA, then we should delete the old one, and add
* the new STA. This is taken care of in the lim_del_sta() routine.
*
* Prior to BTAMP, we were setting this flag so that when
* PE receives SME_ASSOC_CNF, and if this flag is set, then
* PE shall delete the old station and then add. But now in
* BTAMP, we're directly adding station before waiting for
* SME_ASSOC_CNF, so we can do this now.
*/
if (!updateContext) {
pStaDs->mlmStaContext.updateContext = 0;
/* BTAMP: Add STA context at HW - issue WMA_ADD_STA_REQ to HAL */
if (lim_add_sta(pMac, pStaDs, false, psessionEntry) !=
eSIR_SUCCESS) {
lim_log(pMac, LOGE,
FL("could not Add STA with assocId=%d"),
pStaDs->assocId);
lim_reject_association(pMac, pStaDs->staAddr,
pStaDs->mlmStaContext.subType,
true,
pStaDs->mlmStaContext.authType,
pStaDs->assocId, true,
(tSirResultCodes)
eSIR_MAC_UNSPEC_FAILURE_STATUS,
psessionEntry);
if (psessionEntry->parsedAssocReq)
pAssocReq = psessionEntry->parsedAssocReq[
pStaDs->assocId];
goto error;
}
} else {
pStaDs->mlmStaContext.updateContext = 1;
mlmPrevState = pStaDs->mlmStaContext.mlmState;
/* As per the HAL/FW needs the reassoc req need not be calling lim_del_sta */
if (subType != LIM_REASSOC) {
/* we need to set the mlmState here in order differentiate in lim_del_sta. */
pStaDs->mlmStaContext.mlmState =
eLIM_MLM_WT_ASSOC_DEL_STA_RSP_STATE;
if (lim_del_sta(pMac, pStaDs, true, psessionEntry) !=
eSIR_SUCCESS) {
lim_log(pMac, LOGE,
FL
("could not DEL STA with assocId=%d staId %d"),
pStaDs->assocId, pStaDs->staIndex);
lim_reject_association(pMac, pStaDs->staAddr,
pStaDs->mlmStaContext.
subType, true,
pStaDs->mlmStaContext.
authType, pStaDs->assocId,
true,
(tSirResultCodes)
eSIR_MAC_UNSPEC_FAILURE_STATUS,
psessionEntry);
/* Restoring the state back. */
pStaDs->mlmStaContext.mlmState = mlmPrevState;
if (psessionEntry->parsedAssocReq)
pAssocReq =
psessionEntry->parsedAssocReq[
pStaDs->assocId];
goto error;
}
} else {
/* mlmState is changed in lim_add_sta context */
/* use the same AID, already allocated */
if (lim_add_sta(pMac, pStaDs, false, psessionEntry) !=
eSIR_SUCCESS) {
lim_log(pMac, LOGE,
FL("Could not AddSta with assocId= %d"
"staId %d"),
pStaDs->assocId, pStaDs->staIndex);
lim_reject_association(pMac, pStaDs->staAddr,
pStaDs->mlmStaContext.
subType, true,
pStaDs->mlmStaContext.
authType, pStaDs->assocId,
true,
(tSirResultCodes)
eSIR_MAC_WME_REFUSED_STATUS,
psessionEntry);
/* Restoring the state back. */
pStaDs->mlmStaContext.mlmState = mlmPrevState;
if (psessionEntry->parsedAssocReq)
pAssocReq =
psessionEntry->parsedAssocReq[
pStaDs->assocId];
goto error;
}
}
}
/* AddSta is sucess here */
if (LIM_IS_AP_ROLE(psessionEntry) &&
IS_DOT11_MODE_HT(psessionEntry->dot11mode) &&
pAssocReq->HTCaps.present && pAssocReq->wmeInfoPresent) {
/** Update in the HAL Station Table for the Update of the Protection Mode */
lim_post_sm_state_update(pMac, pStaDs->staIndex,
pStaDs->htMIMOPSState,
pStaDs->staAddr,
psessionEntry->smeSessionId);
}
return;
error:
if (pAssocReq != NULL) {
if (pAssocReq->assocReqFrame) {
cdf_mem_free(pAssocReq->assocReqFrame);
pAssocReq->assocReqFrame = NULL;
pAssocReq->assocReqFrameLength = 0;
}
cdf_mem_free(pAssocReq);
/* to avoid double free */
if (assoc_req_copied && psessionEntry->parsedAssocReq)
psessionEntry->parsedAssocReq[pStaDs->assocId] = NULL;
}
/* If it is not duplicate Assoc request then only make to Null */
if ((pStaDs != NULL) &&
(pStaDs->mlmStaContext.mlmState != eLIM_MLM_WT_ADD_STA_RSP_STATE)) {
if (psessionEntry->parsedAssocReq != NULL) {
pTempAssocReq =
psessionEntry->parsedAssocReq[pStaDs->assocId];
if (pTempAssocReq != NULL) {
if (pTempAssocReq->assocReqFrame) {
cdf_mem_free(pTempAssocReq->
assocReqFrame);
pTempAssocReq->assocReqFrame = NULL;
pTempAssocReq->assocReqFrameLength = 0;
}
cdf_mem_free(pTempAssocReq);
psessionEntry->
parsedAssocReq[pStaDs->assocId] = NULL;
}
}
}
return;
} /*** end lim_process_assoc_req_frame() ***/
#ifdef FEATURE_WLAN_WAPI
/**
* lim_fill_assoc_ind_wapi_info()- Updates WAPI data in assoc indication
* @mac_ctx: Global Mac context
* @assoc_req: pointer to association request
* @assoc_ind: Pointer to association indication
* @wpsie: WPS IE
*
* This function updates WAPI meta data in association indication message
* sent to SME.
*
* Return: None
*/
static void lim_fill_assoc_ind_wapi_info(tpAniSirGlobal mac_ctx,
tpSirAssocReq assoc_req, tpLimMlmAssocInd assoc_ind,
uint8_t *wpsie)
{
if (assoc_req->wapiPresent && (NULL == wpsie)) {
lim_log(mac_ctx, LOG2,
FL("Received WAPI IE length in Assoc Req is %d"),
assoc_req->wapi.length);
assoc_ind->wapiIE.wapiIEdata[0] = SIR_MAC_WAPI_EID;
assoc_ind->wapiIE.wapiIEdata[1] = assoc_req->wapi.length;
cdf_mem_copy(&assoc_ind->wapiIE.wapiIEdata[2],
assoc_req->wapi.info, assoc_req->wapi.length);
assoc_ind->wapiIE.length =
2 + assoc_req->wapi.length;
}
return;
}
#endif
/**
* lim_fill_assoc_ind_vht_info() - Updates VHT information in assoc indication
* @mac_ctx: Global Mac context
* @assoc_req: pointer to association request
* @session_entry: PE session entry
* @assoc_ind: Pointer to association indication
*
* This function updates VHT information in association indication message
* sent to SME.
*
* Return: None
*/
static void lim_fill_assoc_ind_vht_info(tpAniSirGlobal mac_ctx,
tpPESession session_entry, tpSirAssocReq assoc_req,
tpLimMlmAssocInd assoc_ind)
{
uint8_t chan;
if (session_entry->limRFBand == SIR_BAND_2_4_GHZ) {
if (session_entry->vhtCapability
&& assoc_req->VHTCaps.present)
assoc_ind->chan_info.info = MODE_11AC_VHT20;
else if (session_entry->htCapability
&& assoc_req->HTCaps.present)
assoc_ind->chan_info.info = MODE_11NG_HT20;
else
assoc_ind->chan_info.info = MODE_11G;
} else {
if (session_entry->vhtCapability
&& assoc_req->VHTCaps.present) {
if ((session_entry->ch_width > CH_WIDTH_40MHZ)
&& assoc_req->HTCaps.supportedChannelWidthSet) {
chan = session_entry->ch_center_freq_seg0;
assoc_ind->chan_info.band_center_freq1 =
cds_chan_to_freq(chan);
assoc_ind->chan_info.info = MODE_11AC_VHT80;
} else if ((session_entry->ch_width == CH_WIDTH_40MHZ)
&& assoc_req->HTCaps.supportedChannelWidthSet) {
assoc_ind->chan_info.info = MODE_11AC_VHT40;
if (session_entry->htSecondaryChannelOffset ==
PHY_DOUBLE_CHANNEL_LOW_PRIMARY)
assoc_ind->chan_info.band_center_freq1
+= 10;
else
assoc_ind->chan_info.band_center_freq1
-= 10;
} else {
assoc_ind->chan_info.info = MODE_11AC_VHT20;
}
} else if (session_entry->htCapability
&& assoc_req->HTCaps.present) {
if ((session_entry->ch_width == CH_WIDTH_40MHZ)
&& assoc_req->HTCaps.supportedChannelWidthSet) {
assoc_ind->chan_info.info = MODE_11NA_HT40;
if (session_entry->htSecondaryChannelOffset ==
PHY_DOUBLE_CHANNEL_LOW_PRIMARY)
assoc_ind->chan_info.band_center_freq1
+= 10;
else
assoc_ind->chan_info.band_center_freq1
-= 10;
} else {
assoc_ind->chan_info.info = MODE_11NA_HT20;
}
} else {
assoc_ind->chan_info.info = MODE_11A;
}
}
return;
}
/**
* lim_send_mlm_assoc_ind() - Sends assoc indication to SME
* @mac_ctx: Global Mac context
* @sta_ds: Station DPH hash entry
* @session_entry: PE session entry
*
* This function sends either LIM_MLM_ASSOC_IND
* or LIM_MLM_REASSOC_IND to SME.
*
* Return: None
*/
void lim_send_mlm_assoc_ind(tpAniSirGlobal mac_ctx,
tpDphHashNode sta_ds, tpPESession session_entry)
{
tpLimMlmAssocInd assoc_ind = NULL;
tpSirAssocReq assoc_req;
uint16_t temp, rsn_len;
uint32_t phy_mode;
uint8_t sub_type;
uint8_t *wpsie = NULL;
uint32_t tmp;
/* Get a copy of the already parsed Assoc Request */
assoc_req =
(tpSirAssocReq) session_entry->parsedAssocReq[sta_ds->assocId];
/* Get the phy_mode */
lim_get_phy_mode(mac_ctx, &phy_mode, session_entry);
/* Determine if its Assoc or ReAssoc Request */
if (assoc_req->reassocRequest == 1)
sub_type = LIM_REASSOC;
else
sub_type = LIM_ASSOC;
lim_log(mac_ctx, LOG1,
FL("Sessionid %d ssid %s sub_type %d Associd %d staAddr "
MAC_ADDRESS_STR), session_entry->peSessionId,
assoc_req->ssId.ssId, sub_type, sta_ds->assocId,
MAC_ADDR_ARRAY(sta_ds->staAddr));
if (sub_type == LIM_ASSOC || sub_type == LIM_REASSOC) {
temp = sizeof(tLimMlmAssocInd);
assoc_ind = cdf_mem_malloc(temp);
if (NULL == assoc_ind) {
lim_release_peer_idx(mac_ctx, sta_ds->assocId,
session_entry);
lim_log(mac_ctx, LOGP,
FL("AllocateMemory failed for assoc_ind"));
return;
}
cdf_mem_set(assoc_ind, temp, 0);
cdf_mem_copy((uint8_t *) assoc_ind->peerMacAddr,
(uint8_t *) sta_ds->staAddr, sizeof(tSirMacAddr));
assoc_ind->aid = sta_ds->assocId;
cdf_mem_copy((uint8_t *) &assoc_ind->ssId,
(uint8_t *) &(assoc_req->ssId),
assoc_req->ssId.length + 1);
assoc_ind->sessionId = session_entry->peSessionId;
assoc_ind->authType = sta_ds->mlmStaContext.authType;
assoc_ind->capabilityInfo = assoc_req->capabilityInfo;
/* Fill in RSN IE information */
assoc_ind->rsnIE.length = 0;
/* if WPS IE is present, ignore RSN IE */
if (assoc_req->addIEPresent && assoc_req->addIE.length) {
wpsie = limGetWscIEPtr(mac_ctx,
assoc_req->addIE.addIEdata,
assoc_req->addIE.length);
}
if (assoc_req->rsnPresent && (NULL == wpsie)) {
lim_log(mac_ctx, LOG2, FL("Assoc Req RSN IE len = %d"),
assoc_req->rsn.length);
assoc_ind->rsnIE.length = 2 + assoc_req->rsn.length;
assoc_ind->rsnIE.rsnIEdata[0] = SIR_MAC_RSN_EID;
assoc_ind->rsnIE.rsnIEdata[1] =
assoc_req->rsn.length;
cdf_mem_copy(&assoc_ind->rsnIE.rsnIEdata[2],
assoc_req->rsn.info,
assoc_req->rsn.length);
}
/* Fill in 802.11h related info */
if (assoc_req->powerCapabilityPresent
&& assoc_req->supportedChannelsPresent) {
assoc_ind->spectrumMgtIndicator = eSIR_TRUE;
assoc_ind->powerCap.minTxPower =
assoc_req->powerCapability.minTxPower;
assoc_ind->powerCap.maxTxPower =
assoc_req->powerCapability.maxTxPower;
lim_convert_supported_channels(mac_ctx, assoc_ind,
assoc_req);
} else {
assoc_ind->spectrumMgtIndicator = eSIR_FALSE;
}
/* This check is to avoid extra Sec IEs present incase of WPS */
if (assoc_req->wpaPresent && (NULL == wpsie)) {
rsn_len = assoc_ind->rsnIE.length;
if ((rsn_len + assoc_req->wpa.length)
>= SIR_MAC_MAX_IE_LENGTH) {
lim_log(mac_ctx, LOGE,
FL("rsnIEdata index out of bounds %d"),
rsn_len);
cdf_mem_free(assoc_ind);
return;
}
assoc_ind->rsnIE.rsnIEdata[rsn_len] =
SIR_MAC_WPA_EID;
assoc_ind->rsnIE.rsnIEdata[rsn_len + 1]
= assoc_req->wpa.length;
cdf_mem_copy(
&assoc_ind->rsnIE.rsnIEdata[rsn_len + 2],
assoc_req->wpa.info, assoc_req->wpa.length);
assoc_ind->rsnIE.length += 2 + assoc_req->wpa.length;
}
#ifdef FEATURE_WLAN_WAPI
lim_fill_assoc_ind_wapi_info(mac_ctx, assoc_req, assoc_ind,
wpsie);
#endif
assoc_ind->addIE.length = 0;
if (assoc_req->addIEPresent) {
cdf_mem_copy(&assoc_ind->addIE.addIEdata,
assoc_req->addIE.addIEdata,
assoc_req->addIE.length);
assoc_ind->addIE.length = assoc_req->addIE.length;
}
/*
* Add HT Capabilities into addIE for OBSS
* processing in hostapd
*/
if (assoc_req->HTCaps.present) {
rsn_len = assoc_ind->addIE.length;
if (assoc_ind->addIE.length + DOT11F_IE_HTCAPS_MIN_LEN
+ 2 < SIR_MAC_MAX_IE_LENGTH) {
assoc_ind->addIE.addIEdata[rsn_len] =
SIR_MAC_HT_CAPABILITIES_EID;
assoc_ind->addIE.addIEdata[rsn_len + 1] =
DOT11F_IE_HTCAPS_MIN_LEN;
cdf_mem_copy(
&assoc_ind->addIE.addIEdata[rsn_len+2],
((uint8_t *)&assoc_req->HTCaps) + 1,
DOT11F_IE_HTCAPS_MIN_LEN);
assoc_ind->addIE.length +=
2 + DOT11F_IE_HTCAPS_MIN_LEN;
} else {
lim_log(mac_ctx, LOGP,
FL("Fail:HT capabilities IE to addIE"));
}
}
if (assoc_req->wmeInfoPresent) {
if (wlan_cfg_get_int (mac_ctx,
(uint16_t) WNI_CFG_WME_ENABLED, &tmp)
!= eSIR_SUCCESS)
lim_log(mac_ctx, LOGP,
FL("wlan_cfg_get_int failed for id %d"),
WNI_CFG_WME_ENABLED);
/* check whether AP is enabled with WMM */
if (tmp)
assoc_ind->WmmStaInfoPresent = 1;
else
assoc_ind->WmmStaInfoPresent = 0;
/*
* Note: we are not rejecting association here
* because IOT will fail
*/
}
/* Required for indicating the frames to upper layer */
assoc_ind->assocReqLength = assoc_req->assocReqFrameLength;
assoc_ind->assocReqPtr = assoc_req->assocReqFrame;
assoc_ind->beaconPtr = session_entry->beacon;
assoc_ind->beaconLength = session_entry->bcnLen;
assoc_ind->chan_info.chan_id =
session_entry->currentOperChannel;
assoc_ind->chan_info.mhz =
cds_chan_to_freq(session_entry->currentOperChannel);
assoc_ind->chan_info.band_center_freq1 =
cds_chan_to_freq(session_entry->currentOperChannel);
assoc_ind->chan_info.band_center_freq2 = 0;
assoc_ind->chan_info.reg_info_1 =
(session_entry->maxTxPower << 16);
assoc_ind->chan_info.reg_info_2 =
(session_entry->maxTxPower << 8);
/* updates VHT information in assoc indication */
lim_fill_assoc_ind_vht_info(mac_ctx, session_entry, assoc_req,
assoc_ind);
lim_post_sme_message(mac_ctx, LIM_MLM_ASSOC_IND,
(uint32_t *) assoc_ind);
cdf_mem_free(assoc_ind);
}
return;
}