Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
/** @file keyMgmtSta.c
 *
 *  @brief This file defines key management API for sta
 * Copyright (C) 2014-2017, Marvell International Ltd.
 *
 * This software file (the "File") is distributed by Marvell International
 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
 * (the "License").  You may use, redistribute and/or modify this File in
 * accordance with the terms and conditions of the License, a copy of which
 * is available by writing to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
 *
 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
 * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
 * this warranty disclaimer.
 */

/******************************************************
Change log:
    03/07/2014: Initial version
******************************************************/

#include "wltypes.h"
#include "IEEE_types.h"
#include "hostsa_ext_def.h"
#include "authenticator.h"
#include "wl_macros.h"
#include "keyMgmtSta.h"
#include "pass_phrase.h"
#include "wlpd.h"
#include "KeyApiStaDefs.h"
#include "crypt_new.h"
#include "pmkCache.h"
#include "sha1.h"
#include "md5.h"
#include "rc4.h"
#include "aes_cmac.h"
#include "mrvl_sha256_crypto.h"

#include "keyMgmtSta_rom.h"
#include "tlv.h"

#define DEAUTH_DELAY_TIME_INTERVAL            40000	/* 40 ms */

#define PWK_MSG1_RETRIES       7

/* 10 seconds timeout for completing RSN key handshake */
//#define RSNSECUREDTIMEOUT  10000000
#define RSNSECUREDTIMEOUT  MRVDRV_TIMER_10S

//static void SendMICFailReport_sta(cm_ConnectionInfo_t* connPtr,
//                                  keyMgmtInfoSta_t* pKeyMgmtInfoSta,
//                                  BOOLEAN isUnicast);
#if 0
static BufferReturnNotify_t keyMgmtKeyGroupTxDone(phostsa_private priv);
static BufferReturnNotify_t keyMgmtKeyPairwiseTxDone(phostsa_private priv);
static BufferReturnNotify_t keyMgmtKeyPairAndGroupTxDone(phostsa_private priv);
#endif
static void keyMgmtKeyGroupTxDone(phostsa_private priv);
static void keyMgmtKeyPairwiseTxDone(phostsa_private priv);
static void keyMgmtKeyPairAndGroupTxDone(phostsa_private priv);

static supplicantData_t keyMgmt_SuppData[MAX_SUPPLICANT_SESSIONS];

void FillKeyMaterialStruct(phostsa_private priv,
			   UINT16 key_len, UINT8 isPairwise, KeyData_t *pKey);
void FillGrpKeyMaterialStruct(phostsa_private priv,
			      UINT16 keyType,
			      UINT8 *pn,
			      UINT8 keyIdx, UINT8 keyLen, KeyData_t *pKey);
UINT16 keyMgmtFormatWpaRsnIe(phostsa_private priv,
			     UINT8 *pos,
			     IEEEtypes_MacAddr_t *pBssid,
			     IEEEtypes_MacAddr_t *pStaAddr,
			     UINT8 *pPmkid, BOOLEAN addPmkid);
t_u8 supplicantIsEnabled(void *priv);

void
allocSupplicantData(void *priv)
{
	phostsa_private psapriv = (phostsa_private)priv;
	int i = 0;

	if (psapriv->suppData) {
		return;
	}
	//if (pm_fns->bss_type == MLAN_BSS_TYPE_STA)
	{

//        int_sta = os_if_save_EnterCriticalSection();
		for (i = 0; i < MAX_SUPPLICANT_SESSIONS; i++) {
			if (keyMgmt_SuppData[i].inUse == FALSE) {
				keyMgmt_SuppData[i].inUse = TRUE;
				supplicantInit((void *)psapriv,
					       &keyMgmt_SuppData[i]);
				psapriv->suppData =
					(void *)&keyMgmt_SuppData[i];
				break;
			}
		}
//        os_if_save_ExitCriticalSection(int_sta);

//        os_ASSERT(connPtr->suppData);
	}

}

void
freeSupplicantData(void *priv)
{
	phostsa_private psapriv = (phostsa_private)priv;
	struct supplicantData *suppData = psapriv->suppData;

	if (suppData != NULL) {
		suppData->inUse = FALSE;
		suppData = NULL;
	}
}

mlan_status
initSupplicantTimer(void *priv)
{
	phostsa_private psapriv = (phostsa_private)priv;
	hostsa_util_fns *util_fns = &psapriv->util_fns;
	mlan_status ret = MLAN_STATUS_SUCCESS;

	if (util_fns->moal_init_timer(util_fns->pmoal_handle,
				      &psapriv->suppData->keyMgmtInfoSta.
				      rsnTimer,
				      keyMgmtStaRsnSecuredTimeoutHandler,
				      psapriv) != MLAN_STATUS_SUCCESS) {
		ret = MLAN_STATUS_FAILURE;
		return ret;
	}

	return ret;
}

void
freeSupplicantTimer(void *priv)
{
	phostsa_private psapriv = (phostsa_private)priv;
	hostsa_util_fns *util_fns = &psapriv->util_fns;

	if (psapriv->suppData->keyMgmtInfoSta.rsnTimer) {
		util_fns->moal_free_timer(util_fns->pmoal_handle,
					  psapriv->suppData->keyMgmtInfoSta.
					  rsnTimer);
		psapriv->suppData->keyMgmtInfoSta.rsnTimer = NULL;
	}
}

//#if defined(PSK_SUPPLICANT) || defined (WPA_NONE)
void
keyMgmtSendDeauth2Peer(phostsa_private priv, UINT16 reason)
{
	hostsa_mlan_fns *pm_fns = &priv->mlan_fns;

	/* Assumes we are sending to AP */
	//keyMgmtSendDeauth((cm_ConnectionInfo_t*)connPtr,
	//                  &((cm_ConnectionInfo_t*)connPtr)->suppData->localBssid,
	//                  reason);
#if 0
	ret = wlan_prepare_cmd(priv,
			       HostCmd_CMD_802_11_DEAUTHENTICATE,
			       HostCmd_ACT_GEN_SET,
			       0, NULL, &priv->suppData->localBssid);

	if (ret == MLAN_STATUS_SUCCESS)
		wlan_recv_event(priv, MLAN_EVENT_ID_DRV_DEFER_HANDLING, MNULL);
#endif
	pm_fns->hostsa_StaSendDeauth(pm_fns->pmlan_private,
				     (t_u8 *)&priv->suppData->localBssid,
				     reason);
}

BOOLEAN
keyMgmtProcessMsgExt(phostsa_private priv, keyMgmtInfoSta_t *pKeyMgmtInfoSta,
		     EAPOL_KeyMsg_t *pKeyMsg)
{
	if (pKeyMsg->key_info.KeyType && pKeyMsg->key_info.KeyMIC) {
		/* PWK Msg #3 processing */
#ifdef DOT11R
		if (supplicantAkmWpa2Ft
		    (priv,
		     &pKeyMgmtInfoSta->connPtr->suppData->customMIB_RSNConfig.
		     AKM)) {
			if (dot11r_process_pwk_msg3(pKeyMsg) == FALSE) {
				return FALSE;
			}
		}
#endif

#ifdef CCX_MFP
		if (ccx_mfp_process_pwk_msg3(pKeyMsg) == FALSE) {
			return FALSE;
		}
#endif
	}

	/*
	 **  KDE processing for Msg#3 and for any Group Key rotations
	 */
	if (pKeyMsg->key_info.EncryptedKeyData) {
#ifdef DOT11W
		KDE_t *pKde;

		/* Parse IGTK for 11w */
		pKde = parseKeyKDE_DataType(priv, pKeyMsg->key_data,
					    pKeyMsg->key_material_len,
					    KDE_DATA_TYPE_IGTK);
		if (pKde) {
			//Not install same iGtk
			if (!memcmp(&priv->util_fns,
				    pKeyMgmtInfoSta->IGtk.Key,
				    (UINT8 *)(((IGtkKde_t *)pKde->data)->IGtk),
				    MIN(sizeof(pKeyMgmtInfoSta->IGtk.Key),
					(pKde->length - 12)))) {
				return TRUE;
			} else {
				keyMgmtSetIGtk(priv, pKeyMgmtInfoSta,
					       (IGtkKde_t *)pKde->data,
					       pKde->length);
			}
#if 0
			hostEventPrintHex(assocAgent_getConnPtr(),
					  "SetIGTK", keyMgmtGetIGtk(), 16);
#endif
		}
#endif
	}

	return TRUE;
}

#ifdef WAR_ROM_BUG50312_SIMUL_INFRA_WFD
EAPOL_KeyMsg_t *
patch_ProcessRxEAPOL_GrpMsg1(phostsa_private priv, mlan_buffer *pmbuf,
			     keyMgmtInfoSta_t *pKeyMgmtInfoSta)
{
	hostsa_util_fns *util_fns = &priv->util_fns;
	EAPOL_KeyMsg_t *pKeyMsg;
	KeyData_t GRKey;

	pKeyMsg = GetKeyMsgNonceFromEAPOL(priv, pmbuf, pKeyMgmtInfoSta);
	if (!pKeyMsg) {
		return NULL;
	}

	KeyMgmtSta_ApplyKEK(priv, pKeyMsg,
			    &pKeyMgmtInfoSta->GRKey,
			    pKeyMgmtInfoSta->EAPOL_Encr_Key);

	pKeyMgmtInfoSta->RSNDataTrafficEnabled = 1;
	//microTimerStop(pKeyMgmtInfoSta->rsnTimer);
	util_fns->moal_stop_timer(util_fns->pmoal_handle,
				  pKeyMgmtInfoSta->rsnTimer);
	//pKeyMgmtInfoSta->rsnTimer = 0;

	/* Decrypt the group key */
	if (pKeyMsg->desc_type == 2) {
		/* WPA2 */
		/* handle it according to 802.11i GTK frame format */
		parseKeyDataGTK(priv, pKeyMsg->key_data,
				pKeyMsg->key_material_len, &GRKey);
		/* Not install same GTK */
		if (!memcmp
		    (util_fns, pKeyMgmtInfoSta->GRKey.Key, GRKey.Key,
		     TK_SIZE)) {
			priv->gtk_installed = 1;
		} else {
			memcpy(util_fns, &pKeyMgmtInfoSta->GRKey, &GRKey,
			       sizeof(KeyData_t));
			pKeyMgmtInfoSta->GRKey.TxIV16 = GRKey.TxIV16;
			pKeyMgmtInfoSta->GRKey.TxIV32 = 0xFFFFFFFF;
			priv->gtk_installed = 0;
		}

		if (keyMgmtProcessMsgExt(priv, pKeyMgmtInfoSta, pKeyMsg) ==
		    FALSE) {
			return NULL;
		}
	} else {
		/* WPA or Dynamic WEP */
		if (!memcmp
		    (util_fns, pKeyMgmtInfoSta->GRKey.Key, pKeyMsg->key_data,
		     pKeyMsg->key_material_len)) {
			priv->gtk_installed = 1;
		} else {
			memcpy(util_fns, pKeyMgmtInfoSta->GRKey.Key,
			       pKeyMsg->key_data, pKeyMsg->key_material_len);

			pKeyMgmtInfoSta->GRKey.KeyIndex =
				pKeyMsg->key_info.KeyIndex;
		}
	}

	return pKeyMsg;
}
#endif

