Orange Pi5 kernel

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

3 Commits   0 Branches   0 Tags
/** @file keyMgntAP.c
 *
 *  @brief This file defined the eapol paket process and key management for authenticator
 *
 * 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
******************************************************/
//Authenticator related function definitions
#include "wltypes.h"
#include "IEEE_types.h"

#include "hostsa_ext_def.h"
#include "authenticator.h"

#include "wl_macros.h"
#include "wlpd.h"
#include "pass_phrase.h"
#include "sha1.h"
#include "crypt_new.h"
#include "parser.h"
#include "keyCommonDef.h"
#include  "keyMgmtStaTypes.h"
#include "AssocAp_srv_rom.h"
#include "pmkCache.h"
#include "keyMgmtApTypes.h"
#include "keyMgmtAp.h"
#include "rc4.h"
#include "authenticator_api.h"

//////////////////////
// STATIC FUNCTIONS
//////////////////////

//#ifdef AUTHENTICATOR
////////////////////////
// FORWARD DECLARATIONS
////////////////////////
Status_e GeneratePWKMsg3(hostsa_private *priv, cm_Connection *connPtr);
Status_e GenerateGrpMsg1(hostsa_private *priv, cm_Connection *connPtr);
Status_e GenerateApEapolMsg(hostsa_private *priv,
			    t_void *pconnPtr, keyMgmtState_e msgState);

static void
handleFailedHSK(t_void *priv, t_void *pconnPtr, IEEEtypes_ReasonCode_t reason)
{
	phostsa_private psapriv = (phostsa_private)priv;
	hostsa_mlan_fns *pm_fns = &psapriv->mlan_fns;
	cm_Connection *connPtr = (cm_Connection *)pconnPtr;

	KeyMgmtStopHskTimer(connPtr);
	pm_fns->hostsa_SendDeauth(pm_fns->pmlan_private, connPtr->mac_addr,
				  (t_u16)reason);
}

static void
incrementReplayCounter(apKeyMgmtInfoSta_t *pKeyMgmtInfo)
{
	if (++pKeyMgmtInfo->counterLo == 0) {
		pKeyMgmtInfo->counterHi++;
	}
}

int
isValidReplayCount(t_void *priv, apKeyMgmtInfoSta_t *pKeyMgmtInfo,
		   UINT8 *pRxReplayCount)
{
	phostsa_private psapriv = (phostsa_private)priv;
	hostsa_util_fns *util_fns = &psapriv->util_fns;
	UINT32 rxCounterHi;
	UINT32 rxCounterLo;

	memcpy(util_fns, &rxCounterHi, pRxReplayCount, 4);
	memcpy(util_fns, &rxCounterLo, pRxReplayCount + 4, 4);

	if ((pKeyMgmtInfo->counterHi == WORD_SWAP(rxCounterHi)) &&
	    (pKeyMgmtInfo->counterLo == WORD_SWAP(rxCounterLo))) {
		return 1;
	}
	return 0;
}

void
KeyMgmtSendGrpKeyMsgToAllSta(hostsa_private *priv)
{
	hostsa_mlan_fns *pm_fns = &priv->mlan_fns;
	apKeyMgmtInfoSta_t *pKeyMgmtInfo;
	cm_Connection *connPtr = MNULL;
	t_void *sta_node = MNULL;

	ENTER();

	pm_fns->Hostsa_find_connection(priv->pmlan_private, (t_void *)&connPtr,
				       &sta_node);

	while (connPtr != MNULL) {
		pKeyMgmtInfo = &connPtr->staData.keyMgmtInfo;

		if (pKeyMgmtInfo->rom.keyMgmtState == HSK_END) {
			GenerateApEapolMsg(priv, connPtr,
					   GRP_REKEY_MSG1_PENDING);
		} else if ((pKeyMgmtInfo->rom.keyMgmtState == WAITING_4_GRPMSG2)
			   || (pKeyMgmtInfo->rom.staSecType.wpa2 &&
			       (pKeyMgmtInfo->rom.keyMgmtState ==
				WAITING_4_MSG4)) ||
			   (pKeyMgmtInfo->rom.keyMgmtState ==
			    WAITING_4_GRP_REKEY_MSG2)) {
			// TODO:How to handle group rekey if either Groupwise handshake
			// Group rekey is already in progress for this STA?
		}

		pm_fns->Hostsa_find_next_connection(priv->pmlan_private,
						    (t_void *)&connPtr,
						    &sta_node);
	}

	LEAVE();
}

