blob: ccf02014e6dc8f9c52dd2d0597ef3a778a225d14 [file] [log] [blame]
/*
* 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;
/* 'Change' timer for future activations */
lim_deactivate_and_change_timer(pMac, eLIM_AUTH_RETRY_TIMER);
/* 'Change' timer for future activations */
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_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;
} 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_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);
}