#ifdef WAR_ROM_BUG50312_SIMUL_INFRA_WFD
EAPOL_KeyMsg_t *
patch_ProcessRxEAPOL_PwkMsg3(phostsa_private priv, mlan_buffer *pmbuf,
			     keyMgmtInfoSta_t *pKeyMgmtInfoSta)
{
	hostsa_util_fns *util_fns = &priv->util_fns;
	EAPOL_KeyMsg_t *pKeyMsg;

	pKeyMsg = GetKeyMsgNonceFromEAPOL(priv, pmbuf, pKeyMgmtInfoSta);
	if (!pKeyMsg) {
		return NULL;
	}
	pKeyMgmtInfoSta->newPWKey.TxIV16 = 1;
	pKeyMgmtInfoSta->newPWKey.TxIV32 = 0;

	/* look for group key once the pairwise has been plumbed */
	if (pKeyMsg->key_info.EncryptedKeyData) {
		/* I think the timer stop should be moved later on
		   in case ramHook_Process_CCX_MFP_11r returns
		   FALSE
		 */

//        microTimerStop(pKeyMgmtInfoSta->rsnTimer);
		util_fns->moal_stop_timer(util_fns->pmoal_handle,
					  pKeyMgmtInfoSta->rsnTimer);
//        pKeyMgmtInfoSta->rsnTimer = 0;

		KeyMgmtSta_ApplyKEK(priv, pKeyMsg,
				    &pKeyMgmtInfoSta->GRKey,
				    pKeyMgmtInfoSta->EAPOL_Encr_Key);

		if (keyMgmtProcessMsgExt(priv, pKeyMgmtInfoSta, pKeyMsg) ==
		    FALSE) {
			return NULL;
		}

		parseKeyDataGTK(priv, pKeyMsg->key_data,
				pKeyMsg->key_material_len,
				&pKeyMgmtInfoSta->GRKey);

	}
	return pKeyMsg;
}
#endif

/* This routine must be called after mlmeStaInit_UR
** It assumes that parent session structures are initialized
** (vmacEntry_ur and mlmeStaInfo_URepeater)
*/
void
KeyMgmtInitSta(phostsa_private priv)
{
	KeyMgmtSta_InitSession(priv, &priv->suppData->keyMgmtInfoSta);
}

Status_e
GeneratePWKMsg2(phostsa_private priv, mlan_buffer *pmbuf,
		UINT8 *pSNonce, UINT8 *pEAPOLMICKey, UINT8 forceKeyDescVersion)
{
	hostsa_mlan_fns *pm_fns = &priv->mlan_fns;
	EAPOL_KeyMsg_Tx_t *pTxEapol = MNULL;
	UINT16 frameLen;
	UINT16 packet_len = 0;
	BOOLEAN rsnIeAdded = FALSE;
	EAPOL_KeyMsg_t *pRxEapol =
		(EAPOL_KeyMsg_t *)(pmbuf->pbuf + pmbuf->data_offset +
				   sizeof(ether_hdr_t));
	struct supplicantData *suppData = priv->suppData;
	pmlan_buffer newbuf = MNULL;
	UINT8 intf_hr_len =
		pm_fns->Hostsa_get_intf_hr_len(pm_fns->pmlan_private);

	PRINTM(MMSG, "ENTER: %s\n", __FUNCTION__);

	newbuf = pm_fns->hostsa_alloc_mlan_buffer(pm_fns->pmlan_adapter,
						  MLAN_TX_DATA_BUF_SIZE_2K, 0,
						  MOAL_MALLOC_BUFFER);
	if (newbuf) {
		newbuf->bss_index = pmbuf->bss_index;
		newbuf->buf_type = pmbuf->buf_type;
		newbuf->priority = pmbuf->priority;
		newbuf->in_ts_sec = pmbuf->in_ts_sec;
		newbuf->in_ts_usec = pmbuf->in_ts_usec;
		newbuf->data_offset =
			(sizeof(TxPD) + intf_hr_len + DMA_ALIGNMENT);
	}

	if (newbuf == NULL) {
		PRINTM(MERROR, "GeneratePWKMsg2 newbuf=NULL\n");
		return FAIL;
	}

	pTxEapol = (EAPOL_KeyMsg_Tx_t *)(newbuf->pbuf + newbuf->data_offset);
	KeyMgmtSta_PrepareEAPOLFrame(priv, pTxEapol,
				     pRxEapol,
				     (t_u8 *)&suppData->localBssid,
				     (t_u8 *)&suppData->localStaAddr, pSNonce);

#ifdef DOT11R
	if (dot11r_is_ft_akm(&connPtr->suppData->customMIB_RSNConfig.AKM)) {
		dot11r_process_pwk_msg2(connPtr, &pTxEapol->keyMsg);
		rsnIeAdded = TRUE;
	}
#endif

	if (!rsnIeAdded && (pTxEapol->keyMsg.desc_type != 1)) {
		/* Add the RSN/WPA IE if not dynamic WEP */
		pTxEapol->keyMsg.key_material_len
			= keyMgmtFormatWpaRsnIe(priv,
						(UINT8 *)&pTxEapol->keyMsg.
						key_data, &suppData->localBssid,
						&suppData->localStaAddr, NULL,
						FALSE);
	}
#ifdef CCX_MFP
	ccx_mfp_process_pwk_msg2(&pTxEapol->keyMsg);
#endif

	frameLen = KeyMgmtSta_PopulateEAPOLLengthMic(priv, pTxEapol,
						     pEAPOLMICKey,
						     EAPOL_PROTOCOL_V1,
						     forceKeyDescVersion);

	packet_len = frameLen + sizeof(Hdr_8021x_t) + sizeof(ether_hdr_t);
	UpdateEAPOLWcbLenAndTransmit(priv, newbuf, packet_len);

	PRINTM(MMSG, "LEAVE: %s\n", __FUNCTION__);
	return SUCCESS;
}

Status_e
GeneratePWKMsg4(phostsa_private priv, mlan_buffer *pmbuf,
		keyMgmtInfoSta_t *pKeyMgmtInfoSta, BOOLEAN groupKeyReceived)
{
	hostsa_mlan_fns *pm_fns = &priv->mlan_fns;
	struct supplicantData *suppData = priv->suppData;
	EAPOL_KeyMsg_Tx_t *pTxEapol;
	UINT16 frameLen;
	UINT16 packet_len = 0;
	EAPOL_KeyMsg_t *pRxEapol =
		(EAPOL_KeyMsg_t *)(pmbuf->pbuf + pmbuf->data_offset +
				   sizeof(ether_hdr_t));
	pmlan_buffer newbuf = MNULL;
	UINT8 intf_hr_len =
		pm_fns->Hostsa_get_intf_hr_len(pm_fns->pmlan_private);

	PRINTM(MMSG, "Enter GeneratePWKMsg4\n");

	newbuf = pm_fns->hostsa_alloc_mlan_buffer(pm_fns->pmlan_adapter,
						  MLAN_TX_DATA_BUF_SIZE_2K, 0,
						  MOAL_MALLOC_BUFFER);
	if (newbuf) {
		newbuf->bss_index = pmbuf->bss_index;
		newbuf->buf_type = pmbuf->buf_type;
		newbuf->priority = pmbuf->priority;
		newbuf->in_ts_sec = pmbuf->in_ts_sec;
		newbuf->in_ts_usec = pmbuf->in_ts_usec;
		newbuf->data_offset =
			(sizeof(TxPD) + intf_hr_len + DMA_ALIGNMENT);
	}

	if (newbuf == NULL) {
		PRINTM(MERROR, "GeneratePWKMsg4 newbuf=NULL\n");
		return FAIL;
	}

	pTxEapol = (EAPOL_KeyMsg_Tx_t *)(newbuf->pbuf + newbuf->data_offset);

	KeyMgmtSta_PrepareEAPOLFrame(priv, pTxEapol,
				     pRxEapol,
				     (t_u8 *)&suppData->localBssid,
				     (t_u8 *)&suppData->localStaAddr, NULL);

	frameLen = KeyMgmtSta_PopulateEAPOLLengthMic(priv, pTxEapol,
						     pKeyMgmtInfoSta->
						     EAPOL_MIC_Key,
						     EAPOL_PROTOCOL_V1, 0);

	/* Set the BuffDesc free callback so the PSK supplicant can determine
	 **  if the 4th message was successfully received by the AP.  Allows
	 **  the supplicant to hold off switching/setting the new key until
	 **  it is sure the AP has acknowledged the handshake completion
	 */
#if 0
	if (pKeyMgmtInfoSta->RSNDataTrafficEnabled) {
		pBufDesc->isCB = 1;
		if (groupKeyReceived) {
			pBufDesc->freeCallback = keyMgmtKeyPairAndGroupTxDone;
		} else {
			pBufDesc->freeCallback = keyMgmtKeyPairwiseTxDone;
		}
	} else {
#endif

		if (groupKeyReceived) {
			keyMgmtKeyPairAndGroupTxDone(priv);
		} else {
			keyMgmtKeyPairwiseTxDone(priv);
		}
#if 0
	}
#endif

	packet_len = frameLen + sizeof(Hdr_8021x_t) + sizeof(ether_hdr_t);
	UpdateEAPOLWcbLenAndTransmit(priv, newbuf, packet_len);

	PRINTM(MMSG, "Leave GeneratePWKMsg4\n");
	return SUCCESS;
}

Status_e
GenerateGrpMsg2(phostsa_private priv, mlan_buffer *pmbuf,
		keyMgmtInfoSta_t *pKeyMgmtInfoSta)
{
	hostsa_mlan_fns *pm_fns = &priv->mlan_fns;
	EAPOL_KeyMsg_t *pRxEapol =
		(EAPOL_KeyMsg_t *)(pmbuf->pbuf + pmbuf->data_offset +
				   sizeof(ether_hdr_t));
	EAPOL_KeyMsg_Tx_t *pTxEapol;
	UINT16 frameLen;
	UINT16 packet_len = 0;
	struct supplicantData *suppData = priv->suppData;
	pmlan_buffer newbuf = MNULL;
	UINT8 intf_hr_len =
		pm_fns->Hostsa_get_intf_hr_len(pm_fns->pmlan_private);

	PRINTM(MMSG, "ENTER: %s\n", __FUNCTION__);

	newbuf = pm_fns->hostsa_alloc_mlan_buffer(pm_fns->pmlan_adapter,
						  MLAN_TX_DATA_BUF_SIZE_2K, 0,
						  MOAL_MALLOC_BUFFER);
	if (newbuf) {
		newbuf->bss_index = pmbuf->bss_index;
		newbuf->buf_type = pmbuf->buf_type;
		newbuf->priority = pmbuf->priority;
		newbuf->in_ts_sec = pmbuf->in_ts_sec;
		newbuf->in_ts_usec = pmbuf->in_ts_usec;
		newbuf->data_offset =
			(sizeof(TxPD) + intf_hr_len + DMA_ALIGNMENT);
	}

	if (newbuf == NULL) {
		PRINTM(MERROR, "GenerateGrpMsg2 newbuf=NULL\n");
		return FAIL;
	}

	pTxEapol = (EAPOL_KeyMsg_Tx_t *)(newbuf->pbuf + newbuf->data_offset);

	KeyMgmtSta_PrepareEAPOLFrame(priv, pTxEapol,
				     pRxEapol,
				     (t_u8 *)&suppData->localBssid,
				     (t_u8 *)&suppData->localStaAddr, NULL);

	frameLen = KeyMgmtSta_PopulateEAPOLLengthMic(priv, pTxEapol,
						     pKeyMgmtInfoSta->
						     EAPOL_MIC_Key,
						     EAPOL_PROTOCOL_V1, 0);
//    pBufDesc->isCB = 1;
//    pBufDesc->freeCallback = keyMgmtKeyGroupTxDone;
	keyMgmtKeyGroupTxDone(priv);

	packet_len = frameLen + sizeof(Hdr_8021x_t) + sizeof(ether_hdr_t);
	UpdateEAPOLWcbLenAndTransmit(priv, newbuf, packet_len);

	PRINTM(MMSG, "LEAVE: %s\n", __FUNCTION__);
	return SUCCESS;
}