UINT32
keyApi_ApUpdateKeyMaterial(void *priv, cm_Connection *connPtr,
			   BOOLEAN updateGrpKey)
{
	phostsa_private psapriv = (phostsa_private)priv;
	hostsa_util_fns *util_fns = &psapriv->util_fns;
	hostsa_mlan_fns *pm_fns = &psapriv->mlan_fns;
	BssConfig_t *pBssConfig = MNULL;
	KeyData_t *pKeyData = MNULL;
	//cipher_key_buf_t *pCipherKeyBuf;
	Cipher_t *pCipher = MNULL;
	//KeyData_t pwsKeyData;
	mlan_ds_encrypt_key encrypt_key;
	t_u8 bcast_addr[MAC_ADDR_SIZE] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
	apInfo_t *pApInfo = &psapriv->apinfo;

	pBssConfig = &pApInfo->bssConfig;

	if (pBssConfig->SecType.wpa || pBssConfig->SecType.wpa2) {
		memset(util_fns, &encrypt_key, 0, sizeof(mlan_ds_encrypt_key));

		//connPtr->cmFlags.RSNEnabled = TRUE;
		if (updateGrpKey == TRUE) {
			pKeyData = &pApInfo->bssData.grpKeyData;
			pCipher = &pBssConfig->RsnConfig.mcstCipher;
		} else if (connPtr) {
			/*  pCipherKeyBuf = connPtr->pwTxRxCipherKeyBuf;
			   memcpy((void*)&pwsKeyData,
			   (void*)&pCipherKeyBuf->cipher_key.ckd.hskData.pwsKeyData,
			   sizeof(KeyData_t)); */
			pKeyData = &connPtr->hskData.pwsKeyData;
			pCipher =
				&connPtr->staData.keyMgmtInfo.rom.staUcstCipher;
		}

		if (updateGrpKey == TRUE) {
			memcpy(util_fns, encrypt_key.mac_addr, bcast_addr,
			       MAC_ADDR_SIZE);
			encrypt_key.key_flags |= KEY_FLAG_GROUP_KEY;
		} else if (connPtr) {
			memcpy(util_fns, encrypt_key.mac_addr,
			       connPtr->mac_addr, MAC_ADDR_SIZE);
			encrypt_key.key_flags |= KEY_FLAG_SET_TX_KEY;
		}

		if (!pKeyData || !pCipher) {
			PRINTM(MERROR, "Invalid KeyData or Cipher pointer!\n");
			return 1;
		}

		if (pCipher->ccmp) {
	    /**AES*/
			encrypt_key.key_len = TK_SIZE;
			memcpy(util_fns, encrypt_key.key_material,
			       pKeyData->Key, TK_SIZE);
		} else if (pCipher->tkip) {
	    /**TKIP*/
			encrypt_key.key_len =
				TK_SIZE + MIC_KEY_SIZE + MIC_KEY_SIZE;
			memcpy(util_fns, encrypt_key.key_material,
			       pKeyData->Key, TK_SIZE);
			memcpy(util_fns, &encrypt_key.key_material[TK_SIZE],
			       pKeyData->TxMICKey, MIC_KEY_SIZE);
			memcpy(util_fns,
			       &encrypt_key.key_material[TK_SIZE +
							 MIC_KEY_SIZE],
			       pKeyData->RxMICKey, MIC_KEY_SIZE);
		}
	/**set pn 0*/
		memset(util_fns, encrypt_key.pn, 0, PN_SIZE);

	/**key flag*/
		encrypt_key.key_flags |= KEY_FLAG_RX_SEQ_VALID;
	/**key index*/
		encrypt_key.key_index = pKeyData->KeyIndex;
	/**set command to fw update key*/
		pm_fns->hostsa_set_encrypt_key(psapriv->pmlan_private,
					       &encrypt_key);

	}

	return 0;
}

void
GenerateGTK(void *priv)
{
	phostsa_private psapriv = (phostsa_private)priv;
	apInfo_t *pApInfo = &psapriv->apinfo;
	BssData_t *pBssData = MNULL;

	pBssData = &pApInfo->bssData;

	GenerateGTK_internal(psapriv, &pBssData->grpKeyData,
			     pBssData->GNonce, psapriv->curr_addr);
}

void
ReInitGTK(t_void *priv)
{
	phostsa_private psapriv = (phostsa_private)priv;
	apInfo_t *pApInfo = &psapriv->apinfo;
	BssData_t *pBssData;

	pBssData = &pApInfo->bssData;

	/*
	   Disabled for interop
	   Not all clients like this
	   pBssData->grpKeyData.KeyIndex = (pBssData->grpKeyData.KeyIndex & 3) + 1;
	 */

	ROM_InitGTK(psapriv, &pBssData->grpKeyData,
		    pBssData->GNonce, psapriv->curr_addr);

	keyApi_ApUpdateKeyMaterial(priv, MNULL, MTRUE);
}

void
KeyMgmtGrpRekeyCountUpdate(t_void *context)
{
	phostsa_private psapriv = (phostsa_private)context;
	apInfo_t *pApInfo = &psapriv->apinfo;
	hostsa_util_fns *putil_fns = &psapriv->util_fns;

	ENTER();

	if (psapriv->GrpRekeyTimerIsSet &&
	    pApInfo->bssData.grpRekeyCntRemaining) {
		//Periodic group rekey is configured.
		pApInfo->bssData.grpRekeyCntRemaining--;
		if (!pApInfo->bssData.grpRekeyCntRemaining) {
			//Group rekey timeout hit.
			pApInfo->bssData.grpRekeyCntRemaining
				= pApInfo->bssData.grpRekeyCntConfigured;

			ReInitGTK((t_void *)psapriv);

			KeyMgmtSendGrpKeyMsgToAllSta(psapriv);
		}

	/**start Group rekey timer*/
		putil_fns->moal_start_timer(putil_fns->pmoal_handle,
					    psapriv->GrpRekeytimer,
					    MFALSE, MRVDRV_TIMER_60S);
	}

	LEAVE();
}

