/*
 * authSm.c
 *
 * Copyright(c) 1998 - 2009 Texas Instruments. All rights reserved.      
 * All rights reserved.                                                  
 *                                                                       
 * Redistribution and use in source and binary forms, with or without    
 * modification, are permitted provided that the following conditions    
 * are met:                                                              
 *                                                                       
 *  * Redistributions of source code must retain the above copyright     
 *    notice, this list of conditions and the following disclaimer.      
 *  * Redistributions in binary form must reproduce the above copyright  
 *    notice, this list of conditions and the following disclaimer in    
 *    the documentation and/or other materials provided with the         
 *    distribution.                                                      
 *  * Neither the name Texas Instruments nor the names of its            
 *    contributors may be used to endorse or promote products derived    
 *    from this software without specific prior written permission.      
 *                                                                       
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS   
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT     
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT  
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT      
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT   
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/** \file authSM.c
 *  \brief 802.11 authentication SM source
 *
 *  \see authSM.h
 */


/***************************************************************************/
/*																		   */
/*		MODULE:	authSM.c												   */
/*    PURPOSE:	802.11 authentication SM source							   */
/*																	 	   */
/***************************************************************************/

#define __FILE_ID__  FILE_ID_64
#include "osApi.h"

#include "paramOut.h"
#include "fsm.h"
#include "report.h"
#include "timer.h"
#include "mlmeApi.h"
#include "mlmeBuilder.h"
#include "authSm.h"
#include "openAuthSm.h"
#include "sharedKeyAuthSm.h"
#include "DrvMainModules.h"

/* Constants */ 

/** number of states in the state machine */
#define	AUTH_SM_MAX_NUM_STATES		4

/** number of events in the state machine */
#define	AUTH_SM_MAX_NUM_EVENTS		8

/* Enumerations */

/* Typedefs */

/* Structures */

/* External data definitions */

/* External functions definitions */

/* Global variables */

/* Local function prototypes */

/* functions */

/**
*
* auth_create - allocate memory for authentication SM
*
* \b Description: 
*
* Allocate memory for authentication SM. \n
* 		Allocates memory for Association context. \n
* 		Allocates memory for authentication timer. \n
* 		Allocates memory for authentication SM matrix. \n
*
* \b ARGS:
*
*  I   - hOs - OS context  \n
*
* \b RETURNS:
*
*  TI_OK if successful, TI_NOK otherwise.
*
* \sa rsn_mainSecSmKeysOnlyStop()
*/
TI_HANDLE auth_create(TI_HANDLE hOs)
{
	auth_t 	*pHandle;
	TI_STATUS		status;

	/* allocate authentication context memory */
	pHandle = (auth_t*)os_memoryAlloc(hOs, sizeof(auth_t));
	if (pHandle == NULL)
	{
		return NULL;
	}
	
	os_memoryZero(hOs, pHandle, sizeof(auth_t));

	pHandle->hOs = hOs;
    
	/* allocate memory for authentication state machine */
	status = fsm_Create(hOs, &pHandle->pAuthSm, AUTH_SM_MAX_NUM_STATES, AUTH_SM_MAX_NUM_EVENTS);
	if (status != TI_OK)
	{
		os_memoryFree(hOs, pHandle, sizeof(auth_t));
		return NULL;
	}

	return pHandle;
}


/**
*
* auth_unload - unload authentication SM from memory
*
* \b Description: 
*
* Unload authentication SM from memory
*
* \b ARGS:
*
*  I   - hAuth - Authentication SM context  \n
*
* \b RETURNS:
*
*  TI_OK if successful, TI_NOK otherwise.
*
* \sa rsn_mainSecSmKeysOnlyStop()
*/
TI_STATUS auth_unload(TI_HANDLE hAuth)
{
    TI_STATUS 		status;
	auth_t		*pHandle;

	pHandle = (auth_t*)hAuth;

	status = fsm_Unload(pHandle->hOs, pHandle->pAuthSm);
    if (status != TI_OK)
	{
		/* report failure but don't stop... */
TRACE0(pHandle->hReport, REPORT_SEVERITY_ERROR, "AUTH_SM: Error releasing FSM memory \n");
	}
	
	if (pHandle->hAuthSmTimer)
	{
		tmr_DestroyTimer (pHandle->hAuthSmTimer);
	}
	
	os_memoryFree(pHandle->hOs, pHandle, sizeof(auth_t));

	return TI_OK;
}