BOOLEAN
KeyMgmtStaHsk_Recvd_PWKMsg1(phostsa_private priv, mlan_buffer *pmbuf,
			    IEEEtypes_MacAddr_t *sa, IEEEtypes_MacAddr_t *da)
{
	EAPOL_KeyMsg_t *pKeyMsg = NULL;
	struct supplicantData *suppData = priv->suppData;
	keyMgmtInfoSta_t *pKeyMgmtInfoSta = &suppData->keyMgmtInfoSta;
	UINT8 *pPmk;
	BOOLEAN msgProcessed;
	BOOLEAN genPwkMsg2;
	BOOLEAN retval;
	UINT32 uMaxRetry = 5;	// MAX_SUPPLICANT_INIT_TIMEOUT

	PRINTM(MMSG, "ENTER: %s\n", __FUNCTION__);

	msgProcessed = FALSE;
	genPwkMsg2 = TRUE;
	retval = FALSE;

//#ifdef PSK_SUPPLICANT
	/* Wait for supplicant data to be initialized, which will complete
	 * after set channel/DPD trainign is complete
	 */
	while (uMaxRetry-- && (suppData->suppInitialized != TRUE)) {
//        OSATaskSleep(1);
	}
//#endif

	pKeyMsg = GetKeyMsgNonceFromEAPOL(priv, pmbuf, pKeyMgmtInfoSta);
	if (!pKeyMsg) {
		PRINTM(MERROR, "KeyMgmtStaHsk_Recvd_PWKMsg1 pKeyMsg is NULL\n");
		return FALSE;
	}
#ifdef DOT11R
	if (!msgProcessed &&
	    dot11r_is_ft_akm(&connPtr->suppData->customMIB_RSNConfig.AKM)) {
		dot11r_process_pwk_msg1(connPtr,
					sa,
					da,
					pKeyMgmtInfoSta->SNonce,
					pKeyMgmtInfoSta->ANonce);

		msgProcessed = TRUE;
		retval = TRUE;
	}
#endif
#ifdef PSK_SUPPLICANT_CCKM
	if (!msgProcessed && ccx_is_cckm_enabled(connPtr)) {
		retval = cckm_Recvd_PWKMsg1(connPtr,
					    sa,
					    da,
					    pEAPoLBufDesc,
					    pKeyMgmtInfoSta->SNonce,
					    (UINT8 *)connPtr->suppData->
					    hashSsId.SsId,
					    connPtr->suppData->hashSsId.Len);
		genPwkMsg2 = FALSE;
		msgProcessed = TRUE;
	}
#endif

	if (!msgProcessed
	    && supplicantAkmIsWpaWpa2(priv, &suppData->customMIB_RSNConfig.AKM))
	{
		if (supplicantAkmIsWpaWpa2Psk(priv,
					      &suppData->customMIB_RSNConfig.
					      AKM)) {
			/* Selected AKM Suite is PSK based */
			pPmk = pmkCacheFindPSK((void *)priv,
					       (UINT8 *)suppData->hashSsId.SsId,
					       suppData->hashSsId.Len);
		} else {
			pPmk = pmkCacheFindPMK(priv, &suppData->localBssid);
		}

		if (!pPmk) {
			PRINTM(MERROR,
			       "KeyMgmtStaHsk_Recvd_PWKMsg1 pPmk is NULL\n");
			return FALSE;
		}

		KeyMgmtSta_DeriveKeys(priv, pPmk,
				      (UINT8 *)da,
				      (UINT8 *)sa,
				      pKeyMgmtInfoSta->ANonce,
				      pKeyMgmtInfoSta->SNonce,
				      pKeyMgmtInfoSta->EAPOL_MIC_Key,
				      pKeyMgmtInfoSta->EAPOL_Encr_Key,
				      &pKeyMgmtInfoSta->newPWKey,
				      supplicantAkmUsesKdf(priv,
							   &suppData->
							   customMIB_RSNConfig.
							   AKM));

		retval = TRUE;

		/* PMKID checking not used by embedded supplicant.
		 ** Commenting out the code in case it needs to be
		 ** readded later.
		 */
#if 0
		/* Need to check for PMKID response */
		if (pKeyMsg->desc_type == 2) {
			if (keyLen) {
				KDE_t *pKde;

				/* Parse PMKID though it's _not used_ now */
				pKde = parseKeyKDE_DataType(pKeyMsg->key_data,
							    keyLen,
							    KDE_DATA_TYPE_PMKID);

				if (pKde
				    && gcustomMIB_RSNConfig.pmkidValid
				    && memcmp(pKde->data,
					      gcustomMIB_RSNConfig.PMKID,
					      sizeof(gcustomMIB_RSNConfig.
						     PMKID))) {
					/* PMKID could be invalid if generated based on an
					 ** old key. A new key should have been negotiated
					 ** We should regenerate PMKID and check it.
					 */
				}
			}
		}
#endif
	}

	if (genPwkMsg2) {
		/* construct Message 2 */
		if (GeneratePWKMsg2(priv, pmbuf,
				    pKeyMgmtInfoSta->SNonce,
				    pKeyMgmtInfoSta->EAPOL_MIC_Key,
				    0) != SUCCESS) {
			PRINTM(MERROR,
			       "KeyMgmtStaHsk_Recvd_PWKMsg1 GeneratePWKMsg2 Fail\n");
			retval = FALSE;
		}
	}

	if (retval == TRUE) {
#ifdef MIB_STATS
		INC_MIB_STAT(connPtr, eapolSentFrmFwCnt);
#endif
		updateApReplayCounter(priv, pKeyMgmtInfoSta,
				      (UINT8 *)pKeyMsg->replay_cnt);

		pKeyMgmtInfoSta->RSNSecured = FALSE;
	}

	PRINTM(MMSG, "LEAVE: %s\n", __FUNCTION__);
	return retval;
}

EAPOL_KeyMsg_t const *
KeyMgmtStaHsk_Recvd_PWKMsg3(phostsa_private priv, mlan_buffer *pmbuf)
{
	EAPOL_KeyMsg_t *pKeyMsg;
//    cm_ConnectionInfo_t* connPtr = pEAPoLBufDesc->intf.connPtr;
	struct supplicantData *suppData = priv->suppData;
	keyMgmtInfoSta_t *pKeyMgmtInfoSta = &suppData->keyMgmtInfoSta;

	PRINTM(MMSG, "ENTER: %s\n", __FUNCTION__);

#ifdef WAR_ROM_BUG50312_SIMUL_INFRA_WFD
	pKeyMsg = patch_ProcessRxEAPOL_PwkMsg3(pEAPoLBufDesc, pKeyMgmtInfoSta);
#else
	pKeyMsg = ProcessRxEAPOL_PwkMsg3(priv, pmbuf, pKeyMgmtInfoSta);
#endif
	if (!pKeyMsg) {
		PRINTM(MERROR, "KeyMgmtStaHsk_Recvd_PWKMsg3 pKeyMsg is NULL\n");
		return NULL;
	}

	/* construct Message 4 */
	if (GeneratePWKMsg4(priv, pmbuf,
			    pKeyMgmtInfoSta,
			    (pKeyMsg->desc_type == 2)) != SUCCESS) {
		PRINTM(MERROR,
		       "KeyMgmtStaHsk_Recvd_PWKMsg3 GeneratePWKMsg4 Fail\n");
		return pKeyMsg;
	}
#ifdef MIB_STATS
	INC_MIB_STAT(connPtr, eapolSentFrmFwCnt);
#endif

	updateApReplayCounter(priv, pKeyMgmtInfoSta,
			      (UINT8 *)pKeyMsg->replay_cnt);

	PRINTM(MMSG, "LEAVE: %s\n", __FUNCTION__);
	return NULL;
}

EAPOL_KeyMsg_t const *
KeyMgmtStaHsk_Recvd_GrpMsg1(phostsa_private priv, mlan_buffer *pmbuf)
{
	EAPOL_KeyMsg_t *pKeyMsg;
	struct supplicantData *suppData = priv->suppData;
	keyMgmtInfoSta_t *pKeyMgmtInfoSta = &suppData->keyMgmtInfoSta;

	PRINTM(MMSG, "ENTER: %s\n", __FUNCTION__);

#ifdef WAR_ROM_BUG50312_SIMUL_INFRA_WFD
	pKeyMsg = patch_ProcessRxEAPOL_GrpMsg1(priv, pKeyMgmtInfoSta);
#else
	pKeyMsg = ProcessRxEAPOL_GrpMsg1(priv, pmbuf, pKeyMgmtInfoSta);
#endif
	if (!pKeyMsg) {
		PRINTM(MERROR, "KeyMgmtStaHsk_Recvd_GrpMsg1 pKeyMsg is NULL\n");
		return NULL;
	}
	/* construct Message Grp Msg2 */
	if (GenerateGrpMsg2(priv, pmbuf, pKeyMgmtInfoSta) != SUCCESS) {
		PRINTM(MERROR,
		       "KeyMgmtStaHsk_Recvd_GrpMsg1 GenerateGrpMsg2 Fail\n");
		return NULL;
	}
#ifdef MIB_STATS
	INC_MIB_STAT(connPtr, eapolSentFrmFwCnt);
#endif

	updateApReplayCounter(priv, pKeyMgmtInfoSta,
			      (UINT8 *)pKeyMsg->replay_cnt);

	PRINTM(MMSG, "LEAVE: %s\n", __FUNCTION__);
	return pKeyMsg;
}

void
ProcessKeyMgmtDataSta(phostsa_private priv, mlan_buffer *pmbuf,
		      IEEEtypes_MacAddr_t *sa, IEEEtypes_MacAddr_t *da)
{
	UINT8 retry;
	EAPOL_KeyMsg_t *pKeyMsg =
		(EAPOL_KeyMsg_t *)(pmbuf->pbuf + pmbuf->data_offset +
				   sizeof(ether_hdr_t));

	retry = 0;

	if (pKeyMsg->key_info.KeyType) {
		/* PWK */
		if (pKeyMsg->key_info.KeyMIC) {
			/* 3rd msg in seq */
			KeyMgmtStaHsk_Recvd_PWKMsg3(priv, pmbuf);
		} else {
			while ((KeyMgmtStaHsk_Recvd_PWKMsg1(priv, pmbuf, sa, da)
				== FALSE)
			       && (retry < PWK_MSG1_RETRIES)) {
				/* Delay and retry Msg1 processing in case failure was
				 **  due to the host not having time to program a PMK
				 **  yet for 802.1x AKMPs
				 */
				//hal_WaitInUs(100);
				retry++;
			}
			//KeyMgmtStaHsk_Recvd_PWKMsg1(priv, pmbuf, sa, da);

		}
	} else {
		/* GRP */
		if (!KeyMgmtStaHsk_Recvd_GrpMsg1(priv, pmbuf)) {
#if defined(MEF_ENH) && defined(VISTA_802_11_DRIVER_INTERFACE)
			hostsleep_initiate_wakeup_with_reason
				(WOL_GRP_KEY_REFRESH_ERROR,
				 WOL_VACUOUS_PATTERN_ID);
#endif
		}
	}

}

#if 0
/*
**  This function send a MIC failure event to the AP
*/
void
SendMICFailReport_sta(cm_ConnectionInfo_t * connPtr,
		      keyMgmtInfoSta_t *pKeyMgmtInfoSta, BOOLEAN isUnicast)
{
	EAPOL_KeyMsg_Tx_t *pTxEapol;
	UINT16 frameLen;
	UINT32 int_sta;
	BufferDesc_t *pBufDesc;

	if (pKeyMgmtInfoSta->staCounterHi == 0xffffffff
	    && pKeyMgmtInfoSta->staCounterLo == 0xffffffff) {
		KeyMgmtResetCounter(pKeyMgmtInfoSta);
		return;
	}

	int_sta = os_if_save_EnterCriticalSection();

	/* Since there is a MIC failure drop all packets in Tx queue. */
	while ((pBufDesc = (BufferDesc_t *) getq(&wlan_data_q)) != NULL) {
		/* Do nothing here. We are just dropping the packet
		 **   and releasing the queue.
		 */
		mrvl_HandleTxDone(pBufDesc, 0);
	}

	os_if_save_ExitCriticalSection(int_sta);

	pBufDesc = GetTxEAPOLBuffer(connPtr, &pTxEapol, NULL);

	if (pBufDesc == NULL) {
		return;
	}
	KeyMgmtSta_PrepareEAPOLMicErrFrame(pTxEapol,
					   isUnicast,
					   &connPtr->suppData->localBssid,
					   &connPtr->suppData->localStaAddr,
					   pKeyMgmtInfoSta);
	SetEAPOLKeyDescTypeVersion(pTxEapol,
				   connPtr->suppData->customMIB_RSNConfig.
				   wpaType.wpa2,
				   supplicantAkmUsesKdf(&connPtr->suppData->
							customMIB_RSNConfig.
							AKM),
				   connPtr->suppData->customMIB_RSNConfig.
				   ucstCipher.ccmp);

	if (pKeyMgmtInfoSta->staCounterLo++ == 0) {
		pKeyMgmtInfoSta->staCounterHi++;
	}

	frameLen = KeyMgmtSta_PopulateEAPOLLengthMic(pTxEapol,
						     pKeyMgmtInfoSta->
						     EAPOL_MIC_Key,
						     EAPOL_PROTOCOL_V1, 0);

	UpdateEAPOLWcbLenAndTransmit(pBufDesc, frameLen);
}
#endif