void
KeyMgmtInit(void *priv)
{
	phostsa_private psapriv = (phostsa_private)priv;
	apInfo_t *pApInfo = &psapriv->apinfo;
	UINT8 *pPassPhrase;
	UINT8 *pPskValue;
	UINT8 passPhraseLen;

	pPassPhrase = pApInfo->bssConfig.RsnConfig.PSKPassPhrase;
	pPskValue = pApInfo->bssConfig.RsnConfig.PSKValue;
	passPhraseLen = pApInfo->bssConfig.RsnConfig.PSKPassPhraseLen;

	ROM_InitGTK(psapriv, &pApInfo->bssData.grpKeyData,
		    pApInfo->bssData.GNonce, psapriv->curr_addr);

	if (pApInfo->bssData.updatePassPhrase == MTRUE) {
		pmkCacheGeneratePSK(priv, pApInfo->bssConfig.SsId,
				    pApInfo->bssConfig.SsIdLen,
				    (char *)pPassPhrase, pPskValue);

		pApInfo->bssData.updatePassPhrase = MFALSE;
	}
}

void
KeyMgmtHskTimeout(t_void *context)
{
	cm_Connection *connPtr = (cm_Connection *)context;
	phostsa_private priv = (phostsa_private)connPtr->priv;
	hostsa_mlan_fns *pm_fns = &priv->mlan_fns;
	apKeyMgmtInfoSta_t *pKeyMgmtInfo;
	apRsnConfig_t *pRsnConfig;
	IEEEtypes_ReasonCode_t reason;
	BOOLEAN maxRetriesDone = MFALSE;
	apInfo_t *pApInfo = &priv->apinfo;

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

	pKeyMgmtInfo = &connPtr->staData.keyMgmtInfo;
	pRsnConfig = &pApInfo->bssConfig.RsnConfig;

	connPtr->timer_is_set = 0;
	/* Assume when this function gets called pKeyMgmtInfo->keyMgmtState
	 ** will not be in HSK_NOT_STARTED or HSK_END
	 */
	if (pKeyMgmtInfo->rom.keyMgmtState <= WAITING_4_MSG4) {
		if (pKeyMgmtInfo->numHskTries >= pRsnConfig->MaxPwsHskRetries) {
			maxRetriesDone = MTRUE;
			reason = IEEEtypes_REASON_4WAY_HANDSHK_TIMEOUT;
		}
	} else {
		if (pKeyMgmtInfo->numHskTries >= pRsnConfig->MaxGrpHskRetries) {
			maxRetriesDone = MTRUE;
			reason = IEEEtypes_REASON_GRP_KEY_UPD_TIMEOUT;
		}
	}

	if (maxRetriesDone) {
		// Some STAs do not respond to PWK Msg1 if the EAPOL Proto Version is 1
		// in 802.1X header, hence switch to v2 after all attempts with v1 fail
		// for PWK Msg1. Set the HskTimeoutCtn to 1 to get the same "retries"
		// as with v1.
		if (((WAITING_4_MSG2 == pKeyMgmtInfo->rom.keyMgmtState)
		     || (MSG1_PENDING == pKeyMgmtInfo->rom.keyMgmtState))
		    && (EAPOL_PROTOCOL_V1 == pKeyMgmtInfo->EAPOLProtoVersion)) {
			pKeyMgmtInfo->numHskTries = 1;
			pKeyMgmtInfo->EAPOLProtoVersion = EAPOL_PROTOCOL_V2;
			GenerateApEapolMsg(priv, connPtr,
					   pKeyMgmtInfo->rom.keyMgmtState);
		} else {
			pm_fns->hostsa_SendDeauth(priv->pmlan_private,
						  connPtr->mac_addr,
						  (t_u16)reason);
			pKeyMgmtInfo->rom.keyMgmtState = HSK_END;
		}
	} else {
		GenerateApEapolMsg(priv, connPtr,
				   pKeyMgmtInfo->rom.keyMgmtState);
	}

	return;
}

