blob: 2549bf55c835cc7f86618528d3f0f53aa024d176 [file] [log] [blame]
/*
* Copyright (c) 2012-2017 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 limPropExtsUtils.cc contains the utility functions
* to populate, parse proprietary extensions required to
* support ANI feature set.
*
* Author: Chandra Modumudi
* Date: 11/27/02
* History:-
* Date Modified by Modification Information
* --------------------------------------------------------------------
*
*/
#include "aniGlobal.h"
#include "wniCfg.h"
#include "sirCommon.h"
#include "sirDebug.h"
#include "utilsApi.h"
#include "cfgApi.h"
#include "limApi.h"
#include "limTypes.h"
#include "limUtils.h"
#include "limAssocUtils.h"
#include "limPropExtsUtils.h"
#include "limSerDesUtils.h"
#include "limTrace.h"
#include "limSession.h"
#define LIM_GET_NOISE_MAX_TRY 5
#define LIM_OPERATING_EXT_IDENTIFIER 201
/**
* limCheckOUI() - Check if the given OUI match in IE buffer
* @pMac: Pointer to Global MAC structure
* @pIE: Pointer to starting IE
* @ieLen: Length of all IEs
*
* Return: None
*/
static void limCheckOUI(tpAniSirGlobal pMac, tANI_U8 *pIE, tANI_U16 ieLen)
{
tANI_U16 left = ieLen;
tANI_U8 *ptr = pIE;
tANI_U8 elem_id, elem_len, oui_len, i=0;
pMac->roam.configParam.agg_btc_sco_enabled = eANI_BOOLEAN_FALSE;
if (!ptr || ieLen == 0) {
limLog(pMac, LOGE, FL("Invalid IEs"));
return;
}
if (!pMac->roam.configParam.num_ba_buff_btc_sco)
return;
oui_len = 3;
while(i < oui_len && pMac->roam.configParam.agg_btc_sco_oui[i] == 0)
i+=1;
if (i == oui_len) {
/*
* If gEnableAggBTCScoOUI ini is not set, oui is set to all
* zeros and aggregation during SCO should be enabled for
* all APs.
*/
pMac->roam.configParam.agg_btc_sco_enabled = eANI_BOOLEAN_TRUE;
return;
}
while (left >= 2) {
elem_id = ptr[0];
elem_len = ptr[1];
left -= 2;
if (elem_len > left) {
limLog(pMac, LOGE, FL("Invalid IEs eid: %d elem_len: %d left: %d"),
elem_id, elem_len, left);
return;
}
if (SIR_MAC_EID_VENDOR == elem_id) {
if (memcmp(&ptr[2], &pMac->roam.configParam.agg_btc_sco_oui,
oui_len) == 0) {
pMac->roam.configParam.agg_btc_sco_enabled = eANI_BOOLEAN_TRUE;
return;
}
}
left -= elem_len;
ptr += (elem_len + 2);
}
}
/**
* limExtractApCapability()
*
*FUNCTION:
* This function is called to extract AP's HCF/WME/WSM capability
* from the IEs received from it in Beacon/Probe Response frames
*
*LOGIC:
*
*ASSUMPTIONS:
* NA
*
*NOTE:
*
* @param pMac Pointer to Global MAC structure
* @param pIE Pointer to starting IE in Beacon/Probe Response
* @param ieLen Length of all IEs combined
* @param qosCap Bits are set according to capabilities
* @return 0 - If AP does not assert HCF capability & 1 - otherwise
*/
void
limExtractApCapability(tpAniSirGlobal pMac, tANI_U8 *pIE, tANI_U16 ieLen,
tANI_U8 *qosCap, tANI_U16 *propCap, tANI_U8 *uapsd,
tPowerdBm *localConstraint,
tpPESession psessionEntry
)
{
tSirProbeRespBeacon *pBeaconStruct;
#if !defined WLAN_FEATURE_VOWIFI
tANI_U32 localPowerConstraints = 0;
#endif
pBeaconStruct = vos_mem_malloc(sizeof(tSirProbeRespBeacon));
if ( NULL == pBeaconStruct )
{
limLog(pMac, LOGE, FL("Unable to allocate memory in limExtractApCapability") );
return;
}
vos_mem_set( (tANI_U8 *) pBeaconStruct, sizeof(tSirProbeRespBeacon), 0);
*qosCap = 0;
*propCap = 0;
*uapsd = 0;
PELOG3(limLog( pMac, LOG3,
FL("In limExtractApCapability: The IE's being received are:"));
sirDumpBuf( pMac, SIR_LIM_MODULE_ID, LOG3, pIE, ieLen );)
if (sirParseBeaconIE(pMac, pBeaconStruct, pIE, (tANI_U32)ieLen) == eSIR_SUCCESS)
{
if (pBeaconStruct->wmeInfoPresent || pBeaconStruct->wmeEdcaPresent
|| pBeaconStruct->HTCaps.present)
LIM_BSS_CAPS_SET(WME, *qosCap);
if (LIM_BSS_CAPS_GET(WME, *qosCap) && pBeaconStruct->wsmCapablePresent)
LIM_BSS_CAPS_SET(WSM, *qosCap);
if (pBeaconStruct->propIEinfo.aniIndicator &&
pBeaconStruct->propIEinfo.capabilityPresent)
*propCap = pBeaconStruct->propIEinfo.capability;
if (pBeaconStruct->HTCaps.present)
pMac->lim.htCapabilityPresentInBeacon = 1;
else
pMac->lim.htCapabilityPresentInBeacon = 0;
#ifdef WLAN_FEATURE_11AC
VOS_TRACE(VOS_MODULE_ID_PE, VOS_TRACE_LEVEL_INFO_MED,
"***beacon.VHTCaps.present*****=%d BSS_VHT_CAPABLE:%d",
pBeaconStruct->VHTCaps.present,
IS_BSS_VHT_CAPABLE(pBeaconStruct->VHTCaps));
VOS_TRACE(VOS_MODULE_ID_PE, VOS_TRACE_LEVEL_INFO_MED,
"***beacon.SU Beamformer Capable*****=%d",pBeaconStruct->VHTCaps.suBeamFormerCap);
if (IS_BSS_VHT_CAPABLE(pBeaconStruct->VHTCaps)
&& pBeaconStruct->VHTOperation.present)
{
psessionEntry->vhtCapabilityPresentInBeacon = 1;
psessionEntry->apCenterChan = pBeaconStruct->VHTOperation.chanCenterFreqSeg1;
psessionEntry->apChanWidth = pBeaconStruct->VHTOperation.chanWidth;
}
else
{
psessionEntry->vhtCapabilityPresentInBeacon = 0;
}
#endif
// Extract the UAPSD flag from WMM Parameter element
if (pBeaconStruct->wmeEdcaPresent)
*uapsd = pBeaconStruct->edcaParams.qosInfo.uapsd;
/* Get MaxTxPwr from country IE if present.
If the channel number field has a positive integer value less
than 201, then it contains a positive integer value that indicates
the lowest channel number in the subband */
if (pBeaconStruct->countryInfoPresent &&
pBeaconStruct->countryInfoParam.channelTransmitPower[0].channelNumber < LIM_OPERATING_EXT_IDENTIFIER )
{
int i;
tANI_U8 firstChannel =0, numChannels =0;
tANI_U8 channel = psessionEntry->currentOperChannel;
for (i=0; i < pBeaconStruct->countryInfoParam.numIntervals; ++i)
{
if (i >= COUNTRY_INFO_MAX_CHANNEL)
break;
firstChannel = pBeaconStruct->countryInfoParam.channelTransmitPower[i].channelNumber;
numChannels = pBeaconStruct->countryInfoParam.channelTransmitPower[i].numChannel;
if ((channel >= firstChannel) &&
(channel < (firstChannel + numChannels)))
break;
}
if (i < pBeaconStruct->countryInfoParam.numIntervals && i < COUNTRY_INFO_MAX_CHANNEL)
{
*localConstraint = pBeaconStruct->countryInfoParam.channelTransmitPower[i].maxTransmitPower;
}
}
#if defined FEATURE_WLAN_ESE
/* If there is Power Constraint Element specifically,
* adapt to it. Hence there is else condition check
* for this if statement.
*/
if ( pBeaconStruct->eseTxPwr.present)
{
*localConstraint = pBeaconStruct->eseTxPwr.power_limit;
}
#endif
if (pBeaconStruct->powerConstraintPresent)
{
*localConstraint -= pBeaconStruct->localPowerConstraint.localPowerConstraints;
}
#if !defined WLAN_FEATURE_VOWIFI
localPowerConstraints = (tANI_U32)pBeaconStruct->localPowerConstraint.localPowerConstraints;
if (cfgSetInt(pMac, WNI_CFG_LOCAL_POWER_CONSTRAINT, localPowerConstraints) != eSIR_SUCCESS)
{
limLog(pMac, LOGP, FL("Could not update local power constraint to cfg."));
}
#endif
psessionEntry->countryInfoPresent = FALSE; /* Initializing before first use */
if (pBeaconStruct->countryInfoPresent)
{
psessionEntry->countryInfoPresent = TRUE;
}
/* Save the Extended caps from AP in probe resp or beacon */
if (pBeaconStruct->ExtCap.present)
{
vos_mem_copy(&psessionEntry->ExtCap, &pBeaconStruct->ExtCap, sizeof(tDot11fIEExtCap));
}
}
limCheckOUI(pMac, pIE, ieLen);
/* Update HS 2.0 Information Element */
sir_copy_hs20_ie(&psessionEntry->hs20vendor_ie,
&pBeaconStruct->hs20vendor_ie);
vos_mem_free(pBeaconStruct);
return;
} /****** end limExtractApCapability() ******/
/**
* limGetHTCBState
*
*FUNCTION:
* This routing provides the translation of Airgo Enum to HT enum for determining
* secondary channel offset.
* Airgo Enum is required for backward compatibility purposes.
*
*
*NOTE:
*
* @param pMac - Pointer to Global MAC structure
* @return The corresponding HT enumeration
*/
ePhyChanBondState limGetHTCBState(ePhyChanBondState aniCBMode)
{
switch ( aniCBMode )
{
#ifdef WLAN_FEATURE_11AC
case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW:
case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED:
case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH:
#endif
case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY:
return PHY_DOUBLE_CHANNEL_HIGH_PRIMARY;
#ifdef WLAN_FEATURE_11AC
case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW:
case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED:
case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH:
#endif
case PHY_DOUBLE_CHANNEL_LOW_PRIMARY:
return PHY_DOUBLE_CHANNEL_LOW_PRIMARY;
#ifdef WLAN_FEATURE_11AC
case PHY_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED:
return PHY_SINGLE_CHANNEL_CENTERED;
#endif
default :
return PHY_SINGLE_CHANNEL_CENTERED;
}
}
/*
* limGetStaPeerType
*
*FUNCTION:
* Based on a combination of the following -
* 1) tDphHashNode.aniPeer
* 2) tDphHashNode.propCapability
* this API determines if a given STA is an ANI peer or not
*
*LOGIC:
*
*ASSUMPTIONS:
*
*NOTE:
*
* @param pMac - Pointer to Global MAC structure
* @param pStaDs - Pointer to the tpDphHashNode of the STA
* under consideration
* @return tStaRateMode
*/
tStaRateMode limGetStaPeerType( tpAniSirGlobal pMac,
tpDphHashNode pStaDs,
tpPESession psessionEntry)
{
tStaRateMode staPeerType = eSTA_11b;
// Determine the peer-STA type
if( pStaDs->aniPeer )
{
if(PROP_CAPABILITY_GET( TAURUS, pStaDs->propCapability ))
staPeerType = eSTA_TAURUS;
else if( PROP_CAPABILITY_GET( TITAN, pStaDs->propCapability ))
staPeerType = eSTA_TITAN;
else
staPeerType = eSTA_POLARIS;
}
#ifdef WLAN_FEATURE_11AC
else if(pStaDs->mlmStaContext.vhtCapability)
staPeerType = eSTA_11ac;
#endif
else if(pStaDs->mlmStaContext.htCapability)
staPeerType = eSTA_11n;
else if(pStaDs->erpEnabled)
staPeerType = eSTA_11bg;
else if(psessionEntry->limRFBand == SIR_BAND_5_GHZ)
staPeerType = eSTA_11a;
return staPeerType;
}