#ifdef WAR_ROM_BUG57216_QUIET_TIME_INTERVAL
/* This function assumes that argument state would be either
    NO_MIC_FAILURE or FIRST_MIC_FAIL_IN_60_SEC
    It must not be called with state othe than these two
*/
#define MIC_ERROR_QUIET_TIME_INTERVAL           60000000	/* 60 sec */
#define MIC_ERROR_CHECK_TIME_INTERVAL         60000000

void
KeyMgmtSta_handleMICErr(MIC_Fail_State_e state,
			keyMgmtInfoSta_t *pKeyMgmtInfoSta,
			MicroTimerCallback_t callback, UINT8 flags)
{
	UINT32 expiry;
	UINT32 int_save = tx_interrupt_control(TX_INT_DISABLE);

	if (state == NO_MIC_FAILURE) {
		/* First MIC failure */
		pKeyMgmtInfoSta->sta_MIC_Error.status =
			FIRST_MIC_FAIL_IN_60_SEC;
		expiry = MIC_ERROR_CHECK_TIME_INTERVAL;
	} else {
		/* Received 2 MIC failures within 60 sec. Do deauth from AP */
		pKeyMgmtInfoSta->sta_MIC_Error.disableStaAsso = 1;
		pKeyMgmtInfoSta->sta_MIC_Error.status =
			SECOND_MIC_FAIL_IN_60_SEC;
		pKeyMgmtInfoSta->apCounterHi = 0;
		pKeyMgmtInfoSta->apCounterLo = 0;
		expiry = MIC_ERROR_QUIET_TIME_INTERVAL;
	}
	tx_interrupt_control(int_save);
#if 0
	microTimerStop(pKeyMgmtInfoSta->micTimer);

	microTimerStart(callback,
			(UINT32)pKeyMgmtInfoSta,
			expiry, &pKeyMgmtInfoSta->micTimer, flags);
#endif
}
#endif

#if 0
void
supplicantMICCounterMeasureInvoke(cm_ConnectionInfo_t * connPtr,
				  BOOLEAN isUnicast)
{
	MIC_Fail_State_e state;
	keyMgmtInfoSta_t *pKeyMgmtInfoSta = &connPtr->suppData->keyMgmtInfoSta;

	if (pKeyMgmtInfoSta->sta_MIC_Error.MICCounterMeasureEnabled) {
		state = pKeyMgmtInfoSta->sta_MIC_Error.status;

		/* Watchdog and clear any pending TX packets to ensure that
		 ** We are able to get a TX buffer
		 */
		tx_watchdog_recovery();
		SendMICFailReport_sta(connPtr, pKeyMgmtInfoSta, isUnicast);

		switch (state) {
		case NO_MIC_FAILURE:
			/* Received 1st MIC failure */
			/* Noneed to check if timer is active. It will not be active
			 ** cause this is the first state
			 */
			KeyMgmtSta_handleMICErr(state,
						pKeyMgmtInfoSta,
						MicErrTimerExp_Sta,
						MICRO_TIMER_FLAG_KILL_ON_PS_ENTRY);

			connPtr->suppData->customMIB_RSNStats.
				TKIPLocalMICFailures++;

			break;

		case FIRST_MIC_FAIL_IN_60_SEC:
			/* Received 2 MIC failures within 60 sec. Do deauth from AP */
			connPtr->suppData->customMIB_RSNStats.
				TKIPCounterMeasuresInvoked++;

			KeyMgmtSta_handleMICErr(state,
						pKeyMgmtInfoSta,
						MicErrTimerExp_Sta,
						MICRO_TIMER_FLAG_KILL_ON_PS_ENTRY);

			/* Is this really needed? */
			pKeyMgmtInfoSta->connPtr = connPtr;

			KeyMgmtSta_handleMICDeauthTimer(pKeyMgmtInfoSta,
							DeauthDelayTimerExp_Sta,
							DEAUTH_DELAY_TIME_INTERVAL,
							MICRO_TIMER_FLAG_KILL_ON_PS_ENTRY);

			break;

		case SECOND_MIC_FAIL_IN_60_SEC:
			/*No need to do anything. Everything has been taken care of by
			 ** the above state
			 */

		default:
			break;
		}
	}
	return;
}
#endif
/*
  Start the key Management session
*/
void
keyMgmtSta_StartSession(phostsa_private priv,
			IEEEtypes_MacAddr_t *pBssid,
			IEEEtypes_MacAddr_t *pStaAddr)
{
	hostsa_util_fns *util_fns = &priv->util_fns;
	keyMgmtInfoSta_t *pKeyMgmtInfoSta = &priv->suppData->keyMgmtInfoSta;

	//pKeyMgmtInfoSta->psapriv = priv;

	memcpy(util_fns, &priv->suppData->localStaAddr,
	       pStaAddr, sizeof(priv->suppData->localStaAddr));
	memcpy(util_fns, &priv->suppData->localBssid,
	       pBssid, sizeof(priv->suppData->localBssid));

	keyMgmtSta_StartSession_internal(priv, pKeyMgmtInfoSta,
					 //keyMgmtStaRsnSecuredTimeoutHandler,
					 RSNSECUREDTIMEOUT, 0);	//MICRO_TIMER_FLAG_KILL_ON_PS_ENTRY);

}

void
supplicantClrEncryptKey(void *priv)
{
	phostsa_private psapriv = (phostsa_private)priv;
	hostsa_mlan_fns *pm_fns = NULL;

	if (!psapriv)
		return;

	pm_fns = &psapriv->mlan_fns;
	pm_fns->hostsa_clr_encrypt_key(psapriv->pmlan_private);
}

UINT32
keyApi_UpdateKeyMaterial(void *priv, key_MgtMaterial_t *keyMgtData_p)
{
	phostsa_private psapriv = (phostsa_private)priv;
	hostsa_util_fns *util_fns = &psapriv->util_fns;
	hostsa_mlan_fns *pm_fns = &psapriv->mlan_fns;
	//UINT8 wepKeyIndex;
	mlan_ds_encrypt_key encrypt_key;
	t_u8 bcast_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };

	memset(util_fns, &encrypt_key, 0, sizeof(mlan_ds_encrypt_key));

	PRINTM(MMSG, "keyApi_UpdateKeyMaterial keyType=%x keyLen=%x\n",
	       keyMgtData_p->keyType, keyMgtData_p->keyLen);
	switch (keyMgtData_p->keyType) {
	case KEY_TYPE_TKIP:
	case KEY_TYPE_AES:
		/* The Key Info definition for TKIP and AES is the same */
		if (keyMgtData_p->keyInfo & KEY_INFO_UNICAST) {
			/* Unicast Key */
			//SET_KEY_STATE_ENABLED(pwkey,
			//                      (keyMgtData_p->keyInfo
			//                        & KEY_INFO_ENABLED)? TRUE : FALSE);
			//pwkey->hdr.keyType = keyMgtData_p->keyType;
			//pwkey->hdr.keyDirection = KEY_DIRECTION_RXTX;
			//pwkey->hdr.keyLen = keyMgtData_p->keyLen;

			//if (IS_KEY_STATE_ENABLED(pwkey))
			//{
			//    ramHook_keyApiSta_setConnDataTrafficEnabled(connPtr, TRUE);
			//     ramHook_keyApiSta_setConnCurPktTxEnabled(connPtr, TRUE);
			//     SET_KEY_STATE_FORCE_EAPOL_UNENCRYPTED(pwkey, TRUE);
			// }
			encrypt_key.key_flags |= KEY_FLAG_SET_TX_KEY;
			encrypt_key.key_len = keyMgtData_p->keyLen;
			memcpy(util_fns, encrypt_key.mac_addr,
			       psapriv->suppData->localBssid, MAC_ADDR_SIZE);

			/* The Key Material is different */
			if (keyMgtData_p->keyLen &&
			    (keyMgtData_p->keyType == KEY_TYPE_TKIP)) {
				/* Update key if included */
				memcpy(util_fns,
				       (void *)encrypt_key.key_material,
				       (const void *)keyMgtData_p->keyEncypt.
				       TKIP.key, TK_SIZE);
				memcpy(util_fns,
				       (void *)&encrypt_key.
				       key_material[TK_SIZE],
				       (const void *)keyMgtData_p->keyEncypt.
				       TKIP.txMicKey, MIC_KEY_SIZE);
				memcpy(util_fns,
				       (void *)&encrypt_key.
				       key_material[TK_SIZE + MIC_KEY_SIZE],
				       (const void *)keyMgtData_p->keyEncypt.
				       TKIP.rxMicKey, MIC_KEY_SIZE);
			} else if (keyMgtData_p->keyLen &&
				   (keyMgtData_p->keyType == KEY_TYPE_AES)) {
				/* Update key if included */
				memcpy(util_fns,
				       (uint8 *)encrypt_key.key_material,
				       (uint8 *)keyMgtData_p->keyEncypt.AES.key,
				       TK_SIZE);

				/* duplicate to group key,
				 * for adhoc aes to use.
				 */
				//if (!IS_KEY_STATE_ENABLED(gwkey))
				// {
				/* Multicast Key */
				//   SET_KEY_STATE_ENABLED(gwkey,
				//                          (keyMgtData_p->keyInfo
				//                          & KEY_INFO_ENABLED) ? TRUE : FALSE);
				//   gwkey->hdr.keyType = keyMgtData_p->keyType;
				//   gwkey->hdr.keyDirection = KEY_DIRECTION_RXTX;
				//   gwkey->hdr.keyLen = keyMgtData_p->keyLen;
				//    if (IS_KEY_STATE_ENABLED(gwkey))
				//    {
				//       gwkey->ckd.tkip_aes.loReplayCounter16 = 0;
				//      gwkey->ckd.tkip_aes.hiReplayCounter32 = 0xffffffff;
				//   }
				//   memcpy((uint8*)gwkey->ckd.tkip_aes.key,
				//         (uint8*)keyMgtData_p->keyEncypt.AES.key,
				//         TK_SIZE);
				// }
			}
		}

		if (keyMgtData_p->keyInfo & KEY_INFO_MULTICAST) {
			/* Multicast Key */
			//SET_KEY_STATE_ENABLED(gwkey,
			//                      (keyMgtData_p->
			//                       keyInfo & KEY_INFO_ENABLED) ? TRUE :
			//                      FALSE);
			//gwkey->hdr.keyType = keyMgtData_p->keyType;
			//gwkey->hdr.keyDirection = KEY_DIRECTION_RXTX;
			//gwkey->hdr.keyLen = keyMgtData_p->keyLen;
			//if (IS_KEY_STATE_ENABLED(gwkey))
			//{
			//     gwkey->ckd.tkip_aes.loReplayCounter16 = 0;
			//    gwkey->ckd.tkip_aes.hiReplayCounter32 = 0xffffffff;

			//    if (!IS_KEY_STATE_ENABLED(pwkey))
			//     {
			//        gwkey->ckd.tkip_aes.txIV32 = 0x0;
			//       gwkey->ckd.tkip_aes.txIV16 = 0x1;
			//       ramHook_keyApiSta_setConnDataTrafficEnabled(connPtr, TRUE);
			//      ramHook_keyApiSta_setConnCurPktTxEnabled(connPtr, TRUE);
			//  }
			// }
			encrypt_key.key_flags |= KEY_FLAG_GROUP_KEY;
			encrypt_key.key_len = keyMgtData_p->keyLen;
			memcpy(util_fns, encrypt_key.mac_addr, bcast_addr,
			       MAC_ADDR_SIZE);

			if (keyMgtData_p->keyLen &&
			    (keyMgtData_p->keyType == KEY_TYPE_TKIP)) {
				/* Update key if included */
				memcpy(util_fns,
				       (void *)encrypt_key.key_material,
				       (const void *)keyMgtData_p->keyEncypt.
				       TKIP.key, TK_SIZE);
				memcpy(util_fns,
				       (void *)&encrypt_key.
				       key_material[TK_SIZE],
				       (const void *)keyMgtData_p->keyEncypt.
				       TKIP.txMicKey, MIC_KEY_SIZE);
				memcpy(util_fns,
				       (void *)&encrypt_key.
				       key_material[TK_SIZE + MIC_KEY_SIZE],
				       (const void *)keyMgtData_p->keyEncypt.
				       TKIP.rxMicKey, MIC_KEY_SIZE);
			} else if (keyMgtData_p->keyLen &&
				   (keyMgtData_p->keyType == KEY_TYPE_AES)) {
				/* Update key if included */
				memcpy(util_fns,
				       (uint8 *)encrypt_key.key_material,
				       (uint8 *)keyMgtData_p->keyEncypt.AES.key,
				       TK_SIZE);
			}
		}
	/**set pn 0*/
		memset(util_fns, encrypt_key.pn, 0, sizeof(encrypt_key.pn));
	/**key flag*/
		encrypt_key.key_flags |= KEY_FLAG_RX_SEQ_VALID;

		//ramHook_keyApi_PalladiumHook1(connPtr);
	/**set command to fw update key*/
		pm_fns->hostsa_set_encrypt_key((void *)psapriv->pmlan_private,
					       &encrypt_key);

		break;

#ifndef WAR_ROM_BUG54733_PMF_SUPPORT
	case KEY_TYPE_AES_CMAC:
		if ( /*NULL != igwkey && */
			(keyMgtData_p->keyInfo & KEY_INFO_MULTICAST_IGTK)) {
			/* Multicast Key */
			//SET_KEY_STATE_ENABLED(igwkey,
			//                                        (keyMgtData_p->keyInfo
			//                                        & KEY_INFO_ENABLED) ? TRUE : FALSE);
			//igwkey->hdr.keyType = keyMgtData_p->keyType;
			//igwkey->hdr.keyDirection = KEY_DIRECTION_RXTX;
			//igwkey->hdr.keyLen = keyMgtData_p->keyLen;
			if (keyMgtData_p->keyLen) {
				/* Update IPN if included */
				//memcpy((UINT8 *)&igwkey->ckd.tkip_aes.loReplayCounter16,
				//              (UINT8 *)&keyMgtData_p->keyEncypt.iGTK.ipn[0],
				//              sizeof(igwkey->ckd.tkip_aes.loReplayCounter16));

				//memcpy((UINT8 *)&igwkey->ckd.tkip_aes.hiReplayCounter32,
				//              (UINT8 *)&keyMgtData_p->keyEncypt.iGTK.ipn[2],
				//              sizeof(igwkey->ckd.tkip_aes.hiReplayCounter32));

				/* Update key if included */
				//memcpy((UINT8 *)igwkey->ckd.tkip_aes.key,
				//         (UINT8 *)keyMgtData_p->keyEncypt.iGTK.key,
				//         CRYPTO_AES_CMAC_KEY_LEN);
				memcpy(util_fns,
				       (uint8 *)encrypt_key.key_material,
				       (UINT8 *)keyMgtData_p->keyEncypt.iGTK.
				       key, CRYPTO_AES_CMAC_KEY_LEN);
			}
			/**set pn 0*/
			memset(util_fns, encrypt_key.pn, 0,
			       sizeof(encrypt_key.pn));
			/**key flag*/
			encrypt_key.key_flags |= KEY_FLAG_RX_SEQ_VALID;

			//ramHook_keyApi_PalladiumHook1(connPtr);
			/**set command to fw update key*/
			pm_fns->hostsa_set_encrypt_key(psapriv->pmlan_private,
						       &encrypt_key);
		}
		break;
#endif
	}

	return 0;
}