void
KeyMgmtStartHskTimer(void *context)
{
	cm_Connection *connPtr = (cm_Connection *)context;
	phostsa_private psapriv = (phostsa_private)(connPtr->priv);
	hostsa_util_fns *util_fns = &psapriv->util_fns;
	apInfo_t *pApInfo = MNULL;
	UINT32 timeoutInms;
	apRsnConfig_t *pRsnConfig;

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

	pApInfo = &psapriv->apinfo;
	pRsnConfig = &pApInfo->bssConfig.RsnConfig;
	if ((connPtr->staData.keyMgmtInfo.rom.keyMgmtState >= MSG1_PENDING)
	    && (connPtr->staData.keyMgmtInfo.rom.keyMgmtState <=
		WAITING_4_MSG4)) {
		timeoutInms = pRsnConfig->PwsHskTimeOut;
	} else if ((connPtr->staData.keyMgmtInfo.rom.keyMgmtState >=
		    GRPMSG1_PENDING)
		   && (connPtr->staData.keyMgmtInfo.rom.keyMgmtState <=
		       WAITING_4_GRP_REKEY_MSG2)) {
		timeoutInms = pRsnConfig->GrpHskTimeOut;
	} else {
		//EAPOL HSK is not in progress. No need to start HSK timer
		return;
	}

	// Retry happen, increase timeout to at least 1 sec
	if (connPtr->staData.keyMgmtInfo.numHskTries > 0) {
		timeoutInms = MAX(AP_RETRY_EAPOL_HSK_TIMEOUT, timeoutInms);
	}

	/* if STA is in PS1 then we are using max(STA_PS_EAPOL_HSK_TIMEOUT,
	 * HSKtimeout)for timeout instead of configured timeout value
	 */
	/* if(PWR_MODE_PWR_SAVE == connPtr->staData.pwrSaveInfo.mode)
	   {
	   timeoutInms = MAX(STA_PS_EAPOL_HSK_TIMEOUT, timeoutInms);
	   }
	 */
	util_fns->moal_start_timer(util_fns->pmoal_handle,
				   connPtr->HskTimer, MFALSE, timeoutInms);
	connPtr->timer_is_set = 1;
}

void
KeyMgmtStopHskTimer(t_void *pconnPtr)
{
	cm_Connection *connPtr = (cm_Connection *)pconnPtr;
	phostsa_private priv = (phostsa_private)connPtr->priv;
	hostsa_util_fns *util_fns = &priv->util_fns;

	util_fns->moal_stop_timer(util_fns->pmoal_handle, connPtr->HskTimer);

	connPtr->timer_is_set = 0;
}

void
PrepDefaultEapolMsg(phostsa_private priv, cm_Connection *connPtr,
		    EAPOL_KeyMsg_Tx_t **pTxEapolPtr, pmlan_buffer pmbuf)
{
	hostsa_util_fns *util_fns = &priv->util_fns;
	apInfo_t *pApInfo = &priv->apinfo;
	EAPOL_KeyMsg_Tx_t *tx_eapol_ptr;
	apKeyMgmtInfoSta_t *pKeyMgmtInfo;
	hostsa_mlan_fns *pm_fns = &priv->mlan_fns;
	UINT8 intf_hr_len =
		pm_fns->Hostsa_get_intf_hr_len(pm_fns->pmlan_private);
#define UAP_EAPOL_PRIORITY 7	/* Voice */

	ENTER();

	pmbuf->priority = UAP_EAPOL_PRIORITY;
	pmbuf->buf_type = MLAN_BUF_TYPE_DATA;
	pmbuf->data_offset = (sizeof(UapTxPD) + intf_hr_len + DMA_ALIGNMENT);
	tx_eapol_ptr =
		(EAPOL_KeyMsg_Tx_t *)((UINT8 *)pmbuf->pbuf +
				      pmbuf->data_offset);
	memset(util_fns, (UINT8 *)tx_eapol_ptr, 0x00,
	       sizeof(EAPOL_KeyMsg_Tx_t));

	formEAPOLEthHdr(priv, tx_eapol_ptr, connPtr->mac_addr, priv->curr_addr);

	pKeyMgmtInfo = &connPtr->staData.keyMgmtInfo;

	SetEAPOLKeyDescTypeVersion(tx_eapol_ptr,
				   pKeyMgmtInfo->rom.staSecType.wpa2,
				   MFALSE,
				   (pKeyMgmtInfo->rom.staUcstCipher.ccmp ||
				    pApInfo->bssConfig.RsnConfig.mcstCipher.
				    ccmp));

	*pTxEapolPtr = tx_eapol_ptr;

	LEAVE();
}

Status_e
GeneratePWKMsg1(hostsa_private *priv, cm_Connection *connPtr)
{
	hostsa_mlan_fns *pm_fns = &priv->mlan_fns;
	EAPOL_KeyMsg_Tx_t *tx_eapol_ptr;
	UINT16 frameLen = 0, packet_len = 0;
	apKeyMgmtInfoSta_t *pKeyMgmtInfo;
	UINT32 replay_cnt[2];
	eapolHskData_t *pHskData;
	pmlan_buffer pmbuf = MNULL;

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

	pmbuf = pm_fns->hostsa_alloc_mlan_buffer(priv->pmlan_adapter,
						 MLAN_TX_DATA_BUF_SIZE_2K, 0,
						 MOAL_MALLOC_BUFFER);
	if (pmbuf == NULL) {
		PRINTM(MERROR, "allocate buffer fail for eapol \n");
		return FAIL;
	}

	PrepDefaultEapolMsg(priv, connPtr, &tx_eapol_ptr, pmbuf);

	pKeyMgmtInfo = &connPtr->staData.keyMgmtInfo;
	pHskData = &connPtr->hskData;

	incrementReplayCounter(pKeyMgmtInfo);
	replay_cnt[0] = pKeyMgmtInfo->counterHi;
	replay_cnt[1] = pKeyMgmtInfo->counterLo;

	supplicantGenerateRand(priv, pHskData->ANonce, NONCE_SIZE);

	PopulateKeyMsg(priv, tx_eapol_ptr,
		       &pKeyMgmtInfo->rom.staUcstCipher,
		       PAIRWISE_KEY_MSG, replay_cnt, pHskData->ANonce);

	frameLen = EAPOL_KeyMsg_Len - sizeof(Hdr_8021x_t)
		- sizeof(tx_eapol_ptr->keyMsg.key_data)
		+ tx_eapol_ptr->keyMsg.key_material_len;	//key_mtr_len is 0 here

	packet_len = frameLen + sizeof(Hdr_8021x_t) + sizeof(ether_hdr_t);

	tx_eapol_ptr->keyMsg.hdr_8021x.protocol_ver
		= pKeyMgmtInfo->EAPOLProtoVersion;
	tx_eapol_ptr->keyMsg.hdr_8021x.pckt_type
		= IEEE_8021X_PACKET_TYPE_EAPOL_KEY;
	tx_eapol_ptr->keyMsg.hdr_8021x.pckt_body_len = htons(frameLen);

	UpdateEAPOLWcbLenAndTransmit(priv, pmbuf, packet_len);
	return SUCCESS;
}

