/* * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the * above copyright notice and this permission notice appear in all * copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ /* * This file was originally distributed by Qualcomm Atheros, Inc. * under proprietary terms before Copyright ownership was assigned * to the Linux Foundation. */ /* * * This file lim_utils.cc contains the utility functions * LIM uses. * Author: Chandra Modumudi * Date: 02/13/02 * History:- * Date Modified by Modification Information * -------------------------------------------------------------------- */ #include "ani_global.h" #include "wni_api.h" #include "sir_common.h" #include "wni_cfg.h" #include "cfg_api.h" #include "utils_api.h" #include "lim_utils.h" #include "lim_security_utils.h" #include "lim_ft_defs.h" #include "lim_session.h" #define LIM_SEED_LENGTH 16 /* * preauth node timeout value in interval of 10msec */ #define LIM_OPENAUTH_TIMEOUT 500 /** * lim_is_auth_algo_supported() * ***FUNCTION: * This function is called in various places within LIM code * to determine whether passed authentication algorithm is enabled * or not * ***LOGIC: * ***ASSUMPTIONS: * NA * ***NOTE: * NA * * @param authType Indicates MAC based authentication type * (eSIR_OPEN_SYSTEM or eSIR_SHARED_KEY) * If Shared Key authentication to be used, * 'Privacy Option Implemented' flag is also * checked. * * @return true if passed authType is enabled else false */ uint8_t lim_is_auth_algo_supported(tpAniSirGlobal pMac, tAniAuthType authType, tpPESession psessionEntry) { uint32_t algoEnable, privacyOptImp; if (authType == eSIR_OPEN_SYSTEM) { if (LIM_IS_AP_ROLE(psessionEntry)) { if ((psessionEntry->authType == eSIR_OPEN_SYSTEM) || (psessionEntry->authType == eSIR_AUTO_SWITCH)) return true; else return false; } if (wlan_cfg_get_int(pMac, WNI_CFG_OPEN_SYSTEM_AUTH_ENABLE, &algoEnable) != eSIR_SUCCESS) { pe_err("could not retrieve AuthAlgo1 Enable value"); return false; } else return algoEnable > 0 ? true : false; } else { if (LIM_IS_AP_ROLE(psessionEntry)) { if ((psessionEntry->authType == eSIR_SHARED_KEY) || (psessionEntry->authType == eSIR_AUTO_SWITCH)) algoEnable = true; else algoEnable = false; } else if (wlan_cfg_get_int (pMac, WNI_CFG_SHARED_KEY_AUTH_ENABLE, &algoEnable) != eSIR_SUCCESS) { pe_err("could not retrieve AuthAlgo2 Enable value"); return false; } if (LIM_IS_AP_ROLE(psessionEntry)) { privacyOptImp = psessionEntry->privacy; } else if (wlan_cfg_get_int(pMac, WNI_CFG_PRIVACY_ENABLED, &privacyOptImp) != eSIR_SUCCESS) { pe_err("could not retrieve PrivacyOptImplemented value"); return false; } return algoEnable && privacyOptImp; } } /****** end lim_is_auth_algo_supported() ******/ /** * lim_init_pre_auth_list * ***FUNCTION: * This function is called while starting a BSS at AP * to initialize MAC authenticated STA list. This may also be called * while joining/starting an IBSS if MAC authentication is allowed * in IBSS mode. * ***LOGIC: * ***ASSUMPTIONS: * ***NOTE: * * @param pMac - Pointer to Global MAC structure * @return None */ void lim_init_pre_auth_list(tpAniSirGlobal pMac) { pMac->lim.pLimPreAuthList = NULL; } /*** end lim_init_pre_auth_list() ***/ /** * lim_delete_pre_auth_list * ***FUNCTION: * This function is called cleanup Pre-auth list either on * AP or on STA when moving from one persona to other. * ***LOGIC: * ***ASSUMPTIONS: * ***NOTE: * * @param pMac - Pointer to Global MAC structure * @return None */ void lim_delete_pre_auth_list(tpAniSirGlobal pMac) { struct tLimPreAuthNode *pCurrNode, *pTempNode; pCurrNode = pTempNode = pMac->lim.pLimPreAuthList; while (pCurrNode != NULL) { pTempNode = pCurrNode->next; lim_release_pre_auth_node(pMac, pCurrNode); pCurrNode = pTempNode; } pMac->lim.pLimPreAuthList = NULL; } /*** end lim_delete_pre_auth_list() ***/ /** * lim_search_pre_auth_list * ***FUNCTION: * This function is called when Authentication frame is received * by AP (or at a STA in IBSS supporting MAC based authentication) * to search if a STA is in the middle of MAC Authentication * transaction sequence. * ***LOGIC: * ***ASSUMPTIONS: * ***NOTE: * * @param macAddr - MAC address of the STA that sent * Authentication frame. * * @return Pointer to pre-auth node if found, else NULL */ struct tLimPreAuthNode *lim_search_pre_auth_list(tpAniSirGlobal pMac, tSirMacAddr macAddr) { struct tLimPreAuthNode *pTempNode = pMac->lim.pLimPreAuthList; while (pTempNode != NULL) { if (!qdf_mem_cmp((uint8_t *) macAddr, (uint8_t *) &pTempNode->peerMacAddr, sizeof(tSirMacAddr))) break; pTempNode = pTempNode->next; } return pTempNode; } /*** end lim_search_pre_auth_list() ***/ /** * lim_delete_open_auth_pre_auth_node() - delete any stale preauth nodes * @mac_ctx: Pointer to Global MAC structure * * This function is called to delete any stale preauth nodes on * receiving authentication frame and existing preauth nodes * reached the maximum allowed limit. * * Return: return true if any preauthnode deleted else false */ uint8_t lim_delete_open_auth_pre_auth_node(tpAniSirGlobal mac_ctx) { struct tLimPreAuthNode *prev_node, *temp_node, *found_node; uint8_t auth_node_freed = false; temp_node = prev_node = mac_ctx->lim.pLimPreAuthList; if (temp_node == NULL) return auth_node_freed; while (temp_node != NULL) { if (temp_node->mlmState == eLIM_MLM_AUTHENTICATED_STATE && temp_node->authType == eSIR_OPEN_SYSTEM && (qdf_mc_timer_get_system_ticks() > (LIM_OPENAUTH_TIMEOUT + temp_node->timestamp) || qdf_mc_timer_get_system_ticks() < temp_node->timestamp)) { /* Found node to be deleted */ auth_node_freed = true; found_node = temp_node; if (mac_ctx->lim.pLimPreAuthList == temp_node) { prev_node = mac_ctx->lim.pLimPreAuthList = temp_node = found_node->next; } else { prev_node->next = temp_node->next; temp_node = prev_node->next; } lim_release_pre_auth_node(mac_ctx, found_node); } else { prev_node = temp_node; temp_node = prev_node->next; } } return auth_node_freed; } /** * lim_add_pre_auth_node * ***FUNCTION: * This function is called at AP while sending Authentication * frame2. * This may also be called on a STA in IBSS if MAC authentication is * allowed in IBSS mode. * ***LOGIC: * Node is always added to the front of the list * ***ASSUMPTIONS: * ***NOTE: * * @param pMac - Pointer to Global MAC structure * @param pAuthNode - Pointer to pre-auth node to be added to the list. * * @return None */ void lim_add_pre_auth_node(tpAniSirGlobal pMac, struct tLimPreAuthNode *pAuthNode) { pMac->lim.gLimNumPreAuthContexts++; pAuthNode->next = pMac->lim.pLimPreAuthList; pMac->lim.pLimPreAuthList = pAuthNode; } /*** end lim_add_pre_auth_node() ***/ /** * lim_release_pre_auth_node * ***FUNCTION: * This function is called to realease the accquired * pre auth node from list. * ***LOGIC: * ***ASSUMPTIONS: * ***NOTE: * * @param pMac - Pointer to Global MAC structure * @param pAuthNode - Pointer to Pre Auth node to be released * @return None */ void lim_release_pre_auth_node(tpAniSirGlobal pMac, tpLimPreAuthNode pAuthNode) { pAuthNode->fFree = 1; MTRACE(mac_trace (pMac, TRACE_CODE_TIMER_DEACTIVATE, NO_SESSION, eLIM_PRE_AUTH_CLEANUP_TIMER)); tx_timer_deactivate(&pAuthNode->timer); pMac->lim.gLimNumPreAuthContexts--; } /*** end lim_release_pre_auth_node() ***/ /** * lim_delete_pre_auth_node * ***FUNCTION: * This function is called at AP when a pre-authenticated STA is * Associated/Reassociated or when AuthFrame4 is received after * Auth Response timeout. * This may also be called on a STA in IBSS if MAC authentication and * Association/Reassociation is allowed in IBSS mode. * ***LOGIC: * ***ASSUMPTIONS: * ***NOTE: * * @param pMac - Pointer to Global MAC structure * @param peerMacAddr - MAC address of the STA that need to be deleted * from pre-auth node list. * * @return None */ void lim_delete_pre_auth_node(tpAniSirGlobal pMac, tSirMacAddr macAddr) { struct tLimPreAuthNode *pPrevNode, *pTempNode; pTempNode = pPrevNode = pMac->lim.pLimPreAuthList; if (pTempNode == NULL) return; if (!qdf_mem_cmp((uint8_t *) macAddr, (uint8_t *) &pTempNode->peerMacAddr, sizeof(tSirMacAddr))) { /* First node to be deleted */ pMac->lim.pLimPreAuthList = pTempNode->next; pe_debug("first node to delete, Release data entry: %pK id %d peer", pTempNode, pTempNode->authNodeIdx); lim_print_mac_addr(pMac, macAddr, LOGD); lim_release_pre_auth_node(pMac, pTempNode); return; } pTempNode = pTempNode->next; while (pTempNode != NULL) { if (!qdf_mem_cmp((uint8_t *) macAddr, (uint8_t *) &pTempNode->peerMacAddr, sizeof(tSirMacAddr))) { /* Found node to be deleted */ pPrevNode->next = pTempNode->next; pe_debug("subsequent node to delete, Release data entry: %pK id %d peer", pTempNode, pTempNode->authNodeIdx); lim_print_mac_addr(pMac, macAddr, LOGD); lim_release_pre_auth_node(pMac, pTempNode); return; } pPrevNode = pTempNode; pTempNode = pTempNode->next; } pe_err("peer not found in pre-auth list, addr= "); lim_print_mac_addr(pMac, macAddr, LOGE); } /*** end lim_delete_pre_auth_node() ***/ /** * limRestoreFromPreAuthState * ***FUNCTION: * This function is called on STA whenever an Authentication * sequence is complete and state prior to auth need to be * restored. * ***LOGIC: * MLM_AUTH_CNF is prepared and sent to SME state machine. * In case of restoring from pre-auth: * - Channel Id is programmed at LO/RF synthesizer * - BSSID is programmed at RHP * ***ASSUMPTIONS: * ***NOTE: * * @param pMac - Pointer to Global MAC structure * @param resultCode - result of authentication attempt * @return None */ void lim_restore_from_auth_state(tpAniSirGlobal pMac, tSirResultCodes resultCode, uint16_t protStatusCode, tpPESession sessionEntry) { tSirMacAddr currentBssId; tLimMlmAuthCnf mlmAuthCnf; #ifdef FEATURE_WLAN_DIAG_SUPPORT lim_diag_event_report(pMac, WLAN_PE_DIAG_AUTH_COMP_EVENT, sessionEntry, resultCode, protStatusCode); #endif qdf_mem_copy((uint8_t *) &mlmAuthCnf.peerMacAddr, (uint8_t *) &pMac->lim.gpLimMlmAuthReq->peerMacAddr, sizeof(tSirMacAddr)); mlmAuthCnf.authType = pMac->lim.gpLimMlmAuthReq->authType; mlmAuthCnf.resultCode = resultCode; mlmAuthCnf.protStatusCode = protStatusCode; /* Update PE session ID */ mlmAuthCnf.sessionId = sessionEntry->peSessionId; /* / Free up buffer allocated */ /* / for pMac->lim.gLimMlmAuthReq */ qdf_mem_free(pMac->lim.gpLimMlmAuthReq); pMac->lim.gpLimMlmAuthReq = NULL; sessionEntry->limMlmState = sessionEntry->limPrevMlmState; MTRACE(mac_trace (pMac, TRACE_CODE_MLM_STATE, sessionEntry->peSessionId, sessionEntry->limMlmState)); /* * Set the auth_ack_status status flag as success as * host have received the auth rsp and no longer auth * retry is needed also cancel the auth rety timer */ pMac->auth_ack_status = LIM_AUTH_ACK_RCD_SUCCESS; /* Auth retry and AUth failure timers are not started for SAE */ /* 'Change' timer for future activations */ if (tx_timer_running(&pMac->lim.limTimers. g_lim_periodic_auth_retry_timer)) lim_deactivate_and_change_timer(pMac, eLIM_AUTH_RETRY_TIMER); /* 'Change' timer for future activations */ if (tx_timer_running(&pMac->lim.limTimers.gLimAuthFailureTimer)) lim_deactivate_and_change_timer(pMac, eLIM_AUTH_FAIL_TIMER); sir_copy_mac_addr(currentBssId, sessionEntry->bssId); if (sessionEntry->limSmeState == eLIM_SME_WT_PRE_AUTH_STATE) { pMac->lim.gLimPreAuthChannelNumber = 0; } lim_post_sme_message(pMac, LIM_MLM_AUTH_CNF, (uint32_t *) &mlmAuthCnf); } /*** end lim_restore_from_auth_state() ***/ /** * lim_encrypt_auth_frame() * ***FUNCTION: * This function is called in lim_process_auth_frame() function * to encrypt Authentication frame3 body. * ***LOGIC: * ***ASSUMPTIONS: * NA * ***NOTE: * NA * * @param pMac Pointer to Global MAC structure * @param keyId key id to used * @param pKey Pointer to the key to be used for encryption * @param pPlainText Pointer to the body to be encrypted * @param pEncrBody Pointer to the encrypted auth frame body * @param keyLength 8 (WEP40) or 16 (WEP104) * @return None */ void lim_encrypt_auth_frame(tpAniSirGlobal pMac, uint8_t keyId, uint8_t *pKey, uint8_t *pPlainText, uint8_t *pEncrBody, uint32_t keyLength) { uint8_t seed[LIM_SEED_LENGTH], icv[SIR_MAC_WEP_ICV_LENGTH]; uint16_t frame_len; frame_len = ((tpSirMacAuthFrameBody)pPlainText)->length + SIR_MAC_AUTH_FRAME_INFO_LEN + SIR_MAC_CHALLENGE_ID_LEN; keyLength += 3; /* Bytes 3-7 of seed is key */ qdf_mem_copy((uint8_t *) &seed[3], pKey, keyLength - 3); /* Compute CRC-32 and place them in last 4 bytes of plain text */ lim_compute_crc32(icv, pPlainText, frame_len); qdf_mem_copy(pPlainText + frame_len, icv, SIR_MAC_WEP_ICV_LENGTH); /* Run RC4 on plain text with the seed */ lim_rc4(pEncrBody + SIR_MAC_WEP_IV_LENGTH, (uint8_t *) pPlainText, seed, keyLength, frame_len + SIR_MAC_WEP_ICV_LENGTH); /* Prepare IV */ pEncrBody[0] = seed[0]; pEncrBody[1] = seed[1]; pEncrBody[2] = seed[2]; pEncrBody[3] = keyId << 6; } /****** end lim_encrypt_auth_frame() ******/ /** * lim_compute_crc32() * ***FUNCTION: * This function is called to compute CRC-32 on a given source. * Used while encrypting/decrypting Authentication frame 3. * ***LOGIC: * ***ASSUMPTIONS: * NA * ***NOTE: * NA * * @param pDest Destination location for computed CRC * @param pSrc Source location to be CRC computed * @param len Length over which CRC to be computed * @return None */ void lim_compute_crc32(uint8_t *pDest, uint8_t *pSrc, uint16_t len) { uint32_t crc; int i; crc = 0; crc = ~crc; while (len-- > 0) crc = lim_crc_update(crc, *pSrc++); crc = ~crc; for (i = 0; i < SIR_MAC_WEP_IV_LENGTH; i++) { pDest[i] = (uint8_t) crc; crc >>= 8; } } /****** end lim_compute_crc32() ******/ /** * lim_rc4() * ***FUNCTION: * This function is called to run RC4 algorithm. Called while * encrypting/decrypting Authentication frame 3. * ***LOGIC: * ***ASSUMPTIONS: * NA * ***NOTE: * NA * * @param pDest Destination location for encrypted text * @param pSrc Source location to be encrypted * @param seed Contains seed (IV + key) for PRNG * @param keyLength 8 (WEP40) or 16 (WEP104) * @param frameLen Length of the frame * * @return None */ void lim_rc4(uint8_t *pDest, uint8_t *pSrc, uint8_t *seed, uint32_t keyLength, uint16_t frameLen) { typedef struct { uint8_t i, j; uint8_t sbox[256]; } tRC4Context; tRC4Context ctx; { uint16_t i, j, k; /* */ /* Initialize sbox using seed */ /* */ ctx.i = ctx.j = 0; for (i = 0; i < 256; i++) ctx.sbox[i] = (uint8_t) i; j = 0; k = 0; for (i = 0; i < 256; i++) { uint8_t temp; if (k < LIM_SEED_LENGTH) j = (uint8_t) (j + ctx.sbox[i] + seed[k]); temp = ctx.sbox[i]; ctx.sbox[i] = ctx.sbox[j]; ctx.sbox[j] = temp; if (++k >= keyLength) k = 0; } } { uint8_t i = ctx.i; uint8_t j = ctx.j; uint16_t len = frameLen; while (len-- > 0) { uint8_t temp1, temp2; i = (uint8_t) (i + 1); temp1 = ctx.sbox[i]; j = (uint8_t) (j + temp1); ctx.sbox[i] = temp2 = ctx.sbox[j]; ctx.sbox[j] = temp1; temp1 = (uint8_t) (temp1 + temp2); temp1 = ctx.sbox[temp1]; temp2 = (uint8_t) (pSrc ? *pSrc++ : 0); *pDest++ = (uint8_t) (temp1 ^ temp2); } ctx.i = i; ctx.j = j; } } /****** end lim_rc4() ******/ /** * lim_decrypt_auth_frame() * ***FUNCTION: * This function is called in lim_process_auth_frame() function * to decrypt received Authentication frame3 body. * ***LOGIC: * ***ASSUMPTIONS: * NA * ***NOTE: * NA * * @param pMac Pointer to Global MAC structure * @param pKey Pointer to the key to be used for decryption * @param pEncrBody Pointer to the body to be decrypted * @param pPlainBody Pointer to the decrypted body * @param keyLength 8 (WEP40) or 16 (WEP104) * * @return Decrypt result - eSIR_SUCCESS for success and * LIM_DECRYPT_ICV_FAIL for ICV mismatch. * If decryption is a success, pBody will * have decrypted auth frame body. */ uint8_t lim_decrypt_auth_frame(tpAniSirGlobal pMac, uint8_t *pKey, uint8_t *pEncrBody, uint8_t *pPlainBody, uint32_t keyLength, uint16_t frameLen) { uint8_t seed[LIM_SEED_LENGTH], icv[SIR_MAC_WEP_ICV_LENGTH]; int i; keyLength += 3; /* Bytes 0-2 of seed is received IV */ qdf_mem_copy((uint8_t *) seed, pEncrBody, SIR_MAC_WEP_IV_LENGTH - 1); /* Bytes 3-7 of seed is key */ qdf_mem_copy((uint8_t *) &seed[3], pKey, keyLength - 3); /* Run RC4 on encrypted text with the seed */ lim_rc4(pPlainBody, pEncrBody + SIR_MAC_WEP_IV_LENGTH, seed, keyLength, frameLen); /* Compute CRC-32 and place them in last 4 bytes of encrypted body */ lim_compute_crc32(icv, (uint8_t *) pPlainBody, (frameLen - SIR_MAC_WEP_ICV_LENGTH)); /* Compare RX_ICV with computed ICV */ for (i = 0; i < SIR_MAC_WEP_ICV_LENGTH; i++) { pe_debug("computed ICV%d[%x], rxed ICV%d[%x]", i, icv[i], i, pPlainBody[frameLen - SIR_MAC_WEP_ICV_LENGTH + i]); if (icv[i] != pPlainBody[frameLen - SIR_MAC_WEP_ICV_LENGTH + i]) return LIM_DECRYPT_ICV_FAIL; } return eSIR_SUCCESS; } /****** end lim_decrypt_auth_frame() ******/ /** * lim_post_sme_set_keys_cnf * * A utility API to send MLM_SETKEYS_CNF to SME */ void lim_post_sme_set_keys_cnf(tpAniSirGlobal pMac, tLimMlmSetKeysReq *pMlmSetKeysReq, tLimMlmSetKeysCnf *mlmSetKeysCnf) { /* Prepare and Send LIM_MLM_SETKEYS_CNF */ qdf_copy_macaddr(&mlmSetKeysCnf->peer_macaddr, &pMlmSetKeysReq->peer_macaddr); /* Free up buffer allocated for mlmSetKeysReq */ qdf_mem_zero(pMlmSetKeysReq, sizeof(tLimMlmSetKeysReq)); qdf_mem_free(pMlmSetKeysReq); pMac->lim.gpLimMlmSetKeysReq = NULL; lim_post_sme_message(pMac, LIM_MLM_SETKEYS_CNF, (uint32_t *) mlmSetKeysCnf); } /** * lim_send_set_bss_key_req() * ***FUNCTION: * This function is called from lim_process_mlm_set_keys_req(), * when PE is trying to setup the Group Keys related * to a specified encryption type * ***LOGIC: * ***ASSUMPTIONS: * NA * ***NOTE: * NA * * @param pMac Pointer to Global MAC structure * @param pMlmSetKeysReq Pointer to MLM_SETKEYS_REQ buffer * @return none */ void lim_send_set_bss_key_req(tpAniSirGlobal pMac, tLimMlmSetKeysReq *pMlmSetKeysReq, tpPESession psessionEntry) { tSirMsgQ msgQ; tpSetBssKeyParams pSetBssKeyParams = NULL; tLimMlmSetKeysCnf mlmSetKeysCnf; tSirRetStatus retCode; uint32_t val = 0; if (pMlmSetKeysReq->numKeys > SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS) { pe_debug("numKeys = %d is more than SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS", pMlmSetKeysReq->numKeys); /* Respond to SME with error code */ mlmSetKeysCnf.resultCode = eSIR_SME_INVALID_PARAMETERS; goto end; } /* Package WMA_SET_BSSKEY_REQ message parameters */ pSetBssKeyParams = qdf_mem_malloc(sizeof(tSetBssKeyParams)); if (NULL == pSetBssKeyParams) { pe_err("Unable to allocate memory during SET_BSSKEY"); /* Respond to SME with error code */ mlmSetKeysCnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; goto end; } /* Update the WMA_SET_BSSKEY_REQ parameters */ pSetBssKeyParams->bssIdx = psessionEntry->bssIdx; pSetBssKeyParams->encType = pMlmSetKeysReq->edType; if (eSIR_SUCCESS != wlan_cfg_get_int(pMac, WNI_CFG_SINGLE_TID_RC, &val)) pe_warn("Unable to read WNI_CFG_SINGLE_TID_RC"); pSetBssKeyParams->singleTidRc = (uint8_t) val; /* Update PE session Id */ pSetBssKeyParams->sessionId = psessionEntry->peSessionId; pSetBssKeyParams->smesessionId = pMlmSetKeysReq->smesessionId; if (pMlmSetKeysReq->key[0].keyId && ((pMlmSetKeysReq->edType == eSIR_ED_WEP40) || (pMlmSetKeysReq->edType == eSIR_ED_WEP104)) ) { /* IF the key id is non-zero and encryption type is WEP, Send all the 4 * keys to HAL with filling the key at right index in pSetBssKeyParams->key. */ pSetBssKeyParams->numKeys = SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS; qdf_mem_copy((uint8_t *) &pSetBssKeyParams-> key[pMlmSetKeysReq->key[0].keyId], (uint8_t *) &pMlmSetKeysReq->key[0], sizeof(pMlmSetKeysReq->key[0])); } else { pSetBssKeyParams->numKeys = pMlmSetKeysReq->numKeys; qdf_mem_copy((uint8_t *) &pSetBssKeyParams->key, (uint8_t *) &pMlmSetKeysReq->key, sizeof(tSirKeys) * pMlmSetKeysReq->numKeys); } SET_LIM_PROCESS_DEFD_MESGS(pMac, false); msgQ.type = WMA_SET_BSSKEY_REQ; msgQ.reserved = 0; msgQ.bodyptr = pSetBssKeyParams; msgQ.bodyval = 0; pe_debug("Sending WMA_SET_BSSKEY_REQ..."); MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); retCode = wma_post_ctrl_msg(pMac, &msgQ); if (eSIR_SUCCESS != retCode) { pe_err("Posting SET_BSSKEY to HAL failed, reason=%X", retCode); /* Respond to SME with LIM_MLM_SETKEYS_CNF */ mlmSetKeysCnf.resultCode = eSIR_SME_HAL_SEND_MESSAGE_FAIL; qdf_mem_zero(pSetBssKeyParams, sizeof(tSetBssKeyParams)); qdf_mem_free(pSetBssKeyParams); } else return; /* Continue after WMA_SET_BSSKEY_RSP... */ end: lim_post_sme_set_keys_cnf(pMac, pMlmSetKeysReq, &mlmSetKeysCnf); } /** * @function : lim_send_set_sta_key_req() * * @brief : This function is called from lim_process_mlm_set_keys_req(), * when PE is trying to setup the Unicast Keys related * to a specified STA with specified encryption type * ***LOGIC: * ***ASSUMPTIONS: * NA * ***NOTE: * NA * * @param pMac Pointer to Global MAC structure * @param pMlmSetKeysReq Pointer to MLM_SETKEYS_REQ buffer * @param staIdx STA index for which the keys are being set * @param defWEPIdx The default WEP key index [0..3] * @return none */ void lim_send_set_sta_key_req(tpAniSirGlobal pMac, tLimMlmSetKeysReq *pMlmSetKeysReq, uint16_t staIdx, uint8_t defWEPIdx, tpPESession sessionEntry, bool sendRsp) { tSirMsgQ msgQ; tpSetStaKeyParams pSetStaKeyParams = NULL; tLimMlmSetKeysCnf mlmSetKeysCnf; tSirRetStatus retCode; uint32_t val = 0; /* Package WMA_SET_STAKEY_REQ message parameters */ pSetStaKeyParams = qdf_mem_malloc(sizeof(tSetStaKeyParams)); if (NULL == pSetStaKeyParams) { pe_err("Unable to allocate memory during SET_BSSKEY"); goto fail; } /* Update the WMA_SET_STAKEY_REQ parameters */ pSetStaKeyParams->staIdx = staIdx; pSetStaKeyParams->encType = pMlmSetKeysReq->edType; if (eSIR_SUCCESS != wlan_cfg_get_int(pMac, WNI_CFG_SINGLE_TID_RC, &val)) pe_warn("Unable to read WNI_CFG_SINGLE_TID_RC"); pSetStaKeyParams->singleTidRc = (uint8_t) val; /* Update PE session ID */ pSetStaKeyParams->sessionId = sessionEntry->peSessionId; /** * For WEP - defWEPIdx indicates the default WEP * Key to be used for TX * For all others, there's just one key that can * be used and hence it is assumed that * defWEPIdx = 0 (from the caller) */ pSetStaKeyParams->defWEPIdx = defWEPIdx; pSetStaKeyParams->smesessionId = pMlmSetKeysReq->smesessionId; qdf_copy_macaddr(&pSetStaKeyParams->peer_macaddr, &pMlmSetKeysReq->peer_macaddr); if (sendRsp == true) { /** Store the Previous MlmState*/ sessionEntry->limPrevMlmState = sessionEntry->limMlmState; SET_LIM_PROCESS_DEFD_MESGS(pMac, false); } if (LIM_IS_IBSS_ROLE(sessionEntry) && !pMlmSetKeysReq->key[0].unicast) { if (sendRsp == true) sessionEntry->limMlmState = eLIM_MLM_WT_SET_STA_BCASTKEY_STATE; msgQ.type = WMA_SET_STA_BCASTKEY_REQ; } else { if (sendRsp == true) sessionEntry->limMlmState = eLIM_MLM_WT_SET_STA_KEY_STATE; msgQ.type = WMA_SET_STAKEY_REQ; } MTRACE(mac_trace (pMac, TRACE_CODE_MLM_STATE, sessionEntry->peSessionId, sessionEntry->limMlmState)); /** * In the Case of WEP_DYNAMIC, ED_TKIP and ED_CCMP * the Key[0] contains the KEY, so just copy that alone, * for the case of WEP_STATIC the hal gets the key from cfg */ switch (pMlmSetKeysReq->edType) { case eSIR_ED_WEP40: case eSIR_ED_WEP104: /* FIXME! Is this OK? */ if (0 == pMlmSetKeysReq->numKeys) { uint32_t i; for (i = 0; i < SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS; i++) { qdf_mem_copy((uint8_t *) &pSetStaKeyParams-> key[i], (uint8_t *) &pMlmSetKeysReq-> key[i], sizeof(tSirKeys)); } pSetStaKeyParams->wepType = eSIR_WEP_STATIC; sessionEntry->limMlmState = eLIM_MLM_WT_SET_STA_KEY_STATE; MTRACE(mac_trace (pMac, TRACE_CODE_MLM_STATE, sessionEntry->peSessionId, sessionEntry->limMlmState)); } else { /*This case the keys are coming from upper layer so need to fill the * key at the default wep key index and send to the HAL */ if (defWEPIdx < SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS) { qdf_mem_copy((uint8_t *) &pSetStaKeyParams-> key[defWEPIdx], (uint8_t *) &pMlmSetKeysReq-> key[0], sizeof(pMlmSetKeysReq->key[0])); pMlmSetKeysReq->numKeys = SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS; } else { pe_err("Wrong Key Index %d", defWEPIdx); goto free_sta_key; } } break; case eSIR_ED_TKIP: case eSIR_ED_CCMP: case eSIR_ED_GCMP: case eSIR_ED_GCMP_256: #ifdef FEATURE_WLAN_WAPI case eSIR_ED_WPI: #endif { qdf_mem_copy((uint8_t *) &pSetStaKeyParams->key, (uint8_t *) &pMlmSetKeysReq->key[0], sizeof(tSirKeys)); } break; default: break; } pSetStaKeyParams->sendRsp = sendRsp; msgQ.reserved = 0; msgQ.bodyptr = pSetStaKeyParams; msgQ.bodyval = 0; pe_debug("Sending WMA_SET_STAKEY_REQ..."); MTRACE(mac_trace_msg_tx(pMac, sessionEntry->peSessionId, msgQ.type)); retCode = wma_post_ctrl_msg(pMac, &msgQ); if (eSIR_SUCCESS != retCode) { pe_err("Posting SET_STAKEY to HAL failed, reason=%X", retCode); goto free_sta_key; } else return; /* Continue after WMA_SET_STAKEY_RSP... */ free_sta_key: qdf_mem_zero(pSetStaKeyParams, sizeof(tSetStaKeyParams)); qdf_mem_free(pSetStaKeyParams); fail: /* Respond to SME with LIM_MLM_SETKEYS_CNF */ mlmSetKeysCnf.resultCode = eSIR_SME_HAL_SEND_MESSAGE_FAIL; if (sendRsp == true) lim_post_sme_set_keys_cnf(pMac, pMlmSetKeysReq, &mlmSetKeysCnf); }