void
FillKeyMaterialStruct(phostsa_private priv,
		      UINT16 key_len, UINT8 isPairwise, KeyData_t *pKey)
{
	key_MgtMaterial_t keyMgtData;

#ifdef MIB_STATS
	if (isPairwise) {
		INC_MIB_STAT(connPtr, PTKSentFrmESUPPCnt);
	} else {
		INC_MIB_STAT(connPtr, GTKSentFrmESUPPCnt);
	}
#endif

	FillKeyMaterialStruct_internal(priv, &keyMgtData, key_len, isPairwise,
				       pKey);
	keyApi_UpdateKeyMaterial(priv, &keyMgtData);
}

void
FillGrpKeyMaterialStruct(phostsa_private priv,
			 UINT16 keyType,
			 UINT8 *pn, UINT8 keyIdx, UINT8 keyLen, KeyData_t *pKey)
{
	hostsa_util_fns *util_fns = &priv->util_fns;
	key_MgtMaterial_t keyMgtData;

	if (keyType == KDE_DATA_TYPE_IGTK) {
		memset(util_fns, (void *)&keyMgtData, 0x00, sizeof(keyMgtData));

		keyMgtData.keyType = KEY_TYPE_AES_CMAC;
		keyMgtData.keyInfo = KEY_INFO_MULTICAST_IGTK | KEY_INFO_ENABLED;
		keyMgtData.keyLen = keyLen;

		memcpy(util_fns, keyMgtData.keyEncypt.iGTK.ipn, pn,
		       CRYPTO_AES_CMAC_IPN_LEN);
		memcpy(util_fns, keyMgtData.keyEncypt.iGTK.key, pKey->Key,
		       keyLen);
	} else {
		FillKeyMaterialStruct_internal(priv, &keyMgtData, keyLen, FALSE,
					       pKey);
	}

	keyApi_UpdateKeyMaterial(priv, &keyMgtData);
}

void
supplicantInitSession(void *priv,
		      t_u8 *pSsid, t_u16 len, t_u8 *pBssid, t_u8 *pStaAddr)
{
	phostsa_private psapriv = (phostsa_private)priv;
	hostsa_util_fns *util_fns = &psapriv->util_fns;

	if (supplicantIsEnabled((void *)psapriv)) {
		KeyMgmtInitSta(psapriv);
		memcpy(util_fns, (void *)psapriv->suppData->hashSsId.SsId,
		       pSsid, len);
		psapriv->suppData->hashSsId.Len = len;
		keyMgmtSta_StartSession(psapriv, (IEEEtypes_MacAddr_t *)pBssid,
					(IEEEtypes_MacAddr_t *)pStaAddr);
		psapriv->suppData->suppInitialized = TRUE;
		psapriv->gtk_installed = 0;
	}
}

UINT8
supplicantIsCounterMeasuresActive(phostsa_private priv)
{
	return priv->suppData->keyMgmtInfoSta.sta_MIC_Error.disableStaAsso;
}

//#endif

void
init_customApp_mibs(phostsa_private priv, supplicantData_t *suppData)
{
	hostsa_util_fns *util_fns = &priv->util_fns;

	memset(util_fns, &suppData->customMIB_RSNStats,
	       0x00, sizeof(suppData->customMIB_RSNStats));
	memset(util_fns, &suppData->customMIB_RSNConfig,
	       0x00, sizeof(suppData->customMIB_RSNConfig));
	/* keep noRsn = 1 as default setting */
	suppData->customMIB_RSNConfig.wpaType.noRsn = 1;

}

SecurityMode_t
supplicantCurrentSecurityMode(phostsa_private priv)
{
	return (priv->suppData->customMIB_RSNConfig.wpaType);
}

AkmSuite_t *
supplicantCurrentAkmSuite(phostsa_private priv)
{
	return &priv->suppData->customMIB_RSNConfig.AKM;
}

//#pragma arm section code = ".wlandatapathcode"
t_u8
supplicantIsEnabled(void *priv)
{
	phostsa_private psapriv = (phostsa_private)priv;

	if (!psapriv || psapriv->suppData == NULL) {
		return 0;
	}

	return (psapriv->suppData->customMIB_RSNConfig.RSNEnabled);
}

//#pragma arm section code

void
supplicantDisable(void *priv)
{
	phostsa_private psapriv = (phostsa_private)priv;

	if (!supplicantIsEnabled((void *)psapriv)) {
		return;
	}
	psapriv->suppData->customMIB_RSNConfig.RSNEnabled = 0;
	init_customApp_mibs(psapriv, psapriv->suppData);

	PRINTM(MMSG, "supplicantDisable RSNEnabled=%x\n",
	       psapriv->suppData->customMIB_RSNConfig.RSNEnabled);
}

void
supplicantQueryPassphraseAndEnable(void *priv, t_u8 *pbuf)
{
	phostsa_private psapriv = (phostsa_private)priv;
	pmkElement_t *pPMKElement = MNULL;
	mlan_ssid_bssid *ssid_bssid = (mlan_ssid_bssid *)pbuf;
	mlan_802_11_ssid *pssid = &ssid_bssid->ssid;

	if (!psapriv || psapriv->suppData == NULL)
		return;
	if (!ssid_bssid)
		return;
	if (!pssid->ssid_len)
		return;
	/* extract the PSK from the cache entry */
	pPMKElement =
		pmkCacheFindPSKElement((void *)psapriv, pssid->ssid,
				       pssid->ssid_len);
	if (pPMKElement)
		psapriv->suppData->customMIB_RSNConfig.RSNEnabled = 1;
	else
		psapriv->suppData->customMIB_RSNConfig.RSNEnabled = 0;

	PRINTM(MMSG,
	       "supplicantQueryPassphraseAndEnable RSNEnabled=%x ssid=%s\n",
	       psapriv->suppData->customMIB_RSNConfig.RSNEnabled, pssid->ssid);
}

void
supplicantSetAssocRsn(phostsa_private priv,
		      SecurityMode_t wpaType,
		      Cipher_t *pMcstCipher,
		      Cipher_t *pUcstCipher,
		      AkmSuite_t *pAkm,
		      IEEEtypes_RSNCapability_t *pRsnCap,
		      Cipher_t *pGrpMgmtCipher)
{
	hostsa_util_fns *util_fns = &priv->util_fns;
	IEEEtypes_RSNCapability_t rsnCap;

	if (pRsnCap == NULL) {
		/* It is being added as an IOT workaround for APs that
		 * do not properly handle association requests that omit
		 * the RSN Capability field in the RSN IE
		 */
		memset(util_fns, &rsnCap, 0x00, sizeof(rsnCap));
		pRsnCap = &rsnCap;
	}

	supplicantSetAssocRsn_internal(priv,
				       &priv->suppData->customMIB_RSNConfig,
				       &priv->suppData->currParams,
				       wpaType,
				       pMcstCipher,
				       pUcstCipher,
				       pAkm, pRsnCap, pGrpMgmtCipher);
}

UINT16
keyMgmtFormatWpaRsnIe(phostsa_private priv,
		      UINT8 *pos,
		      IEEEtypes_MacAddr_t *pBssid,
		      IEEEtypes_MacAddr_t *pStaAddr,
		      UINT8 *pPmkid, BOOLEAN addPmkid)
{
	struct supplicantData *suppData = priv->suppData;

	return keyMgmtFormatWpaRsnIe_internal(priv,
					      &suppData->customMIB_RSNConfig,
					      pos,
					      pBssid,
					      pStaAddr, pPmkid, addPmkid);
}

static void
install_wpa_none_keys(phostsa_private priv, UINT8 type, UINT8 unicast)
{
	UINT8 *pPMK;
	key_MgtMaterial_t keyMgtData;

	pPMK = pmkCacheFindPSK((void *)priv,
			       (UINT8 *)priv->suppData->hashSsId.SsId,
			       priv->suppData->hashSsId.Len);
	if (pPMK == NULL) {
		return;
	}

	install_wpa_none_keys_internal(priv, &keyMgtData, pPMK, type, unicast);

	keyApi_UpdateKeyMaterial(priv, &keyMgtData);

	/* there's no timer or other to initialize */
	KeyMgmtInitSta(priv);
	priv->suppData->keyMgmtInfoSta.RSNSecured = TRUE;
}