// returns 0 on success, or error code
Status_e
ProcessPWKMsg2(hostsa_private *priv,
	       cm_Connection *connPtr, t_u8 *pbuf, t_u32 len)
{
	EAPOL_KeyMsg_t *rx_eapol_ptr;
	UINT8 *PMK;
	apKeyMgmtInfoSta_t *pKeyMgmtInfo;
	BssConfig_t *pBssConfig = NULL;
	IEPointers_t iePointers;
	UINT32 ieLen;
	UINT8 *pIe = NULL;
	apInfo_t *pApInfo = &priv->apinfo;
	Cipher_t wpaUcastCipher;
	Cipher_t wpa2UcastCipher;
	eapolHskData_t *pHskData = &connPtr->hskData;

	pKeyMgmtInfo = &connPtr->staData.keyMgmtInfo;
	rx_eapol_ptr = (EAPOL_KeyMsg_t *)(pbuf + ETHII_HEADER_LEN);

	pBssConfig = &pApInfo->bssConfig;
	// compare the RSN IE from assoc req to current
	pIe = (UINT8 *)rx_eapol_ptr->key_data;
	ieLen = pIe[1] + sizeof(IEEEtypes_InfoElementHdr_t);
	GetIEPointers((void *)priv, pIe, ieLen, &iePointers);
	wpaUcastCipher = pBssConfig->RsnConfig.wpaUcstCipher;
	wpa2UcastCipher = pBssConfig->RsnConfig.wpa2UcstCipher;
	PRINTM(MMSG, "ENTER: %s\n", __FUNCTION__);

	if (assocSrvAp_checkRsnWpa(connPtr, &pKeyMgmtInfo->rom,
				   wpaUcastCipher,
				   wpa2UcastCipher,
				   pBssConfig->RsnConfig.mcstCipher,
				   pBssConfig->RsnConfig.AuthKey,
				   &pKeyMgmtInfo->rom.staSecType,
				   iePointers.pRsn,
				   iePointers.pWpa, TRUE) == FAIL) {
		handleFailedHSK(priv, connPtr, IEEEtypes_REASON_IE_4WAY_DIFF);
		return FAIL;
	}

	PMK = pApInfo->bssConfig.RsnConfig.PSKValue;

	KeyMgmtAp_DerivePTK(priv, PMK,
			    connPtr->mac_addr,
			    priv->curr_addr,
			    pHskData->ANonce,
			    rx_eapol_ptr->key_nonce,
			    pKeyMgmtInfo->EAPOL_MIC_Key,
			    pKeyMgmtInfo->EAPOL_Encr_Key,
			    &pHskData->pwsKeyData, MFALSE);

	if (!IsEAPOL_MICValid(priv, rx_eapol_ptr, pKeyMgmtInfo->EAPOL_MIC_Key)) {
		return FAIL;
	}

	KeyMgmtStopHskTimer(connPtr);
	connPtr->staData.keyMgmtInfo.numHskTries = 0;

	return GenerateApEapolMsg(priv, connPtr, MSG3_PENDING);
}

