blob: 667032d65f83eade537ee0b383be10b2baa00c92 [file] [log] [blame]
/*
* Copyright (c) 2011-2014, 2016-2017, 2019 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.
*/
/**=========================================================================
\file limSession.c
\brief implementation for lim Session related APIs
\author Sunit Bhatia
========================================================================*/
/*--------------------------------------------------------------------------
Include Files
------------------------------------------------------------------------*/
#include "aniGlobal.h"
#include "limDebug.h"
#include "limSession.h"
#include "limUtils.h"
#if defined(FEATURE_WLAN_ESE) && !defined(FEATURE_WLAN_ESE_UPLOAD)
#include "eseApi.h"
#endif
/*--------------------------------------------------------------------------
\brief peInitBeaconParams() - Initialize the beaconParams structure
\param tpPESession - pointer to the session context or NULL if session can not be created.
\return void
\sa
--------------------------------------------------------------------------*/
void peInitBeaconParams(tpAniSirGlobal pMac, tpPESession psessionEntry)
{
psessionEntry->beaconParams.beaconInterval = 0;
psessionEntry->beaconParams.fShortPreamble = 0;
psessionEntry->beaconParams.llaCoexist = 0;
psessionEntry->beaconParams.llbCoexist = 0;
psessionEntry->beaconParams.llgCoexist = 0;
psessionEntry->beaconParams.ht20Coexist = 0;
psessionEntry->beaconParams.llnNonGFCoexist = 0;
psessionEntry->beaconParams.fRIFSMode = 0;
psessionEntry->beaconParams.fLsigTXOPProtectionFullSupport = 0;
psessionEntry->beaconParams.gHTObssMode = 0;
// Number of legacy STAs associated
vos_mem_set((void*)&psessionEntry->gLim11bParams, sizeof(tLimProtStaParams), 0);
vos_mem_set((void*)&psessionEntry->gLim11aParams, sizeof(tLimProtStaParams), 0);
vos_mem_set((void*)&psessionEntry->gLim11gParams, sizeof(tLimProtStaParams), 0);
vos_mem_set((void*)&psessionEntry->gLimNonGfParams, sizeof(tLimProtStaParams), 0);
vos_mem_set((void*)&psessionEntry->gLimHt20Params, sizeof(tLimProtStaParams), 0);
vos_mem_set((void*)&psessionEntry->gLimLsigTxopParams, sizeof(tLimProtStaParams), 0);
vos_mem_set((void*)&psessionEntry->gLimOlbcParams, sizeof(tLimProtStaParams), 0);
}
/*--------------------------------------------------------------------------
\brief peCreateSession() - creates a new PE session given the BSSID
This function returns the session context and the session ID if the session
corresponding to the passed BSSID is found in the PE session table.
\param pMac - pointer to global adapter context
\param bssid - BSSID of the new session
\param sessionId -session ID is returned here, if session is created.
\return tpPESession - pointer to the session context or NULL if session can not be created.
\sa
--------------------------------------------------------------------------*/
tpPESession peCreateSession(tpAniSirGlobal pMac, tANI_U8 *bssid , tANI_U8* sessionId, tANI_U16 numSta)
{
tANI_U8 i;
for(i =0; i < pMac->lim.maxBssId; i++)
{
/* Find first free room in session table */
if(pMac->lim.gpSession[i].valid == FALSE)
{
vos_mem_set((void*)&pMac->lim.gpSession[i], sizeof(tPESession), 0);
//Allocate space for Station Table for this session.
pMac->lim.gpSession[i].dph.dphHashTable.pHashTable = vos_mem_vmalloc(
sizeof(tpDphHashNode)*numSta);
if ( NULL == pMac->lim.gpSession[i].dph.dphHashTable.pHashTable )
{
limLog(pMac, LOGE, FL("memory allocate for size %lu failed!"),
(long unsigned int) sizeof(tpDphHashNode)*numSta);
return NULL;
}
pMac->lim.gpSession[i].dph.dphHashTable.pDphNodeArray = vos_mem_vmalloc(
sizeof(tDphHashNode)*numSta);
if ( NULL == pMac->lim.gpSession[i].dph.dphHashTable.pDphNodeArray )
{
limLog(pMac, LOGE, FL("memory allocate failed for Node array"
"of size %lu"),
(long unsigned int) sizeof(tDphHashNode)*numSta);
vos_mem_vfree(pMac->lim.gpSession[i].dph.dphHashTable.pHashTable);
pMac->lim.gpSession[i].dph.dphHashTable.pHashTable = NULL;
return NULL;
}
pMac->lim.gpSession[i].dph.dphHashTable.size = numSta;
dphHashTableClassInit(pMac,
&pMac->lim.gpSession[i].dph.dphHashTable);
pMac->lim.gpSession[i].gpLimPeerIdxpool = vos_mem_vmalloc(sizeof(
*pMac->lim.gpSession[i].gpLimPeerIdxpool) * (numSta+1));
if ( NULL == pMac->lim.gpSession[i].gpLimPeerIdxpool )
{
limLog(pMac, LOGE, FL("memory allocate failed "
"for peerId pool of size %lu!"), (long unsigned int)
sizeof(*pMac->lim.gpSession[i].gpLimPeerIdxpool) * (numSta+1));
vos_mem_vfree(pMac->lim.gpSession[i].dph.dphHashTable.pHashTable);
vos_mem_vfree(pMac->lim.gpSession[i].dph.dphHashTable.pDphNodeArray);
pMac->lim.gpSession[i].dph.dphHashTable.pHashTable = NULL;
pMac->lim.gpSession[i].dph.dphHashTable.pDphNodeArray = NULL;
return NULL;
}
vos_mem_set(pMac->lim.gpSession[i].gpLimPeerIdxpool,
sizeof(*pMac->lim.gpSession[i].gpLimPeerIdxpool) * (numSta+1), 0);
pMac->lim.gpSession[i].freePeerIdxHead = 0;
pMac->lim.gpSession[i].freePeerIdxTail = 0;
pMac->lim.gpSession[i].gLimNumOfCurrentSTAs = 0;
/* Copy the BSSID to the session table */
sirCopyMacAddr(pMac->lim.gpSession[i].bssId, bssid);
pMac->lim.gpSession[i].valid = TRUE;
/* Intialize the SME and MLM states to IDLE */
pMac->lim.gpSession[i].limMlmState = eLIM_MLM_IDLE_STATE;
pMac->lim.gpSession[i].limSmeState = eLIM_SME_IDLE_STATE;
pMac->lim.gpSession[i].limCurrentAuthType = eSIR_OPEN_SYSTEM;
peInitBeaconParams(pMac, &pMac->lim.gpSession[i]);
#ifdef WLAN_FEATURE_VOWIFI_11R
pMac->lim.gpSession[i].is11Rconnection = FALSE;
#endif
#ifdef FEATURE_WLAN_ESE
pMac->lim.gpSession[i].isESEconnection = FALSE;
#endif
#if defined WLAN_FEATURE_VOWIFI_11R || defined FEATURE_WLAN_ESE || defined(FEATURE_WLAN_LFR)
pMac->lim.gpSession[i].isFastTransitionEnabled = FALSE;
#endif
#ifdef FEATURE_WLAN_LFR
pMac->lim.gpSession[i].isFastRoamIniFeatureEnabled = FALSE;
#endif
*sessionId = i;
pMac->lim.gpSession[i].gLimPhyMode = WNI_CFG_PHY_MODE_11G; //TODO :Check with the team what should be default mode
/* Initialize CB mode variables when session is created */
pMac->lim.gpSession[i].htSupportedChannelWidthSet = 0;
pMac->lim.gpSession[i].htRecommendedTxWidthSet = 0;
pMac->lim.gpSession[i].htSecondaryChannelOffset = 0;
#ifdef FEATURE_WLAN_TDLS
vos_mem_set(pMac->lim.gpSession[i].peerAIDBitmap,
sizeof(pMac->lim.gpSession[i].peerAIDBitmap), 0);
pMac->lim.gpSession[i].tdlsChanSwitProhibited = 0;
#endif
pMac->lim.gpSession[i].fWaitForProbeRsp = 0;
pMac->lim.gpSession[i].fIgnoreCapsChange = 0;
limLog(pMac, LOG1, FL("Create a new sessionId (%d) with BSSID: "
MAC_ADDRESS_STR " Max No. of STA %d"),
pMac->lim.gpSession[i].peSessionId,
MAC_ADDR_ARRAY(bssid), numSta);
return(&pMac->lim.gpSession[i]);
}
}
limLog(pMac, LOGE, FL("Session can not be created.. Reached Max permitted sessions "));
return NULL;
}
/*--------------------------------------------------------------------------
\brief peFindSessionByBssid() - looks up the PE session given the BSSID.
This function returns the session context and the session ID if the session
corresponding to the given BSSID is found in the PE session table.
\param pMac - pointer to global adapter context
\param bssid - BSSID of the session
\param sessionId -session ID is returned here, if session is found.
\return tpPESession - pointer to the session context or NULL if session is not found.
\sa
--------------------------------------------------------------------------*/
tpPESession peFindSessionByBssid(tpAniSirGlobal pMac, tANI_U8* bssid, tANI_U8* sessionId)
{
tANI_U8 i;
for(i =0; i < pMac->lim.maxBssId; i++)
{
/* If BSSID matches return corresponding tables address*/
if( (pMac->lim.gpSession[i].valid) && (sirCompareMacAddr(pMac->lim.gpSession[i].bssId, bssid)))
{
*sessionId = i;
return(&pMac->lim.gpSession[i]);
}
}
limLog(pMac, LOG4, FL("Session lookup fails for BSSID: "));
limPrintMacAddr(pMac, bssid, LOG4);
return(NULL);
}
tANI_S8 limGetInfraSessionId(tpAniSirGlobal pMac)
{
tANI_U8 i;
for (i = 0; i < pMac->lim.maxBssId; i++)
{
if ((pMac->lim.gpSession[i].valid) &&
(pMac->lim.gpSession[i].limSystemRole == eLIM_STA_ROLE))
{
return i;
}
}
limLog(pMac, LOG4, FL("Session lookup fails for infra mode"));
return -1;
}
/*--------------------------------------------------------------------------
\brief peFindSessionByBssIdx() - looks up the PE session given the bssIdx.
This function returns the session context if the session
corresponding to the given bssIdx is found in the PE session table.
\param pMac - pointer to global adapter context
\param bssIdx - bss index of the session
\return tpPESession - pointer to the session context or NULL if session is not found.
\sa
--------------------------------------------------------------------------*/
tpPESession peFindSessionByBssIdx(tpAniSirGlobal pMac, tANI_U8 bssIdx)
{
tANI_U8 i;
for (i = 0; i < pMac->lim.maxBssId; i++)
{
/* If BSSID matches return corresponding tables address*/
if ( (pMac->lim.gpSession[i].valid) && (pMac->lim.gpSession[i].bssIdx == bssIdx))
{
return &pMac->lim.gpSession[i];
}
}
limLog(pMac, LOG4, FL("Session lookup fails for bssIdx: %d"), bssIdx);
return NULL;
}
tpPESession pe_find_session_by_sme_session_id(tpAniSirGlobal mac_ctx,
tANI_U8 sme_session_id)
{
uint8_t i;
for (i = 0; i < mac_ctx->lim.maxBssId; i++) {
if ((mac_ctx->lim.gpSession[i].valid) &&
(mac_ctx->lim.gpSession[i].smeSessionId == sme_session_id))
return &mac_ctx->lim.gpSession[i];
}
limLog(mac_ctx, LOG4, FL("Session lookup fails for smeSessionID: %d"),
sme_session_id);
return NULL;
}
/*--------------------------------------------------------------------------
\brief peFindSessionBySessionId() - looks up the PE session given the session ID.
This function returns the session context if the session
corresponding to the given session ID is found in the PE session table.
\param pMac - pointer to global adapter context
\param sessionId -session ID for which session context needs to be looked up.
\return tpPESession - pointer to the session context or NULL if session is not found.
\sa
--------------------------------------------------------------------------*/
tpPESession peFindSessionBySessionId(tpAniSirGlobal pMac , tANI_U8 sessionId)
{
if(sessionId >= pMac->lim.maxBssId)
{
limLog(pMac, LOGE, FL("Invalid sessionId: %d "), sessionId);
return(NULL);
}
if((pMac->lim.gpSession[sessionId].valid == TRUE))
{
return(&pMac->lim.gpSession[sessionId]);
}
return(NULL);
}
/*--------------------------------------------------------------------------
\brief peFindSessionByStaId() - looks up the PE session given staid.
This function returns the session context and the session ID if the session
corresponding to the given StaId is found in the PE session table.
\param pMac - pointer to global adapter context
\param staid - StaId of the session
\param sessionId -session ID is returned here, if session is found.
\return tpPESession - pointer to the session context or NULL if session is not found.
\sa
--------------------------------------------------------------------------*/
tpPESession peFindSessionByStaId(tpAniSirGlobal pMac, tANI_U8 staid, tANI_U8* sessionId)
{
tANI_U8 i, j;
for(i =0; i < pMac->lim.maxBssId; i++)
{
if(pMac->lim.gpSession[i].valid)
{
for(j = 0; j < pMac->lim.gpSession[i].dph.dphHashTable.size; j++)
{
if((pMac->lim.gpSession[i].dph.dphHashTable.pDphNodeArray[j].valid) &&
(pMac->lim.gpSession[i].dph.dphHashTable.pDphNodeArray[j].added) &&
(staid == pMac->lim.gpSession[i].dph.dphHashTable.pDphNodeArray[j].staIndex))
{
*sessionId = i;
return(&pMac->lim.gpSession[i]);
}
}
}
}
limLog(pMac, LOG4, FL("Session lookup fails for StaId: %d\n "), staid);
return(NULL);
}
/*--------------------------------------------------------------------------
\brief peDeleteSession() - deletes the PE session given the session ID.
\param pMac - pointer to global adapter context
\param sessionId -session ID of the session which needs to be deleted.
\sa
--------------------------------------------------------------------------*/
void peDeleteSession(tpAniSirGlobal pMac, tpPESession psessionEntry)
{
tANI_U16 i = 0;
tANI_U16 n;
TX_TIMER *timer_ptr;
eHalStatus lock_status = eHAL_STATUS_SUCCESS;
limLog(pMac, LOGW, FL("Trying to delete a session %d Opmode %d BssIdx %d"
" BSSID: " MAC_ADDRESS_STR), psessionEntry->peSessionId,
psessionEntry->operMode, psessionEntry->bssIdx,
MAC_ADDR_ARRAY(psessionEntry->bssId));
for (n = 0; n < pMac->lim.maxStation; n++)
{
timer_ptr = &pMac->lim.limTimers.gpLimCnfWaitTimer[n];
if(psessionEntry->peSessionId == timer_ptr->sessionId)
{
if(VOS_TRUE == tx_timer_running(timer_ptr))
{
tx_timer_deactivate(timer_ptr);
}
}
}
#ifdef WLAN_FEATURE_11AC
/* Unblock the MuBF for other session if the MuBf session is deleted
*/
if(psessionEntry->txMuBformee)
{
pMac->isMuBfsessionexist = FALSE;
}
#endif
if (psessionEntry->pLimStartBssReq != NULL)
{
vos_mem_free( psessionEntry->pLimStartBssReq );
psessionEntry->pLimStartBssReq = NULL;
}
if(psessionEntry->pLimJoinReq != NULL)
{
vos_mem_free( psessionEntry->pLimJoinReq );
psessionEntry->pLimJoinReq = NULL;
}
if(psessionEntry->pLimReAssocReq != NULL)
{
vos_mem_free( psessionEntry->pLimReAssocReq );
psessionEntry->pLimReAssocReq = NULL;
}
if(psessionEntry->pLimMlmJoinReq != NULL)
{
vos_mem_free( psessionEntry->pLimMlmJoinReq );
psessionEntry->pLimMlmJoinReq = NULL;
}
lock_status = pe_AcquireGlobalLock(&pMac->lim);
if (eHAL_STATUS_SUCCESS == lock_status)
{
if (psessionEntry->dph.dphHashTable.pHashTable != NULL)
{
vos_mem_vfree(psessionEntry->dph.dphHashTable.pHashTable);
psessionEntry->dph.dphHashTable.pHashTable = NULL;
}
}
pe_ReleaseGlobalLock(&pMac->lim);
if(psessionEntry->dph.dphHashTable.pDphNodeArray != NULL)
{
vos_mem_vfree(psessionEntry->dph.dphHashTable.pDphNodeArray);
psessionEntry->dph.dphHashTable.pDphNodeArray = NULL;
}
if(psessionEntry->gpLimPeerIdxpool != NULL)
{
vos_mem_vfree(psessionEntry->gpLimPeerIdxpool);
psessionEntry->gpLimPeerIdxpool = NULL;
}
if(psessionEntry->beacon != NULL)
{
vos_mem_free( psessionEntry->beacon);
psessionEntry->beacon = NULL;
}
if(psessionEntry->assocReq != NULL)
{
vos_mem_free( psessionEntry->assocReq);
psessionEntry->assocReq = NULL;
}
if(psessionEntry->assocRsp != NULL)
{
vos_mem_free( psessionEntry->assocRsp);
psessionEntry->assocRsp = NULL;
}
if(psessionEntry->parsedAssocReq != NULL)
{
// Cleanup the individual allocation first
for (i=0; i < psessionEntry->dph.dphHashTable.size; i++)
{
if ( psessionEntry->parsedAssocReq[i] != NULL )
{
if( ((tpSirAssocReq)(psessionEntry->parsedAssocReq[i]))->assocReqFrame )
{
vos_mem_free(((tpSirAssocReq)
(psessionEntry->parsedAssocReq[i]))->assocReqFrame);
((tpSirAssocReq)(psessionEntry->parsedAssocReq[i]))->assocReqFrame = NULL;
((tpSirAssocReq)(psessionEntry->parsedAssocReq[i]))->assocReqFrameLength = 0;
}
vos_mem_free(psessionEntry->parsedAssocReq[i]);
psessionEntry->parsedAssocReq[i] = NULL;
}
}
// Cleanup the whole block
vos_mem_free(psessionEntry->parsedAssocReq);
psessionEntry->parsedAssocReq = NULL;
}
if (NULL != psessionEntry->limAssocResponseData)
{
vos_mem_free( psessionEntry->limAssocResponseData);
psessionEntry->limAssocResponseData = NULL;
}
#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR)
if (NULL != psessionEntry->pLimMlmReassocRetryReq)
{
vos_mem_free( psessionEntry->pLimMlmReassocRetryReq);
psessionEntry->pLimMlmReassocRetryReq = NULL;
}
#endif
if (NULL != psessionEntry->pLimMlmReassocReq)
{
vos_mem_free( psessionEntry->pLimMlmReassocReq);
psessionEntry->pLimMlmReassocReq = NULL;
}
#if defined(FEATURE_WLAN_ESE) && !defined(FEATURE_WLAN_ESE_UPLOAD)
limCleanupEseCtxt(pMac, psessionEntry);
#endif
psessionEntry->valid = FALSE;
return;
}
/*--------------------------------------------------------------------------
\brief peFindSessionByPeerSta() - looks up the PE session given the Station Address.
This function returns the session context and the session ID if the session
corresponding to the given station address is found in the PE session table.
\param pMac - pointer to global adapter context
\param sa - Peer STA Address of the session
\param sessionId -session ID is returned here, if session is found.
\return tpPESession - pointer to the session context or NULL if session is not found.
\sa
--------------------------------------------------------------------------*/
tpPESession peFindSessionByPeerSta(tpAniSirGlobal pMac, tANI_U8* sa, tANI_U8* sessionId)
{
tANI_U8 i;
tpDphHashNode pSta;
tANI_U16 aid;
for(i =0; i < pMac->lim.maxBssId; i++)
{
if( (pMac->lim.gpSession[i].valid))
{
pSta = dphLookupHashEntry(pMac, sa, &aid, &pMac->lim.gpSession[i].dph.dphHashTable);
if (pSta != NULL)
{
*sessionId = i;
return &pMac->lim.gpSession[i];
}
}
}
limLog(pMac, LOG1, FL("Session lookup fails for Peer StaId: "));
limPrintMacAddr(pMac, sa, LOG1);
return NULL;
}