void
supplicantInstallWpaNoneKeys(phostsa_private priv)
{
	if (priv->suppData->customMIB_RSNConfig.RSNEnabled
	    && priv->suppData->customMIB_RSNConfig.wpaType.wpaNone) {
		install_wpa_none_keys(priv,
				      priv->suppData->customMIB_RSNConfig.
				      mcstCipher.ccmp, 0);
		install_wpa_none_keys(priv,
				      priv->suppData->customMIB_RSNConfig.
				      mcstCipher.ccmp, 1);
	}
}

void
supplicantSetProfile(phostsa_private priv,
		     SecurityMode_t wpaType,
		     Cipher_t mcstCipher, Cipher_t ucstCipher)
{
	priv->suppData->currParams.wpaType = wpaType;
	priv->suppData->currParams.mcstCipher = mcstCipher;
	priv->suppData->currParams.ucstCipher = ucstCipher;
}

void
supplicantGetProfile(phostsa_private priv,
		     SecurityMode_t *pWpaType,
		     Cipher_t *pMcstCipher, Cipher_t *pUcstCipher)
{
	*pWpaType = priv->suppData->currParams.wpaType;
	*pMcstCipher = priv->suppData->currParams.mcstCipher;
	*pUcstCipher = priv->suppData->currParams.ucstCipher;
}

void
supplicantGetProfileCurrent(phostsa_private priv,
			    SecurityMode_t *pWpaType,
			    Cipher_t *pMcstCipher, Cipher_t *pUcstCipher)
{
	*pWpaType = priv->suppData->customMIB_RSNConfig.wpaType;
	*pMcstCipher = priv->suppData->customMIB_RSNConfig.mcstCipher;
	*pUcstCipher = priv->suppData->customMIB_RSNConfig.ucstCipher;
}

void
supplicantInit(void *priv, supplicantData_t *suppData)
{
	phostsa_private psapriv = (phostsa_private)priv;
	hostsa_util_fns *util_fns = &psapriv->util_fns;

	init_customApp_mibs(priv, suppData);

	memset(util_fns, &suppData->currParams, 0xff, sizeof(SecurityParams_t));
	memset(util_fns, &suppData->keyMgmtInfoSta, 0,
	       sizeof(keyMgmtInfoSta_t));
	suppData->keyMgmtInfoSta.sta_MIC_Error.disableStaAsso = 0;
	suppData->keyMgmtInfoSta.sta_MIC_Error.MICCounterMeasureEnabled = 1;
	suppData->keyMgmtInfoSta.sta_MIC_Error.status = NO_MIC_FAILURE;
	KeyMgmtResetCounter(&suppData->keyMgmtInfoSta);
}

void
supplicantStopSessionTimer(void *priv)
{
	phostsa_private psapriv = (phostsa_private)priv;
	hostsa_util_fns *util_fns = NULL;

	if (!psapriv || psapriv->suppData == NULL) {
		return;
	}

	util_fns = &psapriv->util_fns;
	if (psapriv->suppData->keyMgmtInfoSta.rsnTimer) {
		util_fns->moal_stop_timer(util_fns->pmoal_handle,
					  psapriv->suppData->keyMgmtInfoSta.
					  rsnTimer);
		//priv->suppData->keyMgmtInfoSta.rsnTimer = 0;
	}
}

void
supplicantSmeResetNotification(phostsa_private priv)
{
	supplicantStopSessionTimer(priv);
}

UINT16
keyMgmtGetKeySize(phostsa_private priv, UINT8 isPairwise)
{
	return keyMgmtGetKeySize_internal(&priv->suppData->customMIB_RSNConfig,
					  isPairwise);
}

void
keyMgmtSetMICKey(phostsa_private priv, UINT8 *pKey)
{
	hostsa_util_fns *util_fns = &priv->util_fns;

	memcpy(util_fns, priv->suppData->keyMgmtInfoSta.EAPOL_MIC_Key,
	       pKey, sizeof(priv->suppData->keyMgmtInfoSta.EAPOL_MIC_Key));
}

UINT8 *
keyMgmtGetMICKey(phostsa_private priv)
{
	return (priv->suppData->keyMgmtInfoSta.EAPOL_MIC_Key);
}

void
keyMgmtSetEAPOLEncrKey(phostsa_private priv, UINT8 *pKey)
{
	hostsa_util_fns *util_fns = &priv->util_fns;

	memcpy(util_fns, priv->suppData->keyMgmtInfoSta.EAPOL_Encr_Key,
	       pKey, sizeof(priv->suppData->keyMgmtInfoSta.EAPOL_Encr_Key));
}

void
keyMgmtSetTemporalKeyOnly(phostsa_private priv, UINT8 *pTk)
{
	hostsa_util_fns *util_fns = &priv->util_fns;

	memcpy(util_fns, &priv->suppData->keyMgmtInfoSta.newPWKey.Key,
	       pTk, sizeof(priv->suppData->keyMgmtInfoSta.newPWKey.Key));
}

UINT8 *
keyMgmtGetEAPOLEncrKey(phostsa_private priv)
{
	return (priv->suppData->keyMgmtInfoSta.EAPOL_Encr_Key);
}

void
keyMgmtSetPairwiseKey(phostsa_private priv, KeyData_t *pKey)
{
	hostsa_util_fns *util_fns = &priv->util_fns;

	memcpy(util_fns, &priv->suppData->keyMgmtInfoSta.newPWKey,
	       pKey, sizeof(priv->suppData->keyMgmtInfoSta.newPWKey));
}

void
keyMgmtSetGroupKey(phostsa_private priv, KeyData_t *pKey)
{
	hostsa_util_fns *util_fns = &priv->util_fns;

	memcpy(util_fns, &priv->suppData->keyMgmtInfoSta.GRKey,
	       pKey, sizeof(priv->suppData->keyMgmtInfoSta.GRKey));

	FillKeyMaterialStruct(priv,
			      keyMgmtGetKeySize(priv, FALSE), FALSE, pKey);
}

void
keyMgmtSetGtk(phostsa_private priv, IEEEtypes_GtkElement_t * pGtk, UINT8 *pKek)
{
	hostsa_util_fns *util_fns = &priv->util_fns;
	UINT8 encrKeyLen;

	/* Determine the encrypted key field length from the IE length */
	encrKeyLen = pGtk->Len - (sizeof(pGtk->KeyInfo) +
				  sizeof(pGtk->KeyLen) + sizeof(pGtk->RSC));

	MRVL_AesUnWrap(pKek,
		       2,
		       encrKeyLen / 8 - 1,
		       (UINT8 *)pGtk->Key, NULL, (UINT8 *)pGtk->Key);

	memcpy(util_fns, &priv->suppData->keyMgmtInfoSta.GRKey.Key,
	       (UINT8 *)pGtk->Key,
	       sizeof(priv->suppData->keyMgmtInfoSta.GRKey.Key));

	FillGrpKeyMaterialStruct(priv,
				 KDE_DATA_TYPE_GTK,
				 pGtk->RSC,
				 pGtk->KeyInfo.KeyId,
				 pGtk->KeyLen,
				 &priv->suppData->keyMgmtInfoSta.GRKey);
}

void
keyMgmtSetIGtk(phostsa_private priv, keyMgmtInfoSta_t *pKeyMgmtInfoSta,
	       IGtkKde_t *pIGtkKde, UINT8 iGtkKdeLen)
{
	hostsa_util_fns *util_fns = &priv->util_fns;
	UINT8 iGtkLen;

	iGtkLen = iGtkKdeLen - 12;	/* OUI + dataType + keyId + IPN = 12 bytes */

	memcpy(util_fns, &pKeyMgmtInfoSta->IGtk.Key,
	       (UINT8 *)pIGtkKde->IGtk,
	       MIN(sizeof(pKeyMgmtInfoSta->IGtk.Key), iGtkLen));

	FillGrpKeyMaterialStruct(priv,
				 KDE_DATA_TYPE_IGTK,
				 pIGtkKde->IPN,
				 pIGtkKde->keyId[0],
				 iGtkLen, &pKeyMgmtInfoSta->IGtk);

}

UINT8 *
keyMgmtGetIGtk(phostsa_private priv)
{
	return (priv->suppData->keyMgmtInfoSta.IGtk.Key);
}

void
keyMgmtPlumbPairwiseKey(phostsa_private priv)
{
	hostsa_util_fns *util_fns = &priv->util_fns;

	memcpy(util_fns, &priv->suppData->keyMgmtInfoSta.PWKey,
	       &priv->suppData->keyMgmtInfoSta.newPWKey,
	       sizeof(priv->suppData->keyMgmtInfoSta.PWKey));

	FillKeyMaterialStruct(priv,
			      keyMgmtGetKeySize(priv, TRUE),
			      TRUE, &priv->suppData->keyMgmtInfoSta.PWKey);
}

#if 0
#pragma arm section code = ".wlandatapathcode"
void
keyMgmtSuccessfulDecryptNotify(cm_ConnectionInfo_t * connPtr,
			       cipher_key_t *pRxCipherKey)
{
	if (supplicantIsEnabled(connPtr)) {
		connPtr->suppData->keyMgmtInfoSta.pRxDecryptKey = pRxCipherKey;

		if (connPtr->suppData->keyMgmtInfoSta.pRxDecryptKey &&
		    (!connPtr->suppData->customMIB_RSNConfig.RSNEnabled ||
		     (connPtr->suppData->customMIB_RSNConfig.RSNEnabled &&
		      connPtr->suppData->keyMgmtInfoSta.pwkHandshakeComplete)))
		{
			SET_KEY_STATE_FORCE_EAPOL_UNENCRYPTED(connPtr->
							      suppData->
							      keyMgmtInfoSta.
							      pRxDecryptKey,
							      FALSE);
		}
	} else {
		if (pRxCipherKey &&
		    (!connPtr->cmFlags.RSNEnabled ||
		     (connPtr->cmFlags.RSNEnabled &&
		      connPtr->cmFlags.gDataTrafficEnabled))) {
			SET_KEY_STATE_FORCE_EAPOL_UNENCRYPTED(pRxCipherKey,
							      FALSE);
		}
	}
}

#pragma arm section code
#endif
static void
keyMgmtKeyGroupTxDone(phostsa_private priv)
{
	if (priv->gtk_installed)
		return;
	/*
	 **  if (!pBufDesc || (pBufDesc->rsvd & 0x00FF == 0))
	 **
	 **  Removed check to verify the 4th message was a success.  If we
	 **   miss the ACK from the 4th(WPA2)/2nd(WPA) message, but the AP
	 **   received it, then it won't retry and we will be stuck waiting for
	 **   a session timeout.
	 **
	 **  Could add back later if we retry the message in case of TX failure.
	 */
	FillKeyMaterialStruct(priv,
			      keyMgmtGetKeySize(priv, FALSE),
			      FALSE, &priv->suppData->keyMgmtInfoSta.GRKey);

	priv->suppData->keyMgmtInfoSta.RSNDataTrafficEnabled = TRUE;

	if (priv->suppData->keyMgmtInfoSta.RSNSecured == FALSE) {
		priv->suppData->keyMgmtInfoSta.RSNSecured = TRUE;

		keyMgmtControlledPortOpen(priv);
	}
#ifdef MULTI_CH_SW
	chmgr_UnlockCh(connPtr, 0);
#endif

	//return NULL;
}

static void
keyMgmtKeyPairwiseTxDone(phostsa_private priv)
{
	if (!priv->suppData->keyMgmtInfoSta.pwkHandshakeComplete) {
		/*
		 **  if (!pBufDesc || (pBufDesc->rsvd & 0x00FF == 0))
		 **
		 **  Removed check to verify the 4th message was a success.  If we
		 **   miss the ACK from the 4th(WPA2) message, but the AP
		 **   received it, then it won't retry and we will be stuck waiting for
		 **   a session timeout.
		 **
		 **  Could add back later if we retry the message in case of TX failure.
		 */
		keyMgmtPlumbPairwiseKey(priv);

		priv->suppData->keyMgmtInfoSta.pwkHandshakeComplete = TRUE;

		if (priv->suppData->keyMgmtInfoSta.pRxDecryptKey &&
		    priv->suppData->keyMgmtInfoSta.pwkHandshakeComplete) {
			SET_KEY_STATE_FORCE_EAPOL_UNENCRYPTED(priv->suppData->
							      keyMgmtInfoSta.
							      pRxDecryptKey,
							      FALSE);
		}
	}
}