/**
*
* auth_init - Init required handles and module variables,
*
* \b Description: 
*
* Init required handles and module variables,
*
* \b ARGS:
*
*  I   - pStadHandles - The driver modules handles  \n
*
* \b RETURNS:
*
*  void
*
* \sa auth_Create, auth_Unload
*/
void auth_init (TStadHandlesList *pStadHandles)
{
	auth_t *pHandle = (auth_t*)(pStadHandles->hAuth);
	
	pHandle->hMlme   = pStadHandles->hMlmeSm;
	pHandle->hRsn    = pStadHandles->hRsn;
	pHandle->hReport = pStadHandles->hReport;
	pHandle->hOs     = pStadHandles->hOs;
    pHandle->hTimer  = pStadHandles->hTimer;
}


TI_STATUS auth_SetDefaults (TI_HANDLE hAuth, authInitParams_t *pAuthInitParams)
{
    auth_t		*pHandle = (TI_HANDLE) hAuth;

	pHandle->timeout = pAuthInitParams->authResponseTimeout;
	pHandle->maxCount = pAuthInitParams->authMaxRetryCount;
	
	pHandle->retryCount = 0;
	pHandle->authRejectCount = 0;
	pHandle->authTimeoutCount = 0;

	pHandle->authType = AUTH_LEGACY_NONE;

	/* allocate OS timer memory */
    pHandle->hAuthSmTimer = tmr_CreateTimer (pHandle->hTimer);
	if (pHandle->hAuthSmTimer == NULL)
	{
        TRACE0(pHandle->hReport, REPORT_SEVERITY_ERROR, "auth_SetDefaults(): Failed to create hAuthSmTimer!\n");
		return TI_NOK;
	}

	return TI_OK;
}


/**
*
* auth_start - Start event for the authentication SM
*
* \b Description: 
*
* Start event for the authentication SM
*
* \b ARGS:
*
*  I   - hAuth - Authentication SM context  \n
*
* \b RETURNS:
*
*  TI_OK if successful, TI_NOK otherwise.
*
* \sa auth_Stop, auth_Recv
*/
TI_STATUS auth_start(TI_HANDLE hAuth)
{
	auth_t		*pHandle = (auth_t*)hAuth;

	if (pHandle == NULL)
    {
		return TI_NOK;
    }

	if (pHandle->authType == AUTH_LEGACY_NONE)
    {
        TRACE0(pHandle->hReport, REPORT_SEVERITY_ERROR, "auth_start: pHandle->authType == AUTH_LEGACY_NONE\n");
		return TI_NOK;
    }

	switch (pHandle->authType)
	{
    case AUTH_LEGACY_RESERVED1: 
	case AUTH_LEGACY_OPEN_SYSTEM:
		return auth_osSMEvent(&pHandle->currentState, OPEN_AUTH_SM_EVENT_START, pHandle);

	case AUTH_LEGACY_SHARED_KEY:
		return auth_skSMEvent(&pHandle->currentState, SHARED_KEY_AUTH_SM_EVENT_START, pHandle);

	default:
        TRACE0(pHandle->hReport, REPORT_SEVERITY_ERROR, "auth_start: pHandle->authType unknown.\n");
		return TI_NOK;
	}
}

/**
*
* auth_stop - Stop event for the authentication SM
*
* \b Description: 
*
* Stop event for the authentication SM
*
* \b ARGS:
*
*  I   - hAuth - Authentication SM context  \n
*
* \b RETURNS:
*
*  TI_OK if successful, TI_NOK otherwise.
*
* \sa auth_Start, auth_Recv
*/
TI_STATUS auth_stop(TI_HANDLE hAuth, TI_BOOL sendDeAuth, mgmtStatus_e reason )
{
	auth_t		*pHandle;

	pHandle = (auth_t*)hAuth;

	if (pHandle == NULL)
		return TI_NOK;
	
	if (pHandle->authType == AUTH_LEGACY_NONE)
		return TI_NOK;

	if( sendDeAuth == TI_TRUE )
	{
		deAuth_t	deAuth;
		deAuth.reason = ENDIAN_HANDLE_WORD(reason);
		mlmeBuilder_sendFrame(pHandle->hMlme, DE_AUTH, (TI_UINT8*)&deAuth, sizeof(deAuth_t), 0);
	}

	switch (pHandle->authType)
	{
    case AUTH_LEGACY_RESERVED1:
	case AUTH_LEGACY_OPEN_SYSTEM:
		return auth_osSMEvent(&pHandle->currentState, OPEN_AUTH_SM_EVENT_STOP, pHandle);

	case AUTH_LEGACY_SHARED_KEY:
		return auth_skSMEvent(&pHandle->currentState, SHARED_KEY_AUTH_SM_EVENT_STOP, pHandle);

	default:
		return TI_NOK;
	}
}

