/**
 * suppRsnFsmCreate
 *
 * FUNCTION
 * Allocates and initializes the state of an RSN key FSM instance for
 * the given BP context.
 * 
 * @parm ctx the BP context whose instance is being created
 * @param pskBased pass in eANI_BOOLEAN_TRUE is this BP is to be
 * authenticated based on a pre-shared key as opposed to EAP.
 *
 * @return ANI_OK if the operation succeeds
 */
int
suppRsnFsmCreate(tBtampContext *ctx)
{
    int retVal = ANI_OK;
    tSuppRsnFsm *fsm = &ctx->uFsm.suppFsm;

    // First, clear everything out
    vos_mem_zero( fsm, sizeof(tSuppRsnFsm));

    if( !VOS_IS_STATUS_SUCCESS( bapRsnRegisterTxRxCallbacks( suppRsnTxCompleteHandler,
                                            suppRsnRxFrameHandler ) ) )
    {
        return ANI_ERROR;
    }

    if( !VOS_IS_STATUS_SUCCESS( bapRsnRegisterRxCallback( ctx->pvosGCtx ) ) )
    {
        return ANI_ERROR;
    }

    // Allocate the supplicant context
    fsm->suppCtx = (tSuppContext *)vos_mem_malloc( sizeof(tSuppContext) );
    if (fsm->suppCtx == NULL) 
    {
        retVal = ANI_E_MALLOC_FAILED;
        VOS_ASSERT( 0 );
        goto error;
    }
    // Clear out the supplicant context
    vos_mem_zero( fsm->suppCtx, sizeof(tSuppContext));

    fsm->ctx = ctx;
    //Only support CCMP
    fsm->suppCtx->pwCipherType = eCSR_ENCRYPT_TYPE_AES;

    retVal = aniAsfPacketAllocateExplicit(&fsm->lastEapol,
                                          RSN_MAX_PACKET_SIZE,
                                          EAPOL_TX_HEADER_SIZE);
    if (retVal != ANI_OK) 
    {
        VOS_ASSERT( 0 );
        goto error;
    }

    aniAsfPacketAllocate(&fsm->suppCtx->pmk);
    if (fsm->suppCtx->pmk == NULL) 
    {
        retVal = ANI_E_MALLOC_FAILED;
        VOS_ASSERT( 0 );
        goto error;
    }

    fsm->suppCtx->ieAp = NULL; 

    fsm->cryptHandle = 0;
    if( !VOS_IS_STATUS_SUCCESS( vos_crypto_init( &fsm->cryptHandle ) ) )
    {
        retVal = ANI_E_FAILED;
        VOS_ASSERT( 0 );
    }

    fsm->currentState = INITIALIZE;
    gotoStateInit(fsm);

    suppRsnFsmProcessEvent( fsm, RSN_FSM_AUTH_START, NULL );

    return ANI_OK;

 error:
    suppRsnFsmFree( ctx );

    return retVal;
    
}
/**
 * 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;
    
}