static
	void
keyMgmtKeyPairAndGroupTxDone(phostsa_private priv)
{
	if (!priv->suppData->keyMgmtInfoSta.pwkHandshakeComplete) {
		keyMgmtKeyPairwiseTxDone(priv);
		keyMgmtKeyGroupTxDone(priv);
	}
}

void
keyMgmtControlledPortOpen(phostsa_private priv)
{
	hostsa_mlan_fns *pm_fns = &priv->mlan_fns;

	supplicantStopSessionTimer((void *)priv);

	pm_fns->Hostsa_StaControlledPortOpen(pm_fns->pmlan_private);
}

#ifdef WAR_ROM_BUG42707_RSN_IE_LEN_CHECK

BOOLEAN
patch_supplicantParseRsnIe(phostsa_private priv, IEEEtypes_RSNElement_t *pRsnIe,
			   SecurityMode_t *pWpaTypeOut,
			   Cipher_t *pMcstCipherOut,
			   Cipher_t *pUcstCipherOut,
			   AkmSuite_t *pAkmListOut,
			   UINT8 akmOutMax,
			   IEEEtypes_RSNCapability_t *pRsnCapOut,
			   Cipher_t *pGrpMgmtCipherOut)
{
	hostsa_util_fns *util_fns = &priv->util_fns;
	UINT8 *pIeData;
	UINT8 *pIeEnd;
	UINT8 *pGrpKeyCipher;
	UINT16 pwsKeyCnt;
	UINT8 *pPwsKeyCipherList;
	UINT16 authKeyCnt;
	UINT8 *pAuthKeyList;

	IEEEtypes_RSNCapability_t *pRsnCap;

	UINT16 *pPMKIDCnt;

	UINT8 *pGrpMgmtCipher;

	memset(util_fns, pWpaTypeOut, 0x00, sizeof(SecurityMode_t));

	pWpaTypeOut->wpa2 = 1;

	/* Set the start and end of the IE data */
	pIeData = (UINT8 *)&pRsnIe->Ver;
	pIeEnd = pIeData + pRsnIe->Len;

	/* Skip past the version field */
	pIeData += sizeof(pRsnIe->Ver);

	/* Parse the group key cipher list */
	pGrpKeyCipher = pIeData;
	pIeData += sizeof(pRsnIe->GrpKeyCipher);
	supplicantParseMcstCipher(priv, pMcstCipherOut, pGrpKeyCipher);

	/* Parse the pairwise key cipher list */
	memcpy(util_fns, &pwsKeyCnt, pIeData, sizeof(pwsKeyCnt));
	pIeData += sizeof(pRsnIe->PwsKeyCnt);

	pPwsKeyCipherList = pIeData;
	pIeData += pwsKeyCnt * sizeof(pRsnIe->PwsKeyCipherList);
	supplicantParseUcstCipher(priv, pUcstCipherOut, pwsKeyCnt,
				  pPwsKeyCipherList);

	/* Parse and return the AKM list */
	memcpy(util_fns, &authKeyCnt, pIeData, sizeof(authKeyCnt));
	pIeData += sizeof(pRsnIe->AuthKeyCnt);

	pAuthKeyList = pIeData;
	pIeData += authKeyCnt * sizeof(pRsnIe->AuthKeyList);
	memset(util_fns, pAkmListOut, 0x00, akmOutMax * sizeof(AkmSuite_t));
	memcpy(util_fns, pAkmListOut,
	       pAuthKeyList,
	       MIN(authKeyCnt, akmOutMax) * sizeof(pRsnIe->AuthKeyList));

	/* Check if the RSN Capability is included */
	if (pIeData < pIeEnd) {
		pRsnCap = (IEEEtypes_RSNCapability_t *)pIeData;
		pIeData += sizeof(pRsnIe->RsnCap);

		if (pRsnCapOut) {
			memcpy(util_fns, pRsnCapOut, pRsnCap,
			       sizeof(IEEEtypes_RSNCapability_t));
		}
	}

	/* Check if the PMKID count is included */
	if (pIeData < pIeEnd) {
		pPMKIDCnt = (UINT16 *)pIeData;
		pIeData += sizeof(pRsnIe->PMKIDCnt);

		/* Check if the PMKID List is included */
		if (pIeData < pIeEnd) {
			/* pPMKIDList = pIeData; <-- Currently not used in parsing */
			pIeData += *pPMKIDCnt * sizeof(pRsnIe->PMKIDList);
		}
	}

	/* Check if the Group Mgmt Cipher is included */
	if (pIeData < pIeEnd) {
		pGrpMgmtCipher = pIeData;

		if (pGrpMgmtCipherOut) {
			memcpy(util_fns, pGrpMgmtCipherOut,
			       pGrpMgmtCipher, sizeof(pRsnIe->GrpMgmtCipher));
		}
	}

	return TRUE;
}

#endif

//#pragma arm section code = ".init"
void
keyMgmtSta_RomInit(void)
{
//#if defined(PSK_SUPPLICANT) || defined (WPA_NONE)
	//ramHook_keyMgmtProcessMsgExt = keyMgmtProcessMsgExt;
	//ramHook_keyMgmtSendDeauth = keyMgmtSendDeauth2Peer;
//#endif

#ifdef WAR_ROM_BUG42707_RSN_IE_LEN_CHECK
	supplicantParseRsnIe_hook = patch_supplicantParseRsnIe;
#endif

}

//#pragma arm section code

#if defined(BTAMP)
UINT8 *
parseKeyDataField(cm_ConnectionInfo_t * connPtr, UINT8 *pKey, UINT16 len)
{
	keyMgmtInfoSta_t *pKeyMgmtInfoSta;
	KDE_t *pKde;

	pKeyMgmtInfoSta = &connPtr->suppData->keyMgmtInfoSta;

	/* parse KDE GTK */
	pKde = parseKeyDataGTK(pKey, len, &pKeyMgmtInfoSta->GRKey);

	/* Parse PMKID though it's _not used_ now */

	pKde = parseKeyKDE_DataType(pKey, len, KDE_DATA_TYPE_PMKID);

	if (pKde) {
		/* PMKID KDE */
		return (UINT8 *)pKde->data;
	}

	return NULL;
}

/* Add RSN IE to a frame body */
UINT16
btampAddRsnIe(cm_ConnectionInfo_t * connPtr, IEEEtypes_RSNElement_t *pRsnIe)
{
	const uint8 wpa2_psk[4] = { 0x00, 0x0f, 0xac, 0x02 };	/* WPA2 PSK */
	UINT16 ieSize;
	IEEEtypes_RSNCapability_t rsncap;
	SecurityMode_t securityMode;
	Cipher_t mcstWpa2;
	Cipher_t ucstWpa2;
	AkmSuite_t *pAkmWpa2;

	memset(util_fns, &securityMode, 0x00, sizeof(securityMode));
	memset(util_fns, &mcstWpa2, 0x00, sizeof(mcstWpa2));
	memset(util_fns, &ucstWpa2, 0x00, sizeof(ucstWpa2));
	memset(util_fns, &rsncap, 0, sizeof(rsncap));

	mcstWpa2.ccmp = 1;
	ucstWpa2.ccmp = 1;
	securityMode.wpa2 = 1;

	pAkmWpa2 = (AkmSuite_t *)wpa2_psk;

	supplicantSetProfile(connPtr, securityMode, mcstWpa2, ucstWpa2);

	supplicantSetAssocRsn(connPtr, securityMode, &mcstWpa2, &ucstWpa2,
			      pAkmWpa2, &rsncap, NULL);

	ieSize = keyMgmtFormatWpaRsnIe(connPtr,
				       (UINT8 *)pRsnIe,
				       NULL, NULL, NULL, FALSE);
	return ieSize;
}
#endif
#if 0
void
supplicantParseAndFormatRsnIe(phostsa_private priv,
			      IEEEtypes_RSNElement_t *pRsnIe,
			      SecurityMode_t *pWpaTypeOut,
			      Cipher_t *pMcstCipherOut,
			      Cipher_t *pUcstCipherOut, AkmSuite_t *pAkmListOut,
			      UINT8 akmOutMax,
			      IEEEtypes_RSNCapability_t *pRsnCapOut,
			      Cipher_t *pGrpMgmtCipherOut)
{
	hostsa_util_fns *util_fns = &priv->util_fns;
	UINT8 *pIeData;
	UINT8 *pIeEnd;
	UINT8 *pGrpKeyCipher;
	UINT16 pwsKeyCnt;
	UINT8 *pPwsKeyCipherList;
	UINT16 authKeyCnt;
	UINT8 *pAuthKeyList;

	IEEEtypes_RSNCapability_t *pRsnCap;

	UINT16 *pPMKIDCnt;

	UINT8 *pGrpMgmtCipher;

//longl add
	UINT8 *pos = NULL;
	UINT8 cp_size = 0;
#if 0
#if !defined(REMOVE_PATCH_HOOKS)
	if (supplicantParseRsnIe_hook(pRsnIe,
				      pWpaTypeOut,
				      pMcstCipherOut,
				      pUcstCipherOut,
				      pAkmListOut,
				      akmOutMax,
				      pRsnCapOut, pGrpMgmtCipherOut)) {
		return;
	}
#endif
#endif
	memset(util_fns, pWpaTypeOut, 0x00, sizeof(SecurityMode_t));
	memset(util_fns, (UINT8 *)priv->suppData->wpa_rsn_ie, 0x00,
	       MAX_IE_SIZE);
	pos = (UINT8 *)priv->suppData->wpa_rsn_ie;

	pWpaTypeOut->wpa2 = 1;

	/* Set the start and end of the IE data */
	pIeData = (UINT8 *)&pRsnIe->Ver;
	pIeEnd = pIeData + pRsnIe->Len;

	/* Skip past the version field */
	pIeData += sizeof(pRsnIe->Ver);

	/* Parse the group key cipher list */
	pGrpKeyCipher = pIeData;
	pIeData += sizeof(pRsnIe->GrpKeyCipher);
	supplicantParseMcstCipher(priv, pMcstCipherOut, pGrpKeyCipher);

	cp_size = pIeData - (UINT8 *)pRsnIe;
	memcpy(util_fns, pos, (UINT8 *)pRsnIe, cp_size);
	pos += cp_size;

	/* Parse the pairwise key cipher list */
	memcpy(util_fns, &pwsKeyCnt, pIeData, sizeof(pwsKeyCnt));
	pIeData += sizeof(pRsnIe->PwsKeyCnt);

	if (pwsKeyCnt > 0) {
		(*(UINT16 *)pos) = (UINT16)1;
		pos += sizeof(UINT16);
	}

	pPwsKeyCipherList = pIeData;
	pIeData += pwsKeyCnt * sizeof(pRsnIe->PwsKeyCipherList);
	supplicantParseUcstCipher(priv, pUcstCipherOut, pwsKeyCnt,
				  pPwsKeyCipherList);

	if (pUcstCipherOut->ccmp == 1) {
		memcpy(util_fns, pos, wpa2_oui04, sizeof(wpa2_oui04));
		pos += sizeof(wpa2_oui04);
	} else if (pUcstCipherOut->tkip == 1) {
		memcpy(util_fns, pos, wpa2_oui02, sizeof(wpa2_oui02));
		pos += sizeof(wpa2_oui02);
	}
	if ((pUcstCipherOut->ccmp == 1) && (pUcstCipherOut->tkip == 1))
		pUcstCipherOut->tkip = 0;

	cp_size = pIeEnd - pIeData;
	memcpy(util_fns, pos, pIeData, cp_size);
	pos += cp_size;
	((IEEEtypes_RSNElement_t *)(priv->suppData->wpa_rsn_ie))->Len =
		pos - (UINT8 *)priv->suppData->wpa_rsn_ie -
		sizeof(IEEEtypes_InfoElementHdr_t);

	/* Parse and return the AKM list */
	memcpy(util_fns, &authKeyCnt, pIeData, sizeof(authKeyCnt));
	pIeData += sizeof(pRsnIe->AuthKeyCnt);

	pAuthKeyList = pIeData;
	pIeData += authKeyCnt * sizeof(pRsnIe->AuthKeyList);
	memset(util_fns, pAkmListOut, 0x00, akmOutMax * sizeof(AkmSuite_t));
	memcpy(util_fns, pAkmListOut,
	       pAuthKeyList,
	       MIN(authKeyCnt, akmOutMax) * sizeof(pRsnIe->AuthKeyList));

	DBG_HEXDUMP(MCMD_D, " pAuthKeyList",
		    (t_u8 *)pAuthKeyList, MIN(authKeyCnt,
					      akmOutMax) *
		    sizeof(pRsnIe->AuthKeyList));
	DBG_HEXDUMP(MCMD_D, " pAuthKeyList", (t_u8 *)pAkmListOut,
		    MIN(authKeyCnt, akmOutMax) * sizeof(pRsnIe->AuthKeyList));
	/* Check if the RSN Capability is included */
	if (pIeData < pIeEnd) {
		pRsnCap = (IEEEtypes_RSNCapability_t *)pIeData;
		pIeData += sizeof(pRsnIe->RsnCap);

		if (pRsnCapOut) {
			memcpy(util_fns, pRsnCapOut, pRsnCap,
			       sizeof(IEEEtypes_RSNCapability_t));
		}
	}

	/* Check if the PMKID count is included */
	if (pIeData < pIeEnd) {
		pPMKIDCnt = (UINT16 *)pIeData;
		pIeData += sizeof(pRsnIe->PMKIDCnt);

		/* Check if the PMKID List is included */
		if (pIeData < pIeEnd) {
			/* pPMKIDList = pIeData; <-- Currently not used in parsing */
			pIeData += *pPMKIDCnt * sizeof(pRsnIe->PMKIDList);
		}
	}

	/* Check if the Group Mgmt Cipher is included */
	if (pIeData < pIeEnd) {
		pGrpMgmtCipher = pIeData;

		if (pGrpMgmtCipherOut) {
			memcpy(util_fns, pGrpMgmtCipherOut,
			       pGrpMgmtCipher, sizeof(pRsnIe->GrpMgmtCipher));
		}
	}
}

