/* * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved. * * 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 lim_assoc_utils.cc contains the utility functions * LIM uses while processing (Re) Association messages. * Author: Chandra Modumudi * Date: 02/13/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_api.h" #include "sir_common.h" #include "wni_cfg.h" #include "cfg_api.h" #include "sch_api.h" #include "utils_api.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 "lim_send_messages.h" #include "lim_ibss_peer_mgmt.h" #include "lim_ft_defs.h" #include "lim_session.h" #include "qdf_types.h" #include "wma_types.h" #include "lim_types.h" #include "wlan_utility.h" #ifdef FEATURE_WLAN_TDLS #define IS_TDLS_PEER(type) ((type) == STA_ENTRY_TDLS_PEER) #else #define IS_TDLS_PEER(type) 0 #endif /** * lim_cmp_ssid() - utility function to compare SSIDs * @rx_ssid: Received SSID * @session_entry: Session entry * * This function is called in various places within LIM code * to determine whether received SSID is same as SSID in use. * * Return: zero if SSID matched, non-zero otherwise. */ uint32_t lim_cmp_ssid(tSirMacSSid *rx_ssid, tpPESession session_entry) { return qdf_mem_cmp(rx_ssid, &session_entry->ssId, session_entry->ssId.length); } /** * lim_compare_capabilities() * ***FUNCTION: * This function is called during Association/Reassociation * frame handling to determine whether received capabilities * match with local capabilities or not. * ***LOGIC: * ***ASSUMPTIONS: * NA * ***NOTE: * NA * * @param pMac - Pointer to Global MAC structure * @param pAssocReq - Pointer to received Assoc Req frame * @param pLocalCapabs - Pointer to local capabilities * * @return status - true for Capabilitity match else false. */ uint8_t lim_compare_capabilities(tpAniSirGlobal pMac, tSirAssocReq *pAssocReq, tSirMacCapabilityInfo *pLocalCapabs, tpPESession psessionEntry) { uint32_t val; if (LIM_IS_AP_ROLE(psessionEntry) && (pAssocReq->capabilityInfo.ibss)) { /* Requesting STA asserting IBSS capability. */ pe_debug("Requesting STA asserting IBSS capability"); return false; } /* Compare CF capabilities */ if (pAssocReq->capabilityInfo.cfPollable || pAssocReq->capabilityInfo.cfPollReq) { /* AP does not support PCF functionality */ pe_debug(" AP does not support PCF functionality"); return false; } /* Compare short preamble capability */ if (pAssocReq->capabilityInfo.shortPreamble && (pAssocReq->capabilityInfo.shortPreamble != pLocalCapabs->shortPreamble)) { /* Allowing a STA requesting short preamble while */ /* AP does not support it */ } pe_debug("QoS in AssocReq: %d, local capabs qos: %d", pAssocReq->capabilityInfo.qos, pLocalCapabs->qos); /* Compare QoS capability */ if (pAssocReq->capabilityInfo.qos && (pAssocReq->capabilityInfo.qos != pLocalCapabs->qos)) pe_debug("Received unmatched QOS but cfg to suppress - continuing"); /* * If AP supports shortSlot and if apple user has * enforced association only from shortSlot station, * then AP must reject any station that does not support * shortSlot */ if (LIM_IS_AP_ROLE(psessionEntry) && (pLocalCapabs->shortSlotTime == 1)) { if (wlan_cfg_get_int (pMac, WNI_CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY, &val) != QDF_STATUS_SUCCESS) { pe_err("error getting WNI_CFG_FORCE_SHORT_SLOT_ASSOC_ONLY"); return false; } if (val) { if (pAssocReq->capabilityInfo.shortSlotTime != pLocalCapabs->shortSlotTime) { pe_err("AP rejects association as station doesn't support shortslot time"); return false; } return false; } } return true; } /****** end lim_compare_capabilities() ******/ /** * lim_check_rx_basic_rates() * ***FUNCTION: * This function is called during Association/Reassociation * frame handling to determine whether received rates in * Assoc/Reassoc request frames include all BSS basic rates * or not. * ***LOGIC: * ***ASSUMPTIONS: * NA * ***NOTE: * NA * * @param rxRateSet - pointer to SSID structure * * @return status - true if ALL BSS basic rates are present in the * received rateset else false. */ uint8_t lim_check_rx_basic_rates(tpAniSirGlobal pMac, tSirMacRateSet rxRateSet, tpPESession psessionEntry) { tSirMacRateSet *pRateSet, basicRate; uint8_t i, j, k, match; pRateSet = qdf_mem_malloc(sizeof(tSirMacRateSet)); if (NULL == pRateSet) { pe_err("call to AllocateMemory failed for RATESET"); return false; } /* Copy operational rate set from session Entry */ qdf_mem_copy(pRateSet->rate, (psessionEntry->rateSet.rate), psessionEntry->rateSet.numRates); pRateSet->numRates = psessionEntry->rateSet.numRates; /* Extract BSS basic rateset from operational rateset */ for (i = 0, j = 0; ((i < pRateSet->numRates) && (i < SIR_MAC_RATESET_EID_MAX)); i++) { if ((pRateSet->rate[i] & 0x80) == 0x80) { /* msb is set, so this is a basic rate */ basicRate.rate[j++] = pRateSet->rate[i]; } } /* * For each BSS basic rate, find if it is present in the * received rateset. */ for (k = 0; k < j; k++) { match = 0; for (i = 0; ((i < rxRateSet.numRates) && (i < SIR_MAC_RATESET_EID_MAX)); i++) { if ((rxRateSet.rate[i] | 0x80) == basicRate.rate[k]) match = 1; } if (!match) { /* Free up memory allocated for rateset */ qdf_mem_free((uint8_t *) pRateSet); return false; } } /* Free up memory allocated for rateset */ qdf_mem_free((uint8_t *) pRateSet); return true; } /****** end lim_check_rx_basic_rates() ******/ /** * lim_check_mcs_set() * ***FUNCTION: * This function is called during Association/Reassociation * frame handling to determine whether received MCS rates in * Assoc/Reassoc request frames includes all Basic MCS Rate Set or not. * ***LOGIC: * ***ASSUMPTIONS: * NA * ***NOTE: * NA * * @param supportedMCSSet - pointer to Supported MCS Rate Set * * @return status - true if ALL MCS Basic Rate Set rates are present in the * received rateset else false. */ uint8_t lim_check_mcs_set(tpAniSirGlobal pMac, uint8_t *supportedMCSSet) { uint8_t basicMCSSet[SIZE_OF_BASIC_MCS_SET] = { 0 }; uint32_t cfgLen = 0; uint8_t i; uint8_t validBytes; uint8_t lastByteMCSMask = 0x1f; cfgLen = WNI_CFG_BASIC_MCS_SET_LEN; if (wlan_cfg_get_str(pMac, WNI_CFG_BASIC_MCS_SET, (uint8_t *) basicMCSSet, (uint32_t *) &cfgLen) != QDF_STATUS_SUCCESS) { /* / Could not get Basic MCS rateset from CFG. Log error. */ pe_err("could not retrieve Basic MCS rateset"); return false; } validBytes = VALID_MCS_SIZE / 8; /* check if all the Basic MCS Bits are set in supported MCS bitmap */ for (i = 0; i < validBytes; i++) { if ((basicMCSSet[i] & supportedMCSSet[i]) != basicMCSSet[i]) { pe_warn("One of Basic MCS Set Rates is not supported by the Station"); return false; } } /* check the last 5 bits of the valid MCS bitmap */ if (((basicMCSSet[i] & lastByteMCSMask) & (supportedMCSSet[i] & lastByteMCSMask)) != (basicMCSSet[i] & lastByteMCSMask)) { pe_warn("One of Basic MCS Set Rates is not supported by the Station"); return false; } return true; } #define SECURITY_SUITE_TYPE_MASK 0xFF #define SECURITY_SUITE_TYPE_WEP40 0x1 #define SECURITY_SUITE_TYPE_TKIP 0x2 #define SECURITY_SUITE_TYPE_CCMP 0x4 #define SECURITY_SUITE_TYPE_WEP104 0x4 #define SECURITY_SUITE_TYPE_GCMP 0x8 #define SECURITY_SUITE_TYPE_GCMP_256 0x9 /** * is_non_rsn_cipher()- API to check whether cipher suit is rsn or not * @cipher_suite: cipher suit * * Return: True in case non ht cipher else false */ static inline bool is_non_rsn_cipher(uint8_t cipher_suite) { uint8_t cipher_mask; cipher_mask = cipher_suite & SECURITY_SUITE_TYPE_MASK; if ((cipher_mask == SECURITY_SUITE_TYPE_CCMP) || (cipher_mask == SECURITY_SUITE_TYPE_GCMP) || (cipher_mask == SECURITY_SUITE_TYPE_GCMP_256)) return false; return true; } /** * lim_check_rx_rsn_ie_match()- validate received rsn ie with supported cipher * suites. * @mac_ctx: pointer to global mac structure * @rx_rsn_ie: received rsn IE pointer * @session_entry: pe session entry * @sta_is_ht: peer station HT capability * @pmf_connection: set to true if this is pmf connection * * This function is called during Association/Reassociation * frame handling to determine whether received RSN in * Assoc/Reassoc request frames include supported cipher suites or not. * * Return: QDF_STATUS_SUCCESS if ALL supported cipher suites are present in the * received rsn IE else failure status. */ uint8_t lim_check_rx_rsn_ie_match(tpAniSirGlobal mac_ctx, tDot11fIERSN * const rx_rsn_ie, tpPESession session_entry, uint8_t sta_is_ht, bool *pmf_connection) { tDot11fIERSN *rsn_ie; uint8_t i, j, match, only_non_ht_cipher = 1; #ifdef WLAN_FEATURE_11W bool we_are_pmf_capable; bool we_require_pmf; bool they_are_pmf_capable; bool they_require_pmf; #endif /* RSN IE should be received from PE */ rsn_ie = &session_entry->gStartBssRSNIe; if (!rx_rsn_ie) { pe_debug("Rx RSN IE is NULL"); return QDF_STATUS_E_FAILURE; } /* Check groupwise cipher suite */ for (i = 0; i < sizeof(rx_rsn_ie->gp_cipher_suite); i++) if (rsn_ie->gp_cipher_suite[i] != rx_rsn_ie->gp_cipher_suite[i]) { pe_debug("Invalid groupwise cipher suite"); return eSIR_MAC_INVALID_GROUP_CIPHER_STATUS; } /* * For each Pairwise cipher suite check whether we support * received pairwise */ match = 0; for (i = 0; i < rx_rsn_ie->pwise_cipher_suite_count; i++) { for (j = 0; j < rsn_ie->pwise_cipher_suite_count; j++) { if (!qdf_mem_cmp(&rx_rsn_ie->pwise_cipher_suites[i], &rsn_ie->pwise_cipher_suites[j], sizeof(rsn_ie->pwise_cipher_suites[j]))) { match = 1; break; } } if (sta_is_ht) #ifdef ANI_LITTLE_BYTE_ENDIAN only_non_ht_cipher = is_non_rsn_cipher( rx_rsn_ie->pwise_cipher_suites[i][3]); #else only_non_ht_cipher = is_non_rsn_cipher( rx_rsn_ie->pwise_cipher_suites[i][0]); #endif } if ((!match) || ((sta_is_ht) && only_non_ht_cipher)) { pe_debug("Invalid pairwise cipher suite"); return eSIR_MAC_INVALID_PAIRWISE_CIPHER_STATUS; } /* * Check RSN capabilities * Bit 0 of First Byte - PreAuthentication Capability */ if (((rx_rsn_ie->RSN_Cap[0] >> 0) & 0x1) == true) { /* this is supported by AP only */ pe_debug("Invalid RSN information element capabilities"); return eSIR_MAC_INVALID_RSN_IE_CAPABILITIES_STATUS; } *pmf_connection = false; #ifdef WLAN_FEATURE_11W we_are_pmf_capable = session_entry->pLimStartBssReq->pmfCapable; we_require_pmf = session_entry->pLimStartBssReq->pmfRequired; they_are_pmf_capable = (rx_rsn_ie->RSN_Cap[0] >> 7) & 0x1; they_require_pmf = (rx_rsn_ie->RSN_Cap[0] >> 6) & 0x1; if ((they_require_pmf && they_are_pmf_capable && !we_are_pmf_capable) || (we_require_pmf && !they_are_pmf_capable)) { pe_debug("Association fail, robust management frames policy" " violation they_require_pmf =%d" " theyArePMFCapable %d weArePMFCapable %d" " weRequirePMF %d theyArePMFCapable %d", they_require_pmf, they_are_pmf_capable, we_are_pmf_capable, we_require_pmf, they_are_pmf_capable); return eSIR_MAC_ROBUST_MGMT_FRAMES_POLICY_VIOLATION; } if (they_are_pmf_capable && we_are_pmf_capable) *pmf_connection = true; pe_debug("weAreCapable %d, weRequire %d, theyAreCapable %d," " theyRequire %d, PMFconnection %d", we_are_pmf_capable, we_require_pmf, they_are_pmf_capable, they_require_pmf, *pmf_connection); #endif return QDF_STATUS_SUCCESS; } /** * lim_check_rx_wpa_ie_match() - to check supported cipher suites * * @mac: pointer to global mac structure * @rx_wpaie: Received WPA IE in (Re)Assco req * @session_entry: pointer to PE session * @sta_is_ht: peer station is HT * * This function is called during Association/Reassociation * frame handling to determine whether received RSN in * Assoc/Reassoc request frames include supported cipher suites or not. * * Return: Success if ALL supported cipher suites are present in the * received wpa IE else failure status. */ uint8_t lim_check_rx_wpa_ie_match(tpAniSirGlobal mac, tDot11fIEWPA rx_wpaie, tpPESession session_entry, uint8_t sta_is_ht) { tDot11fIEWPA *wpa_ie; uint8_t i, j, match, only_non_ht_cipher = 1; /* WPA IE should be received from PE */ wpa_ie = &session_entry->gStartBssWPAIe; /* Check groupwise cipher suite */ for (i = 0; i < 4; i++) { if (wpa_ie->multicast_cipher[i] != rx_wpaie.multicast_cipher[i]) { pe_debug("Invalid groupwise cipher suite"); return eSIR_MAC_INVALID_GROUP_CIPHER_STATUS; } } /* * For each Pairwise cipher suite check whether we support * received pairwise */ match = 0; for (i = 0; i < rx_wpaie.unicast_cipher_count; i++) { for (j = 0; j < wpa_ie->unicast_cipher_count; j++) { if (!qdf_mem_cmp(rx_wpaie.unicast_ciphers[i], wpa_ie->unicast_ciphers[j], 4)) { match = 1; break; } } if ((sta_is_ht) #ifdef ANI_LITTLE_BYTE_ENDIAN && ((rx_wpaie. unicast_ciphers[i][3] & SECURITY_SUITE_TYPE_MASK) == SECURITY_SUITE_TYPE_CCMP)) #else && ((rx_wpaie. unicast_ciphers[i][0] & SECURITY_SUITE_TYPE_MASK) == SECURITY_SUITE_TYPE_CCMP)) #endif { only_non_ht_cipher = 0; } } if ((!match) || ((sta_is_ht) && only_non_ht_cipher)) { pe_debug("Invalid pairwise cipher suite"); return eSIR_MAC_CIPHER_SUITE_REJECTED_STATUS; } return QDF_STATUS_SUCCESS; } /** * lim_cleanup_rx_path() * ***FUNCTION: * This function is called to cleanup STA state at SP & RFP. * ***LOGIC: * To circumvent RFP's handling of dummy packet when it does not * have an incomplete packet for the STA to be deleted, a packet * with 'more framgents' bit set will be queued to RFP's WQ before * queuing 'dummy packet'. * A 'dummy' BD is pushed into RFP's WQ with type=00, subtype=1010 * (Disassociation frame) and routing flags in BD set to eCPU's * Low Priority WQ. * RFP cleans up its local context for the STA id mentioned in the * BD and then pushes BD to eCPU's low priority WQ. * ***ASSUMPTIONS: * NA * ***NOTE: * NA * * @param pMac Pointer to Global MAC structure * @param pStaDs Pointer to the per STA data structure * initialized by LIM and maintained at DPH * * @return None */ QDF_STATUS lim_cleanup_rx_path(tpAniSirGlobal pMac, tpDphHashNode pStaDs, tpPESession psessionEntry) { QDF_STATUS retCode = QDF_STATUS_SUCCESS; pe_debug("Cleanup Rx Path for AID: %d" "psessionEntry->limSmeState: %d, mlmState: %d", pStaDs->assocId, psessionEntry->limSmeState, pStaDs->mlmStaContext.mlmState); psessionEntry->isCiscoVendorAP = false; if (pMac->lim.gLimAddtsSent) { MTRACE(mac_trace (pMac, TRACE_CODE_TIMER_DEACTIVATE, psessionEntry->peSessionId, eLIM_ADDTS_RSP_TIMER)); tx_timer_deactivate(&pMac->lim.limTimers.gLimAddtsRspTimer); pe_debug("Reset gLimAddtsSent flag and send addts timeout to SME"); lim_process_sme_addts_rsp_timeout(pMac, pMac->lim.gLimAddtsRspTimerCount); } if (pStaDs->mlmStaContext.mlmState == eLIM_MLM_WT_ASSOC_CNF_STATE) { lim_deactivate_and_change_per_sta_id_timer(pMac, eLIM_CNF_WAIT_TIMER, pStaDs->assocId); if (!pStaDs->mlmStaContext.updateContext) { /** * There is no context at Polaris to delete. * Release our assigned AID back to the free pool */ if (LIM_IS_AP_ROLE(psessionEntry)) { lim_del_sta(pMac, pStaDs, true, psessionEntry); return retCode; } lim_delete_dph_hash_entry(pMac, pStaDs->staAddr, pStaDs->assocId, psessionEntry); return retCode; } } /* delete all tspecs associated with this sta. */ lim_admit_control_delete_sta(pMac, pStaDs->assocId); /** * Make STA hash entry invalid at eCPU so that DPH * does not process any more data packets and * releases those BDs */ pStaDs->valid = 0; lim_send_sme_tsm_ie_ind(pMac, psessionEntry, 0, 0, 0); /* Any roaming related changes should be above this line */ if (lim_is_roam_synch_in_progress(psessionEntry)) return QDF_STATUS_SUCCESS; pStaDs->mlmStaContext.mlmState = eLIM_MLM_WT_DEL_STA_RSP_STATE; if (LIM_IS_STA_ROLE(psessionEntry)) { MTRACE(mac_trace (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, eLIM_MLM_WT_DEL_STA_RSP_STATE)); psessionEntry->limMlmState = eLIM_MLM_WT_DEL_STA_RSP_STATE; /* Deactivating probe after heart beat timer */ lim_deactivate_and_change_timer(pMac, eLIM_PROBE_AFTER_HB_TIMER); lim_deactivate_and_change_timer(pMac, eLIM_JOIN_FAIL_TIMER); } #ifdef WLAN_DEBUG /* increment a debug count */ pMac->lim.gLimNumRxCleanup++; #endif /* Do DEL BSS or DEL STA only if ADD BSS was success */ if (!psessionEntry->add_bss_failed) { if (psessionEntry->limSmeState == eLIM_SME_JOIN_FAILURE_STATE) { retCode = lim_del_bss(pMac, pStaDs, psessionEntry->bssIdx, psessionEntry); } else retCode = lim_del_sta(pMac, pStaDs, true, psessionEntry); } return retCode; } /*** end lim_cleanup_rx_path() ***/ /** * lim_send_del_sta_cnf() - Send Del sta confirmation * @pMac: Pointer to Global MAC structure * @sta_dsaddr: sta ds address * @staDsAssocId: sta ds association id * @mlmStaContext: MLM station context * @statusCode: Status code * @psessionEntry: Session entry * * This function is called to send appropriate CNF message to SME. * * Return: None */ void lim_send_del_sta_cnf(tpAniSirGlobal pMac, struct qdf_mac_addr sta_dsaddr, uint16_t staDsAssocId, tLimMlmStaContext mlmStaContext, tSirResultCodes statusCode, tpPESession psessionEntry) { tLimMlmDisassocCnf mlmDisassocCnf; tLimMlmDeauthCnf mlmDeauthCnf; tLimMlmPurgeStaInd mlmPurgeStaInd; pe_debug("Sessionid: %d staDsAssocId: %d Trigger: %d statusCode: %d sta_dsaddr: "MAC_ADDRESS_STR, psessionEntry->peSessionId, staDsAssocId, mlmStaContext.cleanupTrigger, statusCode, MAC_ADDR_ARRAY(sta_dsaddr.bytes)); if (LIM_IS_STA_ROLE(psessionEntry)) { /* Set BSSID at CFG to null */ tSirMacAddr nullAddr = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; sir_copy_mac_addr(nullAddr, psessionEntry->bssId); /* Free up buffer allocated for JoinReq held by */ /* MLM state machine */ if (psessionEntry->pLimMlmJoinReq) { qdf_mem_free(psessionEntry->pLimMlmJoinReq); psessionEntry->pLimMlmJoinReq = NULL; } psessionEntry->limAID = 0; } if ((mlmStaContext.cleanupTrigger == eLIM_HOST_DISASSOC) || (mlmStaContext.cleanupTrigger == eLIM_LINK_MONITORING_DISASSOC) || (mlmStaContext.cleanupTrigger == eLIM_PROMISCUOUS_MODE_DISASSOC)) { /** * Host or LMM driven Disassociation. * Issue Disassoc Confirm to SME. */ pe_debug("Lim Posting DISASSOC_CNF to Sme. Trigger: %d", mlmStaContext.cleanupTrigger); qdf_mem_copy((uint8_t *) &mlmDisassocCnf.peerMacAddr, (uint8_t *) sta_dsaddr.bytes, QDF_MAC_ADDR_SIZE); mlmDisassocCnf.resultCode = statusCode; mlmDisassocCnf.disassocTrigger = mlmStaContext.cleanupTrigger; /* Update PE session Id */ mlmDisassocCnf.sessionId = psessionEntry->peSessionId; lim_post_sme_message(pMac, LIM_MLM_DISASSOC_CNF, (uint32_t *) &mlmDisassocCnf); } else if ((mlmStaContext.cleanupTrigger == eLIM_HOST_DEAUTH) || (mlmStaContext.cleanupTrigger == eLIM_LINK_MONITORING_DEAUTH)) { /** * Host or LMM driven Deauthentication. * Issue Deauth Confirm to SME. */ pe_debug("Lim Posting DEAUTH_CNF to Sme. Trigger: %d", mlmStaContext.cleanupTrigger); qdf_copy_macaddr(&mlmDeauthCnf.peer_macaddr, &sta_dsaddr); mlmDeauthCnf.resultCode = statusCode; mlmDeauthCnf.deauthTrigger = mlmStaContext.cleanupTrigger; /* PE session Id */ mlmDeauthCnf.sessionId = psessionEntry->peSessionId; lim_post_sme_message(pMac, LIM_MLM_DEAUTH_CNF, (uint32_t *) &mlmDeauthCnf); } else if ((mlmStaContext.cleanupTrigger == eLIM_PEER_ENTITY_DISASSOC) || (mlmStaContext.cleanupTrigger == eLIM_PEER_ENTITY_DEAUTH)) { /** * Received Disassociation/Deauthentication from peer. * Issue Purge Ind to SME. */ pe_debug("Lim Posting PURGE_STA_IND to Sme. Trigger: %d", mlmStaContext.cleanupTrigger); qdf_mem_copy((uint8_t *) &mlmPurgeStaInd.peerMacAddr, (uint8_t *) sta_dsaddr.bytes, QDF_MAC_ADDR_SIZE); mlmPurgeStaInd.reasonCode = (uint8_t) mlmStaContext.disassocReason; mlmPurgeStaInd.aid = staDsAssocId; mlmPurgeStaInd.purgeTrigger = mlmStaContext.cleanupTrigger; mlmPurgeStaInd.sessionId = psessionEntry->peSessionId; lim_post_sme_message(pMac, LIM_MLM_PURGE_STA_IND, (uint32_t *) &mlmPurgeStaInd); } else if (mlmStaContext.cleanupTrigger == eLIM_JOIN_FAILURE) { /* PE setup the peer entry in HW upfront, right after join is completed. */ /* If there is a failure during rest of the assoc sequence, this context needs to be cleaned up. */ uint8_t smesessionId; uint16_t smetransactionId; smesessionId = psessionEntry->smeSessionId; smetransactionId = psessionEntry->transactionId; psessionEntry->limSmeState = eLIM_SME_JOIN_FAILURE_STATE; MTRACE(mac_trace (pMac, TRACE_CODE_SME_STATE, psessionEntry->peSessionId, psessionEntry->limSmeState)); /* if it is a reassoc failure to join new AP */ if ((mlmStaContext.resultCode == eSIR_SME_FT_REASSOC_TIMEOUT_FAILURE) || (mlmStaContext.resultCode == eSIR_SME_FT_REASSOC_FAILURE) || (mlmStaContext.resultCode == eSIR_SME_REASSOC_TIMEOUT_RESULT_CODE)) { pe_debug("Lim Posting eWNI_SME_REASSOC_RSP to SME" "resultCode: %d, statusCode: %d," "sessionId: %d", mlmStaContext.resultCode, mlmStaContext.protStatusCode, psessionEntry->peSessionId); lim_send_sme_join_reassoc_rsp(pMac, eWNI_SME_REASSOC_RSP, mlmStaContext.resultCode, mlmStaContext.protStatusCode, psessionEntry, smesessionId, smetransactionId); if (mlmStaContext.resultCode != eSIR_SME_SUCCESS) { pe_delete_session(pMac, psessionEntry); psessionEntry = NULL; } } else { qdf_mem_free(psessionEntry->pLimJoinReq); psessionEntry->pLimJoinReq = NULL; pe_debug("Lim Posting eWNI_SME_JOIN_RSP to SME." "resultCode: %d,statusCode: %d," "sessionId: %d", mlmStaContext.resultCode, mlmStaContext.protStatusCode, psessionEntry->peSessionId); lim_send_sme_join_reassoc_rsp(pMac, eWNI_SME_JOIN_RSP, mlmStaContext.resultCode, mlmStaContext.protStatusCode, psessionEntry, smesessionId, smetransactionId); if (mlmStaContext.resultCode != eSIR_SME_SUCCESS) { pe_delete_session(pMac, psessionEntry); psessionEntry = NULL; } } } else if (mlmStaContext.cleanupTrigger == eLIM_DUPLICATE_ENTRY) { /** * LIM driven Disassociation. * Issue Disassoc Confirm to SME. */ pe_debug("Lim Posting DISASSOC_CNF to Sme. Trigger: %d", mlmStaContext.cleanupTrigger); qdf_mem_copy((uint8_t *) &mlmDisassocCnf.peerMacAddr, (uint8_t *) sta_dsaddr.bytes, QDF_MAC_ADDR_SIZE); mlmDisassocCnf.resultCode = statusCode; mlmDisassocCnf.disassocTrigger = eLIM_DUPLICATE_ENTRY; /* Update PE session Id */ mlmDisassocCnf.sessionId = psessionEntry->peSessionId; lim_post_sme_message(pMac, LIM_MLM_DISASSOC_CNF, (uint32_t *) &mlmDisassocCnf); } if (NULL != psessionEntry && !LIM_IS_AP_ROLE(psessionEntry)) { pe_delete_session(pMac, psessionEntry); psessionEntry = NULL; } } /** * lim_reject_association() - function to reject Re/Association Request * * @mac_ctx: pointer to global mac structure * @peer_addr: mac address of the peer * @sub_type: Indicates whether it is Association Request (=0) or * Reassociation Request (=1) frame * @add_pre_auth_context:Indicates whether pre-auth context * to be added for this STA * @auth_type: Indicates auth type to be added * @sta_id: Indicates staId of the STA being rejected * association * @delete_sta: Indicates whether to delete STA context * at Polaris * @result_code: Indicates what reasonCode to be sent in * Re/Assoc response to STA * @session_entry: pointer to PE session * * This function is called whenever Re/Association Request need * to be rejected due to failure in assigning an AID or failure * in adding STA context at Polaris or reject by applications. * Resources allocated if any are freedup and (Re) Association * Response frame is sent to requesting STA. Pre-Auth context * will be added for this STA if it does not exist already * * Return: none */ void lim_reject_association(tpAniSirGlobal mac_ctx, tSirMacAddr peer_addr, uint8_t sub_type, uint8_t add_pre_auth_context, tAniAuthType auth_type, uint16_t sta_id, uint8_t delete_sta, enum eSirMacStatusCodes result_code, tpPESession session_entry) { tpDphHashNode sta_ds; pe_debug("Sessionid: %d auth_type: %d sub_type: %d add_pre_auth_context: %d sta_id: %d delete_sta: %d result_code : %d peer_addr: " MAC_ADDRESS_STR, session_entry->peSessionId, auth_type, sub_type, add_pre_auth_context, sta_id, delete_sta, result_code, MAC_ADDR_ARRAY(peer_addr)); if (add_pre_auth_context) { /* Create entry for this STA in pre-auth list */ struct tLimPreAuthNode *auth_node; auth_node = lim_acquire_free_pre_auth_node(mac_ctx, &mac_ctx->lim.gLimPreAuthTimerTable); if (auth_node) { qdf_mem_copy((uint8_t *) auth_node->peerMacAddr, peer_addr, sizeof(tSirMacAddr)); auth_node->fTimerStarted = 0; auth_node->mlmState = eLIM_MLM_AUTHENTICATED_STATE; auth_node->authType = (tAniAuthType) auth_type; auth_node->timestamp = qdf_mc_timer_get_system_ticks(); lim_add_pre_auth_node(mac_ctx, auth_node); } } if (delete_sta == false) { lim_send_assoc_rsp_mgmt_frame(mac_ctx, eSIR_MAC_MAX_ASSOC_STA_REACHED_STATUS, 1, peer_addr, sub_type, 0, session_entry); pe_warn("received Re/Assoc req when max associated STAs reached from"); lim_print_mac_addr(mac_ctx, peer_addr, LOGW); lim_send_sme_max_assoc_exceeded_ntf(mac_ctx, peer_addr, session_entry->smeSessionId); return; } sta_ds = dph_get_hash_entry(mac_ctx, sta_id, &session_entry->dph.dphHashTable); if (sta_ds == NULL) { pe_err("No STA context, yet rejecting Association"); return; } /* * Polaris has state for this STA. * Trigger cleanup. */ sta_ds->mlmStaContext.cleanupTrigger = eLIM_REASSOC_REJECT; /* Receive path cleanup */ lim_cleanup_rx_path(mac_ctx, sta_ds, session_entry); /* * Send Re/Association Response with * status code to requesting STA. */ lim_send_assoc_rsp_mgmt_frame(mac_ctx, result_code, 0, peer_addr, sub_type, 0, session_entry); if (session_entry->parsedAssocReq[sta_ds->assocId] != NULL) { uint8_t *assoc_req_frame; assoc_req_frame = (uint8_t *)((tpSirAssocReq) (session_entry-> parsedAssocReq[sta_ds->assocId]))->assocReqFrame; /* *Assoction confirmation is complete, *free the copy of association request frame. */ if (assoc_req_frame) { qdf_mem_free(assoc_req_frame); assoc_req_frame = NULL; } qdf_mem_free(session_entry->parsedAssocReq[sta_ds->assocId]); session_entry->parsedAssocReq[sta_ds->assocId] = NULL; } } /** * lim_decide_ap_protection_on_ht20_delete() - function to update protection * parameters. * @mac_ctx: pointer to global mac structure * @sta_ds: station node * @beacon_params: ap beacon parameters * @session_entry: pe session entry * * protection related function while HT20 station is getting deleted. * * Return: none */ static void lim_decide_ap_protection_on_ht20_delete(tpAniSirGlobal mac_ctx, tpDphHashNode sta_ds, tpUpdateBeaconParams beacon_params, tpPESession session_entry) { uint32_t i = 0; pe_debug("(%d) A HT 20 STA is disassociated. Addr is %pM", session_entry->gLimHt20Params.numSta, sta_ds->staAddr); if (session_entry->gLimHt20Params.numSta > 0) { for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { if (!session_entry->protStaCache[i].active) continue; if (!qdf_mem_cmp(session_entry->protStaCache[i].addr, sta_ds->staAddr, sizeof(tSirMacAddr))) { session_entry->gLimHt20Params.numSta--; session_entry->protStaCache[i].active = false; break; } } } if (session_entry->gLimHt20Params.numSta == 0) { /* disable protection */ pe_debug("No 11B STA exists, PESessionID %d", session_entry->peSessionId); lim_enable_ht20_protection(mac_ctx, false, false, beacon_params, session_entry); } } /** * lim_decide_ap_protection_on_delete() - update SAP protection on station * deletion. * @mac_ctx: pointer to global mac structure * @sta_ds: station node * @beacon_params: ap beacon parameters * @session_entry: pe session entry * * Decides about protection related settings when a station is getting deleted. * * Return: none */ void lim_decide_ap_protection_on_delete(tpAniSirGlobal mac_ctx, tpDphHashNode sta_ds, tpUpdateBeaconParams beacon_params, tpPESession session_entry) { uint32_t phy_mode; tHalBitVal erp_enabled = eHAL_CLEAR; enum band_info rf_band = BAND_UNKNOWN; uint32_t i; if (NULL == sta_ds) return; lim_get_rf_band_new(mac_ctx, &rf_band, session_entry); lim_get_phy_mode(mac_ctx, &phy_mode, session_entry); erp_enabled = sta_ds->erpEnabled; if ((BAND_5G == rf_band) && (true == session_entry->htCapability) && (session_entry->beaconParams.llaCoexist) && (false == sta_ds->mlmStaContext.htCapability)) { /* * we are HT. if we are 11A, then protection is not required or * we are HT and 11A station is leaving. * protection consideration required. * HT station leaving ==> this case is commonly handled * between both the bands below. */ pe_debug("(%d) A 11A STA is disassociated. Addr is %pM", session_entry->gLim11aParams.numSta, sta_ds->staAddr); for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { if (session_entry->protStaCache[i].active && (!qdf_mem_cmp( session_entry->protStaCache[i].addr, sta_ds->staAddr, sizeof(tSirMacAddr)))) { session_entry->protStaCache[i].active = false; break; } } if (session_entry->gLim11aParams.numSta == 0) { /* disable protection */ lim_update_11a_protection(mac_ctx, false, false, beacon_params, session_entry); } } /* we are HT or 11G and 11B station is getting deleted */ if ((BAND_2G == rf_band) && (phy_mode == WNI_CFG_PHY_MODE_11G || session_entry->htCapability) && (erp_enabled == eHAL_CLEAR)) { pe_debug("(%d) A legacy STA is disassociated. Addr is %pM", session_entry->gLim11bParams.numSta, sta_ds->staAddr); for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { if (session_entry->protStaCache[i].active && (!qdf_mem_cmp( session_entry->protStaCache[i].addr, sta_ds->staAddr, sizeof(tSirMacAddr)))) { session_entry->gLim11bParams.numSta--; session_entry->protStaCache[i].active = false; break; } } if (session_entry->gLim11bParams.numSta == 0) { /* disable protection */ lim_enable11g_protection(mac_ctx, false, false, beacon_params, session_entry); } } /* * we are HT AP and non-11B station is leaving. * 11g station is leaving */ if ((BAND_2G == rf_band) && session_entry->htCapability && !sta_ds->mlmStaContext.htCapability) { pe_debug("(%d) A 11g STA is disassociated. Addr is %pM", session_entry->gLim11bParams.numSta, sta_ds->staAddr); for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { if (session_entry->protStaCache[i].active && (!qdf_mem_cmp( session_entry->protStaCache[i].addr, sta_ds->staAddr, sizeof(tSirMacAddr)))) { session_entry->gLim11gParams.numSta--; session_entry->protStaCache[i].active = false; break; } } if (session_entry->gLim11gParams.numSta == 0) { /* disable protection */ lim_enable_ht_protection_from11g(mac_ctx, false, false, beacon_params, session_entry); } } if (!((true == session_entry->htCapability) && (true == sta_ds->mlmStaContext.htCapability))) return; /* * Applies to 2.4 as well as 5 GHZ. * HT non-GF leaving */ if (!sta_ds->htGreenfield) { pe_debug("(%d) A non-GF STA is disassociated. Addr is %pM", session_entry->gLimNonGfParams.numSta, sta_ds->staAddr); for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { if (session_entry->protStaCache[i].active && (!qdf_mem_cmp( session_entry->protStaCache[i].addr, sta_ds->staAddr, sizeof(tSirMacAddr)))) { session_entry->protStaCache[i].active = false; break; } } if (session_entry->gLimNonGfParams.numSta == 0) { /* disable protection */ lim_enable_ht_non_gf_protection(mac_ctx, false, false, beacon_params, session_entry); } } /* * Applies to 2.4 as well as 5 GHZ. * HT 20Mhz station leaving */ if (session_entry->beaconParams.ht20Coexist && (eHT_CHANNEL_WIDTH_20MHZ == sta_ds->htSupportedChannelWidthSet)) { lim_decide_ap_protection_on_ht20_delete(mac_ctx, sta_ds, beacon_params, session_entry); } /* * Applies to 2.4 as well as 5 GHZ. * LSIG TXOP not supporting staiton leaving */ if ((false == session_entry->beaconParams. fLsigTXOPProtectionFullSupport) && (false == sta_ds->htLsigTXOPProtection)) { pe_debug("(%d) A HT LSIG not supporting STA is disassociated. Addr is %pM", session_entry->gLimLsigTxopParams.numSta, sta_ds->staAddr); for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { if (session_entry->protStaCache[i].active && (!qdf_mem_cmp( session_entry->protStaCache[i].addr, sta_ds->staAddr, sizeof(tSirMacAddr)))) { session_entry->protStaCache[i].active = false; break; } } if (session_entry->gLimLsigTxopParams.numSta == 0) { /* disable protection */ lim_enable_ht_lsig_txop_protection(mac_ctx, true, false, beacon_params, session_entry); } } } /** * lim_decide_short_preamble() - update short preamble parameters * @mac_ctx: pointer to global mac structure * @sta_ds: station node * @beacon_params: ap beacon parameters * @session_entry: pe session entry * * Decides about any short preamble related change because of new station * joining. * * Return: None */ static void lim_decide_short_preamble(tpAniSirGlobal mac_ctx, tpDphHashNode sta_ds, tpUpdateBeaconParams beacon_params, tpPESession session_entry) { uint32_t i; if (sta_ds->shortPreambleEnabled == eHAL_CLEAR) { pe_debug("(%d) A non-short preamble STA is disassociated. Addr is %pM", session_entry->gLimNoShortParams.numNonShortPreambleSta, sta_ds->staAddr); for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { if (session_entry->gLimNoShortParams. staNoShortCache[i].active && (!qdf_mem_cmp(session_entry-> gLimNoShortParams. staNoShortCache[i].addr, sta_ds->staAddr, sizeof(tSirMacAddr)))) { session_entry->gLimNoShortParams. numNonShortPreambleSta--; session_entry->gLimNoShortParams. staNoShortCache[i].active = false; break; } } if (session_entry->gLimNoShortParams.numNonShortPreambleSta) return; /* * enable short preamble * reset the cache */ qdf_mem_zero((uint8_t *) &session_entry->gLimNoShortParams, sizeof(tLimNoShortParams)); if (lim_enable_short_preamble(mac_ctx, true, beacon_params, session_entry) != QDF_STATUS_SUCCESS) pe_err("Cannot enable short preamble"); } } /** * lim_decide_short_slot() - update short slot time related parameters * @mac_ctx: pointer to global mac structure * @sta_ds: station node * @beacon_params: ap beacon parameters * @session_entry: pe session entry * * Decides about any short slot time related change because of station leaving * the BSS. * Return: None */ static void lim_decide_short_slot(tpAniSirGlobal mac_ctx, tpDphHashNode sta_ds, tpUpdateBeaconParams beacon_params, tpPESession session_entry) { uint32_t i, val, non_short_slot_sta_count; if (sta_ds->shortSlotTimeEnabled != eHAL_CLEAR) return; pe_debug("(%d) A non-short slottime STA is disassociated. Addr is %pM", mac_ctx->lim.gLimNoShortSlotParams.numNonShortSlotSta, sta_ds->staAddr); wlan_cfg_get_int(mac_ctx, WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED, &val); if (LIM_IS_AP_ROLE(session_entry)) { non_short_slot_sta_count = session_entry->gLimNoShortSlotParams.numNonShortSlotSta; for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { if (session_entry->gLimNoShortSlotParams. staNoShortSlotCache[i].active && (!qdf_mem_cmp(session_entry-> gLimNoShortSlotParams. staNoShortSlotCache[i].addr, sta_ds->staAddr, sizeof(tSirMacAddr)))) { non_short_slot_sta_count--; session_entry->gLimNoShortSlotParams. staNoShortSlotCache[i].active = false; break; } } if (non_short_slot_sta_count == 0 && val) { /* * enable short slot time * reset the cache */ qdf_mem_zero((uint8_t *) &session_entry-> gLimNoShortSlotParams, sizeof(tLimNoShortSlotParams)); beacon_params->fShortSlotTime = true; beacon_params->paramChangeBitmap |= PARAM_SHORT_SLOT_TIME_CHANGED; session_entry->shortSlotTimeSupported = true; } session_entry->gLimNoShortSlotParams.numNonShortSlotSta = non_short_slot_sta_count; } else { non_short_slot_sta_count = mac_ctx->lim.gLimNoShortSlotParams.numNonShortSlotSta; for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { if (mac_ctx->lim.gLimNoShortSlotParams. staNoShortSlotCache[i].active && (!qdf_mem_cmp( mac_ctx->lim.gLimNoShortSlotParams. staNoShortSlotCache[i].addr, sta_ds->staAddr, sizeof(tSirMacAddr)))) { non_short_slot_sta_count--; mac_ctx->lim.gLimNoShortSlotParams. staNoShortSlotCache[i].active = false; break; } } if (val && !non_short_slot_sta_count) { /* * enable short slot time * reset the cache */ qdf_mem_zero( (uint8_t *) &mac_ctx->lim.gLimNoShortSlotParams, sizeof(tLimNoShortSlotParams)); /*in case of AP set SHORT_SLOT_TIME to enable*/ if (LIM_IS_AP_ROLE(session_entry)) { beacon_params->fShortSlotTime = true; beacon_params->paramChangeBitmap |= PARAM_SHORT_SLOT_TIME_CHANGED; session_entry->shortSlotTimeSupported = true; } } mac_ctx->lim.gLimNoShortSlotParams.numNonShortSlotSta = non_short_slot_sta_count; } } /** * lim_populate_vht_mcs_set - function to populate vht mcs rate set * @mac_ctx: pointer to global mac structure * @rates: pointer to supported rate set * @peer_vht_caps: pointer to peer vht capabilities * @session_entry: pe session entry * * Populates vht mcs rate set based on peer and self capabilities * * Return: QDF_STATUS_SUCCESS on success else QDF_STATUS_E_FAILURE */ QDF_STATUS lim_populate_vht_mcs_set(tpAniSirGlobal mac_ctx, tpSirSupportedRates rates, tDot11fIEVHTCaps *peer_vht_caps, tpPESession session_entry, uint8_t nss) { uint32_t val; uint32_t self_sta_dot11mode = 0; uint16_t mcs_map_mask = MCSMAPMASK1x1; uint16_t mcs_map_mask2x2 = 0; wlan_cfg_get_int(mac_ctx, WNI_CFG_DOT11_MODE, &self_sta_dot11mode); if (!IS_DOT11_MODE_VHT(self_sta_dot11mode)) return QDF_STATUS_SUCCESS; if (wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_RX_MCS_MAP, &val) != QDF_STATUS_SUCCESS) { pe_err("could not retrieve VHT RX MCS MAP"); goto error; } rates->vhtRxMCSMap = (uint16_t) val; if (wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_TX_MCS_MAP, &val) != QDF_STATUS_SUCCESS) { pe_err("could not retrieve VHT TX MCS MAP"); goto error; } rates->vhtTxMCSMap = (uint16_t) val; if (wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE, &val) != QDF_STATUS_SUCCESS) { pe_err("couldn't retrieve VHT RX Supported data rate MAP"); goto error; } rates->vhtRxHighestDataRate = (uint16_t) val; if (wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE, &val) != QDF_STATUS_SUCCESS) { pe_err("couldn't retrieve VHT RX Supported data rate MAP"); goto error; } rates->vhtTxHighestDataRate = (uint16_t) val; if (NSS_1x1_MODE == nss) { rates->vhtRxMCSMap |= VHT_MCS_1x1; rates->vhtTxMCSMap |= VHT_MCS_1x1; rates->vhtTxHighestDataRate = VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1; rates->vhtRxHighestDataRate = VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1; if (session_entry && !session_entry->ch_width && !mac_ctx->roam.configParam.enable_vht20_mcs9 && ((rates->vhtRxMCSMap & VHT_1x1_MCS_MASK) == VHT_1x1_MCS9_MAP)) { DISABLE_VHT_MCS_9(rates->vhtRxMCSMap, NSS_1x1_MODE); DISABLE_VHT_MCS_9(rates->vhtTxMCSMap, NSS_1x1_MODE); } } else { if (session_entry && !session_entry->ch_width && !mac_ctx->roam.configParam.enable_vht20_mcs9 && ((rates->vhtRxMCSMap & VHT_2x2_MCS_MASK) == VHT_2x2_MCS9_MAP)) { DISABLE_VHT_MCS_9(rates->vhtRxMCSMap, NSS_2x2_MODE); DISABLE_VHT_MCS_9(rates->vhtTxMCSMap, NSS_2x2_MODE); } } if ((peer_vht_caps == NULL) || (!peer_vht_caps->present)) return QDF_STATUS_SUCCESS; rates->vhtTxHighestDataRate = QDF_MIN(rates->vhtTxHighestDataRate, peer_vht_caps->txSupDataRate); rates->vhtRxHighestDataRate = QDF_MIN(rates->vhtRxHighestDataRate, peer_vht_caps->rxHighSupDataRate); if (session_entry && session_entry->nss == NSS_2x2_MODE) mcs_map_mask2x2 = MCSMAPMASK2x2; if ((peer_vht_caps->txMCSMap & mcs_map_mask) < (rates->vhtRxMCSMap & mcs_map_mask)) { rates->vhtRxMCSMap &= ~(mcs_map_mask); rates->vhtRxMCSMap |= (peer_vht_caps->txMCSMap & mcs_map_mask); } if ((peer_vht_caps->rxMCSMap & mcs_map_mask) < (rates->vhtTxMCSMap & mcs_map_mask)) { rates->vhtTxMCSMap &= ~(mcs_map_mask); rates->vhtTxMCSMap |= (peer_vht_caps->rxMCSMap & mcs_map_mask); } if (mcs_map_mask2x2) { uint16_t peer_mcs_map, self_mcs_map; peer_mcs_map = peer_vht_caps->txMCSMap & mcs_map_mask2x2; self_mcs_map = rates->vhtRxMCSMap & mcs_map_mask2x2; if ((self_mcs_map != mcs_map_mask2x2) && ((peer_mcs_map == mcs_map_mask2x2) || (peer_mcs_map < self_mcs_map))) { rates->vhtRxMCSMap &= ~mcs_map_mask2x2; rates->vhtRxMCSMap |= peer_mcs_map; } peer_mcs_map = (peer_vht_caps->rxMCSMap & mcs_map_mask2x2); self_mcs_map = (rates->vhtTxMCSMap & mcs_map_mask2x2); if ((self_mcs_map != mcs_map_mask2x2) && ((peer_mcs_map == mcs_map_mask2x2) || (peer_mcs_map < self_mcs_map))) { rates->vhtTxMCSMap &= ~mcs_map_mask2x2; rates->vhtTxMCSMap |= peer_mcs_map; } } pe_debug("enable2x2 - %d nss %d vhtRxMCSMap - %x vhtTxMCSMap - %x", mac_ctx->roam.configParam.enable2x2, nss, rates->vhtRxMCSMap, rates->vhtTxMCSMap); if (NULL != session_entry) { session_entry->supported_nss_1x1 = ((rates->vhtTxMCSMap & VHT_MCS_1x1) == VHT_MCS_1x1) ? true : false; pe_debug("VHT supported nss 1x1: %d", session_entry->supported_nss_1x1); } return QDF_STATUS_SUCCESS; error: return QDF_STATUS_E_FAILURE; } /** * lim_populate_own_rate_set() - comprises the basic and extended rates read * from CFG * @mac_ctx: pointer to global mac structure * @rates: pointer to supported rates * @supported_mcs_set: pointer to supported mcs rates * @basic_only: update only basic rates if set true * @session_entry: pe session entry * @vht_caps: pointer to vht capability * * This function is called by limProcessAssocRsp() or * lim_add_staInIBSS() * - It creates a combined rate set of 12 rates max which * comprises the basic and extended rates read from CFG * - It sorts the combined rate Set and copy it in the * rate array of the pSTA descriptor * - It sets the erpEnabled bit of the STA descriptor * ERP bit is set iff the dph PHY mode is 11G and there is at least * an A rate in the supported or extended rate sets * * Return: QDF_STATUS_SUCCESS or QDF_STATUS_E_FAILURE. */ QDF_STATUS lim_populate_own_rate_set(tpAniSirGlobal mac_ctx, tpSirSupportedRates rates, uint8_t *supported_mcs_set, uint8_t basic_only, tpPESession session_entry, struct sDot11fIEVHTCaps *vht_caps, struct sDot11fIEhe_cap *he_caps) { tSirMacRateSet temp_rate_set; tSirMacRateSet temp_rate_set2; uint32_t i, j, val, min, is_arate; uint32_t phy_mode = 0; uint32_t self_sta_dot11mode = 0; uint8_t a_rate_index = 0; uint8_t b_rate_index = 0; is_arate = 0; wlan_cfg_get_int(mac_ctx, WNI_CFG_DOT11_MODE, &self_sta_dot11mode); lim_get_phy_mode(mac_ctx, &phy_mode, session_entry); /* * Include 11b rates only when the device configured in * auto, 11a/b/g or 11b_only */ if ((self_sta_dot11mode == WNI_CFG_DOT11_MODE_ALL) || (self_sta_dot11mode == WNI_CFG_DOT11_MODE_11A) || (self_sta_dot11mode == WNI_CFG_DOT11_MODE_11AC) || (self_sta_dot11mode == WNI_CFG_DOT11_MODE_11N) || (self_sta_dot11mode == WNI_CFG_DOT11_MODE_11G) || (self_sta_dot11mode == WNI_CFG_DOT11_MODE_11B)) { val = WNI_CFG_SUPPORTED_RATES_11B_LEN; wlan_cfg_get_str(mac_ctx, WNI_CFG_SUPPORTED_RATES_11B, (uint8_t *) &temp_rate_set.rate, &val); temp_rate_set.numRates = (uint8_t) val; } else { temp_rate_set.numRates = 0; } /* Include 11a rates when the device configured in non-11b mode */ if (!IS_DOT11_MODE_11B(self_sta_dot11mode)) { val = WNI_CFG_SUPPORTED_RATES_11A_LEN; wlan_cfg_get_str(mac_ctx, WNI_CFG_SUPPORTED_RATES_11A, (uint8_t *) &temp_rate_set2.rate, &val); temp_rate_set2.numRates = (uint8_t) val; } else { temp_rate_set2.numRates = 0; } if ((temp_rate_set.numRates + temp_rate_set2.numRates) > 12) { pe_err("more than 12 rates in CFG"); return QDF_STATUS_E_FAILURE; } /* copy all rates in temp_rate_set, there are 12 rates max */ for (i = 0; i < temp_rate_set2.numRates; i++) temp_rate_set.rate[i + temp_rate_set.numRates] = temp_rate_set2.rate[i]; temp_rate_set.numRates += temp_rate_set2.numRates; /** * Sort rates in temp_rate_set (they are likely to be already sorted) * put the result in pSupportedRates */ qdf_mem_zero((uint8_t *) rates, sizeof(tSirSupportedRates)); for (i = 0; i < temp_rate_set.numRates; i++) { min = 0; val = 0xff; is_arate = 0; for (j = 0; (j < temp_rate_set.numRates) && (j < SIR_MAC_RATESET_EID_MAX); j++) { if ((uint32_t) (temp_rate_set.rate[j] & 0x7f) < val) { val = temp_rate_set.rate[j] & 0x7f; min = j; } } if (sirIsArate(temp_rate_set.rate[min] & 0x7f)) is_arate = 1; if (is_arate) rates->llaRates[a_rate_index++] = temp_rate_set.rate[min]; else rates->llbRates[b_rate_index++] = temp_rate_set.rate[min]; temp_rate_set.rate[min] = 0xff; } if (IS_DOT11_MODE_HT(self_sta_dot11mode)) { val = SIZE_OF_SUPPORTED_MCS_SET; if (wlan_cfg_get_str(mac_ctx, WNI_CFG_SUPPORTED_MCS_SET, rates->supportedMCSSet, &val) != QDF_STATUS_SUCCESS) { pe_err("could not retrieve supportedMCSSet"); return QDF_STATUS_E_FAILURE; } if (session_entry->nss == NSS_1x1_MODE) rates->supportedMCSSet[1] = 0; /* * if supported MCS Set of the peer is passed in, * then do the intersection * else use the MCS set from local CFG. */ if (supported_mcs_set != NULL) { for (i = 0; i < SIR_MAC_MAX_SUPPORTED_MCS_SET; i++) rates->supportedMCSSet[i] &= supported_mcs_set[i]; } pe_debug("MCS Rate Set Bitmap: "); for (i = 0; i < SIR_MAC_MAX_SUPPORTED_MCS_SET; i++) pe_debug("%x ", rates->supportedMCSSet[i]); } lim_populate_vht_mcs_set(mac_ctx, rates, vht_caps, session_entry, session_entry->nss); lim_populate_he_mcs_set(mac_ctx, rates, he_caps, session_entry, session_entry->nss); return QDF_STATUS_SUCCESS; } #ifdef WLAN_FEATURE_11AX /** * lim_calculate_he_nss() - function to calculate new nss from he rates * @rates: supported rtes struct object * @session: pe session entry * This function calculates nss from rx_he_mcs_map_lt_80 within rates struct * object and assigns new value to nss within pe_session * * Return: None */ static void lim_calculate_he_nss(tpSirSupportedRates rates, tpPESession session) { HE_GET_NSS(rates->rx_he_mcs_map_lt_80, session->nss); } #else static void lim_calculate_he_nss(tpSirSupportedRates rates, tpPESession session) { } #endif QDF_STATUS lim_populate_peer_rate_set(tpAniSirGlobal pMac, tpSirSupportedRates pRates, uint8_t *pSupportedMCSSet, uint8_t basicOnly, tpPESession psessionEntry, tDot11fIEVHTCaps *pVHTCaps, tDot11fIEhe_cap *he_caps) { tSirMacRateSet tempRateSet; tSirMacRateSet tempRateSet2; uint32_t i, j, val, min, isArate = 0; /* copy operational rate set from psessionEntry */ if (psessionEntry->rateSet.numRates <= SIR_MAC_RATESET_EID_MAX) { qdf_mem_copy((uint8_t *) tempRateSet.rate, (uint8_t *) (psessionEntry->rateSet.rate), psessionEntry->rateSet.numRates); tempRateSet.numRates = psessionEntry->rateSet.numRates; } else { pe_err("more than SIR_MAC_RATESET_EID_MAX rates"); return QDF_STATUS_E_FAILURE; } if ((psessionEntry->dot11mode == WNI_CFG_DOT11_MODE_11G) || (psessionEntry->dot11mode == WNI_CFG_DOT11_MODE_11A) || (psessionEntry->dot11mode == WNI_CFG_DOT11_MODE_11AC) || (psessionEntry->dot11mode == WNI_CFG_DOT11_MODE_11N)) { if (psessionEntry->extRateSet.numRates <= SIR_MAC_RATESET_EID_MAX) { qdf_mem_copy((uint8_t *) tempRateSet2.rate, (uint8_t *) (psessionEntry->extRateSet. rate), psessionEntry->extRateSet.numRates); tempRateSet2.numRates = psessionEntry->extRateSet.numRates; } else { pe_err("psessionEntry->extRateSet.numRates more than SIR_MAC_RATESET_EID_MAX rates"); return QDF_STATUS_E_FAILURE; } } else tempRateSet2.numRates = 0; if ((tempRateSet.numRates + tempRateSet2.numRates) > SIR_MAC_RATESET_EID_MAX) { pe_err("more than 12 rates in CFG"); return QDF_STATUS_E_FAILURE; } /* copy all rates in tempRateSet, there are 12 rates max */ for (i = 0; i < tempRateSet2.numRates; i++) tempRateSet.rate[i + tempRateSet.numRates] = tempRateSet2.rate[i]; tempRateSet.numRates += tempRateSet2.numRates; /** * Sort rates in tempRateSet (they are likely to be already sorted) * put the result in pSupportedRates */ { uint8_t aRateIndex = 0; uint8_t bRateIndex = 0; qdf_mem_zero((uint8_t *) pRates, sizeof(tSirSupportedRates)); for (i = 0; i < tempRateSet.numRates; i++) { min = 0; val = 0xff; isArate = 0; for (j = 0; (j < tempRateSet.numRates) && (j < SIR_MAC_RATESET_EID_MAX); j++) { if ((uint32_t) (tempRateSet.rate[j] & 0x7f) < val) { val = tempRateSet.rate[j] & 0x7f; min = j; } } if (sirIsArate(tempRateSet.rate[min] & 0x7f)) isArate = 1; /* * HAL needs to know whether the rate is basic rate or not, as it needs to * update the response rate table accordingly. e.g. if one of the 11a rates is * basic rate, then that rate can be used for sending control frames. * HAL updates the response rate table whenever basic rate set is changed. */ if (basicOnly) { if (tempRateSet.rate[min] & 0x80) { if (isArate) pRates->llaRates[aRateIndex++] = tempRateSet.rate[min]; else pRates->llbRates[bRateIndex++] = tempRateSet.rate[min]; } } else { if (isArate) pRates->llaRates[aRateIndex++] = tempRateSet.rate[min]; else pRates->llbRates[bRateIndex++] = tempRateSet.rate[min]; } tempRateSet.rate[min] = 0xff; } } if (IS_DOT11_MODE_HT(psessionEntry->dot11mode)) { val = SIZE_OF_SUPPORTED_MCS_SET; if (wlan_cfg_get_str(pMac, WNI_CFG_SUPPORTED_MCS_SET, pRates->supportedMCSSet, &val) != QDF_STATUS_SUCCESS) { pe_err("could not retrieve supportedMCSSet"); return QDF_STATUS_E_FAILURE; } if (psessionEntry->nss == NSS_1x1_MODE) pRates->supportedMCSSet[1] = 0; /* if supported MCS Set of the peer is passed in, then do the * intersection, else use the MCS set from local CFG. */ if (pSupportedMCSSet != NULL) { for (i = 0; i < SIR_MAC_MAX_SUPPORTED_MCS_SET; i++) pRates->supportedMCSSet[i] &= pSupportedMCSSet[i]; } pe_debug("MCS Rate Set Bitmap: "); for (i = 0; i < SIR_MAC_MAX_SUPPORTED_MCS_SET; i++) pe_debug("%x ", pRates->supportedMCSSet[i]); if (pRates->supportedMCSSet[0] == 0) { pe_debug("Incorrect MCS 0 - 7. They must be supported"); pRates->supportedMCSSet[0] = 0xFF; } psessionEntry->supported_nss_1x1 = ((pRates->supportedMCSSet[1] != 0) ? false : true); pe_debug("HT supported nss 1x1: %d", psessionEntry->supported_nss_1x1); } lim_populate_vht_mcs_set(pMac, pRates, pVHTCaps, psessionEntry, psessionEntry->nss); lim_populate_he_mcs_set(pMac, pRates, he_caps, psessionEntry, psessionEntry->nss); if (IS_DOT11_MODE_HE(psessionEntry->dot11mode) && he_caps) { lim_calculate_he_nss(pRates, psessionEntry); } else if (IS_DOT11_MODE_VHT(psessionEntry->dot11mode)) { if ((pRates->vhtRxMCSMap & MCSMAPMASK2x2) == MCSMAPMASK2x2) psessionEntry->nss = NSS_1x1_MODE; } else if (pRates->supportedMCSSet[1] == 0) { psessionEntry->nss = NSS_1x1_MODE; } pe_debug("nss: %d", psessionEntry->nss); return QDF_STATUS_SUCCESS; } /*** lim_populate_peer_rate_set() ***/ /** * lim_populate_matching_rate_set() -process the CFG rate sets and * the rate sets received in the Assoc request on AP. * @mac_ctx: pointer to global mac structure * @sta_ds: station node * @oper_rate_set: pointer to operating rate set * @ext_rate_set: pointer to extended rate set * @supported_mcs_set: pointer to supported rate set * @session_entry: pointer to pe session entry * @vht_caps: pointer to vht capabilities * * This is called at the time of Association Request * processing on AP and while adding peer's context * in IBSS role to process the CFG rate sets and * the rate sets received in the Assoc request on AP * or Beacon/Probe Response from peer in IBSS. * * 1. It makes the intersection between our own rate Sat * and extemcded rate set and the ones received in the * association request. * 2. It creates a combined rate set of 12 rates max which * comprised the basic and extended rates * 3. It sorts the combined rate Set and copy it in the * rate array of the pSTA descriptor * * The parser has already ensured unicity of the rates in the * association request structure * * Return: QDF_STATUS_SUCCESS on success else QDF_STATUS_E_FAILURE */ QDF_STATUS lim_populate_matching_rate_set(tpAniSirGlobal mac_ctx, tpDphHashNode sta_ds, tSirMacRateSet *oper_rate_set, tSirMacRateSet *ext_rate_set, uint8_t *supported_mcs_set, tpPESession session_entry, tDot11fIEVHTCaps *vht_caps, tDot11fIEhe_cap *he_caps) { tSirMacRateSet temp_rate_set; tSirMacRateSet temp_rate_set2; uint32_t i, j, val, min, is_arate; uint32_t phy_mode; uint8_t mcs_set[SIZE_OF_SUPPORTED_MCS_SET]; tpSirSupportedRates rates; uint8_t a_rate_index = 0; uint8_t b_rate_index = 0; is_arate = 0; lim_get_phy_mode(mac_ctx, &phy_mode, session_entry); /* copy operational rate set from session_entry */ qdf_mem_copy((temp_rate_set.rate), (session_entry->rateSet.rate), session_entry->rateSet.numRates); temp_rate_set.numRates = (uint8_t) session_entry->rateSet.numRates; if (phy_mode == WNI_CFG_PHY_MODE_11G) { qdf_mem_copy((temp_rate_set2.rate), (session_entry->extRateSet.rate), session_entry->extRateSet.numRates); temp_rate_set2.numRates = (uint8_t) session_entry->extRateSet.numRates; } else { temp_rate_set2.numRates = 0; } /* * absolute sum of both num_rates should be less than 12. following * 16-bit sum avoids false codition where 8-bit arthematic overflow * might have caused total sum to be less than 12 */ if (((uint16_t)temp_rate_set.numRates + (uint16_t)temp_rate_set2.numRates) > 12) { pe_err("more than 12 rates in CFG"); return QDF_STATUS_E_FAILURE; } /* * Handling of the rate set IEs is the following: * - keep only rates that we support and that the station supports * - sort and the rates into the pSta->rate array */ /* Copy all rates in temp_rate_set, there are 12 rates max */ for (i = 0; i < temp_rate_set2.numRates; i++) temp_rate_set.rate[i + temp_rate_set.numRates] = temp_rate_set2.rate[i]; temp_rate_set.numRates += temp_rate_set2.numRates; /* * Sort rates in temp_rate_set (they are likely to be already sorted) * put the result in temp_rate_set2 */ temp_rate_set2.numRates = 0; for (i = 0; i < temp_rate_set.numRates; i++) { min = 0; val = 0xff; for (j = 0; j < temp_rate_set.numRates; j++) if ((uint32_t) (temp_rate_set.rate[j] & 0x7f) < val) { val = temp_rate_set.rate[j] & 0x7f; min = j; } temp_rate_set2.rate[temp_rate_set2.numRates++] = temp_rate_set.rate[min]; temp_rate_set.rate[min] = 0xff; } /* * Copy received rates in temp_rate_set, the parser has ensured * unicity of the rates so there cannot be more than 12 */ for (i = 0; (i < oper_rate_set->numRates && i < SIR_MAC_RATESET_EID_MAX); i++) temp_rate_set.rate[i] = oper_rate_set->rate[i]; temp_rate_set.numRates = oper_rate_set->numRates; pe_debug("Sum of SUPPORTED and EXTENDED Rate Set (%1d)", temp_rate_set.numRates + ext_rate_set->numRates); if (ext_rate_set->numRates && ((temp_rate_set.numRates + ext_rate_set->numRates) > 12) && temp_rate_set.numRates < 12) { int found = 0; int tail = temp_rate_set.numRates; for (i = 0; (i < ext_rate_set->numRates && i < SIR_MAC_RATESET_EID_MAX); i++) { found = 0; for (j = 0; j < (uint32_t) tail; j++) { if ((temp_rate_set.rate[j] & 0x7F) == (ext_rate_set->rate[i] & 0x7F)) { found = 1; break; } } if (!found) { temp_rate_set.rate[temp_rate_set.numRates++] = ext_rate_set->rate[i]; if (temp_rate_set.numRates >= 12) break; } } } else if (ext_rate_set->numRates && ((temp_rate_set.numRates + ext_rate_set->numRates) <= 12)) { for (j = 0; ((j < ext_rate_set->numRates) && (j < SIR_MAC_RATESET_EID_MAX) && ((i + j) < SIR_MAC_RATESET_EID_MAX)); j++) temp_rate_set.rate[i + j] = ext_rate_set->rate[j]; temp_rate_set.numRates += ext_rate_set->numRates; } else if (ext_rate_set->numRates) { pe_debug("Relying only on the SUPPORTED Rate Set IE"); } rates = &sta_ds->supportedRates; qdf_mem_zero((uint8_t *) rates, sizeof(tSirSupportedRates)); for (i = 0; (i < temp_rate_set2.numRates && i < SIR_MAC_RATESET_EID_MAX); i++) { for (j = 0; (j < temp_rate_set.numRates && j < SIR_MAC_RATESET_EID_MAX); j++) { if ((temp_rate_set2.rate[i] & 0x7F) != (temp_rate_set.rate[j] & 0x7F)) continue; if (sirIsArate(temp_rate_set2.rate[i] & 0x7f) && a_rate_index < SIR_NUM_11A_RATES) { is_arate = 1; rates->llaRates[a_rate_index++] = temp_rate_set2.rate[i]; } else if ((b_rate_index < SIR_NUM_11B_RATES) && !(sirIsArate(temp_rate_set2.rate[i] & 0x7f))) { rates->llbRates[b_rate_index++] = temp_rate_set2.rate[i]; } break; } } /* * Now add the Polaris rates only when Proprietary rates are enabled. * compute the matching MCS rate set, if peer is 11n capable and self * mode is 11n */ #ifdef FEATURE_WLAN_TDLS if (sta_ds->mlmStaContext.htCapability) #else if (IS_DOT11_MODE_HT(session_entry->dot11mode) && (sta_ds->mlmStaContext.htCapability)) #endif { val = SIZE_OF_SUPPORTED_MCS_SET; if (wlan_cfg_get_str(mac_ctx, WNI_CFG_SUPPORTED_MCS_SET, mcs_set, &val) != QDF_STATUS_SUCCESS) { pe_err("could not retrieve supportedMCSet"); return QDF_STATUS_E_FAILURE; } if (session_entry->nss == NSS_1x1_MODE) mcs_set[1] = 0; for (i = 0; i < val; i++) sta_ds->supportedRates.supportedMCSSet[i] = mcs_set[i] & supported_mcs_set[i]; pe_debug("lim_populate_matching_rate_set: MCS Rate Set Bitmap" " from CFG and DPH : "); for (i = 0; i < SIR_MAC_MAX_SUPPORTED_MCS_SET; i++) { pe_debug("%x %x ", mcs_set[i], sta_ds->supportedRates.supportedMCSSet[i]); } } lim_populate_vht_mcs_set(mac_ctx, &sta_ds->supportedRates, vht_caps, session_entry, session_entry->nss); lim_populate_he_mcs_set(mac_ctx, &sta_ds->supportedRates, he_caps, session_entry, session_entry->nss); /* * Set the erpEnabled bit if the phy is in G mode and at least * one A rate is supported */ if ((phy_mode == WNI_CFG_PHY_MODE_11G) && is_arate) sta_ds->erpEnabled = eHAL_SET; return QDF_STATUS_SUCCESS; } /** * lim_populate_vht_caps() - populates vht capabilities based on input * capabilities * @input_caps: input capabilities based on which we format the vht * capabilities * * function to populate the supported vht capabilities. * * Return: vht capabilities derived based on input parameters. */ static uint32_t lim_populate_vht_caps(tDot11fIEVHTCaps input_caps) { uint32_t vht_caps; vht_caps = ((input_caps.maxMPDULen << SIR_MAC_VHT_CAP_MAX_MPDU_LEN) | (input_caps.supportedChannelWidthSet << SIR_MAC_VHT_CAP_SUPP_CH_WIDTH_SET) | (input_caps.ldpcCodingCap << SIR_MAC_VHT_CAP_LDPC_CODING_CAP) | (input_caps.shortGI80MHz << SIR_MAC_VHT_CAP_SHORTGI_80MHZ) | (input_caps.shortGI160and80plus80MHz << SIR_MAC_VHT_CAP_SHORTGI_160_80_80MHZ) | (input_caps.txSTBC << SIR_MAC_VHT_CAP_TXSTBC) | (input_caps.rxSTBC << SIR_MAC_VHT_CAP_RXSTBC) | (input_caps.suBeamFormerCap << SIR_MAC_VHT_CAP_SU_BEAMFORMER_CAP) | (input_caps.suBeamformeeCap << SIR_MAC_VHT_CAP_SU_BEAMFORMEE_CAP) | (input_caps.csnofBeamformerAntSup << SIR_MAC_VHT_CAP_CSN_BEAMORMER_ANT_SUP) | (input_caps.numSoundingDim << SIR_MAC_VHT_CAP_NUM_SOUNDING_DIM) | (input_caps.muBeamformerCap << SIR_MAC_VHT_CAP_NUM_BEAM_FORMER_CAP) | (input_caps.muBeamformeeCap << SIR_MAC_VHT_CAP_NUM_BEAM_FORMEE_CAP) | (input_caps.vhtTXOPPS << SIR_MAC_VHT_CAP_TXOPPS) | (input_caps.htcVHTCap << SIR_MAC_VHT_CAP_HTC_CAP) | (input_caps.maxAMPDULenExp << SIR_MAC_VHT_CAP_MAX_AMDU_LEN_EXPO) | (input_caps.vhtLinkAdaptCap << SIR_MAC_VHT_CAP_LINK_ADAPT_CAP) | (input_caps.rxAntPattern << SIR_MAC_VHT_CAP_RX_ANTENNA_PATTERN) | (input_caps.txAntPattern << SIR_MAC_VHT_CAP_TX_ANTENNA_PATTERN) | (input_caps.reserved1 << SIR_MAC_VHT_CAP_RESERVED2)); return vht_caps; } /** * lim_update_he_stbc_capable() - Update stbc capable flag based on * HE capability * @add_sta_params: add sta related parameters * * Update stbc cpable flag based on HE capability * * Return: None */ #ifdef WLAN_FEATURE_11AX static void lim_update_he_stbc_capable(tpAddStaParams add_sta_params) { if (add_sta_params && add_sta_params->he_capable && add_sta_params->stbc_capable) add_sta_params->stbc_capable = add_sta_params->he_config.rx_stbc_lt_80mhz; } #else static void lim_update_he_stbc_capable(tpAddStaParams add_sta_params) {} #endif /** * lim_add_sta()- called to add an STA context at hardware * @mac_ctx: pointer to global mac structure * @sta_ds: station node * @update_entry: set to true for updating the entry * @session_entry: pe session entry * * This function is called to add an STA context at hardware * whenever a STA is (Re) Associated. * * Return: QDF_STATUS_SUCCESS on success else QDF_STATUS failure codes */ QDF_STATUS lim_add_sta(tpAniSirGlobal mac_ctx, tpDphHashNode sta_ds, uint8_t update_entry, tpPESession session_entry) { tpAddStaParams add_sta_params = NULL; struct scheduler_msg msg_q = {0}; QDF_STATUS ret_code = QDF_STATUS_SUCCESS; tSirMacAddr sta_mac, *sta_Addr; tpSirAssocReq assoc_req; uint8_t i, nw_type_11b = 0; tLimIbssPeerNode *peer_node; /* for IBSS mode */ const uint8_t *p2p_ie = NULL; tDot11fIEVHTCaps vht_caps; sir_copy_mac_addr(sta_mac, session_entry->selfMacAddr); pe_debug("sessionid: %d update_entry = %d limsystemrole = %d", session_entry->smeSessionId, update_entry, GET_LIM_SYSTEM_ROLE(session_entry)); add_sta_params = qdf_mem_malloc(sizeof(tAddStaParams)); if (NULL == add_sta_params) { pe_err("Unable to allocate memory during ADD_STA"); return QDF_STATUS_E_NOMEM; } if (LIM_IS_AP_ROLE(session_entry) || LIM_IS_IBSS_ROLE(session_entry) || LIM_IS_NDI_ROLE(session_entry)) sta_Addr = &sta_ds->staAddr; #ifdef FEATURE_WLAN_TDLS /* SystemRole shouldn't be matter if staType is TDLS peer */ else if (STA_ENTRY_TDLS_PEER == sta_ds->staType) sta_Addr = &sta_ds->staAddr; #endif else sta_Addr = &sta_mac; pe_debug(MAC_ADDRESS_STR ": Subtype(Assoc/Reassoc): %d", MAC_ADDR_ARRAY(*sta_Addr), sta_ds->mlmStaContext.subType); qdf_mem_copy((uint8_t *) add_sta_params->staMac, (uint8_t *) *sta_Addr, sizeof(tSirMacAddr)); qdf_mem_copy((uint8_t *) add_sta_params->bssId, session_entry->bssId, sizeof(tSirMacAddr)); qdf_mem_copy(&add_sta_params->capab_info, &sta_ds->mlmStaContext.capabilityInfo, sizeof(add_sta_params->capab_info)); /* Copy legacy rates */ qdf_mem_copy((uint8_t *) &add_sta_params->supportedRates, (uint8_t *) &sta_ds->supportedRates, sizeof(tSirSupportedRates)); add_sta_params->assocId = sta_ds->assocId; add_sta_params->wmmEnabled = sta_ds->qosMode; add_sta_params->listenInterval = sta_ds->mlmStaContext.listenInterval; add_sta_params->shortPreambleSupported = sta_ds->shortPreambleEnabled; if (LIM_IS_AP_ROLE(session_entry) && (sta_ds->mlmStaContext.subType == LIM_REASSOC)) { /* * TBD - need to remove this REASSOC check * after fixinf rmmod issue */ add_sta_params->updateSta = sta_ds->mlmStaContext.updateContext; } sta_ds->valid = 0; sta_ds->mlmStaContext.mlmState = eLIM_MLM_WT_ADD_STA_RSP_STATE; pe_debug("Assoc ID: %d wmmEnabled: %d listenInterval: %d" " shortPreambleSupported: %d", add_sta_params->assocId, add_sta_params->wmmEnabled, add_sta_params->listenInterval, add_sta_params->shortPreambleSupported); /* This will indicate HAL to "allocate" a new STA index */ #ifdef FEATURE_WLAN_TDLS /* * As there is corner case in-between add_sta and change_sta,if del_sta * for other staIdx happened, firmware return wrong staIdx * (recently removed staIdx). Until we get a confirmation from the * firmware team it is now return correct staIdx for same sta_mac_addr * for update case, we want to get around it by passing valid staIdx * given by add_sta time. */ if ((STA_ENTRY_TDLS_PEER == sta_ds->staType) && (true == update_entry)) add_sta_params->staIdx = sta_ds->staIndex; else #endif add_sta_params->staIdx = STA_INVALID_IDX; add_sta_params->staType = sta_ds->staType; add_sta_params->updateSta = update_entry; add_sta_params->status = QDF_STATUS_SUCCESS; add_sta_params->respReqd = 1; /* Update VHT/HT Capability */ if (LIM_IS_AP_ROLE(session_entry) || LIM_IS_IBSS_ROLE(session_entry)) { add_sta_params->htCapable = sta_ds->mlmStaContext.htCapability; add_sta_params->vhtCapable = sta_ds->mlmStaContext.vhtCapability; } #ifdef FEATURE_WLAN_TDLS /* SystemRole shouldn't be matter if staType is TDLS peer */ else if (STA_ENTRY_TDLS_PEER == sta_ds->staType) { add_sta_params->htCapable = sta_ds->mlmStaContext.htCapability; add_sta_params->vhtCapable = sta_ds->mlmStaContext.vhtCapability; } #endif else { add_sta_params->htCapable = session_entry->htCapability; add_sta_params->vhtCapable = session_entry->vhtCapability; } pe_debug("StaIdx: %d updateSta: %d htcapable: %d vhtCapable: %d", add_sta_params->staIdx, add_sta_params->updateSta, add_sta_params->htCapable, add_sta_params->vhtCapable); /* * If HT client is connected to SAP DUT and self cap is NSS = 2 then * disable ASYNC DBS scan by sending WMI_VDEV_PARAM_SMPS_INTOLERANT * to FW, because HT client's can't drop down chain using SMPS frames. */ if (!policy_mgr_is_hw_dbs_2x2_capable(mac_ctx->psoc) && LIM_IS_AP_ROLE(session_entry) && (STA_ENTRY_PEER == sta_ds->staType) && !add_sta_params->vhtCapable && (session_entry->nss == 2)) { session_entry->ht_client_cnt++; if (session_entry->ht_client_cnt == 1) { pe_debug("setting SMPS intolrent vdev_param"); wma_cli_set_command(session_entry->smeSessionId, (int)WMI_VDEV_PARAM_SMPS_INTOLERANT, 1, VDEV_CMD); } } lim_update_sta_he_capable(mac_ctx, add_sta_params, sta_ds, session_entry); add_sta_params->greenFieldCapable = sta_ds->htGreenfield; add_sta_params->maxAmpduDensity = sta_ds->htAMpduDensity; add_sta_params->maxAmpduSize = sta_ds->htMaxRxAMpduFactor; add_sta_params->fDsssCckMode40Mhz = sta_ds->htDsssCckRate40MHzSupport; add_sta_params->fShortGI20Mhz = sta_ds->htShortGI20Mhz; add_sta_params->fShortGI40Mhz = sta_ds->htShortGI40Mhz; add_sta_params->lsigTxopProtection = sta_ds->htLsigTXOPProtection; add_sta_params->maxAmsduSize = sta_ds->htMaxAmsduLength; add_sta_params->ch_width = sta_ds->htSupportedChannelWidthSet; add_sta_params->mimoPS = sta_ds->htMIMOPSState; pe_debug("greenFieldCapable: %d maxAmpduDensity: %d maxAmpduDensity: %d", add_sta_params->greenFieldCapable, add_sta_params->maxAmpduDensity, add_sta_params->maxAmpduSize); pe_debug("fDsssCckMode40Mhz: %d fShortGI20Mhz: %d fShortGI40Mhz: %d", add_sta_params->fDsssCckMode40Mhz, add_sta_params->fShortGI20Mhz, add_sta_params->fShortGI40Mhz); pe_debug("lsigTxopProtection: %d maxAmsduSize: %d txChannelWidth: %d mimoPS: %d", add_sta_params->lsigTxopProtection, add_sta_params->maxAmsduSize, add_sta_params->ch_width, add_sta_params->mimoPS); if (add_sta_params->vhtCapable) { if (sta_ds->vhtSupportedChannelWidthSet) add_sta_params->ch_width = sta_ds->vhtSupportedChannelWidthSet + 1; add_sta_params->vhtSupportedRxNss = sta_ds->vhtSupportedRxNss; if (LIM_IS_AP_ROLE(session_entry) || LIM_IS_P2P_DEVICE_GO(session_entry)) add_sta_params->vhtSupportedRxNss = QDF_MIN( add_sta_params->vhtSupportedRxNss, session_entry->nss); add_sta_params->vhtTxBFCapable = #ifdef FEATURE_WLAN_TDLS ((STA_ENTRY_PEER == sta_ds->staType) || (STA_ENTRY_TDLS_PEER == sta_ds->staType)) ? sta_ds->vhtBeamFormerCapable : session_entry->vht_config.su_beam_formee; #else (STA_ENTRY_PEER == sta_ds->staType) ? sta_ds->vhtBeamFormerCapable : session_entry->vht_config.su_beam_formee; #endif add_sta_params->enable_su_tx_bformer = sta_ds->vht_su_bfee_capable; } pe_debug("TxChWidth %d vhtTxBFCap %d, su_bfer %d", add_sta_params->ch_width, add_sta_params->vhtTxBFCapable, add_sta_params->enable_su_tx_bformer); #ifdef FEATURE_WLAN_TDLS if ((STA_ENTRY_PEER == sta_ds->staType) || (STA_ENTRY_TDLS_PEER == sta_ds->staType)) #else if (STA_ENTRY_PEER == sta_ds->staType) #endif { /* * peer STA get the LDPC capability from sta_ds, * which populated from * HT/VHT capability */ if (add_sta_params->vhtTxBFCapable && mac_ctx->lim.disableLDPCWithTxbfAP) { add_sta_params->htLdpcCapable = 0; add_sta_params->vhtLdpcCapable = 0; } else { if (session_entry->txLdpcIniFeatureEnabled & 0x1) add_sta_params->htLdpcCapable = sta_ds->htLdpcCapable; else add_sta_params->htLdpcCapable = 0; if (session_entry->txLdpcIniFeatureEnabled & 0x2) add_sta_params->vhtLdpcCapable = sta_ds->vhtLdpcCapable; else add_sta_params->vhtLdpcCapable = 0; } } else if (STA_ENTRY_SELF == sta_ds->staType) { /* For Self STA get the LDPC capability from config.ini */ add_sta_params->htLdpcCapable = (session_entry->txLdpcIniFeatureEnabled & 0x01); add_sta_params->vhtLdpcCapable = ((session_entry->txLdpcIniFeatureEnabled >> 1) & 0x01); } /* Update PE session ID */ add_sta_params->sessionId = session_entry->peSessionId; /* Update SME session ID */ add_sta_params->smesessionId = session_entry->smeSessionId; add_sta_params->maxTxPower = session_entry->maxTxPower; if (session_entry->parsedAssocReq != NULL) { uint16_t aid = sta_ds->assocId; /* Get a copy of the already parsed Assoc Request */ assoc_req = (tpSirAssocReq) session_entry->parsedAssocReq[aid]; if (assoc_req && assoc_req->addIEPresent && assoc_req->addIE.length) { p2p_ie = limGetP2pIEPtr(mac_ctx, assoc_req->addIE.addIEdata, assoc_req->addIE.length); } add_sta_params->p2pCapableSta = (p2p_ie != NULL); if (assoc_req && add_sta_params->htCapable) { qdf_mem_copy(&add_sta_params->ht_caps, ((uint8_t *) &assoc_req->HTCaps) + 1, sizeof(add_sta_params->ht_caps)); } if (assoc_req && add_sta_params->vhtCapable) { if (assoc_req->vendor_vht_ie.VHTCaps.present) vht_caps = assoc_req->vendor_vht_ie.VHTCaps; else vht_caps = assoc_req->VHTCaps; add_sta_params->vht_caps = lim_populate_vht_caps(vht_caps); } lim_add_he_cap(add_sta_params, assoc_req); } else if (LIM_IS_IBSS_ROLE(session_entry)) { /* * in IBSS mode, use peer node as the source of ht_caps * and vht_caps */ peer_node = lim_ibss_peer_find(mac_ctx, *sta_Addr); if (!peer_node) { pe_err("Can't find IBSS peer node for ADD_STA"); return QDF_STATUS_E_NOENT; } if (peer_node->atimIePresent) { add_sta_params->atimIePresent = peer_node->atimIePresent; add_sta_params->peerAtimWindowLength = peer_node->peerAtimWindowLength; } add_sta_params->ht_caps = (peer_node->htSupportedChannelWidthSet << SIR_MAC_HT_CAP_CHWIDTH40_S) | (peer_node->htGreenfield << SIR_MAC_HT_CAP_GREENFIELD_S) | (peer_node->htShortGI20Mhz << SIR_MAC_HT_CAP_SHORTGI20MHZ_S) | (peer_node->htShortGI40Mhz << SIR_MAC_HT_CAP_SHORTGI40MHZ_S) | (SIR_MAC_TXSTBC << SIR_MAC_HT_CAP_TXSTBC_S) | (SIR_MAC_RXSTBC << SIR_MAC_HT_CAP_RXSTBC_S) | (peer_node->htMaxAmsduLength << SIR_MAC_HT_CAP_MAXAMSDUSIZE_S) | (peer_node->htDsssCckRate40MHzSupport << SIR_MAC_HT_CAP_DSSSCCK40_S); add_sta_params->vht_caps = lim_populate_vht_caps(peer_node->VHTCaps); } #ifdef FEATURE_WLAN_TDLS if (STA_ENTRY_TDLS_PEER == sta_ds->staType) { add_sta_params->ht_caps = sta_ds->ht_caps; add_sta_params->vht_caps = sta_ds->vht_caps; if (add_sta_params->vhtCapable) { add_sta_params->maxAmpduSize = SIR_MAC_GET_VHT_MAX_AMPDU_EXPO( sta_ds->vht_caps); } pe_debug("Sta type is TDLS_PEER, ht_caps: 0x%x, vht_caps: 0x%x", add_sta_params->ht_caps, add_sta_params->vht_caps); } #endif #ifdef FEATURE_WLAN_TDLS if (sta_ds->wmeEnabled && (LIM_IS_AP_ROLE(session_entry) || (STA_ENTRY_TDLS_PEER == sta_ds->staType))) #else if (sta_ds->wmeEnabled && LIM_IS_AP_ROLE(session_entry)) #endif { add_sta_params->uAPSD = 0; /* * update UAPSD and send it to LIM to add STA * bitmap MSB <- LSB MSB 4 bits are for * trigger enabled AC setting and LSB 4 bits * are for delivery enabled AC setting * 7 6 5 4 3 2 1 0 * BE BK VI VO BE BK VI VO */ add_sta_params->uAPSD |= sta_ds->qos.capability.qosInfo.acvo_uapsd; add_sta_params->uAPSD |= (sta_ds->qos.capability.qosInfo.acvi_uapsd << 1); add_sta_params->uAPSD |= (sta_ds->qos.capability.qosInfo.acbk_uapsd << 2); add_sta_params->uAPSD |= (sta_ds->qos.capability.qosInfo.acbe_uapsd << 3); /* * making delivery enabled and * trigger enabled setting the same. */ add_sta_params->uAPSD |= add_sta_params->uAPSD << 4; add_sta_params->maxSPLen = sta_ds->qos.capability.qosInfo.maxSpLen; pe_debug("uAPSD = 0x%x, maxSpLen = %d", add_sta_params->uAPSD, add_sta_params->maxSPLen); } #ifdef WLAN_FEATURE_11W add_sta_params->rmfEnabled = sta_ds->rmfEnabled; pe_debug("PMF enabled %d", add_sta_params->rmfEnabled); #endif pe_debug("htLdpcCapable: %d vhtLdpcCapable: %d " "p2pCapableSta: %d", add_sta_params->htLdpcCapable, add_sta_params->vhtLdpcCapable, add_sta_params->p2pCapableSta); if (!add_sta_params->htLdpcCapable) add_sta_params->ht_caps &= ~(1 << SIR_MAC_HT_CAP_ADVCODING_S); if (!add_sta_params->vhtLdpcCapable) add_sta_params->vht_caps &= ~(1 << SIR_MAC_VHT_CAP_LDPC_CODING_CAP); /* * we need to defer the message until we get the * response back from HAL. */ if (add_sta_params->respReqd) SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, false); add_sta_params->nwType = session_entry->nwType; if (!(add_sta_params->htCapable || add_sta_params->vhtCapable)) { nw_type_11b = 1; for (i = 0; i < SIR_NUM_11A_RATES; i++) { if (sirIsArate(sta_ds->supportedRates.llaRates[i] & 0x7F)) { nw_type_11b = 0; break; } } if (nw_type_11b) add_sta_params->nwType = eSIR_11B_NW_TYPE; } if (add_sta_params->htCapable && session_entry->htConfig.ht_tx_stbc) { struct sDot11fIEHTCaps *ht_caps = (struct sDot11fIEHTCaps *) &add_sta_params->ht_caps; if (ht_caps->rxSTBC) add_sta_params->stbc_capable = 1; else add_sta_params->stbc_capable = 0; } if (add_sta_params->vhtCapable && add_sta_params->stbc_capable) { struct sDot11fIEVHTCaps *vht_caps = (struct sDot11fIEVHTCaps *) &add_sta_params->vht_caps; if (vht_caps->rxSTBC) add_sta_params->stbc_capable = 1; else add_sta_params->stbc_capable = 0; } lim_update_he_stbc_capable(add_sta_params); msg_q.type = WMA_ADD_STA_REQ; msg_q.reserved = 0; msg_q.bodyptr = add_sta_params; msg_q.bodyval = 0; pe_debug("Sending WMA_ADD_STA_REQ for assocId %d", sta_ds->assocId); MTRACE(mac_trace_msg_tx(mac_ctx, session_entry->peSessionId, msg_q.type)); ret_code = wma_post_ctrl_msg(mac_ctx, &msg_q); if (QDF_STATUS_SUCCESS != ret_code) { if (add_sta_params->respReqd) SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, true); pe_err("ADD_STA_REQ for aId %d failed (reason %X)", sta_ds->assocId, ret_code); qdf_mem_free(add_sta_params); } return ret_code; } /** * lim_del_sta() * ***FUNCTION: * This function is called to delete an STA context at hardware * whenever a STA is disassociated * ***LOGIC: * ***ASSUMPTIONS: * NA * ***NOTE: * NA * * @param pMac - Pointer to Global MAC structure * @param pStaDs - Pointer to the STA datastructure created by * LIM and maintained by DPH * @param fRespReqd - flag to indicate whether the delete is synchronous (true) * or not (false) * @return retCode - Indicates success or failure return code */ QDF_STATUS lim_del_sta(tpAniSirGlobal pMac, tpDphHashNode pStaDs, bool fRespReqd, tpPESession psessionEntry) { tpDeleteStaParams pDelStaParams = NULL; struct scheduler_msg msgQ = {0}; QDF_STATUS retCode = QDF_STATUS_SUCCESS; pDelStaParams = qdf_mem_malloc(sizeof(tDeleteStaParams)); if (NULL == pDelStaParams) { pe_err("Unable to allocate memory during ADD_STA"); return QDF_STATUS_E_NOMEM; } /* * 2G-AS platform: SAP associates with HT (11n)clients as 2x1 in 2G and * 2X2 in 5G * Non-2G-AS platform: SAP associates with HT (11n) clients as 2X2 in 2G * and 5G; and enable async dbs scan when all HT clients are gone * 5G-AS: Don't care */ if (!policy_mgr_is_hw_dbs_2x2_capable(pMac->psoc) && LIM_IS_AP_ROLE(psessionEntry) && (pStaDs->staType == STA_ENTRY_PEER) && !pStaDs->mlmStaContext.vhtCapability && (psessionEntry->nss == 2)) { psessionEntry->ht_client_cnt--; if (psessionEntry->ht_client_cnt == 0) { pe_debug("clearing SMPS intolrent vdev_param"); wma_cli_set_command(psessionEntry->smeSessionId, (int)WMI_VDEV_PARAM_SMPS_INTOLERANT, 0, VDEV_CMD); } } /* */ /* DPH contains the STA index only for "peer" STA entries. */ /* LIM global contains "self" STA index */ /* Thus, */ /* if( STA role ) */ /* get STA index from LIM global */ /* else */ /* get STA index from DPH */ /* */ #ifdef FEATURE_WLAN_TDLS if (LIM_IS_STA_ROLE(psessionEntry) && (pStaDs->staType != STA_ENTRY_TDLS_PEER)) #else if (LIM_IS_STA_ROLE(psessionEntry)) #endif pDelStaParams->staIdx = psessionEntry->staId; else pDelStaParams->staIdx = pStaDs->staIndex; pDelStaParams->assocId = pStaDs->assocId; pStaDs->valid = 0; if (!fRespReqd) pDelStaParams->respReqd = 0; else { if (!(IS_TDLS_PEER(pStaDs->staType))) { /* when lim_del_sta is called from processSmeAssocCnf * then mlmState is already set properly. */ if (eLIM_MLM_WT_ASSOC_DEL_STA_RSP_STATE != GET_LIM_STA_CONTEXT_MLM_STATE(pStaDs)) { MTRACE(mac_trace (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, eLIM_MLM_WT_DEL_STA_RSP_STATE)); SET_LIM_STA_CONTEXT_MLM_STATE(pStaDs, eLIM_MLM_WT_DEL_STA_RSP_STATE); } if (LIM_IS_STA_ROLE(psessionEntry)) { MTRACE(mac_trace (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, eLIM_MLM_WT_DEL_STA_RSP_STATE)); psessionEntry->limMlmState = eLIM_MLM_WT_DEL_STA_RSP_STATE; } } /* we need to defer the message until we get the * response back from HAL. */ SET_LIM_PROCESS_DEFD_MESGS(pMac, false); pDelStaParams->respReqd = 1; } /* Update PE session ID */ pDelStaParams->sessionId = psessionEntry->peSessionId; pDelStaParams->smesessionId = psessionEntry->smeSessionId; pDelStaParams->staType = pStaDs->staType; qdf_mem_copy((uint8_t *) pDelStaParams->staMac, (uint8_t *) pStaDs->staAddr, sizeof(tSirMacAddr)); pDelStaParams->status = QDF_STATUS_SUCCESS; msgQ.type = WMA_DELETE_STA_REQ; msgQ.reserved = 0; msgQ.bodyptr = pDelStaParams; msgQ.bodyval = 0; pe_debug("Sessionid %d :Sending SIR_HAL_DELETE_STA_REQ " "for STAID: %X and AssocID: %d MAC : " MAC_ADDRESS_STR, pDelStaParams->sessionId, pDelStaParams->staIdx, pDelStaParams->assocId, MAC_ADDR_ARRAY(pStaDs->staAddr)); MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); retCode = wma_post_ctrl_msg(pMac, &msgQ); if (QDF_STATUS_SUCCESS != retCode) { if (fRespReqd) SET_LIM_PROCESS_DEFD_MESGS(pMac, true); pe_err("Posting DELETE_STA_REQ to HAL failed, reason=%X", retCode); qdf_mem_free(pDelStaParams); } return retCode; } /** * lim_add_sta_self() * ***FUNCTION: * This function is called to add an STA context at hardware * whenever a STA is (Re) Associated. * ***LOGIC: * ***ASSUMPTIONS: * NA * ***NOTE: * NA * * @param pMac - Pointer to Global MAC structure * @param pStaDs - Pointer to the STA datastructure created by * LIM and maintained by DPH * @return retCode - Indicates success or failure return code */ QDF_STATUS lim_add_sta_self(tpAniSirGlobal pMac, uint16_t staIdx, uint8_t updateSta, tpPESession psessionEntry) { tpAddStaParams pAddStaParams = NULL; struct scheduler_msg msgQ = {0}; QDF_STATUS retCode = QDF_STATUS_SUCCESS; tSirMacAddr staMac; uint32_t listenInterval = WNI_CFG_LISTEN_INTERVAL_STADEF; uint32_t ampduLenExponent = 0; /*This self Sta dot 11 mode comes from the cfg and the expectation here is * that cfg carries the systemwide capability that device under * consideration can support. This capability gets plumbed into the cfg * cache at system initialization time via the .dat and .ini file override * mechanisms and will not change. If it does change, it is the * responsibility of SME to evict the selfSta and reissue a new AddStaSelf * command.*/ uint32_t selfStaDot11Mode = 0, selfTxWidth = 0; uint32_t val; wlan_cfg_get_int(pMac, WNI_CFG_DOT11_MODE, &selfStaDot11Mode); wlan_cfg_get_int(pMac, WNI_CFG_HT_CAP_INFO_SUPPORTED_CHAN_WIDTH_SET, &selfTxWidth); pe_debug("cfgDot11Mode: %d selfTxWidth: %d", (int)selfStaDot11Mode, (int)selfTxWidth); pe_debug("Roam Channel Bonding Mode %d", (int)pMac->roam.configParam.uCfgDot11Mode); sir_copy_mac_addr(staMac, psessionEntry->selfMacAddr); pe_debug(MAC_ADDRESS_STR ": ", MAC_ADDR_ARRAY(staMac)); pAddStaParams = qdf_mem_malloc(sizeof(tAddStaParams)); if (NULL == pAddStaParams) { pe_err("Unable to allocate memory during ADD_STA"); return QDF_STATUS_E_NOMEM; } /* / Add STA context at MAC HW (BMU, RHP & TFP) */ qdf_mem_copy((uint8_t *) pAddStaParams->staMac, (uint8_t *) staMac, sizeof(tSirMacAddr)); qdf_mem_copy((uint8_t *) pAddStaParams->bssId, psessionEntry->bssId, sizeof(tSirMacAddr)); pAddStaParams->assocId = psessionEntry->limAID; pAddStaParams->staType = STA_ENTRY_SELF; pAddStaParams->status = QDF_STATUS_SUCCESS; pAddStaParams->respReqd = 1; /* Update PE session ID */ pAddStaParams->sessionId = psessionEntry->peSessionId; /* Update SME session ID */ pAddStaParams->smesessionId = psessionEntry->smeSessionId; pAddStaParams->maxTxPower = psessionEntry->maxTxPower; /* This will indicate HAL to "allocate" a new STA index */ pAddStaParams->staIdx = staIdx; pAddStaParams->updateSta = updateSta; if (wlan_cfg_get_int(pMac, WNI_CFG_SHORT_PREAMBLE, &val) != QDF_STATUS_SUCCESS) { pe_err("Couldn't get SHORT_PREAMBLE, set default"); pAddStaParams->shortPreambleSupported = 1; } else { pAddStaParams->shortPreambleSupported = val; } lim_populate_own_rate_set(pMac, &pAddStaParams->supportedRates, NULL, false, psessionEntry, NULL, NULL); if (IS_DOT11_MODE_HT(selfStaDot11Mode)) { pAddStaParams->htCapable = true; #ifdef DISABLE_GF_FOR_INTEROP if ((psessionEntry->pLimJoinReq != NULL) && (!psessionEntry->pLimJoinReq->bssDescription. aniIndicator)) { pe_err("Turning off Greenfield, when adding self entry"); pAddStaParams->greenFieldCapable = WNI_CFG_GREENFIELD_CAPABILITY_DISABLE; } else #endif { pAddStaParams->greenFieldCapable = lim_get_ht_capability(pMac, eHT_GREENFIELD, psessionEntry); pAddStaParams->ch_width = pMac->roam.configParam.channelBondingMode5GHz; pAddStaParams->mimoPS = lim_get_ht_capability(pMac, eHT_MIMO_POWER_SAVE, psessionEntry); pAddStaParams->rifsMode = lim_get_ht_capability(pMac, eHT_RIFS_MODE, psessionEntry); pAddStaParams->lsigTxopProtection = lim_get_ht_capability(pMac, eHT_LSIG_TXOP_PROTECTION, psessionEntry); pAddStaParams->maxAmpduDensity = lim_get_ht_capability(pMac, eHT_MPDU_DENSITY, psessionEntry); pAddStaParams->maxAmpduSize = lim_get_ht_capability(pMac, eHT_MAX_RX_AMPDU_FACTOR, psessionEntry); pAddStaParams->maxAmsduSize = lim_get_ht_capability(pMac, eHT_MAX_AMSDU_LENGTH, psessionEntry); pAddStaParams->max_amsdu_num = lim_get_ht_capability(pMac, eHT_MAX_AMSDU_NUM, psessionEntry); pAddStaParams->fDsssCckMode40Mhz = lim_get_ht_capability(pMac, eHT_DSSS_CCK_MODE_40MHZ, psessionEntry); pAddStaParams->fShortGI20Mhz = psessionEntry->htConfig.ht_sgi20; pAddStaParams->fShortGI40Mhz = psessionEntry->htConfig.ht_sgi40; pe_debug("greenFieldCapable: %d maxAmpduDensity: %d " "maxAmpduSize: %d", pAddStaParams->greenFieldCapable, pAddStaParams->maxAmpduDensity, pAddStaParams->maxAmpduSize); pe_debug("fDsssCckMode40Mhz: %d fShortGI20Mhz: %d " "fShortGI40Mhz: %d lsigTxopProtection: %d", pAddStaParams->fDsssCckMode40Mhz, pAddStaParams->fShortGI20Mhz, pAddStaParams->fShortGI40Mhz, pAddStaParams->lsigTxopProtection); pe_debug("maxAmsduSize: %d txChannelWidth: %d mimoPS: %d rifsMode %d", pAddStaParams->maxAmsduSize, pAddStaParams->ch_width, pAddStaParams->mimoPS, pAddStaParams->rifsMode); } } pAddStaParams->vhtCapable = IS_DOT11_MODE_VHT(selfStaDot11Mode); if (pAddStaParams->vhtCapable) { pAddStaParams->ch_width = psessionEntry->ch_width; pe_debug("VHT WIDTH SET %d", pAddStaParams->ch_width); } pAddStaParams->vhtTxBFCapable = psessionEntry->vht_config.su_beam_formee; pAddStaParams->enable_su_tx_bformer = psessionEntry->vht_config.su_beam_former; pe_debug("vhtCapable: %d vhtTxBFCapable %d, su_bfer %d", pAddStaParams->vhtCapable, pAddStaParams->vhtTxBFCapable, pAddStaParams->enable_su_tx_bformer); /* In 11ac mode, the hardware is capable of supporting 128K AMPDU size */ if (IS_DOT11_MODE_VHT(selfStaDot11Mode)) { if (wlan_cfg_get_int (pMac, WNI_CFG_VHT_AMPDU_LEN_EXPONENT, &duLenExponent) != QDF_STATUS_SUCCESS) { pe_err("Couldn't get WNI_CFG_VHT_AMPDU_LEN_EXPONENT"); } pAddStaParams->maxAmpduSize = (uint8_t) ampduLenExponent; } pAddStaParams->vhtTxMUBformeeCapable = psessionEntry->vht_config.mu_beam_formee; pAddStaParams->enableVhtpAid = psessionEntry->enableVhtpAid; pAddStaParams->enableAmpduPs = psessionEntry->enableAmpduPs; pAddStaParams->enableHtSmps = (psessionEntry->enableHtSmps && (!psessionEntry->supported_nss_1x1)); pAddStaParams->htSmpsconfig = psessionEntry->htSmpsvalue; pAddStaParams->send_smps_action = psessionEntry->send_smps_action; /* For Self STA get the LDPC capability from session i.e config.ini */ pAddStaParams->htLdpcCapable = (psessionEntry->txLdpcIniFeatureEnabled & 0x01); pAddStaParams->vhtLdpcCapable = ((psessionEntry->txLdpcIniFeatureEnabled >> 1) & 0x01); if (wlan_cfg_get_int(pMac, WNI_CFG_LISTEN_INTERVAL, &listenInterval) != QDF_STATUS_SUCCESS) pe_err("Couldn't get LISTEN_INTERVAL"); pAddStaParams->listenInterval = (uint16_t) listenInterval; if (QDF_P2P_CLIENT_MODE == psessionEntry->pePersona) { pAddStaParams->p2pCapableSta = 1; } pe_debug(" StaIdx: %d updateSta = %d htcapable = %d ", pAddStaParams->staIdx, pAddStaParams->updateSta, pAddStaParams->htCapable); pe_debug("htLdpcCapable: %d vhtLdpcCapable: %d " "p2pCapableSta: %d", pAddStaParams->htLdpcCapable, pAddStaParams->vhtLdpcCapable, pAddStaParams->p2pCapableSta); if (psessionEntry->isNonRoamReassoc) { pAddStaParams->nonRoamReassoc = 1; psessionEntry->isNonRoamReassoc = 0; } pe_debug("sessionid: %d Assoc ID: %d listenInterval = %d " "shortPreambleSupported: %d", psessionEntry->smeSessionId, pAddStaParams->assocId, pAddStaParams->listenInterval, pAddStaParams->shortPreambleSupported); if (IS_DOT11_MODE_HE(selfStaDot11Mode)) lim_add_self_he_cap(pAddStaParams, psessionEntry); msgQ.type = WMA_ADD_STA_REQ; msgQ.reserved = 0; msgQ.bodyptr = pAddStaParams; msgQ.bodyval = 0; pe_debug(MAC_ADDRESS_STR ":Sessionid %d : " "Sending WMA_ADD_STA_REQ. (aid %d)", MAC_ADDR_ARRAY(pAddStaParams->staMac), pAddStaParams->sessionId, pAddStaParams->assocId); MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); retCode = wma_post_ctrl_msg(pMac, &msgQ); if (QDF_STATUS_SUCCESS != retCode) { pe_err("Posting WMA_ADD_STA_REQ to HAL failed, reason=%X", retCode); qdf_mem_free(pAddStaParams); } return retCode; } /** * limTeardownInfraBSS() * ***FUNCTION: * This function is called by various LIM functions to teardown * an established Infrastructure BSS * ***LOGIC: * ***ASSUMPTIONS: * ***NOTE: * * @param pMac - Pointer to Global MAC structure * @return None */ void lim_teardown_infra_bss(tpAniSirGlobal pMac, tpPESession psessionEntry) { tSirMacAddr bcAddr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; /** * Send Broadcast Disassociate frame with * 'leaving BSS' reason. */ lim_send_disassoc_mgmt_frame(pMac, eSIR_MAC_DISASSOC_LEAVING_BSS_REASON, bcAddr, psessionEntry, false); } /*** end lim_teardown_infra_bss() ***/ /** * lim_handle_cnf_wait_timeout() * ***FUNCTION: * This function is called by limProcessMessageQueue to handle * various confirmation failure cases. * ***LOGIC: * ***ASSUMPTIONS: * ***NOTE: * * @param pMac - Pointer to Global MAC structure * @param pStaDs - Pointer to a sta descriptor * @return None */ void lim_handle_cnf_wait_timeout(tpAniSirGlobal pMac, uint16_t staId) { tpDphHashNode pStaDs; tpPESession psessionEntry = NULL; psessionEntry = pe_find_session_by_session_id(pMac, pMac->lim.limTimers.gpLimCnfWaitTimer[staId].sessionId); if (psessionEntry == NULL) { pe_err("Session Does not exist for given sessionID"); return; } pStaDs = dph_get_hash_entry(pMac, staId, &psessionEntry->dph.dphHashTable); if (pStaDs == NULL) { pe_err("No STA context in SIR_LIM_CNF_WAIT_TIMEOUT"); return; } switch (pStaDs->mlmStaContext.mlmState) { case eLIM_MLM_WT_ASSOC_CNF_STATE: pe_debug("Did not receive Assoc Cnf in eLIM_MLM_WT_ASSOC_CNF_STATE sta Assoc id %d", pStaDs->assocId); lim_print_mac_addr(pMac, pStaDs->staAddr, LOGD); if (LIM_IS_AP_ROLE(psessionEntry)) { lim_reject_association(pMac, pStaDs->staAddr, pStaDs->mlmStaContext.subType, true, pStaDs->mlmStaContext.authType, pStaDs->assocId, true, eSIR_MAC_UNSPEC_FAILURE_STATUS, psessionEntry); } break; default: pe_warn("Received CNF_WAIT_TIMEOUT in state %d", pStaDs->mlmStaContext.mlmState); } } /** * lim_delete_dph_hash_entry()- function to delete dph hash entry * @mac_ctx: pointer to global mac structure * @sta_addr: peer station address * @sta_id: id assigned to peer station * @session_entry: pe session entry * * This function is called whenever we need to delete * the dph hash entry * * Return: none */ void lim_delete_dph_hash_entry(tpAniSirGlobal mac_ctx, tSirMacAddr sta_addr, uint16_t sta_id, tpPESession session_entry) { uint16_t aid; tpDphHashNode sta_ds; tUpdateBeaconParams beacon_params; qdf_mem_zero(&beacon_params, sizeof(tUpdateBeaconParams)); beacon_params.paramChangeBitmap = 0; lim_deactivate_and_change_per_sta_id_timer(mac_ctx, eLIM_CNF_WAIT_TIMER, sta_id); if (NULL == session_entry) { pe_err("NULL session_entry"); return; } beacon_params.bssIdx = session_entry->bssIdx; sta_ds = dph_lookup_hash_entry(mac_ctx, sta_addr, &aid, &session_entry->dph.dphHashTable); if (sta_ds == NULL) { pe_err("sta_ds is NULL"); return; } pe_debug("Deleting DPH Hash entry for STAID: %X", sta_id); /* * update the station count and perform associated actions * do this before deleting the dph hash entry */ lim_util_count_sta_del(mac_ctx, sta_ds, session_entry); if (LIM_IS_AP_ROLE(session_entry) || LIM_IS_IBSS_ROLE(session_entry)) { if (LIM_IS_AP_ROLE(session_entry)) { if (session_entry->gLimProtectionControl != WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) lim_decide_ap_protection_on_delete(mac_ctx, sta_ds, &beacon_params, session_entry); } if (sta_ds->non_ecsa_capable) { if (session_entry->lim_non_ecsa_cap_num == 0) { pe_debug("NonECSA sta 0, id %d is ecsa", sta_id); } else { session_entry->lim_non_ecsa_cap_num--; pe_debug("reducing the non ECSA num to %d", session_entry->lim_non_ecsa_cap_num); } } if (LIM_IS_IBSS_ROLE(session_entry)) lim_ibss_decide_protection_on_delete(mac_ctx, sta_ds, &beacon_params, session_entry); lim_decide_short_preamble(mac_ctx, sta_ds, &beacon_params, session_entry); lim_decide_short_slot(mac_ctx, sta_ds, &beacon_params, session_entry); /* Send message to HAL about beacon parameter change. */ pe_debug("param bitmap: %d", beacon_params.paramChangeBitmap); if (beacon_params.paramChangeBitmap && (false == mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running)) { sch_set_fixed_beacon_fields(mac_ctx, session_entry); lim_send_beacon_params(mac_ctx, &beacon_params, session_entry); } lim_obss_send_detection_cfg(mac_ctx, session_entry, false); #ifdef WLAN_FEATURE_11W if (sta_ds->rmfEnabled) { pe_debug("delete pmf timer sta-idx:%d assoc-id:%d", sta_ds->staIndex, sta_ds->assocId); tx_timer_delete(&sta_ds->pmfSaQueryTimer); } #endif } if (dph_delete_hash_entry(mac_ctx, sta_addr, sta_id, &session_entry->dph.dphHashTable) != QDF_STATUS_SUCCESS) pe_err("error deleting hash entry"); } /** * lim_check_and_announce_join_success()- function to check if the received * Beacon/Probe Response is from the BSS that we're attempting to join. * @mac: pointer to global mac structure * @beacon_probe_rsp: pointer to reveived beacon/probe response frame * @header: pointer to received management frame header * @session_entry: pe session entry * * This function is called upon receiving Beacon/Probe Response * frame in WT_JOIN_BEACON_STATE to check if the received * Beacon/Probe Response is from the BSS that we're attempting * to join. * If the Beacon/Probe Response is indeed from the BSS we're * attempting to join, join success is sent to SME. * * Return: none */ void lim_check_and_announce_join_success(tpAniSirGlobal mac_ctx, tSirProbeRespBeacon *beacon_probe_rsp, tpSirMacMgmtHdr header, tpPESession session_entry) { tSirMacSSid current_ssid; tLimMlmJoinCnf mlm_join_cnf; uint32_t val = 0; uint32_t *noa_duration_from_beacon = NULL; uint32_t *noa2_duration_from_beacon = NULL; uint32_t noa; uint32_t total_num_noa_desc = 0; qdf_mem_copy(current_ssid.ssId, session_entry->ssId.ssId, session_entry->ssId.length); current_ssid.length = (uint8_t) session_entry->ssId.length; /* * Check for SSID only in probe response. Beacons may not carry * SSID information in hidden SSID case */ if (((SIR_MAC_MGMT_FRAME == header->fc.type) && (SIR_MAC_MGMT_PROBE_RSP == header->fc.subType)) && current_ssid.length && (qdf_mem_cmp((uint8_t *) &beacon_probe_rsp->ssId, (uint8_t *) ¤t_ssid, (uint8_t) (1 + current_ssid.length)))) { /* * Received SSID does not match with the one we've. * Ignore received Beacon frame */ pe_debug("SSID received in Beacon does not match"); #ifdef WLAN_DEBUG mac_ctx->lim.gLimBcnSSIDMismatchCnt++; #endif return; } if (!LIM_IS_STA_ROLE(session_entry)) return; pe_debug("Received Beacon/PR with matching BSSID:%pM PESessionID %d", session_entry->bssId, session_entry->peSessionId); /* Deactivate Join Failure timer */ lim_deactivate_and_change_timer(mac_ctx, eLIM_JOIN_FAIL_TIMER); /* Deactivate Periodic Join timer */ lim_deactivate_and_change_timer(mac_ctx, eLIM_PERIODIC_JOIN_PROBE_REQ_TIMER); if (QDF_P2P_CLIENT_MODE == session_entry->pePersona && beacon_probe_rsp->P2PProbeRes.NoticeOfAbsence.present) { noa_duration_from_beacon = (uint32_t *) (beacon_probe_rsp->P2PProbeRes.NoticeOfAbsence.NoADesc + 1); if (beacon_probe_rsp->P2PProbeRes.NoticeOfAbsence.num_NoADesc) total_num_noa_desc = beacon_probe_rsp->P2PProbeRes.NoticeOfAbsence. num_NoADesc / SIZE_OF_NOA_DESCRIPTOR; noa = *noa_duration_from_beacon; if (total_num_noa_desc > 1) { noa2_duration_from_beacon = (uint32_t *) (beacon_probe_rsp->P2PProbeRes.NoticeOfAbsence.NoADesc + SIZE_OF_NOA_DESCRIPTOR + 1); noa += *noa2_duration_from_beacon; } /* * If MAX Noa exceeds 3 secs we will consider only 3 secs to * avoid arbitrary values in noa duration field */ noa = noa > MAX_NOA_PERIOD_IN_MICROSECS ? MAX_NOA_PERIOD_IN_MICROSECS : noa; noa = noa / 1000; /* Convert to ms */ if (wlan_cfg_get_int(mac_ctx, WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, &val) == QDF_STATUS_SUCCESS) { session_entry->defaultAuthFailureTimeout = val; cfg_set_int(mac_ctx, WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, val + noa); } } else { session_entry->defaultAuthFailureTimeout = 0; } /* * Check if MBO Association disallowed subattr is present and post * failure status to LIM if present */ if (!session_entry->ignore_assoc_disallowed && beacon_probe_rsp->assoc_disallowed) { pe_err("Connection fails due to assoc disallowed reason(%d):%pM PESessionID %d", beacon_probe_rsp->assoc_disallowed_reason, session_entry->bssId, session_entry->peSessionId); mlm_join_cnf.resultCode = eSIR_SME_ASSOC_REFUSED; mlm_join_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; session_entry->limMlmState = eLIM_MLM_IDLE_STATE; mlm_join_cnf.sessionId = session_entry->peSessionId; if (session_entry->pLimMlmJoinReq) { qdf_mem_free(session_entry->pLimMlmJoinReq); session_entry->pLimMlmJoinReq = NULL; } lim_post_sme_message(mac_ctx, LIM_MLM_JOIN_CNF, (uint32_t *) &mlm_join_cnf); return; } /* Update Beacon Interval at CFG database */ if (beacon_probe_rsp->HTCaps.present) lim_update_sta_run_time_ht_capability(mac_ctx, &beacon_probe_rsp->HTCaps); if (beacon_probe_rsp->HTInfo.present) lim_update_sta_run_time_ht_info(mac_ctx, &beacon_probe_rsp->HTInfo, session_entry); session_entry->limMlmState = eLIM_MLM_JOINED_STATE; MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, session_entry->peSessionId, eLIM_MLM_JOINED_STATE)); /* * update the capability info based on recently received beacon/probe * response frame */ session_entry->limCurrentBssCaps = lim_get_u16((uint8_t *)&beacon_probe_rsp->capabilityInfo); /* * Announce join success by sending * Join confirm to SME. */ mlm_join_cnf.resultCode = eSIR_SME_SUCCESS; mlm_join_cnf.protStatusCode = eSIR_MAC_SUCCESS_STATUS; /* Update PE sessionId */ mlm_join_cnf.sessionId = session_entry->peSessionId; lim_post_sme_message(mac_ctx, LIM_MLM_JOIN_CNF, (uint32_t *) &mlm_join_cnf); if ((IS_DOT11_MODE_VHT(session_entry->dot11mode)) && beacon_probe_rsp->vendor_vht_ie.VHTCaps.present) { session_entry->is_vendor_specific_vhtcaps = true; session_entry->vendor_specific_vht_ie_sub_type = beacon_probe_rsp->vendor_vht_ie.sub_type; pe_debug("VHT caps are present in vendor specific IE"); } /* Update HS 2.0 Information Element */ if (beacon_probe_rsp->hs20vendor_ie.present) { pe_debug("HS20 Indication Element Present, rel#:%u, id:%u", beacon_probe_rsp->hs20vendor_ie.release_num, beacon_probe_rsp->hs20vendor_ie.hs_id_present); qdf_mem_copy(&session_entry->hs20vendor_ie, &beacon_probe_rsp->hs20vendor_ie, sizeof(tDot11fIEhs20vendor_ie) - sizeof(beacon_probe_rsp->hs20vendor_ie.hs_id)); if (beacon_probe_rsp->hs20vendor_ie.hs_id_present) qdf_mem_copy(&session_entry->hs20vendor_ie.hs_id, &beacon_probe_rsp->hs20vendor_ie.hs_id, sizeof(beacon_probe_rsp->hs20vendor_ie.hs_id)); } } /** * lim_extract_ap_capabilities() * ***FUNCTION: * This function is called to extract all of the AP's capabilities * from the IEs received from it in Beacon/Probe Response frames * ***LOGIC: * This routine mimics the lim_extract_ap_capability() API. The difference here * is that this API returns the entire tSirProbeRespBeacon info as is. It is * left to the caller of this API to use this info as required * ***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 beaconStruct A pointer to tSirProbeRespBeacon that needs to be * populated * @return status A status reporting QDF_STATUS_SUCCESS or QDF_STATUS_E_FAILURE */ QDF_STATUS lim_extract_ap_capabilities(tpAniSirGlobal pMac, uint8_t *pIE, uint16_t ieLen, tpSirProbeRespBeacon beaconStruct) { qdf_mem_zero((uint8_t *) beaconStruct, sizeof(tSirProbeRespBeacon)); pe_debug("lim_extract_ap_capabilities: The IE's being received are:"); QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, pIE, ieLen); /* Parse the Beacon IE's, Don't try to parse if we dont have anything in IE */ if (ieLen > 0) { if (QDF_STATUS_SUCCESS != sir_parse_beacon_ie(pMac, beaconStruct, pIE, (uint32_t) ieLen)) { pe_err("APCapExtract: Beacon parsing error!"); return QDF_STATUS_E_FAILURE; } } return QDF_STATUS_SUCCESS; } /** * lim_del_bss() * ***FUNCTION: * This function is called to delete BSS context at hardware * whenever a STA is disassociated * ***LOGIC: * ***ASSUMPTIONS: * NA * ***NOTE: * NA * * @param pMac - Pointer to Global MAC structure * @param pStaDs - Pointer to the STA datastructure created by * LIM and maintained by DPH * @return retCode - Indicates success or failure return code */ QDF_STATUS lim_del_bss(tpAniSirGlobal pMac, tpDphHashNode pStaDs, uint16_t bssIdx, tpPESession psessionEntry) { tpDeleteBssParams pDelBssParams = NULL; struct scheduler_msg msgQ = {0}; QDF_STATUS retCode = QDF_STATUS_SUCCESS; pDelBssParams = qdf_mem_malloc(sizeof(tDeleteBssParams)); if (NULL == pDelBssParams) { pe_err("Unable to allocate memory during ADD_BSS"); return QDF_STATUS_E_NOMEM; } pDelBssParams->sessionId = psessionEntry->peSessionId; /* update PE session Id */ /* DPH was storing the AssocID in staID field, */ /* staID is actually assigned by HAL when AddSTA message is sent. */ if (pStaDs != NULL) { pDelBssParams->bssIdx = pStaDs->bssId; pStaDs->valid = 0; pStaDs->mlmStaContext.mlmState = eLIM_MLM_WT_DEL_BSS_RSP_STATE; } else pDelBssParams->bssIdx = bssIdx; psessionEntry->limMlmState = eLIM_MLM_WT_DEL_BSS_RSP_STATE; MTRACE(mac_trace (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, eLIM_MLM_WT_DEL_BSS_RSP_STATE)); if ((psessionEntry->peSessionId == pMac->lim.limTimers.gLimJoinFailureTimer.sessionId) && (true == tx_timer_running(&pMac->lim.limTimers.gLimJoinFailureTimer))) { lim_deactivate_and_change_timer(pMac, eLIM_JOIN_FAIL_TIMER); } pDelBssParams->status = QDF_STATUS_SUCCESS; pDelBssParams->respReqd = 1; qdf_mem_copy(pDelBssParams->bssid, psessionEntry->bssId, sizeof(tSirMacAddr)); pDelBssParams->smesessionId = psessionEntry->smeSessionId; pe_debug("Sessionid %d : Sending HAL_DELETE_BSS_REQ " "for bss idx: %X BSSID:" MAC_ADDRESS_STR, pDelBssParams->sessionId, pDelBssParams->bssIdx, MAC_ADDR_ARRAY(psessionEntry->bssId)); /* we need to defer the message until we get the response back from HAL. */ SET_LIM_PROCESS_DEFD_MESGS(pMac, false); pe_debug("process_ho_fail = %d", psessionEntry->process_ho_fail); if (psessionEntry->process_ho_fail) msgQ.type = WMA_DELETE_BSS_HO_FAIL_REQ; else msgQ.type = WMA_DELETE_BSS_REQ; msgQ.reserved = 0; msgQ.bodyptr = pDelBssParams; msgQ.bodyval = 0; MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); retCode = wma_post_ctrl_msg(pMac, &msgQ); if (QDF_STATUS_SUCCESS != retCode) { SET_LIM_PROCESS_DEFD_MESGS(pMac, true); pe_err("Posting DELETE_BSS_REQ to HAL failed, reason=%X", retCode); qdf_mem_free(pDelBssParams); } return retCode; } /** * lim_update_vhtcaps_assoc_resp : Update VHT caps in assoc response. * @mac_ctx Pointer to Global MAC structure * @pAddBssParams: parameters required for add bss params. * @vht_caps: VHT capabilities. * @psessionEntry : session entry. * * Return : void */ static void lim_update_vhtcaps_assoc_resp(tpAniSirGlobal mac_ctx, tpAddBssParams pAddBssParams, tDot11fIEVHTCaps *vht_caps, tpPESession psessionEntry) { pAddBssParams->staContext.vht_caps = ((vht_caps->maxMPDULen << SIR_MAC_VHT_CAP_MAX_MPDU_LEN) | (vht_caps->supportedChannelWidthSet << SIR_MAC_VHT_CAP_SUPP_CH_WIDTH_SET) | (vht_caps->ldpcCodingCap << SIR_MAC_VHT_CAP_LDPC_CODING_CAP) | (vht_caps->shortGI80MHz << SIR_MAC_VHT_CAP_SHORTGI_80MHZ) | (vht_caps->shortGI160and80plus80MHz << SIR_MAC_VHT_CAP_SHORTGI_160_80_80MHZ) | (vht_caps->txSTBC << SIR_MAC_VHT_CAP_TXSTBC) | (vht_caps->rxSTBC << SIR_MAC_VHT_CAP_RXSTBC) | (vht_caps->suBeamFormerCap << SIR_MAC_VHT_CAP_SU_BEAMFORMER_CAP) | (vht_caps->suBeamformeeCap << SIR_MAC_VHT_CAP_SU_BEAMFORMEE_CAP) | (vht_caps->csnofBeamformerAntSup << SIR_MAC_VHT_CAP_CSN_BEAMORMER_ANT_SUP) | (vht_caps->numSoundingDim << SIR_MAC_VHT_CAP_NUM_SOUNDING_DIM) | (vht_caps->muBeamformerCap << SIR_MAC_VHT_CAP_NUM_BEAM_FORMER_CAP) | (vht_caps->muBeamformeeCap << SIR_MAC_VHT_CAP_NUM_BEAM_FORMEE_CAP) | (vht_caps->vhtTXOPPS << SIR_MAC_VHT_CAP_TXOPPS) | (vht_caps->htcVHTCap << SIR_MAC_VHT_CAP_HTC_CAP) | (vht_caps->maxAMPDULenExp << SIR_MAC_VHT_CAP_MAX_AMDU_LEN_EXPO) | (vht_caps->vhtLinkAdaptCap << SIR_MAC_VHT_CAP_LINK_ADAPT_CAP) | (vht_caps->rxAntPattern << SIR_MAC_VHT_CAP_RX_ANTENNA_PATTERN) | (vht_caps->txAntPattern << SIR_MAC_VHT_CAP_TX_ANTENNA_PATTERN) | (vht_caps->reserved1 << SIR_MAC_VHT_CAP_RESERVED2)); pAddBssParams->staContext.maxAmpduSize = SIR_MAC_GET_VHT_MAX_AMPDU_EXPO( pAddBssParams->staContext.vht_caps); pe_debug("Updating VHT caps in assoc Response"); } /** * lim_update_vht_oper_assoc_resp : Update VHT Operations in assoc response. * @mac_ctx Pointer to Global MAC structure * @pAddBssParams: parameters required for add bss params. * @vht_oper: VHT Operations to update. * @psessionEntry : session entry. * * Return : void */ static void lim_update_vht_oper_assoc_resp(tpAniSirGlobal mac_ctx, tpAddBssParams pAddBssParams, tDot11fIEVHTOperation *vht_oper, tpPESession psessionEntry) { if (vht_oper->chanWidth && psessionEntry->ch_width) { pAddBssParams->ch_width = vht_oper->chanWidth + 1; pAddBssParams->ch_center_freq_seg0 = vht_oper->chanCenterFreqSeg1; pAddBssParams->ch_center_freq_seg1 = vht_oper->chanCenterFreqSeg2; } pe_debug("Updating VHT Operation in assoc Response"); } #ifdef WLAN_SUPPORT_TWT /** * lim_set_sta_ctx_twt() - Save the TWT settings in STA context * @sta_ctx: Pointer to Station Context * @session: Pointer to PE session * * Return: None */ static void lim_set_sta_ctx_twt(tAddStaParams *sta_ctx, tpPESession session) { sta_ctx->twt_requestor = session->peer_twt_requestor; sta_ctx->twt_responder = session->peer_twt_responder; } #else static inline void lim_set_sta_ctx_twt(tAddStaParams *sta_ctx, tpPESession session) { } #endif /** * limSendAddBss() * ***FUNCTION: * ***LOGIC: * 1) LIM receives eWNI_SME_JOIN_REQ * 2) For a valid eWNI_SME_JOIN_REQ, LIM sends * SIR_HAL_ADD_BSS_REQ to HAL * ***ASSUMPTIONS: * JOIN REQ parameters are saved in pMac->lim.gLimMlmJoinReq * ADD BSS parameters can be obtained from two sources: * 1) pMac->lim.gLimMlmJoinReq * 2) beaconStruct, passed as parameter * So, if a reqd parameter is found in bssDescriptions * then it is given preference over beaconStruct * ***NOTE: * * @param pMac Pointer to Global MAC structure * pAssocRsp contains the structured assoc/reassoc Response got from AP * beaconstruct Has the ProbeRsp/Beacon structured details * bssDescription bssDescription passed to PE from the SME * @return None */ QDF_STATUS lim_sta_send_add_bss(tpAniSirGlobal pMac, tpSirAssocRsp pAssocRsp, tpSchBeaconStruct pBeaconStruct, tpSirBssDescription bssDescription, uint8_t updateEntry, tpPESession psessionEntry) { struct scheduler_msg msgQ = {0}; tpAddBssParams pAddBssParams = NULL; uint32_t retCode; tpDphHashNode pStaDs = NULL; uint8_t chanWidthSupp = 0; bool is_vht_cap_in_vendor_ie = false; uint32_t enableTxBF20MHz; tDot11fIEVHTCaps *vht_caps = NULL; tDot11fIEVHTOperation *vht_oper = NULL; tAddStaParams *sta_context; uint32_t listen_interval = WNI_CFG_LISTEN_INTERVAL_STADEF; /* Package SIR_HAL_ADD_BSS_REQ message parameters */ pAddBssParams = qdf_mem_malloc(sizeof(tAddBssParams)); if (NULL == pAddBssParams) { pe_err("Unable to allocate memory during ADD_BSS"); retCode = QDF_STATUS_E_NOMEM; goto returnFailure; } qdf_mem_copy(pAddBssParams->bssId, bssDescription->bssId, sizeof(tSirMacAddr)); /* Fill in tAddBssParams selfMacAddr */ qdf_mem_copy(pAddBssParams->selfMacAddr, psessionEntry->selfMacAddr, sizeof(tSirMacAddr)); pe_debug("sessionid: %d updateEntry: %d limsystemrole: %d", psessionEntry->smeSessionId, updateEntry, GET_LIM_SYSTEM_ROLE(psessionEntry)); pe_debug("BSSID: " MAC_ADDRESS_STR, MAC_ADDR_ARRAY(pAddBssParams->bssId)); pAddBssParams->bssType = eSIR_INFRASTRUCTURE_MODE; pAddBssParams->operMode = BSS_OPERATIONAL_MODE_STA; /* Update PE session ID */ pAddBssParams->sessionId = psessionEntry->peSessionId; pAddBssParams->beaconInterval = bssDescription->beaconInterval; pAddBssParams->dtimPeriod = pBeaconStruct->tim.dtimPeriod; pAddBssParams->updateBss = updateEntry; pAddBssParams->cfParamSet.cfpCount = pBeaconStruct->cfParamSet.cfpCount; pAddBssParams->cfParamSet.cfpPeriod = pBeaconStruct->cfParamSet.cfpPeriod; pAddBssParams->cfParamSet.cfpMaxDuration = pBeaconStruct->cfParamSet.cfpMaxDuration; pAddBssParams->cfParamSet.cfpDurRemaining = pBeaconStruct->cfParamSet.cfpDurRemaining; pAddBssParams->rateSet.numRates = pAssocRsp->supportedRates.numRates; qdf_mem_copy(pAddBssParams->rateSet.rate, pAssocRsp->supportedRates.rate, pAssocRsp->supportedRates.numRates); if (IS_DOT11_MODE_11B(psessionEntry->dot11mode) && bssDescription->nwType != eSIR_11B_NW_TYPE) { pAddBssParams->nwType = eSIR_11B_NW_TYPE; } else { pAddBssParams->nwType = bssDescription->nwType; } pAddBssParams->shortSlotTimeSupported = (uint8_t) pAssocRsp->capabilityInfo.shortSlotTime; pAddBssParams->llaCoexist = (uint8_t) psessionEntry->beaconParams.llaCoexist; pAddBssParams->llbCoexist = (uint8_t) psessionEntry->beaconParams.llbCoexist; pAddBssParams->llgCoexist = (uint8_t) psessionEntry->beaconParams.llgCoexist; pAddBssParams->ht20Coexist = (uint8_t) psessionEntry->beaconParams.ht20Coexist; pe_debug("BSS Type %d Beacon Interval: %d dtimPeriod: %d " "cfpCount: %d", pAddBssParams->bssType, pAddBssParams->beaconInterval, pAddBssParams->dtimPeriod, pAddBssParams->cfParamSet.cfpCount); pe_debug("cfpPeriod: %d cfpMaxDuration: %d cfpDurRemaining: %d " "numRates: %d", pAddBssParams->cfParamSet.cfpPeriod, pAddBssParams->cfParamSet.cfpMaxDuration, pAddBssParams->cfParamSet.cfpDurRemaining, pAddBssParams->rateSet.numRates); pe_debug("nwType:%d shortSlotTimeSupported: %d llaCoexist: %d " "llbCoexist: %d llgCoexist: %d ht20Coexist: %d", pAddBssParams->nwType, pAddBssParams->shortSlotTimeSupported, pAddBssParams->llaCoexist, pAddBssParams->llbCoexist, pAddBssParams->llgCoexist, pAddBssParams->ht20Coexist); pAddBssParams->dot11_mode = psessionEntry->dot11mode; pe_debug("dot11_mode: %d", pAddBssParams->dot11_mode); if (IS_DOT11_MODE_HT(psessionEntry->dot11mode)) chanWidthSupp = lim_get_ht_capability(pMac, eHT_SUPPORTED_CHANNEL_WIDTH_SET, psessionEntry); /* Use the advertised capabilities from the received beacon/PR */ if (IS_DOT11_MODE_HT(psessionEntry->dot11mode) && (pAssocRsp->HTCaps.present)) { pAddBssParams->htCapable = pAssocRsp->HTCaps.present; pe_debug("htCapable: %d", pAddBssParams->htCapable); if (pBeaconStruct->HTInfo.present) { pAddBssParams->htOperMode = (tSirMacHTOperatingMode) pAssocRsp->HTInfo.opMode; pAddBssParams->dualCTSProtection = (uint8_t) pAssocRsp->HTInfo.dualCTSProtection; if ((pAssocRsp->HTCaps.supportedChannelWidthSet) && (chanWidthSupp)) { pAddBssParams->ch_width = (uint8_t) pAssocRsp->HTInfo.recommendedTxWidthSet; if (pAssocRsp->HTInfo.secondaryChannelOffset == PHY_DOUBLE_CHANNEL_LOW_PRIMARY) pAddBssParams->ch_center_freq_seg0 = bssDescription->channelId + 2; else if (pAssocRsp->HTInfo.secondaryChannelOffset == PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) pAddBssParams->ch_center_freq_seg0 = bssDescription->channelId - 2; } else { pAddBssParams->ch_width = CH_WIDTH_20MHZ; pAddBssParams->ch_center_freq_seg0 = 0; } pAddBssParams->llnNonGFCoexist = (uint8_t) pAssocRsp->HTInfo.nonGFDevicesPresent; pAddBssParams->fLsigTXOPProtectionFullSupport = (uint8_t) pAssocRsp->HTInfo. lsigTXOPProtectionFullSupport; pAddBssParams->fRIFSMode = pAssocRsp->HTInfo.rifsMode; pe_debug("htOperMode: %d dualCTSProtection: %d txChannelWidth: %d center_freq_0: %d", pAddBssParams->htOperMode, pAddBssParams->dualCTSProtection, pAddBssParams->ch_width, pAddBssParams->ch_center_freq_seg0); pe_debug("llnNonGFCoexist: %d " "fLsigTXOPProtectionFullSupport: %d fRIFSMode %d", pAddBssParams->llnNonGFCoexist, pAddBssParams->fLsigTXOPProtectionFullSupport, pAddBssParams->fRIFSMode); } } pAddBssParams->currentOperChannel = bssDescription->channelId; pe_debug("currentOperChannel %d", pAddBssParams->currentOperChannel); if (psessionEntry->vhtCapability && (pAssocRsp->VHTCaps.present)) { pAddBssParams->vhtCapable = pAssocRsp->VHTCaps.present; vht_caps = &pAssocRsp->VHTCaps; vht_oper = &pAssocRsp->VHTOperation; } else if (psessionEntry->vhtCapability && pAssocRsp->vendor_vht_ie.VHTCaps.present){ pAddBssParams->vhtCapable = pAssocRsp->vendor_vht_ie.VHTCaps.present; pe_debug("VHT Caps and Operation are present in vendor Specific IE"); vht_caps = &pAssocRsp->vendor_vht_ie.VHTCaps; vht_oper = &pAssocRsp->vendor_vht_ie.VHTOperation; } else { pAddBssParams->vhtCapable = 0; } if (pAddBssParams->vhtCapable) { if (vht_oper != NULL) lim_update_vht_oper_assoc_resp(pMac, pAddBssParams, vht_oper, psessionEntry); if (vht_caps != NULL) lim_update_vhtcaps_assoc_resp(pMac, pAddBssParams, vht_caps, psessionEntry); } pe_debug("vhtCapable %d TxChannelWidth %d center_freq_0 %d center_freq_1 %d", pAddBssParams->vhtCapable, pAddBssParams->ch_width, pAddBssParams->ch_center_freq_seg0, pAddBssParams->ch_center_freq_seg1); if (lim_is_session_he_capable(psessionEntry) && (pAssocRsp->he_cap.present)) { lim_add_bss_he_cap(pAddBssParams, pAssocRsp); lim_add_bss_he_cfg(pAddBssParams, psessionEntry); } /* * Populate the STA-related parameters here * Note that the STA here refers to the AP * staType = PEER */ sta_context = &pAddBssParams->staContext; /* Identifying AP as an STA */ pAddBssParams->staContext.staType = STA_ENTRY_OTHER; qdf_mem_copy(pAddBssParams->staContext.bssId, bssDescription->bssId, sizeof(tSirMacAddr)); if (wlan_cfg_get_int(pMac, WNI_CFG_LISTEN_INTERVAL, &listen_interval) != QDF_STATUS_SUCCESS) pe_err("Couldn't get LISTEN_INTERVAL"); pAddBssParams->staContext.listenInterval = listen_interval; /* Fill Assoc id from the dph table */ pStaDs = dph_lookup_hash_entry(pMac, pAddBssParams->staContext.bssId, &pAddBssParams->staContext.assocId, &psessionEntry->dph.dphHashTable); if (pStaDs == NULL) { pe_err("Couldn't get assoc id for " "MAC ADDR: " MAC_ADDRESS_STR, MAC_ADDR_ARRAY( pAddBssParams->staContext.staMac)); return QDF_STATUS_E_FAILURE; } pAddBssParams->staContext.uAPSD = psessionEntry->gUapsdPerAcBitmask; pAddBssParams->staContext.maxSPLen = 0; pAddBssParams->staContext.shortPreambleSupported = (uint8_t) pAssocRsp->capabilityInfo.shortPreamble; pAddBssParams->staContext.updateSta = updateEntry; pe_debug("StaContext: " MAC_ADDRESS_STR " shortPreambleSupported: %d", MAC_ADDR_ARRAY(pAddBssParams->staContext.staMac), pAddBssParams->staContext.shortPreambleSupported); if (IS_DOT11_MODE_HT(psessionEntry->dot11mode) && pBeaconStruct->HTCaps.present) { pAddBssParams->staContext.us32MaxAmpduDuration = 0; pAddBssParams->staContext.htCapable = 1; pAddBssParams->staContext.greenFieldCapable = (uint8_t) pAssocRsp->HTCaps.greenField; pAddBssParams->staContext.lsigTxopProtection = (uint8_t) pAssocRsp->HTCaps.lsigTXOPProtection; pe_debug("StaCtx: htCap %d GFcap %d lsigTxopProtn %d", pAddBssParams->staContext.htCapable, pAddBssParams->staContext.greenFieldCapable, pAddBssParams->staContext.lsigTxopProtection); if (psessionEntry->htConfig.ht_tx_stbc) pAddBssParams->staContext.stbc_capable = pAssocRsp->HTCaps.rxSTBC; if (psessionEntry->vhtCapability && (IS_BSS_VHT_CAPABLE(pBeaconStruct->VHTCaps) || IS_BSS_VHT_CAPABLE(pBeaconStruct-> vendor_vht_ie.VHTCaps))) { pAddBssParams->staContext.vhtCapable = 1; pAddBssParams->staContext.vhtSupportedRxNss = pStaDs->vhtSupportedRxNss; if (pAssocRsp->VHTCaps.present) vht_caps = &pAssocRsp->VHTCaps; else if (pAssocRsp->vendor_vht_ie.VHTCaps.present) { vht_caps = &pAssocRsp->vendor_vht_ie.VHTCaps; pe_debug("VHT Caps are in vendor Specific IE"); is_vht_cap_in_vendor_ie = true; } if ((vht_caps != NULL) && (vht_caps->suBeamFormerCap || vht_caps->muBeamformerCap) && psessionEntry->vht_config.su_beam_formee) sta_context->vhtTxBFCapable = 1; if ((vht_caps != NULL) && vht_caps->muBeamformerCap && psessionEntry->vht_config.mu_beam_formee) sta_context->vhtTxMUBformeeCapable = 1; if ((vht_caps != NULL) && vht_caps->suBeamformeeCap && psessionEntry->vht_config.su_beam_former) sta_context->enable_su_tx_bformer = 1; if (vht_caps && pAddBssParams->staContext.stbc_capable) pAddBssParams->staContext.stbc_capable = vht_caps->rxSTBC; } if (lim_is_session_he_capable(psessionEntry) && pAssocRsp->he_cap.present) { lim_intersect_ap_he_caps(psessionEntry, pAddBssParams, NULL, pAssocRsp); lim_update_he_stbc_capable(&pAddBssParams->staContext); } /* * in limExtractApCapability function intersection of FW * advertised channel width and AP advertised channel * width has been taken into account for calculating * psessionEntry->ch_width */ if (chanWidthSupp && ((pAssocRsp->HTCaps.supportedChannelWidthSet) || (pBeaconStruct->HTCaps.supportedChannelWidthSet))) { pAddBssParams->staContext.ch_width = psessionEntry->ch_width; } else { sta_context->ch_width = CH_WIDTH_20MHZ; if ((QDF_IS_STATUS_SUCCESS( wlan_cfg_get_int(pMac, WNI_CFG_VHT_ENABLE_TXBF_20MHZ, &enableTxBF20MHz))) && (false == enableTxBF20MHz)) sta_context->vhtTxBFCapable = 0; } pe_debug("StaCtx: vhtCap %d ChBW %d TxBF %d", pAddBssParams->staContext.vhtCapable, pAddBssParams->staContext.ch_width, sta_context->vhtTxBFCapable); pe_debug("StaContext su_tx_bfer %d", sta_context->enable_su_tx_bformer); pAddBssParams->staContext.mimoPS = (tSirMacHTMIMOPowerSaveState) pAssocRsp->HTCaps.mimoPowerSave; pAddBssParams->staContext.maxAmsduSize = (uint8_t) pAssocRsp->HTCaps.maximalAMSDUsize; pAddBssParams->staContext.maxAmpduDensity = pAssocRsp->HTCaps.mpduDensity; pAddBssParams->staContext.fDsssCckMode40Mhz = (uint8_t) pAssocRsp->HTCaps.dsssCckMode40MHz; /* * We will check gShortGI20Mhz and gShortGI40Mhz from * session entry if they are set then we will use what ever * Assoc response coming from AP supports. If these * values are set as 0 in session entry then we will * hardcode this values to 0. */ if (psessionEntry->htConfig.ht_sgi20) { pAddBssParams->staContext.fShortGI20Mhz = (uint8_t)pAssocRsp->HTCaps.shortGI20MHz; } else { pAddBssParams->staContext.fShortGI20Mhz = false; } if (psessionEntry->htConfig.ht_sgi40) { pAddBssParams->staContext.fShortGI40Mhz = (uint8_t) pAssocRsp->HTCaps.shortGI40MHz; } else { pAddBssParams->staContext.fShortGI40Mhz = false; } if (!pAddBssParams->staContext.vhtCapable) /* Use max ampd factor advertised in * HTCAP for non-vht connection */ { pAddBssParams->staContext.maxAmpduSize = pAssocRsp->HTCaps.maxRxAMPDUFactor; } else if (pAddBssParams->staContext.maxAmpduSize < pAssocRsp->HTCaps.maxRxAMPDUFactor) { pAddBssParams->staContext.maxAmpduSize = pAssocRsp->HTCaps.maxRxAMPDUFactor; } if (pAddBssParams->staContext.vhtTxBFCapable && pMac->lim.disableLDPCWithTxbfAP) { pAddBssParams->staContext.htLdpcCapable = 0; pAddBssParams->staContext.vhtLdpcCapable = 0; } else { if (psessionEntry->txLdpcIniFeatureEnabled & 0x1) pAddBssParams->staContext.htLdpcCapable = (uint8_t) pAssocRsp->HTCaps.advCodingCap; else pAddBssParams->staContext.htLdpcCapable = 0; if (pAssocRsp->VHTCaps.present) vht_caps = &pAssocRsp->VHTCaps; else if (pAssocRsp->vendor_vht_ie.VHTCaps.present) { vht_caps = &pAssocRsp->vendor_vht_ie.VHTCaps; pe_debug("VHT Caps is in vendor Specific IE"); } if (vht_caps != NULL && (psessionEntry->txLdpcIniFeatureEnabled & 0x2)) { if (!is_vht_cap_in_vendor_ie) pAddBssParams->staContext.vhtLdpcCapable = (uint8_t) pAssocRsp->VHTCaps.ldpcCodingCap; else pAddBssParams->staContext.vhtLdpcCapable = (uint8_t) vht_caps->ldpcCodingCap; } else { pAddBssParams->staContext.vhtLdpcCapable = 0; } } if (pBeaconStruct->HTInfo.present) pAddBssParams->staContext.rifsMode = pAssocRsp->HTInfo.rifsMode; pe_debug("StaCtx: ChBW %d mimoPS %d maxAmsduSize %d", pAddBssParams->staContext.ch_width, pAddBssParams->staContext.mimoPS, pAddBssParams->staContext.maxAmsduSize); pe_debug("maxAmpduDens %d CckMode40Mhz %d SGI20Mhz %d", pAddBssParams->staContext.maxAmpduDensity, pAddBssParams->staContext.fDsssCckMode40Mhz, pAddBssParams->staContext.fShortGI20Mhz); pe_debug("SGI40M %d maxAmpdu %d htLdpc %d vhtLdpc %d", pAddBssParams->staContext.fShortGI40Mhz, pAddBssParams->staContext.maxAmpduSize, pAddBssParams->staContext.htLdpcCapable, pAddBssParams->staContext.vhtLdpcCapable); } pAddBssParams->staContext.smesessionId = psessionEntry->smeSessionId; pAddBssParams->staContext.wpa_rsn = pBeaconStruct->rsnPresent; pAddBssParams->staContext.wpa_rsn |= (pBeaconStruct->wpaPresent << 1); /* For OSEN Connection AP does not advertise RSN or WPA IE * so from the IEs we get from supplicant we get this info * so for FW to transmit EAPOL message 4 we shall set * wpa_rsn */ if ((!pAddBssParams->staContext.wpa_rsn) && (psessionEntry->isOSENConnection)) pAddBssParams->staContext.wpa_rsn = 1; qdf_mem_copy(&pAddBssParams->staContext.capab_info, &pAssocRsp->capabilityInfo, sizeof(pAddBssParams->staContext.capab_info)); qdf_mem_copy(&pAddBssParams->staContext.ht_caps, (uint8_t *) &pAssocRsp->HTCaps + sizeof(uint8_t), sizeof(pAddBssParams->staContext.ht_caps)); /* If WMM IE or 802.11E IE is present then enable WMM */ if ((psessionEntry->limWmeEnabled && pAssocRsp->wmeEdcaPresent) || (psessionEntry->limQosEnabled && pAssocRsp->edcaPresent)) pAddBssParams->staContext.wmmEnabled = 1; else pAddBssParams->staContext.wmmEnabled = 0; /* Update the rates */ pStaDs = dph_get_hash_entry(pMac, DPH_STA_HASH_INDEX_PEER, &psessionEntry->dph.dphHashTable); if (pStaDs != NULL) { qdf_mem_copy((uint8_t *) &pAddBssParams->staContext. supportedRates, (uint8_t *)&pStaDs->supportedRates, sizeof(tSirSupportedRates)); } else pe_err("could not Update the supported rates"); pAddBssParams->staContext.encryptType = psessionEntry->encryptType; pAddBssParams->maxTxPower = psessionEntry->maxTxPower; pe_debug("maxTxPower: %d", pAddBssParams->maxTxPower); /* FIXME_GEN4 - Any other value that can be used for initialization? */ pAddBssParams->status = QDF_STATUS_SUCCESS; pAddBssParams->respReqd = true; /* update persona */ pAddBssParams->halPersona = (uint8_t) psessionEntry->pePersona; if (QDF_P2P_CLIENT_MODE == psessionEntry->pePersona) pAddBssParams->staContext.p2pCapableSta = 1; pAddBssParams->bSpectrumMgtEnabled = psessionEntry->spectrumMgtEnabled; pAddBssParams->extSetStaKeyParamValid = 0; pe_debug("extSetStaKeyParamValid: %d", pAddBssParams->extSetStaKeyParamValid); #ifdef WLAN_FEATURE_11W if (psessionEntry->limRmfEnabled) { pAddBssParams->rmfEnabled = 1; pAddBssParams->staContext.rmfEnabled = 1; } #endif /* Set a new state for MLME */ if (eLIM_MLM_WT_ASSOC_RSP_STATE == psessionEntry->limMlmState) psessionEntry->limMlmState = eLIM_MLM_WT_ADD_BSS_RSP_ASSOC_STATE; else psessionEntry->limMlmState = eLIM_MLM_WT_ADD_BSS_RSP_REASSOC_STATE; MTRACE(mac_trace (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, psessionEntry->limMlmState)); if (!pAddBssParams->staContext.htLdpcCapable) pAddBssParams->staContext.ht_caps &= ~(1 << SIR_MAC_HT_CAP_ADVCODING_S); if (!pAddBssParams->staContext.vhtLdpcCapable) pAddBssParams->staContext.vht_caps &= ~(1 << SIR_MAC_VHT_CAP_LDPC_CODING_CAP); pe_debug("staContext wmmEnabled: %d encryptType: %d " "p2pCapableSta: %d", pAddBssParams->staContext.wmmEnabled, pAddBssParams->staContext.encryptType, pAddBssParams->staContext.p2pCapableSta); pe_debug("bSpectrumMgtEnabled: %d halPersona: %d setting " "LimMlm state to %d", pAddBssParams->bSpectrumMgtEnabled, pAddBssParams->halPersona, psessionEntry->limMlmState); if (psessionEntry->isNonRoamReassoc) pAddBssParams->nonRoamReassoc = 1; pAddBssParams->nss = psessionEntry->nss; pe_debug("nss value: %d", pAddBssParams->nss); /* we need to defer the message until we get the response back from HAL. */ SET_LIM_PROCESS_DEFD_MESGS(pMac, false); if (cds_is_5_mhz_enabled()) { pAddBssParams->ch_width = CH_WIDTH_5MHZ; pAddBssParams->staContext.ch_width = CH_WIDTH_5MHZ; } else if (cds_is_10_mhz_enabled()) { pAddBssParams->ch_width = CH_WIDTH_10MHZ; pAddBssParams->staContext.ch_width = CH_WIDTH_10MHZ; } lim_set_sta_ctx_twt(&pAddBssParams->staContext, psessionEntry); msgQ.type = WMA_ADD_BSS_REQ; /** @ToDo : Update the Global counter to keeptrack of the PE <--> HAL messages*/ msgQ.reserved = 0; msgQ.bodyptr = pAddBssParams; msgQ.bodyval = 0; pe_debug("SessionId: %d Sending WMA_ADD_BSS_REQ", psessionEntry->peSessionId); MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); retCode = wma_post_ctrl_msg(pMac, &msgQ); if (QDF_STATUS_SUCCESS != retCode) { SET_LIM_PROCESS_DEFD_MESGS(pMac, true); qdf_mem_free(pAddBssParams); pe_err("Posting ADD_BSS_REQ to HAL failed, reason=%X", retCode); goto returnFailure; } else return retCode; returnFailure: /* Clean-up will be done by the caller... */ return retCode; } QDF_STATUS lim_sta_send_add_bss_pre_assoc(tpAniSirGlobal pMac, uint8_t updateEntry, tpPESession psessionEntry) { struct scheduler_msg msgQ = {0}; tpAddBssParams pAddBssParams = NULL; uint32_t retCode; tSchBeaconStruct *pBeaconStruct; uint8_t chanWidthSupp = 0; tDot11fIEVHTOperation *vht_oper = NULL; tDot11fIEVHTCaps *vht_caps = NULL; uint32_t listen_interval = WNI_CFG_LISTEN_INTERVAL_STADEF; tpSirBssDescription bssDescription = &psessionEntry->pLimJoinReq->bssDescription; pBeaconStruct = qdf_mem_malloc(sizeof(tSchBeaconStruct)); if (NULL == pBeaconStruct) { pe_err("Unable to allocate memory during ADD_BSS"); return QDF_STATUS_E_NOMEM; } /* Package SIR_HAL_ADD_BSS_REQ message parameters */ pAddBssParams = qdf_mem_malloc(sizeof(tAddBssParams)); if (NULL == pAddBssParams) { pe_err("Unable to allocate memory during ADD_BSS"); retCode = QDF_STATUS_E_NOMEM; goto returnFailure; } lim_extract_ap_capabilities(pMac, (uint8_t *) bssDescription->ieFields, lim_get_ielen_from_bss_description(bssDescription), pBeaconStruct); if (pMac->lim.gLimProtectionControl != WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) lim_decide_sta_protection_on_assoc(pMac, pBeaconStruct, psessionEntry); qdf_mem_copy(pAddBssParams->bssId, bssDescription->bssId, sizeof(tSirMacAddr)); /* Fill in tAddBssParams selfMacAddr */ qdf_mem_copy(pAddBssParams->selfMacAddr, psessionEntry->selfMacAddr, sizeof(tSirMacAddr)); pe_debug("sessionid: %d updateEntry = %d limsystemrole = %d", psessionEntry->smeSessionId, updateEntry, GET_LIM_SYSTEM_ROLE(psessionEntry)); pe_debug("BSSID: " MAC_ADDRESS_STR, MAC_ADDR_ARRAY(pAddBssParams->bssId)); /* Incorrect BSS Type which caused UMA Descriptor to be overwritten on * top of an already established Infra link. This lead to issues in * concurrent data transfer. */ pAddBssParams->bssType = psessionEntry->bssType; /* eSIR_INFRASTRUCTURE_MODE; */ pAddBssParams->operMode = BSS_OPERATIONAL_MODE_STA; pAddBssParams->beaconInterval = bssDescription->beaconInterval; pAddBssParams->dtimPeriod = pBeaconStruct->tim.dtimPeriod; pAddBssParams->updateBss = updateEntry; pAddBssParams->cfParamSet.cfpCount = pBeaconStruct->cfParamSet.cfpCount; pAddBssParams->cfParamSet.cfpPeriod = pBeaconStruct->cfParamSet.cfpPeriod; pAddBssParams->cfParamSet.cfpMaxDuration = pBeaconStruct->cfParamSet.cfpMaxDuration; pAddBssParams->cfParamSet.cfpDurRemaining = pBeaconStruct->cfParamSet.cfpDurRemaining; pAddBssParams->rateSet.numRates = pBeaconStruct->supportedRates.numRates; qdf_mem_copy(pAddBssParams->rateSet.rate, pBeaconStruct->supportedRates.rate, pBeaconStruct->supportedRates.numRates); pAddBssParams->nwType = bssDescription->nwType; pAddBssParams->shortSlotTimeSupported = (uint8_t) pBeaconStruct->capabilityInfo.shortSlotTime; pAddBssParams->llaCoexist = (uint8_t) psessionEntry->beaconParams.llaCoexist; pAddBssParams->llbCoexist = (uint8_t) psessionEntry->beaconParams.llbCoexist; pAddBssParams->llgCoexist = (uint8_t) psessionEntry->beaconParams.llgCoexist; pAddBssParams->ht20Coexist = (uint8_t) psessionEntry->beaconParams.ht20Coexist; pe_debug("BSS Type %d Beacon Interval: %d dtimPeriod: %d " "cfpCount: %d", pAddBssParams->bssType, pAddBssParams->beaconInterval, pAddBssParams->dtimPeriod, pAddBssParams->cfParamSet.cfpCount); pe_debug("cfpPeriod: %d cfpMaxDuration: %d cfpDurRemaining: %d" " numRates: %d", pAddBssParams->cfParamSet.cfpPeriod, pAddBssParams->cfParamSet.cfpMaxDuration, pAddBssParams->cfParamSet.cfpDurRemaining, pAddBssParams->rateSet.numRates); pe_debug("nwType:%d shortSlotTimeSupported: %d" "llaCoexist: %d llbCoexist: %d llgCoexist: %d ht20Coexist: %d", pAddBssParams->nwType, pAddBssParams->shortSlotTimeSupported, pAddBssParams->llaCoexist, pAddBssParams->llbCoexist, pAddBssParams->llgCoexist, pAddBssParams->ht20Coexist); /* Use the advertised capabilities from the received beacon/PR */ if (IS_DOT11_MODE_HT(psessionEntry->dot11mode) && (pBeaconStruct->HTCaps.present)) { pAddBssParams->htCapable = pBeaconStruct->HTCaps.present; pe_debug("htCapable: %d", pAddBssParams->htCapable); if (pBeaconStruct->HTInfo.present) { pAddBssParams->htOperMode = (tSirMacHTOperatingMode) pBeaconStruct->HTInfo. opMode; pAddBssParams->dualCTSProtection = (uint8_t) pBeaconStruct->HTInfo.dualCTSProtection; chanWidthSupp = lim_get_ht_capability(pMac, eHT_SUPPORTED_CHANNEL_WIDTH_SET, psessionEntry); if ((pBeaconStruct->HTCaps.supportedChannelWidthSet) && (chanWidthSupp)) { pAddBssParams->ch_width = (uint8_t) pBeaconStruct->HTInfo. recommendedTxWidthSet; if (pBeaconStruct->HTInfo.secondaryChannelOffset == PHY_DOUBLE_CHANNEL_LOW_PRIMARY) pAddBssParams->ch_center_freq_seg0 = bssDescription->channelId + 2; if (pBeaconStruct->HTInfo.secondaryChannelOffset == PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) pAddBssParams->ch_center_freq_seg0 = bssDescription->channelId - 2; } else { pAddBssParams->ch_width = CH_WIDTH_20MHZ; pAddBssParams->ch_center_freq_seg0 = 0; } pAddBssParams->llnNonGFCoexist = (uint8_t) pBeaconStruct->HTInfo.nonGFDevicesPresent; pAddBssParams->fLsigTXOPProtectionFullSupport = (uint8_t) pBeaconStruct->HTInfo. lsigTXOPProtectionFullSupport; pAddBssParams->fRIFSMode = pBeaconStruct->HTInfo.rifsMode; pe_debug("htOperMode: %d dualCTSProtection: %d txChannelWidthSet: %d center_freq_seg0: %d", pAddBssParams->htOperMode, pAddBssParams->dualCTSProtection, pAddBssParams->txChannelWidthSet, pAddBssParams->ch_center_freq_seg0); pe_debug("llnNonGFCoexist: %d " "fLsigTXOPProtectionFullSupport: %d fRIFSMode %d", pAddBssParams->llnNonGFCoexist, pAddBssParams->fLsigTXOPProtectionFullSupport, pAddBssParams->fRIFSMode); } } pAddBssParams->currentOperChannel = bssDescription->channelId; pe_debug("currentOperChannel %d", pAddBssParams->currentOperChannel); if (psessionEntry->vhtCapability && (IS_BSS_VHT_CAPABLE(pBeaconStruct->VHTCaps) || IS_BSS_VHT_CAPABLE(pBeaconStruct->vendor_vht_ie.VHTCaps))) { pAddBssParams->vhtCapable = 1; if (pBeaconStruct->VHTOperation.present) vht_oper = &pBeaconStruct->VHTOperation; else if (pBeaconStruct->vendor_vht_ie.VHTOperation.present) { vht_oper = &pBeaconStruct->vendor_vht_ie.VHTOperation; pe_debug("VHT Operation is present in vendor Specific IE"); } if ((vht_oper != NULL) && vht_oper->chanWidth && chanWidthSupp) { pAddBssParams->ch_center_freq_seg0 = vht_oper->chanCenterFreqSeg1; pAddBssParams->ch_center_freq_seg1 = vht_oper->chanCenterFreqSeg2; } /* * in limExtractApCapability function intersection of FW * advertised channel width and AP advertised channel width has * been taken into account for calculating * psessionEntry->ch_width */ pAddBssParams->ch_width = psessionEntry->ch_width; pAddBssParams->staContext.maxAmpduSize = SIR_MAC_GET_VHT_MAX_AMPDU_EXPO( pAddBssParams->staContext.vht_caps); } else { pAddBssParams->vhtCapable = 0; } if (lim_is_session_he_capable(psessionEntry) && pBeaconStruct->he_cap.present) { lim_update_bss_he_capable(pMac, pAddBssParams); lim_add_bss_he_cfg(pAddBssParams, psessionEntry); } pe_debug("vhtCapable %d vhtTxChannelWidthSet %d center_freq_seg0 - %d, center_freq_seg1 - %d", pAddBssParams->vhtCapable, pAddBssParams->ch_width, pAddBssParams->ch_center_freq_seg0, pAddBssParams->ch_center_freq_seg1); /* * Populate the STA-related parameters here * Note that the STA here refers to the AP */ /* Identifying AP as an STA */ pAddBssParams->staContext.staType = STA_ENTRY_OTHER; qdf_mem_copy(pAddBssParams->staContext.bssId, bssDescription->bssId, sizeof(tSirMacAddr)); if (wlan_cfg_get_int(pMac, WNI_CFG_LISTEN_INTERVAL, &listen_interval) != QDF_STATUS_SUCCESS) pe_err("Couldn't get LISTEN_INTERVAL"); pAddBssParams->staContext.listenInterval = listen_interval; pAddBssParams->staContext.assocId = 0; pAddBssParams->staContext.uAPSD = 0; pAddBssParams->staContext.maxSPLen = 0; pAddBssParams->staContext.shortPreambleSupported = (uint8_t) pBeaconStruct->capabilityInfo.shortPreamble; pAddBssParams->staContext.updateSta = updateEntry; pe_debug("StaCtx: " MAC_ADDRESS_STR " shortPreamble: %d", MAC_ADDR_ARRAY(pAddBssParams->staContext.staMac), pAddBssParams->staContext.shortPreambleSupported); pAddBssParams->dot11_mode = psessionEntry->dot11mode; pe_debug("dot11_mode:%d", pAddBssParams->dot11_mode); if (IS_DOT11_MODE_HT(psessionEntry->dot11mode) && (pBeaconStruct->HTCaps.present)) { pAddBssParams->staContext.us32MaxAmpduDuration = 0; pAddBssParams->staContext.htCapable = 1; pAddBssParams->staContext.greenFieldCapable = (uint8_t) pBeaconStruct->HTCaps.greenField; pAddBssParams->staContext.lsigTxopProtection = (uint8_t) pBeaconStruct->HTCaps.lsigTXOPProtection; pe_debug("StaCtx: htCap %d GFCap %d lsigTxopProtn %d", pAddBssParams->staContext.htCapable, pAddBssParams->staContext.greenFieldCapable, pAddBssParams->staContext.lsigTxopProtection); if (psessionEntry->vhtCapability && (IS_BSS_VHT_CAPABLE(pBeaconStruct->VHTCaps) || IS_BSS_VHT_CAPABLE( pBeaconStruct->vendor_vht_ie.VHTCaps))) { pAddBssParams->staContext.vhtCapable = 1; if (pBeaconStruct->VHTCaps.present) vht_caps = &pBeaconStruct->VHTCaps; else if (pBeaconStruct->vendor_vht_ie.VHTCaps.present) vht_caps = &pBeaconStruct-> vendor_vht_ie.VHTCaps; if ((vht_caps != NULL) && (vht_caps->suBeamFormerCap || vht_caps->muBeamformerCap) && psessionEntry->vht_config.su_beam_formee) pAddBssParams->staContext.vhtTxBFCapable = 1; if ((vht_caps != NULL) && vht_caps->muBeamformerCap && psessionEntry->vht_config.mu_beam_formee) pAddBssParams->staContext.vhtTxMUBformeeCapable = 1; if ((vht_caps != NULL) && vht_caps->suBeamformeeCap && psessionEntry->vht_config.su_beam_former) pAddBssParams->staContext.enable_su_tx_bformer = 1; pe_debug("StaContext: su_tx_bfer %d", pAddBssParams->staContext.enable_su_tx_bformer); } if (lim_is_session_he_capable(psessionEntry) && pBeaconStruct->he_cap.present) lim_intersect_ap_he_caps(psessionEntry, pAddBssParams, pBeaconStruct, NULL); if ((pBeaconStruct->HTCaps.supportedChannelWidthSet) && (chanWidthSupp)) { pAddBssParams->staContext.ch_width = (uint8_t) pBeaconStruct->HTInfo. recommendedTxWidthSet; if ((vht_oper != NULL) && pAddBssParams->staContext.vhtCapable && vht_oper->chanWidth) pAddBssParams->staContext.ch_width = vht_oper->chanWidth + 1; pe_debug("StaCtx: vhtCap %d ch_bw %d TxBF %d", pAddBssParams->staContext.vhtCapable, pAddBssParams->staContext.ch_width, pAddBssParams->staContext.vhtTxBFCapable); } else { pAddBssParams->staContext.ch_width = CH_WIDTH_20MHZ; } pAddBssParams->staContext.mimoPS = (tSirMacHTMIMOPowerSaveState) pBeaconStruct->HTCaps. mimoPowerSave; pAddBssParams->staContext.maxAmsduSize = (uint8_t) pBeaconStruct->HTCaps.maximalAMSDUsize; pAddBssParams->staContext.maxAmpduDensity = pBeaconStruct->HTCaps.mpduDensity; pAddBssParams->staContext.fDsssCckMode40Mhz = (uint8_t) pBeaconStruct->HTCaps.dsssCckMode40MHz; /* * We will check gShortGI20Mhz and gShortGI40Mhz from ini file. * if they are set then we will use what ever Beacon coming * from AP supports. If these values are set as 0 in ini file * then we will hardcode this values to 0. */ if (true == psessionEntry->htConfig.ht_sgi20) pAddBssParams->staContext.fShortGI20Mhz = (uint8_t)pBeaconStruct->HTCaps.shortGI20MHz; else pAddBssParams->staContext.fShortGI20Mhz = false; if (true == psessionEntry->htConfig.ht_sgi40) pAddBssParams->staContext.fShortGI40Mhz = (uint8_t) pBeaconStruct->HTCaps.shortGI40MHz; else pAddBssParams->staContext.fShortGI40Mhz = false; pAddBssParams->staContext.maxAmpduSize = pBeaconStruct->HTCaps.maxRxAMPDUFactor; if (pAddBssParams->staContext.vhtTxBFCapable && pMac->lim.disableLDPCWithTxbfAP) { pAddBssParams->staContext.htLdpcCapable = 0; pAddBssParams->staContext.vhtLdpcCapable = 0; } else { if (psessionEntry->txLdpcIniFeatureEnabled & 0x1) pAddBssParams->staContext.htLdpcCapable = (uint8_t) pBeaconStruct->HTCaps. advCodingCap; else pAddBssParams->staContext.htLdpcCapable = 0; if (pBeaconStruct->VHTCaps.present) vht_caps = &pBeaconStruct->VHTCaps; else if (pBeaconStruct->vendor_vht_ie.VHTCaps.present) { vht_caps = &pBeaconStruct->vendor_vht_ie.VHTCaps; pe_debug("VHT Caps are in vendor Specific IE"); } if (vht_caps != NULL && (psessionEntry->txLdpcIniFeatureEnabled & 0x2)) pAddBssParams->staContext.vhtLdpcCapable = (uint8_t) vht_caps->ldpcCodingCap; else pAddBssParams->staContext.vhtLdpcCapable = 0; } if (pBeaconStruct->HTInfo.present) pAddBssParams->staContext.rifsMode = pBeaconStruct->HTInfo.rifsMode; pe_debug("StaContext ChannelWidth: %d mimoPS: %d maxAmsduSize: %d", pAddBssParams->staContext.ch_width, pAddBssParams->staContext.mimoPS, pAddBssParams->staContext.maxAmsduSize); pe_debug("maxAmpduDensity %d Cck40Mhz %d SGI20Mhz %d", pAddBssParams->staContext.maxAmpduDensity, pAddBssParams->staContext.fDsssCckMode40Mhz, pAddBssParams->staContext.fShortGI20Mhz); pe_debug("SGI40M %d maxAmpdu %d htLdpc %d vhtLdpc %d", pAddBssParams->staContext.fShortGI40Mhz, pAddBssParams->staContext.maxAmpduSize, pAddBssParams->staContext.htLdpcCapable, pAddBssParams->staContext.vhtLdpcCapable); } /* * If WMM IE or 802.11E IE is not present * and AP is HT AP then enable WMM */ if ((psessionEntry->limWmeEnabled && (pBeaconStruct->wmeEdcaPresent || pAddBssParams->staContext.htCapable)) || (psessionEntry->limQosEnabled && (pBeaconStruct->edcaPresent || pAddBssParams->staContext.htCapable))) pAddBssParams->staContext.wmmEnabled = 1; else pAddBssParams->staContext.wmmEnabled = 0; /* Update the rates */ lim_populate_peer_rate_set(pMac, &pAddBssParams->staContext. supportedRates, pBeaconStruct->HTCaps.supportedMCSSet, false, psessionEntry, &pBeaconStruct->VHTCaps, &pBeaconStruct->he_cap); pAddBssParams->staContext.encryptType = psessionEntry->encryptType; pAddBssParams->maxTxPower = psessionEntry->maxTxPower; pe_debug("maxTxPower: %d", pAddBssParams->maxTxPower); pAddBssParams->status = QDF_STATUS_SUCCESS; pAddBssParams->respReqd = true; pAddBssParams->staContext.smesessionId = psessionEntry->smeSessionId; pAddBssParams->staContext.sessionId = psessionEntry->peSessionId; pAddBssParams->sessionId = psessionEntry->peSessionId; pAddBssParams->halPersona = (uint8_t) psessionEntry->pePersona; /* update persona */ pAddBssParams->bSpectrumMgtEnabled = psessionEntry->spectrumMgtEnabled; pAddBssParams->extSetStaKeyParamValid = 0; pe_debug("extSetStaKeyParamValid: %d", pAddBssParams->extSetStaKeyParamValid); #ifdef WLAN_FEATURE_11W if (psessionEntry->limRmfEnabled) { pAddBssParams->rmfEnabled = 1; pAddBssParams->staContext.rmfEnabled = 1; } #endif pAddBssParams->nss = psessionEntry->nss; pe_debug("nss value: %d", pAddBssParams->nss); /* Set a new state for MLME */ psessionEntry->limMlmState = eLIM_MLM_WT_ADD_BSS_RSP_PREASSOC_STATE; MTRACE(mac_trace (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, psessionEntry->limMlmState)); pe_debug("staContext wmmEnabled: %d encryptType: %d " "p2pCapableSta: %d", pAddBssParams->staContext.wmmEnabled, pAddBssParams->staContext.encryptType, pAddBssParams->staContext.p2pCapableSta); pe_debug("bSpectrumMgtEnabled: %d halPersona: %d setting " "LimMlm state to %d", pAddBssParams->bSpectrumMgtEnabled, pAddBssParams->halPersona, psessionEntry->limMlmState); /* we need to defer the message until we get the response back from HAL. */ SET_LIM_PROCESS_DEFD_MESGS(pMac, false); if (cds_is_5_mhz_enabled()) { pAddBssParams->ch_width = CH_WIDTH_5MHZ; pAddBssParams->staContext.ch_width = CH_WIDTH_5MHZ; } else if (cds_is_10_mhz_enabled()) { pAddBssParams->ch_width = CH_WIDTH_10MHZ; pAddBssParams->staContext.ch_width = CH_WIDTH_10MHZ; } msgQ.type = WMA_ADD_BSS_REQ; /** @ToDo : Update the Global counter to keeptrack of the PE <--> HAL messages*/ msgQ.reserved = 0; msgQ.bodyptr = pAddBssParams; msgQ.bodyval = 0; pe_debug("SessionId:%d Sending WMA_ADD_BSS_REQ", psessionEntry->peSessionId); MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); retCode = wma_post_ctrl_msg(pMac, &msgQ); if (QDF_STATUS_SUCCESS != retCode) { SET_LIM_PROCESS_DEFD_MESGS(pMac, true); qdf_mem_free(pAddBssParams); pe_err("Posting ADD_BSS_REQ to HAL failed, reason=%X", retCode); goto returnFailure; } else { qdf_mem_free(pBeaconStruct); return retCode; } returnFailure: /* Clean-up will be done by the caller... */ qdf_mem_free(pBeaconStruct); return retCode; } /** * lim_prepare_and_send_del_sta_cnf() - prepares and send del sta cnf * * @pMac: mac global context * @pStaDs: sta dph node * @statusCode: status code * @psessionEntry: session context * * deletes DPH entry, changes the MLM mode for station, calls * lim_send_del_sta_cnf * * Return: void */ void lim_prepare_and_send_del_sta_cnf(tpAniSirGlobal pMac, tpDphHashNode pStaDs, tSirResultCodes statusCode, tpPESession psessionEntry) { uint16_t staDsAssocId = 0; struct qdf_mac_addr sta_dsaddr; tLimMlmStaContext mlmStaContext; if (pStaDs == NULL) { pe_err("pStaDs is NULL"); return; } staDsAssocId = pStaDs->assocId; qdf_mem_copy((uint8_t *) sta_dsaddr.bytes, pStaDs->staAddr, QDF_MAC_ADDR_SIZE); mlmStaContext = pStaDs->mlmStaContext; if (LIM_IS_AP_ROLE(psessionEntry)) lim_release_peer_idx(pMac, pStaDs->assocId, psessionEntry); lim_delete_dph_hash_entry(pMac, pStaDs->staAddr, pStaDs->assocId, psessionEntry); if (LIM_IS_STA_ROLE(psessionEntry)) { psessionEntry->limMlmState = eLIM_MLM_IDLE_STATE; MTRACE(mac_trace(pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, psessionEntry->limMlmState)); } lim_send_del_sta_cnf(pMac, sta_dsaddr, staDsAssocId, mlmStaContext, statusCode, psessionEntry); } /** ------------------------------------------------------------- \fn lim_init_pre_auth_timer_table \brief Initialize the Pre Auth Tanle and creates the timer for each node for the timeout value got from cfg. \param tpAniSirGlobal pMac \param tpLimPreAuthTable pPreAuthTimerTable \return none -------------------------------------------------------------*/ void lim_init_pre_auth_timer_table(tpAniSirGlobal pMac, tpLimPreAuthTable pPreAuthTimerTable) { uint32_t cfgValue; uint32_t authNodeIdx; tLimPreAuthNode **pAuthNode = pPreAuthTimerTable->pTable; /* Get AUTH_RSP Timers value */ if (wlan_cfg_get_int(pMac, WNI_CFG_AUTHENTICATE_RSP_TIMEOUT, &cfgValue) != QDF_STATUS_SUCCESS) { pe_err("could not retrieve AUTH_RSP timeout value"); return; } cfgValue = SYS_MS_TO_TICKS(cfgValue); for (authNodeIdx = 0; authNodeIdx < pPreAuthTimerTable->numEntry; authNodeIdx++) { if (tx_timer_create(pMac, &(pAuthNode[authNodeIdx]->timer), "AUTH RESPONSE TIMEOUT", lim_auth_response_timer_handler, authNodeIdx, cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) { pe_err("Cannot create Auth Rsp timer of Index: %d", authNodeIdx); return; } pAuthNode[authNodeIdx]->authNodeIdx = (uint8_t) authNodeIdx; pAuthNode[authNodeIdx]->fFree = 1; } } /** ------------------------------------------------------------- \fn lim_acquire_free_pre_auth_node \brief Retrives a free Pre Auth node from Pre Auth Table. \param tpAniSirGlobal pMac \param tpLimPreAuthTable pPreAuthTimerTable \return none -------------------------------------------------------------*/ tLimPreAuthNode *lim_acquire_free_pre_auth_node(tpAniSirGlobal pMac, tpLimPreAuthTable pPreAuthTimerTable) { uint32_t i; tLimPreAuthNode **pTempNode = pPreAuthTimerTable->pTable; for (i = 0; i < pPreAuthTimerTable->numEntry; i++) { if (pTempNode[i]->fFree == 1) { pTempNode[i]->fFree = 0; return pTempNode[i]; } } return NULL; } /** ------------------------------------------------------------- \fn lim_get_pre_auth_node_from_index \brief Depending on the Index this retrieves the pre auth node. \param tpAniSirGlobal pMac \param tpLimPreAuthTable pAuthTable \param uint32_t authNodeIdx \return none -------------------------------------------------------------*/ tLimPreAuthNode *lim_get_pre_auth_node_from_index(tpAniSirGlobal pMac, tpLimPreAuthTable pAuthTable, uint32_t authNodeIdx) { if ((authNodeIdx >= pAuthTable->numEntry) || (pAuthTable->pTable == NULL)) { pe_err("Invalid Auth Timer Index: %d NumEntry: %d", authNodeIdx, pAuthTable->numEntry); return NULL; } return pAuthTable->pTable[authNodeIdx]; } /* Util API to check if the channels supported by STA is within range */ QDF_STATUS lim_is_dot11h_supported_channels_valid(tpAniSirGlobal pMac, tSirAssocReq *assoc) { /* * Allow all the stations to join with us. * 802.11h-2003 11.6.1 => An AP may use the supported channels list for associated STAs * as an input into an algorithm used to select a new channel for the BSS. * The specification of the algorithm is beyond the scope of this amendment. */ return QDF_STATUS_SUCCESS; } /* Util API to check if the txpower supported by STA is within range */ QDF_STATUS lim_is_dot11h_power_capabilities_in_range(tpAniSirGlobal pMac, tSirAssocReq *assoc, tpPESession psessionEntry) { int8_t localMaxTxPower; uint32_t localPwrConstraint; localMaxTxPower = cfg_get_regulatory_max_transmit_power(pMac, psessionEntry->currentOperChannel); if (wlan_cfg_get_int (pMac, WNI_CFG_LOCAL_POWER_CONSTRAINT, &localPwrConstraint) != QDF_STATUS_SUCCESS) { pe_err("Unable to get Local Power Constraint from cfg"); return QDF_STATUS_E_FAILURE; } localMaxTxPower -= (int8_t) localPwrConstraint; /** * The min Tx Power of the associating station should not be greater than (regulatory * max tx power - local power constraint configured on AP). */ if (assoc->powerCapability.minTxPower > localMaxTxPower) { pe_warn("minTxPower (STA): %d, localMaxTxPower (AP): %d", assoc->powerCapability.minTxPower, localMaxTxPower); return QDF_STATUS_E_FAILURE; } return QDF_STATUS_SUCCESS; } /** ------------------------------------------------------------- \fn lim_fill_rx_highest_supported_rate \brief Fills in the Rx Highest Supported Data Rate field from \ the 'supported MCS set' field in HT capability element. \param tpAniSirGlobal pMac \param tpSirSupportedRates pRates \param uint8_t* pSupportedMCSSet \return none -------------------------------------------------------------*/ void lim_fill_rx_highest_supported_rate(tpAniSirGlobal pMac, uint16_t *rxHighestRate, uint8_t *pSupportedMCSSet) { tSirMacRxHighestSupportRate *pRxHighestRate; uint8_t *pBuf; uint16_t rate = 0; pBuf = pSupportedMCSSet + MCS_RX_HIGHEST_SUPPORTED_RATE_BYTE_OFFSET; rate = lim_get_u16(pBuf); pRxHighestRate = (tSirMacRxHighestSupportRate *) &rate; *rxHighestRate = pRxHighestRate->rate; return; } #ifdef WLAN_FEATURE_11W /** ------------------------------------------------------------- \fn lim_send_sme_unprotected_mgmt_frame_ind \brief Forwards the unprotected management frame to SME. \param tpAniSirGlobal pMac \param frameType - 802.11 frame type \param frame - frame buffer \param sessionId - id for the current session \param psessionEntry - PE session context \return none -------------------------------------------------------------*/ void lim_send_sme_unprotected_mgmt_frame_ind(tpAniSirGlobal pMac, uint8_t frameType, uint8_t *frame, uint32_t frameLen, uint16_t sessionId, tpPESession psessionEntry) { struct scheduler_msg mmhMsg = {0}; tSirSmeUnprotMgmtFrameInd *pSirSmeMgmtFrame = NULL; uint16_t length; length = sizeof(tSirSmeUnprotMgmtFrameInd) + frameLen; pSirSmeMgmtFrame = qdf_mem_malloc(length); if (NULL == pSirSmeMgmtFrame) { pe_err("Memory allocation failed"); return; } pSirSmeMgmtFrame->sessionId = sessionId; pSirSmeMgmtFrame->frameType = frameType; qdf_mem_copy(pSirSmeMgmtFrame->frameBuf, frame, frameLen); pSirSmeMgmtFrame->frameLen = frameLen; mmhMsg.type = eWNI_SME_UNPROT_MGMT_FRM_IND; mmhMsg.bodyptr = pSirSmeMgmtFrame; mmhMsg.bodyval = 0; lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); return; } #endif #ifdef FEATURE_WLAN_ESE /** ------------------------------------------------------------- \fn lim_send_sme_tsm_ie_ind \brief Forwards the TSM IE information to SME. \param tpAniSirGlobal pMac \param psessionEntry - PE session context \param tid - traffic id \param state - tsm state (enabled/disabled) \param measurementInterval - measurement interval \return none -------------------------------------------------------------*/ void lim_send_sme_tsm_ie_ind(tpAniSirGlobal pMac, tpPESession psessionEntry, uint8_t tid, uint8_t state, uint16_t measInterval) { struct scheduler_msg mmhMsg = {0}; tpSirSmeTsmIEInd pSirSmeTsmIeInd = NULL; if (!pMac || !psessionEntry) return; pSirSmeTsmIeInd = qdf_mem_malloc(sizeof(tSirSmeTsmIEInd)); if (NULL == pSirSmeTsmIeInd) { pe_err("AllocateMemory failed for tSirSmeTsmIEInd"); return; } pSirSmeTsmIeInd->sessionId = psessionEntry->smeSessionId; pSirSmeTsmIeInd->tsmIe.tsid = tid; pSirSmeTsmIeInd->tsmIe.state = state; pSirSmeTsmIeInd->tsmIe.msmt_interval = measInterval; mmhMsg.type = eWNI_SME_TSM_IE_IND; mmhMsg.bodyptr = pSirSmeTsmIeInd; mmhMsg.bodyval = 0; lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); return; } #endif /* FEATURE_WLAN_ESE */