Status_e
GeneratePWKMsg3(hostsa_private *priv, cm_Connection *connPtr)
{
	hostsa_mlan_fns *pm_fns = &priv->mlan_fns;
	EAPOL_KeyMsg_Tx_t *tx_eapol_ptr;
	UINT16 frameLen = 0, packet_len = 0;
	apKeyMgmtInfoSta_t *pKeyMgmtInfo;
	apInfo_t *pApInfo = &priv->apinfo;
	BssConfig_t *pBssConfig = MNULL;
	UINT32 replay_cnt[2];
	eapolHskData_t *pHskData;
	pmlan_buffer pmbuf = MNULL;

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

	pmbuf = pm_fns->hostsa_alloc_mlan_buffer(priv->pmlan_adapter,
						 MLAN_TX_DATA_BUF_SIZE_2K, 0,
						 MOAL_MALLOC_BUFFER);
	if (pmbuf == NULL) {
		PRINTM(MERROR, "allocate buffer fail for eapol \n");
		return FAIL;
	}

	PrepDefaultEapolMsg(priv, connPtr, &tx_eapol_ptr, pmbuf);

	pBssConfig = &pApInfo->bssConfig;

	pKeyMgmtInfo = &connPtr->staData.keyMgmtInfo;
	pHskData = &connPtr->hskData;

	incrementReplayCounter(pKeyMgmtInfo);

	replay_cnt[0] = pKeyMgmtInfo->counterHi;
	replay_cnt[1] = pKeyMgmtInfo->counterLo;

	PopulateKeyMsg(priv, tx_eapol_ptr,
		       &pKeyMgmtInfo->rom.staUcstCipher,
		       ((PAIRWISE_KEY_MSG | SECURE_HANDSHAKE_FLAG) |
			((pKeyMgmtInfo->rom.staSecType.
			  wpa2) ? WPA2_HANDSHAKE : 0)), replay_cnt,
		       pHskData->ANonce);

	/*if (pKeyMgmtInfo->staSecType.wpa2)
	   {
	   // Netgear WAG511 and USB55 cards don't like this field set to
	   // anything other than zero. Hence hard code this value to zero
	   // in all outbound EAPOL frames...
	   // The client is now vulnerable to replay attacks from the point
	   // it receives EAP-message3 till reception of first management
	   // frame from uAP.

	   tx_eapol_ptr->keyMsg.key_RSC[0] =
	   pApInfo->bssConfig.grpKeyData.TxIV16 & 0x00FF;
	   tx_eapol_ptr->keyMsg.key_RSC[1] =
	   (pApInfo->bssConfig.grpKeyData.TxIV16 >> 8) & 0x00FF;
	   memcpy((void*)(tx_eapol_ptr->keyMsg.key_RSC + 2),
	   &pApInfo->bssData.grpKeyData.TxIV32, 4);
	   } */
/*
    pBcnFrame = (dot11MgtFrame_t *)BML_DATA_PTR(connPtr->pBcnBufferDesc);
    if (pKeyMgmtInfo->rom.staSecType.wpa)
    {
        pWpaIE = syncSrv_ParseAttrib(pBcnFrame,
                                     ELEM_ID_VENDOR_SPECIFIC,
                                     IEEE_MSG_BEACON,
                                     (UINT8 *)wpa_oui01,
                                     sizeof(wpa_oui01));
    }
    else if (pKeyMgmtInfo->rom.staSecType.wpa2)
    {
        pWpa2IE = syncSrv_ParseAttrib(pBcnFrame,
                                      ELEM_ID_RSN,
                                      IEEE_MSG_BEACON,
                                      NULL,
                                      0);
    }*/
	if (!KeyData_UpdateKeyMaterial(priv, tx_eapol_ptr,
				       &pKeyMgmtInfo->rom.staSecType,
				       pBssConfig->wpa_ie,
				       pBssConfig->rsn_ie)) {
		/* We have WPA/WPA2 enabled but no corresponding IE */
		pm_fns->hostsa_free_mlan_buffer(pm_fns->pmlan_adapter, pmbuf);
		return FAIL;
	}

	if (pKeyMgmtInfo->rom.staSecType.wpa2) {	// WPA2
		prepareKDE(priv, tx_eapol_ptr,
			   &pApInfo->bssData.grpKeyData,
			   &pApInfo->bssConfig.RsnConfig.mcstCipher);

		if (!Encrypt_keyData((t_void *)priv, tx_eapol_ptr,
				     pKeyMgmtInfo->EAPOL_Encr_Key,
				     &pKeyMgmtInfo->rom.staUcstCipher))
		{
			pm_fns->hostsa_free_mlan_buffer(pm_fns->pmlan_adapter,
							pmbuf);
			return FAIL;
		}
	}

	frameLen = KeyMgmtSta_PopulateEAPOLLengthMic(priv,
						     tx_eapol_ptr,
						     pKeyMgmtInfo->
						     EAPOL_MIC_Key,
						     pKeyMgmtInfo->
						     EAPOLProtoVersion,
						     tx_eapol_ptr->keyMsg.
						     key_info.
						     KeyDescriptorVersion);

	packet_len = frameLen + sizeof(Hdr_8021x_t) + sizeof(ether_hdr_t);
	UpdateEAPOLWcbLenAndTransmit(priv, pmbuf, packet_len);
	return SUCCESS;
}

Status_e
ProcessPWKMsg4(hostsa_private *priv,
	       cm_Connection *connPtr, t_u8 *pbuf, t_u32 len)
{
	hostsa_mlan_fns *pm_fns = &priv->mlan_fns;
	EAPOL_KeyMsg_t *rx_eapol_ptr;
	apKeyMgmtInfoSta_t *pKeyMgmtInfo;
	eapolHskData_t *pHskData = &connPtr->hskData;

	pKeyMgmtInfo = &connPtr->staData.keyMgmtInfo;
	rx_eapol_ptr = (EAPOL_KeyMsg_t *)(pbuf + ETHII_HEADER_LEN);
	PRINTM(MMSG, "ENTER: %s\n", __FUNCTION__);

	if (!IsEAPOL_MICValid(priv, rx_eapol_ptr, pKeyMgmtInfo->EAPOL_MIC_Key)) {
		return FAIL;
	}
	pHskData->pwsKeyData.TxIV16 = 0x0001;
	pHskData->pwsKeyData.TxIV32 = 0;

	if (keyApi_ApUpdateKeyMaterial(priv, connPtr, FALSE)) {
		handleFailedHSK(priv, connPtr, IEEEtypes_REASON_UNSPEC);
		return FAIL;
	}

	KeyMgmtStopHskTimer(connPtr);
	connPtr->staData.keyMgmtInfo.numHskTries = 0;
	if (pKeyMgmtInfo->rom.staSecType.wpa2) {
		pm_fns->Hostsa_sendEventRsnConnect(priv->pmlan_private,
						   connPtr->mac_addr);
		pKeyMgmtInfo->rom.keyMgmtState = HSK_END;
	} else {
		return GenerateApEapolMsg(priv, connPtr, GRPMSG1_PENDING);
	}

	return SUCCESS;
}