/**
*
* auth_recv - Recive a message from the AP
*
* \b Description: 
*
* Parse a message form the AP and perform the appropriate event.
*
* \b ARGS:
*
*  I   - hAuth - Authentication SM context  \n
*
* \b RETURNS:
*
*  TI_OK if successful, TI_NOK otherwise.
*
* \sa auth_Start, auth_Stop
*/
TI_STATUS auth_recv(TI_HANDLE hAuth, mlmeFrameInfo_t *pFrame)
{
	auth_t			*pHandle;

	pHandle = (auth_t*)hAuth;

	if (pHandle == NULL)
		return TI_NOK;
	
	if (pFrame->subType != AUTH)
		return TI_NOK;

	if (pHandle->authType == AUTH_LEGACY_NONE)
		return TI_NOK;

	if (pFrame->content.auth.status != STATUS_SUCCESSFUL)
		pHandle->authRejectCount++;

	switch (pHandle->authType)
	{
	case AUTH_LEGACY_RESERVED1:
	case AUTH_LEGACY_OPEN_SYSTEM:
		return openAuth_Recv(hAuth, pFrame);

	case AUTH_LEGACY_SHARED_KEY:
		return sharedKeyAuth_Recv(hAuth, pFrame);

	default:
		return TI_OK;
	}
}

/**
*
* auth_getParam - Get a specific parameter from the authentication SM
*
* \b Description: 
*
* Get a specific parameter from the authentication SM.
*
* \b ARGS:
*
*  I   - hAuth - Authentication SM context  \n
*  I/O - pParam - Parameter \n
*
* \b RETURNS:
*
*  TI_OK if successful, TI_NOK otherwise.
*
* \sa auth_Start, auth_Stop
*/
TI_STATUS auth_getParam(TI_HANDLE hAuth, paramInfo_t *pParam)
{
	auth_t		*pHandle;

	pHandle = (auth_t*)hAuth;

	if ((pHandle == NULL) || (pParam == NULL))
	{
		return TI_NOK;
	}

	switch (pParam->paramType)
	{
	case AUTH_RESPONSE_TIMEOUT_PARAM:
		pParam->content.authResponseTimeout = pHandle->timeout;
		break;

	case AUTH_COUNTERS_PARAM:
		pParam->content.siteMgrTiWlanCounters.AuthRejects = pHandle->authRejectCount;
		pParam->content.siteMgrTiWlanCounters.AuthTimeouts = pHandle->authTimeoutCount;
		break;

	case AUTH_LEGACY_TYPE_PARAM:
		pParam->content.authLegacyAuthType = pHandle->authType;
		break;

	default:
		return TI_NOK;
	}

	return TI_OK;
}

/**
*
* auth_setParam - Set a specific parameter to the authentication SM
*
* \b Description: 
*
* Set a specific parameter to the authentication SM.
*
* \b ARGS:
*
*  I   - hAuth - Authentication SM context  \n
*  I/O - pParam - Parameter \n
*
* \b RETURNS:
*
*  TI_OK if successful, TI_NOK otherwise.
*
* \sa auth_Start, auth_Stop
*/
TI_STATUS auth_setParam(TI_HANDLE hAuth, paramInfo_t *pParam)
{
	auth_t		*pHandle;

	pHandle = (auth_t*)hAuth;

	if ((pHandle == NULL) || (pParam == NULL))
	{
		return TI_NOK;
	}

	switch (pParam->paramType)
	{
	case AUTH_LEGACY_TYPE_PARAM:
		pHandle->authType = pParam->content.authLegacyAuthType;

		switch (pHandle->authType)
		{
        case AUTH_LEGACY_RESERVED1:
		case AUTH_LEGACY_OPEN_SYSTEM:
			openAuth_Config(hAuth, pHandle->hOs);
			break;

		case AUTH_LEGACY_SHARED_KEY:
			sharedKeyAuth_Config(hAuth, pHandle->hOs);
			break;

		default:
			return TI_NOK;
		}
		break;

	case AUTH_RESPONSE_TIMEOUT_PARAM:
		if ((pParam->content.authResponseTimeout >= AUTH_RESPONSE_TIMEOUT_MIN) &&
			(pParam->content.authResponseTimeout <= AUTH_RESPONSE_TIMEOUT_MAX))
		{
			pHandle->timeout = pParam->content.authResponseTimeout;
		} 
		else 
		{
			return TI_NOK;
		}
		break;

	default:
		return TI_NOK;
	}

	return TI_OK;
}