void
supplicantParseAndFormatWpaIe(phostsa_private priv, IEEEtypes_WPAElement_t *pIe,
			      SecurityMode_t *pWpaType,
			      Cipher_t *pMcstCipher,
			      Cipher_t *pUcstCipher,
			      AkmSuite_t *pAkmList, UINT8 akmOutMax)
{
	hostsa_util_fns *util_fns = &priv->util_fns;
	IEEEtypes_WPAElement_t *pTemp = pIe;
	int count;
	int akmCount = akmOutMax;
	AkmSuite_t *pAkm = pAkmList;
	UINT8 *pos = NULL;
	UINT8 cp_size = 0;
	UINT8 *pIeEnd =
		(UINT8 *)pIe + sizeof(IEEEtypes_InfoElementHdr_t) + pIe->Len;

	PRINTM(MMSG, "ENTER: %s\n", __FUNCTION__);

	memset(util_fns, pMcstCipher, 0x00, sizeof(Cipher_t));
	memset(util_fns, pUcstCipher, 0x00, sizeof(Cipher_t));
	memset(util_fns, pAkmList, 0x00, akmOutMax * sizeof(AkmSuite_t));
	memset(util_fns, pWpaType, 0x00, sizeof(SecurityMode_t));
	memset(util_fns, (UINT8 *)priv->suppData->wpa_rsn_ie, 0x00,
	       MAX_IE_SIZE);
	pos = (UINT8 *)priv->suppData->wpa_rsn_ie;

	pWpaType->wpa = 1;

	/* record the AP's multicast cipher */
	if (!memcmp
	    (util_fns, (char *)pTemp->GrpKeyCipher, wpa_oui02,
	     sizeof(wpa_oui02))) {
		/* WPA TKIP */
		pMcstCipher->tkip = 1;
	} else if (!memcmp
		   (util_fns, (char *)pTemp->GrpKeyCipher, wpa_oui04,
		    sizeof(wpa_oui04))) {
		/* WPA AES */
		pMcstCipher->ccmp = 1;
	} else if (!memcmp
		   (util_fns, (char *)pTemp->GrpKeyCipher, wpa_oui01,
		    sizeof(wpa_oui01))) {
		/* WPA WEP 40 */
		pMcstCipher->wep40 = 1;
	} else if (!memcmp
		   (util_fns, (char *)pTemp->GrpKeyCipher, wpa_oui05,
		    sizeof(wpa_oui05))) {
		/* WPA WEP 104 */
		pMcstCipher->wep104 = 1;
	}

	cp_size = (UINT8 *)(&pTemp->PwsKeyCnt) - (UINT8 *)pIe;
	memcpy(util_fns, pos, (UINT8 *)pIe, cp_size);
	pos += cp_size;

	count = pTemp->PwsKeyCnt;

	if (count > 0) {
		(*(UINT16 *)pos) = (UINT16)1;
		pos += sizeof(UINT16);
	}

	while (count) {
		/* record the AP's unicast cipher */
		if (!memcmp(util_fns, (char *)pTemp->PwsKeyCipherList,
			    wpa_oui02, sizeof(wpa_oui02))) {
			/* WPA TKIP */
			pUcstCipher->tkip = 1;
		} else if (!memcmp(util_fns, (char *)pTemp->PwsKeyCipherList,
				   wpa_oui04, sizeof(wpa_oui04))) {
			/* WPA AES */
			pUcstCipher->ccmp = 1;
		}
		count--;

		if (count) {
			pTemp = (IEEEtypes_WPAElement_t *)((UINT8 *)pTemp +
							   sizeof(pTemp->
								  PwsKeyCipherList));
		}
	}

	if (pUcstCipher->ccmp == 1) {
		memcpy(util_fns, pos, wpa_oui04, sizeof(wpa_oui04));
		pos += sizeof(wpa_oui04);
	} else if (pUcstCipher->tkip == 1) {
		memcpy(util_fns, pos, wpa_oui02, sizeof(wpa_oui02));
		pos += sizeof(wpa_oui02);
	}
	if ((pUcstCipher->ccmp == 1) && (pUcstCipher->tkip == 1))
		pUcstCipher->tkip = 0;

	cp_size = pIeEnd - (UINT8 *)(&pTemp->AuthKeyCnt);
	memcpy(util_fns, pos, &pTemp->AuthKeyCnt, cp_size);
	pos += cp_size;
	((IEEEtypes_RSNElement_t *)(priv->suppData->wpa_rsn_ie))->Len =
		pos - (UINT8 *)priv->suppData->wpa_rsn_ie -
		sizeof(IEEEtypes_InfoElementHdr_t);

	count = pTemp->AuthKeyCnt;

	while (count) {
		if (akmCount) {
			/* Store the AKM */
			memcpy(util_fns, pAkm,
			       (char *)pTemp->AuthKeyList,
			       sizeof(pTemp->AuthKeyList));
			pAkm++;
			akmCount--;
		}

		count--;

		if (count) {
			pTemp = (IEEEtypes_WPAElement_t *)((UINT8 *)pTemp
							   +
							   sizeof(pTemp->
								  AuthKeyList));
		}
	}

	if (!memcmp(util_fns, pAkmList, wpa_oui_none, sizeof(wpa_oui_none))) {
		pWpaType->wpaNone = 1;
	}

}
#endif

void *
processRsnWpaInfo(void *priv, void *prsnwpa_ie)
{
	phostsa_private psapriv = (phostsa_private)priv;
	hostsa_util_fns *util_fns = &psapriv->util_fns;
	Cipher_t mcstCipher;
	Cipher_t ucstCipher;
	SecurityMode_t wpaType;
	AkmSuite_t akmList[AKM_SUITE_MAX];
	IEEEtypes_RSNCapability_t rsnCap;
	t_u8 type = ((IEEEtypes_InfoElementHdr_t *)prsnwpa_ie)->ElementId;

	if (supplicantIsEnabled((void *)psapriv)) {

		memset(util_fns, &wpaType, 0x00, sizeof(wpaType));

		if (type == ELEM_ID_RSN || type == ELEM_ID_VENDOR_SPECIFIC) {
			if (type == ELEM_ID_RSN) {
				supplicantParseRsnIe(psapriv,
						     (IEEEtypes_RSNElement_t *)
						     prsnwpa_ie, &wpaType,
						     &mcstCipher, &ucstCipher,
						     akmList,
						     NELEMENTS(akmList),
						     &rsnCap, NULL);
			} else if (type == ELEM_ID_VENDOR_SPECIFIC) {
				supplicantParseWpaIe(psapriv,
						     (IEEEtypes_WPAElement_t *)
						     prsnwpa_ie, &wpaType,
						     &mcstCipher, &ucstCipher,
						     akmList,
						     NELEMENTS(akmList));
			}

			if (wpaType.wpa2 || wpaType.wpa) {
				memset(util_fns, &rsnCap, 0x00, sizeof(rsnCap));

				supplicantSetProfile(psapriv, wpaType,
						     mcstCipher, ucstCipher);

				supplicantSetAssocRsn(psapriv,
						      wpaType,
						      &mcstCipher,
						      &ucstCipher,
						      akmList, &rsnCap, NULL);

				memset(util_fns,
				       (UINT8 *)psapriv->suppData->wpa_rsn_ie,
				       0x00, MAX_IE_SIZE);
				if (keyMgmtFormatWpaRsnIe
				    (psapriv,
				     (UINT8 *)&psapriv->suppData->wpa_rsn_ie,
				     &psapriv->suppData->localBssid,
				     &psapriv->suppData->localStaAddr, NULL,
				     FALSE))
					return (void *)(psapriv->suppData->
							wpa_rsn_ie);
			}
		}

	}
	return NULL;
}

t_u8
supplicantFormatRsnWpaTlv(void *priv, void *rsn_wpa_ie, void *rsn_ie_tlv)
{
	phostsa_private psapriv = (phostsa_private)priv;
	hostsa_util_fns *util_fns = &psapriv->util_fns;
	void *supp_rsn_wpa_ie = NULL;
	MrvlIEGeneric_t *prsn_ie = (MrvlIEGeneric_t *)rsn_ie_tlv;
	t_u8 total_len = 0;

	if (rsn_wpa_ie) {
		supp_rsn_wpa_ie =
			processRsnWpaInfo((void *)psapriv, rsn_wpa_ie);
		if (!supp_rsn_wpa_ie)
			return total_len;

		/* WPA_IE or RSN_IE */
		prsn_ie->IEParam.Type =
			(t_u16)(((IEEEtypes_InfoElementHdr_t *)
				 supp_rsn_wpa_ie)->ElementId);
		prsn_ie->IEParam.Type = prsn_ie->IEParam.Type & 0x00FF;
		prsn_ie->IEParam.Type = wlan_cpu_to_le16(prsn_ie->IEParam.Type);
		prsn_ie->IEParam.Length =
			(t_u16)(((IEEEtypes_InfoElementHdr_t *)
				 supp_rsn_wpa_ie)->Len);
		prsn_ie->IEParam.Length = prsn_ie->IEParam.Length & 0x00FF;
		if (prsn_ie->IEParam.Length <= MAX_IE_SIZE) {
			memcpy(util_fns, rsn_ie_tlv + sizeof(prsn_ie->IEParam),
			       (t_u8 *)supp_rsn_wpa_ie +
			       sizeof(IEEEtypes_InfoElementHdr_t),
			       prsn_ie->IEParam.Length);
		} else
			return total_len;

		HEXDUMP("ASSOC_CMD: RSN IE", (t_u8 *)rsn_ie_tlv,
			sizeof(prsn_ie->IEParam) + prsn_ie->IEParam.Length);
		total_len += sizeof(prsn_ie->IEParam) + prsn_ie->IEParam.Length;
		prsn_ie->IEParam.Length =
			wlan_cpu_to_le16(prsn_ie->IEParam.Length);
	}
	return total_len;
}