Status_e
GenerateGrpMsg1(hostsa_private *priv, cm_Connection *connPtr)
{
	hostsa_mlan_fns *pm_fns = &priv->mlan_fns;
	EAPOL_KeyMsg_Tx_t *tx_eapol_ptr;
	UINT16 frameLen = 0, packet_len = 0;
	apKeyMgmtInfoSta_t *pKeyMgmtInfo;
	apInfo_t *pApInfo = &priv->apinfo;
	UINT32 replay_cnt[2];
	pmlan_buffer pmbuf = MNULL;

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

	pmbuf = pm_fns->hostsa_alloc_mlan_buffer(priv->pmlan_adapter,
						 MLAN_TX_DATA_BUF_SIZE_2K, 0,
						 MOAL_MALLOC_BUFFER);
	if (pmbuf == NULL) {
		PRINTM(MERROR, "allocate buffer fail for eapol \n");
		return FAIL;
	}

	PrepDefaultEapolMsg(priv, connPtr, &tx_eapol_ptr, pmbuf);

	pKeyMgmtInfo = &connPtr->staData.keyMgmtInfo;

	incrementReplayCounter(pKeyMgmtInfo);

	replay_cnt[0] = pKeyMgmtInfo->counterHi;
	replay_cnt[1] = pKeyMgmtInfo->counterLo;

	PopulateKeyMsg(priv, tx_eapol_ptr,
		       &pApInfo->bssConfig.RsnConfig.mcstCipher,
		       (SECURE_HANDSHAKE_FLAG |
			((pKeyMgmtInfo->rom.staSecType.
			  wpa2) ? WPA2_HANDSHAKE : 0)), replay_cnt,
		       pApInfo->bssData.GNonce);

	KeyData_AddKey(priv,
		       tx_eapol_ptr,
		       &pKeyMgmtInfo->rom.staSecType,
		       &pApInfo->bssData.grpKeyData,
		       &pApInfo->bssConfig.RsnConfig.mcstCipher);
	if (!Encrypt_keyData(priv, tx_eapol_ptr,
			     pKeyMgmtInfo->EAPOL_Encr_Key,
			     &pKeyMgmtInfo->rom.staUcstCipher))
	{
		// nothing here.
	}

	frameLen = KeyMgmtSta_PopulateEAPOLLengthMic(priv,
						     tx_eapol_ptr,
						     pKeyMgmtInfo->
						     EAPOL_MIC_Key,
						     pKeyMgmtInfo->
						     EAPOLProtoVersion,
						     tx_eapol_ptr->keyMsg.
						     key_info.
						     KeyDescriptorVersion);

	packet_len = frameLen + sizeof(Hdr_8021x_t) + sizeof(ether_hdr_t);

	UpdateEAPOLWcbLenAndTransmit(priv, pmbuf, packet_len);
	return SUCCESS;
}

Status_e
ProcessGrpMsg2(hostsa_private *priv,
	       cm_Connection *connPtr, t_u8 *pbuf, t_u32 len)
{
	hostsa_mlan_fns *pm_fns = &priv->mlan_fns;
	EAPOL_KeyMsg_t *rx_eapol_ptr;
	apKeyMgmtInfoSta_t *pKeyMgmtInfo;

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

	rx_eapol_ptr = (EAPOL_KeyMsg_t *)(pbuf + ETHII_HEADER_LEN);

	pKeyMgmtInfo = &connPtr->staData.keyMgmtInfo;

	if (!IsEAPOL_MICValid(priv, rx_eapol_ptr, pKeyMgmtInfo->EAPOL_MIC_Key)) {
		handleFailedHSK(priv, connPtr, IEEEtypes_REASON_IE_4WAY_DIFF);
		return FAIL;
	}
	KeyMgmtStopHskTimer(connPtr);
	connPtr->staData.keyMgmtInfo.numHskTries = 0;

	if (WAITING_4_GRPMSG2 == pKeyMgmtInfo->rom.keyMgmtState) {
		/* sendEventRsnConnect(connPtr, pKeyMgmtInfo); */
		pm_fns->Hostsa_sendEventRsnConnect(priv->pmlan_private,
						   connPtr->mac_addr);
	}

	pKeyMgmtInfo->rom.keyMgmtState = HSK_END;

	return SUCCESS;
}

