| /* |
| * Copyright (c) 2011-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. |
| */ |
| |
| /**========================================================================= |
| |
| \file lim_session.c |
| |
| \brief implementation for lim Session related APIs |
| |
| \author Sunit Bhatia |
| |
| ========================================================================*/ |
| |
| /*-------------------------------------------------------------------------- |
| Include Files |
| ------------------------------------------------------------------------*/ |
| #include "ani_global.h" |
| #include "lim_ft_defs.h" |
| #include "lim_ft.h" |
| #include "lim_session.h" |
| #include "lim_utils.h" |
| |
| #include "sch_api.h" |
| #include "lim_send_messages.h" |
| |
| /*-------------------------------------------------------------------------- |
| |
| \brief pe_init_beacon_params() - Initialize the beaconParams structure |
| |
| \param tpPESession - pointer to the session context or NULL if session can not be created. |
| \return void |
| \sa |
| |
| --------------------------------------------------------------------------*/ |
| |
| static void pe_init_beacon_params(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 */ |
| qdf_mem_set((void *)&psessionEntry->gLim11bParams, |
| sizeof(tLimProtStaParams), 0); |
| qdf_mem_set((void *)&psessionEntry->gLim11aParams, |
| sizeof(tLimProtStaParams), 0); |
| qdf_mem_set((void *)&psessionEntry->gLim11gParams, |
| sizeof(tLimProtStaParams), 0); |
| qdf_mem_set((void *)&psessionEntry->gLimNonGfParams, |
| sizeof(tLimProtStaParams), 0); |
| qdf_mem_set((void *)&psessionEntry->gLimHt20Params, |
| sizeof(tLimProtStaParams), 0); |
| qdf_mem_set((void *)&psessionEntry->gLimLsigTxopParams, |
| sizeof(tLimProtStaParams), 0); |
| qdf_mem_set((void *)&psessionEntry->gLimOlbcParams, |
| sizeof(tLimProtStaParams), 0); |
| } |
| |
| /* |
| * pe_reset_protection_callback() - resets protection structs so that when an AP |
| * causing use of protection goes away, corresponding protection bit can be |
| * reset |
| * @ptr: pointer to pSessionEntry |
| * |
| * This function resets protection structs so that when an AP causing use of |
| * protection goes away, corresponding protection bit can be reset. This allowes |
| * protection bits to be reset once legacy overlapping APs are gone. |
| * |
| * Return: void |
| */ |
| static void pe_reset_protection_callback(void *ptr) |
| { |
| tpPESession pe_session_entry = (tpPESession)ptr; |
| tpAniSirGlobal mac_ctx = (tpAniSirGlobal)pe_session_entry->mac_ctx; |
| int8_t i = 0; |
| tUpdateBeaconParams beacon_params; |
| uint16_t current_protection_state = 0; |
| tpDphHashNode station_hash_node = NULL; |
| tSirMacHTOperatingMode old_op_mode; |
| bool bcn_prms_changed = false; |
| |
| if (pe_session_entry->valid == false) { |
| pe_err("session already deleted. exiting timer callback"); |
| return; |
| } |
| |
| /* |
| * During CAC period, if the callback is triggered, the beacon |
| * template may get updated. Subsequently if the vdev is not up, the |
| * vdev would be made up -- which should not happen during the CAC |
| * period. To avoid this, ignore the protection callback if the session |
| * is not yet up. |
| */ |
| if (!wma_is_vdev_up(pe_session_entry->smeSessionId)) { |
| pe_err("session is not up yet. exiting timer callback"); |
| return; |
| } |
| |
| current_protection_state |= |
| pe_session_entry->gLimOverlap11gParams.protectionEnabled | |
| pe_session_entry->gLimOverlap11aParams.protectionEnabled << 1 | |
| pe_session_entry->gLimOverlapHt20Params.protectionEnabled << 2 | |
| pe_session_entry->gLimOverlapNonGfParams.protectionEnabled << 3 | |
| pe_session_entry->gLimOlbcParams.protectionEnabled << 4; |
| |
| pe_debug("old protection state: 0x%04X, new protection state: 0x%04X", |
| pe_session_entry->old_protection_state, |
| current_protection_state); |
| |
| qdf_mem_zero(&pe_session_entry->gLimOverlap11gParams, |
| sizeof(pe_session_entry->gLimOverlap11gParams)); |
| qdf_mem_zero(&pe_session_entry->gLimOverlap11aParams, |
| sizeof(pe_session_entry->gLimOverlap11aParams)); |
| qdf_mem_zero(&pe_session_entry->gLimOverlapHt20Params, |
| sizeof(pe_session_entry->gLimOverlapHt20Params)); |
| qdf_mem_zero(&pe_session_entry->gLimOverlapNonGfParams, |
| sizeof(pe_session_entry->gLimOverlapNonGfParams)); |
| |
| qdf_mem_zero(&pe_session_entry->gLimOlbcParams, |
| sizeof(pe_session_entry->gLimOlbcParams)); |
| |
| /* |
| * Do not reset fShortPreamble and beaconInterval, as they |
| * are not updated. |
| */ |
| pe_session_entry->beaconParams.llaCoexist = 0; |
| pe_session_entry->beaconParams.llbCoexist = 0; |
| pe_session_entry->beaconParams.llgCoexist = 0; |
| pe_session_entry->beaconParams.ht20Coexist = 0; |
| pe_session_entry->beaconParams.llnNonGFCoexist = 0; |
| pe_session_entry->beaconParams.fRIFSMode = 0; |
| pe_session_entry->beaconParams.fLsigTXOPProtectionFullSupport = 0; |
| pe_session_entry->beaconParams.gHTObssMode = 0; |
| |
| qdf_mem_zero(&mac_ctx->lim.gLimOverlap11gParams, |
| sizeof(mac_ctx->lim.gLimOverlap11gParams)); |
| qdf_mem_zero(&mac_ctx->lim.gLimOverlap11aParams, |
| sizeof(mac_ctx->lim.gLimOverlap11aParams)); |
| qdf_mem_zero(&mac_ctx->lim.gLimOverlapHt20Params, |
| sizeof(mac_ctx->lim.gLimOverlapHt20Params)); |
| qdf_mem_zero(&mac_ctx->lim.gLimOverlapNonGfParams, |
| sizeof(mac_ctx->lim.gLimOverlapNonGfParams)); |
| |
| old_op_mode = pe_session_entry->htOperMode; |
| pe_session_entry->htOperMode = eSIR_HT_OP_MODE_PURE; |
| mac_ctx->lim.gHTOperMode = eSIR_HT_OP_MODE_PURE; |
| |
| qdf_mem_zero(&beacon_params, sizeof(tUpdateBeaconParams)); |
| /* index 0, is self node, peers start from 1 */ |
| for (i = 1 ; i <= mac_ctx->lim.gLimAssocStaLimit ; i++) { |
| station_hash_node = dph_get_hash_entry(mac_ctx, i, |
| &pe_session_entry->dph.dphHashTable); |
| if (NULL == station_hash_node) |
| continue; |
| lim_decide_ap_protection(mac_ctx, station_hash_node->staAddr, |
| &beacon_params, pe_session_entry); |
| } |
| |
| if (pe_session_entry->htOperMode != old_op_mode) |
| bcn_prms_changed = true; |
| |
| if ((current_protection_state != |
| pe_session_entry->old_protection_state) && |
| (false == mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running)) { |
| pe_debug("protection changed, update beacon template"); |
| /* update beacon fix params and send update to FW */ |
| qdf_mem_zero(&beacon_params, sizeof(tUpdateBeaconParams)); |
| beacon_params.bssIdx = pe_session_entry->bssIdx; |
| beacon_params.fShortPreamble = |
| pe_session_entry->beaconParams.fShortPreamble; |
| beacon_params.beaconInterval = |
| pe_session_entry->beaconParams.beaconInterval; |
| beacon_params.llaCoexist = |
| pe_session_entry->beaconParams.llaCoexist; |
| beacon_params.llbCoexist = |
| pe_session_entry->beaconParams.llbCoexist; |
| beacon_params.llgCoexist = |
| pe_session_entry->beaconParams.llgCoexist; |
| beacon_params.ht20MhzCoexist = |
| pe_session_entry->beaconParams.ht20Coexist; |
| beacon_params.llnNonGFCoexist = |
| pe_session_entry->beaconParams.llnNonGFCoexist; |
| beacon_params.fLsigTXOPProtectionFullSupport = |
| pe_session_entry->beaconParams. |
| fLsigTXOPProtectionFullSupport; |
| beacon_params.fRIFSMode = |
| pe_session_entry->beaconParams.fRIFSMode; |
| beacon_params.smeSessionId = |
| pe_session_entry->smeSessionId; |
| beacon_params.paramChangeBitmap |= PARAM_llBCOEXIST_CHANGED; |
| bcn_prms_changed = true; |
| } |
| |
| if (bcn_prms_changed) { |
| sch_set_fixed_beacon_fields(mac_ctx, pe_session_entry); |
| lim_send_beacon_params(mac_ctx, &beacon_params, pe_session_entry); |
| } |
| |
| pe_session_entry->old_protection_state = current_protection_state; |
| if (qdf_mc_timer_start(&pe_session_entry-> |
| protection_fields_reset_timer, |
| SCH_PROTECTION_RESET_TIME) |
| != QDF_STATUS_SUCCESS) { |
| pe_err("cannot create or start protectionFieldsResetTimer"); |
| } |
| } |
| |
| #ifdef WLAN_FEATURE_11W |
| /** |
| * pe_init_pmf_comeback_timer: init PMF comeback timer |
| * @mac_ctx: pointer to global adapter context |
| * @session: pe session |
| * @session_id: session ID |
| * |
| * Return: void |
| */ |
| static void pe_init_pmf_comeback_timer(tpAniSirGlobal mac_ctx, |
| tpPESession session, uint8_t session_id) |
| { |
| QDF_STATUS status; |
| |
| session->pmfComebackTimerInfo.pMac = mac_ctx; |
| session->pmfComebackTimerInfo.sessionID = session_id; |
| status = qdf_mc_timer_init(&session->pmfComebackTimer, |
| QDF_TIMER_TYPE_SW, lim_pmf_comeback_timer_callback, |
| (void *)&session->pmfComebackTimerInfo); |
| if (!QDF_IS_STATUS_SUCCESS(status)) |
| pe_err("cannot init pmf comeback timer"); |
| } |
| #else |
| static inline void |
| pe_init_pmf_comeback_timer(tpAniSirGlobal mac_ctx, |
| tpPESession session, uint8_t session_id) |
| { |
| } |
| #endif |
| |
| /** |
| * lim_get_peer_idxpool_size: get number of peer idx pool size |
| * @num_sta: Max number of STA |
| * @bss_type: BSS type |
| * |
| * The peer index start from 1 and thus index 0 is not used, so |
| * add 1 to the max sta. For STA if TDLS is enabled add 2 as |
| * index 1 is reserved for peer BSS. |
| * |
| * Return: number of peer idx pool size |
| */ |
| #ifdef FEATURE_WLAN_TDLS |
| static inline uint8_t |
| lim_get_peer_idxpool_size(uint16_t num_sta, tSirBssType bss_type) |
| { |
| /* |
| * In station role, index 1 is reserved for peer |
| * corresponding to AP. For TDLS the index should |
| * start from 2 |
| */ |
| if (bss_type == eSIR_INFRASTRUCTURE_MODE) |
| return num_sta + 2; |
| else |
| return num_sta + 1; |
| |
| } |
| #else |
| static inline uint8_t |
| lim_get_peer_idxpool_size(uint16_t num_sta, tSirBssType bss_type) |
| { |
| return num_sta + 1; |
| } |
| #endif |
| |
| /** |
| * pe_create_session() creates a new PE session given the BSSID |
| * @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. |
| * @param bssType: station or a |
| * |
| * 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. |
| * |
| * Return: tpPESession: pointer to the session context or NULL if session |
| * can not be created. |
| */ |
| |
| tpPESession |
| pe_create_session(tpAniSirGlobal pMac, uint8_t *bssid, uint8_t *sessionId, |
| uint16_t numSta, tSirBssType bssType) |
| { |
| QDF_STATUS status; |
| uint8_t i; |
| tpPESession session_ptr; |
| for (i = 0; i < pMac->lim.maxBssId; i++) { |
| /* Find first free room in session table */ |
| if (pMac->lim.gpSession[i].valid == true) |
| continue; |
| break; |
| } |
| |
| if (i == pMac->lim.maxBssId) { |
| pe_err("Session can't be created. Reached max sessions"); |
| return NULL; |
| } |
| |
| session_ptr = &pMac->lim.gpSession[i]; |
| qdf_mem_set((void *)session_ptr, sizeof(tPESession), 0); |
| /* Allocate space for Station Table for this session. */ |
| session_ptr->dph.dphHashTable.pHashTable = |
| qdf_mem_malloc(sizeof(tpDphHashNode) * (numSta + 1)); |
| if (NULL == session_ptr->dph.dphHashTable.pHashTable) { |
| pe_err("memory allocate failed!"); |
| return NULL; |
| } |
| |
| session_ptr->dph.dphHashTable.pDphNodeArray = |
| qdf_mem_malloc(sizeof(tDphHashNode) * (numSta + 1)); |
| if (NULL == session_ptr->dph.dphHashTable.pDphNodeArray) { |
| pe_err("memory allocate failed!"); |
| qdf_mem_free(session_ptr->dph.dphHashTable.pHashTable); |
| session_ptr->dph.dphHashTable. |
| pHashTable = NULL; |
| return NULL; |
| } |
| |
| |
| session_ptr->dph.dphHashTable.size = numSta + 1; |
| dph_hash_table_class_init(pMac, &session_ptr->dph.dphHashTable); |
| session_ptr->gpLimPeerIdxpool = qdf_mem_malloc( |
| sizeof(*(session_ptr->gpLimPeerIdxpool)) * |
| lim_get_peer_idxpool_size(numSta, bssType)); |
| if (NULL == session_ptr->gpLimPeerIdxpool) { |
| pe_err("memory allocate failed!"); |
| qdf_mem_free(session_ptr->dph.dphHashTable.pHashTable); |
| qdf_mem_free(session_ptr->dph.dphHashTable.pDphNodeArray); |
| session_ptr->dph.dphHashTable.pHashTable = NULL; |
| session_ptr->dph.dphHashTable.pDphNodeArray = NULL; |
| return NULL; |
| } |
| session_ptr->freePeerIdxHead = 0; |
| session_ptr->freePeerIdxTail = 0; |
| session_ptr->gLimNumOfCurrentSTAs = 0; |
| /* Copy the BSSID to the session table */ |
| sir_copy_mac_addr(session_ptr->bssId, bssid); |
| if (bssType == eSIR_MONITOR_MODE) |
| sir_copy_mac_addr(pMac->lim.gpSession[i].selfMacAddr, bssid); |
| session_ptr->valid = true; |
| /* Intialize the SME and MLM states to IDLE */ |
| session_ptr->limMlmState = eLIM_MLM_IDLE_STATE; |
| session_ptr->limSmeState = eLIM_SME_IDLE_STATE; |
| session_ptr->limCurrentAuthType = eSIR_OPEN_SYSTEM; |
| pe_init_beacon_params(pMac, &pMac->lim.gpSession[i]); |
| session_ptr->is11Rconnection = false; |
| #ifdef FEATURE_WLAN_ESE |
| session_ptr->isESEconnection = false; |
| #endif |
| session_ptr->isFastTransitionEnabled = false; |
| session_ptr->isFastRoamIniFeatureEnabled = false; |
| *sessionId = i; |
| session_ptr->gLimPhyMode = WNI_CFG_PHY_MODE_11G; |
| /* Initialize CB mode variables when session is created */ |
| session_ptr->htSupportedChannelWidthSet = 0; |
| session_ptr->htRecommendedTxWidthSet = 0; |
| session_ptr->htSecondaryChannelOffset = 0; |
| #ifdef FEATURE_WLAN_TDLS |
| qdf_mem_set(session_ptr->peerAIDBitmap, |
| sizeof(session_ptr->peerAIDBitmap), 0); |
| session_ptr->tdls_prohibited = false; |
| session_ptr->tdls_chan_swit_prohibited = false; |
| #endif |
| session_ptr->fWaitForProbeRsp = 0; |
| session_ptr->fIgnoreCapsChange = 0; |
| session_ptr->ignore_assoc_disallowed = pMac->ignore_assoc_disallowed; |
| |
| pe_debug("Create a new PE session: %d BSSID: "MAC_ADDRESS_STR" Max No of STA: %d", |
| *sessionId, MAC_ADDR_ARRAY(bssid), numSta); |
| |
| if (eSIR_INFRA_AP_MODE == bssType || eSIR_IBSS_MODE == bssType) { |
| session_ptr->pSchProbeRspTemplate = |
| qdf_mem_malloc(SCH_MAX_PROBE_RESP_SIZE); |
| session_ptr->pSchBeaconFrameBegin = |
| qdf_mem_malloc(SCH_MAX_BEACON_SIZE); |
| session_ptr->pSchBeaconFrameEnd = |
| qdf_mem_malloc(SCH_MAX_BEACON_SIZE); |
| if ((NULL == session_ptr->pSchProbeRspTemplate) |
| || (NULL == session_ptr->pSchBeaconFrameBegin) |
| || (NULL == session_ptr->pSchBeaconFrameEnd)) { |
| pe_err("memory allocate failed!"); |
| qdf_mem_free(session_ptr->dph.dphHashTable.pHashTable); |
| qdf_mem_free(session_ptr->dph.dphHashTable.pDphNodeArray); |
| qdf_mem_free(session_ptr->gpLimPeerIdxpool); |
| qdf_mem_free(session_ptr->pSchProbeRspTemplate); |
| qdf_mem_free(session_ptr->pSchBeaconFrameBegin); |
| qdf_mem_free(session_ptr->pSchBeaconFrameEnd); |
| |
| session_ptr->dph.dphHashTable.pHashTable = NULL; |
| session_ptr->dph.dphHashTable.pDphNodeArray = NULL; |
| session_ptr->gpLimPeerIdxpool = NULL; |
| session_ptr->pSchProbeRspTemplate = NULL; |
| session_ptr->pSchBeaconFrameBegin = NULL; |
| session_ptr->pSchBeaconFrameEnd = NULL; |
| return NULL; |
| } |
| } |
| if (eSIR_INFRASTRUCTURE_MODE == bssType) |
| lim_ft_open(pMac, &pMac->lim.gpSession[i]); |
| |
| if (eSIR_MONITOR_MODE == bssType) |
| lim_ft_open(pMac, &pMac->lim.gpSession[i]); |
| |
| if (eSIR_INFRA_AP_MODE == bssType) { |
| session_ptr->old_protection_state = 0; |
| session_ptr->mac_ctx = (void *)pMac; |
| status = qdf_mc_timer_init( |
| &session_ptr->protection_fields_reset_timer, |
| QDF_TIMER_TYPE_SW, pe_reset_protection_callback, |
| (void *)&pMac->lim.gpSession[i]); |
| if (status == QDF_STATUS_SUCCESS) { |
| status = qdf_mc_timer_start( |
| &session_ptr->protection_fields_reset_timer, |
| SCH_PROTECTION_RESET_TIME); |
| } |
| if (status != QDF_STATUS_SUCCESS) |
| pe_err("cannot create or start protectionFieldsResetTimer"); |
| } |
| pe_init_pmf_comeback_timer(pMac, session_ptr, *sessionId); |
| session_ptr->ht_client_cnt = 0; |
| |
| return &pMac->lim.gpSession[i]; |
| } |
| |
| /*-------------------------------------------------------------------------- |
| \brief pe_find_session_by_bssid() - 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 pe_find_session_by_bssid(tpAniSirGlobal pMac, uint8_t *bssid, |
| uint8_t *sessionId) |
| { |
| uint8_t i; |
| |
| for (i = 0; i < pMac->lim.maxBssId; i++) { |
| /* If BSSID matches return corresponding tables address */ |
| if ((pMac->lim.gpSession[i].valid) |
| && (sir_compare_mac_addr(pMac->lim.gpSession[i].bssId, |
| bssid))) { |
| *sessionId = i; |
| return &pMac->lim.gpSession[i]; |
| } |
| } |
| |
| pe_debug("Session lookup fails for BSSID:"); |
| lim_print_mac_addr(pMac, bssid, LOGD); |
| return NULL; |
| |
| } |
| |
| /*-------------------------------------------------------------------------- |
| \brief pe_find_session_by_bss_idx() - 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 pe_find_session_by_bss_idx(tpAniSirGlobal pMac, uint8_t bssIdx) |
| { |
| uint8_t 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]; |
| } |
| } |
| pe_debug("Session lookup fails for bssIdx: %d", bssIdx); |
| return NULL; |
| } |
| |
| /*-------------------------------------------------------------------------- |
| \brief pe_find_session_by_session_id() - 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 pe_find_session_by_session_id(tpAniSirGlobal pMac, |
| uint8_t sessionId) |
| { |
| if (sessionId >= pMac->lim.maxBssId) { |
| pe_err("Invalid sessionId: %d", sessionId); |
| return NULL; |
| } |
| |
| if (pMac->lim.gpSession[sessionId].valid) |
| return &pMac->lim.gpSession[sessionId]; |
| |
| return NULL; |
| } |
| |
| /** |
| * pe_find_session_by_sta_id() - looks up the PE session given staid. |
| * @mac_ctx: pointer to global adapter context |
| * @staid: StaId of the session |
| * @session_id: session ID is returned here, if session is found. |
| * |
| * 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. |
| * |
| * Return: session pointer |
| */ |
| tpPESession |
| pe_find_session_by_sta_id(tpAniSirGlobal mac_ctx, |
| uint8_t staid, |
| uint8_t *session_id) |
| { |
| uint8_t i, j; |
| tpPESession session_ptr; |
| dphHashTableClass *dph_ptr; |
| |
| for (i = 0; i < mac_ctx->lim.maxBssId; i++) { |
| if (!mac_ctx->lim.gpSession[i].valid) |
| continue; |
| session_ptr = &mac_ctx->lim.gpSession[i]; |
| dph_ptr = &session_ptr->dph.dphHashTable; |
| for (j = 0; j < dph_ptr->size; j++) { |
| if (dph_ptr->pDphNodeArray[j].valid |
| && dph_ptr->pDphNodeArray[j].added |
| && staid == dph_ptr->pDphNodeArray[j].staIndex) { |
| *session_id = i; |
| return session_ptr; |
| } |
| } |
| } |
| |
| pe_debug("Session lookup fails for StaId: %d", staid); |
| return NULL; |
| } |
| |
| /** |
| * pe_delete_session() - deletes the PE session given the session ID. |
| * @mac_ctx: pointer to global adapter context |
| * @session: session to be deleted. |
| * |
| * Deletes the given PE session |
| * |
| * Return: void |
| */ |
| void pe_delete_session(tpAniSirGlobal mac_ctx, tpPESession session) |
| { |
| uint16_t i = 0; |
| uint16_t n; |
| TX_TIMER *timer_ptr; |
| |
| if (!session || (session && !session->valid)) { |
| pe_err("session is not valid"); |
| return; |
| } |
| |
| pe_debug("Trying to delete PE session: %d Opmode: %d BssIdx: %d BSSID: "MAC_ADDRESS_STR, |
| session->peSessionId, session->operMode, |
| session->bssIdx, |
| MAC_ADDR_ARRAY(session->bssId)); |
| for (n = 0; n < (mac_ctx->lim.maxStation + 1); n++) { |
| timer_ptr = &mac_ctx->lim.limTimers.gpLimCnfWaitTimer[n]; |
| if (session->peSessionId == timer_ptr->sessionId) |
| if (true == tx_timer_running(timer_ptr)) |
| tx_timer_deactivate(timer_ptr); |
| } |
| |
| if (LIM_IS_AP_ROLE(session)) { |
| qdf_mc_timer_stop(&session->protection_fields_reset_timer); |
| qdf_mc_timer_destroy(&session->protection_fields_reset_timer); |
| } |
| |
| /* Delete FT related information */ |
| lim_ft_cleanup(mac_ctx, session); |
| if (session->pLimStartBssReq != NULL) { |
| qdf_mem_free(session->pLimStartBssReq); |
| session->pLimStartBssReq = NULL; |
| } |
| |
| if (session->pLimJoinReq != NULL) { |
| qdf_mem_free(session->pLimJoinReq); |
| session->pLimJoinReq = NULL; |
| } |
| |
| if (session->pLimReAssocReq != NULL) { |
| qdf_mem_free(session->pLimReAssocReq); |
| session->pLimReAssocReq = NULL; |
| } |
| |
| if (session->pLimMlmJoinReq != NULL) { |
| qdf_mem_free(session->pLimMlmJoinReq); |
| session->pLimMlmJoinReq = NULL; |
| } |
| |
| if (session->dph.dphHashTable.pHashTable != NULL) { |
| qdf_mem_free(session->dph.dphHashTable.pHashTable); |
| session->dph.dphHashTable.pHashTable = NULL; |
| } |
| |
| if (session->dph.dphHashTable.pDphNodeArray != NULL) { |
| qdf_mem_free(session->dph.dphHashTable.pDphNodeArray); |
| session->dph.dphHashTable.pDphNodeArray = NULL; |
| } |
| |
| if (session->gpLimPeerIdxpool != NULL) { |
| qdf_mem_free(session->gpLimPeerIdxpool); |
| session->gpLimPeerIdxpool = NULL; |
| } |
| |
| if (session->beacon != NULL) { |
| qdf_mem_free(session->beacon); |
| session->beacon = NULL; |
| session->bcnLen = 0; |
| } |
| |
| if (session->assocReq != NULL) { |
| qdf_mem_free(session->assocReq); |
| session->assocReq = NULL; |
| session->assocReqLen = 0; |
| } |
| |
| if (session->assocRsp != NULL) { |
| qdf_mem_free(session->assocRsp); |
| session->assocRsp = NULL; |
| session->assocRspLen = 0; |
| } |
| |
| if (session->parsedAssocReq != NULL) { |
| tpSirAssocReq tmp_ptr = NULL; |
| /* Cleanup the individual allocation first */ |
| for (i = 0; i < session->dph.dphHashTable.size; i++) { |
| if (session->parsedAssocReq[i] == NULL) |
| continue; |
| tmp_ptr = ((tpSirAssocReq) |
| (session->parsedAssocReq[i])); |
| if (tmp_ptr->assocReqFrame) { |
| qdf_mem_free(tmp_ptr->assocReqFrame); |
| tmp_ptr->assocReqFrame = NULL; |
| tmp_ptr->assocReqFrameLength = 0; |
| } |
| qdf_mem_free(session->parsedAssocReq[i]); |
| session->parsedAssocReq[i] = NULL; |
| } |
| /* Cleanup the whole block */ |
| qdf_mem_free(session->parsedAssocReq); |
| session->parsedAssocReq = NULL; |
| } |
| if (NULL != session->limAssocResponseData) { |
| qdf_mem_free(session->limAssocResponseData); |
| session->limAssocResponseData = NULL; |
| } |
| if (NULL != session->pLimMlmReassocRetryReq) { |
| qdf_mem_free(session->pLimMlmReassocRetryReq); |
| session->pLimMlmReassocRetryReq = NULL; |
| } |
| if (NULL != session->pLimMlmReassocReq) { |
| qdf_mem_free(session->pLimMlmReassocReq); |
| session->pLimMlmReassocReq = NULL; |
| } |
| |
| if (NULL != session->pSchProbeRspTemplate) { |
| qdf_mem_free(session->pSchProbeRspTemplate); |
| session->pSchProbeRspTemplate = NULL; |
| } |
| |
| if (NULL != session->pSchBeaconFrameBegin) { |
| qdf_mem_free(session->pSchBeaconFrameBegin); |
| session->pSchBeaconFrameBegin = NULL; |
| } |
| |
| if (NULL != session->pSchBeaconFrameEnd) { |
| qdf_mem_free(session->pSchBeaconFrameEnd); |
| session->pSchBeaconFrameEnd = NULL; |
| } |
| |
| /* Must free the buffer before peSession invalid */ |
| if (NULL != session->addIeParams.probeRespData_buff) { |
| qdf_mem_free(session->addIeParams.probeRespData_buff); |
| session->addIeParams.probeRespData_buff = NULL; |
| session->addIeParams.probeRespDataLen = 0; |
| } |
| if (NULL != session->addIeParams.assocRespData_buff) { |
| qdf_mem_free(session->addIeParams.assocRespData_buff); |
| session->addIeParams.assocRespData_buff = NULL; |
| session->addIeParams.assocRespDataLen = 0; |
| } |
| if (NULL != session->addIeParams.probeRespBCNData_buff) { |
| qdf_mem_free(session->addIeParams.probeRespBCNData_buff); |
| session->addIeParams.probeRespBCNData_buff = NULL; |
| session->addIeParams.probeRespBCNDataLen = 0; |
| } |
| #ifdef WLAN_FEATURE_11W |
| if (QDF_TIMER_STATE_RUNNING == |
| qdf_mc_timer_get_current_state(&session->pmfComebackTimer)) |
| qdf_mc_timer_stop(&session->pmfComebackTimer); |
| qdf_mc_timer_destroy(&session->pmfComebackTimer); |
| #endif |
| session->valid = false; |
| |
| if (session->access_policy_vendor_ie) |
| qdf_mem_free(session->access_policy_vendor_ie); |
| |
| session->access_policy_vendor_ie = NULL; |
| |
| if (LIM_IS_AP_ROLE(session)) |
| lim_check_and_reset_protection_params(mac_ctx); |
| |
| return; |
| } |
| |
| /*-------------------------------------------------------------------------- |
| \brief pe_find_session_by_peer_sta() - 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 pe_find_session_by_peer_sta(tpAniSirGlobal pMac, uint8_t *sa, |
| uint8_t *sessionId) |
| { |
| uint8_t i; |
| tpDphHashNode pSta; |
| uint16_t aid; |
| |
| for (i = 0; i < pMac->lim.maxBssId; i++) { |
| if ((pMac->lim.gpSession[i].valid)) { |
| pSta = |
| dph_lookup_hash_entry(pMac, sa, &aid, |
| &pMac->lim.gpSession[i].dph. |
| dphHashTable); |
| if (pSta != NULL) { |
| *sessionId = i; |
| return &pMac->lim.gpSession[i]; |
| } |
| } |
| } |
| |
| pe_debug("Session lookup fails for Peer StaId:"); |
| lim_print_mac_addr(pMac, sa, LOGD); |
| return NULL; |
| } |
| |
| /** |
| * pe_find_session_by_sme_session_id() - looks up the PE session for given sme |
| * session id |
| * @mac_ctx: pointer to global adapter context |
| * @sme_session_id: sme session id |
| * |
| * looks up the PE session for given sme session id |
| * |
| * Return: pe session entry for given sme session if found else NULL |
| */ |
| tpPESession pe_find_session_by_sme_session_id(tpAniSirGlobal mac_ctx, |
| uint8_t 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]; |
| } |
| } |
| return NULL; |
| } |
| |
| /** |
| * pe_get_active_session_count() - function to return active pe session count |
| * |
| * @mac_ctx: pointer to global mac structure |
| * |
| * returns number of active pe session count |
| * |
| * Return: 0 if there are no active sessions else return number of active |
| * sessions |
| */ |
| uint8_t pe_get_active_session_count(tpAniSirGlobal mac_ctx) |
| { |
| uint8_t i, active_session_count = 0; |
| |
| for (i = 0; i < mac_ctx->lim.maxBssId; i++) |
| if (mac_ctx->lim.gpSession[i].valid) |
| active_session_count++; |
| |
| return active_session_count; |
| } |