/**
*
* auth_smTimeout - Set a specific parameter to the authentication SM
*
* \b Description: 
*
* Set a specific parameter to the authentication SM.
*
* \b ARGS:
*
*  I   - hAuth - authentication SM context  \n
*  I   - bTwdInitOccured - Indicates if TWDriver recovery occured since timer started  \n
*
* \b RETURNS:
*
*  TI_OK if successful, TI_NOK otherwise.
*
* \sa auth_Start, auth_Stop
*/
void auth_smTimeout (TI_HANDLE hAuth, TI_BOOL bTwdInitOccured)
{
	auth_t		*pHandle;

	pHandle = (auth_t*)hAuth;

	if (pHandle == NULL)
		return;
	
	if (pHandle->authType == AUTH_LEGACY_NONE)
		return;

	pHandle->authTimeoutCount++;

	switch (pHandle->authType)
	{
    case AUTH_LEGACY_RESERVED1:
	case AUTH_LEGACY_OPEN_SYSTEM:
		openAuth_Timeout(pHandle);
		break;

	case AUTH_LEGACY_SHARED_KEY:
		sharedKey_Timeout(pHandle);
		break;

	default:
		break;
	}
}

/*****************************************************************************
**
** Authentication messages builder/Parser
**
*****************************************************************************/

/**
*
* auth_smMsgBuild - Build an authentication message and send it to the mlme builder
*
* \b Description: 
*
* Build an authentication message and send it to the mlme builder.
*
* \b ARGS:
*
*  I   - pAssoc - Association SM context  \n
*  I/O - pParam - Parameter \n
*
* \b RETURNS:
*
*  TI_OK if successful, TI_NOK otherwise.
*
* \sa auth_Start, auth_Stop
*/
TI_STATUS auth_smMsgBuild(auth_t *pCtx, TI_UINT16 seq, TI_UINT16 statusCode, TI_UINT8* pChallange, TI_UINT8 challangeLen)
{
	TI_STATUS				status;
	TI_UINT8				len;
	TI_UINT8				authMsg[MAX_AUTH_MSG_LEN];
	authMsg_t			*pAuthMsg;
	dot11_CHALLENGE_t	*pDot11Challenge;
	TI_UINT8				wepOpt;

	wepOpt = 0;

	pAuthMsg = (authMsg_t*)authMsg;
	
	/* insert algorithm */
	pAuthMsg->authAlgo = (TI_UINT16)pCtx->authType;

	/* insert sequense */
	pAuthMsg->seqNum = ENDIAN_HANDLE_WORD(seq);

	/* insert status code */
	pAuthMsg->status = ENDIAN_HANDLE_WORD(statusCode);

	len = sizeof(pAuthMsg->authAlgo) + sizeof(pAuthMsg->seqNum) + sizeof(pAuthMsg->status);

	if (pChallange != NULL)
	{
		pDot11Challenge = (dot11_CHALLENGE_t*)&authMsg[len];

		pDot11Challenge->hdr[0] = CHALLANGE_TEXT_IE_ID;
		pDot11Challenge->hdr[1] = challangeLen;

		os_memoryCopy(pCtx->hOs, (void *)pDot11Challenge->text, pChallange, challangeLen);
		len += challangeLen + 2;

		wepOpt = 1;
	}

	status =  mlmeBuilder_sendFrame(pCtx->hMlme, AUTH, authMsg, len, wepOpt);

	return status;
}