blob: fcbc6e494a2b648d9494a93b95fb676286ada36a [file] [log] [blame]
/*
* Copyright (c) 2012-2013 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*
* This file was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
/*
* $File: //depot/software/projects/feature_branches/gen5_phase1/os/linux/classic/ap/apps/ssm/auth8021x/ani8021xAuthRsnFsm.c $
*
* Contains definitions for the RSN EAPOL-Key FSM on the
* authenticator side. This is based on 802.11i.
*
* Author: Mayank D. Upadhyay
* Date: 19-December-2002
* History:-
* Date Modified by Modification Information
* ------------------------------------------------------
*
*/
#include "vos_types.h"
#include "bapRsnSsmServices.h"
#include "bapRsnSsmEapol.h"
#include "bapRsnErrors.h"
#include "bapInternal.h"
#include "bapRsn8021xFsm.h"
#include "bapRsn8021xAuthFsm.h"
#include "vos_utils.h"
#include "vos_memory.h"
#include "vos_timer.h"
#include "bapRsnTxRx.h"
#include "bapRsnSsmAesKeyWrap.h"
#include "btampFsm.h"
// The different states that this FSM transitions through
#define DISCONNECT 0
#define DISCONNECTED 1
#define INITIALIZE 2
#define AUTHENTICATION 3
#define AUTHENTICATION_2 4
#define GET_PSK 5
#define GET_EAP_KEY 6
#define PTK_START 7
#define PTK_INIT_NEGO 8
#define PTK_INIT_NEGO_TX 9
#define PTK_INIT_DONE 10
#define UPDATE_KEYS_REQ 11
#define INTEG_FAILURE 12
#define KEY_UPDATE 13
#define NUM_STATES (KEY_UPDATE + 1)
static tAuthRsnFsmConsts authConsts = { 2000, 3 }; //timeout, retry limit
static v_U8_t aniSsmIeRsnOui[] = ANI_SSM_IE_RSN_OUI;
/**************************************
* Static functions in this module
**************************************/
static
int zeroOutPtk(tAuthRsnFsm *fsm);
static
int stopAllTimers(tAuthRsnFsm *fsm);
static
int checkMic(tAuthRsnFsm *fsm,
tAniEapolKeyAvailEventData *data);
static
int checkLocalReplayCounter(tAuthRsnFsm *fsm,
tAniEapolKeyAvailEventData *data);
static
int checkPeerReplayCounter(tAuthRsnFsm *fsm,
tAniEapolKeyAvailEventData *data);
static int checkInfoElement(tAuthRsnFsm *fsm,
tAniEapolKeyAvailEventData *data);
static
int derivePtk(tAuthRsnFsm *fsm,
tAniEapolKeyAvailEventData *data);
static int checkTransition(tAuthRsnFsm *fsm, void *arg);
static int
gotoStateInit(tAuthRsnFsm *fsm);
static void msg2TimerCallback( void * );
static void msg4TimerCallback( void * );
static int authRsnRxFrameHandler( v_PVOID_t pvosGCtx, vos_pkt_t *pPacket );
static int authRsnTxCompleteHandler( v_PVOID_t pvosGCtx, vos_pkt_t *pPacket, VOS_STATUS retStatus );
/********************************
* Functions Forward Declarations
********************************/
int authRsnAuthStartEventHandler( tAuthRsnFsm *fsm );
int authRsnAuthDisconEventHandler( tAuthRsnFsm *fsm );
/*************************
* The exported functions
*************************/
/**
* authRsnFsmInit
*
* FUNCTION:
* Initializes the constants and the callbacks needed by this FSM
* module.
*
* @param consts the various constant values needed by this FSM
* @param cb callbacks to the various procedures needed by this FSM
*
* @return ANI_OK if the operation succeeds
*/
int
authRsnFsmInit(tAuthRsnFsmConsts *constsIn)
{
// TODO: Read the constants in from config
// authConsts = *constsIn;
authConsts.timeoutPeriod = 2000; //ms
authConsts.maxTries = 3;
return ANI_OK;
}
/**
* authRsnFsmCreate
*
* FUNCTION
* Allocates and initializes the state of an RSN key FSM instance for
* the given STA context.
*
* @parm staCtx the STA context whose instance is being created
* @param pskBased pass in eANI_BOOLEAN_TRUE is this STA is to be
* authenticated based on a pre-shared key as opposed to EAP.
*
* @return ANI_OK if the operation succeeds
*/
int
authRsnFsmCreate(tBtampContext *ctx)
{
int retVal = ANI_OK;
tAuthRsnFsm *fsm = &ctx->uFsm.authFsm;
// First, clear everything out
vos_mem_zero( fsm, sizeof(tAuthRsnFsm));
if( !VOS_IS_STATUS_SUCCESS( bapRsnRegisterTxRxCallbacks( authRsnTxCompleteHandler,
authRsnRxFrameHandler ) ) )
{
return ANI_ERROR;
}
if( !VOS_IS_STATUS_SUCCESS( bapRsnRegisterRxCallback( ctx->pvosGCtx ) ) )
{
return ANI_ERROR;
}
// Allocate the station context
fsm->staCtx = (tStaContext *)vos_mem_malloc( sizeof(tStaContext) );
if (fsm->staCtx == NULL)
{
retVal = ANI_E_MALLOC_FAILED;
VOS_ASSERT( 0 );
goto error;
}
// Clear out the station context
vos_mem_zero( fsm->staCtx, sizeof(tStaContext) );
fsm->ctx = ctx;
fsm->staCtx->authRsnFsm = fsm;
//Only support CCMP
fsm->staCtx->pwCipherType = eCSR_ENCRYPT_TYPE_AES;
if( !VOS_IS_STATUS_SUCCESS( vos_timer_init( &fsm->msg2Timer, VOS_TIMER_TYPE_SW, msg2TimerCallback, fsm ) ) )
{
retVal = ANI_E_MALLOC_FAILED;
VOS_ASSERT( 0 );
goto error;
}
if( !VOS_IS_STATUS_SUCCESS( vos_timer_init( &fsm->msg4Timer, VOS_TIMER_TYPE_SW, msg4TimerCallback, fsm ) ) )
{
retVal = ANI_E_MALLOC_FAILED;
VOS_ASSERT( 0 );
goto error;
}
retVal = aniAsfPacketAllocateExplicit(&fsm->lastEapol,
RSN_MAX_PACKET_SIZE,
EAPOL_TX_HEADER_SIZE );
if (retVal != ANI_OK)
{
VOS_ASSERT( 0 );
goto error;
}
aniAsfPacketAllocate(&fsm->staCtx->pmk);
if (fsm->staCtx->pmk == NULL)
{
retVal = ANI_E_MALLOC_FAILED;
VOS_ASSERT( 0 );
goto error;
}
aniAsfPacketAllocateExplicit(&fsm->staCtx->ieSta,
RSN_IE_MAX_PACKET_SIZE,
RSN_IE_HEADER_SIZE );
if (fsm->staCtx->ieSta == NULL)
{
retVal = ANI_E_MALLOC_FAILED;
VOS_ASSERT( 0 );
goto error;
}
fsm->cryptHandle = 0;
if( !VOS_IS_STATUS_SUCCESS( vos_crypto_init( &fsm->cryptHandle ) ) )
{
retVal = ANI_E_FAILED;
VOS_ASSERT( 0 );
goto error;
}
fsm->currentState = INITIALIZE;
gotoStateInit(fsm);
//We can call this function here because it is connected at this time
authRsnFsmProcessEvent( fsm, RSN_FSM_AUTH_START, NULL );
return ANI_OK;
error:
authRsnFsmFree(ctx);
return retVal;
}
/**
* authRsnFsmFree
*
* FUNCTION
* Frees a previously allocated RSN Key FSM in a STA context. If the
* RSN Key FSM is not yet allocated, then this is an error.
*
* @param ctx the STA context whose FSM instance is to be freed
*
* @return ANI_OK if the operation succeeds
*/
int
authRsnFsmFree(tBtampContext *ctx)
{
tAuthRsnFsm *fsm = &ctx->uFsm.authFsm;
VOS_ASSERT(fsm);
if( fsm->cryptHandle)
{
vos_crypto_deinit( fsm->cryptHandle );
}
bapRsnClearTxRxCallbacks();
if ( fsm->staCtx )
{
fsm->staCtx->authRsnFsm = NULL;
}
if ( VOS_TIMER_STATE_UNUSED != fsm->msg2Timer.state ) vos_timer_destroy( &fsm->msg2Timer );
if ( VOS_TIMER_STATE_UNUSED != fsm->msg4Timer.state ) vos_timer_destroy( &fsm->msg4Timer );
if (fsm->lastEapol)
{
aniAsfPacketFree(fsm->lastEapol);
fsm->lastEapol = NULL;
}
if( fsm->staCtx )
{
if( fsm->staCtx->pmk )
{
aniAsfPacketFree( fsm->staCtx->pmk );
fsm->staCtx->pmk = NULL;
}
vos_mem_free(fsm->staCtx);
fsm->staCtx = NULL;
}
vos_mem_zero( fsm, sizeof(tAuthRsnFsm) );
return ANI_OK;
}
/**
* authRsnFsmProcessEvent
*
* FUNCTION
* Passes an event to the RSN key FSM instance for immediate processing.
*
* @param fsm the RSN Key FSM instance
* @param eventId the AAG event to process
* @param arg an optional argument for this event
*
* @return ANI_OK if the operation succeeds
*/
int
authRsnFsmProcessEvent(tAuthRsnFsm *fsm, tRsnFsmEvent eventId, void *arg)
{
VOS_ASSERT(fsm);
switch (eventId) {
case RSN_FSM_TIMER_EXPIRED:
// Proceed straight to checkTransition
break;
case RSN_FSM_AUTH_START:
fsm->authReq = eANI_BOOLEAN_TRUE;
authRsnAuthStartEventHandler(fsm);
break;
case RSN_FSM_EAPOL_FRAME_AVAILABLE:
fsm->eapolAvail = eANI_BOOLEAN_TRUE;
break;
case RSN_FSM_DISCONNECT:
fsm->disconnect = eANI_BOOLEAN_TRUE;
authRsnAuthDisconEventHandler(fsm);
break;
case RSN_FSM_INTEG_FAILED:
fsm->integFailed = eANI_BOOLEAN_TRUE;
break;
default:
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
"Unknown event for Auth RSN Key Fsm: %d\n", eventId);
VOS_ASSERT( 0 );
return ANI_E_ILLEGAL_ARG;
break;
}
checkTransition(fsm, arg);
return ANI_OK;
}
int
authRsnAuthStartEventHandler(tAuthRsnFsm *fsm)
{
static v_U8_t btampStaRSNIE[] = {0x30, 0x14, 0x01, 0x00, 0x00, 0x0f, 0xac, 0x04, 0x01, 0x00,
0x00, 0x0f, 0xac, 0x04, 0x01, 0x00, 0x00, 0x0f, 0xac, 0x02, 0x00, 0x00 };
// Copy required info
vos_mem_copy( &fsm->staCtx->authMac, fsm->ctx->self_mac_addr, 6);
vos_mem_copy( &fsm->staCtx->suppMac, fsm->ctx->peer_mac_addr, 6);
aniAsfPacketAppendBuffer( fsm->staCtx->pmk, fsm->ctx->key_material, fsm->ctx->key_length);
aniAsfPacketAppendBuffer( fsm->staCtx->ieSta, btampStaRSNIE, sizeof(btampStaRSNIE));
return ANI_OK;
}
int
authRsnAuthDisconEventHandler(tAuthRsnFsm *fsm)
{
// Free Stactx .?
return ANI_OK;
}
/***********************
* The static functions
***********************/
static int
gotoStateInit(tAuthRsnFsm *fsm)
{
fsm->currentState = INITIALIZE;
// TODO: Move this to a global position which applies to WEP as
// well
//initGlobalKeys = eANI_BOOLEAN_FALSE;
fsm->authReq = eANI_BOOLEAN_FALSE;
fsm->eapolAvail = eANI_BOOLEAN_FALSE;
fsm->disconnect = eANI_BOOLEAN_FALSE;
fsm->integFailed = eANI_BOOLEAN_FALSE;
fsm->numTries = 0;
// Create two replay counter's..one for our requests, and another
// for STA's requests. Initialize the first one randomly.
aniSsmReplayCtrCreate(fsm->cryptHandle, &fsm->staCtx->localReplayCtr,
ANI_EAPOL_KEY_RSN_RSC_SIZE, 0);
aniSsmReplayCtrCreate(fsm->cryptHandle, &fsm->staCtx->peerReplayCtr,
ANI_EAPOL_KEY_RSN_RSC_SIZE, 0);
return ANI_OK;
}
static int
gotoStateAuthentication(tAuthRsnFsm *fsm)
{
fsm->currentState = AUTHENTICATION;
zeroOutPtk(fsm);
fsm->authReq = eANI_BOOLEAN_FALSE;
checkTransition(fsm, NULL); // UCT rule
return ANI_OK;
}
static int
gotoStateAuthentication2(tAuthRsnFsm *fsm)
{
fsm->currentState = AUTHENTICATION_2;
if( !VOS_IS_STATUS_SUCCESS( vos_rand_get_bytes( fsm->cryptHandle, fsm->aNonce, ANI_EAPOL_KEY_RSN_NONCE_SIZE ) ) )
{
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
"gotoStateAuthentication2 fail to get random number. Disconnect\n" );
bapAuthDisconnect( fsm->ctx );
return ANI_ERROR;
}
fsm->numTries = 0;
checkTransition(fsm, NULL); // UCT rule
return ANI_OK;
}
static int
gotoStateGetPsk(tAuthRsnFsm *fsm)
{
//This is simply a transaction because we already have the PMK. We always do.
fsm->currentState = GET_PSK;
fsm->numTries = 0;
checkTransition(fsm, NULL);
return ANI_OK;
}
static int
gotoStatePtkStart(tAuthRsnFsm *fsm)
{
tAniEapolRsnKeyDesc txDesc;
int retVal;
fsm->msg2TimeOut = VOS_FALSE;
fsm->currentState = PTK_START;
// Create a new packet if we don't have one to retransmit
//if (aniAsfPacketGetLen(fsm->lastEapol) == 0)
#if 0
if( fsm->lastEapol )
{
aniAsfPacketFree( fsm->lastEapol );
fsm->lastEapol = NULL;
retVal = aniAsfPacketAllocateExplicit(&fsm->lastEapol,
RSN_MAX_PACKET_SIZE,
EAPOL_TX_HEADER_SIZE );
#endif
aniAsfPacketEmptyExplicit(fsm->lastEapol,
EAPOL_TX_HEADER_SIZE);
//}
// if (1)
//{
vos_mem_zero( &txDesc, sizeof(txDesc) );
// The Key Information bits...
if (fsm->staCtx->pwCipherType == eCSR_ENCRYPT_TYPE_AES)
{
txDesc.info.keyDescVers = ANI_EAPOL_KEY_DESC_VERS_AES;
}
else {
return ANI_E_ILLEGAL_ARG;
}
txDesc.info.unicastFlag = eANI_BOOLEAN_TRUE;
txDesc.info.ackFlag = eANI_BOOLEAN_TRUE;
// The other fields...
txDesc.keyLen = aagGetKeyMaterialLen(fsm->staCtx->pwCipherType);
aniSsmReplayCtrNext(fsm->staCtx->localReplayCtr, txDesc.replayCounter);
vos_mem_copy(txDesc.keyNonce, fsm->aNonce, sizeof(txDesc.keyNonce));
retVal = aniEapolWriteKey(fsm->cryptHandle,
fsm->lastEapol,
fsm->staCtx->suppMac,
fsm->staCtx->authMac,
ANI_EAPOL_KEY_DESC_TYPE_RSN_NEW,
&txDesc,
NULL, 0);
if( !ANI_IS_STATUS_SUCCESS( retVal ) )
{
return retVal;
}
#if 0
}
else {
retransmit = eANI_BOOLEAN_TRUE;
}
#endif
if( VOS_IS_STATUS_SUCCESS( bapRsnSendEapolFrame( fsm->ctx->pvosGCtx, fsm->lastEapol ) ) )
{
retVal = ANI_OK;
}
else
{
//we fail to send the eapol frame disconnect
bapAuthDisconnect( fsm->ctx );
retVal = ANI_ERROR;
}
return retVal;
}
static int
gotoStatePtkInitNego(tAuthRsnFsm *fsm, void *arg)
{
fsm->currentState = PTK_INIT_NEGO;
// Replay counter will be automatically updated when we create a
// new packet
fsm->numTries = 0;
aniAsfPacketEmptyExplicit(fsm->lastEapol,
EAPOL_TX_HEADER_SIZE);
checkTransition(fsm, arg);
return ANI_OK;
}
// Use this only with trusted IE like the one we generated locally
static int
getRsnIeFromAdvertizedIes(tAuthRsnFsm *fsm, v_U8_t **rsnIe)
{
int retVal = ANI_E_ILLEGAL_ARG;
v_U8_t *ptr = fsm->advertizedRsnIe;
if (*ptr == ANI_SSM_IE_RSN_ELEM_ID)
{
retVal = *(ptr + 1) + 2; // The L field from the TLV + 2B TL
*rsnIe = ptr;
}
return retVal;
}
// Use this only with trusted IE like the one we generated locally
static void
addPad(
v_U8_t *dataBytes,
int dataLen,
int padLen)
{
int i;
// The first byte of padding is 0xdd. The rest are 0x00's
// See 802.11i section 8.5.2 subsection "Key Data Encapsulation"
for ( i=dataLen ; i < dataLen+padLen; i++)
{
if ( i == dataLen )
{
dataBytes[i] = 0xdd;
}
else {
dataBytes[i] = 0x00;
}
}
return;
}
/**
* aagAppendGroupKeyForRsn
*
* Appends the group key to the packet in the RSN key encapulation format.
*
* @param packet - the packet to append to
* @param radioId - the radio whose group key needs to be appended
*
* @return ANI_OK if the operation succeeds
*/
#define STATIC_WEP_KEY_LEN 16
#define GROUP_KEY_ID 0
#define ANI_SSM_IE_RSN_KEY_DATA_ENCAPS_ID 0xDD
#define ANI_SSM_IE_RSN_GROUP_KEY_DATA_ENCAPS_ID 1
int
aagAppendGroupKeyForRsn(tAniPacket *packet)
{
#if 0
tAniPacket *groupKey = NULL;
#else
tANI_U8 groupKey[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15};
#endif
tANI_U8 *groupKeyBytes = NULL;
tANI_U8 *lenPtr = NULL;
tANI_U8 *endPtr = NULL;
int groupKeyLen;
int retVal;
#if 0
groupKey = AAG_GROUP_KEY(radioId);
if (groupKey == NULL) {
ANI_AAG_LOG_E("Group key is not yet set on radio %d, id %d!",
radioId, AAG_GROUP_KEY_ID(radioId));
assert(0 && "Group key is still NULL!");
return ANI_E_FAILED;
}
groupKeyLen = aniAsfPacketGetBytes(groupKey, &groupKeyBytes);
CHECK_NO_ERROR(groupKeyLen);
if (aagConfig.logLevel >= LOG_INFO) {
ANI_AAG_LOG_D("Will encapsulate group key bytes %s",
aniAsfHexStr(groupKeyBytes, groupKeyLen));
}
#else
groupKeyBytes = groupKey;
groupKeyLen = STATIC_WEP_KEY_LEN;
#endif
/*
* Add the key data encapsulation needed for RSN/WPA2
*/
// The IE ID
retVal = aniAsfPacketAppend8(packet, ANI_SSM_IE_RSN_KEY_DATA_ENCAPS_ID);
//CHECK_NO_ERROR(retVal);
// Obtain the position for the length
aniAsfPacketGetBytesFromTail(packet, &lenPtr);
// Write out a dummy length - we'll fill this in later. It will be
// 6 bytes more than the length of the GTK
retVal = aniAsfPacketAppend8(packet, 0);
//CHECK_NO_ERROR(retVal);
// Copy the RSN OUI
retVal = aniAsfPacketAppendBuffer(packet, aniSsmIeRsnOui, sizeof(aniSsmIeRsnOui));
//CHECK_NO_ERROR(retVal);
// Indicate that the key type is group key
retVal = aniAsfPacketAppend8(packet, ANI_SSM_IE_RSN_GROUP_KEY_DATA_ENCAPS_ID);
//CHECK_NO_ERROR(retVal);
// Copy the key-id to the first two bits of the next byte
// Copy the Tx bit the third bit of the same byte
// (Here, I assume the Group Key is to be used for both STA Tx and Rx)
retVal = aniAsfPacketAppend8(
packet,
GROUP_KEY_ID );
//AAG_GROUP_KEY_ID(radioId) );
//CHECK_NO_ERROR(retVal);
retVal = aniAsfPacketMoveRight(packet, 1); // Reserved bits (1 byte)
//CHECK_NO_ERROR(retVal);
// Copy the real key bytes
retVal = aniAsfPacketAppendBuffer(packet, groupKeyBytes, groupKeyLen);
//CHECK_NO_ERROR(retVal);
// Calculate and enter the length of the entire encoding
aniAsfPacketGetBytesFromTail(packet, &endPtr);
*lenPtr = endPtr - (lenPtr + 1) ; // subtract one to avoid tail
return retVal;
}
static int
gotoStatePtkInitNegoTx(tAuthRsnFsm *fsm)
{
tAniEapolRsnKeyDesc txDesc;
v_BOOL_t retransmit = eANI_BOOLEAN_FALSE;
v_U8_t *rsnWpaIe = NULL;
int rsnWpaIeLen;
static tAniPacket *keyData;
// The longest length...the extra 8 bytes account for RSN key data
// encapsulation
v_U8_t paddedGroupKeyEncaps[1024];
int padLen = 0;
v_U8_t *groupKeyBytes;
int groupKeyLen;
v_U8_t *wrappedKey = NULL;
// Variables used for RC4 GTK wrap
//v_U8_t keyIv[ANI_EAPOL_KEY_RSN_IV_SIZE];
//v_U32_t keyIvLsb;
int retVal = 0;
//invalidate this
fsm->msg4TimeOut = VOS_FALSE;
fsm->currentState = PTK_INIT_NEGO_TX ;
if (keyData == NULL)
{
// Allocate the packet the first time around that you enter
retVal = aniAsfPacketAllocateExplicit(&keyData, 1024, 10);
if( !ANI_IS_STATUS_SUCCESS( retVal ) )
{
return retVal;
}
}
else {
// Just empty out the packet
aniAsfPacketEmptyExplicit(keyData, 10);
}
do
{
// Create a new EAPOL frame if we don't have one to retransmit
//if (aniAsfPacketGetLen(fsm->lastEapol) == 0)
#if 0
if( fsm->lastEapol )
{
aniAsfPacketFree( fsm->lastEapol );
fsm->lastEapol = NULL;
retVal = aniAsfPacketAllocateExplicit(&fsm->lastEapol,
RSN_MAX_PACKET_SIZE,
EAPOL_TX_HEADER_SIZE );
#endif
aniAsfPacketEmptyExplicit(fsm->lastEapol,
EAPOL_TX_HEADER_SIZE);
// }
if (1)
{
vos_mem_zero( &txDesc, sizeof(txDesc) );
// The Key Information bits...
if (fsm->staCtx->pwCipherType == eCSR_ENCRYPT_TYPE_AES)
{
txDesc.info.keyDescVers = ANI_EAPOL_KEY_DESC_VERS_AES;
}
else {
txDesc.info.keyDescVers = ANI_EAPOL_KEY_DESC_VERS_RC4;
}
txDesc.info.unicastFlag = eANI_BOOLEAN_TRUE;
txDesc.info.installFlag = eANI_BOOLEAN_TRUE;
txDesc.info.ackFlag = eANI_BOOLEAN_TRUE;
txDesc.info.micFlag = eANI_BOOLEAN_TRUE;
txDesc.keyLen = aagGetKeyMaterialLen(fsm->staCtx->pwCipherType);
aniSsmReplayCtrNext(fsm->staCtx->localReplayCtr, txDesc.replayCounter);
vos_mem_copy(txDesc.keyNonce, fsm->aNonce, sizeof(txDesc.keyNonce));
// Add the RSN IE (but not any WPA IE)
rsnWpaIeLen = getRsnIeFromAdvertizedIes(fsm, &rsnWpaIe);
if( !ANI_IS_STATUS_SUCCESS( rsnWpaIeLen) ) break;
retVal = aniAsfPacketAppendBuffer(keyData, rsnWpaIe, rsnWpaIeLen);
if( !ANI_IS_STATUS_SUCCESS( retVal ) ) break;
// Add the RSN group key encapsulation
retVal = aagAppendGroupKeyForRsn ( keyData );
if( !ANI_IS_STATUS_SUCCESS( retVal ) ) break;
groupKeyLen = aniAsfPacketGetBytes(keyData, &groupKeyBytes);
if( !ANI_IS_STATUS_SUCCESS( groupKeyLen ) )
{
retVal = ANI_E_FAILED;
break;
}
txDesc.info.secureFlag = eANI_BOOLEAN_TRUE;
txDesc.info.encKeyDataFlag = eANI_BOOLEAN_TRUE;
if ( fsm->staCtx->pwCipherType == eCSR_ENCRYPT_TYPE_AES )
{
/*
* Use the AES key wrap algorithm if either one of the pairwise
* key or the group key is an AES key.
*
* If the key being sent is not a multiple of
* ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE, then pad it with
* zeroes. e.g., if we are sending a WEP key of 5 or 13
* bytes.
*/
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
"AES Key Wrap invoked. groupKeyLen = %d", groupKeyLen);
padLen = groupKeyLen % ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE;
if (padLen != 0) {
padLen = ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE - padLen;
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
"Before AES Key Wrap: padLen = %d", padLen);
if (groupKeyLen + padLen > sizeof(paddedGroupKeyEncaps)) {
#if 0
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
"Cannot encode group key encapsulation of len %d and cipher type %s "
"to send to %s %s (aid %d, radio %d, user %s)",
groupKeyLen,
aniSsmIntGetCipherStr(AAG_GROUP_CIPHER(fsm->ctx->radioId)),
(fsm->ctx->bpIndicator ? "BP" : "STA"),
aniAsfHexStr(fsm->ctx->suppMac, sizeof(tAniMacAddr)),
fsm->ctx->aid,
fsm->ctx->radioId,
aagGetStaUserId(fsm->ctx));
#endif
retVal = ANI_E_FAILED;
}
// OK, after you compute the pad length, you need to
// add the padding - 0xdd followed by 0x00's
addPad( groupKeyBytes , groupKeyLen , padLen );
// add the padding length
groupKeyLen += padLen;
// IMMEDIATELY adjust the packet size to reflect the pad
aniAsfPacketMoveRight(keyData, padLen);
if( !ANI_IS_STATUS_SUCCESS( retVal) ) break;
}
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
"Before AES Key Wrap: padded groupKeyLen = %d", groupKeyLen);
retVal = aniSsmAesKeyWrap(fsm->cryptHandle, groupKeyBytes, groupKeyLen,
fsm->staCtx->ptk + ANI_EAPOL_KEY_RSN_MIC_SIZE,
ANI_EAPOL_KEY_RSN_ENC_KEY_SIZE,
&wrappedKey);
if( !ANI_IS_STATUS_SUCCESS( retVal) ) break;
// This doesn't work...
//groupKeyBytes = wrappedKey;
//groupKeyLen += ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE;
// ...here is the right way to do it
// Add the length of the prepended IV A[0]
if (NULL == wrappedKey)
{
break;
}
groupKeyLen += ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE;
vos_mem_copy( groupKeyBytes, wrappedKey, groupKeyLen);
// Free the array used to hold the wrapped key
if (wrappedKey) vos_mem_free( wrappedKey);
// IMMEDIATELY adjust the packet size to reflect the IV
aniAsfPacketMoveRight(keyData, ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE);
}
else {
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
"Auth RC4 Key Wrap invoked. groupKeyLen = %d", groupKeyLen);
}
txDesc.keyDataLen = aniAsfPacketGetBytes(keyData, &txDesc.keyData);
retVal = aniEapolWriteKey(fsm->cryptHandle,
fsm->lastEapol,
fsm->staCtx->suppMac,
fsm->staCtx->authMac,
ANI_EAPOL_KEY_DESC_TYPE_RSN_NEW,
&txDesc,
fsm->staCtx->ptk,
CSR_AES_KEY_LEN);
if( !ANI_IS_STATUS_SUCCESS( retVal) ) break;
}
else {
retransmit = eANI_BOOLEAN_TRUE;
}
if( VOS_IS_STATUS_SUCCESS( bapRsnSendEapolFrame( fsm->ctx->pvosGCtx, fsm->lastEapol ) ) )
{
retVal = ANI_OK;
}
else
{
//we fail to send the eapol frame disconnect
bapAuthDisconnect( fsm->ctx );
retVal = ANI_ERROR;
}
}while( 0 );
return retVal;
}
static int
gotoStatePtkInitDone(tAuthRsnFsm *fsm, tAniEapolKeyAvailEventData *data)
{
int retVal;
tAniEapolRsnKeyDesc *rxDesc;
tCsrRoamSetKey setKeyInfo;
fsm->currentState = PTK_INIT_DONE;
rxDesc = data->keyDesc;
vos_mem_zero( &setKeyInfo, sizeof( tCsrRoamSetKey ) );
setKeyInfo.encType = eCSR_ENCRYPT_TYPE_AES;
setKeyInfo.keyDirection = eSIR_TX_RX;
vos_mem_copy( setKeyInfo.peerMac, fsm->staCtx->suppMac, sizeof( tAniMacAddr ) );
setKeyInfo.paeRole = 0; //this is a supplicant
setKeyInfo.keyId = 0; //always
setKeyInfo.keyLength = CSR_AES_KEY_LEN;
vos_mem_copy( setKeyInfo.Key, (v_U8_t *)fsm->staCtx->ptk + (2 * CSR_AES_KEY_LEN ), CSR_AES_KEY_LEN );
//fsm->suppCtx->ptk contains the 3 16-bytes keys. We need the last one.
if( VOS_IS_STATUS_SUCCESS( bapSetKey( fsm->ctx->pvosGCtx, &setKeyInfo ) ) )
{
//Done
aniAsfPacketEmptyExplicit(fsm->lastEapol, EAPOL_TX_HEADER_SIZE);
retVal = ANI_OK;
}
else
{
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR, "Auth: gotoStatePtkInitDone fail to set key\n" );
retVal = ANI_ERROR;
}
return retVal;
}
static int
gotoStateUpdateKeysReq(tAuthRsnFsm *fsm, tAniEapolKeyAvailEventData *data)
{
tAniEapolRsnKeyDesc *rxDesc;
fsm->currentState = UPDATE_KEYS_REQ;
rxDesc = data->keyDesc;
aniSsmReplayCtrUpdate(fsm->staCtx->peerReplayCtr, rxDesc->replayCounter);
checkTransition(fsm, data);
return ANI_OK;
}
static int
gotoStateIntegFailure(tAuthRsnFsm *fsm, tSirMicFailureInfo *micFailureInfo)
{
fsm->currentState = INTEG_FAILURE;
fsm->integFailed = eANI_BOOLEAN_FALSE;
checkTransition(fsm, NULL); // UCT
return ANI_OK;
}
static int
gotoStateKeyUpdate(tAuthRsnFsm *fsm)
{
fsm->currentState = KEY_UPDATE;
if( VOS_IS_STATUS_SUCCESS( vos_rand_get_bytes(fsm->cryptHandle, fsm->aNonce, ANI_EAPOL_KEY_RSN_NONCE_SIZE) ) )
{
// Replay counter will be automatically updated when we create a
// new packet
checkTransition(fsm, NULL); // UCT
return ANI_OK;
}
return ANI_ERROR;
}
static int
gotoStateDisconnect(tAuthRsnFsm *fsm)
{
fsm->currentState = DISCONNECT;
//What else do we need to clean up? Or BAP will call our vleanup function?
// FSM does not exist after this...
bapAuthDisconnect( fsm->ctx );
return ANI_OK;
}
static
int zeroOutPtk(tAuthRsnFsm *fsm)
{
return ANI_OK;
}
static
int stopAllTimers(tAuthRsnFsm *fsm)
{
vos_timer_stop( &fsm->msg2Timer );
vos_timer_stop( &fsm->msg4Timer );
return ANI_OK;
}
static
int derivePtk(tAuthRsnFsm *fsm, tAniEapolKeyAvailEventData *data)
{
v_U32_t prfLen;
tAniEapolRsnKeyDesc *rxDesc;
VOS_ASSERT(fsm->staCtx->pmk);
switch (fsm->staCtx->pwCipherType)
{
case eCSR_ENCRYPT_TYPE_AES:
prfLen = AAG_RSN_PTK_PRF_LEN_CCMP;
break;
default:
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
"Auth cannot generate PTK for invalid algorithm %d\n",
fsm->staCtx->pwCipherType);
return ANI_E_ILLEGAL_ARG;
break;
};
rxDesc = (tAniEapolRsnKeyDesc *) data->keyDesc;
return aagPtkPrf(fsm->cryptHandle,
fsm->staCtx->ptk,
prfLen,
fsm->staCtx->pmk,
fsm->staCtx->authMac,
fsm->staCtx->suppMac,
fsm->aNonce,
rxDesc->keyNonce);
}
static int
checkMic(tAuthRsnFsm *fsm,
tAniEapolKeyAvailEventData *data)
{
int retVal;
retVal = aniEapolKeyCheckMic(fsm->cryptHandle,
data->eapolFrame,
ANI_EAPOL_KEY_DESC_TYPE_RSN_NEW,
data->keyDesc,
fsm->staCtx->ptk,
CSR_AES_KEY_LEN);
if (retVal == ANI_E_MIC_FAILED)
{
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
"Auth failed EAPOL-MIC check in pairwise key exchange!\n");
}
return retVal;
}
static int
checkLocalReplayCounter(tAuthRsnFsm *fsm,
tAniEapolKeyAvailEventData *data)
{
int retVal = ANI_E_NULL_VALUE;
int cmp;
tAniEapolRsnKeyDesc *rxDesc;
rxDesc = data->keyDesc;
if( rxDesc )
{
cmp = aniSsmReplayCtrCmp(fsm->staCtx->localReplayCtr, rxDesc->replayCounter);
// The STA should have sent back the same replay ctr as in our request
if (cmp != 0)
{
retVal = ANI_E_REPLAY_CHECK_FAILED;
}
else
{
retVal = ANI_OK;
}
}
return retVal;
}
static
int checkPeerReplayCounter(tAuthRsnFsm *fsm,
tAniEapolKeyAvailEventData *data)
{
int retVal = ANI_E_NULL_VALUE;
int cmp;
tAniEapolRsnKeyDesc *rxDesc;
rxDesc = data->keyDesc;
if( rxDesc )
{
cmp = aniSsmReplayCtrCmp(fsm->staCtx->peerReplayCtr, rxDesc->replayCounter);
// The STA should have sent a newer replay ctr than its old
// request. The first message is exempted from the check.
if (fsm->staCtx->pastFirstPeerRequest && cmp >= 0)
{
retVal = ANI_E_REPLAY_CHECK_FAILED;
}
fsm->staCtx->pastFirstPeerRequest = eANI_BOOLEAN_TRUE;
}
return retVal;
}
static int checkInfoElement(tAuthRsnFsm *fsm,
tAniEapolKeyAvailEventData *data)
{
tAniEapolRsnKeyDesc *desc;
v_U8_t *ieStaBytes;
int ieStaLen;
desc = (tAniEapolRsnKeyDesc *) data->keyDesc;
if( desc )
{
ieStaLen = aniAsfPacketGetBytes(fsm->staCtx->ieSta, &ieStaBytes);
if( !ANI_IS_STATUS_SUCCESS( ieStaLen ) )
{
return ieStaLen;
}
if ((desc->keyDataLen != ieStaLen) ||
( !vos_mem_compare(desc->keyData, ieStaBytes, ieStaLen-2) ))
{
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
"Auth STA sent inconsistent RSN IE!\n");
return ANI_E_FAILED;
}
// Copy RSN IE
//vos_mem_copy(fsm->advertizedRsnIe, desc->keyData, ieStaLen);
vos_mem_copy(fsm->advertizedRsnIe, ieStaBytes, ieStaLen);
return ANI_OK;
}
else
{
return ANI_E_NULL_VALUE;
}
}
static
int checkTransition(tAuthRsnFsm *fsm, void *arg)
{
int retVal;
tAniEapolKeyAvailEventData *data;
tAniEapolRsnKeyDesc *rxDesc;
tSirMicFailureInfo *micFailureInfo;
if (fsm->disconnect)
{
stopAllTimers(fsm);
gotoStateDisconnect(fsm);
return ANI_OK;
}
if (fsm->authReq)
{
stopAllTimers(fsm);
gotoStateAuthentication(fsm);
return ANI_OK;
}
switch (fsm->currentState)
{
case INITIALIZE:
break;
case AUTHENTICATION:
gotoStateAuthentication2(fsm);
break;
case AUTHENTICATION_2:
gotoStateGetPsk( fsm );
break;
case GET_PSK:
//We always have PMK otherwise BAP won't let us here
gotoStatePtkStart(fsm);
break;
case PTK_START:
if ( fsm->eapolAvail )
{
fsm->eapolAvail = eANI_BOOLEAN_FALSE;
if (NULL == arg)
{
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
"arg is NULL, exiting checkTransition()");
return ANI_E_FAILED;
}
data = (tAniEapolKeyAvailEventData *) arg;
retVal = checkLocalReplayCounter(fsm, data);
if (retVal != ANI_OK)
return ANI_OK; // Caller should not fail
retVal = derivePtk(fsm, data);
if( !ANI_IS_STATUS_SUCCESS( retVal ) )
{
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
"Auth derivePtk failed with code %d!\n", retVal);
return retVal;
}
retVal = checkMic(fsm, data);
if (retVal != ANI_OK)
{
bapAuthDisconnect( fsm->ctx );
return retVal;
}
retVal = gotoStatePtkInitNego(fsm, arg);
}
else if ( fsm->msg2TimeOut )
{
if (fsm->numTries <= authConsts.maxTries)
{
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
"Auth Retransmitting EAPOL-Key Msg1\n");
// Stay in the same state but repeat actions
gotoStatePtkStart(fsm);
}
else {
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
"Auth failed to recv EAPOL-Key Msg2 "
"Disconnecting...\n");
gotoStateDisconnect(fsm);
}
}
break;
case PTK_INIT_NEGO:
if (NULL == arg)
{
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
"arg is NULL, exiting checkTransition()");
return ANI_E_FAILED;
}
data = (tAniEapolKeyAvailEventData *) arg;
retVal = checkInfoElement(fsm, data);
if (retVal != ANI_OK)
{
gotoStateDisconnect(fsm);
}
else {
gotoStatePtkInitNegoTx(fsm);
}
break;
case PTK_INIT_NEGO_TX:
if (fsm->eapolAvail)
{
fsm->eapolAvail = eANI_BOOLEAN_FALSE;
if (NULL == arg)
{
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
"arg is NULL, exiting checkTransition()");
return ANI_E_FAILED;
}
data = (tAniEapolKeyAvailEventData *) arg;
retVal = checkLocalReplayCounter(fsm, data);
if (retVal != ANI_OK)
return ANI_OK; // Caller should not fail
retVal = checkMic(fsm, data);
if (retVal != ANI_OK)
{
bapAuthDisconnect( fsm->ctx );
return retVal;
}
retVal = gotoStatePtkInitDone(fsm, data);
} else if ( fsm->msg4TimeOut )
{
if (fsm->numTries <= authConsts.maxTries)
{
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
"Auth retransmitting EAPOL-Key Msg3 \n");
// Stay in the same state but repeat actions
gotoStatePtkInitNegoTx(fsm);
}
else {
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
"Auth failed to recv EAPOL-Key Msg4 "
"Disconnecting...\n" );
gotoStateDisconnect(fsm);
}
}
break;
case PTK_INIT_DONE:
if (fsm->eapolAvail) {
fsm->eapolAvail = eANI_BOOLEAN_FALSE;
if (NULL == arg)
{
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
"arg is NULL, exiting checkTransition()");
return ANI_E_FAILED;
}
data = (tAniEapolKeyAvailEventData *) arg;
rxDesc = (tAniEapolRsnKeyDesc *) data->keyDesc;
if (rxDesc->info.requestFlag)
{
retVal = checkPeerReplayCounter(fsm, data);
if (retVal != ANI_OK)
return ANI_OK; // Caller should not fail
retVal = checkMic(fsm, data);
if (retVal != ANI_OK)
{
bapAuthDisconnect( fsm->ctx->pvosGCtx );
return retVal;
}
retVal = gotoStateUpdateKeysReq(fsm, arg);
}
}
else if (fsm->integFailed) {
micFailureInfo = (tSirMicFailureInfo *) arg;
gotoStateIntegFailure(fsm, arg);
}
break;
case UPDATE_KEYS_REQ:
if (NULL == arg)
{
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
"arg is NULL, exiting checkTransition()");
return ANI_E_FAILED;
}
data = (tAniEapolKeyAvailEventData *) arg;
rxDesc = (tAniEapolRsnKeyDesc *) data->keyDesc;
if (rxDesc->info.errorFlag)
{
/*
* This was generated by a unicast packet sent from the AP to the STA/BP.
* The TX address is the AP's address. The src address is lost.
* If the STA is a BP, then the true dst is lost. We will treat
* the dst field as the address of the reporter of the MIC failure.
*/
micFailureInfo = (tSirMicFailureInfo *) vos_mem_malloc( sizeof(tSirMicFailureInfo) );
if( NULL == micFailureInfo )
{
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
"Fail to allocate memory for AuthRsnFsm: %d\n",
fsm->currentState);
return ANI_E_MALLOC_FAILED;
}
vos_mem_copy(micFailureInfo->taMacAddr, fsm->staCtx->authMac, sizeof(tAniMacAddr));
vos_mem_copy(micFailureInfo->dstMacAddr, fsm->staCtx->suppMac, sizeof(tAniMacAddr));
micFailureInfo->multicast = eANI_BOOLEAN_FALSE;
// Copy whatever sequence number came in the EAPOL-key message
vos_mem_copy(micFailureInfo->TSC, rxDesc->keyRecvSeqCounter, SIR_CIPHER_SEQ_CTR_SIZE);
gotoStateIntegFailure(fsm, micFailureInfo);
vos_mem_free(micFailureInfo);
}
else {
// TBD: Untested. Why are local aNonce and local replyCtr not incremented in spec?
gotoStatePtkStart(fsm);
}
break;
case INTEG_FAILURE:
gotoStateKeyUpdate(fsm);
break;
case KEY_UPDATE:
gotoStatePtkStart(fsm);
break;
default:
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
"Nothing to do in this state for AuthRsnFsm: %d\n",
fsm->currentState);
// Catch all for states that need no change:
// assert(eANI_BOOLEAN_FALSE && "Illegal AuthRsnFsm state!");
return ANI_E_FAILED;
}
return ANI_OK;
}
static void msg2TimerCallback( void *pv )
{
tAuthRsnFsm *fsm = (tAuthRsnFsm *)pv;
if (NULL == fsm)
{
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
"fsm is NULL in %s", __func__);
return;
}
//Only when waiting for msg2
if( PTK_START == fsm->currentState )
{
fsm->msg2TimeOut = eANI_BOOLEAN_TRUE;
}
//We may need to synchronize this call
authRsnFsmProcessEvent( fsm, RSN_FSM_TIMER_EXPIRED, NULL );
}
static void msg4TimerCallback( void *pv )
{
tAuthRsnFsm *fsm = (tAuthRsnFsm *)pv;
if (NULL == fsm)
{
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
"fsm is NULL in %s", __func__);
return;
}
//Only when we are waiting for msg4
if( PTK_INIT_NEGO_TX == fsm->currentState )
{
fsm->msg4TimeOut = eANI_BOOLEAN_TRUE;
}
//We may need to synchronize this call
authRsnFsmProcessEvent( fsm, RSN_FSM_TIMER_EXPIRED, NULL );
}
//
//This function alwasy assume the incoming vos_packet is 802_3 frame.
static int authRsnRxFrameHandler( v_PVOID_t pvosGCtx, vos_pkt_t *pPacket )
{
int retVal = ANI_ERROR;
tAniPacket *pAniPacket;
tBtampContext *ctx;
tAuthRsnFsm *fsm;
/* Validate params */
if ((pvosGCtx == NULL) || (NULL == pPacket))
{
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
"param is NULL in %s", __func__);
return retVal;
}
ctx = (tBtampContext *)VOS_GET_BAP_CB( pvosGCtx );
if (NULL == ctx)
{
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
"ctx is NULL in %s", __func__);
return retVal;
}
fsm = &ctx->uFsm.authFsm;
if (NULL == fsm)
{
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
"fsm is NULL in %s", __func__);
return retVal;
}
do
{
//ToDO: We need to synchronize this. For now, use the simplest form, drop the packet comes later.
if( fsm->fReceiving )
{
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
" ******authRsnRxFrameHandler receive eapol packet while processing. Drop the new comer\n" );
break;
}
fsm->fReceiving = VOS_TRUE;
retVal = bapRsnFormPktFromVosPkt( &pAniPacket, pPacket );
if( !ANI_IS_STATUS_SUCCESS( retVal ) ) break;
//Now we can process the eapol frame
//handler will free the pAniPacket
bapRsnEapolHandler( fsm, pAniPacket, VOS_TRUE );
}while( 0 );
fsm->fReceiving = VOS_FALSE;
vos_pkt_return_packet( pPacket );
return retVal;
}
static int authRsnTxCompleteHandler( v_PVOID_t pvosGCtx, vos_pkt_t *pPacket, VOS_STATUS retStatus )
{
tBtampContext *ctx = (tBtampContext *)VOS_GET_BAP_CB( pvosGCtx );
tAuthRsnFsm *fsm;
vos_pkt_return_packet( pPacket );
if (NULL == ctx)
{
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
"ctx is NULL in %s", __func__);
return ANI_ERROR;
}
fsm = &ctx->uFsm.authFsm;
if (NULL == fsm)
{
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
"fsm is NULL in %s", __func__);
return ANI_ERROR;
}
if(!VOS_IS_STATUS_SUCCESS( retStatus ) )
{
//No need to do anything. Retransmit is handled by timeout
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
"Auth: TL Tx complete with error %d current state is %d \n", retStatus, fsm->currentState );
}
if( PTK_START == fsm->currentState )
{
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_INFO,
" Auth: start msg2 timer\n" );
//Start msg2Timer
fsm->numTries++;
vos_timer_stop( &fsm->msg2Timer );
vos_timer_start(&fsm->msg2Timer, authConsts.timeoutPeriod);
}
else if( ( PTK_INIT_NEGO == fsm->currentState ) ||
( PTK_INIT_NEGO_TX == fsm->currentState ) )
{
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_INFO,
" Auth: start msg4 timer\n" );
fsm->numTries++;
vos_timer_stop( &fsm->msg4Timer );
vos_timer_start(&fsm->msg4Timer, authConsts.timeoutPeriod);
}
return ANI_OK;
}
static int
authEapolKeyHandler( tAuthRsnFsm *fsm, tAniPacket *eapolFrame, tAniMacAddr staMac )
{
int retVal;
int descType;
void *keyDesc;
tAniEapolRsnKeyDesc *rsnDesc;
tAniEapolKeyAvailEventData data;
do
{
retVal = aniEapolParseKey(eapolFrame, &descType, &keyDesc);
if( !ANI_IS_STATUS_SUCCESS( retVal ) ) break;
if ((descType == ANI_EAPOL_KEY_DESC_TYPE_RSN_NEW)
|| (descType == ANI_EAPOL_KEY_DESC_TYPE_RSN))
{
rsnDesc = (tAniEapolRsnKeyDesc *) keyDesc;
data.keyDesc = keyDesc;
data.eapolFrame = eapolFrame;
// Pass on the event to the RSN FSM only if it is for a pairwise key
if (rsnDesc->info.unicastFlag)
{
retVal = authRsnFsmProcessEvent(fsm,
RSN_FSM_EAPOL_FRAME_AVAILABLE,
&data);
}
else {
//Not worry about GTK stuff
}
}
else {
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
"Got unexpected legacy 802.1x RC4 Key message \n" );
retVal = ANI_E_FAILED;
break;
}
}while( 0 );
aniEapolKeyFreeDesc(descType, keyDesc);
return retVal;
}
void authEapolHandler( tAuthRsnFsm *fsm, tAniPacket *eapolFrame,
tAniMacAddr dstMac,
tAniMacAddr srcMac,
v_U8_t *type)
{
switch (*type)
{
case ANI_EAPOL_TYPE_START:
//No doing anything because we only support WPA2-PSK
break;
case ANI_EAPOL_TYPE_LOGOFF:
//ignore
break;
case ANI_EAPOL_TYPE_KEY:
authEapolKeyHandler(fsm, eapolFrame, srcMac);
break;
default:
VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
"Auth: EAPOL type not implemented: 0x%.2x\n", *type);
break;
}
}