Status_e
GenerateApEapolMsg(hostsa_private *priv,
		   t_void *pconnPtr, keyMgmtState_e msgState)
{
	cm_Connection *connPtr = (cm_Connection *)pconnPtr;
	Status_e status;
	// OSASysContext prevContext;

	if (connPtr->timer_is_set) {
		KeyMgmtStopHskTimer((t_void *)connPtr);
	}
	/* If msgState is any waiting_** state,
	 ** it will decrease to corresponding **_pending state.
	 */
	/* Note: it will reduce the if checks
	 */
	if ((msgState & 0x1) == 0) {
		msgState--;
	}
	connPtr->staData.keyMgmtInfo.rom.keyMgmtState = msgState;

	if (msgState == MSG1_PENDING) {
		status = GeneratePWKMsg1(priv, connPtr);
	} else if (msgState == MSG3_PENDING) {
		status = GeneratePWKMsg3(priv, connPtr);
	} else if ((msgState == GRPMSG1_PENDING)
		   || (msgState == GRP_REKEY_MSG1_PENDING)) {
		status = GenerateGrpMsg1(priv, connPtr);
	} else {
		//This should not happen
		return FAIL;
	}
	if (SUCCESS == status) {
		connPtr->staData.keyMgmtInfo.rom.keyMgmtState++;
	}

	if (SUCCESS == status) {
		connPtr->staData.keyMgmtInfo.numHskTries++;
		/* we are starting the timer irrespective of whether the msg generation is
		   sucessful or not. This is because, if the msg generation fails because
		   of buffer unavailabilty then we can re-try the msg after the timeout
		   period. */
		if (!connPtr->timer_is_set)
			KeyMgmtStartHskTimer(connPtr);
	}

	return status;
}

//#endif // AUTHENTICATOR

void
ApMicErrTimerExpCb(t_void *context)
{
	cm_Connection *connPtr = (cm_Connection *)context;
	phostsa_private priv;
	// UINT32 int_save;
	apInfo_t *pApInfo;

	if (connPtr == NULL) {
		//no AP connection. Do nothing, just return
		return;
	}
	priv = (phostsa_private)connPtr->priv;
	if (!priv)
		return;
	pApInfo = &priv->apinfo;

	switch (connPtr->staData.apMicError.status) {
	case FIRST_MIC_FAIL_IN_60_SEC:
		connPtr->staData.apMicError.status = NO_MIC_FAILURE;
		break;
	case SECOND_MIC_FAIL_IN_60_SEC:
		if ((pApInfo->bssConfig.RsnConfig.mcstCipher.tkip) &&
		    IsAuthenticatorEnabled(priv)) {
			// re-enable the group re-key timer
			pApInfo->bssData.grpRekeyCntRemaining
				= pApInfo->bssData.grpRekeyCntConfigured;
		}
		connPtr->staData.apMicError.status = NO_MIC_FAILURE;
		connPtr->staData.apMicError.disableStaAsso = 0;

		break;
	default:
		break;
	}
}

void
ApMicCounterMeasureInvoke(t_void *pconnPtr)
{
	cm_Connection *connPtr = (cm_Connection *)pconnPtr;
	phostsa_private priv = (phostsa_private)connPtr->priv;
	hostsa_mlan_fns *pm_fns = &priv->mlan_fns;
	hostsa_util_fns *util_fns = &priv->util_fns;
	apInfo_t *pApInfo = &priv->apinfo;

	if (connPtr->staData.apMicError.MICCounterMeasureEnabled) {
		switch (connPtr->staData.apMicError.status) {
		case NO_MIC_FAILURE:
			util_fns->moal_start_timer(util_fns->pmoal_handle,
						   connPtr->staData.apMicTimer,
						   MFALSE, MRVDRV_TIMER_60S);
			connPtr->staData.apMicError.status =
				FIRST_MIC_FAIL_IN_60_SEC;
			break;

		case FIRST_MIC_FAIL_IN_60_SEC:
			connPtr->staData.apMicError.disableStaAsso = 1;
			connPtr->staData.apMicError.status =
				SECOND_MIC_FAIL_IN_60_SEC;
			//start timer for 60 seconds
			util_fns->moal_stop_timer(util_fns->pmoal_handle,
						  connPtr->staData.apMicTimer);
			util_fns->moal_start_timer(util_fns->pmoal_handle,
						   connPtr->staData.apMicTimer,
						   MFALSE, MRVDRV_TIMER_60S);

			/*  smeAPStateMgr_sendSmeMsg(connPtr, MlmeApBcastDisassoc); */
			pm_fns->Hostsa_DisAssocAllSta(priv->pmlan_private,
						      IEEEtypes_REASON_MIC_FAILURE);
			// if current GTK is tkip
			if ((pApInfo->bssConfig.RsnConfig.mcstCipher.tkip) &&
			    IsAuthenticatorEnabled(priv)) {
				//Disable periodic group rekey and re-init GTK.
				priv->GrpRekeyTimerIsSet = MFALSE;
				pApInfo->bssData.grpRekeyCntRemaining = 0;
				ReInitGTK(priv);
			}
			break;

		default:
			break;
		}
	}
	return;
}